[英]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='© <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.