Matt Winward
Matt Winward

Reputation: 1255

Need some help generating a screenshot from google maps API

I've spent the last week building a client-side html page that allows the user to draw shapes, add labels and calculate areas. Ultimately, the system needs to be able to turn this work into a flat image that can be automatically added to a word document.

I've investigated various approaches to doing this and keep running into pitfalls. One approach was to send the html of the page server-side and then render and screenshot it using the Browser object from Windows Forms. Another (that I've yet to try) would involve doing something similar, but using PhantomJS server-side.

However, I've realised that the HTML that I'm getting from the page doesn't render what I'm expecting anyway, so I've taken one step forward and two back.

As a quick test, I added this button click event to my page, which captures the page's HTML:

var html = document.documentElement.outerHTML;
var fso = new ActiveXObject("Scripting.FileSystemObject");
var s = fso.CreateTextFile("C:\\Test.html", true);
s.Write(html);
s.Close();

This is an example of the kind of content that the page contains (and that I need in the screenshot):

Expected screenshot content.

However, if I view Test.html in Internet Explorer, I get this:

Google maps HTML example in IE.

.. and if I open it in Chrome I get this:

Google maps HTML example in chrome.

I imagine this is something to do with how gooogle maps works (where it dynamically loads and removes javascript data files to help render shapes). If I could just capture the HTML in its entirety, and working, then I'm hoping I'll be able to screenshot it server-side, but it's not looking hopeful.

Any ideas for reliably turning the page into a flat image?

P.S. I was looking into google's static maps API as well, but that doesn't support things like circles or custom overlays (as far as I can tell)!

EDIT: I've realised that the shapes are drawn into dynamic canvas objects the are tiled across the map, and these canvas elements do not come through with the page HTML (and even if they did, they don't seem to contain the shape data in the DOM).

Upvotes: 3

Views: 2054

Answers (1)

Nick
Nick

Reputation: 2907

I have had to do something very similar in the past.

What I did was, I drew polygons in various colors, added placemarks, shapes etc and then saved everything down into a string using Json.

I used javascript to save all the data like this:

 var feature = MapToolbar.features[type+'Tab'][id];
 var vertices = MapToolbar.getLatLngVertices(feature.getPath());
 allData[id] = { color: feature.fillColor, data: vertices}; });
 var allDataJson = JSON.stringify(allData);
 var hfPolyPath = $("div.hiddenVars input").get(0);

the getLatLngVertices:

  getLatLngVertices: function(path) {
     var pathArray = path.getArray();
     var vertices = [];
     for( var i = 0, n = pathArray.length;  i < n;  i++ ) {
        var latLng = pathArray[i];
        vertices.push({ lat: latLng.lat(), lng: latLng.lng() });
     }
     return vertices;
    },

I wrapped the code into a single function called "SaveBounds()" and it would generate the Json string for me and save it in a hidden field.

Then I generated a static image using the google api.

This can either be done server side, or with jQuery. In my case I need to send the image as an attachment to an email so I have to do it server side but it should be even easier to do it with jQuery.

What you need to do is use http://maps.googleapis.com/maps/api/staticmap You can add all the query string parameters to that in order to produce an image that looks identical to your dynamic map.

The code I have in C# is:

            sb.Append("http://maps.googleapis.com/maps/api/staticmap?");
            sb.Append("center=" + centerMap.Value.Substring(1, centerMap.Value.Length - 1));
            sb.Append("&zoom" + zoom.Value);
            sb.Append("&size=450x450");
            sb.Append("&mapType=" + mapType.Value);

            var decodedMapData = Server.UrlDecode(polyPath.Value);

            var dataObject = JsonConvert.DeserializeObject<dynamic>(decodedMapData);

            string staticImgSrc = sb.ToString();

            foreach (var key in dataObject)
            {
                var color = key.Value["color"];
                var array = key.Value["data"];
                var fillcolor = "0x" + color.ToString().Substring(1) + "80";
                staticImgSrc += "&path=color:0x00000080|weight:2|fillcolor:" + fillcolor;
                var count = 0;
                var lat = string.Empty;
                var lng = string.Empty;
                foreach (var arrayItem in array)
                {
                    staticImgSrc += "|" + arrayItem.lat.ToString() + "," + arrayItem.lng.ToString();
                    if (count == 0)
                    {
                        lat = arrayItem.lat.ToString();
                        lng = arrayItem.lng.ToString();
                    }
                    count++;
                }
                staticImgSrc += "|" + lat + "," + lng;
            }

            staticImgSrc += "&sensor=false";

You can use the final image url to either save the image, send it in an email or whatever you like. You can add as many shapes and placemarks as you want and you can have them filled in any colour you want. You can control the map type, positioning, zoom etc so the end result is an image absolutely identical to the dynamic map that you started from.

Upvotes: 3

Related Questions