Background
I use google maps together with clustermarkererplus to display various markertypes with infobubbles on a map. To deal with markers with exactly the same coordinate (or very close) an offset is generated for the markers that overlap by using OverlappingMarkerSpiderfier (OMS). Searching for an answer to this has so far only led me to adjustment of the thickness of the offset lines.
Problem
When there are many markers the offset given by the OMS is too small.
Questions
How can I increase the offset (leg length)?
Can it be dependent on if the number of markers separated by the OMS is more than a certain value?
Example (to show the effect)
Visualisation of what I want to do, increase offset (leg length)
Code
Documentation of OMS is available at: https://github.com/jawj/OverlappingMarkerSpiderfier
//Options I use
options = {keepSpiderfied:true};
//Creation of the OMS
new OverlappingMarkerSpiderfier(map, options);
//Click listener
oms.addListener('click', function(marker, event) {
//Code for showing infowindows
});
//Adding marker
oms.addMarker(marker);
OverlappingMarkerSpiderfier has adjustable offset (leg length) by specifying two different options:
circleFootSeparation: "default:23" (Offset from the center of the circle)
spiralLengthFactor:"default:4" (Value proportional to the offset from the spiral center)
Angular separation can also be adjusted for the spiral
spiralFootSeparation:"default:26"
I'm not familiar with OverlappingMarkerSpiderfier, so just did some research and found this tutorial. It also include 'legWeight' which determine the thickness of the lines joining spiderfied markers to their original locations.
Here's the link for Overlapping Marker Spiderfier: https://github.com/jawj/OverlappingMarkerSpiderfier
I hope it might help you.
Related
currently i have a little project that needs to make marker static and move map to the marker display on the map - i hope it makes any sense -
how to move map not marker - like i said the marker cannot move but the map needs to move to the marker when location changed - also marker is displayed at the bottom the map to make room for other events above the marker such as a path display and etc -
whats done already is when car moves it watches gps - then tells marker to move to that gps as a current location and then panby to the bottom of the map - this makes marker jerk at the bottom of the map when its location changed - so i figured if i keep marker static by placing it into a div above map and fixate it via css style - so it stays in the same place all the time - but this is wrong as it cannot be moved with map then when someone drags map with a finger - so this cannot be right solution - what is your solution to this dilema unless i am missing something -
To achieve what you want, you need to rotate the map on the correct axis, find the position of the center of the map, and finally center the map at the right place.
1 - Rotate the map
In your case (I presume you want the car always face of the road in front of the user position) you need to rotate the map before centering, otherwise the map is always oriented to the north and it can be anoying when the car move in other orientation (south for exemple). In this case the point of view is oriented in the wrong direction and the user don't see the upcoming road.
You can find an exemple here in the documentation. Basicaly you need to use setHeading() method. The rotation on gmap is not easy than it can be (see this post).
2 - Find the center of the map
To find the updated position of the center of your map, you need to retrieve the latLng location of a point always at the same distance (in pixel of the map container) above your marker fixed location. Use the methods fromLatLngToPoint() and fromPointToLatLng() to retrieve the position from the map to the real world or vice versa (see getProjection() for more details).
Exemple :
Your map is displayed in 1000*1000 px and the bottom position of the marker you choose is at 500px of the left side and 950px of the top side. If you want to move the center of the map without changing the position of the marker, you need to find the latLng position of the point at 450px above your marker.
function findMapCenter(map, markerLatLng) {
// need this to adjust from the actual zoom on the map
let scale = Math.pow(2, map.getZoom());
// position in pixel x.y from the container
let markerWorldCoordinate = map.getProjection().fromLatLngToPoint(markerLatLng);
// calcul of the position of the center
let centerWorldCoordinate = new google.maps.Point(
markerWorldCoordinate.x,
markerWorldCoordinate.y + (450/scale) // 450 because in my exemple is from 450px at the top of the marker
);
// return latLng of the center point of the map
return map.getProjection().fromPointToLatLng(centerWorldCoordinate);
}
3 - Set the map at the right place
Use setCenter() method to center the map on a choosen latLng location.
let marker; // = config of your marker
let gMap = new google.maps.Map(document.getElementById('map'));
update({lat:MARKER_LATITUDE, lng:MARKER_LONGITUDE});
// call this every time you want to update
function update(markerNewLatLng){
// ... first step : rotate the map if you need to
// then update marker position
marker.setPosition(markerNewLatLng);
// center the map
gMap.setCenter(findMapCenter(gmap, markerNewLatLng));
}
I need to show marker across map, drag sideway will have the marker show without hiding the previous one
worldCopyJump will replicate but previous map marker will be gone
I need to limit maxbound only to top and bottom, not sideway.
I couldnt use code below:
var maxSouthWest = L.latLng(-85, -360);
var maxNorthEast = L.latLng(85, 360);
var maxBounds = L.latLngBounds(maxSouthWest, maxNorthEast);
Can the latitude and longitude to be correct even crossing map dateline?
I need to draw shortest polyline route which similar to google map, example Japan to USA
in my leaflet will have the longitude more than 180 (240 example), which i want it to be in correct lat lng
worldCopyJump doesnt suit what I need
cannot cut polyline as user are allow to draw the best route line (even wrapping the whole world)
Refer to https://github.com/Leaflet/Leaflet/issues/5340 for image.
Code:
var map = L.map('map');
L.tileLayer('//{s}.tile.cloudmade.com/41339be4c5064686b781a5a00678de62/998/256/{z}/{x}/{y}.png',{minZoom:8, maxZoom:15}).addTo(map);
marker1 = L.marker([37.4185539, -122.0829068]).addTo(map);
marker1.bindPopup("Google Campus");
marker2 = L.marker([37.792359, -122.404686]).addTo(map);
marker2.bindPopup("Financial District");
var group = new L.featureGroup([marker1, marker2]);
map.fitBounds(group.getBounds());
The above code will center the map on the center of the markers, but does not set a zoom level so that the markers and only the markers are visible.
If I leave out the 'minZoom' attribute of the map object when adding the initial layer, the entire globe is visible. My desire is to have the map set a zoom and boundaries so that the markers are visible, and zoomed in. Any clues on how to accomplish this?
I thought that the fitBounds method would set a Zoom level, but for some reason in my situation it does not do so.
Your code is setting the map to a zoom level where both of the markers are visible at the highest possible zoom level. Because of the distance between the two markers and the way web mapping works, this is best fit using raster map tiles. Higher zoom levels will be zoomed in so much that you won't be able to see both markers.
I have a balloon which pops up when clicking on a Marker. Sometimes the balloon exeeds the bounds of the map and is not fully shown.
I can't center the map to the coordinates of the marker, because the ballon is sometimes too high and would still be outside the bounds. So I need an offset which moves the center of the map slightly down so the balloon is always nicly in the middle of my map.
The problem is that Google maps doesn't work with pixels but with LatLng. Therefore I need a dynamically scalable function to keep the offset in every zoomlevel the same!
Alright, I found an algorithmic solution!
map.setCenter(
new google.maps.LatLng(
marker.getPosition().lat()+(X/Math.pow(2,map.getZoom())),
marker.getPosition().lng()
)
);
Each zoom level nearly doubles the LatLng which is shown on the map. So just find an X which is the perfect offset for you (in my case it was 128) and everything works great!
PS: The position of the marker is the same as the balloon.
I am trying to get my custom markers to show up on my map after i have used the fitBounds() method to fit the boundaries of the map to the markers themselves.
I have done this by looping over the markers array and then extending the boundaries of the map to incorporate the marker co-ordinates.
This works fine with the stock google maps markers. However, my client wants to use quite large (36px by 57px) marker images for their site. How do i compensate for this when fitting the boundaries of the map?
At the moment when using the custom marker images they do not all fit inside the boundaries set.
Since you already have calculated the bounds, you may just need to extend the bounds to add enough buffer area to include the large images. The formula you can use to calculate or extend a bounds this way is called a convex hull; the Computational Geometry Algorithms Library has a section on 2D Convex Hull Algorithms or there is a JavaScript Quickhull Article that also includes a nifty online example near the bottom of the page. Hope this is helpful -
The cheap answer is to always zoom out one level after fitBounds(). But we can do a bit better.
I like writing hacks. Here I am making the assumption that the size of your marker will never be larger than 36x57. I tested a while back to find that fitBounds() leaves a margin of around 42 px between the edge and the closest marker (maybe not on mobiles), and I'm also assuming you are not repositioning the marker, that is, it will always be displayed above the given coordinate position. If icons run off to the other sides, adjustments are needed.
My hack takes advantage of a function that measures the pixel position of a LatLng (using the container version, I read here that the div version is not reliable with bounds changes).
Since we know the height of the icon, and where the topmost marker is, we can pan the map south a bit if it's determined to be offscreen. In case there's not enough margin below, the only option is to zoom out. My only concern is it will be jerky because it calls for two events: fitBounds and the custom panning/zooming. The only answer then would be to rewrite a custom fitBounds. When I tested manually the events ran smoothly.
http://jsfiddle.net/sZJjY/
Click to add cat icons, right-click to trigger the resize/panning.
Example: place 3-4 kitties, right-click, then purposely place another that goes off the top, right-click again.
function fitIcons() {
var left = 180.0;
var right = -180.0;
var top = -90.0;
var bottom = 90.0;
for (var i = 0; i < markers.length; i++) {
curlat = markers[i].getPosition().lat();
curlng = markers[i].getPosition().lng();
if(curlat > top) { top = curlat; }
if(curlat < bottom) { bottom = curlat; }
if(curlng > right) { right = curlng; }
if(curlng < left) { left = curlng; }
}
var overlay = new google.maps.OverlayView();
overlay.draw = function() {};
overlay.setMap(map);
map.fitBounds(new google.maps.LatLngBounds(
new google.maps.LatLng(bottom, left),
new google.maps.LatLng(top, right)));
topPixels = overlay.getProjection().fromLatLngToContainerPixel(
new google.maps.LatLng(top, right));
bottomPixels = overlay.getProjection().fromLatLngToContainerPixel(
new google.maps.LatLng(bottom, left));
topGap = topPixels.y;
bottomGap = $("#map_canvas").height() - bottomPixels.y;
if(topGap < iconHeight) {
if(bottomGap > iconHeight) {
map.panBy(0, topGap);
}
else {
map.setZoom(map.getZoom() - 1);
}
}
}