【问题标题】:Using React, Leaflet, leaflet-pixi-overlay, a marker popup closes right away after click使用 React、Leaflet、leaflet-pixi-overlay,单击后立即关闭标记弹出窗口
【发布时间】:2020-06-22 15:40:07
【问题描述】:

我正在 React 下制作传单地图。出于性能原因,我不得不使用 PixiOverlay 来绘制我的标记 (https://github.com/manubb/Leaflet.PixiOverlay)。 不过,我遇到了弹出窗口的问题。使用以下代码:

  • 单击标记时正确触发标记的单击事件
  • 如果在单击并释放标记的同时拖动地图,弹出窗口会正常打开
  • 但只需一次“干净”点击,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 问题?

【问题讨论】:

    标签: javascript reactjs leaflet pixi.js react-leaflet


    【解决方案1】:

    在这一点上,我并没有真正看到阻止事件传播的“干净”方式。 我的解决方案是:

    • 禁用点击地图时自动关闭弹出窗口
    • 检测地图的点击是否与标记的点击相同;当它不是时关闭弹出窗口

    使用以下选项声明弹出窗口:

    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();
          }
        });
    

    这有点脏,因为它假定标记的点击事件如果首先处理...

    【讨论】:

      猜你喜欢
      • 2021-08-03
      • 1970-01-01
      • 2020-10-02
      • 2019-08-13
      • 1970-01-01
      • 1970-01-01
      • 2019-01-11
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多