5

Because there is a limitation to 2048 characters in the get request, you are not able to generate an image with Google Static Maps which contains a polygon with a great number of polygon points.

Especially if you try to draw many complex polygons on one map. If you use Google Maps API, you will have no problem - it works very well! But I want to have an image (jpg or png)...

So, is there any opportunity to create an image from the Google Maps API? Or any way to 'trick' the 2048 char limitation?

Thanks!

Flo Bayer
  • 1,190
  • 4
  • 12
  • 25
  • Refer the below url, this will help a lot https://developers.google.com/maps/documentation/staticmaps/?hl=fr#EncodedPolylines – user3364541 Feb 28 '14 at 11:10

3 Answers3

6

There's no way to 'trick' the character limit, but it is possible to simplify your polyline to bring the encoded polyline string below the character limit. This may or may not result in a polygon of suitable fidelity for your needs.

One additional caveat is that (to the best of my knowledge) the Static Maps API only allows a single encoded polyline to be drawn on the map (this can look like a polygon, if you either close it yourself or fill it, but it's still a polyline, not a polygon).

One option for simplifying your polyline is the Douglas Peucker algorithm. Below is an implementation which extends the google.maps.Polyline object with a simplify method.

This relies on having the Google Maps JS API loaded, which you may not want if you're using Static Maps, but the code below could easily be re-written.

google.maps.Polyline.prototype.simplify = function(tolerance) {

    var points = this.getPath().getArray(); // An array of google.maps.LatLng objects
    var keep = []; // The simplified array of points

    // Check there is something to simplify.
    if (points.length <= 2) {
        return points;
    }

    function distanceToSegment(p, v, w) {

        function distanceSquared(v, w) {
            return Math.pow((v.x - w.x),2) + Math.pow((v.y - w.y),2) 
        }
        function distanceToSegmentSquared(p, v, w) {

            var l2 = distanceSquared(v, w);
            if (l2 === 0) return distanceSquared(p, v);

            var t = ((p.x - v.x) * (w.x - v.x) + (p.y - v.y) * (w.y - v.y)) / l2;
            if (t < 0) return distanceSquared(p, v);
            if (t > 1) return distanceSquared(p, w);
            return distanceSquared(p, { x: v.x + t * (w.x - v.x), y: v.y + t * (w.y - v.y) });
        }

        // Lat/Lng to x/y
        function ll2xy(p){
            return {x:p.lat(),y:p.lng()};
        }

        return Math.sqrt(distanceToSegmentSquared(ll2xy(p), ll2xy(v), ll2xy(w))); 
    }

    function dp( points, tolerance ) {

        // If the segment is too small, just keep the first point. 
        // We push the final point on at the very end.
        if ( points.length <= 2 ) {
            return [points[0]];
        }

        var keep = [],  // An array of points to keep
            v = points[0], // Starting point that defines a segment
            w = points[points.length-1], // Ending point that defines a segment
            maxDistance = 0, // Distance of farthest point
            maxIndex = 0; // Index of said point

        // Loop over every intermediate point to find point greatest distance from segment
        for ( var i = 1, ii = points.length - 2; i <= ii; i++ ) {
            var distance = distanceToSegment(points[i], points[0], points[points.length-1]);
            if( distance > maxDistance ) {
                maxDistance = distance;
                maxIndex = i;
            }
        }

        // check if the max distance is greater than our tollerance allows 
        if ( maxDistance >= tolerance ) {

            // Recursivly call dp() on first half of points
            keep = keep.concat( dp( points.slice( 0, maxIndex + 1 ), tolerance ) );

            // Then on second half
            keep = keep.concat( dp( points.slice( maxIndex, points.length ), tolerance ) );

        } else {
            // Discarding intermediate point, keep the first
            keep = [points[0]];
        }
        return keep;
    };

    // Push the final point on
    keep = dp(points, tolerance);
    keep.push(points[points.length-1]);
    return keep;

};

This has been cobbled together with the help of a couple of examples (here and here).

You can now take your original polyline and feed it through this function with increasing tolerance until the resulting encoded polyline falls below the URL length limit (which will depend on the other parameters you're passing to Static Maps).

Something like this should work:

var line = new google.maps.Polyline({path: path});
var encoded = google.maps.geometry.encoding.encodePath(line.getPath());
var tol = 0.0001;
while (encoded.length > 1800) {
    path = line.simplify(tol);
    line = new google.maps.Polyline({path: path});
    encoded = google.maps.geometry.encoding.encodePath(path);
    tol += .005;
}
Community
  • 1
  • 1
drzax
  • 1,675
  • 1
  • 16
  • 20
  • Thanks - I should try that next time. Actually I've decided to get the expected Google Static Image and draw a filled polygon with PHP on it. It's possible by a linear function and it works fine. – Flo Bayer Sep 12 '13 at 08:13
  • This answer is amazing. Thank you so much. – Henry C Sep 07 '15 at 17:39
0

Another way is to use a javascript library that can convert your content of a canvas to an image. Something like

Though I am not sure about it's performance for googlemaps with overlay's.

EDIT: If you're using html2canvas, be sure to checkout this question: https://stackoverflow.com/a/17816195/2279924

Community
  • 1
  • 1
Patrick
  • 879
  • 2
  • 11
  • 29
0

As of September 2016 the URL limit has been changed to 8192 characters in size.

https://developers.google.com/maps/documentation/static-maps/intro#url-size-restriction

There was also a feature request in public issue tracker that was marked as Fixed.

xomena
  • 31,125
  • 6
  • 88
  • 117