1

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>

After reading here and there, I tried using solution from geocodezip here

I wanted to add arrow end direction between two points and I ended up adding extra code like this

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

How do I adjust correctly the heading arrow pointing direction because of the curved line? Thanks in advance.

geocodezip
  • 158,664
  • 13
  • 220
  • 245
Ardeus
  • 1,921
  • 3
  • 17
  • 26

1 Answers1

3

You can use a curved polyline, using original Belzier Curve code from nicoabie's answer to this question on StackOverflow: Letting users draw curved lines on a google map?.

Add the icon at the end:

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

it will be automatically adjusted to point the correct direction (example in the documentation)

proof of concept fiddle

screenshot of resulting map

code snippet:

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>
geocodezip
  • 158,664
  • 13
  • 220
  • 245