I'm using google maps api 3 along with agm (angular google maps) to place a lot of custom markers on the map. Some of these markers are low priority so i've implemented clustering (using markerClusterer) on those markers to help with performance.
However the higher priority markers need to always be above the clusters, currently clusters appear to be on their own layer and that layer is always above the markers layer.
Is there a way to force clusters and markers to be on the same layer, so I can implement a zIndex? Or at the very least, force the makers layer to be above the clusters layer.
Or alternatively, could we detect if clusters are over markers, and shift the cluster so that it's out of the way.
After working on it for ages, I found the only way to do this is to create a pane so that the getPanes method is available, from there you move the markerLayer (where the markers live) to the overlayMouseTarget, here is a semi working example:
First, set the zIndex of the marker, or markers
marker.setZIndex(9999);
marker.setMap(this.map);
I use a pretty lengthy method of checking json info in order to change the zIndex number, so for this example i'll just say all markers need to be above the cluster, then in any markers that I plan to put into the cluster, I set that marker to 10 and push to an array, then set that array to the markercluster. Now onto the layering:
const overlay = function() {};
overlay.prototype = new google.maps.OverlayView();
overlay.prototype.onAdd = function() {
const panes = this.getPanes();
for(let i = 0; i < panes.markerLayer.childNodes.length; i++) {
panes.overlayMouseTarget.appendChild(panes.markerLayer.childNodes[i]);
}
console.log(panes.overlayMouseTarget);
};
const x = new overlay();
x.setMap(this.map);
With this, this pushes all the markers and cluster into the same dom element, so the zIndex is respected.
Related
I've got an array of Google Maps Markers that I get after clicking on cluster.
I would need to check if the markers of this array have the same position. Because I can find myself in the situation where it could be, where in one cluster all of markers have the same position.
There is my code :
google.maps.event.addListener(markerCluster, 'clusterclick', function(cluster) {
var markers = cluster.getMarkers();
map.setCenter(markers[0].getPosition());
map.setZoom(map.getZoom()+10);
for(i in markers) {
// Here, how to compare each marker (by comparing the position) between them of markers ?
markers[i].setMap(cluster.getMap());
marker = markers[i];
}
cluster.clusterIcon_.hide();
setTimeout(function(){
google.maps.event.trigger(marker, 'click');
},100);
});
So my question, is how to compare each marker (by comparing the position) between them of markers array ? How to check if they have the same position ?
Thanks.
EDIT :
I found the solution :
const bounds = cluster.getBounds();
const areMarkersCoincident = bounds.getNorthEast().equals(bounds.getSouthWest());
Thanks for your help !
It depends on what you are trying to achieve.
For example, if you just need a simple clustering solution you can just use google maps marker clusters: https://developers.google.com/maps/documentation/javascript/marker-clustering
But for something else you can just compare positions of the markers.
For that, you have latitude and longitude.
Here you can read the documentation of LatLng class in google maps and see that it has method equals which can compare two coordinates. https://developers.google.com/maps/documentation/javascript/reference/coordinates#LatLng
But don't forget that in some cases you might need to compare not just marker positions, but also if the marker icons intersect. For that, you can either use LatLngBounds https://developers.google.com/maps/documentation/javascript/reference/coordinates#LatLngBounds and it has a method contains
I'm trying to load lot's of marker on a leaflet map
With this method :
L.marker([item.latitude, item.longitude]).addTo(this.map);
I loop for at least 100 markers and the map become really laggy after that.
Is there a way to optimize a map on which I want to display lot's of markers ?
I've used ngx-leaflet-markercluster with ngx-leaflet successfully to display 4000 markers. The plug-in uses a combination of cluster markers and regular markers that dynamically appear at certain zoom levels.
The plugin also spiderfy markers that have the same coordinates.
It works well with Angular 8.
ngx-leaflet-markercluster uses leaflet.markercluster and looks like this:
Clustering the markers is the best way to handle performance issues, in my opinion. Since that's no solution in your case, you can improve the performance by putting all the markers in one layer first and adding that single layer to your map, instead of adding all markers to the map individually.
You can compare the performance here:
Example adding grouped to map: http://jsfiddle.net/HarolddP/g12vj3mt/2/
Example adding individually to map: http://jsfiddle.net/HarolddP/euz7f6o2/
Suggested improvement:
var map = L.map('map').setView([51.5, -0.09], 3);
var markers = [];
for (var i=0; i<500; i++){
lat = ..; lng = ..;
marker = new L.marker([lat, lng]);
markers.push(marker);
}
markerGroup = L.layerGroup(markers);
markerGroup.addTo(map);
Another suggested solution is to add only the markers to the map that are in the boundary of your view.
As you can imagine, the performance also depends on what kind of markers you are using. Are they big in size? As you can see in the examples, the 500 standard leaflet markers are still performing quite well (at my machine).
I have a map where I need to place markers for locations drawn from a database. The locations can be from one end of the country to the other and I want to limit marker placement to only the visible map area.
What segments of the api cover this? Are there any best practices for handling this use case?
You can get the bounds of the map with:
bounds = map.getBounds();
The result is a LatLngBounds object. Then for a marker marker, you can test if it is in the map with:
if ( bounds.contains(marker.getPosition()) ) {
}
I am using google map(clustering version) from the following link:
google map clusterer
everything is good and for example when I have 1000 location it clusters them but when I have 200 location and density is not high it does not clusters. I want to clusters even those that are not dense what should I do? is there anyway that I can change level of sensitivity of this google map to distance and zoom to be able to cluster even markers in a less dense area?
As you figured out which parameters to use with the above comments, here is how to pass these params to your marker cluster constructor:
var mcOptions = {
gridSize: 50,
minimumClusterSize: 10
};
var markerCluster = new MarkerClusterer(map, markers, mcOptions);
Where map is your map object and markers is your markers array. The numbers used are only for example. You have to play with these to get the desired results. Hope this helps.
Swift
cluster size change worked for me this way in the latest version and its super easy
// Set up the cluster manager with the supplied icon generator and
// renderer.
let iconGenerator = GMUDefaultClusterIconGenerator()
let algorithm = GMUNonHierarchicalDistanceBasedAlgorithm()
let renderer = GMUDefaultClusterRenderer(mapView: mapView,
clusterIconGenerator: iconGenerator)
renderer.delegate = self
renderer.minimumClusterSize = 5 // Here is the setting
clusterManager = GMUClusterManager(map: mapView, algorithm: algorithm,
renderer: renderer)
clusterManager.setDelegate(self, mapDelegate: self)
This is somewhat similar to the question asked here --
I'm writing a search box for a map application, which retrieves a whole set of search results (people's names & info) at once from a server and then pages through the list of results. So at any given point on the map there are two kinds of markers -- a background marker for points which are in the search results but not in the current page, and a foreground marker for points which are in the current page of search results.
All this works nicely.. what I'd like to do now is set it up so that if a user zooms or pans the map, the search results list updates to show only markers within the current map bounds.
Obviously there are server-side ways to do this, or I could also just run through the whole list of markers to see which fit within the current bounds; but does anybody know a built-in way to do this within leaflet? Something which would look like map.getVisibleLayers()?
I think this may be of help:
https://github.com/stefanocudini/leaflet-list-markers
as you can see from the demo, including all markers in a layer, this plugin shows a list of only those visible in the current viewport.
Its usage is simple, in a row:
var markersLayer = new L.LayerGroup();
map.addControl( new L.Control.ListMarkers({layer: markersLayer}) );
The code for obtain it is like as:
var layers = L.LayerGroup(), //layers contains all markers..
contained = []; //makers in map boundingbox
layers.eachLayer(function(l) {
if( l instanceof L.Marker && map.getBounds().contains(l.getLatLng()) )
contained.push(l);
});
Here's a fully working function that does the job:
// var map is an instance of a Leaflet map
// this function assumes you have added markers as GeoJSON to the map
// it will return an array of all features currently shown in the
// active bounding region.
function getFeaturesInView() {
var features = [];
map.eachLayer( function(layer) {
if(layer instanceof L.Marker) {
if(map.getBounds().contains(layer.getLatLng())) {
features.push(layer.feature);
}
}
});
return features;
}
You have to check the bounds of each layer versus the map's bounds. Because eachLayer() returns all layers regardless of whether they are in the visible extent.
if(map.getBounds().contains(layer.getLatLng())) { ... }
In Stefano's code, this is shown around this line:
https://github.com/stefanocudini/leaflet-list-markers/blob/master/src/leaflet-list-markers.js#L95
Regarding the last part of your question, if you want to iterate through visible layers, you can use eachLayer, e.g:
map.eachLayer(function (layer) {
// do something with the layer
});
API reference: http://leafletjs.com/reference.html#map-stuff-methods