【问题标题】:Confine dragging of Google Maps V3 Marker to Polyline将 Google Maps V3 标记的拖动限制到折线
【发布时间】:2012-05-28 11:48:56
【问题描述】:

我创建了一个谷歌地图并在上面画了一条折线。然后我在折线的开始处添加了一个标记(与折线的起始坐标相同)。

我想做的是抓住并拖动标记,但让它“粘”在多段线上,这样你就只能沿着多段线拖动它,而不能拖到它的旁边或旁边。

是否可以将可拖动标记限制在 GM V3 中的路径上?如果没有,任何人都可以想到如何做到这一点?当用户放下标记时,可能会将标记捕捉到路径上最近的点,但我更喜欢更平滑的“沿路径拖动”效果。

也很高兴收到 ArcGis 建议。没有提供代码,因为这更像是一个理论上的问题。

如果我需要进一步解释,请告诉我。

提前致谢

【问题讨论】:

    标签: draggable google-maps-markers arcgis google-polyline


    【解决方案1】:

    好的,我已经设法解决了这个问题。它不是很优雅,我相信它可以改进,但这是我提出的一般概念:

    我从 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 Fiddle:

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

    尚未跨浏览器测试。使用 Chrome 最新版本。

    【讨论】:

    • 尝试自己在移动平台上解决这个问题,所有这些三角函数对于在每个拖动 tic 上运行的表达式来说有点吓人,我建议计算一个简单的Manhattan distance 应该是准确的在相对规模上足够了,只使用基本的算术运算
    【解决方案2】:

    感谢您提供此解决方案。

    为了让它在没有依赖关系的情况下工作,我不得不修改几行:

    首先,检查 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; 

    【讨论】:

      猜你喜欢
      • 2015-10-27
      • 2014-11-05
      • 2011-05-30
      • 2016-05-29
      • 2014-02-14
      • 1970-01-01
      • 1970-01-01
      • 2010-12-06
      • 1970-01-01
      相关资源
      最近更新 更多