Getting popup bound to a polyline to appear onMouseover in react-leaflet - javascript

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"

Related

React-flow & dare: reactFlowInstance.fitView() fits the instance in the screen after 2nd button click. (1st only changes the direction of the graph)

I have tried different ways of implementing this beauty, but it doesn't seem to work. My problem is that when I hit the button, I want to change the layout of the graph, which happens and I am glad for it, but I also want my graph to be centered (fit) on the screen. The first button click changes the direction, but doesn't fit the instance. To fit the instance I need to hit the button for a second time. I guess it has to do with asynchronous JS or? This is my code:
const onChangeTreeLayout = useCallback(
(treeLayoutDirection) => {
const layoutedElements = getLayoutedGraphElements(
elements,
treeLayoutDirection,
setTreeLayoutDirection
);
setElements(layoutedElements);
},
[elements]
);
Then how I get the instance and trigger it follows: Note: I can't use useReactFlow() hook as we decided not to migrate to a newer version. But useZoomPanHelper does its work anyway.
const reactFlowInstance = useZoomPanHelper();
<button
onClick={() => {
onChangeTreeLayout('TB');
reactFlowInstance.fitView();
}}
>
Horizontal Layout
</button>
I have also tried putting the function .fitView() inside the onChangeTreeLayout but I get the same behaviour.

How to extend Leaflet Icon Class to add data-open attribute to marker HTML?

I'm trying to trigger some functionality based on the click of a marker on a GeoJSON layer in Leaflet. The eventual functionality I'm trying to implement is a flyout, or scroll out type modal populated from the individual feature's JSON attributes. Essentially, I'm trying to implement the functionality in this Tutsplus Tutorial with dynamic feature content based on the marker click.
I THINK I've figured out most of the pieces I need, but I'm struggling with how to add a data attribute, specifically data-open, to the individual marker. Building on an earlier question of mine I've realized it's not enough to just update a DOM element's CSS, but rather my app should be implementing changes based on data attributes to fully get the functionality I want.
From this question I know that this should be done by extending the L.Icon class that Leaflet provides, but the answer is a bit too terse for my current JS skills. I apologize for this effectively being a "ELI5" of a previously asked question, but I'm not sure where the options and slug come into function. I think they're implied by the question, rather than the answer I'm citing and being set on the marker itself.
Here's a simplified version of the the click handler on my markers, which grabs and zooms to location, gets feature info, and populates that info to a div. The zoom functionality works, as does extracting and placing the feature info, but I'm struggling with how to connect the functionality to trigger the modal and place the div with the feature info over the map.
function zoomToFeature(e) {
var latLngs = [e.target.getLatLng()];
var markerBounds = L.latLngBounds(latLngs);
var street = e.target.feature.properties.str_addr;
document.getElementById('street').textContent = street;
mymap.fitBounds(markerBounds);
//where the modal trigger should be
document.getElementById('infoBox').classList.add('is-visible');
}
Here are the event listeners taken from the linked tutorial, which are currently not firing, but I have them working in a standalone implementation:
const openEls = document.querySelectorAll("[data-open]");
const closeEls = document.querySelectorAll("[data-close]");
const isVisible = "is-visible";
//this is the event I want to trigger on marker click
for (const el of openEls) {
el.addEventListener("click", function() {
const modalId = this.dataset.open;
console.log(this);
document.getElementById(modalId).classList.add(isVisible);
});
}
for (const el of closeEls) {
el.addEventListener("click", function() {
this.parentElement.parentElement.parentElement.classList.remove(isVisible);
});
}
document.addEventListener("click", e => {
if (e.target == document.querySelector(".modal.is-visible")) {
document.querySelector(".modal.is-visible").classList.remove(isVisible);
}
});
So, where I'm trying to get is that when my markers are clicked, the trigger the modal to appear over the map. So, I think I'm missing connecting the marker click event with the event that triggers the modal. I think what's missing is adding the data attribute to the markers, or some way chain the events without the data attributes. As there's no direct way to add an attribute to the markers, I try to add slug option on my circle markers:
var circleMarkerOptions = {
radius: 2,
weight: 1,
opacity: 1,
fillOpacity: 0.8,
slug: 'open',
}
and If I read the previously asked question's answer correctly, than extending the Icon Class this way should add a data-open attribute.
L.Icon.DataMarkup = L.Icon.extend({
_setIconStyles: function(img, name) {
L.Icon.prototype._setIconStyles.call(this, img, name);
if (options.slug) {
img.dataset.slug = options.slug;
}
}
});
A stripped down version of my code is here (thanks #ghybs). My full implementation pulls the markers from a PostGIS table. It's a bit hard to see in the Plunker, but this code adds my class to my modal, but doesn't trigger the functionality. It does trigger the visibility if the class is manually updated to modal.is-visible, but the current implementation which renders modal is-visbile doesn't, which I think is because the CSS is interpreted on page load(?) and not in response to the update via the dev tools, while the concatenated css class matches extactly(?). When I do trigger the modal via the dev tools, the close modal listeners don't seem to work, so I'm also missing that piece of the puzzle.
So, it's a work-around to setting the data attribute, but I realized I was shoe-horning a solution where it wasn't needed. Assuming someone ends up with the same mental block. Appropriate listeners on the modal close button and another function passed to the existing marker click listener produce the desired functionality.
const closeM = document.querySelector(".close-modal");
closeM.addEventListener("click", closeMe);
var modal = document.getElementById('infoBox');
and
function modalAction(){
modal.style.display = 'block';
}
function closeMe(){
modal.style.display = 'none';
}

Empty ghost Popup when dynamically rendering popup in react-leaflet

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}
>

How to change map zoomlevel on buttonclick without using dijit?

I am working with the esri javascript API to create a webmap. I want to have a button next to the map to allow me to zoom-in/out (not the standard esri button). Now, I found a lot of examples doing this using dijit (https://developers.arcgis.com/javascript/jssamples/toolbar_navigation.html) but I just want to use a simple html button like: Zoom in and then in the script part say something like:
function zoomin(){map.setZoom()}
Now my problem is that I don't know how to make that work. I guess the problem is that after the buttonclick it can't find the zoomin function since it's inside the require([...]),function(){} But I can't put it outside neither since the code depends on the require.
So, it would be great if you could tell me what to do.
For zooming in on the map, use the setZoom method incrementing the current zoom level to zoom in and decreasing to zoom out. For example:
//zoom out:
map.setZoom(map.getZoom()-1);
//zoom in:
map.setZoom(map.getZoom()+1);
As an example, using the sandbox of the Esri sample above:
http://developers.arcgis.com/javascript/sandbox/sandbox.html?sample=toolbar_navigation
...replace line 85 to 91 with this:
registry.byId("zoomin").on("click", function () {
//navToolbar.activate(Navigation.ZOOM_IN);
map.setZoom(map.getZoom()+1);
});
registry.byId("zoomout").on("click", function () {
//navToolbar.activate(Navigation.ZOOM_OUT);
map.setZoom(map.getZoom()-1);
});
This will allow the Zoom In and Zoom Out buttons to control the map.
Hope this helps.

TinyMCE 4 replicate clicking of a toolbar icon

I have recently migrated from TinyMCE v3 to v4. I have a custom image inserter which was development on v3 and can't get some elements to work on v4.
I'm having issues opening the default image dialog box. In version 3 this was completed using tinyMCE.execCommand('mceAdvImage');. I am aware mceAdvImage has been removed and have tried using tinymce.activeEditor.windowManager.open('mceImage');.
Anyone know how to do this? I'm ripping out my hair trying to find a solution.
I also faced this issue today and found a solution.
My usecase was to open image dialog on double click.
In tinyMCE.init function you need to add this (example):
tinyMCE.init({
...
ed.on('DblClick', function(e) {
if (e.target.nodeName=='IMG') {
tinyMCE.activeEditor.execCommand('mceImageDialog');
}
});
...
});
I used a command name 'mceImageDialog' but you can use whatever you want. The key to making this command work is to open image plugin.js and add these lines
Path: plugins/image/plugin.js (plugin.min.js):
...
editor.addCommand("mceImageDialog", function(ui, val) {
showDialog();
});
...
And thats it. After doubleclick on image element, the image dialog appears. For your solution you need i think only the plugin addCommand and use this command for your purposes.
Hope this helps.

Categories

Resources