2017-09-18 1 views
2

Ich habe versucht, den Punkt der Markierung in vordefinierten Punkten (Breiten/Längen), die im Array "Polypath" in dem Beispiel, so dass der Marker zu gehen nächsten Punkt entlang Polylinie, so kann ich den ausgewählten Punkt zu einer anderen Berechnung verwenden.Google Maps API - Draggable Marker Entlang Polylinie in den definierten Punkten

Dieser Code zeigt das aktuelle Verhalten in den Benutzer die Markierung halten kann, wo immer er in der Polylinie will:

var gmap; 
 
var currentMarker = new google.maps.Marker({ 
 
      position: new google.maps.LatLng(54.13512, -117.0114), 
 
      draggable: true 
 
     }); 
 
var snapToRoute = null; 
 
var polypath = new Array(
 
     new google.maps.LatLng(54.13512, -117.0114), 
 
     new google.maps.LatLng(54.13353, -117.01141), 
 
     new google.maps.LatLng(54.1332, -117.01159), 
 
     new google.maps.LatLng(54.13241, -117.01157), 
 
     new google.maps.LatLng(54.13217, -117.01142), 
 
     new google.maps.LatLng(54.12725, -117.01143), 
 
     new google.maps.LatLng(54.12185, -117.00125), 
 
     new google.maps.LatLng(54.1188, -116.9955), 
 
     new google.maps.LatLng(54.11603, -116.99473), 
 
     new google.maps.LatLng(54.11517, -116.99281), 
 
     new google.maps.LatLng(54.10235, -116.97771), 
 
     new google.maps.LatLng(54.10244, -116.96093), 
 
     new google.maps.LatLng(54.10197, -116.96067), 
 
     new google.maps.LatLng(54.10158, -116.96075), 
 
     new google.maps.LatLng(54.09808, -116.95913), 
 
     new google.maps.LatLng(54.09725, -116.95668), 
 
     new google.maps.LatLng(54.09669, -116.95598), 
 
     new google.maps.LatLng(54.08378, -116.9471), 
 
     new google.maps.LatLng(54.08218, -116.94696), 
 
     new google.maps.LatLng(54.07374, -116.93832), 
 
     new google.maps.LatLng(54.07319, -116.93571), 
 
     new google.maps.LatLng(54.07185, -116.93527)); 
 
     
 
    var polyline = new google.maps.Polyline({ 
 
\t \t \t \t path: polypath, 
 
\t \t \t \t strokeColor: "red", 
 
\t \t \t \t strokeWeight: 2, 
 
\t \t \t \t strokeOpacity: 1 
 
\t \t \t }); 
 

 
function initialize() { 
 
    gmap = new google.maps.Map(
 
    document.getElementById("map_canvas"), { 
 
     center: new google.maps.LatLng(54.10244, -116.96093), 
 
     zoom: 12 
 
    }); 
 
    
 
    
 
    currentMarker.setMap(gmap); 
 
    polyline.setMap(gmap); 
 
    
 
    
 
    snapToRoute = new SnapToRoute(gmap, currentMarker, polyline); 
 
} 
 

 
google.maps.event.addDomListener(window, "load", initialize); 
 

 
function SnapToRoute(map, marker, polyline) { 
 
    this.routePixels_ = []; 
 
    this.normalProj_ = map.getProjection(); 
 
    this.map_ = map; 
 
    this.marker_ = marker; 
 
    this.polyline_ = polyline; 
 

 
    this.init_(); 
 
} 
 

 
SnapToRoute.prototype.init_ = function() { 
 
    this.loadLineData_(); 
 
    this.loadMapListener_(); 
 
}; 
 

 
SnapToRoute.prototype.updateTargets = function (marker, polyline) { 
 
    this.marker_ = marker || this.marker_; 
 
    this.polyline_ = polyline || this.polyline_; 
 
    this.loadLineData_(); 
 
}; 
 

 
SnapToRoute.prototype.loadMapListener_ = function() { 
 
    var me = this; 
 

 
    google.maps.event.addListener(me.marker_, "dragend", function (evt) { 
 
     me.updateMarkerLocation_(evt.latLng); 
 
    }); 
 

 
    google.maps.event.addListener(me.marker_, "drag", function (evt) { 
 
     me.updateMarkerLocation_(evt.latLng); 
 
    }); 
 

 
    google.maps.event.addListener(me.map_, "zoomend", function (evt) { 
 
     me.loadLineData_(); 
 
    }); 
 
}; 
 

 
SnapToRoute.prototype.loadLineData_ = function() { 
 
    var zoom = this.map_.getZoom(); 
 
    this.routePixels_ = []; 
 
    var path = this.polyline_.getPath(); 
 
    for (var i = 0; i < path.getLength(); i++) { 
 
     var Px = this.normalProj_.fromLatLngToPoint(path.getAt(i)); 
 
     this.routePixels_.push(Px); 
 
    } 
 
}; 
 

 
SnapToRoute.prototype.updateMarkerLocation_ = function (mouseLatLng) { 
 
    var markerLatLng = this.getClosestLatLng(mouseLatLng); 
 
    this.marker_.setPosition(markerLatLng); 
 
}; 
 

 
SnapToRoute.prototype.getClosestLatLng = function (latlng) { 
 
    var r = this.distanceToLines_(latlng); 
 
    return this.normalProj_.fromPointToLatLng(new google.maps.Point(r.x, r.y)); 
 
}; 
 

 
SnapToRoute.prototype.getDistAlongRoute = function (latlng) { 
 
    if (typeof (opt_latlng) === 'undefined') { 
 
     latlng = this.marker_.getLatLng(); 
 
    } 
 
    var r = this.distanceToLines_(latlng); 
 
    return this.getDistToLine_(r.i, r.to); 
 
}; 
 

 
SnapToRoute.prototype.distanceToLines_ = function (mouseLatLng) { 
 
    var zoom = this.map_.getZoom(); 
 
    var mousePx = this.normalProj_.fromLatLngToPoint(mouseLatLng); 
 
    var routePixels_ = this.routePixels_; 
 
    return this.getClosestPointOnLines_(mousePx, routePixels_); 
 
}; 
 

 
SnapToRoute.prototype.getDistToLine_ = function (line, to) { 
 
    var routeOverlay = this.polyline_; 
 
    var d = 0; 
 
    for (var n = 1; n < line; n++) { 
 
     d += google.maps.geometry.spherical.computeDistanceBetween(routeOverlay.getAt(n - 1), routeOverlay.getAt(n)); 
 
    } 
 
    d += google.maps.geometry.spherical.computeDistanceBetween(routeOverlay.getAt(line - 1), routeOverlay.getAt(line)) * to; 
 
    return d; 
 
}; 
 

 
SnapToRoute.prototype.getClosestPointOnLines_ = function (pXy, aXys) { 
 
    var minDist; 
 
    var to; 
 
    var from; 
 
    var x; 
 
    var y; 
 
    var i; 
 
    var dist; 
 

 
    if (aXys.length > 1) { 
 
     for (var n = 1; n < aXys.length; n++) { 
 
      if (aXys[n].x !== aXys[n - 1].x) { 
 
       var a = (aXys[n].y - aXys[n - 1].y)/(aXys[n].x - aXys[n - 1].x); 
 
       var b = aXys[n].y - a * aXys[n].x; 
 
       dist = Math.abs(a * pXy.x + b - pXy.y)/Math.sqrt(a * a + 1); 
 
      } else { 
 
       dist = Math.abs(pXy.x - aXys[n].x); 
 
      } 
 

 
      var rl2 = Math.pow(aXys[n].y - aXys[n - 1].y, 2) + Math.pow(aXys[n].x - aXys[n - 1].x, 2); 
 
      var ln2 = Math.pow(aXys[n].y - pXy.y, 2) + Math.pow(aXys[n].x - pXy.x, 2); 
 
      var lnm12 = Math.pow(aXys[n - 1].y - pXy.y, 2) + Math.pow(aXys[n - 1].x - pXy.x, 2); 
 
      var dist2 = Math.pow(dist, 2); 
 
      var calcrl2 = ln2 - dist2 + lnm12 - dist2; 
 
      if (calcrl2 > rl2) { 
 
       dist = Math.sqrt(Math.min(ln2, lnm12)); 
 
      } 
 

 
      if ((minDist == null) || (minDist > dist)) { 
 
       to = Math.sqrt(lnm12 - dist2)/Math.sqrt(rl2); 
 
       from = Math.sqrt(ln2 - dist2)/Math.sqrt(rl2); 
 
       minDist = dist; 
 
       i = n; 
 
      } 
 
     } 
 
     if (to > 1) { 
 
      to = 1; 
 
     } 
 
     if (from > 1) { 
 
      to = 0; 
 
      from = 1; 
 
     } 
 
     var dx = aXys[i - 1].x - aXys[i].x; 
 
     var dy = aXys[i - 1].y - aXys[i].y; 
 

 
     x = aXys[i - 1].x - (dx * to); 
 
     y = aXys[i - 1].y - (dy * to); 
 
    } 
 
    return { 
 
     'x': x, 
 
      'y': y, 
 
      'i': i, 
 
      'to': to, 
 
      'from': from 
 
    }; 
 
};
html, body, #map_canvas { 
 
    height: 100%; 
 
    width: 100%; 
 
    margin: 0px; 
 
    padding: 0px 
 
}
<script src="https://maps.googleapis.com/maps/api/js?sensor=false&libraries=geometry,places&ext=.js"></script> 
 
<div id="map_canvas" style="border: 2px solid #3872ac;"></div>

Antwort

3

den Code entfernen, der auf die den Punkt zum nächsten Punkt interpoliert Linie zwischen den Ecken.

var dx = aXys[i - 1].x - aXys[i].x; 
var dy = aXys[i - 1].y - aXys[i].y; 

x = aXys[i - 1].x - (dx * to); 
y = aXys[i - 1].y - (dy * to); 

Änderung, die einen der Eckpunkte zurückzukehren (i wird der nächste Scheitelpunkt i-1 der vorhergehende Scheitelpunkt):

x = aXys[i].x; 
y = aXys[i].y; 

proof of concept fiddle

Codefragment:

var gmap; 
 
var currentMarker = new google.maps.Marker({ 
 
    position: new google.maps.LatLng(54.13512, -117.0114), 
 
    draggable: true 
 
}); 
 
var snapToRoute = null; 
 
var polypath = new Array(
 
    new google.maps.LatLng(54.13512, -117.0114), 
 
    new google.maps.LatLng(54.13353, -117.01141), 
 
    new google.maps.LatLng(54.1332, -117.01159), 
 
    new google.maps.LatLng(54.13241, -117.01157), 
 
    new google.maps.LatLng(54.13217, -117.01142), 
 
    new google.maps.LatLng(54.12725, -117.01143), 
 
    new google.maps.LatLng(54.12185, -117.00125), 
 
    new google.maps.LatLng(54.1188, -116.9955), 
 
    new google.maps.LatLng(54.11603, -116.99473), 
 
    new google.maps.LatLng(54.11517, -116.99281), 
 
    new google.maps.LatLng(54.10235, -116.97771), 
 
    new google.maps.LatLng(54.10244, -116.96093), 
 
    new google.maps.LatLng(54.10197, -116.96067), 
 
    new google.maps.LatLng(54.10158, -116.96075), 
 
    new google.maps.LatLng(54.09808, -116.95913), 
 
    new google.maps.LatLng(54.09725, -116.95668), 
 
    new google.maps.LatLng(54.09669, -116.95598), 
 
    new google.maps.LatLng(54.08378, -116.9471), 
 
    new google.maps.LatLng(54.08218, -116.94696), 
 
    new google.maps.LatLng(54.07374, -116.93832), 
 
    new google.maps.LatLng(54.07319, -116.93571), 
 
    new google.maps.LatLng(54.07185, -116.93527)); 
 

 
var polyline = new google.maps.Polyline({ 
 
    path: polypath, 
 
    strokeColor: "red", 
 
    strokeWeight: 2, 
 
    strokeOpacity: 1 
 
}); 
 

 
function initialize() { 
 
    gmap = new google.maps.Map(
 
    document.getElementById("map_canvas"), { 
 
     center: new google.maps.LatLng(54.10244, -116.96093), 
 
     zoom: 12 
 
    }); 
 

 

 
    currentMarker.setMap(gmap); 
 
    polyline.setMap(gmap); 
 

 

 
    snapToRoute = new SnapToRoute(gmap, currentMarker, polyline); 
 
} 
 

 
google.maps.event.addDomListener(window, "load", initialize); 
 

 
function SnapToRoute(map, marker, polyline) { 
 
    this.routePixels_ = []; 
 
    this.normalProj_ = map.getProjection(); 
 
    this.map_ = map; 
 
    this.marker_ = marker; 
 
    this.polyline_ = polyline; 
 

 
    this.init_(); 
 
} 
 

 
SnapToRoute.prototype.init_ = function() { 
 
    this.loadLineData_(); 
 
    this.loadMapListener_(); 
 
}; 
 

 
SnapToRoute.prototype.updateTargets = function(marker, polyline) { 
 
    this.marker_ = marker || this.marker_; 
 
    this.polyline_ = polyline || this.polyline_; 
 
    this.loadLineData_(); 
 
}; 
 

 
SnapToRoute.prototype.loadMapListener_ = function() { 
 
    var me = this; 
 

 
    google.maps.event.addListener(me.marker_, "dragend", function(evt) { 
 
    me.updateMarkerLocation_(evt.latLng); 
 
    }); 
 

 
    google.maps.event.addListener(me.marker_, "drag", function(evt) { 
 
    me.updateMarkerLocation_(evt.latLng); 
 
    }); 
 

 
    google.maps.event.addListener(me.map_, "zoomend", function(evt) { 
 
    me.loadLineData_(); 
 
    }); 
 
}; 
 

 
SnapToRoute.prototype.loadLineData_ = function() { 
 
    var zoom = this.map_.getZoom(); 
 
    this.routePixels_ = []; 
 
    var path = this.polyline_.getPath(); 
 
    for (var i = 0; i < path.getLength(); i++) { 
 
    var Px = this.normalProj_.fromLatLngToPoint(path.getAt(i)); 
 
    this.routePixels_.push(Px); 
 
    } 
 
}; 
 

 
SnapToRoute.prototype.updateMarkerLocation_ = function(mouseLatLng) { 
 
    var markerLatLng = this.getClosestLatLng(mouseLatLng); 
 
    this.marker_.setPosition(markerLatLng); 
 
}; 
 

 
SnapToRoute.prototype.getClosestLatLng = function(latlng) { 
 
    var r = this.distanceToLines_(latlng); 
 
    return this.normalProj_.fromPointToLatLng(new google.maps.Point(r.x, r.y)); 
 
}; 
 

 
SnapToRoute.prototype.getDistAlongRoute = function(latlng) { 
 
    if (typeof(opt_latlng) === 'undefined') { 
 
    latlng = this.marker_.getLatLng(); 
 
    } 
 
    var r = this.distanceToLines_(latlng); 
 
    return this.getDistToLine_(r.i, r.to); 
 
}; 
 

 
SnapToRoute.prototype.distanceToLines_ = function(mouseLatLng) { 
 
    var zoom = this.map_.getZoom(); 
 
    var mousePx = this.normalProj_.fromLatLngToPoint(mouseLatLng); 
 
    var routePixels_ = this.routePixels_; 
 
    return this.getClosestPointOnLines_(mousePx, routePixels_); 
 
}; 
 

 
SnapToRoute.prototype.getDistToLine_ = function(line, to) { 
 
    var routeOverlay = this.polyline_; 
 
    var d = 0; 
 
    for (var n = 1; n < line; n++) { 
 
    d += google.maps.geometry.spherical.computeDistanceBetween(routeOverlay.getAt(n - 1), routeOverlay.getAt(n)); 
 
    } 
 
    d += google.maps.geometry.spherical.computeDistanceBetween(routeOverlay.getAt(line - 1), routeOverlay.getAt(line)) * to; 
 
    return d; 
 
}; 
 

 
SnapToRoute.prototype.getClosestPointOnLines_ = function(pXy, aXys) { 
 
    var minDist; 
 
    var to; 
 
    var from; 
 
    var x; 
 
    var y; 
 
    var i; 
 
    var dist; 
 

 
    if (aXys.length > 1) { 
 
    for (var n = 1; n < aXys.length; n++) { 
 
     if (aXys[n].x !== aXys[n - 1].x) { 
 
     var a = (aXys[n].y - aXys[n - 1].y)/(aXys[n].x - aXys[n - 1].x); 
 
     var b = aXys[n].y - a * aXys[n].x; 
 
     dist = Math.abs(a * pXy.x + b - pXy.y)/Math.sqrt(a * a + 1); 
 
     } else { 
 
     dist = Math.abs(pXy.x - aXys[n].x); 
 
     } 
 

 
     var rl2 = Math.pow(aXys[n].y - aXys[n - 1].y, 2) + Math.pow(aXys[n].x - aXys[n - 1].x, 2); 
 
     var ln2 = Math.pow(aXys[n].y - pXy.y, 2) + Math.pow(aXys[n].x - pXy.x, 2); 
 
     var lnm12 = Math.pow(aXys[n - 1].y - pXy.y, 2) + Math.pow(aXys[n - 1].x - pXy.x, 2); 
 
     var dist2 = Math.pow(dist, 2); 
 
     var calcrl2 = ln2 - dist2 + lnm12 - dist2; 
 
     if (calcrl2 > rl2) { 
 
     dist = Math.sqrt(Math.min(ln2, lnm12)); 
 
     } 
 

 
     if ((minDist == null) || (minDist > dist)) { 
 
     to = Math.sqrt(lnm12 - dist2)/Math.sqrt(rl2); 
 
     from = Math.sqrt(ln2 - dist2)/Math.sqrt(rl2); 
 
     minDist = dist; 
 
     i = n; 
 
     } 
 
    } 
 
    if (to > 1) { 
 
     to = 1; 
 
    } 
 
    if (from > 1) { 
 
     to = 0; 
 
     from = 1; 
 
    } 
 
    x = aXys[i].x; // aXys[i - 1].x - (dx * to); 
 
    y = aXys[i].y; // aXys[i - 1].y - (dy * to); 
 
    } 
 
    return { 
 
    'x': x, 
 
    'y': y, 
 
    'i': i, 
 
    'to': to, 
 
    'from': from 
 
    }; 
 
};
html, 
 
body, 
 
#map_canvas { 
 
    height: 100%; 
 
    width: 100%; 
 
    margin: 0px; 
 
    padding: 0px 
 
}
<script src="https://maps.googleapis.com/maps/api/js?sensor=false&libraries=geometry,places&ext=.js"></script> 
 
<div id="map_canvas" style="border: 2px solid #3872ac;"></div>