Get leaflet marker from a layer - leaflet

I'm new to leaflet and am trying to implement a set of markers with different CSS-styles.
So, I am aware that after adding a marker to a map I can access different CSS-attributes by calling getElement() on my marker for example:
marker.addTo(map);
marker.getElement().style.borderColor = '#000';
This works just fine, but when adding a marker to a layer, this can no longer be used since a TypeError occurs (getElement() is undefined). Here is the example code where the error occurs:
myLayer.addLayer(marker);
marker.getElement().style.borderColor = '#000';
Am I overlooking a simpler way to set CSS-Attributes for markers and divicons that are added to layers or is there a similar way to access layer-added markers and divicons in JavaScript?

So I found a solution that is working for me.
The idea is to extend the function that is used to create the icon.
Last answer here github.com/Leaflet/Leaflet/issues/5231 helped a lot.
var borderSize = ...;
L.DivIcon.Custom = L.DivIcon.extend({
createIcon: function(oldIcon) {
var icon = L.DivIcon.prototype.createIcon.call(this, oldIcon);
icon.style.borderSize = borderSize;
...
return icon;
}
})
var icon = new L.DivIcon.Custom({
...
});
var ll = L.latLng(entry.Longitude, entry.Latitude);
var marker = L.marker(ll, {
icon: icon
})
this.myLayer.addLayer(marker);

Welcome to SO!
When not added onto a map (since your parent myLayer may not be added to the map itself), a marker does not have any element.
If you do not need to change too many styles individually and dynamically, you might rather use the className option of your Icon / DivIcon.

Related

Remove Leaflet overlayMaps layer programmatically

Using Leaflet javascript. I would like my "clear button" to do two things...
1) uncheck all the L.Control layers
2) remove the current overlay from the map
I can do the first easily enough using this code:
var checks = document.querySelectorAll('[type = "checkbox"]'), i;
function uncheckBoxes() {
for (i = 0; i < checks.length; ++i) {
checks[i].checked = false;
}
}
The next is a little more tricky. I have tried using the removeLayer() and clearLayers() function but they do not work. I don't see a way in the leaflet documentation to remove an L.control overlayMap layer from the map unless you physically uncheck it yourself.
Any insight into this would be greatly appreciated.
Not exactly sure what is your difficulty in programmatically removing some layers / overlays from your map.
It is normally trivial (map.removeLayer(layer)), and the Layers Control automatically reflects what is happening on the map (in that case, if layer is one of the overlays, its associated checkbox will become unticked).
As for removing all your overlays from map, you just need to keep a reference to those overlays, loop through them and remove them from the map:
var overlays = {
'Name 1': someLayer,
'Name 2': someOtherLayer
};
L.control.layers(null, overlays).addTo(map);
// Whenever you want to remove all overlays:
for (var name in overlays) {
map.removeLayer(overlays[name]);
}
Demo: https://jsfiddle.net/3v7hd2vx/357/

leafeltjs (mapbox) z-index ordering not working

Another developer created our original map but I'm tasked with making some changes. One of these is making sure the activated marker is brought to the front when clicked on (where it is partially overlapped by other markers).
The developers have used mapbox 2.2.2.
I have looked at leafletjs's docs, have followed some instructions on other posted solutions (e.g. solution one and solution two). Neither of these makes any difference.
Examining the marker in Chrome's console I can see the value of options.zIndexOffset is being set (10000 in my test case). I've even set _zIndex to an artificially high value and can see that reflected in the marker's data structure. But visually nothing is changing.
This is how the map is set up initially. All features are from a single geojson feed:
L.mapbox.accessToken = '<access token here>';
var map = L.mapbox.map('map', 'map.id', {
}).setView([37.8, -96], 3);
var jsonFeed, jsonFeedURL;
var featureLayer = L.mapbox.featureLayer()
.addTo(map)
.setFilter(function (f) {
return false;
});
$.getJSON(jsonFeedURL, function (json) {
jsonFeed = json;
jsonFeedOld = json;
// Load all the map features from our json file
featureLayer.setGeoJSON(jsonFeed);
}).done(function(e) {
// Once the json feed has loaded via AJAX, check to see if
// we should show a default view
mapControl.activateInitialItem();
});
Below is a snippet of how I had tried setting values to change the z-index. When a visual marker on the featureLayer is clicked, 'activateMarker' is called:
featureLayer.on('click', function (e) {
mapControl.activateMarker(e);
});
The GEOjson feed has urls for the icons to show, and the active marker icon is switched to an alternative version (which is also larger). When the active feature is a single Point I've tried to set values for the marker (lines commented out, some of the various things I've tried!)
activateMarker: function (e) {
var marker = e.layer;
var feature = e.layer.feature;
this.resetMarkers();
if (feature.properties.hasOwnProperty('icon')) {
feature.properties.icon['oldIcon'] = feature.properties.icon['iconUrl'];
feature.properties.icon['iconUrl'] = feature.properties.icon['iconActive'];
feature.properties.icon['oldIconSize'] = feature.properties.icon['iconSize'];
feature.properties.icon['iconSize'] = feature.properties.icon['iconSizeActive'];
}
if (feature.geometry.type == 'Point') {
marker.setZIndexOffset(10001);
marker.addTo(featureLayer);
}
//featureLayer.setGeoJSON(jsonFeed);
}
Any advice would be greatly appreciated! I'm at the point where I don't know what else to try (and that's saying something).
What probably happens is that you just flush your markers with the last call to .setGeoJSON():
If the layer already has features, they are replaced with the new features.
You correctly adjust the GeoJSON data related to your icon, so that when re-created, your featureLayer can use the new values to show a new icon (depending on how you configured featureLayer).
But anything you changed directly on the marker is lost, as the marker is removed and replaced by a new one, re-built from the GeoJSON data.
The "cleanest" way would probably be to avoid re-creating all features at every click.
Another way could be to also change something else in your GeoJSON data that tells featureLayer to build your new marker (through the pointToLayer option) with a different zIndexOffset option.

Unable to add marker to Angular Leaflet directive

I'm trying to add a marker to the Leaflet directive but somehow it doesn't accept markers created with the default L.marker() method.
The directive is used as follows:
<leaflet markers="markers" center="center" layers="layers" defaults="defaults"></leaflet>
I'm extending my $scope in the controller as prescribed:
angular.extend($scope, {
markers: {},
//markers: { { someName: {lat:52.163815,lng:5.365131} } //this does work
});
Adding a marker afterwards doesn't work somehow. First the .markers object is not an array, so I can't just add any elements using push(). But even adding an element as associative array doesn't work:
var marker = L.marker(L.latLng(52.163815, 5.365131));
$scope.markers[0] = marker;
The error is:
[AngularJS - Leaflet] The marker definition is not valid.
[AngularJS - Leaflet] Received invalid data on the marker 0.
I'm overlooking something very simple but I've got no idea what... Any lead would be greatly appreciated.
$scope.markers is expecting to get an object with marker properties, not the marker itself. What would work in your example is just a LatLng object, before wrapping it as Marker.
$scope.markers[0] = L.latLng(52.163815, 5.365131);
Or, if you get Markers from the outside, you can get it back from the inside:
$scope.markers[0] = marker.getLatLng();
Obviously, that doesn't convey another markers' properties, just coordinates.

Leaflet Maps Marker Popup Open on Hashtag from URL

I am passing a latlng from a link on another page to my map. My map has the markers based on this latlng. So what I am passing is exactly what the map markers are using to show on the map.
var hash = window.location.hash;
var hashless = hash.replace("#", "");
var ll = hashless.split(",", 2);
map.setView(new L.LatLng(ll[0], ll[1]), 14);
This is working great, but I am struggling at getting the marker to show it's infowindow. I would like only the link clicked on to be the marker that is showing it's popup. I am able to zoom right to the marker, but not able to get the popup to work in a reasonable way.
I have tried a few things, but map.getBounds() seems to be the one I should be working with, unless you can ID a marker based on Lat/Lng. Can you?
I am using bounds in the map.on function.... but none of the events seems to really work well. Originally thought LOAD would do it, but no results... viewreset, mousemove, etc... all show the popup in this simple function, but it is not really any good as it flickers etc... when moving things around:
map.on('viewreset', function () {
// Construct an empty list to fill with onscreen markers.
console.log("YA");
var inBounds = [], bounds = map.getBounds();
datalayer.eachLayer(function (marker) {
if (bounds.contains(marker.getLatLng())) {
inBounds.push(marker.options.title);
marker.openPopup();
}
});
});
How can I set the marker.openPopup() from my link to the current marker at that lat/lng passed to it?

Why doesn't marker.dragging.disable() work?

The following code receives an error on the lines for enabling and disabling the marker dragging ("Unable to get property 'disable' of undefined or null reference"). The markers show up on the map just fine and are draggable as the creation line indicates. Placing an alert in place of the enable line produces a proper object so I believe the marker is defined. Is there something I need to do to enable the IHandler interface? Or am I missing something else?
var marker = L.marker(L.latLng(lat,lon), {icon:myIcon, draggable:'true'})
.bindLabel(name, {noHide: true,direction: 'right'});
marker._myId = name;
if (mode === 0) {
marker.dragging.enable();
} else {
marker.dragging.disable();
}
I had a similar problem today (perhaps the same one) it was due to a bug in leaflet (see leaflet issue #2578) where changing the icon of a marker invalidates any drag handling set on that marker. This makes any calls to marker.dragging.disable() fail.
The fix hasn't made it into leaflets master at time of writing. A workaround is to change the icon after updating the draggable status if possible.
marker.dragging.disable();
marker.setIcon(marker_icon);
Use the following code to make an object draggable. Set elementToDrag to the object you wish to make draggable, which is in your case: "marker"
var draggable = new L.Draggable(elementToDrag);
draggable.enable();
To disable dragging, use the following code:
draggable.disable()
A class for making DOM elements draggable (including touch support).
Used internally for map and marker dragging. Only works for elements
that were positioned with DomUtil#setPosition
leaflet: Draggable
If you wish to only disable the drag option of a marker, then you can use the following code (where "marker" is the name of your marker object):
marker.dragging.disable();
marker.dragging.enable();
I haven't found an answer but my workaround was this:
var temp;
if (mode === 0) {
temp = true;
} else {
temp = false;
}
var marker = L.marker(L.latLng(lat,lon), {icon:myIcon, draggable:temp})
.bindLabel(name, {noHide: true,direction: 'right'});
marker._myId = name;
Fortunately I change my icon when it is draggable.