如何解决无法访问 react-leaflet
我使用 React Leaflet 来渲染 Leaflet 地图及其 GeoJSON 组件来渲染多边形。我正在尝试将多个多边形作为一个组一起拖动。
我添加了 Leaflet.Path.Drag 库并尝试重用 this 代码。我能够获得处于父状态的转换矩阵。如果我想使用 _transform
方法将此矩阵应用于多个多边形,它不起作用。我认为原因是矩阵没有应用于正确的图层,但我不知道如何解决这个问题。
App.js
import React from "react";
import { MapContainer,GeoJSON,TileLayer } from "react-leaflet";
import { geoJson,latLngBounds } from "leaflet";
import "./styles.css";
import "leaflet/dist/leaflet.css";
import { GeoJsonContainer } from "./GeoJsonContainer";
const objects = [
{
polygon: {
type: "FeatureCollection",features: [
{
type: "Feature",properties: {},geometry: {
type: "polygon",coordinates: [
[
[-104.98569488525392,39.63431579014969],[-104.98569488525392,39.64165260123419],[-104.97161865234376,39.63431579014969]
]
]
}
}
]
}
},{
polygon: {
type: "FeatureCollection",coordinates: [
[
[-105.02964019775392,39.6206315500488],[-105.02964019775392,39.65685252543906],[-104.99067306518556,39.6206315500488]
]
]
}
}
]
}
}
];
const getpolygonPointFromBounds = (latLngBounds) => {
const center = latLngBounds.getCenter();
const latlngs = [];
latlngs.push(latLngBounds.getSouthWest()); //bottom left
latlngs.push({ lat: latLngBounds.getSouth(),lng: center.lng }); //bottom center
latlngs.push(latLngBounds.getSouthEast()); //bottom right
latlngs.push({ lat: center.lat,lng: latLngBounds.getEast() }); // center right
latlngs.push(latLngBounds.getnorthEast()); //top right
latlngs.push({
lat: latLngBounds.getnorth(),lng: latLngBounds.getCenter().lng
}); //top center
latlngs.push(latLngBounds.getnorthWest()); //top left
latlngs.push({
lat: latLngBounds.getCenter().lat,lng: latLngBounds.getWest()
}); //center left
return latlngs;
};
export default function App() {
const [matrix,setMatrix] = React.useState(null);
let newBounds = [];
let selectBoundingBox = [];
objects.forEach((building) => {
const polygonBounds = geoJson(building.polygon).getBounds();
newBounds = [...newBounds,polygonBounds];
});
const polygonPoints = getpolygonPointFromBounds(latLngBounds(newBounds));
const convertedData = polygonPoints.map((point) => [point.lng,point.lat]);
convertedData.push([polygonPoints[0].lng,polygonPoints[0].lat]);
selectBoundingBox = convertedData;
let selectBoxData = null;
if (selectBoundingBox) {
selectBoxData = {
type: "FeatureCollection",coordinates: [selectBoundingBox]
}
}
]
};
}
const handleFeature = (layer) => {
layer.makeDraggable();
layer.dragging.enable();
layer.on("drag",function (e) {
setMatrix(layer.dragging._matrix);
});
};
return (
<MapContainer center={[39.63563779557324,-104.99234676361085]} zoom={12}>
<TileLayer
attribution='&copy <a href="http://osm.org/copyright">OpenStreetMap</a> contributors'
url="https://{s}.tile.osm.org/{z}/{x}/{y}.png"
/>
{objects.map((object,i) => (
<GeoJsonContainer data={object} key={i} matrix={matrix} />
))}
<GeoJSON
data={selectBoxData}
style={() => ({
color: "green",weight: 3,opacity: 0.5
})}
draggable={true}
onEachFeature={(feature,layer) => handleFeature(layer)}
></GeoJSON>
</MapContainer>
);
}
GeoJsonContainer.js
import React from "react";
import { GeoJSON } from "react-leaflet";
require("leaflet-path-drag");
export const GeoJsonContainer = (props) => {
const geoJSONRef = React.useRef(null);
const layerRef = React.useRef(null);
React.useEffect(() => {
if (geoJSONRef?.current?._layers) {
console.log("mount layers",geoJSONRef.current?._layers);
}
},[]);
React.useEffect(() => {
if (geoJSONRef?.current._layers && props.matrix) {
console.log("transform layers",geoJSONRef.current._layers);
const key = Object.keys(geoJSONRef.current._layers)[0];
const geoJSONElementLayer = geoJSONRef.current._layers[key];
if (geoJSONElementLayer) {
console.log("geoJSONElementLayer",geoJSONElementLayer);
console.log("layerRef.current",layerRef.current);
geoJSONElementLayer._transform(props.matrix);
layerRef.current._transform(props.matrix);
}
}
},[props.matrix]);
const handleFeature = (layer) => {
console.log("handleFeature layer",layer);
layerRef.current = layer;
layer.makeDraggable();
layer.dragging.enable();
};
return (
<GeoJSON
ref={geoJSONRef}
data={props.data.polygon}
style={() => ({
color: "#3388ff",opacity: 1
})}
dragging={true}
onEachFeature={(feature,layer) => handleFeature(layer)}
></GeoJSON>
);
};
解决方法
关于
如果我想使用 _transform 将此矩阵应用于多个多边形 方法,它不起作用
这是 React 中的预期行为,因为 matrix
prop 需要不可变,这意味着每次发生变化时都需要传递一个新数组:
layer.on("drag",function (e) {
setMatrix([...layer.dragging._matrix]);
});
代替:
layer.on("drag",function (e) {
setMatrix(layer.dragging._matrix);
});
这样 GeoJsonContainer
组件应该会按预期重新渲染。
另一件事涉及Leaflet.Path.Drag
插件,根据referenced thread,实际上两者 drop
和dropend
事件都需要被正确捕获应用转换,所以也许不是 matrix
道具,而是引入一个 transform
道具来保持矩阵数组和一个标志来确定是否触发了 drop
或 dropend
事件:>
const handleFeature = (layer) => {
layer.makeDraggable();
layer.dragging.enable();
layer.on("drag",function (e) {
setTransform({matrix: layer.dragging._matrix,"end": false});
});
layer.on("dragend","end": true});
});
};
并将其传递给 GeoJsonContainer
组件以应用几何变换:
React.useEffect(() => {
if (props.transform) {
geoJSONRef.current.eachLayer((layer) => {
if (props.transform.end) dragDropTransform(layer);
else __dragTransform(layer);
});
}
},[props.transform]);
哪里
function __dragTransform(layer) {
layer._transform(props.transform.matrix);
}
function dragDropTransform(layer) {
layer.dragging._transformPoints(props.transform.matrix);
layer._updatePath();
layer._project();
layer._transform(null);
}
可能的改进:
- 在提供的示例中,两个 JSON 层实例被实例化,也许考虑创建
GeoJSON
的单个实例并为每个几何体应用样式?
解决方案改进提案
在提供的示例中,实例化了两个层:
在 App
组件中
-
GeoJSON
层,呈现单个外部几何体(多边形)
在 GeoJsonContainer
组件中还有一个
-
GeoJSON
层依次渲染两个内部几何图形(多边形)
如何合并两个 GeoJSON 对象,如下所示:
const dataSource = {...selectBoxData,...objects[0],...objects[1]}
并创建一个单层:
<GeoJSON data={dataSource}></GeoJSON>
这样可以避免对可拖动层进行两次初始化(重复代码的重构)
版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。