Ok por lo que han logrado resolver esto. No es exactamente elegante, y estoy seguro de que podría mejorarse, pero aquí está el concepto general que se me ocurrió:
Creo una serie de puntos latlng de un archivo GPX, pero solo registran puntos cada 20 s. más o menos. Eso no es suficiente granularidad para mis propósitos así que lo que hizo es que acolchada la matriz de puntos con cerca de 10 puntos (en una línea lineal) entre cada par de puntos registrados por el 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);
}
}
});
Ahora que tengo una conjunto más refinado de puntos, lo uso para trazar una polilínea. La polilínea acolchada no se verá diferente de una polilínea dibujada sin el relleno, ya que todos los puntos adicionales se encuentran en una línea lineal "vuela en línea recta" entre los puntos existentes.
var line = new google.maps.Polyline({
path: polyline_path_points_padded,
strokeColor: '#ff0000',
strokeOpacity: 1.0,
strokeWeight: 2
});
line.setMap(map);
Ahora agrego un marcador que pueden arrastrarse en el inicio de la línea:
var latLng = new google.maps.LatLng(startlat,startlng);
var marker = new google.maps.Marker({
position: latLng,
map: map,
draggable:true
});
Todo lo que queda por hacer es controlar los eventos de arrastre y dragend de este marcador:
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));
});
Aquí simplemente enviamos el latLng del marcador a una función find_closest_point_on_path() mientras arrastramos y cuando el marcador se descarta. Enviamos la matriz acolchada de puntos como un camino para buscar.
La función tiene el siguiente aspecto:
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];
}
Lo que hace esta función (con la ayuda de unos grados a la función radianes) es que encuentre la distancia entre la posición de los marcadores y todos los puntos de la línea. Luego encuentra el punto más cercano al marcador y devuelve las coordenadas para el siguiente punto más cercano después de ese. De esta forma, cuando arrastra o suelta el marcador, "se ajusta" al siguiente punto (en lugar de quedar atascado en un punto).
Trabajo JS violín continuación:
http://jsfiddle.net/Z5GwW/4/
no hemos probado varios navegadores. Trabajando en la última versión de Chrome.
tratando de resolver este problema a mí mismo en una plataforma móvil, todas esas funciones trigonométricas son un poco aterradoras para una expresión que se ejecuta o En cada tic de arrastre, sugiero que se calcule una simple [distancia de Manhattan] (http://en.wikipedia.org/wiki/Taxicab_geometry), que debería ser lo suficientemente precisa en una escala relativa y solo utilizar operaciones aritméticas básicas. – jmaculate