【问题标题】:How to draw straight lines inside google map polygon如何在谷歌地图多边形内绘制直线
【发布时间】:2013-03-26 09:21:10
【问题描述】:

我使用google map javascript API V3 创建了一个谷歌地图。我正在绘制邮政编码多边形的数量。根据某些条件,多边形具有不同的颜色。现在我想根据某些标准在一些多边形内绘制直线/哈希标记。我们该怎么做。下面是我为绘制多边形编写的代码。

{% if zip.zip_info.zip_polygon %}
    var path = [
        {% for polycoord in zip.zip_info.zip_polygon %}
            new google.maps.LatLng({{polycoord.1}}, {{polycoord.0}}),
        {% endfor %}
        ];

    var polygon_{{ forloop.counter }} = new google.maps.Polygon(
    {
        path:path, 
        clickable:true,
        strokeColor: '#000000',
        strokeOpacity: 0.15,
        strokeWeight: 2,
        fillColor: fillColor,
        fillOpacity: 1,
        zipcode: '{{zip.zip_info.zipcode}}'
    });

    polygon_{{ forloop.counter }}.setMap(map);

{% endif %}

我也给出了我要求的图片链接。

您可以在图像中看到一些多边形用直线着色,而另一些则只用颜色着色。

【问题讨论】:

  • 听起来你想要一个填充“纹理”,像这样enhancement request
  • 是的,想添加纹理,换句话说,我们可以说我想在多边形内画线。我们能做到吗?
  • 此时您无法使用 API 进行操作。您可以为该增强请求投票(或为您的目的找到另一个更好的请求,或创建一个新请求)。您也许可以使用折线做一些事情,但它可能会影响性能。
  • 感谢 geocodezip。但是我可以在哪里发布增强 API 的请求或者我可以在哪里投票。请指导。
  • 我第一条评论中的链接。 (code.google.com/p/gmaps-api-issues/issues/detail?id=598)

标签: javascript google-maps google-maps-api-3 polygon


【解决方案1】:

我研究过 Bryan Weaver 的解决方案,以便使用绘图管理器使其适用于可编辑的多边形。这是我的jsfiddle example

function initialize() {
   var map = new google.maps.Map(document.getElementById('map-canvas'), {
     zoom: 5,
     center: {
       lat: 24.886,
       lng: -70.268
     },
     mapTypeId: 'terrain'
   });

   var drawingManager = new google.maps.drawing.DrawingManager({
     drawingControl: true,
     drawingControlOptions: {
       position: google.maps.ControlPosition.TOP_CENTER,
       drawingModes: [google.maps.drawing.OverlayType.POLYGON]
     },

     polygonOptions: {
       fillOpacity: 0,
       strokeWeight: 1,
       strokeColor: '#ff0000',
       clickable: true,
       editable: true,
       draggable: true,
     }
   });

   drawingManager.setMap(map);
   google.maps.event.addListener(drawingManager, 'overlaycomplete', function(event) {
     var poly = event.overlay;
     poly.bk = new BW.PolyLineFill(poly.getPath(), this.map, "red", "#000");

     google.maps.event.addListener(poly, 'dragstart', function(event) {
       if (poly.bk != null) {
         poly.bk.setMap(null);
         poly.bk = null
       }
       poly.isBeingDragged = true;
     });

     google.maps.event.addListener(poly, 'dragend', function(event) {
       if (poly.bk != null) {
         poly.bk.setMap(null);
         poly.bk = null
       }
       poly.bk = new BW.PolyLineFill(poly.getPath(), poly.map, "red", "#000");
       poly.isBeingDragged = false;
     });


     google.maps.event.addListener(poly.getPath(), 'set_at', function(event) {
       if (poly.isBeingDragged) return;
       console.log('set_at');
       if (poly.bk != null) {
         poly.bk.setMap(null);
         poly.bk = null
       }
       poly.bk = new BW.PolyLineFill(poly.getPath(), poly.map, "red", "#000");
     });

     google.maps.event.addListener(poly.getPath(), 'insert_at', function(event) {
       if (poly.bk != null) {
         poly.bk.setMap(null);
         poly.bk = null
       }
       poly.bk = new BW.PolyLineFill(poly.getPath().b, poly.map, "red", "#000");
     });


     drawingManager.setDrawingMode(null);
   });

 }

 ///Start custom poly fill code
 PolyLineFill.prototype = new google.maps.OverlayView();

 function PolyLineFill(poly, map, fill, stroke) {
   var bounds = new google.maps.LatLngBounds();
   for (var i = 0; i < poly.length; i++) {
     bounds.extend(poly.getAt(i));
   }

   //initialize all properties.
   this.bounds_ = bounds;
   this.map_ = map;
   this.div_ = null;
   this.poly_ = poly;
   this.polysvg_ = null;
   this.fill_ = fill;
   this.stroke_ = stroke;

   // Explicitly call setMap on this overlay
   this.setMap(map);
 }

 PolyLineFill.prototype.onAdd = function() {
   // Create the DIV and set some basic attributes.
   var div = document.createElement('div');
   div.style.borderStyle = 'none';
   div.style.borderWidth = '0px';
   div.style.position = 'absolute';

   //https://www.w3schools.com/graphics/svg_reference.asp
   //createthe svg element
   var svgns = "http://www.w3.org/2000/svg";
   var svg = document.createElementNS(svgns, "svg");
   svg.setAttributeNS(null, "height", "100%");
   svg.setAttributeNS(null, "width", "100%");
   svg.setAttributeNS(null, "preserveAspectRatio", "xMidYMid meet");

   //A container for referenced elements
   var def = document.createElementNS(svgns, "defs");

   //create the pattern fill 
   var pattern = document.createElementNS(svgns, "pattern");
   //***************************CHANGE PATTERN HERE**********************************     
   pattern.setAttributeNS(null, "id", "lineFill");
   pattern.setAttributeNS(null, "patternUnits", "userSpaceOnUse");
   //pattern.setAttributeNS(null, "patternTransform", "rotate(-33)");

   pattern.setAttributeNS(null, "height", "60");
   pattern.setAttributeNS(null, "width", "60");
   def.appendChild(pattern);

   var rect = document.createElementNS(svgns, "rect");
   rect.setAttributeNS(null, "id", "rectFill");
   rect.setAttributeNS(null, "fill", "green");
   rect.setAttributeNS(null, "fill-opacity", "0.25");
   rect.setAttributeNS(null, "stroke", "#0000FF");
   rect.setAttributeNS(null, "stroke-width", "8");
   rect.setAttributeNS(null, "stroke-opacity", "0.25");
   rect.setAttributeNS(null, "stroke-dasharray", "10 10");
   rect.setAttributeNS(null, "x", "5");
   rect.setAttributeNS(null, "y", "5");
   rect.setAttributeNS(null, "height", "50");
   rect.setAttributeNS(null, "width", "50");
   rect.setAttributeNS(null, "rx", "25");
   rect.setAttributeNS(null, "ry", "25");
   pattern.appendChild(rect);

   svg.appendChild(def);

   //add polygon to the div
   var p = document.createElementNS(svgns, "polygon");
   p.setAttributeNS(null, "fill", "url(#lineFill)");
   //set a reference to this element;
   this.polysvg_ = p;
   svg.appendChild(p);

   div.appendChild(svg);

   // Set the overlay's div_ property to this DIV
   this.div_ = div;

   // We add an overlay to a map via one of the map's panes.
   // We'll add this overlay to the overlayLayer pane.
   var panes = this.getPanes();
   panes.overlayLayer.appendChild(div);
 }

 PolyLineFill.prototype.AdjustPoints = function() {
   //adjust the polygon points based on the projection.
   var proj = this.getProjection();
   var sw = proj.fromLatLngToDivPixel(this.bounds_.getSouthWest());
   var ne = proj.fromLatLngToDivPixel(this.bounds_.getNorthEast());

   var points = "";
   for (var i = 0; i < this.poly_.length; i++) {
     var point = proj.fromLatLngToDivPixel(this.poly_.getAt(i));
     if (i == 0) {
       points += (point.x - sw.x) + ", " + (point.y - ne.y);
     } else {
       points += " " + (point.x - sw.x) + ", " + (point.y - ne.y);
     }
   }
   return points;
 }

 PolyLineFill.prototype.draw = function() {
   // Size and position the overlay. We use a southwest and northeast
   // position of the overlay to peg it to the correct position and size.
   // We need to retrieve the projection from this overlay to do this.
   var overlayProjection = this.getProjection();

   // Retrieve the southwest and northeast coordinates of this overlay
   // in latlngs and convert them to pixels coordinates.
   // We'll use these coordinates to resize the DIV.
   var sw = overlayProjection.fromLatLngToDivPixel(this.bounds_.getSouthWest());
   var ne = overlayProjection.fromLatLngToDivPixel(this.bounds_.getNorthEast());

   // Resize the image's DIV to fit the indicated dimensions.
   var div = this.div_;
   div.style.left = sw.x + 'px';
   div.style.top = ne.y + 'px';
   div.style.width = (ne.x - sw.x) + 'px';
   div.style.height = (sw.y - ne.y) + 'px';

   this.polysvg_.setAttributeNS(null, "points", this.AdjustPoints());
 }

 PolyLineFill.prototype.onRemove = function() {
   this.div_.parentNode.removeChild(this.div_);
   this.div_ = null;
 }
 window.BW = {};
 window.BW.PolyLineFill = PolyLineFill;
 ///end poly fill code


 google.maps.event.addDomListener(window, 'load', initialize);


 //**************************velho
 function showArrays(event) {
   if (this.overlay)
     this.overlay.setMap(null)
   this.overlay = new BW.PolyLineFill(this.getPath().b, this.map, "red", "#000");
 }
     html,
     body {
       height: 100%;
       margin: 0;
       padding: 0;
     }
     
     #map-canvas,
     #map_canvas {
       height: 100%;
     }
     
     @media print {
       html,
       body {
         height: auto;
       }
       #map_canvas {
         height: 650px;
       }
     }
<script src="https://maps.google.com/maps/api/js?sensor=false&libraries=drawing&.js"></script>
<div id="map-canvas"></div>

【讨论】:

    【解决方案2】:

    可以在 CANVAS 中完成:

    http://home.provide.net/~bratliff/hawaii/
    

    单击“样式”单选选项以查看其他可选模式。

    【讨论】:

    • 是的,我在链接中看到了示例,该示例正在运行。但是我们可以使用谷歌地图 V3 API js 来做到这一点吗?
    • 这只适用于静态图像,这可能是他们使用谷歌静态地图的原因。
    【解决方案3】:

    我一直在研究同样的问题。这是我目前所拥有的:jsFiddle of Example

    BW.PolyLineFill 函数创建一个Custom Overlay。它需要 4 个参数,最后两个是可选的。

     1. path: an array of Google LatLng objects   
     2. map: the map to attach theoverlay to 
     3. fillColor: (optional) the color of the fill, default is red. 
     4. strokeColor: (optional) the stroke color, default is black
    

    我还没有测试过性能,它可能还需要更多的调整,但它应该能让你开始。

    相关代码:

    PolyLineFill.prototype = new google.maps.OverlayView();
    function PolyLineFill(poly, map, fill, stroke) {
        var bounds = new google.maps.LatLngBounds();
        for (var i = 0; i < poly.length; i++) {
            bounds.extend(poly[i]);
        }
    
        //initialize all properties.
        this.bounds_ = bounds;
        this.map_ = map;
        this.div_ = null;
        this.poly_ = poly;
        this.polysvg_ = null;
        this.fill_ = fill;
        this.stroke_ = stroke;
    
        // Explicitly call setMap on this overlay
        this.setMap(map);
    }
    
    PolyLineFill.prototype.onAdd = function () {
        // Create the DIV and set some basic attributes.
        var div = document.createElement('div');
        div.style.borderStyle = 'none';
        div.style.borderWidth = '0px';
        div.style.position = 'absolute';
    
        //createthe svg element
        var svgns = "http://www.w3.org/2000/svg";
        var svg = document.createElementNS(svgns, "svg");
        svg.setAttributeNS(null, "preserveAspectRatio", "xMidYMid meet");
    
        var def = document.createElementNS(svgns, "defs");
    
        //create the pattern fill 
        var pattern = document.createElementNS(svgns, "pattern");
        pattern.setAttributeNS(null, "id", "lineFill");
        pattern.setAttributeNS(null, "patternUnits", "userSpaceOnUse");
        pattern.setAttributeNS(null, "patternTransform", "rotate(-45)");
        pattern.setAttributeNS(null, "height", "7");
        pattern.setAttributeNS(null, "width", "7");
        def.appendChild(pattern);
    
        var rect = document.createElementNS(svgns, "rect");
        rect.setAttributeNS(null, "id", "rectFill");
        rect.setAttributeNS(null, "fill", this.fill_ || "red");
        rect.setAttributeNS(null, "fill-opacity", "0.3");
        rect.setAttributeNS(null, "stroke", this.stroke_ || "#000");
        rect.setAttributeNS(null, "stroke-dasharray", "7,7");
        rect.setAttributeNS(null, "height", "7");
        rect.setAttributeNS(null, "width", "7");
        pattern.appendChild(rect);
    
        svg.appendChild(def);
    
        //add polygon to the div
        var p = document.createElementNS(svgns, "polygon");
        p.setAttributeNS(null, "fill", "url(#lineFill)");
        p.setAttributeNS(null, "stroke", "#000");
        p.setAttributeNS(null, "stroke-width", "1");
        //set a reference to this element;
        this.polysvg_ = p;
        svg.appendChild(p);
    
        div.appendChild(svg);
    
        // Set the overlay's div_ property to this DIV
        this.div_ = div;
    
        // We add an overlay to a map via one of the map's panes.
        // We'll add this overlay to the overlayLayer pane.
        var panes = this.getPanes();
        panes.overlayLayer.appendChild(div);
    }
    
    PolyLineFill.prototype.AdjustPoints = function () {
        //adjust the polygon points based on the projection.
        var proj = this.getProjection();
        var sw = proj.fromLatLngToDivPixel(this.bounds_.getSouthWest());
        var ne = proj.fromLatLngToDivPixel(this.bounds_.getNorthEast());
    
        var points = "";
        for (var i = 0; i < this.poly_.length; i++) {
            var point = proj.fromLatLngToDivPixel(this.poly_[i]);
            if (i == 0) {
                points += (point.x - sw.x) + ", " + (point.y - ne.y);
            } else {
                points += " " + (point.x - sw.x) + ", " + (point.y - ne.y);
            }
        }
        return points;
    }
    
    PolyLineFill.prototype.draw = function () {
        // Size and position the overlay. We use a southwest and northeast
        // position of the overlay to peg it to the correct position and size.
        // We need to retrieve the projection from this overlay to do this.
        var overlayProjection = this.getProjection();
    
        // Retrieve the southwest and northeast coordinates of this overlay
        // in latlngs and convert them to pixels coordinates.
        // We'll use these coordinates to resize the DIV.
        var sw = overlayProjection
                    .fromLatLngToDivPixel(this.bounds_.getSouthWest());
        var ne = overlayProjection
                    .fromLatLngToDivPixel(this.bounds_.getNorthEast());
    
        // Resize the image's DIV to fit the indicated dimensions.
        var div = this.div_;
        div.style.left = sw.x + 'px';
        div.style.top = ne.y + 'px';
        div.style.width = (ne.x - sw.x) + 'px';
        div.style.height = (sw.y - ne.y) + 'px';
    
        this.polysvg_.setAttributeNS(null, "points", this.AdjustPoints());
    }
    
    PolyLineFill.prototype.onRemove = function () {
        this.div_.parentNode.removeChild(this.div_);
        this.div_ = null;
    }
    window.BW = {};
    window.BW.PolyLineFill = PolyLineFill;
    

    【讨论】:

    • 这方面有什么进一步的进展吗?看起来它可以工作,但是一旦你放大,事情看起来就不正确了。
    • @BigDubb 您能否更具体地说明什么不起作用?上面小提琴示例中的叠加示例与 Google 地图上定义的边界不完全一致,因为我快速抓取了一些地理数据用于示例。用于收集数据的地图投影与 Google 的投影可能略有不同。更准确的数据会有更好的结果,或者至少与谷歌选择的预测一致。我相信谷歌使用的是墨卡托投影,所以如果你使用其他类型,在转换为屏幕坐标时会出现轻微的偏移。
    • 我在 Chrome 中启动了它。放大犹他州,一旦我超过特定的缩放级别,它就会停止正确地绘制多边形。它的一部分不会渲染,如果你放大得足够多,它就会一起消失。
    • 我已经在我的应用程序中实现了您的解决方案,我遇到了@BigDubb 看到的同样问题。我会检查代码,看看我是否可以修复它,除非你已经有补丁可以解决它。
    • 我已经修复了放大地图时出现的奇怪行为(svg 正在被修剪)。我添加了一个 css 类来赋予它 100% 的高度和宽度。现在缩放问题解决了。另一方面,我更改了渲染形状的类型。我画了一个path 而不是polygon,因为在我的测试中,path 元素对鼠标事件的响应更好,因为鼠标悬停,鼠标点击...Link to my example
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-05-31
    • 1970-01-01
    • 2020-06-28
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多