Reputation: 585
Like in title: How to implement polyline snapping to street when marker is dragging? I spent a lot of time seeking answer but I gave up already. I'd like to use only DirectionsService if it is possible without DirectionsRenderer. Below is my cleaned version of code where snapping working not for each but only for last marker and path is not cleaned. Help would be much appreciated.
My code on jsfiddle and here:
var map,
path = [],
markers = [],
directionsService = new google.maps.DirectionsService(),
poly;
function addMarker(p) {
var marker = new google.maps.Marker({
position: p,
map: map,
draggable: true
});
markers.push(marker);
google.maps.event.addListener(marker, "drag", function () {
var request = {
origin: path[path.length - 1],
destination: marker.getPosition(),
travelMode: google.maps.DirectionsTravelMode.DRIVING
};
directionsService.route(request, function (response, status) {
if (status == google.maps.DirectionsStatus.OK) {
marker.setPosition(response.routes[0].legs[0].end_location);
path = path.concat(response.routes[0].overview_path);
poly.setPath(path);
}
});
});
}
function initialize() {
var myOptions = {
zoom: 17,
center: new google.maps.LatLng(40.7143528, -74.00597310000001),
mapTypeId: google.maps.MapTypeId.ROADMAP,
draggableCursor: "crosshair"
}
map = new google.maps.Map(document.getElementById("map_canvas"), myOptions);
google.maps.event.addListener(map, 'click', function (event) {
if (path.length == 0) {
path.push(event.latLng);
poly = new google.maps.Polyline({
map: map
});
poly.setPath(path);
addMarker(event.latLng);
} else {
var request = {
origin: path[path.length - 1],
destination: event.latLng,
travelMode: google.maps.DirectionsTravelMode.DRIVING
};
directionsService.route(request, function (response, status) {
if (status == google.maps.DirectionsStatus.OK) {
addMarker(response.routes[0].legs[0].end_location);
path = path.concat(response.routes[0].overview_path);
poly.setPath(path);
}
});
}
});
}
Upvotes: 3
Views: 2247
Reputation: 1847
This is a fairly difficult thing to implement while retaining good performance, for reasons stated within my code below. Snapping to roads WHILE dragging markers is what you request but there are limitations and problems with doing this. I will provide you with code to do this without snapping to road WHILE dragging, but rather at the END of marker drag. Note that uncommenting one line of code below enables it to snap to roads while dragging as you request, but I advise against it for reasons stated below. Please see comments towards end of my code here and viewable in action here http://jsfiddle.net/VvR5k/1/
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">
<html>
<head>
<meta http-equiv="content-type" content="text/html; charset=utf-8">
<title>Some Title</title>
</head>
<body>
<p>Click on map to place markers, drag markers to change route</p>
<p>Please view comment block towards end of javascript code!</p>
<p><button type="button" onclick="resetMarkers();">Reset Markers</button></p>
<div id="map_canvas" style="width:800px; height:600px;">
</div>
<script src="http://maps.googleapis.com/maps/api/js?v=3.exp&sensor=false"></script>
<script type="text/javascript">
function init() {
var markers = [],
segments = [],
myOptions = {
zoom: 12,
center: new google.maps.LatLng(34.0504, -118.2444),
mapTypeId: google.maps.MapTypeId.ROADMAP,
disableDoubleClickZoom: true,
draggableCursor: "crosshair"
},
alphas = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ'.split(''),
alphaIdx = 0,
map = new google.maps.Map(document.getElementById("map_canvas"), myOptions),
service = new google.maps.DirectionsService(),
poly = new google.maps.Polyline({
map: map,
strokeColor: '#00FFFF',
strokeOpacity: 0.6,
strokeWeight: 5
});
window.resetMarkers = function () {
for (var i = 0; i < markers.length; i++) {
markers[i].setMap(null);
}
alphaIdx = 0;
segments = [];
markers = [];
poly.setPath([]);
};
function getSegmentsPath() {
var a, i,
len = segments.length,
arr = [];
for (i = 0; i < len; i++) {
a = segments[i];
if (a && a.routes) {
arr = arr.concat(a.routes[0].overview_path);
}
}
return arr;
}
function addSegment(start, end, segIdx) {
service.route(
{
origin: start,
destination: end,
travelMode: google.maps.DirectionsTravelMode.DRIVING
},
function (result, status) {
if (status == google.maps.DirectionsStatus.OK) {
//store the entire result, as we may at some time want
//other data from it, such as the actual directions
segments[segIdx] = result;
poly.setPath(getSegmentsPath());
}
}
);
}
google.maps.event.addListener(map, "click", function (e) {
//limiting the number of markers added to no more than 26, as if we have
//that many we have used up all our alphabetical characters for the icons
if (alphaIdx > 25) {
return;
}
var evtPos = e.latLng,
c = alphas[alphaIdx++],
marker = new google.maps.Marker({
map: map,
position: evtPos,
draggable: true,
icon: 'http://www.google.com/mapfiles/marker'+ c +'.png'
});
marker.segmentIndex = markers.length - 1;
marker.iconChar = c;//just storing this for good measure, may want at some time
function updateSegments() {
var start, end, inserts, i,
idx = this.segmentIndex,
segLen = segments.length, //segLen will always be 1 shorter than markers.length
myPos = this.getPosition();
if (segLen === 0) { //nothing to do, this is the only marker
return;
}
if (idx == -1) { //this is the first marker
start = [myPos];
end = [markers[1].getPosition()];
inserts = [0];
} else if (idx == segLen - 1) { //this is the last marker
start = [markers[markers.length - 2].getPosition()];
end = [myPos];
inserts = [idx];
} else {//there are markers both behind and ahead of this one in the 'markers' array
start = [markers[idx].getPosition(), myPos];
end = [myPos, markers[idx + 2].getPosition()];
inserts = [idx, idx + 1];
}
for (i = 0; i < start.length; i++) {
addSegment(start[i], end[i], inserts[i]);
}
}
/**********************************************************************
Note that the line below which sets an event listener for the markers
'drag' event and which is commented out (uncomment it to test,
but I do not recommend using it in reality) causes us to constantly
poll google for DirectionsResult objects and may perform poorly at times
while a marker is being dragged, as the application must wait for a
directions request to be sent and received from google many many many
times while the marker is dragged. For these reasons, I personally would
only use the dragend event listener. Additionally, using the below line can
very quickly run you up against google maps api services usage limit of
2500 directions requests per day, as while a marker is being dragged it
could cause hundreds and hundreds of directions requests to be made! Not good!
see about usage limits: https://developers.google.com/maps/documentation/directions/#Limits
***********************************************************************/
//google.maps.event.addListener(marker, 'drag', updateSegments);
google.maps.event.addListener(marker, 'dragend', updateSegments);
markers.push(marker);
if (markers.length > 1) {
addSegment(markers[markers.length - 2].getPosition(), evtPos, marker.segmentIndex);
}
});
}
init();
</script>
</body>
</html>
Upvotes: 3