如何在 react-leaflet 中动态移动和旋转标记?
How to dynamically move and rotate marker in react-leaflet?
我用 react-leaflet
和 hook 写了一个 React 项目。我的目标是每秒移动和旋转标记。但是,移动部分工作正常。但是标记的旋转不起作用。最近几天我真的被困住了。我找不到好的解决方案。请帮助我。
地图组件如下
import { MapContainer, TileLayer, Marker, Popup } from "react-leaflet";
import { useState, useEffect } from "react";
import L from 'leaflet';
import 'leaflet-marker-rotation';
const MySimpleMap = () => {
const [lat, setLat] = useState(22.899397);
const [lon, setLon] = useState(89.508279);
const [heading, setHeading] = useState(30)
useEffect(() => {
const interval = setInterval(() => {
myfun();
}, 1000);
return () => {
clearInterval(interval);
};
}, [lat]);
const defaultIcon = L.icon({
iconUrl: "https://unpkg.com/leaflet@1.0.3/dist/images/marker-icon.png",
iconSize: [20, 40],
iconAnchor: [18, 18],
popupAnchor: [0, -10],
shadowAnchor: [10, 10]
});
const myfun = () => {
setLat(lat + 0.00001);
setLon(lon + 0.00001);
setHeading(heading+5);
console.log("angle:" + heading);
};
return (
<MapContainer className="map" center={[lat, lon]} zoom={21}>
<TileLayer
attribution='&copy <a href="http://osm.org/copyright">OpenStreetMap</a> contributors'
url="https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png"
/>
<Marker position={[lat, lon]} icon={defaultIcon} rotationAngle={heading} rotationOrigin="center">
<Popup>
A pretty CSS3 popup. <br /> Easily customizable.
</Popup>
</Marker>
</MapContainer>
);
};
export default MySimpleMap;
完整的问题在这个沙盒中:https://codesandbox.io/s/vigilant-wood-kgv4p?file=/src/App.js
使用此 post , was able to get it to work with your provided codesandbox. The default Marker
component does not have rotationAngle
or rotationOrigin
as valid props, you'd need to do something like done here 中提供的一些旋转标记的答案来获得它。因此,我们可以使用 re-use 旋转代码,并通过将其提升到 re-usable 函数中将其插入到您的代码中:
const applyRotation = (marker, _options) => {
const oldIE = L.DomUtil.TRANSFORM === "msTransform";
const options = Object.assign(_options, { rotationOrigin: "center" });
const { rotationAngle, rotationOrigin } = options;
if (rotationAngle && marker) {
marker._icon.style[L.DomUtil.TRANSFORM + "Origin"] = rotationOrigin;
if (oldIE) {
// for IE 9, use the 2D rotation
marker._icon.style[L.DomUtil.TRANSFORM] = `rotate(${rotationAngle} deg)`;
} else {
// for modern browsers, prefer the 3D accelerated version
marker._icon.style[
L.DomUtil.TRANSFORM
] += ` rotateZ(${rotationAngle}deg)`;
}
}
};
然后在使用 useEffect
更改旋转后调用它,因为我们还希望更新 Markers
位置,否则旋转将不起作用:
useEffect(() => {
applyRotation(markerRef.current, { rotationAngle: heading + 5 });
}, [heading]);
当您调用 myFunc
时,它会更新位置(纬度、经度)以及 header(旋转),因此通过将其放置在 useEffect 中,在下一次渲染时 Marker
应该更新它的位置。
我有一个代码框示例 here。
上述解决方案确实存在一些问题,您需要筛选 leaflet-rotatedmarker
库以获取那些缺失的边缘情况。但是,如果您可以添加该库,则更好的解决方案是导入:
import L from "leaflet";
import "leaflet-rotatedmarker";
并改用扩展 setRotationAngle
。
useEffect(() => {
if (markerRef.current) {
markerRef.current.setRotationAngle(heading);
}
}, [heading]);
您还可以使用它来将其提升到 RotatedMarker
组件中,以便您的道具 rotationAngle={heading} rotationOrigin="center"
的原始用例能够正常工作:
const RotatedMarker = forwardRef(({ children, ...props }, forwardRef) => {
const markerRef = useRef();
const { rotationAngle, rotationOrigin } = props;
useEffect(() => {
const marker = markerRef.current;
if (marker) {
marker.setRotationAngle(rotationAngle);
marker.setRotationOrigin(rotationOrigin);
}
}, [rotationAngle, rotationOrigin]);
return (
<Marker
ref={(ref) => {
markerRef.current = ref;
if (forwardRef) {
forwardRef.current = ref;
}
}}
{...props}
>
{children}
</Marker>
);
});
这是我测试 above out
的代码笔
我用 react-leaflet
和 hook 写了一个 React 项目。我的目标是每秒移动和旋转标记。但是,移动部分工作正常。但是标记的旋转不起作用。最近几天我真的被困住了。我找不到好的解决方案。请帮助我。
地图组件如下
import { MapContainer, TileLayer, Marker, Popup } from "react-leaflet";
import { useState, useEffect } from "react";
import L from 'leaflet';
import 'leaflet-marker-rotation';
const MySimpleMap = () => {
const [lat, setLat] = useState(22.899397);
const [lon, setLon] = useState(89.508279);
const [heading, setHeading] = useState(30)
useEffect(() => {
const interval = setInterval(() => {
myfun();
}, 1000);
return () => {
clearInterval(interval);
};
}, [lat]);
const defaultIcon = L.icon({
iconUrl: "https://unpkg.com/leaflet@1.0.3/dist/images/marker-icon.png",
iconSize: [20, 40],
iconAnchor: [18, 18],
popupAnchor: [0, -10],
shadowAnchor: [10, 10]
});
const myfun = () => {
setLat(lat + 0.00001);
setLon(lon + 0.00001);
setHeading(heading+5);
console.log("angle:" + heading);
};
return (
<MapContainer className="map" center={[lat, lon]} zoom={21}>
<TileLayer
attribution='&copy <a href="http://osm.org/copyright">OpenStreetMap</a> contributors'
url="https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png"
/>
<Marker position={[lat, lon]} icon={defaultIcon} rotationAngle={heading} rotationOrigin="center">
<Popup>
A pretty CSS3 popup. <br /> Easily customizable.
</Popup>
</Marker>
</MapContainer>
);
};
export default MySimpleMap;
完整的问题在这个沙盒中:https://codesandbox.io/s/vigilant-wood-kgv4p?file=/src/App.js
使用此 post , was able to get it to work with your provided codesandbox. The default Marker
component does not have rotationAngle
or rotationOrigin
as valid props, you'd need to do something like done here 中提供的一些旋转标记的答案来获得它。因此,我们可以使用 re-use 旋转代码,并通过将其提升到 re-usable 函数中将其插入到您的代码中:
const applyRotation = (marker, _options) => {
const oldIE = L.DomUtil.TRANSFORM === "msTransform";
const options = Object.assign(_options, { rotationOrigin: "center" });
const { rotationAngle, rotationOrigin } = options;
if (rotationAngle && marker) {
marker._icon.style[L.DomUtil.TRANSFORM + "Origin"] = rotationOrigin;
if (oldIE) {
// for IE 9, use the 2D rotation
marker._icon.style[L.DomUtil.TRANSFORM] = `rotate(${rotationAngle} deg)`;
} else {
// for modern browsers, prefer the 3D accelerated version
marker._icon.style[
L.DomUtil.TRANSFORM
] += ` rotateZ(${rotationAngle}deg)`;
}
}
};
然后在使用 useEffect
更改旋转后调用它,因为我们还希望更新 Markers
位置,否则旋转将不起作用:
useEffect(() => {
applyRotation(markerRef.current, { rotationAngle: heading + 5 });
}, [heading]);
当您调用 myFunc
时,它会更新位置(纬度、经度)以及 header(旋转),因此通过将其放置在 useEffect 中,在下一次渲染时 Marker
应该更新它的位置。
我有一个代码框示例 here。
上述解决方案确实存在一些问题,您需要筛选 leaflet-rotatedmarker
库以获取那些缺失的边缘情况。但是,如果您可以添加该库,则更好的解决方案是导入:
import L from "leaflet";
import "leaflet-rotatedmarker";
并改用扩展 setRotationAngle
。
useEffect(() => {
if (markerRef.current) {
markerRef.current.setRotationAngle(heading);
}
}, [heading]);
您还可以使用它来将其提升到 RotatedMarker
组件中,以便您的道具 rotationAngle={heading} rotationOrigin="center"
的原始用例能够正常工作:
const RotatedMarker = forwardRef(({ children, ...props }, forwardRef) => {
const markerRef = useRef();
const { rotationAngle, rotationOrigin } = props;
useEffect(() => {
const marker = markerRef.current;
if (marker) {
marker.setRotationAngle(rotationAngle);
marker.setRotationOrigin(rotationOrigin);
}
}, [rotationAngle, rotationOrigin]);
return (
<Marker
ref={(ref) => {
markerRef.current = ref;
if (forwardRef) {
forwardRef.current = ref;
}
}}
{...props}
>
{children}
</Marker>
);
});
这是我测试 above out
的代码笔