Is there a way to replicate the behavior of L.LayerGroup.eachLayer() with GridLayer? I'm using Leaflet.VectorGrid (L.VectorGrid.Slicer) in order to wrap some GeoJSON around the world, and I'd like to add each feature to one or more layer groups. For example, the code below for GeoJSON objects works, but not for grid layers.
// want to do something like this; layer groups defined previously
L.geoJSON(usData, {
style: // styling logic
})
.eachLayer(layer => {
layerGroup1.addLayer(layer);
if (category2.indexOf(layer.someProperty) !== -1) {
layerGroup2.addLayer(layer);
}
if (category3.indexOf(layer.someProperty) !== -1) {
layerGroup3.addLayer(layer);
}
})
.addTo(mapObject);
// no eachLayer() method for grid layers or slicers; how could you do this with grid layers?
L.vectorGrid.slicer(usData, {
vectorTileLayerStyles: {
sliced: properties => someFunction(properties)
},
interactive: true
})
.eachLayer(layer => {
// do something with each layer
})
.addTo(mapObject);
Create several instances of L.VectorGrid.Slicer, one per desired LayerGroup. Filter your GeoJSON data accordingly.
You can get every "layer" with:
Object.keys(vectorGrid._vectorTiles).forEach(function(e){console.log(vectorGrid._vectorTiles[e])})
But the problem is, that the layers have no latlng, they have paths. So you can't add them to a Layergroup.
Maybe you can create new polygons when you get the path coords from the feature and convert them to latlng.
Related
I'm using the HERE JS library for mapping. I'd like to add an option into the MapSettingsControl to select the POI Map, as shown at https://developer.here.com/documentation/map-tile/dev_guide/topics/example-poi-tile.html
It seems you need to append "&pois" to the tile requests in order to get this.
I've followed the example in How do I get a Terrain Map in UI Controls HERE Maps v3.1 to create a new selectable map style in the MapSettingsControl.
However, it seems you can only select the map style name and cannot append arguments. Specifically, I cannot see a way of appending the &pois argument to the tile request to get the POI tiles.
Any suggestions?
Ah, I found the answer, but it's a bit fiddly.
var maptypes = platform.createDefaultLayers();
var poi = platform.createDefaultLayers({pois:true});
ui.removeControl("mapsettings");
// create custom one
var ms = new H.ui.MapSettingsControl( {
baseLayers : [ {
label:"Normal", layer: maptypes.vector.normal.map
},
{
label:"POI", layer: poi.raster.normal.map
},
],
layers : [{
label: "layer.traffic", layer: maptypes.vector.normal.traffic
},
{
label: "layer.incidents", layer: maptypes.vector.normal.trafficincidents
}
]
});
ui.addControl("customized",ms);
I have quite a few Tile Layers in my map, and they are all organized into different groups (sometimes they are even nested).
I see in API there's a getLayer() method to retrieve the layer a Vector feature belongs to, and a getLayerGroup() to retrieve all groups associated with a Map.
However, I could not find anything on getting the layerGroup a layer is associated with.
Lets'say I have this situation:
var myGroup = new LayerGroup();
var myLayer = new TileLayer();
myGroup.getLayers().insertAt(0, myLayer);
Is there a way to get myGroup from myLayer?
To get the parent group of a layer would need to write your own search function, something like
function searchGroups(group, layer) {
var result;
var layers = group.getLayers().getArray();
for (var i = 0; i < layer.length; i++) {
if (layers[i] === layer) {
result = group;
} else if (layers[i] instanceof LayerGroup) {
result = searchGroup(layers[i], layer)
}
if (result) {
break;
}
}
return result;
}
then call
var myGroup = searchGroups(map.getLayerGroup(), mylayer);
The getLayers() function you linked only works for a select interaction, you cannot determine from a random feature which layer it belongs to (and it could be in more than one) without a similar search of the features in each vector layer source.
I realize this question has already been answered, but alternatively, you also have the properties attribute for your layers, so you could add an array of group names to the layer itself. For example:
let parent_group = "parent_group";
let sub_group = "sub_group";
let group = new LayerGroup({
name: parent_group,
layers: [
new LayerGroup({
name: sub_group,
layers: [
new TileLayer() {
properties: [
parent_group,
sub_group
]
}
]
})
]
})
Then it's just a matter of looking up the layer name and looking up its properties array - probably a bit more cumbersome to setup initially, but it would save having to recursively search through layerGroups.
I have a leaflet map that has zoom levels 2-7 and uses the MarkerCluster plugin, by default I have the L.MarkerClusterGroup disable clustering a zoom level 2 (which means no clustering) and I'm trying to allow the user to click a button that then changes the clustering zoom level to 5. Is this possible?
I know I could do it by making two markercluster groups, one that has no clustering and one that has clustering and remove/add it based on click but that just seems incredibly messy. Really, there's several ways to do it but they are so incredibly clunky.
Code:
Default (2 is the lowest level of zoom):
var markers = new L.MarkerClusterGroup (
{
disableClusteringAtZoom: 2,
maxClusterRadius: 100,
animateAddingMarkers: true
});
What I want to do be able to do:
$('#mcluster').click(function() {
//do some code that sets the disableClusterAtZoom to 5
});
I could not find a way to disable clustering or set a new value for disableClustering at zoom, but I found a less clunky way of achieving this.
var markers = new L.LayerGroup(); //non cluster layer is added to map
markers.addTo(map);
var clusters = new L.MarkerClusterGroup (
{
disableClusteringAtZoom: 5,
maxClusterRadius: 100,
animateAddingMarkers: true
}); //cluster layer is set and waiting to be used
var clusterStatus = 'no'; //since non cluster group is on by default, the status for cluster is set to no
$('#mcluster').click(function( event ) {
if(clusterStatus === 'no'){
clusterStatus = 'yes';
var current1 = markers.getLayers(); //get current layers in markers
map.removeLayer(markers); // remove markers from map
clusters.clearLayers(); // clear any layers in clusters just in case
current1.forEach(function(item) { //loop through the current layers and add them to clusters
clusters.addLayer(item);
});
map.addLayer(clusters);
} else {
clusterStatus = 'no'; //we're turning off clustering here
var current2 = clusters.getLayers(); //same code as before just reversed
map.removeLayer(clusters);
markers.clearLayers();
current2.forEach(function(item) {
markers.addLayer(item);
});
map.addLayer(markers);
}
});
I'm sure there is a more elegant solution but with my still growing knowledge this is what I came up with.
I know you needed a solution a few months ago, but just to let you know that I released recently a sub-plugin for Leaflet.markercluster that can perform exactly what you are looking for (with a few extra code): Leaflet.MarkerCluster.Freezable (demo here).
var mcg = L.markerClusterGroup().addTo(map),
disableClusteringAtZoom = 2;
function changeClustering() {
if (map.getZoom() >= disableClusteringAtZoom) {
mcg.disableClustering(); // New method from sub-plugin.
} else {
mcg.enableClustering(); // New method from sub-plugin.
}
}
map.on("zoomend", changeClustering);
$('#mcluster').click(function () {
disableClusteringAtZoom = (disableClusteringAtZoom === 2) ? 5 : 2;
changeClustering();
});
mcg.addLayers(arrayOfMarkers);
// Initially disabled, as if disableClusteringAtZoom option were at 2.
changeClustering();
Demo: http://jsfiddle.net/fqnbwg3q/3/
Note: in the above demo I used a refinement to make sure the markers merge with animation when clustering is re-enabled. Simply use a timeout before using enableClustering():
// Use a timeout to trigger clustering after the zoom has ended,
// and make sure markers animate.
setTimeout(function () {
mcg.enableClustering();
}, 0);
I'm developing an app with Google maps that should display several categories on a map. Now I would like to have the possibility to add markers from several categories and delete them as well if necessary.
I've managed to figure out the whole thing. At least, almost... I'm having troubles with the removal of the markers of a category. I've created a live demo on jsfiddle to make this clear.
So here's how I attempt to do this:
CODE
First I initialize the map, etc. (but that is not relevant here). Then I add the markers on the map:
for(i in markers){
var marker = new google.maps.Marker({
map: map,
draggable: false,
position: new google.maps.LatLng(markers[i].latitude, markers[i].longitude),
visible: true,
data: category
});
newMarkers.push(marker);
}
As you can see I have 'data: category' in the object. This is something that's not google maps api, but it gives me no errors and gives me the possibility to search the array when I want to remove the markers. Here the removeMarker function:
function removeMarkers(category)
{
for(i in newMarkers) {
if(newMarkers[i]['data'] == category){
count ++;
newMarkers[i].setMap(null);
newMarkers.splice(i, 1);
}
}
}
It does remove markers, but not all of them...
Does anyone have solution to my problem?
LIVE DEMO
Thanks in advance,
Helena S.
Seems like the problem is that you are iterating the newMarkers array and at the same time removing elements from it.
Try this instead. It only sets the removed marker values in the array to null then, after the loop, filters those null values:
for(i in newMarkers) {
if(newMarkers[i]['data'] == category){
count ++
newMarkers[i].setMap(null);
newMarkers[i] = null;
}
}
newMarkers = newMarkers.filter(function(val){ return !!val; });
http://jsfiddle.net/GJUcy/
I have a map with various markers and i need to be able to draw a rectangle on the map and select the markers which are within the rectangle bounds.
So far i have found some great info here: How to get markers inside an area selected by mouse drag?
I have implemented the keymapzoom plugin ok. like so
$('#dispatcher').gmap3({action:'get'}).enableKeyDragZoom({
boxStyle: {
border: "dashed black",
//backgroundColor: "red",
opacity: 0.5
},
paneStyle: {
backgroundColor: "gray",
opacity: 0.2
}
});
var dz = $('#dispatcher').gmap3({action:'get'}).getDragZoomObject();
google.maps.event.addListener(dz, 'dragend', function (bnds) {
alert(bnds);
});
This gives me the following
((lat,long),(lat,long)) format from the alert(bnds);
I need to know how i can now check if any markers are within this?
I already have an object that is storing the markers for another reason. like:
markers[name] = {};
markers[name].lat = lati;
markers[name].lng = longi;
which might be useful?
I don't understand how to use the GLatLngBounds and containsLatLng(latlng:GLatLng) as suggested.
Your question is tagged with the v3 version of the Maps API, so I'll assume you are using that version (which you should as v2 is deprecated). Note that some classes and methods are named different than in your question.
Bounds are represented with the LatLngBounds class. You can perform the contains method on an instance of that class to determine if a point lies within those bounds.
If you have an object with all your markers, you can loop through them and check each marker, for example:
var bounds = new google.maps.LatLngBounds(sw, ne);
for (var a in markers) {
if (bounds.contains(new google.maps.LatLng(markers[a].lat, markers[a].lng)) {
// marker is within bounds
}
}
On a side note, I would store the LatLng object in the markers object when creating them. That way you don't have to create them wherever you need.
Box/Rectangle Draw Selection in Google Maps
This was my solution..
google.maps.event.addListener(dz, 'dragend', function(e) { //important listener
for(var i = 0; i < markers.length; i++){ // looping through my Markers Collection
if(e.contains(markers[i].position))
console.log("Marker"+ i +" - matched");
}
});