import crypto from "node:crypto" // Helper function to calculate the latitude offset export function calculateLatWithOffset( latitude: number, offsetPx: number, zoomLevel: number ): number { const earthCircumference = 40075017 // Earth's circumference in meters const tileSize = 256 // Height of a tile in pixels (standard in Google Maps) // Calculate ground resolution (meters per pixel) at the given latitude and zoom level const groundResolution = (earthCircumference * Math.cos((latitude * Math.PI) / 180)) / (tileSize * Math.pow(2, zoomLevel)) // Calculate the number of meters for the given offset in pixels const metersOffset = groundResolution * offsetPx // Convert the meters offset into a latitude offset (1 degree latitude is ~111,320 meters) const latOffset = metersOffset / 111320 // Return the new latitude by subtracting the offset return latitude - latOffset } /** * Util functions taken from https://developers.google.com/maps/documentation/maps-static/digital-signature#sample-code-for-url-signing * Used to sign the URL for the Google Static Maps API. */ /** * Convert from 'web safe' base64 to true base64. * * @param {string} safeEncodedString The code you want to translate * from a web safe form. * @return {string} */ function removeWebSafe(safeEncodedString: string) { return safeEncodedString.replace(/-/g, "+").replace(/_/g, "/") } /** * Convert from true base64 to 'web safe' base64 * * @param {string} encodedString The code you want to translate to a * web safe form. * @return {string} */ function makeWebSafe(encodedString: string) { return encodedString.replace(/\+/g, "-").replace(/\//g, "_") } /** * Takes a base64 code and decodes it. * * @param {string} code The encoded data. * @return {string} */ function decodeBase64Hash(code: string) { return Buffer.from(code, "base64") } /** * Takes a key and signs the data with it. * * @param {string} key Your unique secret key. * @param {string} data The url to sign. * @return {string} */ function encodeBase64Hash(key: Buffer, data: string) { return crypto.createHmac("sha1", key).update(data).digest("base64") } /** * Sign a URL using a secret key. * * @param {URL} url The url you want to sign. * @param {string} secret Your unique secret key. * @return {string} */ export function getUrlWithSignature(url: URL, secret = "") { const path = url.pathname + url.search const safeSecret = decodeBase64Hash(removeWebSafe(secret)) const hashedSignature = makeWebSafe(encodeBase64Hash(safeSecret, path)) return `${url.toString()}&signature=${hashedSignature}` }