Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Curved line between two near points in google maps [closed]

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.

like image 912
zesk8 Avatar asked Dec 02 '13 04:12

zesk8


People also ask

Why are lines on a map curved?

In a map the curve of the earth is represented on a flat surface. This makes the longitude lines appear straight. In reality the earth is curved so the longitude lines must also curve. this is way the longitude lines can not be straight.

Why does Google Earth have curved lines?

Our locator maps use the Mercator projection. This works well for zoomed-in maps, but if you're showing entire continents the map will be distorted a lot. And because of this distortion, the straight line on a globe becomes an arc on a Mercator map.

Can I draw a radius on Google Maps?

Click on the map and create a popup marker to select the point. From there, opt for the “Draw Radius.” Choose the proximity distance from the given address found within the radius options in the software.


2 Answers

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);
    });
});
like image 162
bewi Avatar answered Nov 15 '22 18:11

bewi


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

like image 27
nilveryboring Avatar answered Nov 15 '22 17:11

nilveryboring