在vectorSource.clear()和React中刷新后,开放层功能不会消失



使用OpenLayers 7.1.0和React 18.2.0,我有一个地图,其中一些区域框显示在矢量层上,使用GeoJSON数据作为道具提交给我的VectorLayer组件。

features道具发生变化时,会触发useEffect,该效果应该是清除地图上的旧特征,只渲染新特征。新功能会按预期进行渲染,但它们会出现在未删除的旧功能之上。

在尝试通过调用源上的clear()refresh()以及映射上的renderSync()来移除旧特征之后,在将新特征添加到源之前,console.log(vectorLayer.GetSource().GetFeatures())显示一个空数组,但旧特征仍然可见。我试过创建一个全新的源,甚至尝试创建一个新的层,但都没有成功。

我引用了这个例子来设置地图上下文和基本层的结构:https://medium.com/swlh/how-to-incorporate-openlayers-maps-into-react-65b411985744

VectorLayer.js:

import {useContext, useEffect, useState} from 'react';
import MapContext from "../MapContext";
import OLVectorLayer from 'ol/Layer/Vector';
import VectorSource from "ol/source/Vector";
import {createBox} from "ol/interaction/Draw";
import {Draw} from "ol/intraction";
import {GeoJSON} from "ol/format";
const VectorLayer = ({source, style, zIndex = 0, canDraw, onShapeDrawn, features}) => {
const {map} = useContext(MapContext);
//const [vectorLayer, setVectorLayer] = useState(null);
let vectorSource = new VectorSource({wrapX: true});
let vectorLayer = new OLVectorLayer({
source: vectorSource,
style
});
const drawBox = new Draw({
source: vectorSource,
type: 'Circle',
geometryFunction: createBox(),
});
// "Constructor"
useEffect(() => {
if (!map) return;
// let vectorLayer = new OLVectorLayer({
//     source: vectorSource,
//     style
// });
map.addLayer(vectorLayer);
vectorLayer.setZIndex(zIndex);
if( canDraw )
{
map.addInteraction(drawBox);
if( onShapeDrawn != null ) {
drawBox.on('drawend', (e) => {
onShapeDrawn(e);
})
}
}
//setVectorLayer(vectorLayer);
return () => {
if (map) {
map.removeLayer(vectorLayer);
}
}
}, [map]);
// update map if features prop changes
useEffect( () => {
console.log('new # of features');
console.log(features?.features?.length);
if (features?.features?.length) { // may be empty on first render
// vectorLayer.getSource().clear();
// vectorLayer.getSource().refresh();
// map.renderSync();
// console.log('old source features after clear and refresh');
// console.log(vectorLayer.getSource().getFeatures());
map.removeLayer(vectorLayer);
// let featureSource = new VectorSource({
//     wrapX: true
// })
// featureSource.addFeatures(new GeoJSON().readFeatures(features,
//     {dataProjection:'EPSG:4326', featureProjection:'EPSG:4326'}));
// vectorLayer = new OLVectorLayer({
//     source: featureSource,
//     style
// });
vectorSource.clear();
vectorSource.refresh()
vectorSource.addFeatures(new GeoJSON().readFeatures(features,
{dataProjection:'EPSG:4326', featureProjection:'EPSG:4326'}));
// set features to map
// vectorLayer.setSource(featureSource);
map.addLayer(vectorLayer);
vectorLayer.setZIndex(zIndex);
map.renderSync();
}
},[features])
// Enabled/Disabled draw interaction when canDraw bool prop changes
useEffect(() => {
if (!map) return;
console.log(`vector layer canDraw: ${canDraw}`);
if( canDraw )
{
map.removeLayer(vectorLayer);
map.addLayer(vectorLayer);
vectorLayer.setZIndex(zIndex);
map.addInteraction(drawBox);
if( onShapeDrawn != null ) {
drawBox.on('drawend', (e) => {
onShapeDrawn(e);
})
}
} else {
console.log('removing draw interaction');
map.getInteractions().pop();
}
}, [canDraw]);
return null;
}
export default VectorLayer;

我刚刚在注释掉的代码中留下来,展示我尝试过的一些不同的东西。如果浏览起来有点困惑,我很乐意再清理一下。

我认为在每次渲染时都会重新创建向量层。

将vectorLayer的创建置于组件功能之外或使用useMemo:

const vectorLayer = useMemo(()=> {
let vectorSource = new VectorSource({wrapX: true});
let vectorLayer = new OLVectorLayer({
source: vectorSource,
style
});
return vectorLayer
},  []);
Then use the vectorLayer to access the source.

很抱歉回复太晚了,我以为我已经回来更新了!

我能够通过重新构造VectorLayer.js的代码来解决这个问题,以确保源、层和交互只创建一次。该问题是由他们的ol_uid在新渲染中重新生成引起的。

VectorLayer.js

import {useContext, useEffect, useState} from 'react';
import MapContext from "../MapContext";
import OLVectorLayer from 'ol/Layer/Vector';
import VectorSource from "ol/source/Vector";
import {createBox} from "ol/interaction/Draw";
import {Draw} from "ol/interaction";
import {GeoJSON} from "ol/format";
const VectorLayer = (props) => {
const {style, zIndex = 0, canDraw, onShapeDrawn, featureCollection} = props;
const {map} = useContext(MapContext);
const [isInstantiated, setIsInstantiated] = useState(false);
const [vectorLayer, setVectorLayer] = useState(null);
const [vectorSource, setVectorSource] = useState(null);
const [drawBox, setDrawBox] = useState(null);
useEffect(() => {
if (!map || isInstantiated) return;
setVectorSource(new VectorSource({wrapX: true}));
setIsInstantiated(true);
},[map]);
useEffect(() => {
if(!map || !vectorSource) return;
setDrawBox(new Draw({
source: vectorSource,
type: 'Circle',
geometryFunction: createBox(),
}));
setVectorLayer(new OLVectorLayer({
source: vectorSource,
style
}));
}, [vectorSource]);
useEffect(() => {
if(!map || !vectorLayer) return;
map.addLayer(vectorLayer);
vectorLayer.setZIndex(zIndex);
if( canDraw )
{
map.addInteraction(drawBox);
if( onShapeDrawn != null ) {
drawBox.on('drawend', (e) => {
onShapeDrawn(e);
})
}
}   
return () => {
if (map) {
map.removeLayer(vectorLayer);
}
}
}, [vectorLayer]);
// update map if features prop changes
useEffect( () => {
if(!map || !vectorLayer) return;
map.removeLayer(vectorLayer);
vectorSource.clear();
if (featureCollection?.features?.length) { // may be empty on first render
vectorSource.addFeatures(new GeoJSON().readFeatures(featureCollection,
{dataProjection:'EPSG:4326', featureProjection:'EPSG:4326'}));
}
map.addLayer(vectorLayer);
vectorLayer.setZIndex(zIndex);
}, [featureCollection])
// Enable/Disable draw interaction when canDraw bool prop changes
useEffect(() => {
if (!map || !vectorLayer || !drawBox) return;
console.log(`vector layer canDraw: ${canDraw}`);
if( canDraw )
{
map.removeLayer(vectorLayer);
map.addInteraction(drawBox);
if( onShapeDrawn != null ) {
drawBox.on('drawend', (e) => {
onShapeDrawn(e);
})
}
map.addLayer(vectorLayer);
vectorLayer.setZIndex(zIndex);
} else {
console.log('removing draw interaction');
//map.getInteractions().pop();
map.removeInteraction(drawBox);
}
}, [canDraw]);
return null;
}
export default VectorLayer;

谢谢大家的帮助!

最新更新