Конфигурировать перетаскивание маркера V3 на Карты Google для полилинии

Я создал карту Google и нарисовал полилинию. Затем я добавил маркер к началу полиины (такие же коорды, что и стартовые координаты полилинии).

То, что я хотел бы сделать, - это захватить и перетащить маркер, но он "прилипает" к полилинии, так что вы можете только перетаскивать ее вдоль полилинии, а не в сторону или в сторону от нее.

Можно ли ограничить перетаскиваемый маркер на путь в GM V3? Если нет, может кто-нибудь подумать, как это можно сделать? Там есть возможность привязать маркер к ближайшей точке пути, когда пользователь его сбросит, но я предпочел бы более плавный эффект "перетащить путь".

У нас также есть предложения ArcGis. Не предоставили код, так как это более теоретический вопрос.

Сообщите мне, если мне нужно объяснить далее.

Заранее спасибо

Ответы

Ответ 1

Хорошо, поэтому мне удалось это решить. Это не совсем элегантно, и я уверен, что его можно было бы улучшить, но вот общая концепция, которую я придумал:

Я создаю массив точек latlng из файла GPX, но они регистрируют только точки каждые 20 или около того. Это недостаточная гранулярность для моих целей, так что я сделал, я заполнил массив точек примерно с 10 точками (по линейной линии) между каждой парой точек, занесенных в журнал 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);
        }
    }
});

Теперь, когда у меня есть более четкий массив точек, я использую это для построения полилинии. Проложенная полилиния не будет выглядеть иначе, чем полилиния, нарисованная без прокладки, так как все дополнительные точки лежат на линейной линии "как ворона" между существующими точками.

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.

Ответ 2

Благодарим вас за это решение.

Чтобы заставить его работать без зависимостей, мне пришлось изменить пару строк:

Сначала проверьте, существует ли функция toRad():

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