I want to use google Map Api and draw direction between two points. My map is partially covered by a gray box in which some text might be shown. The problem is occurred when distance of the two points is too far and one point is covered by the gray box.
How can I force it to draw the path in a way that whole the path is is shown on the right side of the gray box and none of the points is overlapped by the gray box?
What I currently have:
What I expect:
Since I saw already a few questions on SO about offsetting stuff that would appear behind elements overlaid on the map, I thought I'd give it a bit of time.
Here is how I did it:
Plot a route on the map and listen for the map idle
event before starting with the offset process.
Check the leftmost point of the route bounds to see if it falls behind the overlay. This makes use of the fromLatLngToPoint()
method to translate from lat/lng coordinates to a point on the map projection.
Check how much you can offset the route by comparing the leftmost and rightmost points of the route with the available space on the map. Offset the map until both points fit on the map canvas.
If both points cannot fit within the map canvas, zoom out and start the same process again.
The script must be aware of the width of the overlay and you should apply some margins so that it always fits well.
Here is the function used to translate between coordinates and point:
function fromLatLngToPoint(latLng) {
var scale = Math.pow(2, map.getZoom());
var nw = new google.maps.LatLng(map.getBounds().getNorthEast().lat(), map.getBounds().getSouthWest().lng());
var worldCoordinateNW = map.getProjection().fromLatLngToPoint(nw);
var worldCoordinate = map.getProjection().fromLatLngToPoint(latLng);
return new google.maps.Point(Math.floor((worldCoordinate.x - worldCoordinateNW.x) * scale), Math.floor((worldCoordinate.y - worldCoordinateNW.y) * scale));
}
Here is the demo:
JSFiddle demo
I am sure it can still be optimized but it does the job quite well. Please report issues here if you find any.
Edit:
The same technique works with markers too:
JSFiddle demo
Here is a rewrite for right hand sidebar. Paste the below code in js in JSFiddle link and change CSS for sidebar to right:0
var directionsDisplay;
var directionsService = new google.maps.DirectionsService();
var map;
var routeBounds = false;
var overlayWidth = 400; // Width of the overlay DIV
var leftMargin = 30; // Grace margin to avoid too close fits on the edge of the overlay
var rightMargin = 30; // Grace margin to avoid too close fits on the right and leave space for the controls
overlayWidth+= rightMargin;
var start = new google.maps.LatLng(48.857380, 2.351717);
var end = new google.maps.LatLng(50.108814, 8.672309);
function initialize() {
var btn1 = document.getElementById('calcRoute');
btn1.addEventListener('click', calcRoute);
var btn2 = document.getElementById('offsetMap');
btn2.addEventListener('click', offsetMap);
var btn3 = document.getElementById('fitAndOffsetMap');
btn3.addEventListener('click', fitAndOffsetMap);
var btn4 = document.getElementById('fitMap');
btn4.addEventListener('click', fitMap);
directionsDisplay = new google.maps.DirectionsRenderer({
draggable: true
});
var mapOptions = {
zoom: 13,
mapTypeId: google.maps.MapTypeId.ROADMAP,
center: start,
panControlOptions: {
position: google.maps.ControlPosition.TOP_RIGHT
},
zoomControlOptions: {
position: google.maps.ControlPosition.TOP_RIGHT
}
};
map = new google.maps.Map(document.getElementById("map-canvas"), mapOptions);
directionsDisplay.setMap(map);
}
function offsetMap() {
if (routeBounds !== false) {
// Clear listener defined in directions results
google.maps.event.clearListeners(map, 'idle');
// Top right corner
var topRightCorner = new google.maps.LatLng(map.getBounds().getNorthEast().lat(), map.getBounds().getNorthEast().lng());
// Top right point
var topRightPoint = fromLatLngToPoint(topRightCorner).x;
// Get pixel position of leftmost and rightmost points
var leftCoords = routeBounds.getSouthWest();
var rightCoords = routeBounds.getNorthEast();
var leftMost = fromLatLngToPoint(leftCoords).x;
var rightMost = fromLatLngToPoint(rightCoords).x;
// Calculate left and right offsets
var leftOffset = leftMost-leftMargin;
var rightOffset = (overlayWidth-(topRightPoint - rightMost));
console.log(leftMost,rightMost,topRightPoint,leftOffset,rightOffset)
// Only if left offset is needed
if (rightOffset >= 0) {
if (rightOffset < leftOffset) {
var mapOffset = Math.round((leftOffset-rightOffset ) / 2);
// Pan the map by the offset calculated on the x axis
map.panBy(mapOffset, 0);
// Get the new left point after pan
var newRightPoint = fromLatLngToPoint(rightCoords).x;
console.log("e",newRightPoint,(topRightPoint-newRightPoint))
if ((topRightPoint-newRightPoint) <= overlayWidth) {
console.log("jjjj")
// Leftmost point is still under the overlay
// Offset map again
offsetMap();
}
}
else {
console.log("j")
// Cannot offset map at this zoom level otherwise both leftmost and rightmost points will not fit
// Zoom out and offset map again
map.setZoom(map.getZoom() - 1);
offsetMap();
}
}
}
}
function fromLatLngToPoint(latLng) {
var scale = Math.pow(2, map.getZoom());
var nw = new google.maps.LatLng(map.getBounds().getNorthEast().lat(), map.getBounds().getSouthWest().lng());
var worldCoordinateNW = map.getProjection().fromLatLngToPoint(nw);
var worldCoordinate = map.getProjection().fromLatLngToPoint(latLng);
return new google.maps.Point(Math.floor((worldCoordinate.x - worldCoordinateNW.x) * scale), Math.floor((worldCoordinate.y - worldCoordinateNW.y) * scale));
}
function calcRoute() {
var request = {
origin: start,
destination: end,
travelMode: google.maps.DirectionsTravelMode.DRIVING
};
directionsService.route(request, function (response, status) {
if (status == google.maps.DirectionsStatus.OK) {
directionsDisplay.setDirections(response);
// Define route bounds for use in offsetMap function
routeBounds = response.routes[0].bounds;
// Write directions steps
writeDirectionsSteps(response.routes[0].legs[0].steps);
// Wait for map to be idle before calling offsetMap function
google.maps.event.addListener(map, 'idle', function () {
// Offset map
offsetMap();
});
// Listen for directions changes to update bounds and reapply offset
google.maps.event.addListener(directionsDisplay, 'directions_changed', function () {
// Get the updated route directions response
var updatedResponse = directionsDisplay.getDirections();
// Update route bounds
routeBounds = updatedResponse.routes[0].bounds;
// Fit updated bounds
map.fitBounds(routeBounds);
// Write directions steps
writeDirectionsSteps(updatedResponse.routes[0].legs[0].steps);
// Offset map
offsetMap();
});
}
});
}
function writeDirectionsSteps(steps) {
var overlayContent = document.getElementById("overlayContent");
overlayContent.innerHTML = '';
for (var i = 0; i < steps.length; i++) {
overlayContent.innerHTML += '<p>' + steps[i].instructions + '</p><small>' + steps[i].distance.text + '</small>';
}
}
function fitMap() {
if (routeBounds !== false) {
map.fitBounds(routeBounds);
}
}
function fitAndOffsetMap() {
if (routeBounds !== false) {
map.fitBounds(routeBounds);
offsetMap();
}
}
initialize();
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With