【问题标题】:How to draw a polygon around a polyline in JavaScript?如何在 JavaScript 中围绕折线绘制多边形?
【发布时间】:2013-10-22 13:22:39
【问题描述】:

我想在折线周围画一个多边形。在我的例子中,折线是一个谷歌地图方向,我需要在谷歌地图画布中围绕它显示一个多边形。

第一:

对于偏移,我使用 JavaScript Clipper 库。我有以下折线(路线):我使用 Clipper 在下面制作了一个偏移多边形:

我有一个工作的JS Bin example

代码是:

<html>
  <head>
    <title>Javascript Clipper Library / Offset polyline</title>
    <script src="clipper.js"></script>
    <script>
    function draw() {
      var polygons = [[{"X":72,"Y":59.45},{"X":136,"Y":66},{"X":170,"Y":99},{"X":171,"Y":114},{"X":183,"Y":125},{"X":218,"Y":144},{"X":218,"Y":165},{"X":226,"Y":193},{"X":254,"Y":195},{"X":283,"Y":195},{"X":292,"Y":202},{"X":325,"Y":213},{"X":341,"Y":234},{"X":397,"Y":245},{"X":417,"Y":248}]]; 
      var scale = 100;
      reverse_copy(polygons);
      polygons = scaleup(polygons, scale);
      var cpr = new ClipperLib.Clipper();
      var delta = 25;
      var joinType = ClipperLib.JoinType.jtRound;
      var miterLimit = 2;
      var AutoFix = true;
      var svg, offsetted_polygon,
      cont = document.getElementById('svgcontainer');
      offsetted_polygon = cpr.OffsetPolygons(polygons, delta * scale, joinType, miterLimit, AutoFix);
      //console.log(JSON.stringify(offsetted_polygon));

      // Draw red offset polygon
      svg = '<svg style="margin-top:10px;margin-right:10px;margin-bottom:10px;background-color:#dddddd" width="540" height="340">';
      svg += '<path stroke="red" fill="red" stroke-width="2" stroke-opacity="0.6" fill-opacity="0.2" d="' + polys2path(offsetted_polygon, scale) + '"/>';

      //Draw blue polyline
      svg += '<path stroke="blue" stroke-width="3" d="' + polys2path(polygons, scale) + '"/>';
      svg += '</svg>';

      cont.innerHTML += svg;
    }

    // helper function to scale up polygon coordinates
    function scaleup(poly, scale) {
      var i, j;

      if (!scale)
        scale = 1;

      for(i = 0; i < poly.length; i++) {
        for(j = 0; j < poly[i].length; j++) {
          poly[i][j].X *= scale;
          poly[i][j].Y *= scale;
        }
      }

      return poly;
    }

    // converts polygons to SVG path string
    function polys2path (poly, scale) {
      var path = "", i, j;

      if (!scale)
        scale = 1;

      for(i = 0; i < poly.length; i++) {
        for(j = 0; j < poly[i].length; j++) {
          if (!j)
            path += "M";
          else
            path += "L";
          path += (poly[i][j].X / scale) + ", " + (poly[i][j].Y / scale);
        }
        path += "Z";
      }

      return path;
    }

    function reverse_copy(poly) {
      // Make reverse copy of polygons = convert polyline to a 'flat' polygon ...
      var k, klen = poly.length, len, j; 

      for (k = 0; k < klen; k++) {
        len = poly[k].length;
        poly[k].length = len * 2 - 2;

        for (j = 1; j <= len - 2; j++) {
          poly[k][len - 1 + j] = {
            X: poly[k][len - 1 - j].X,
            Y: poly[k][len - 1 - j].Y
          }
        }
      }
    }
    </script>
  </head>
  <body onload="draw()">
    <h2>Javascript Clipper Library / Offset polyline</h2>
    This page shows an example of offsetting polyline and drawing it using SVG.
    <div id="svgcontainer"></div>
  </body>
</html> 

这一切都很好,但现在我必须用谷歌地图方向的点替换多边形变量,所以我做了这个改变:

directionsService.route(request, function(response, status) {
  if (status == google.maps.DirectionsStatus.OK) {
    directionsDisplay.setDirections(response);

    function draw() {
      var polygons = response.routes[0].overview_path; 

      //REST OF CODE
    }
  }
}

我有一个JS Bin example,其中包含用于偏移折线周围的多边形的代码。

但有一些问题,我无法重新定位,也无法获得方向周围的多边形。

有没有办法解决这个问题?

【问题讨论】:

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


    【解决方案1】:

    我的工作解决方案:working example(基于 Manolis Xountasis 的回答)和这些相关问题的片段:

    1. How to calculate intersection area in Google Maps API with JSTS Library?
    2. Google Maps Polygons self intersecting detection
    • 包括JSTS library
    • 添加例程以将 google.maps.Polyline 路径转换为 ​​JSTS 对象:
    function googleMaps2JTS(boundaries) {
        var coordinates = [];
        var length = 0;
        if (boundaries && boundaries.getLength) length = boundaries.getLength();
        else if (boundaries && boundaries.length) length = boundaries.length;
        for (var i = 0; i < length; i++) {
            if (boundaries.getLength) coordinates.push(new jsts.geom.Coordinate(
            boundaries.getAt(i).lat(), boundaries.getAt(i).lng()));
            else if (boundaries.length) coordinates.push(new jsts.geom.Coordinate(
            boundaries[i].lat(), boundaries[i].lng()));
        }
        return coordinates;
    };
    
    • 然后返回 google.maps.LatLng 数组
    var jsts2googleMaps = function (geometry) {
      var coordArray = geometry.getCoordinates();
      GMcoords = [];
      for (var i = 0; i < coordArray.length; i++) {
        GMcoords.push(new google.maps.LatLng(coordArray[i].x, coordArray[i].y));
      }
      return GMcoords;
    }
    
    directionsService.route(request, function (response, status) {
        if (status == google.maps.DirectionsStatus.OK) {
            directionsDisplay.setDirections(response);
            var overviewPath = response.routes[0].overview_path,
                overviewPathGeo = [];
            for (var i = 0; i < overviewPath.length; i++) {
                overviewPathGeo.push(
                [overviewPath[i].lng(), overviewPath[i].lat()]);
            }
    
            var distance = 10 / 111.12, // Roughly 10km
                geoInput = {
                    type: "LineString",
                    coordinates: overviewPathGeo
                };
            var geoInput = googleMaps2JTS(overviewPath);
            var geometryFactory = new jsts.geom.GeometryFactory();
            var shell = geometryFactory.createLineString(geoInput);
            var polygon = shell.buffer(distance);
    
            var oLanLng = [];
            var oCoordinates;
            oCoordinates = polygon.shell.points[0];
            for (i = 0; i < oCoordinates.length; i++) {
                var oItem;
                oItem = oCoordinates[i];
                oLanLng.push(new google.maps.LatLng(oItem[1], oItem[0]));
            }
            if (routePolygon && routePolygon.setMap) routePolygon.setMap(null);
            routePolygon = new google.maps.Polygon({
                paths: jsts2googleMaps(polygon),
                map: map
            });
        }
    });
    

    【讨论】:

    • shell.buffer(distance) 期望的距离单位是多少?那是怎么计算的? @geocodezip
    • 很高兴了解您如何计算此处的距离?你为什么要在 10/111.12 做?
    • 根据代码中的注释 (var distance = 10 / 111.12, // Roughly 10km) 大约 10 公里 (google.com/#q=km%20per%20degree%20longitude%20km)
    【解决方案2】:

    这是有效的解决方案。你可以找到JSTS files at coderwall.com

    var overviewPath = response.routes[0].overview_path,
    overviewPathGeo = [];
    for (var i = 0; i < overviewPath.length; i++) {
       overviewPathGeo.push(
          [overviewPath[i].lng(), overviewPath[i].lat()]
       );
    }
    
    var distance = value / 10000, // Roughly 10km
    geoInput = {
    type: "LineString",
        coordinates: overviewPathGeo
    };
    var geoReader = new jsts.io.GeoJSONReader(),
        geoWriter = new jsts.io.GeoJSONWriter();
    var geometry = geoReader.read(geoInput).buffer(distance);
    var polygon = geoWriter.write(geometry);
    
    var oLanLng = [];
    var oCoordinates;
    oCoordinates = polygon.coordinates[0];
    for (i = 0; i < oCoordinates.length; i++) {
       var oItem;
       oItem = oCoordinates[i];
       oLanLng.push(new google.maps.LatLng(oItem[1], oItem[0]));
    }
    
    var polygone = new google.maps.Polygon({
        paths: oLanLng,
        map:map
    });
    

    【讨论】:

    • 完美。因为,你没有提供“价值”的价值,我认为distance = 0.001 的距离在路线周围给出了很好的近似多边形
    【解决方案3】:

    这是使用 Turf.js 的缓冲区模块的替代解决方案。我使用 Leaflet 地图来展示结果 - 但这适用于任何映射库。

    var center = [37.78791180770003, -122.40962505340575];
    
    var map = L.map('map').setView(center, 14);;
    
    L.tileLayer(
      'https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png', {
        maxZoom: 18
      }).addTo(map);
    
    
    var line = {
      "type": "Feature",
      "properties": {
        "color": "blue"
      },
      "geometry": {
        "type": "LineString",
        "coordinates": [
          [-122.40447521209718,
            37.79367718768535
          ],
          [-122.40803718566895,
            37.79171022624846
          ],
          [-122.40769386291502,
            37.79096412372944
          ],
          [-122.40662097930908,
            37.789641468930114
          ],
          [-122.40941047668457,
            37.789675383451495
          ],
          [-122.40992546081543,
            37.78875968591083
          ],
          [-122.40962505340575,
            37.78791180770003
          ]
        ]
      }
    };
    
    
    
    L.geoJSON(line, {
      style: function(feature) {
        return {
          color: feature.properties.color
        };
      }
    }).addTo(map);
    
    var polygon = turf.buffer(line, 50, {
      units: 'meters'
    });
    
    L.geoJSON(polygon, {
      style: function(feature) {
        return {
          color: feature.properties.color
        };
      }
    }).addTo(map);
    #map {
      height: 400px;
    }
    <script src="https://npmcdn.com/@turf/turf@6.3.0/turf.min.js"></script>
    <link href="https://cdnjs.cloudflare.com/ajax/libs/leaflet/1.5.1/leaflet.css" rel="stylesheet" />
    <script src="https://cdnjs.cloudflare.com/ajax/libs/leaflet/1.5.1/leaflet.js"></script>
    <div id="map"></div>

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2011-08-12
      • 2013-11-10
      • 1970-01-01
      • 2021-01-16
      • 2019-11-24
      • 1970-01-01
      相关资源
      最近更新 更多