How to use the .openPopup method in a feature group? - leaflet

I have a set of markers that have binded popups, but I can't figure out how to show all the popups when the marker group is toggled in the layers control.
For example, I have my markers like so:
var testMarker = L.marker([32.9076,33.35449]).bindPopup('Marker 1');
var testMarkerTwo = L.marker([33.58259,34.64539]).bindPopup('Marker 2');
Then, I put it in a freature group and append the openPopup method:
var markerGroup = L.featureGroup([testMarker,testMarkerTwo]).openPopup().addTo(map);
This doesn't work.
My final goal is to add that featureGroup to my layers control where I can toggle the group off/on. Before I get to that part, I need to first understand why the openPopup method is not working.
Edit: The answer below appears to only work with the plain Leaflet API, not the Mapbox API.

There are a couple problems here. The first is that by default, Leaflet closes the previously opened popup each time another is opened. The second is that, while your markers have popups bound to them, markerGroup does not, and even if it did, markerGroup.openPopup would only cause a single popup to open.
To get around the first problem, you can use the hack from this answer. If you place the following code at the beginning of your script (before you define your map) it will override the default behavior and allow you to open multiple popups at once:
L.Map = L.Map.extend({
openPopup: function(popup) {
this._popup = popup;
return this.addLayer(popup).fire('popupopen', {
popup: this._popup
});
}
});
Then, once you are able to open multiple popups, you can open all popups in markerGroup using the eachLayer method:
var markerGroup = L.featureGroup([testMarker,testMarkerTwo]).addTo(map);
markerGroup.eachLayer(function(layer) {
layer.openPopup();
});
Here is an example fiddle:
http://fiddle.jshell.net/nathansnider/02gsb1Lt/

Related

Get leaflet marker from a layer

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.

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.

Leaflet Spiderfier/MarkerCluster - Automatically spiderfy dynamic markers

I'm building an online version of a boardgame using Leaflet as the viewport.
My source: https://github.com/edenLOL/gotta-chug-em-all/tree/master
What I'm trying to achieve, is a way to spiderfy/spread out markers that land on the same square as each other, including when they move past each other.
I'm using https://github.com/jawj/OverlappingMarkerSpiderfier-Leaflet to Spiderfy the markers, which appears to work when clicking the markers.
However, I need these markers to be spiderfied always, without requiring a click event. So I set keepSpiderfied: true for the spiderfier object (oms).
var options = { //**spiderfier
keepSpiderfied: true,
nearbyDistance: 120
};
oms = new OverlappingMarkerSpiderfier(map, options); //**spiderfier
But this doesn't work. I can't seem to load the markers in a spiderfied state, it always requires a click to spiderfy them.
For context, markers are generated dynamically during a prompt before the user sees the map.
('#playerIcons > table > tbody > tr > td').on('click', function(){
pokemonSelected = $(this).attr('class');
if ( !$(this).hasClass('pokemonSelected') ){
playerArray[pokeCounter].pokemon = ''+ pokemonSelected +'';
playerArray[pokeCounter].marker = L.marker([playerArray[pokeCounter].coords[0], playerArray[pokeCounter].coords[1]], {
icon: window[pokemonSelected]
}).addTo(map);
oms.addMarker(playerArray[pokeCounter].marker) //**spiderfier
pokeCounter += 1;
} else {
return false;
};
});
I've also tried using Leaflet/Leaflet.markercluster. This works to an extent, and spiderfies the Markers at defined zoom levels, however the markers don't move, and stay stacked on top of each other.
What am I missing here that could be causing these issues? I don't mind using either Spiderfier or MarkerCluster, as both should be able to provide the solution I'm looking for once either issue is fixed.
Spiderfier: Markers need to spiderfy automatically
MarkerCluster: Markers don't physically move when spiderfying out of cluster
Note: If you decide to open index.html, be aware the Pokemon theme song will autoplay in the background on page load (until the map is drawn), so check your volume :)
I solve the problem like this, using fire('click') аfrom leaflet.
scope.spiderMarker - the marker, i want to spidrefy. In your case i think its playerArray[pokeCounter].marker
try{
scope.spiderMarker.fire('click')}
catch (e) {
console.log(e);
};

Mouse over popup on leaflet.js marker

How can I add a mouse over pop up on leaflet.js marker . the pop up data will be dynamic.
I have a service which returns a lat & lon positions which will mark on a map.
I would require a popup on mouse over a marker . the event should send the lat and long position for ex to : http://api.openweathermap.org/data/2.5/weather?lat=40&lon=-100
the data from service should be in popup content.
I have tried but cant build the pop up content dynamically each marker
Please do the needful.
below is the code i have used for markers statesdata is array which stores the lat and longitude values
for ( var i=0; i < totalLength1; i++ ) {
var LamMarker = new L.marker([statesData1[i].KK, statesData1[i].LL]).on('contextmenu',function(e) {
onClick(this, i);
}).on('click',function(e) {
onClick1(this, i)
});
marker_a1.push(LamMarker);
map.addLayer(marker_a1[i]);
on click we call click1 function on context of marker we call click function
How can i add a pop on mouse over passing lat and long from the above code?
Attaching a popup to a marker is fairly easy. It is done by calling the bindPopup method of your L.Marker instance. Per default a popup opens on the click event of the L.Marker instance and closes on the click event of your L.Map instance. Now if you want to do something when a popup opens you can listen to the popupopen event of your L.Map instance.
When you want fetch external data in the background on the popupopen event that is usually done via XHR/AJAX. You can write your own logic or use something like jQuery's XHR/AJAX methods like $.getJSON. Once you receive response data you can then update your popup's content.
In code with comments to explain further:
// A new marker
var marker = new L.Marker([40.7127, -74.0059]).addTo(map);
// Bind popup with content
marker.bindPopup('No data yet, please wait...');
// Listen for the popupopen event on the map
map.on('popupopen', function(event){
// Grab the latitude and longitude from the popup
var ll = event.popup.getLatLng();
// Create url to use for getting the data
var url = 'http://api.openweathermap.org/data/2.5/weather?lat='+ll.lat+'&lon='+ll.lng;
// Fetch the data with the created url
$.getJSON(url, function(response){
// Use response data to update the popup's content
event.popup.setContent('Temperature: ' + response.main.temp);
});
});
// Listen for the popupclose event on the map
map.on('popupclose', function(event){
// Restore previous content
event.popup.setContent('No data yet, please wait...');
});
Here's a working example on Plunker: http://plnkr.co/edit/oq7RO5?p=preview
After comments:
If you want to open the popup on hover instead of click you can add this:
marker.on('mouseover', function(event){
marker.openPopup();
});
If you want to close the popup when you stop hovering instead of map click add this:
marker.on('mouseout', function(event){
marker.closePopup();
});
Here's an updated example: http://plnkr.co/edit/wlPV4F?p=preview
I got fed up with fighting with leaflet's built in functionality. The first thing I did was use the alt option to assign a key to the marker:
var myLocation = myMap.addLayer(L.marker(lat,lng],{icon: icon,alt: myKey}))
The next thing was assign an id using this alt and a title via jQuery (why you can't do that by default irritates me):
$('img[alt='+myKey+']').attr('id','marker_'+myKey).attr('title',sRolloverContent)
Then, I used jQuery tooltip (html will only render this way):
$('#marker_'+myKey).tooltip({
content: sRolloverContent
})
Also, by using the jQuery tooltip instead of the click-only bindPopup, I am able to fire the tooltip from my list, where the row has a matching key id:
$('.search-result-list').live('mouseover',function(){
$('#marker_'+$(this).attr('id')).tooltip('open')
})
$('.search-result-list').live('mouseout',function(){
$('#marker_'+$(this).attr('id')).tooltip('close')
})
By adding the id, I can easily use jQuery to do whatever I want, like highlight a list of locations when the marker is hovered:
$('#marker_'+iFireRescue_id).on('mouseover',function(){
('tr#'+getIndex($(this).attr('id'))).removeClass('alt').removeClass('alt-not').addClass('highlight')
})
$('#marker_'+myKey).on('mouseout',function(){
$('tr#'+getIndex($(this).attr('id'))).removeClass('highlight')
$('#search-results-table tbody tr:odd').addClass('alt')
$('#search-results-table tbody tr:even').addClass('alt-not')
})

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?