2012-05-22 28 views
12

He creado un mapa de Google y he dibujado una polilínea en él. Luego agregué un marcador al inicio de la poline (los mismos coords que los coords iniciales de la polilínea).Confina el arrastre de Google Maps V3 Marker a Polyline

Lo que me gustaría hacer, es tomar y arrastrar el marcador pero hacer que se "adhiera" a la polilínea de manera que solo se puede arrastrar a lo largo de la polilínea y no hacia un lado.

¿Es posible limitar un marcador arrastrable a una ruta en GM V3? Si no, ¿alguien puede pensar cómo se puede hacer esto? Existe la posibilidad de ajustar el marcador al punto más cercano en la ruta cuando el usuario lo suelta, pero prefiero un efecto más suave de "arrastre a lo largo de la ruta".

Feliz de tener sugerencias de ArcGis también. No he proporcionado el código ya que esto es más una pregunta en teoría.

Avísame si necesito explicarte más.

Gracias de antemano

Respuesta

13

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.

+1

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

0

Gracias por esta solución.

para que funcione sin dependencias, tuve que modificar un par de líneas:

En primer lugar, comprobar el toRad() existe función:

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

Y también , retirar _. la dependencia mediante la sustitución del código de retorno:

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

y, por último, incluye distancias [] antes de distancekeys []

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

Cuestiones relacionadas