好的,所以我设法解决了这个问题。它并不完全优雅,我相信它可以改进,但这是我提出的一般概念:
我从 GPX 文件创建了一个 latlng 点数组,但它们仅每 20 秒左右记录一次点。这对我的目的来说粒度不够,所以我所做的是在 gpx 记录的每对点之间用大约 10 个点(在一条直线上)填充点数组:
$.each(array_of_points_to_pad, function(key, pt) {
var current_point = pt;//The current point
var next_point = array_of_points_to_pad[key + 1];//The point immediately after the current point
//Check that we're not on the last point
if (typeof next_point !== 'undefined') {
//Get a 10th of the difference in latitude between current and next points
var lat_incr = (next_point.lat() - current_point.lat()) / 10;
//Get a 10th of the difference in longitude between current and next points
var lng_incr = (next_point.lng() - current_point.lng()) / 10;
//Add the current point to a new padded_points array
padded_points.push(current_point);
//Now add 10 additional points at lat_incr & lng_incr intervals between current and next points (in the new padded_points array)
for (var i = 1; i <= 10; i++) {
var new_pt = new google.maps.LatLng(current_point.lat() + (i * lat_incr), current_point.lng() + (i * lng_incr));
padded_points.push(new_pt);
}
}
});
现在我有了更精细的点数组,我用它来绘制折线。填充的折线看起来与没有填充的折线没有什么不同,因为所有附加点都位于现有点之间的线性“as-the-crow-flies”线上。
var line = new google.maps.Polyline({
path: polyline_path_points_padded,
strokeColor: '#ff0000',
strokeOpacity: 1.0,
strokeWeight: 2
});
line.setMap(map);
现在我在行首添加一个可拖动的标记:
var latLng = new google.maps.LatLng(startlat,startlng);
var marker = new google.maps.Marker({
position: latLng,
map: map,
draggable:true
});
剩下要做的就是控制这个标记的拖动和拖动事件:
google.maps.event.addDomListener(marker,'dragend',function(e){
marker.setPosition(find_closest_point_on_path(e.latLng,padded_points));
});
google.maps.event.addDomListener(marker,'drag',function(e){
marker.setPosition(find_closest_point_on_path(e.latLng,padded_points));
});
在这里,我们只是在拖动和放下标记时将标记的 latLng 发送到函数 find_closest_point_on_path()。我们将填充的点数组作为搜索路径发送。
该函数如下所示:
function find_closest_point_on_path(marker_pt,path_pts){
distances = new Array();
distance_keys = new Array();
$.each(path_pts,function(key, path_pt){
var R = 6371; // km
var dLat = (path_pt.lat()-marker_pt.lat()).toRad();
var dLon = (path_pt.lng()-marker_pt.lng()).toRad();
var lat1 = marker_pt.lat().toRad();
var lat2 = path_pt.lat().toRad();
var a = Math.sin(dLat/2) * Math.sin(dLat/2) +
Math.sin(dLon/2) * Math.sin(dLon/2) * Math.cos(lat1) * Math.cos(lat2);
var c = 2 * Math.atan2(Math.sqrt(a), Math.sqrt(1-a));
var d = R * c;
//Store the key of the point on the path that matches this distance
distance_keys[d] = key;
});
//Return the latLng pt on the path for the second closest point
return path_pts[distance_keys[_.min(distances)]+1];
}
这个函数的作用(借助度数到弧度函数)是找到标记位置和线上所有点之间的距离。然后它找到离标记最近的点,并返回紧随其后的下一个最近点的坐标。这样,当您拖放标记时,它会“捕捉”到下一个点(而不是卡在一个点上)。
下面的工作JS小提琴:
http://jsfiddle.net/Z5GwW/4/
没有跨浏览器测试。在 Chrome 最新版本中工作。