将Google Maps V3标记的拖动限制在折线路径内

13
我已经创建了一个Google地图并在上面绘制了折线。然后我在折线的起点处添加了一个标记(与折线起始坐标相同)。
我想做的是,抓住并拖动标记,但将其“粘”在折线上,以便您只能沿着折线拖动它,而不能离开或移到折线的一侧。
在GM V3中,是否有可能限制可拖动标记到路径上?如果不行,有人能想出怎么做吗?当用户放下标记时,可以将其捕捉到路径上的最近点,但我更喜欢平滑的“沿路径拖动”的效果。
也欢迎提供ArcGIS建议。由于这更多是理论问题,因此没有提供代码。
如果需要进一步解释,请告诉我。
谢谢。
2个回答

13

好的,我已经成功解决了这个问题。虽然不是非常优雅,但我相信它可以改进,以下是我想出的一般概念:

我从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);
        }
    }
});

现在我有一个更精细的点阵,我使用它来绘制折线。填充后的折线看起来与没有填充的折线没有区别,因为所有额外的点都位于现有点之间的线性“直线”上。
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 Fiddle:

http://jsfiddle.net/Z5GwW/4/

还未进行跨浏览器测试。在最新版本的Chrome中工作。


1
尝试在移动平台上解决这个问题,所有那些三角函数对于每次拖动都运行的表达式来说有点可怕,我可以建议计算一个简单的曼哈顿距离,它在相对比例上应该足够准确,并且只使用基本算术运算。 - jmaculate

0

感谢您提供的解决方案。

为了使其在没有依赖项的情况下正常工作,我不得不修改几行代码:

首先,请检查toRad()函数是否存在:

if (typeof(Number.prototype.toRad) === "undefined") {
   Number.prototype.toRad = function() {
     return this * Math.PI / 180;
   }
 }

而且,通过替换返回代码来消除_. 依赖项。

return path_pts[distance_keys[ Math.min(...distances) ]+1];

最后,记得在distancekeys[]前面包含distances[]。

distances[key] = d;
distance_keys[d] = key; 


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接