繁体   English   中英

如何在 javascript 反应中创建一个按钮来启用/禁用 leaflet 的缩放和平移?

[英]How to create a button to enable/disable zoom and pan for leaflet in javascript react?

正如标题所说,我正在搜索如何创建一个按钮来启用/禁用 javascript 反应中 leaflet 的缩放和平移。 实际上创建一个按钮很好,但是在我的 map 上获得我想要的效果不是。

我正在研究一个反应项目并尝试实现一个在“编辑”模式和“静态”模式之间切换的 leaflet map。 编辑将显示带有传单绘制命令的 map,并允许用户缩放和平移。 Static 将隐藏整个绘图界面并禁止缩放和平移,实际上将 map 变为固定图像。

我已经实现了一个 leaflet map 和一个添加/删除“隐藏” class 到绘图 ZA8Z6FDE6331C4BEB666 组件的按钮。 现在我正在尝试向同一个按钮添加一些东西,以在活动和非活动之间切换缩放和平移。

我在代码中手动更改了属性“scrollWheelZoom”和“拖动”并获得了所需的效果,所以我想我现在需要使用按钮更改它们。 我尝试对 select 我的 map 使用 querySelector 并更改属性,但它没有用(我猜 map 已经呈现并且不会更改)。 然后我尝试将参数值设置为等于我用作按钮开关的 boolean state,但我得到了相同的结果。 我在 web 上看到的大多数示例都使用完全不同的方式来创建 map,如果我理解得很好,那是因为除了 leaflet 之外,它们还没有使用 react。

有没有办法更新我的 map 的这些属性,或者以另一种方式创建 map,让我更轻松地更新属性?

这是代码的当前版本。 “scrollWheelZoom”使用查询方法更新,“拖动”使用 state 方法。

//css imports
import './Map.css';
import 'leaflet/dist/leaflet.css';
import 'leaflet-draw/dist/leaflet.draw.css';

//library imports
import React, { useRef, useEffect, useState } from 'react';
import { MapContainer, TileLayer, FeatureGroup } from 'react-leaflet';
import { EditControl } from 'react-leaflet-draw'
import EditOutlinedIcon from '@mui/icons-material/EditOutlined';
import L from 'leaflet';

//solution to the missing icon phenomenon in draw
delete L.Icon.Default.prototype._getIconUrl;

L.Icon.Default.mergeOptions({
    iconRetinaUrl: require('leaflet/dist/images/marker-icon-2x.png'),
    iconUrl: require('leaflet/dist/images/marker-icon.png'),
    shadowUrl: require('leaflet/dist/images/marker-shadow.png')
});

//component proper
export default function Map(props) {
    const [map, setMap] = useState(null) //state that will contain the map object
    let [editState, setEditState] = useState(true); // state to toggle the edit buttons

    //draw object that contains parameters for the drawing functions
    let drawObject = useRef({
        circlemarker: false
    });


    //handler for the edit button to hide/display the drawing tools
    function editHandler(e) {
        const $plc = e.target.closest('.placeholders');//select placeholder
        const $editObjectDraw = $plc.querySelector('.leaflet-draw');//select target object
        const $editObjectMap = $plc.querySelector('.mapContainer');
        if (editState) {
            $editObjectDraw.classList.add('visually-hidden');//update visual state
            $editObjectMap.scrollWheelZoom = editState;
        } else {
            $editObjectDraw.classList.remove('visually-hidden');//update visual state
            $editObjectMap.scrollWheelZoom = editState;
        }
        setEditState(!editState); //reverse boolean state to go from add to remove
    }

    return (
        <div>
            <MapContainer className="mapContainer" center={[45.5053, -73.6138]} zoom={1} scrollWheelZoom={true} dragging={editState}  minZoom={0} maxZoom={18} ref={setMap}>
                <TileLayer
                    attribution='&copy; <a href="https://www.openstreetmap.org/copyright">OpenStreetMap</a> contributors'
                    url="https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png"
                />
                <FeatureGroup>
                    <EditControl
                        className='drawControl'
                        position='topright'
                        onEdited={_onChange}
                        onCreated={_onChange}
                        onDeleted={_onChange}
                        onMounted={_onChange}
                        onEditStart={_onChange}
                        onEditStop={_onChange}
                        onDeleteStart={_onChange}
                        onDeleteStop={_onChange}
                        draw={drawObject.current}
                    />
                </FeatureGroup>

            </MapContainer>
            <button className="mapControl" onClick={editHandler}>
                <EditOutlinedIcon style={{ fill: "#FCF0E5" }} />
                <span>Edit</span>
            </button>
        </div>
    )
}

这是我在这里的第一个问题,我希望在发布之前我没有犯任何大错误。 预先感谢您的帮助。

正如我在评论中所写的那样,您不应将 vanilla js 与 react 结合使用,因为两者都负责更改 state,这将导致意外的错误和行为。

因此,您需要先禁用所有 map 交互,然后按照您的想法启用它们。 一开始您可以轻松实现这一点,因为您将属性作为道具传递并创建 state 变量以在编辑按钮显示之间切换。 唯一的例外是首先需要通过useEffect禁用的缩放控件。 但是为了动态启用 map 交互,您需要通过 map 参考来完成它,因为mapcontainer's道具是不可变的,这意味着您不能通过 state 更改它们。 一旦创建,就无法更改。 你有两个选择来做到这一点。 直接在按钮onChange事件中更改它们,或者创建一个自定义的 react-leaflet 组件,该组件将在启用编辑模式或为 true 时呈现。

export default function Map() {
  const [map, setMap] = useState(null); //state that will contain the map object
  let [editMode, setEditMode] = useState(false); // state to toggle the edit buttons

  useEffect(() => {
    if (map) map.zoomControl.disable();
  }, [map]);

  const handleClick = () => {
    if (!editMode) {
      map.touchZoom.enable();
      map.doubleClickZoom.enable();
      map.scrollWheelZoom.enable();
      map.keyboard.enable();
      map.zoomControl.enable();
      map.dragging.enable();
    } else {
      map.touchZoom.disable();
      map.doubleClickZoom.disable();
      map.scrollWheelZoom.disable();
      map.keyboard.disable();
      map.zoomControl.disable();
      map.dragging.disable();
    }
    setEditMode((prevState) => !prevState);
  };



<MapContainer
        className="mapContainer"
        center={[45.5053, -73.6138]}
        zoom={1}
        style={{ height: "90vh" }}
        minZoom={0}
        maxZoom={18}
        zoomSnap={false}
        ref={setMap}
        scrollWheelZoom={false}
        dragging={false}>
        ...
        {editMode && (
      <FeatureGroup>
        <EditControl
          onEdited={() => {}}
          onCreated={() => {}}
          onDeleted={() => {}}
          draw={{ rectangle: false }}
        />
      </FeatureGroup>
    )}
 </MapContainer>
  <button className="mapControl" onClick={handleClick}>
    <EditOutlinedIcon />
    <span>{!editMode ? "Static" : "Edit"} mode</span>
  </button>
</>

您可以进一步简化onChange function。 检查演示

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM