【问题标题】:How to Use SVG Component in React Leaflet?如何在 React Leaflet 中使用 SVG 组件?
【发布时间】:2022-08-14 23:12:36
【问题描述】:

我将创建的 svg 转换为组件。我将颜色和一个字符串或整数表达式作为道具发送到其中,我想相应地创建一个动态标记。

我希望我的 svg 图标出现在左上角,以替换下面地图上的蓝色标记。

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}/>

我想用它作为。

  • 您包含了大量无法轻松复制的代码。我可以通过在 svg 图标中显示单个标记来帮助您
  • 如果您能准备示例代码,我将非常高兴。 @kboul

标签: javascript reactjs leaflet react-leaflet leaflet-routing-machine


【解决方案1】:

据我所知,我认为不可能仅仅因为地图渲染是由 Leaflet 而不是 React 处理的,所以无法在 Leaflet 地图上渲染一个 react svg 组件。我认为这同样适用于其他知名库,如 Mapbox。我在那里遇到了类似的问题,解决方案与下面的类似。

您可以做的是呈现L.divicon 并将svg 图标作为html 传递。我用你的 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}>

Demo

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-12-13
    • 2017-07-06
    • 2022-11-10
    • 1970-01-01
    相关资源
    最近更新 更多