限制将Google Maps V3标记拖动到折线 [英] Confine dragging of Google Maps V3 Marker to Polyline

查看:78
本文介绍了限制将Google Maps V3标记拖动到折线的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我已经创建了一个Google Map,并在其上绘制了一条折线.然后,我在多变线的开始处添加了一个标记(与折线的开始座标相同).

我想做的是,抓住并拖动标记,但将其粘在"多段线上,这样您就只能沿着多段线拖动它,而不能将其拖到它的侧面或侧面./p>

是否可以将可拖动标记限制在GM V3中的路径上?如果没有,那么谁能想到可以做到这一点?当用户放下标记时,有可能将标记捕捉到路径上的最近点,但我希望使用更平滑的沿路径拖动"效果.

很高兴也有ArcGis建议.没有提供代码,因为这更多是理论上的问题.

让我知道是否需要进一步解释.

预先感谢

解决方案

好,所以我设法解决了这个问题.它并不完全优雅,我敢肯定它可以改进,但这是我想出的一般概念:

我从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小提琴下面:

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

未经跨浏览器测试.使用最新版本的Chrome.

I've created a Google Map and have drawn a polyline on it. I've then added a marker to the start of the polyine (same coords as the starting coords of the polyline).

What I'd like to be able to do, is grab and drag the marker but have it "stick" to the polyline such that you can only drag it along the polyline and not away or to the side of it.

Is it possible to confine a draggable marker to a path in GM V3? If not, can anyone think how this might be done? There's the possibility of snapping the marker to the nearest point on the path when the user drops it, but I'd prefer a smoother "drag along the path" effect.

Happy to have ArcGis suggestions too. Have not provided code as this is more of an in theory question.

Let me know if I need to explain further.

Thanks in advance

解决方案

Ok so I have managed to solve this. It's not exactly elegant, and I'm sure it could be improved on but here's the general concept I've come up with:

I create an array of latlng points from a GPX file, but they only log points every 20s or so. That's not enough granularity for my purposes so what I did is I padded the array of points with about 10 points (on a linear line) between each pair of points logged by the gpx:

$.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);
        }
    }
});

Now that I have a more refined array of points, I use this to plot a polyline. The padded polyline will look no different to a polyline drawn without the padding, as all of the additional points lie on a linear "as-the-crow-flies" line between the existing points.

var line = new google.maps.Polyline({
    path: polyline_path_points_padded,
    strokeColor: '#ff0000',
    strokeOpacity: 1.0,
    strokeWeight: 2
});
line.setMap(map);

Now I add a draggable marker at the start of the line:

var latLng = new google.maps.LatLng(startlat,startlng);
var marker = new google.maps.Marker({
  position: latLng,
  map: map,
  draggable:true
});

All that's left to do is control the drag and dragend events of this marker:

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

Here we simply send the latLng of the marker to a function find_closest_point_on_path() whilst dragging and when the marker is dropped. We send the padded array of points as a path to search.

The function looks like this:

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];
}

What this function does (with the help of a degrees to radians function) is it finds the distance between the markers position and all of the points on the line. Then it finds the closest point to the marker and returns the coordinates for the very next closest point after that one. This way, when you drag or drop the marker it "snaps" to the next point (rather than getting stuck in one spot).

Working JS Fiddle Below:

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

Have not cross-browser tested. Working in Chrome latest version.

这篇关于限制将Google Maps V3标记拖动到折线的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆