Yermo Lamers
Yermo Lamers

Reputation: 1951

Using leaflet mapping api, how do you determine which point in a polyline was clicked on?

I'm using the Leaflet mapping API. I would like to determine which point in a polyline has been clicked on. The polyline is one that I have rendered using the Directions services from MapQuest Open.

The relevant code is:

for ( var i = 0; i < latlngs.length; i++ )
   {

   // the equals method uses a small fudge factor to decide if the two 
   // points are the same.

   if ( latlng.equals( latlngs[ i ] ))
      {
      return i;
      }
   }

.equals() is supposed to compare points with a fudge factor. When I click on the polyline I get an event with lat/lngs like:

'38.83966582989183','-77.0083075761795' 

My lat/lngs in the polyline are of less precision as in:

'38.841289','-77.008842' 

So as I loop through looking for a match equals() never returns true. Clearly, the click event is firing, so leaflet knows I've clicked the polyline, but there doesn't seem to be a clean way of getting the actual offset of the latlng that was clicked on.

I'm considering just reducing the precision returned from the mouse click, but that doesn't "feel" like the right solution.

Any help/pointers would be greatly appreciated.

EDIT:

Setting L.LatLng.MAX_MARGIN to 1.0E-3 seems to work but that seems like a very coarse margin.

Upvotes: 3

Views: 2105

Answers (2)

Seryh
Seryh

Reputation: 3294

My code for leaflet:

var _getClosestPointIndex = function(lPoint, arrayLPoints) {
    var distanceArray = [];
    for ( var i = 0; i < arrayLPoints.length; i++ ) {
        distanceArray.push( lPoint.distanceTo(arrayLPoints[i]) );
    }
    return distanceArray.indexOf(  Math.min.apply(null, distanceArray) );
};    

var polyLine = L.polyline(arrayLatLngCollection, lineOpt);
        polyLine.addEventListener('click dblclick', function(e) {
            var index = _getClosestPointIndex(e.latlng, arrayLatLngCollection);
            var popup = L.popup()
                .setLatLng(new L.latLng(arrayLatLngCollection[index]))
                .setContent('<p>Hello world!<br />This is a nice popup.</p>')
                .openOn(self.map);
});

Upvotes: 4

Yermo Lamers
Yermo Lamers

Reputation: 1951

I've come up with an solution that is probably not coture but seems to work. I notice that there is a _originalPoints array in the polyline. There is also layerPoint member in the polyline event that is a Point object.

I'm not a fan of using undocumented APIs but looping through the points finding the closest point to the clicked point, using the L.LineUtil.pointToSegmentDistance seems to work as in:

    var point = e.layerPoint;

var points = polyline._originalPoints;

for ( var i = 0; i < points.length; i++ )
    {

    if ( i < points.length - 2 )
        {

        if ( min_distance > L.LineUtil.pointToSegmentDistance( point, points[i], points[ i + 1] ) )
            {
            min_distance = L.LineUtil.pointToSegmentDistance( point, points[i], points[ i + 1] );
            min_offset = i;
            }

        }

    }

Upvotes: 1

Related Questions