Static Google Maps Implemention

So, in the last couple of days I’ve been searching for an implementation of a static map on widgets (since ios can support only static elements). I’ve also tried static maps services like geoapify but honestly want cutting for me.
So, haven’t found any, I decided to do my own: I’ve reversed engineered a google vt link and I came up with this:

class GoogleMapsVT {
    constructor() {}
    generate_vt_url(lat, lon, address, dimensions = [512, 512], zoom = 19) {
        let base = "https://www.google.com/maps/vt/pb=";
			let params = [
			    "!1m8", "!4m7",
			    `!1m2!1u${dimensions[0]}!2u${dimensions[1]}!2u${zoom}`,
			    `!3m2!1x${String(lat).replace('.', '')}!2x${String(lon).replace('.', '')}`,
			    "!2m35", "!1e2", "!2sspotlight", "!8m32", "!1m2!12m1!20e1", "!2m7",
			    `!1s0x477e4e5cdd6e8637:0x2c4b6f8740858561`,
			    `!2s${encodeURIComponent(address.replace(' ', '+'))}`,
			    `!4m2!3d${lat}!4d${lon}`,
			    "!5e3", "!6b1", "!13m10", "!2shh,a", "!18m4", "!6b0", "!9b1", "!20b1", "!21b1", "!22m3",
			    "!6e2", "!7e3", "!8e2", "!19u6", "!19u7", "!19u11", "!19u12", "!19u14", "!19u29", "!19u37", 
			    "!19u30", "!19u61", "!19u70", "!2m2!1e4!2st", "!2m3!1e0!2sm!3i999999", "!3m3!2sit!3sIT", 
			    "!5e1105!4e0!5m2!1e0!5f2.0"
			].join('');
		   return base + params;
    }
    async getAddressCoordinates(address) {
        let url = `https://nominatim.openstreetmap.org/?addressdetails=1&q=${encodeURIComponent(address.replace(' ', '+'))}&format=json&limit=1`;
        var request = new Request(url);
	     let response = await request.loadJSON();
        if (response.length > 0) {
            return {
                lat: response[0]["lat"],
                lon: response[0]["lon"]
            };
        } else {
            return null;
        }
    }
}

I’ll also attach a minified version if u want to incorporate it in your widgets:

class GoogleMapsVT {constructor(){}generate_vt_url(_,e,t,m=[1024,1024],s=19){return`https://www.google.com/maps/vt/pb=!1m8!4m7!1m2!1u${m[0]}!2u${m[1]}!2u${s}!3m2!1x${String(_).replace(".","")}!2x${String(e).replace(".","")}!2m35!1e2!2sspotlight!8m32!1m2!12m1!20e1!2m7!1s0x477e4e5cdd6e8637:0x2c4b6f8740858561!2s${encodeURIComponent(t.replace(" ","+"))}!4m2!3d${_}!4d${e}!5e3!6b1!13m10!2shh,a!18m4!6b0!9b1!20b1!21b1!22m3!6e2!7e3!8e2!19u6!19u7!19u11!19u12!19u14!19u29!19u37!19u30!19u61!19u70!2m2!1e4!2st!2m3!1e0!2sm!3i999999!3m3!2sit!3sIT!5e1105!4e0!5m2!1e0!5f2.0`}async getAddressCoordinates(_){let e,t=await new Request(`https://nominatim.openstreetmap.org/?addressdetails=1&q=${encodeURIComponent(_.replace(" ","+"))}&format=json&limit=1`).loadJSON();return t.length>0?{lat:t[0].lat,lon:t[0].lon}:null}}

In my opinion it work great, If u have any tips or bugs let me know :slight_smile: I’ll try to update it.
Here’s a basic working example:

class GoogleMapsVT {constructor(){}generate_vt_url(_,e,t,m=[1024,1024],s=19){return`https://www.google.com/maps/vt/pb=!1m8!4m7!1m2!1u${m[0]}!2u${m[1]}!2u${s}!3m2!1x${String(_).replace(".","")}!2x${String(e).replace(".","")}!2m35!1e2!2sspotlight!8m32!1m2!12m1!20e1!2m7!1s0x477e4e5cdd6e8637:0x2c4b6f8740858561!2s${encodeURIComponent(t.replace(" ","+"))}!4m2!3d${_}!4d${e}!5e3!6b1!13m10!2shh,a!18m4!6b0!9b1!20b1!21b1!22m3!6e2!7e3!8e2!19u6!19u7!19u11!19u12!19u14!19u29!19u37!19u30!19u61!19u70!2m2!1e4!2st!2m3!1e0!2sm!3i999999!3m3!2sit!3sIT!5e1105!4e0!5m2!1e0!5f2.0`}async getAddressCoordinates(_){let e,t=await new Request(`https://nominatim.openstreetmap.org/?addressdetails=1&q=${encodeURIComponent(_.replace(" ","+"))}&format=json&limit=1`).loadJSON();return t.length>0?{lat:t[0].lat,lon:t[0].lon}:null}}

// === EXAMPLE === //
async function fetchImage(url) {
    const request = new Request(url);
    return await request.loadImage();
}

async function createWidgetWithMap(img) {
    let widget = new ListWidget();
	 let widgetImage = widget.addImage(img);
	 widgetImage.cornerRadius = 10;
	 widgetImage.centerAlignImage()
    if (config.runsInWidget) {
        Script.setWidget(widget);
    } else {
        widget.presentLarge();
    }
    
    Script.complete();
}

let googleMapsVT = new GoogleMapsVT();
let address = "Via Quartieri, Ferrara, FE";
let coordinates = await googleMapsVT.getAddressCoordinates(address); // or u can directly add them
if (coordinates) {
    let url = googleMapsVT.generate_vt_url(coordinates.lat, coordinates.lon, address, [512, 512], 17); // [int, int], int ==> image dimensions, zoom
    let img = await fetchImage(url);
    await createWidgetWithMap(img);
	
} else {
    console.log("Address not found.");
}

Result:

3 Likes

Wonderful work! A similar project was done to display current location in a widget before. It’s not so easy to find now but here is the link:

Hi, any way to add traffic data to this? I know if you google “traffic” you get served an image with traffic.

1 Like