11

Is possible to draw a curve line (like a geodesic line) between 2 near points in google maps, for example with these coordinates:

p1 = (23.634501, -102.552783)

p2 = (17.987557, -92.929147)

Is there a javascript library to do it? and is possible to control the curvature of the line?

Thanks.

zesk8
  • 181
  • 1
  • 2
  • 7
  • This question seems to relevant to yours - http://stackoverflow.com/questions/13433648/draw-a-line-between-two-point-on-a-google-map-using-jquery. – Austin Brunkhorst Dec 02 '13 at 04:46
  • Thanks, but I know that "geodesic:true" makes geodesic lines, but that not works when the distance between 2 points is closer and I want to know if exits another way to do it – zesk8 Dec 02 '13 at 05:12
  • There's now a native boolean "geodesic" option in the Google Maps Polyline which does this automatically: https://developers.google.com/maps/documentation/javascript/reference/polygon#PolylineOptions.geodesic – Chris Han Aug 13 '19 at 16:19

2 Answers2

28

I figured out another solution just recently which does not need polylines but rather uses the path value for marker icons which can be calculated on the fly.

In a nutshell: you simply create an SVG path string for a quadratic bezier curve from 0 to p2 - p1 and attach it as a marker icon to p1.

Long version: The pixel coordinates within the container can be obtained invoking google.maps.Projection.fromLatLngToContainerPixel(). The string for a quadratic bezier curve looks like this:

M [startX] [startY] q [controlX] [controlY] [endX] [endY]

We’ll choose (0,0) for the start point, since the marker will by later placed at that point. The relative position of p2 is now e = (p2.x - p1.x, p2.y - p1.y), and the relative position of the point half way between them is m = (e.x/2, e.y/2). An orthogonal vector to e is o = s * norm(-e.x / e.y, 1), where s is some scaling factor with s = |e|/4 beeing a good starting point. We now have the control point with c = (m.x + o.x, m.y + o.y) and the path is:

path = „M 0 0 q c.x c.y e.x e.y“

Now that we have that path, we can simply declare an icon:

var icon = {
    path : path,
    fillOpacity : 0,//important
    scale : 1,
    strokeOpacity: //yours,
    strokeColor : //yours,
    strokeWeight : //yours,
    clickable : false //important
};

Setting clickable to false is essential, because otherwise the area enclosed by the curve becomes clickable and the underlying map won’t recieve the mouse events. Now we can add a marker to the map with the path icon as a parameter and the position of p1:

var marker = new google.maps.Marker({
    position : p1,
    icon : icon,
    map : map,
    clickable : false,
    zIndex : -100 //make the line appear behind ‚real’ markers
});

A few things to note:

  • the sign of scaling factor of the orthogonal o determines the „direction“ of the arc („above“ or „below“ e)
  • If the zoom level changes, you have to adjust the scaling of the icons like this: marker.icon.scale = 1 / 2^(initialZoom - currentZoom) there is no need to recalculate the path.

Sample:

Sample of bezier curves on google maps

jsfiddle with hardcoded example using original question's points

relevant code:

var p1 = new google.maps.LatLng(23.634501, -102.552783);
var p2 = new google.maps.LatLng(17.987557, -92.929147);

var markerP1 = new google.maps.Marker({
    position: p1,
    map: map
});
var markerP2 = new google.maps.Marker({
    position: p2,
    map: map
});
google.maps.event.addListener(map, 'projection_changed', function () {
    var p1 = map.getProjection().fromLatLngToPoint(markerP1.getPosition());
    var p2 = map.getProjection().fromLatLngToPoint(markerP2.getPosition());
    var e = new google.maps.Point(p1.x - p2.x, p1.y - p2.y);
    var m = new google.maps.Point(e.x / 2, e.y / 2);
    var o = new google.maps.Point(0, 7);
    var c = new google.maps.Point(m.x + o.x, m.y + o.y);
    var curveMarker2 = new google.maps.Marker({
        position: markerP1.getPosition(),
        icon: {
            path: "M 0 0 q " + c.x + " " + c.y + " " + e.x + " " + e.y,
            scale: 24,
            strokeWeight: 2,
            fillColor: '#009933',
            fillOpacity: 0,
            rotation: 180,
            anchor: new google.maps.Point(0, 0)
        }
    });
    curveMarker2.setMap(map);
    google.maps.event.addListener(map, 'zoom_changed', function () {
        var zoom = map.getZoom();
        var scale = 1 / (Math.pow(2, -zoom));
        var icon = {
            path: "M 0 0 q " + c.x + " " + c.y + " " + e.x + " " + e.y,
            scale: scale,
            strokeWeight: 2,
            fillColor: '#009933',
            fillOpacity: 0,
            rotation: 180,
            anchor: new google.maps.Point(0, 0)
        };
        curveMarker2.setIcon(icon);
    });
});
geocodezip
  • 158,664
  • 13
  • 220
  • 245
bewi
  • 321
  • 3
  • 9
  • 1
    [fiddle with a hard coded example](http://jsfiddle.net/bfer8e0b/2/) – geocodezip Feb 04 '15 at 04:54
  • 2
    added the relevant code to this answer, plus a link to a working jsfiddle with the original points. – geocodezip Feb 04 '15 at 13:21
  • 8
    Here's an [updated fiddle](http://jsfiddle.net/medmunds/sd10up9t/) that calculates the orthogonal (it's hard-coded in the current example). It also has draggable markers, so you can test it with different points and zooms. – medmunds Apr 25 '15 at 23:22
  • I'm trying to figure out how to get this working with an array of end points. Where P1 is an origin with P2 and P3 both as 2 individual (not connected) destinations. Any suggestions how I would go about this? – Eddie A. May 15 '15 at 19:42
  • How were you able to add that arrow in the middle. I am getting curved lines but I can't think of a way to get an arrow head at the center of the line. – echo_salik May 09 '19 at 09:29
  • There's now a boolean "geodesic" option in the Google Maps Polyline which does this automatically: https://developers.google.com/maps/documentation/javascript/reference/polygon#PolylineOptions.geodesic – Chris Han Aug 13 '19 at 16:19
  • This is amazing. I was wondering (not trying to pick holes) if there is any way to make the path move "smoothly" when zooming rather than the sudden jump - like is there an "onupdatingzoom" type of scenario? – Jarrod McGuire Sep 22 '19 at 11:32
6

Here are the Libraries I found

http://curved_lines.overfx.net/ Dead link

http://www.geocodezip.com/v3_polyline_example_rhumb.html

http://www.geocodezip.com/v3_polyline_example_arc.html

Actually I just found that Google map Polyline takes in a list of point to construct. So u can pass in multiple points to make the line looks curved.

PS: u can use the draw arc function in the 2 links below to get the list of points for drawing

Roko C. Buljan
  • 196,159
  • 39
  • 305
  • 313
nilveryboring
  • 653
  • 1
  • 9
  • 18