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