I am using leafletjs to build a web map and trying to figure out how to show a modal window when a marker is clicked (instead of the default popup method).
Here's my setup:
var myAirports = L.geoJson(myData, {
pointToLayer: function(latlng){
..snip..
},
onEachFeature: function(feature,layer){
$('#myModalOne').modal(options);
}
});
myAirports.addTo(map);
My HTML is like so:
<div id="myModalOne">....</div>
<div id="myModalTwo">....</div>
Lets say my data has a featurecollection with a key of 'name' (i.e., 'name': 'Bush Airport') for each feature. Would I just add a switch statement to my onEachFeature function?
Just need a little guidance,thanks.
Note: I am using Bootstrap for the modal windows
If I understand you correctly, you don't need to set the pointToLayer option which is useful if you want to display something else than a marker.
What you need is to catch the click event on the markers and display a modal window. There is no popup by default.
var myAirports = L.geoJson(myData, {
onEachFeature: function(feature,layer){
layer.on('click', function(e){
$('#myModal'+feature.properties.name).modal(options);
// or whatever that opens the right modal window
});
}
});
myAirports.addTo(map);
Related
So, I know that we have Marker.togglePopup() in Mapbox GL API.
But can we close all popups programmatically?
Here is an example: https://jsfiddle.net/kmandov/eozdazdr/
Click the buttons at the top right to open/close the popup.
Given you have a popup and a marker:
var popup = new mapboxgl.Popup({offset:[0, -30]})
.setText('Construction on the Washington Monument began in 1848.');
new mapboxgl.Marker(el, {offset:[-25, -25]})
.setLngLat(monument)
.setPopup(popup)
.addTo(map);
You can close the popup by calling:
popup.remove();
or you can open it by calling:
popup.addTo(map);
As you can see in the Marker source, togglePopup uses these two methods internally:
togglePopup() {
var popup = this._popup;
if (!popup) return;
else if (popup.isOpen()) popup.remove();
else popup.addTo(this._map);
}
The accepted answer didn't apply to my use case (I wasn't using a Marker). I was able to come up with a different solution by utilizing the mapbox's built-in event workflow. Hopefully this helps someone else.
Mapbox allows you to listen to events on the map (and manually trigger them). The documentation doesn't mention it, but you can use custom events.
Given you have a popup:
// Create popup and add it to the map
const popup = new mapboxgl.Popup({ offset: 37, anchor: 'bottom' }).setDOMContent('<h5>Hello</h5>').setLngLat(feature.geometry.coordinates).addTo(map);
// Add a custom event listener to the map
map.on('closeAllPopups', () => {
popup.remove();
});
When you want to close all popups, fire the event:
map.fire('closeAllPopups');
Mapbox automatically uses the class .mapboxgl-popup for the popup. You can also add additional classes with options.className.
So, if you have jQuery available, just do:
$('.mapboxgl-popup').remove();
Or plain javascript:
const popup = document.getElementsByClassName('mapboxgl-popup');
if ( popup.length ) {
popup[0].remove();
}
I'm pretty sure you can assume there's only ever one popup open. The default behavior seems to be that if one is open and a second item is clicked, the first popup is removed from the DOM completely when the second one opens. If your application allows multiple open popups somehow, you will need to loop through and remove each with plain js, instead of using the first item only.
I know it's an old question but I recently worked on Mapbox. As of mapbox-gl v2.3, mapboxgl.Popup has a closeOnClick property where if set to true, the popup disappears when you click away from the popup.
let popup = new mapboxgl.Popup({
anchor: "top",
closeOnClick: true,
});
map.on(
"click",
"location",
(e) => {
map.getCanvas().style.cursor = "pointer";
let coordinates = e.features[0].geometry.coordinates.slice();
popup
.setLngLat(coordinates)
.setHTML("what I want to display")
.addTo(map);
}
);
Alternatively, you can show the popup on "mouseenter" instead of on "click" and add a "mouseleave" event to remove the popup:
map.on(
"mouseleave",
"location",
() => {
map.getCanvas().style.cursor = "";
popup.remove();
}
);
wrap your popup with React.StrictMode and closeOnClick={false}.
const [popup, setPopup] = useState<boolean>(false);
...
{popup && (
<React.StrictMode>
<Popup longitude={52.001126260374704} latitude={34.906269171550214}
anchor="bottom"
onClose={() => {
setPopup(false)
}}
closeOnClick={false}
>
You are here
</Popup>
</React.StrictMode>
)}
I have a google map application built using the gmap3 plugin that draws dynamic overlays when a marker is clicked. I am trying to make a button inside the overlay to "dismiss" the overlay using this line from my script:
$('.dismiss-overlay').click(function() {
$(this).parent('div').fadeOut();
})
I have tested this and everything appears to function just fine when placed outside of the gmap overlay, but when inside the overlay clicking on the button causes nothing to happen. Below is the full script:
$("#map_canvas").gmap3({
map:{
options:{
streetViewControl: false,
mapTypeControl: false,
zoom: 0
}
},
marker:{
values: markers,
options:{
draggable: false,
icon: "files/map-marker.png"
},
events:{
click: function(marker, event, context) {
$(this).gmap3({
clear:"overlay",
overlay: {
latLng: marker.getPosition(),
options: {
content: '<div class="container overlay"><button class="btn btn-xs dismiss-overlay">x close</button>'+$("#"+context.data.id).html()+'</div>',
offset: {
y: -30,
x: 30
}
}
},
});
$(this).gmap3('get').panTo(marker.getPosition());
$(this).gmap3('get').panBy(150, 0);
}
}
},
autofit:{maxZoom: zoom},
});
});
if you need to see a working example: http://schaffner-publications.com/development/map/
Alright, I found the issue.
The thing is that you are creating your overlay dynamically and your event listener is registered during map.js file load. When user clicks 'More info' button on your sample page (http://schaffner-publications.com/development/map/), map is initialised and when user clicks on the marker its overlay is dynamically created and pushed to the page. Specially the close button div. Meaning browser doesn't know anything about the close button (or events on it) unless user clicks on a marker.
In short your event never gets fired because you registered events on .dismis-overlay divs that were available at the map.js load time (& there weren't any, as you create them dynamically).
So to resolve your issue try changing your map.js where you are setting overlay content to the following.
content: '<div class="container-fluid overlay"><button class="btn btn-xs dismiss-overlay" onclick="$(this).parent().toggle();">x close</button>'+$("#"+context.data.id).html()+'</div>',
I have added just below to your code:
onclick="$(this).parent().toggle();"
Not sure if there is specific reason for using gmap3 plugin. If I were you, I would use google map api without it, gives you more control. If you really need clustering, I would go for leaflet.
OLD ANSWER (See comments)
Instead of parent, just mention the id in the event:
$('.dismiss-overlay').click(function() {
$('#parkmap').modal('toggle');
})
On the other note, I tried fade-out and it just fades out the modal while the dark background still exists. Standard way of closing the modal will be to use toggle instead of fadeout.
Hope this helps. :)
I would like to be able to use checkboxes to toggle on/off layers on a map. The map will be loaded without any layers.
Right now my buttons look like this:
<label><input type="checkbox" name="points" value="addressPoints" /> ADDRESS POINTS</label>
I'm calling my GeoJSON layers like this:
L.geoJson(schoolDistricts, {
style: defaultStyle,
onEachFeature: function (feature, layer) {
layer.bindPopup("<h4>School District: " + feature.properties.name);
layer.setStyle(defaultStyle);
(function(layer, properties) {
layer.on("mouseover", function (e) {
layer.setStyle(highlightStyle);
});
layer.on("mouseout", function (e) {
layer.setStyle(defaultStyle);
});
})(layer, feature.properties.name);
}
});
I know I need to add a change event to the checkbox code. I just don't really know how to go about writing a function to toggle the layer on and off. I have about 10 layers I will need to do this for so I'd like to be able to have a function that I can use for them all.
Hopefully this is enough information to go on.
Thanks!
Leaflet has this capability built into the layers control via an overlay object. The layer control can accept an input for a basemap object and an overlay object. The basemaps are toggled with radio buttons, the overlays are toggled with checkboxes. Here's a simple example:
var basemapObj = {
"First Basemap": L.tileLayer(...),
"Second Basemap": L.tileLayer(...)
}
var overlayObj = {
"LayerA": L.geoJson(...),
"LayerB": L.geoJson(...)
}
L.control.layers(basemapObj, overlayObj).addTo(map);
The link listed in the comments above does the same thing as the built-in control, but requires that you write the code yourself and style the elements, etc. Using the base Leaflet controls is much simpler.
I am trying to draw country shapes on a leaflet map using L.GeoJSON(data).addTo(map). I then want to bind a popup to the click event of that country shape...
new L.GeoJSON(data, {
onEachFeature: function(feature, layer) {
layer['on']('click', popupFunction);
}
}).addTo(this.map);
popupFunction = function(event) {
var layer = event.target;
// Open the 'add' popup and get our content node
var bound = layer.bindPopup(
"<div>Hello World!</div>"
).openPopup();
// Ugly hack to get the HTML content node for the popup
// because I need to do things with it
var contentNode = $(bound['_popup']['_contentNode']);
}
Now this works fine when the data is a single polygon, because then the layer attribute passed to the onEachFeature function is just that: a layer.
However if the data is a multipolygon (i.e. the US) this stops working because the "layer" is now a layerGroup (it has a _layers) attribute and therefore has no _popup attribute and so I can't get the _contentNode for the popup.
It seems like this should be quite a common thing, wanting a popup on a layerGroup. Why does it have no _popup attribute?
short answer: layergroup does not support popup
plan B:
you should consider using FeatureGroup, it extends LayerGroup and has the bindPopup method and this is an example
L.featureGroup([marker1, marker2, polyline])
.bindPopup('Hello world!')
.on('click', function() { alert('Clicked on a group!'); })
.addTo(map);
You cannot bind a L.Popup to anything else than a L.Layer because the popup will some coordinates to anchor on.
For a L.Marker it will be the position (L.Latlng), for the L.Polygon it will be the center (look at the code to see how it is calculated).
As for the other cases (like yours), you can open a popup but you will have to decide where the popup opens:
var popup = L.popup()
.setLatLng(latlng)
.setContent('<p>Hello world!<br />This is a nice popup.</p>')
.openOn(map);
First of all, you should be able to bind popUp in similar way to Using GeoJSON with Leaflet tutorial. Something like this:
var geoJsonLayer = L.geoJson(data, {
onEachFeature: function(feature, layer) {
layer.bindPopup('<div>Hello World!</div>');
}
}).addTo(map);
How to further process your popUps depends on your usecase. Maybe this can be enough for you:
geoJsonLayer.eachLayer(function(layer) {
var popUp = layer._popup;
// process popUp, maybe with popUp.setContent("something");
});
Hope this helps..
I used this code to open all popups in a layer group:
markers.eachLayer(marker => marker.openPopup());
While dealing with layer groups, you might want to consider passing { autoClose: false, closeOnClick: false } options while binding popup, so popups won't get closed while opening new popup, or if user clicks on the map:
marker.bindPopup(item.name, { autoClose: false, closeOnClick: false });
My web application uses the following popup-overlay plugin to show profile content in a popup on the screen:
http://vast-eng.github.io/jquery-popup-overlay/
My problem is related to a Google Map - marker infowindow that I use within the popup window.
When I try to close the infowindow, the popup disappears as well.
This is wrong! I don't immediately see why it is doing this.
If I don't find a solution, I could disable or hide the X, but I prefer not to do this.
The "where" section in the following link shows you the problem:
http://www.zwoop.be/dev/#list/bars/1
Edit
The event parameter returns "undefined" for the following event listener:
google.maps.event.addListener(self.marker.infowindow, "closeclick", function(e)
{
console.log(e);
});
Thanks
Edit2
Here is a quick fiddle that illustrates the problem:
http://jsfiddle.net/462HF/
The blur function in the popup overlay plugin is getting called when you click the 'X' in the infoWindow on the google map, that is why the entire popup is closing. Below is the code in the jquery.popupoverlay.js file:
if (options.blur) {
blurhandler = function (e) {
if (!$(e.target).parents().andSelf().is('#' + el.id)) {
methods.hide(el);
}
};
}
The 'X' is an image, and its parents()only go back to the InfoWindow div, but not the popup div. Therefore, it will call methods.hide(el) and close the popup.
There is probably a better way of determining if it was clicked, but changing it to the following works. It just checks the target's img source:
if (options.blur) {
blurhandler = function (e) {
if (!$(e.target).parents().andSelf().is('#' + el.id) ) {
if(!($(e.target).attr('src') === 'http://maps.gstatic.com/mapfiles/api-3/images/mapcnt3.png'))
methods.hide(el);
}
};
}