使用React, Leaflet, leaflet-pixi-overlay, 标记弹窗点击后立即关闭
Using React, Leaflet, leaflet-pixi-overlay, a marker popup closes right away after click
我正在 React 下制作传单地图。出于性能原因,我不得不使用 PixiOverlay 来绘制我的标记 (https://github.com/manubb/Leaflet.PixiOverlay)。
不过,我遇到了弹出窗口的问题。使用以下代码:
- 当点击标记时正确触发标记的点击事件
- 如果在单击并释放标记时拖动地图,弹出窗口会正常打开
- 但是只要单击一次 'clean',popupclose 事件就会立即触发
到目前为止,我的混合方法(react-leaflet、PixiOverlay)运行良好,但我无法解决这个问题。
以下代码经过简化,部分元素脱离了React的控制,简化了测试代码:
import { Map, TileLayer } from 'react-leaflet';
import 'leaflet/dist/leaflet.css';
import { Paper } from '@material-ui/core';
import * as PIXI from 'pixi.js';
import 'leaflet-pixi-overlay';
import L from 'leaflet';
const pixiMarkerContainer = new PIXI.Container();
let markerTextures = {};
const testPopup = L.popup({ autoPan: false, pane: 'popupPane' });
const markerOverlay = L.pixiOverlay((utils) => {
const map = utils.getMap();
const scale = utils.getScale();
const renderer = utils.getRenderer();
const container = utils.getContainer();
if (map && (Object.keys(markerTextures).length !== 0)) {
if (container.children.length) container.removeChildren();
const newMarker = new PIXI.Sprite(markerTextures.default);
const newMarkerPoint = utils.latLngToLayerPoint([50.63, 13.047]);
newMarker.x = newMarkerPoint.x;
newMarker.y = newMarkerPoint.y;
container.addChild(newMarker);
newMarker.anchor.set(0.5, 1);
newMarker.scale.set(1 / scale);
newMarker.interactive = true;
newMarker.buttonMode = true;
newMarker.click = () => {
testPopup
.setLatLng([50.63, 13.047])
.setContent('<b>Test</b>');
console.log('Open popup');
map.openPopup(testPopup);
};
map.on('popupclose', () => { console.log('Close popup'); });
renderer.render(container);
}
},
pixiMarkerContainer);
function PixiMap() {
const [markerTexturesLoaded, setMarkerTexturesLoaded] = useState(false);
const [mapReady, setMapReady] = useState(false);
const mapRef = useRef(null);
useEffect(() => {
if (Object.keys(markerTextures).length === 0) {
const loader = new PIXI.Loader();
loader.add('default', 'https://manubb.github.io/Leaflet.PixiOverlay/img/marker-icon.png');
loader.load((thisLoader, resources) => {
markerTextures = { default: resources.default.texture };
setMarkerTexturesLoaded(true);
});
}
}, []);
useEffect(() => {
if (mapReady && markerTexturesLoaded) {
const map = mapRef.current.leafletElement;
markerOverlay.addTo(map);
markerOverlay.redraw();
}
}, [mapReady, markerTexturesLoaded]);
return (
<Paper
style={{ flexGrow: 1, height: '100%' }}
>
<Map
preferCanvas
ref={mapRef}
style={{ height: '100%' }}
center={[50.63, 13.047]}
zoom={12}
minZoom={3}
maxZoom={18}
whenReady={() => { setMapReady(true); }}
onClick={() => { console.log('map click'); }}
>
<TileLayer url="https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png?" />
</Map>
</Paper>
);
}
export default PixiMap;
有什么建议吗?谢谢
编辑:
看起来标记和地图都处理了点击事件(在源代码中添加了地图点击记录)。
我希望地图处理点击(关闭弹出窗口),但当点击已经被标记处理时不处理...
编辑#2:
我尝试在标记点击处理程序中添加以下内容:
event.stopPropagation();
event.data.originalEvent.stopPropagation();
但这绝对没有任何作用...看起来这是一个基本的 PIXI 问题?
目前,我还没有真正看到 'clean' 停止事件传播的方法。
我的解决方案是:
- 禁用点击地图时自动关闭弹出窗口
- 检测地图的点击是否与标记的点击相同;不存在时关闭弹出窗口
使用以下选项声明弹出窗口:
const testPopup = L.popup({
autoPan: false,
pane: 'popupPane',
closeOnClick: false, // : disable the automatic close
});
在标记点击处理程序中,记录点击的位置:
newMarker.click = (event) => {
// Set aside the click position:
lastMarkerClickPosition = { ...event.data.global };
testPopup
.setLatLng([50.63, 13.047])
.setContent('<b>Test</b>');
setPopupParams({ text: 'test' });
map.openPopup(testPopup);
};
添加地图点击处理程序,如果需要关闭弹出窗口:
map.on('click', (event) => {
// Find click position
const clickPixiPoint = new PIXI.Point();
interaction.mapPositionToPoint(
clickPixiPoint,
event.originalEvent.clientX,
event.originalEvent.clientY,
);
if (
(clickPixiPoint.x !== lastMarkerClickPosition.x)
|| (clickPixiPoint.y !== lastMarkerClickPosition.y)
) {
map.closePopup();
}
});
这有点脏,因为如果先处理,它会假定标记的点击事件...
我正在 React 下制作传单地图。出于性能原因,我不得不使用 PixiOverlay 来绘制我的标记 (https://github.com/manubb/Leaflet.PixiOverlay)。 不过,我遇到了弹出窗口的问题。使用以下代码:
- 当点击标记时正确触发标记的点击事件
- 如果在单击并释放标记时拖动地图,弹出窗口会正常打开
- 但是只要单击一次 'clean',popupclose 事件就会立即触发
到目前为止,我的混合方法(react-leaflet、PixiOverlay)运行良好,但我无法解决这个问题。
以下代码经过简化,部分元素脱离了React的控制,简化了测试代码:
import { Map, TileLayer } from 'react-leaflet';
import 'leaflet/dist/leaflet.css';
import { Paper } from '@material-ui/core';
import * as PIXI from 'pixi.js';
import 'leaflet-pixi-overlay';
import L from 'leaflet';
const pixiMarkerContainer = new PIXI.Container();
let markerTextures = {};
const testPopup = L.popup({ autoPan: false, pane: 'popupPane' });
const markerOverlay = L.pixiOverlay((utils) => {
const map = utils.getMap();
const scale = utils.getScale();
const renderer = utils.getRenderer();
const container = utils.getContainer();
if (map && (Object.keys(markerTextures).length !== 0)) {
if (container.children.length) container.removeChildren();
const newMarker = new PIXI.Sprite(markerTextures.default);
const newMarkerPoint = utils.latLngToLayerPoint([50.63, 13.047]);
newMarker.x = newMarkerPoint.x;
newMarker.y = newMarkerPoint.y;
container.addChild(newMarker);
newMarker.anchor.set(0.5, 1);
newMarker.scale.set(1 / scale);
newMarker.interactive = true;
newMarker.buttonMode = true;
newMarker.click = () => {
testPopup
.setLatLng([50.63, 13.047])
.setContent('<b>Test</b>');
console.log('Open popup');
map.openPopup(testPopup);
};
map.on('popupclose', () => { console.log('Close popup'); });
renderer.render(container);
}
},
pixiMarkerContainer);
function PixiMap() {
const [markerTexturesLoaded, setMarkerTexturesLoaded] = useState(false);
const [mapReady, setMapReady] = useState(false);
const mapRef = useRef(null);
useEffect(() => {
if (Object.keys(markerTextures).length === 0) {
const loader = new PIXI.Loader();
loader.add('default', 'https://manubb.github.io/Leaflet.PixiOverlay/img/marker-icon.png');
loader.load((thisLoader, resources) => {
markerTextures = { default: resources.default.texture };
setMarkerTexturesLoaded(true);
});
}
}, []);
useEffect(() => {
if (mapReady && markerTexturesLoaded) {
const map = mapRef.current.leafletElement;
markerOverlay.addTo(map);
markerOverlay.redraw();
}
}, [mapReady, markerTexturesLoaded]);
return (
<Paper
style={{ flexGrow: 1, height: '100%' }}
>
<Map
preferCanvas
ref={mapRef}
style={{ height: '100%' }}
center={[50.63, 13.047]}
zoom={12}
minZoom={3}
maxZoom={18}
whenReady={() => { setMapReady(true); }}
onClick={() => { console.log('map click'); }}
>
<TileLayer url="https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png?" />
</Map>
</Paper>
);
}
export default PixiMap;
有什么建议吗?谢谢
编辑: 看起来标记和地图都处理了点击事件(在源代码中添加了地图点击记录)。 我希望地图处理点击(关闭弹出窗口),但当点击已经被标记处理时不处理...
编辑#2: 我尝试在标记点击处理程序中添加以下内容:
event.stopPropagation();
event.data.originalEvent.stopPropagation();
但这绝对没有任何作用...看起来这是一个基本的 PIXI 问题?
目前,我还没有真正看到 'clean' 停止事件传播的方法。 我的解决方案是:
- 禁用点击地图时自动关闭弹出窗口
- 检测地图的点击是否与标记的点击相同;不存在时关闭弹出窗口
使用以下选项声明弹出窗口:
const testPopup = L.popup({
autoPan: false,
pane: 'popupPane',
closeOnClick: false, // : disable the automatic close
});
在标记点击处理程序中,记录点击的位置:
newMarker.click = (event) => {
// Set aside the click position:
lastMarkerClickPosition = { ...event.data.global };
testPopup
.setLatLng([50.63, 13.047])
.setContent('<b>Test</b>');
setPopupParams({ text: 'test' });
map.openPopup(testPopup);
};
添加地图点击处理程序,如果需要关闭弹出窗口:
map.on('click', (event) => {
// Find click position
const clickPixiPoint = new PIXI.Point();
interaction.mapPositionToPoint(
clickPixiPoint,
event.originalEvent.clientX,
event.originalEvent.clientY,
);
if (
(clickPixiPoint.x !== lastMarkerClickPosition.x)
|| (clickPixiPoint.y !== lastMarkerClickPosition.y)
) {
map.closePopup();
}
});
这有点脏,因为如果先处理,它会假定标记的点击事件...