Google Maps provides no option to take snapshot / screenshot of a map directly. There are a few ways, like converting the DOM elements which hold the map into a canvas and then saving it as a base64 data. You can then bind that data to a DOM element inside an img tag or save it as a file. Here I’m going to show how to do that:
Project overview
__favicon.ico
__index.html
src
__assets
__components
____MapSnapshot.vue
__App.vue
__constants.js
__main.js
package.json
First, let’s install the NPM libraries that’d help you achieve this functionality. You’d need 2 libraries:
- load-google-maps-api: To load the Google Maps JavaScript API into your Vue project
- html2canvas: To help you convert your mounted DOM element into a HTML Canvas
You can install them with:
npm install load-google-maps-api html2canvas
You’d notice that it has also installed 4 other dependency libraries needed by them:
Project code
Now, as usual, I’m going to register and render the MapSnapshot component inside App.vue file as follows:
<template>
<div id="app">
<MapSnapshot />
</div>
</template>
<script>
import MapSnapshot from "./components/MapSnapshot";
export default {
name: "App",
components: {
MapSnapshot,
},
};
</script>
<style>
#app {
font-family: "Avenir", Helvetica, Arial, sans-serif;
-webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale;
}
</style>
Code language: HTML, XML (xml)
Then inside the MapSnapshot.vue file, I’m going to write all the snapshot generation code:
<template>
<div>
<div class="np-header-margins">
Google Maps Snapshot (<a
href="http://nightprogrammer.com/"
target="_blank"
>nightprogrammer.com</a
>)
<div @click="initiateMapSnapshot" class="np-snapshot-btn">
Take snapshot
</div>
<div
@click="clearMapSnapshot"
class="np-snapshot-btn"
v-if="snapshotImageData"
>
Clear snapshot
</div>
</div>
<div id="google-map-snapshot" class="np-map-margins"></div>
<div v-if="snapshotImageData">
Snapshot:
<div></div>
<div>
<img :src="snapshotImageData" style="height: 400px; width: 600px" />
</div>
</div>
</div>
</template>
<script>
import loadGoogleMapsApi from "load-google-maps-api";
import html2canvas from "html2canvas";
import { gMapsApiKey } from "./../constans";
export default {
name: "GoogleMapSnapshot",
data() {
return {
map: null,
snapshotImageData: null,
};
},
mounted() {
loadGoogleMapsApi({
key: gMapsApiKey,
libraries: ["places", "drawing", "geometry"],
}).then(async () => {
const mapZoom = 12;
const { google } = window;
const mapOptions = {
zoom: mapZoom,
mapTypeId: google.maps.MapTypeId.HYBRID,
center: new google.maps.LatLng({ lat: 23, lng: 57 }),
mapTypeControl: true,
streetViewControl: false,
mapTypeControlOptions: {
position: google.maps.ControlPosition.BOTTOM_LEFT,
},
};
this.map = new google.maps.Map(
document.getElementById("google-map-snapshot"),
mapOptions
);
const polygonCoords = [
{ lat: 25.774, lng: -80.19 },
{ lat: 18.466, lng: -66.118 },
{ lat: 32.321, lng: -64.757 },
{ lat: 37.321, lng: -75.757 },
{ lat: 25.774, lng: -80.19 },
];
const tempBounds = new google.maps.LatLngBounds();
for (let j = 0; j < polygonCoords.length; j++) {
const x = {
lat: polygonCoords[j].lat,
lng: polygonCoords[j].lng,
};
const BoundLatLng = new google.maps.LatLng({
lat: parseFloat(x.lat),
lng: parseFloat(x.lng),
});
tempBounds.extend(BoundLatLng);
}
const centroid = tempBounds.getCenter();
const PolygonShape = new google.maps.Polygon({
paths: polygonCoords,
strokeColor: "#ffffff",
map: this.map,
strokeWeight: 3,
fillColor: "#0000ff",
fillOpacity: 0.2,
zIndex: 99999,
});
PolygonShape.setMap(this.map);
this.map.setCenter(centroid);
this.map.setZoom(4);
});
},
methods: {
clearMapSnapshot() {
this.snapshotImageData = null;
},
initiateMapSnapshot() {
this.getSnapshotOfElement(
"#google-map-snapshot",
0,
0,
600,
400,
(base64MapData) => {
this.snapshotImageData = base64MapData;
alert(
"Snapshot taken successfully. Scroll down the page to view snapshot."
);
}
);
},
getSnapshotOfElement(
element,
posX,
posY,
width,
height,
convertedSnapshotCallback
) {
html2canvas(document.querySelector(element), {
useCORS: true,
allowTaint: false,
}).then((canvas) => {
const context = canvas.getContext("2d");
const imageData = context.getImageData(
posX,
posY,
canvas.width,
canvas.height
).data;
const outputCanvas = document.createElement("canvas");
const outputContext = outputCanvas.getContext("2d");
outputCanvas.width = canvas.width;
outputCanvas.height = canvas.height;
const outputIData = outputContext.createImageData(
canvas.width,
canvas.height
);
outputIData.data.set(imageData);
outputContext.putImageData(outputIData, 0, 0);
convertedSnapshotCallback(
//use it to get the raw base64 data without format mention
//outputCanvas.toDataURL().replace("data:image/png;base64,", "")
outputCanvas.toDataURL()
);
});
},
},
};
</script>
<style scoped>
.np-header-margins {
margin-left: 40px;
margin-top: 20px;
}
.np-map-margins {
height: 400px;
width: 600px;
margin: 30px 40px;
}
.np-snapshot-btn {
margin: 14px 0px;
background: rgb(0, 119, 255);
width: 140px;
text-align: center;
padding: 6px 8px;
border-radius: 4px;
color: #ffffff;
transition: all 0.3s;
cursor: pointer;
}
.np-snapshot-btn:hover {
background: rgb(0, 74, 158);
transition: all 0.3s;
}
</style>
Code language: HTML, XML (xml)
Let’s breakdown the code and have a look at what I did here by line:
9: A snapshot button to take the snapshot
12: A clear button to clear the generated snapshot
22: Snapshot data rendered as an image (base64)
33: I imported the loadGoogleMapsApi library to make the GMaps functional
34: I imported the html2canvas library to generate a canvas from a DOM element
35: Here I imported the Google Maps API key
62: I initialized map state with the Google Maps data
90: Created and mapped a polygon object on Google maps
110: This is where I’m calling the first function to take the snapshot.
124: In the getSnapShotOfElement function I’m receiving 6 parameters:
- element: To specify the HTML element target
- posX: To specify the initial X coordinate of the renderable element
- posY: To specify the initial Y coordinate of the renderable element
- width: Width of the map, although you can also use canvas.width here
- height: Height of the map, you can also use canvas.height to pick the height on its own
- convertedSnapshotCalledback: A callback function which gets called upon canvas generation
Finally, when the base64 image data is generated, I bind it back to the DOM element as on line 117.
This is how the view is supposed to look like:
And of course, you can find a working demo of the above code on my repos here: