Add layers in MapSettingsControl dynamically so that I can toggle there visibility.
When I tried to add layer in mapSettingControl It was disabled.
Background:
I have a web app developed using leaflet. I have 5 layers as shown in figure-1. Its working fine in leaflet. Now I am using HERE Maps javascript API for developing same web app.
How I did in Leaflet:
I add them as map overlays when adding layer control i.e.
let layerControl = L.control.layers(baseMaps, overlayMaps).addTo(map);
while when I need to add overlay in layer control dynamically I use following:
layerControl.addOverlay(somelayer, "layer name");
This work fine.
How I am doing by using Here Maps js api:
As I have five layers, two are cluster layers while two are marker layer and one geojson.
I have tried to apply same approach by creating GROUP for five layers and adding them into the layers of map setting controls.
public clusterGroup1 = new H.map.Group();
public clusterGroup2 = new H.map.Group();
public markerGroup1 = new H.map.Group();
public markerGroup2 = new H.map.Group();
public boundary = new H.map.Group();
created customized map setting ui :
this.customizedMapSetting = new H.ui.MapSettingsControl({
baseLayers: [{
label: "Normal", layer: defaultLayers.vector.normal.map
}],
layers: [{
label: "Cluster-1",
layer: this.clusterGroup1
},
{
label: "Cluster-2",
layer: this.clusterGroup2
},
{
label: "Marker-1",
layer: this.markerGroup1
},
{
label: "Marker-2",
layer: this.markerGroup2
},
{
label: "Geojson",
layer: this.boundary
}]
});
this.customizedMapSetting.setAlignment('top-right');
ui.addControl("customized", this.customizedMapSetting);
I am adding markers to a group like this:
dataArray.forEach(data=> {
let lat = data.latlng[0];
let lng = data.latlng[1];
var marker = new H.map.Marker({ lat: lat, lng: lng }, { icon: icon});
this.markerGroup1.addObject(marker);
});
Problem Statement
I am unable to get this mapSetting ui working for my layers.
How can I add clusterlayers in MapSettingControl so that I can toggle (show/hide) them? (I think I am not using right approach of group) When I add them as a map.addLayer(clusterLayer) it work fine.
How Should I add layer dynamically in MapSettingControl? Possible alternative of leaflet method :
layerControl.addOverlay(somelayer, "layer name");
Looking at the API, it seems MapSettingsControl.Options has
layers: {
label: 'test',
layer: instance of H.map.layer.Layer
}
The error we get when toggling is InvalidArgumentException from DataModel.add regarding the first argument. I believe this means that on toggle, DataModel.add is called and passed the H.map.Group that is being set in the MapSettingsControl, but the DataModel.add expects a H.map.layer.Layer but receives the H.map.Group.
I'm not sure if it's possible to simply add a H.map.Group in MapSettingsControl. I think we have to somehow add the H.map.Group as a provider for a H.map.layer.Layer and add the Layer object to MapSettingsControl.
EDIT
As for adding cluster. When I try to add a new layer for the cluster, it is grayed out. The cluster provider is created and the ObjectLayer is created as well but I think after you have created the MapSettingsControl and defined the variable that will act as the H.map.layer.Layer, updating the variable will have no effect on the toggle behaviour.
Related
So in leaflet I can do this:
const [groupedLayers] = useState<DeviceFeedLayerGroups>({
mine: new LayerGroup(),
public: new LayerGroup(),
private: new LayerGroup(),
favorite: new LayerGroup(),
});
const onEachFeature = (
feature: Feature<Geometry, NexusGenAllTypes['GeoJSONFeatureProperties']>,
layer: L.Layer,
) => {
/* ... */
groupedLayers[feature.properties.relation].addLayer(layer);
}
geoJSON(deviceFeed, {
pointToLayer,
onEachFeature,
});
This way I can have groups of layers that can be turned on or off. Can this be done with mapbox-gl?
Thanks.
I don't totally understand the Leaflet functionality you're talking about, but:
Mapbox GL JS doesn't support "groups" of layers. However, you could make one GeoJSON source, with several layers that display different features from it, using a filter. Then each layer can be shown or hidden independently.
In my app I had to develop a system that allows the user, with a double click, to zoom in to a cluster.
Everything work, but the problem is that the double click add a feature on the map (a point) and it is persistent (it also replace the feature I selected in case I select not the cluster but the single element, even if I have specified that features.length>=2, so the double click should work only if the user doubles click on the cluster, but it is not like that ).
I would like the select interaction perform only the zoom into the cluster and not that the event adds also a feature on the map. How could I solve this?
var selectDoubleClick = new ol.interaction.Select({
multi: true,
condition: ol.events.condition.doubleClick,
layer: this.clusterLayer,
style: this.selectedClusterStyle
});
selectDoubleClick.on('select',function(event) {
var eventFeature = event.selected[0];
var features = eventFeature.get('features');
if (features.length>=2){
var extent = ol.extent.createEmpty();
features.forEach(function(feature) {
ol.extent.extend(extent, feature.getGeometry().getExtent());
});
this.getMap().getView().fit(extent, {padding: [150, 150, 150, 150]})
}
});
this.map.addInteraction(selectDoubleClick);
I also tried to set selectDoubleClick style:null but it doesn't solve my problem
Follow this discussion, I finally found a solution:
Openlayers 4 - Make layer invisible on feature click
In particular:
The ol.interaction.Select selected features are added to an internal
unmanaged layer.
This is why the selected feature is visible even if the underlying
layer is not.
You could unselect the selected features while you zoom on it using
select_interaction.getFeatures().clear() (just like clicking away).
So I edited my code like that:
selectDoubleClick.on('select',function(event) {
var eventFeature = event.selected[0];
var features = eventFeature.get('features');
if (features.length>1){
var extent = ol.extent.createEmpty();
features.forEach(function(feature) {
ol.extent.extend(extent, feature.getGeometry().getExtent());
});
this.getMap().getView().fit(extent, {padding: [150, 150, 150, 150]})
}else{
selectDoubleClick.getFeatures().clear()
}
});
this.map.addInteraction(selectDoubleClick);
I'm using the leaflet snaking polyline to draw a route on a map with multiple markers, and have it working. However, I want to make the snaking speed a setting that the user can change, so I need to be able to modify the default snaking speed when I add the layerGroup to the layer. To add the layer with the default snaking speed I simply have the following line of code (and it works):
layerGrp.addLayer( endMarker );
layerGrp.addTo(polyLayer).snakeIn();
But I want to really add
layerGrp.addLayer(endMarker, { snakingSpeed: snakingSpeedFromUser } );
layerGrp.addTo(polyLayer).snakeIn();
I've tried what's shown above, and also just
layerGrp.addLayer( {snakingSpeed: snakingSpeedFromUser } );
But both of them give me a runtime error of
Uncaught (in promise) Error: The provided object is not a Layer.
Polylayer is a layergroup so I can show/hide the polylines. Here's where it is added to the map:
var gridLayer = L.layerGroup([]);
var polyLayer = L.layerGroup([]);
var overlayMaps = { "Track": polyLayer, "Grid": gridLayer };
var layerControls = { "Map": mapLayer,
"Track": polyLayer,
"Grid": gridLayer };
How can I add the options to the layerGroup dynamically at runtime?
Thanks......
First of all I would like to thank you all for amazing libraries like leaflet/leaflet.draw and leaflet.snap.
What I want to do is outside leaflet.draw control with supporting leaflet snap. This is nicely working with in side map draw control.
Below I show how did I call outside leaflet draw control:
<div><button id="draw_mark1" onclick="drawMarker1()" >Draw Marker1</button></div>
<div><button id="draw_polyline1" onclick="drawPolyline1()" >Draw Polyline1</button></div>
function drawMarker1(){
var markerDrawer1 = new L.Draw.MarkerA(map, { icon: new myIcon_xx() });
markerDrawer1.enable();
}
function drawPolyline1(){
var polylineDrawer1 = new L.Draw.PolylineType1(map);
polylineDrawer1.enable();
}
note:- leaflet.snap not in the tag list. I want to tag it too.
I'm still learning and I'm a bit stuck. I may be trying to do to much at once. I have a MapBox map working great with a clickable layer menu taken from examples on the MapBox site. I also have a MarkerClusterGroup which also works and is always visible on the map. Is there a way I could somehow have the MarkerClusterGroup clickable on/off just like layers identified in var overlays = { ...
Below is the code that I think needs the help:
var layers = {
Streets: L.mapbox.tileLayer('mapbox.streets').addTo(map),
Satellite: L.mapbox.tileLayer('mapbox.satellite'),
Light: L.mapbox.tileLayer('mapbox.light'),
};
var overlays = {
DataA: L.mapbox.featureLayer().loadURL('/data/ctsnew.geojson'),
DataB: L.mapbox.featureLayer().loadURL('/data/selectZipcodes.geojson'),
};
// Since featureLayer is an asynchronous method, we use the `.on('ready'`
// call to only use its marker data once we know it is actually loaded.
Markers: L.mapbox.featureLayer('examples.map-h61e8o8e').on('ready', function(e) {
// The clusterGroup gets each marker in the group added to it
// once loaded, and then is added to the map
var clusterGroup = new L.MarkerClusterGroup();
e.target.eachLayer(function(layer) {
clusterGroup.addLayer(layer);
});
map.addLayer(clusterGroup);
});
Could be something as simple as misuse of brackets. Thanks in advance.
You have to include your Marker Cluster Group in your overlays object. For example you could instantiate it just before defining overlays, even if your Cluster Group is empty for now.
Then you fill it once it has downloaded its data.
var layers = {
Streets: L.mapbox.tileLayer('mapbox.streets').addTo(map),
Satellite: L.mapbox.tileLayer('mapbox.satellite'),
Light: L.mapbox.tileLayer('mapbox.light'),
};
var clusterGroup = L.markerClusterGroup();
var overlays = {
DataA: L.mapbox.featureLayer().loadURL('/data/ctsnew.geojson'),
DataB: L.mapbox.featureLayer().loadURL('/data/selectZipcodes.geojson'),
Markers: clusterGroup
};
// Since featureLayer is an asynchronous method, we use the `.on('ready'`
// call to only use its marker data once we know it is actually loaded.
L.mapbox.featureLayer('examples.map-h61e8o8e').on('ready', function(e) {
// The clusterGroup gets each marker in the group added to it
// once loaded, and then is added to the map
e.target.eachLayer(function(layer) {
clusterGroup.addLayer(layer);
});
map.addLayer(clusterGroup); // use that line if you want to automatically add the cluster group to the map once it has downloaded its data.
});