I'm dynamically rendering a marker popup in react-leaflet via a series of nested marker elements: DonutMarker, BoundsDriftMarker, and DriftMarker. The Popup is created in DonutMarker (GitHub) and passed to BoundsDriftMarker as a prop:
export default function DonutMarker(props: DonutMarkerProps) {
...
return (
<BoundsDriftMarker
...
popup={
<Popup>
...
test
</Popup>
}
showPopup={props.showPopup}
/>
);
}
then from BoundsDriftMarker (GitHub) it's dynamically rendered as a child to DriftMarker:
export default function BoundsDriftMarker({position, bounds, icon, duration, popup, showPopup}: BoundsDriftMarkerProps) {
...
return (<DriftMarker
...
>
...
{showPopup && popup}
</DriftMarker>)
}
This is what it looks like currently when showPopup == true, along with the React browser plugin correctly showing the Popup element under the marker:
However, when I switch showPopup == false after this, I get an empty popup even though the browser plugin shows no popup:
Are the nested marker components causing this issue, or is there some other problem?
try Seth Lutske answer in
react-leaflet: Clear marker cluster before rendering new markers
He wraps markers in MarkerClusterGroup, and change the key every time he need to refresh markers in map. Works for me too
<MarkerClusterGroup
key={uuidv4()}
spiderfyDistanceMultiplier={1}
showCoverageOnHover={true}
>
Related
I'm trying to get a polyline popup that opens on mouseover.
I've tried forcing the position props of the popup attribute with static values but that doesn't seem to affect anything. I'm unsure if its possible to set this value when its bound to another element. It seems to work if the popup is independantCode pen here
I know I can set a function to execute on mouseover as shown in this codepen.
<Polyline positions={positions}
onMouseOver={(event) => null}
>
But I'm unsure how to make an event that interacts with this child component.
Using
leaflet 1.4.0
react-leaflet 2.2.1
react 16.8.5
react-dom 16.8.5
In order to get the popup displayed once hovering over a polyline you need simply to call
<Polyline
positions={positions}
/*What should onMouseOver do?*/
onMouseOver={e => e.target.openPopup()}>
Optionally add onMouseOut={e => e.target.closePopup()} to close the popup once hovering out
Demo
Updated for recent versions of React
<Polyline
pathOptions={{
"color": "#"+Math.floor(Math.random()*16777215).toString(16), //random color
"weight": 4,
"opacity": 0.65
}}positions={p}
children={<Popup>Henlo </Popup>}
eventHandlers={{
mouseover: (e) => {
e.target.openPopup()
},
mouseout: (e) => {
e.target.closePopup()
}}}
/>
I had big problem with events of Polyline.
to fix it, use:
import "leaflet/dist/leaflet.css";
don't use:
import 'leaflet-css';
from package "leaflet-css": "^0.1.0"
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);
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 am building an application using Semantic UI and ReactJS. I am using a tab module to contain my map, which uses the Leaflet Javascript library to render the map.
The problem is that the tiles do not display correctly until the page is resized.
The is what I have tried:
MapComponent = React.createClass({
componentDidMount() {
let map = L.map('map')
L.tileLayer.provider('Thunderforest.Outdoors').addTo(map)
map.setView([lat, long], zoom)
map.invalidateSize(false)
}
}
Which did not seem to fix the problem.
I tried setting a timeout, like so:
MapComponent = React.createClass({
componentDidMount() {
let map = L.map('map')
L.tileLayer.provider('Thunderforest.Outdoors').addTo(map)
Meteor.setTimeout(() => {
map.invalidateSize(false)
}, 2000)
map.setView([lat, long], zoom)
}
})
Which sometimes worked by setting the timer to 2000, but sometimes it needed to be set to 5000, which is a bit crazy in my opinion.
From what I have read, calling the invalidateSize() function should fix the problem. Any help solving this problem would be greatly appreciated. Thank you.
Call invalidateSize once the tab containing your map becomes visible. In Semantic UI's tab module you can do that by using the onVisible callback:
Called after a tab becomes visible
http://semantic-ui.com/modules/tab.html#/settings
<div class="ui menu top">
<a class="item" data-tab="map">Map</a>
</div>
$('.top.menu .item').tab({
'onVisible': function () {
// Do stuff
}
});
Is there a way to have a loading icon while the map is loading markers? I am using google maps API 3 with javascript and cant find much information on this.
This event is now called "status_changed" per the API docs: https://developers.google.com/maps/documentation/javascript/reference#KmlLayer
It can be used like this:
google.maps.event.addListener(kmlLayer, 'status_changed', function () {
if (kmlLayer.getStatus() == google.maps.KmlLayerStatus.OK) {
// Success
}
else {
// Failure
}
});
If you're loading markers using a KmlLayer object, then you can attach a listener to the event metadata_changed which gets fired after the KmlLayer has loaded all the information.
So you can have your custom loading icon display as soon as you initialize your map, then make the call for the markers using new google.maps.KmlLayer(...). In the listener for metadata_changed you can remove the custom loading icon, or hide it from displaying. So when the KmlLayer finishes loading, then it'll run the code to remove your loading icon.
You can attach listeners by going:
google.maps.event.addListener(kmlLayerObject, 'metadata_changed', function () {
...
}
You could also "hide" the map canvas with a loading div and show it after initialization.
Another thing to be aware of is when the map is hidden on init, it may behave strangely that can be fixed by "resizing" the map:
http://groups.google.com/group/google-maps-js-api-v3/browse_thread/thread/251f20b769d116ea/ba3ca54f5e1352a2