2012-05-22 15 views
12

Ho creato una mappa di Google e ho disegnato una polilinea su di esso. Ho quindi aggiunto un marcatore all'inizio della polina (stesse coordinate delle coordinate iniziali della polilinea).Confine trascinamento di Google Maps V3 Marker su Polyline

Quello che mi piacerebbe essere in grado di fare, è afferrare e trascinare il marcatore ma farlo "attaccare" alla polilinea in modo tale che si possa trascinarlo lungo la polilinea e non lontano o lateralmente.

È possibile limitare un indicatore trascinabile a un percorso in GM V3? In caso contrario, qualcuno può pensare a come questo potrebbe essere fatto? C'è la possibilità di far scattare il marcatore sul punto più vicino sul percorso quando l'utente lo lascia cadere, ma preferirei un effetto "trascinamento lungo il percorso" più agevole.

Felice di avere anche i suggerimenti di ArcGis. Non ho fornito il codice in quanto si tratta più di una domanda teorica.

Fammi sapere se devo spiegare ulteriormente.

Grazie in anticipo

risposta

13

Ok così mi sono riusciti a risolvere questo problema. Non è esattamente elegante, e sono sicuro che potrebbe essere migliorato, ma ecco il concetto generale che ho trovato:

Creo una matrice di punti di latlng da un file GPX, ma registrano solo i punti ogni 20s o così. Non è abbastanza granularità per i miei scopi in modo da quello che ho fatto è che ho imbottiti la matrice di punti con circa 10 punti (su una linea retta) tra ogni coppia di punti registrati dal 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); 
     } 
    } 
}); 

Ora che ho un Array di punti più raffinato, lo uso per tracciare una polilinea. La polilinea imbottita non apparirà diversa da una polilinea disegnata senza il padding, poiché tutti i punti aggiuntivi si trovano su una linea lineare "as-the-crow-mosche" tra i punti esistenti.

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

Ora aggiungo un indicatore trascinabile all'inizio della riga:

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

Tutto quello che resta da fare è controllare la resistenza e dragend eventi di questo indicatore:

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

Qui semplicemente inviamo la latLng del marker a una funzione find_closest_point_on_path() durante il trascinamento e quando il marker viene rilasciato. Inviamo l'array di punti riempito come percorso per la ricerca.

La funzione è simile al seguente:

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

Cosa questa funzione fa (con l'aiuto di un gradi di funzionare radianti) è che trova la distanza tra la posizione di marcatori e tutti i punti sulla linea. Quindi trova il punto più vicino al marcatore e restituisce le coordinate per il prossimo punto più vicino dopo quello. In questo modo, quando trascini o rilasci il marcatore "scatta" al punto successivo (invece di rimanere bloccato in un punto).

lavoro JS Fiddle In basso:

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

non sono cross-browser testati. Funzionando nella versione più recente di Chrome.

+1

cercando di affrontare questo problema io stesso su una piattaforma mobile, tutte quelle funzioni trigonometriche sono un po 'spaventose per un'espressione che gira o n ogni drag tic, potrei suggerire di calcolare una semplice [Manhattan distance] (http://en.wikipedia.org/wiki/Taxicab_geometry) che dovrebbe essere sufficientemente accurata su una scala relativa e utilizza solo operazioni aritmetiche di base – jmaculate

0

Grazie per questa soluzione.

a farlo funzionare senza le dipendenze, ho dovuto modificare un paio di righe:

In primo luogo, controllare il toRad() esiste la funzione:

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

E anche , rimuovere _. la dipendenza sostituendo il codice di ritorno:

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

e, infine, includono distanze [] prima distancekeys []

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

Problemi correlati