Static Maps: Drawing polygons with many points. (2048 char limitation)

*爱你&永不变心* 提交于 2019-12-05 10:29:28
drzax

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;
}
Patrick

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

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.

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!