簡體   English   中英

如何在 React Leaflet 中使用 SVG 組件?

[英]How to Use SVG Component in React Leaflet?

我將創建的 svg 轉換為組件。 我將顏色和字符串或 integer 表達式作為道具發送到其中,我想相應地創建一個動態標記。 在此處輸入圖像描述

我希望我的 svg 圖標出現在左上角,以替換下面 map 上的藍色標記。

TrackingMap.tsx

import React, { useState } from 'react';
//Third Party imports
import 'leaflet/dist/leaflet.css';
import { MapContainer, TileLayer } from 'react-leaflet';
import L from 'leaflet';

//Components imports
import Routing from './Routing';

//Utils import
import { MapWithPopupdatav2 } from './fakeData2';
import { CoordinatInterface, EachPointforRouting } from 'types/Map';



interface DefaultMapWithPopupProps {
  // dataSource: RootMapWithPopupData;
  height?: string;
  width?: string;
}

const TrackingMap = ({ height }: DefaultMapWithPopupProps) => {
  const [markersDataSource, setMarkersDataSource] = useState(
    MapWithPopupdatav2.data.map(item => item.gridData.data.map(item => item))
  );

  const [routeWayColor, setRouteWayColor] = useState<string[]>(
    MapWithPopupdatav2.data.map(item => item.color)
  );

  const [dataForRouting, setDataForRouting] = useState<EachPointforRouting[][]>(
    MapWithPopupdatav2.data.map(eachPoint =>
      eachPoint.gridData.data.map(point =>
        L.latLng(point.latitude, point.longitude)
      )
    )
  );

  const markersLatLon: CoordinatInterface[][] = MapWithPopupdatav2.data.map(
    eachPoint =>
      eachPoint.gridData.data.map(point => ({
        latitude: point.latitude,
        longitude: point.longitude,
      }))
  );
  function centerMapDataCalculate(data: CoordinatInterface[][]) {
    let newArray: CoordinatInterface[] = [];
    data.forEach(item => {
      item.map(point => {
        newArray.push(point);
      });
    });
    return newArray;
  }

  const markersCoordinatesForMapCentering: CoordinatInterface[] =
    centerMapDataCalculate(markersLatLon);
  return (
    <MapContainer scrollWheelZoom={true} style={{ height: `${height}` }}>
      <TileLayer
        attribution='&copy; <a href="https://www.openstreetmap.org/copyright">OpenStreetMap</a> contributors'
        url="https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png"
      />
      {dataForRouting.map((eachPoint, index) => {
        return (
          <React.Fragment key={index}>
            <Routing
              eachPoint={eachPoint}
              dataSource={markersDataSource[index]}
              color={routeWayColor[index]}
              bounds={markersCoordinatesForMapCentering}
            />
            <Marker />
          </React.Fragment>
        );
      })}
    </MapContainer>
  );
};

export default TrackingMap;

路由.tsx

import { useEffect } from 'react';
//Third Party İmports
import L, { latLngBounds } from 'leaflet';
import 'leaflet-routing-machine/dist/leaflet-routing-machine.css';
import 'leaflet-routing-machine';
import { useMap } from 'react-leaflet';

//Components
import { Marker } from 'components/icons';

//Utils import
import { RoutingPropsforTrackingMap } from 'types/Map';


L.Marker.prototype.options.icon = L.icon({
  iconUrl: 'https://unpkg.com/leaflet@1.7.1/dist/images/marker-icon.png',
});

const Routing = ({
  eachPoint,
  dataSource,
  color,
  bounds,
}: RoutingPropsforTrackingMap) => {
  const map = useMap();
  let markerBounds = latLngBounds([]);
  useEffect(() => {
    if (!map) return;

    const routingControl = L.Routing.control({
      waypoints: eachPoint,
      createMarker: function (
        waypointIndex: any,
        waypoint: any,
        numberOfWaypoints: any
      ) {
        //  return L.marker(waypoint.latLng, { icon: svgIcon }).bindPopup(
        return L.marker(waypoint.latLng).bindPopup(
          `<p><b>Location Code:</b>${dataSource[waypointIndex].locationCode}</p>
          <p><b>Location Type:</b>${dataSource[waypointIndex].locationType}</p>
          <p><b>Visit Order:</b>${dataSource[waypointIndex].visitOrder}</p>
          `
        );
      },
      lineOptions: {
        styles: [
          {
            color: color,
            opacity: 1,
            weight: 7,
          },
        ],
      },
      addWaypoints: false,
      draggableWaypoints: false,
      fitSelectedRoutes: false,
      showAlternatives: true,
    }).addTo(map);

    if (bounds.length && bounds.length > 0) {
      bounds.forEach(marker => {
        markerBounds.extend([marker.latitude, marker.longitude]);
      });
      map.fitBounds(markerBounds);
    }

    return () => map.removeControl(routingControl);
  }, [map]);

  return null;
};
export default Routing;

標記.tsx

import * as React from 'react';

const SvgComponent = (props: any) => (
  <div className="markerIcon">
    <p>{props.visitOrder}</p>
    <svg
      width={99}
      height={122}
      fill="none"
      xmlns="http://www.w3.org/2000/svg"
      {...props}
    >
      <g
        style={{
          mixBlendMode: 'darken',
        }}
      >
        <g filter="url(#a)">
          <ellipse cx={49} cy={33} rx={36} ry={33} fill="#0AF291" />
        </g>
        <path
          d="M83.5 33c0 17.277-15.32 31.5-34.5 31.5S14.5 50.277 14.5 33 29.82 1.5 49 1.5 83.5 15.723 83.5 33Z"
          stroke="#000"
          strokeWidth={3}
        />
      </g>
      <g filter="url(#b)">
        <path d="m49.5 116 43.734-75H5.766L49.5 116Z" fill="#0AF291" />
      </g>
      <path
        d="m50.796 116.756-1.296 2.222-1.296-2.222-43.734-75L3.155 39.5h92.69l-1.315 2.256-43.734 75Z"
        stroke="#000"
        strokeWidth={3}
      />
      <defs>
        <filter
          id="a"
          x={13}
          y={0}
          width={72}
          height={70}
          filterUnits="userSpaceOnUse"
          colorInterpolationFilters="sRGB"
        >
          <feFlood floodOpacity={0} result="BackgroundImageFix" />
          <feBlend in="SourceGraphic" in2="BackgroundImageFix" result="shape" />
          <feColorMatrix
            in="SourceAlpha"
            values="0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 127 0"
            result="hardAlpha"
          />
          <feOffset dy={4} />
          <feGaussianBlur stdDeviation={2} />
          <feComposite in2="hardAlpha" operator="arithmetic" k2={-1} k3={1} />
          <feColorMatrix values="0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0.25 0" />
          <feBlend in2="shape" result="effect1_innerShadow_0_1" />
        </filter>
        <filter
          id="b"
          x={0.544}
          y={38}
          width={97.913}
          height={87.956}
          filterUnits="userSpaceOnUse"
          colorInterpolationFilters="sRGB"
        >
          <feFlood floodOpacity={0} result="BackgroundImageFix" />
          <feBlend in="SourceGraphic" in2="BackgroundImageFix" result="shape" />
          <feColorMatrix
            in="SourceAlpha"
            values="0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 127 0"
            result="hardAlpha"
          />
          <feOffset dy={4} />
          <feGaussianBlur stdDeviation={2} />
          <feComposite in2="hardAlpha" operator="arithmetic" k2={-1} k3={1} />
          <feColorMatrix values="0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0.25 0" />
          <feBlend in2="shape" result="effect1_innerShadow_0_1" />
        </filter>
      </defs>
    </svg>
  </div>
);

export default SvgComponent;

將 Routing.tsx 中的顏色和 visitOrder 值設置為

<Marker color={color} visitOrder={dataSource[waypointIndex].visitOrder}/>

我想用它作為。

To my knowledge I think it is not possible to render a react svg component on Leaflet map simply because the map rendering is handled by Leaflet, not by React. 我認為這同樣適用於其他知名庫,如 Mapbox。 我在那里遇到了類似的問題,解決方案與下面的類似。

您可以做的是渲染一個L.divicon並作為 html 傳遞 svg 圖標。 我用你的 svg 玩了一下,但沒能得到你得到的 100% 的實際圖像。 不管怎樣,它真的很接近你所擁有的,我認為你可以很容易地適應它。 所以這里有一個簡單的例子,你如何將 svg 圖標渲染為 react-leaflet 中的 Leaflet 標記。

如此簡單地創建一個 svg 圖標變量,它是L.divIcon的一個實例

const svgIcon = L.divIcon({
  html: `
  <svg
      width="99"
      height="122"
      fill="none"
    xmlns="http://www.w3.org/2000/svg"
    >
   ...your svg icon content
</svg>`,
  className: "svg-icon",
  iconSize: [24, 40],
  iconAnchor: [12, 40]
});

然后將其傳遞給 Marker 的圖標道具

<Marker position={position} icon={svgIcon}>

演示

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM