在 React Leaflet 的地图中找到我的位置

问题描述 投票:0回答:3

我想问我是否使用 React Leaflet (https://react-leaflet.js.org/) 中的地图,但如何向地图添加位置按钮?就像这个我给红色箭头的图像中的“位置我”按钮的示例

以及链接中的图片:
Example of an arrow Location Me

An example on my map where I want to add location Me

以及如何显示位置按钮,您将其从我的编码中保存到哪里?

import { React, useState } from 'react'
import {
  LayersControl,
  MapContainer,
  Marker,
  Popup,
  TileLayer,
  useMapEvents,
} from 'react-leaflet'

const { BaseLayer } = LayersControl

function LocationMarker() {
  const [position, setPosition] = useState(null)
  const map = useMapEvents({
    click() {
      map.locate()
    },
    locationfound(e) {
      setPosition(e.latlng)
      map.flyTo(e.latlng, map.getZoom())
    },
  })

  return position === null ? null : (
    <Marker position={position}>
      <Popup>You are here</Popup>
    </Marker>
  )
}


function MapsMe() {
  return (
    <div className="flex ml-auto">
      <div className="w-4/5">
        <MapContainer center={51.505, -0.09} zoom=20>
          <LayersControl>
            <BaseLayer checked name="OpenStreetMap">
              <TileLayer
                attribution='&copy; <a href="https://www.openstreetmap.org/copyright">OpenStreetMap</a> contributors'
                url="https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png "
              />
            </BaseLayer>
            <LocationMarker />
          </LayersControl>
        </MapContainer>
      </div>
    </div>
  )
}

export default MapsMe

javascript reactjs react-leaflet
3个回答
0
投票

如果您需要获得与图片中完全相同的结果,您需要使用

leaflet-easybutton
库,带有
font-awesome
。否则,您可以通过扩展传单控件轻松构建自己的图标。

安装它们:

npm i leaflet-easybutton

npm i font-awesome

导入它们:

import "leaflet-easybutton/src/easy-button.js";
import "leaflet-easybutton/src/easy-button.css";
import "font-awesome/css/font-awesome.min.css";

使用 fa-map-marker 图标实例化

L.easy-button
,并在回调内保存位置并将地图移动到用户位置。

export default function Map() {
  const [map, setMap] = useState(null);
  const [position, setPosition] = useState(null);

  useEffect(() => {
    if (!map) return;

    L.easyButton("fa-map-marker", () => {
      map.locate().on("locationfound", function (e) {
        setPosition(e.latlng);
        map.flyTo(e.latlng, map.getZoom());
      });
    }).addTo(map);
  }, [map]);

  return (
    <MapContainer
      center={[51.505, -0.09]}
      zoom={20}
      style={{ height: "100vh" }}
      whenCreated={setMap}
    >
    ...
}

这是一个演示。当您打开它时,图标不会显示,因为 svg 图标和codesandbox 存在已知问题,但在本地您不应该有任何问题。


0
投票

这就是我解决同样问题的方法。为传单控件创建了可重复使用的组件。只是一种轻松处理传单类的奇特方式。

import L from "leaflet";
import React, { useEffect, useRef } from "react";

const ControlClasses = {
  bottomleft: "leaflet-bottom leaflet-left",
  bottomright: "leaflet-bottom leaflet-right",
  topleft: "leaflet-top leaflet-left",
  topright: "leaflet-top leaflet-right",
};

type ControlPosition = keyof typeof ControlClasses;
interface LeafLetControlProps {
  position?: ControlPosition;
}

const LeafletControl: React.FC<LeafLetControlProps> = ({
  position,
  children,
}) => {
  const divRef = useRef(null);

  useEffect(() => {
    if (divRef.current) {
      L.DomEvent.disableClickPropagation(divRef.current);
      L.DomEvent.disableScrollPropagation(divRef.current);
    }
  });

  return (
    <div ref={divRef} className={position && ControlClasses[position]}>
      <div className={"leaflet-control"}>{children}</div>
    </div>
  );
};

export default LeafletControl;

将传单控制组件与您想要的功能一起使用。

import { ActionIcon } from "@mantine/core";
import React, { useState } from "react";
import { useMapEvents } from "react-leaflet";
import { CurrentLocation } from "tabler-icons-react";
import LeafletControl from "./LeafletControl";

interface LeadletMyPositionProps {}

const LeadletMyPosition: React.FC<LeadletMyPositionProps> = ({}) => {
  const [loading, setLoading] = useState<boolean>(false);
  const map = useMapEvents({
    locationfound(e) {
      map.flyTo(e.latlng);
      setLoading(false);
    },
  });

  return (
    <LeafletControl position={"topright"}>
      <ActionIcon
        onClick={() => {
          setLoading(true);
          map.locate();
        }}
        loading={loading}
        variant={"transparent"}
      >
        <CurrentLocation />
      </ActionIcon>
    </LeafletControl>
  );
};

export default LeadletMyPosition;


0
投票

@Disco 的答案用更新的语法重写,并删除了对外部图标等的依赖。

import L from "leaflet";
import { PropsWithChildren, useEffect, useRef } from "react";

const ControlClasses = {
  bottomleft: "leaflet-bottom leaflet-left",
  bottomright: "leaflet-bottom leaflet-right",
  topleft: "leaflet-top leaflet-left",
  topright: "leaflet-top leaflet-right"
};

type ControlPosition = keyof typeof ControlClasses;
interface LeafLetControlProps {
  position?: ControlPosition;
}

export default function LeafletControl(
  props: PropsWithChildren<LeafLetControlProps>
) {
  const divRef = useRef(null);

  useEffect(() => {
    if (divRef.current) {
      L.DomEvent.disableClickPropagation(divRef.current);
      L.DomEvent.disableScrollPropagation(divRef.current);
    }
  });

  return (
    <div
      ref={divRef}
      className={props.position && ControlClasses[props.position]}>
      <div className={"leaflet-control leaflet-bar"}>{props.children}</div>
    </div>
  );
}

...和

import { useState } from "react";
import { useMapEvents } from "react-leaflet";
import LeafletControl from "./LeafletControl";
import { IconButton } from "@mui/material";
import MyLocationIcon from '@mui/icons-material/MyLocation';

export default function LeafletMyPosition() {

  const [isLoading, setIsLoading] = useState(false);

  const map = useMapEvents({
    locationfound(e) {
      map.flyTo(e.latlng, 18, { duration: 2});
      setIsLoading(false);
    }
  });

  return (
    <LeafletControl position={"bottomright"}>
        <IconButton
        size="small"
            disabled={isLoading}
            onClick={() => {
            setIsLoading(true);
            map.locate();
          }}
        >
            <MyLocationIcon />
        </IconButton>
    </LeafletControl>
  );
}

使用方法如下:

 <MapContainer>
   <MapController />
    <TileLayer />
    <LeafletMyPosition />
 </MapContainer>
© www.soinside.com 2019 - 2024. All rights reserved.