代码之家  ›  专栏  ›  技术社区  ›  Ardeus

google地图api javascript曲线和箭头端

  •  1
  • Ardeus  · 技术社区  · 6 年前

    var map;
    
    var curvature = 0.5; // how curvy to make the arc
    
    function init() {
      var Map = google.maps.Map,
        LatLng = google.maps.LatLng,
        LatLngBounds = google.maps.LatLngBounds,
        Marker = google.maps.Marker,
        Point = google.maps.Point;
    
      // This is the initial location of the points
      // (you can drag the markers around after the map loads)
      var pos1 = new LatLng(23.634501, -102.552783);
      var pos2 = new LatLng(17.987557, -92.929147);
    
      var bounds = new LatLngBounds();
      bounds.extend(pos1);
      bounds.extend(pos2);
    
      map = new Map(document.getElementById('map-canvas'), {
        center: bounds.getCenter(),
        zoom: 12
      });
      map.fitBounds(bounds);
    
      var markerP1 = new Marker({
        position: pos1,
        label: "1",
        draggable: true,
        map: map
      });
      var markerP2 = new Marker({
        position: pos2,
        label: "2",
        draggable: true,
        map: map
      });
    
      var curveMarker;
      var endArrowMarker;
    
      function updateCurveMarker() {
        var pos1 = markerP1.getPosition(), // latlng
          pos2 = markerP2.getPosition(),
          projection = map.getProjection(),
          p1 = projection.fromLatLngToPoint(pos1), // xy
          p2 = projection.fromLatLngToPoint(pos2);
    
        // Calculate the arc.
        // To simplify the math, these points 
        // are all relative to p1:
        var e = new Point(p2.x - p1.x, p2.y - p1.y), // endpoint (p2 relative to p1)
          m = new Point(e.x / 2, e.y / 2), // midpoint
          o = new Point(e.y, -e.x), // orthogonal
          c = new Point( // curve control point
            m.x + curvature * o.x,
            m.y + curvature * o.y);
    
        var pathDef = 'M 0,0 ' +
          'q ' + c.x + ',' + c.y + ' ' + e.x + ',' + e.y;
    
        var zoom = map.getZoom(),
          scale = 1 / (Math.pow(2, -zoom));
    
        var symbol = {
          path: pathDef,
          scale: scale,
          strokeWeight: 2,
          fillColor: 'none'
        };
    
        if (!curveMarker) {
          curveMarker = new Marker({
            position: pos1,
            clickable: false,
            icon: symbol,
            zIndex: 0, // behind the other markers
            map: map
          });
        } else {
          curveMarker.setOptions({
            position: pos1,
            icon: symbol,
          });
        }
    
        var heading = google.maps.geometry.spherical.computeHeading(pos1, pos2);
    
        var directionIcon = {
          path: google.maps.SymbolPath.FORWARD_OPEN_ARROW,
          scale: 5,
          rotation: heading
        };
        if (!endArrowMarker) {
          endArrowMarker = new Marker({
            position: pos2,
            clickable: false,
            icon: directionIcon,
            map: map
          });
        } else {
          endArrowMarker.setIcon(directionIcon);
        }
      }
    
      google.maps.event.addListener(map, 'projection_changed', updateCurveMarker);
      google.maps.event.addListener(map, 'zoom_changed', updateCurveMarker);
    
      google.maps.event.addListener(markerP1, 'position_changed', updateCurveMarker);
      google.maps.event.addListener(markerP2, 'position_changed', updateCurveMarker);
    }
    
    google.maps.event.addDomListener(window, 'load', init);
    html,
    body,
    #map-canvas {
      height: 100%;
      width: 100%;
      margin: 0px;
      padding: 0px
    }
    <script src="https://maps.googleapis.com/maps/api/js?sensor=false&libraries=geometry,places&ext=.js"></script>
    <script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
    <div id="map-canvas" style="border: 2px solid #3872ac;"></div>

    在阅读了这里和那里之后,我尝试使用geocodezip的解决方案 here

    我想在两点之间添加箭头结束方向,结果添加了如下额外代码

    var heading = google.maps.geometry.spherical.computeHeading(pos1, pos2);
    
    var directionIcon = {
      path: google.maps.SymbolPath.FORWARD_OPEN_ARROW,
      scale: 5,
      rotation: heading
    };
    if (!endArrowMarker) {
      endArrowMarker = new Marker({
        position: pos2,
        clickable: false,
        icon: directionIcon,
        map: map
      });
    } else {
      endArrowMarker.setIcon(directionIcon);
    }
    

    jsfiddle

    由于曲线的存在,如何正确调整指向方向的方向箭头?提前谢谢。

    1 回复  |  直到 6 年前
        1
  •  2
  •   geocodezip    6 年前

    可以使用曲线多段线,使用nicoabie在stackoverflow上回答此问题时的原始belzier曲线代码: Letting users draw curved lines on a google map? 是的。

    在末尾添加图标:

    icons: [{
      icon: {
        path: google.maps.SymbolPath.FORWARD_OPEN_ARROW,
        scale: 5,
      },
      offset: '100%'
    }],
    

    它将自动调整以指向正确的方向( example in the documentation )

    proof of concept fiddle

    screenshot of resulting map

    代码段:

    var map;
    
    var curvature = 0.5; // how curvy to make the arc
    
    function init() {
      var Map = google.maps.Map,
        LatLng = google.maps.LatLng,
        LatLngBounds = google.maps.LatLngBounds,
        Marker = google.maps.Marker,
        Point = google.maps.Point;
    
      var pos1 = new LatLng(23.634501, -102.552783);
      var pos2 = new LatLng(17.987557, -92.929147);
    
      var bounds = new LatLngBounds();
      bounds.extend(pos1);
      bounds.extend(pos2);
    
      map = new Map(document.getElementById('map-canvas'), {
        center: bounds.getCenter(),
        zoom: 12
      });
      map.fitBounds(bounds);
    
      var markerP1 = new Marker({
        position: pos1,
        label: "1",
        draggable: false,
        map: map
      });
      var markerP2 = new Marker({
        position: pos2,
        label: "2",
        draggable: false,
        map: map
      });
      drawCurve(pos2, pos1, map);
      drawCurve(new google.maps.LatLng(19.4326077, -99.133208), new google.maps.LatLng(19.173773, -96.1342240), map);
    }
    
    google.maps.event.addDomListener(window, 'load', init);
    
    function drawCurve(P1, P2, map) {
      var lineLength = google.maps.geometry.spherical.computeDistanceBetween(P1, P2);
      var lineHeading = google.maps.geometry.spherical.computeHeading(P1, P2);
      var lineHeading1, lineHeading2;
      if (lineHeading < 0) {
        lineHeading1 = lineHeading + 45;
        lineHeading2 = lineHeading + 135;
      } else {
        lineHeading1 = lineHeading + -45;
        lineHeading2 = lineHeading + -135;
      }
      var pA = google.maps.geometry.spherical.computeOffset(P1, lineLength / 2.2, lineHeading1);
      var pB = google.maps.geometry.spherical.computeOffset(P2, lineLength / 2.2, lineHeading2);
    
      var curvedLine = new GmapsCubicBezier(P1, pA, pB, P2, 0.01, map);
    }
    
    // original Belzier Curve code from nicoabie's answer to this question on StackOverflow:
    // http://stackoverflow.com/questions/5347984/letting-users-draw-curved-lines-on-a-google-map
    var GmapsCubicBezier = function(latlong1, latlong2, latlong3, latlong4, resolution, map) {
      var lat1 = latlong1.lat();
      var long1 = latlong1.lng();
      var lat2 = latlong2.lat();
      var long2 = latlong2.lng();
      var lat3 = latlong3.lat();
      var long3 = latlong3.lng();
      var lat4 = latlong4.lat();
      var long4 = latlong4.lng();
    
      var points = [];
    
      for (it = 0; it <= 1; it += resolution) {
        points.push(this.getBezier({
          x: lat1,
          y: long1
        }, {
          x: lat2,
          y: long2
        }, {
          x: lat3,
          y: long3
        }, {
          x: lat4,
          y: long4
        }, it));
      }
      var path = [];
      for (var i = 0; i < points.length - 1; i++) {
        path.push(new google.maps.LatLng(points[i].x, points[i].y));
        path.push(new google.maps.LatLng(points[i + 1].x, points[i + 1].y, false));
      }
    
      var Line = new google.maps.Polyline({
        path: path,
        geodesic: true,
        strokeColor: "##35495e",
        strokeOpacity: 0.8,
        strokeWeight: 3,
        icons: [{
          icon: {
            path: google.maps.SymbolPath.FORWARD_OPEN_ARROW,
            scale: 5,
          },
          offset: '100%'
        }],
      });
    
      Line.setMap(map);
    
      return Line;
    };
    
    
    GmapsCubicBezier.prototype = {
    
      B1: function(t) {
        return t * t * t;
      },
      B2: function(t) {
        return 3 * t * t * (1 - t);
      },
      B3: function(t) {
        return 3 * t * (1 - t) * (1 - t);
      },
      B4: function(t) {
        return (1 - t) * (1 - t) * (1 - t);
      },
      getBezier: function(C1, C2, C3, C4, percent) {
        var pos = {};
        pos.x = C1.x * this.B1(percent) + C2.x * this.B2(percent) + C3.x * this.B3(percent) + C4.x * this.B4(percent);
        pos.y = C1.y * this.B1(percent) + C2.y * this.B2(percent) + C3.y * this.B3(percent) + C4.y * this.B4(percent);
        return pos;
      }
    };
    html,
    body,
    #map-canvas {
      height: 98%;
      width: 98%;
      margin: 0px;
      padding: 0px;
    }
    <script src="https://maps.googleapis.com/maps/api/js?libraries=geometry&key=AIzaSyCkUOdZ5y7hMm0yrcCQoCvLwzdM6M8s5qk"></script>
    <script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
    <div id="map-canvas" style="border: 2px solid #3872ac;"></div>