[英]How to refresh/re-render an OpenLayers 6 Map
I have a React component where I render an Open Layers 6 map.我有一个 React 组件,我在其中渲染了 Open Layers 6 map。 I pass in lat/long coordinates as a prop (props.userEnteredLocation) to the map which get translated to a format that open layers expects, to be able to render the correct location.我将纬度/经度坐标作为道具 (props.userEnteredLocation) 传递给 map,它被转换为开放层期望的格式,以便能够呈现正确的位置。
My State is as follows:我的State如下:
const transformCentre = (centre) => {
return transform(centre, "EPSG:4326", "EPSG:3857");
};
const [map, setMap] = useState();
const [centre, setCentre] = useState([74.31071359697442, 31.588167443954312]);
const [featuresLayer, setFeaturesLayer] = useState();
const [point, setPoint] = useState();
const [feature, setFeature] = useState();
const [transformedCentre, setTransformedCentre] = useState(
transformCentre(centre)
);
// create state ref that can be accessed in OpenLayers onclick callback function
// https://stackoverflow.com/a/60643670
const mapRef = useRef();
mapRef.current = map;
I have two React hooks我有两个 React 钩子
// initialize map on first render - logic formerly put into componentDidMount
useEffect(() => {
console.log("Initialised for the first time");
// Create a point
var point = new Point(transformedCentre);
setPoint(point);
// points/lines/polygons are features that can be used in the vector layer
var feature = new Feature({
geometry: point,
name: "Your address is shown here",
});
var iconStyle = new Style({
image: new Icon({
src: markerImg,
}),
});
feature.setStyle(iconStyle);
setFeature(feature);
// create vector source itself for the marker on the map
var vectorSource = new VectorSource({
features: [feature],
});
// create and add vector source layer
const initalFeaturesLayer = new VectorLayer({
source: vectorSource,
});
// create map
const locationMap = new Map({
target: mapRef.current,
layers: [
new TileLayer({
source: new OSM(),
}),
initalFeaturesLayer,
],
view: new View({
center: transformedCentre,
zoom: 17,
}),
controls: [],
});
setMap(locationMap);
setFeaturesLayer(initalFeaturesLayer);
}, []);
This works, the map is correctly rendered at the right location这有效,map 在正确的位置正确渲染
// update map if user changes geo location
useEffect(() => {
console.log("Detected change in User geolocation");
if (props.userEnteredLocation) {
var array = props.userEnteredLocation.split(",");
var newCentre = [parseFloat(array[1]), parseFloat(array[0])];
setCentre(newCentre);
setTransformedCentre(transformCentre(centre));
}
if (map != null) {
console.log("Changing Centre to: " + transformedCentre);
map.getView().setCenter(transformedCentre);
console.log("CENTRE NOW: " + map.getView().getCenter());
point.setCoordinates(transformedCentre);
console.log("POINT CENTRE NOW: " + point.getCoordinates());
feature.setGeometry(point);
console.log("Feature geometry now CENTRE NOW: " + feature.getGeometry());
// set features to map
featuresLayer.setSource(
new VectorSource({
features: [feature],
})
);
featuresLayer.getSource().changed();
}
}, [props.userEnteredLocation]);
//render component
return <div ref={mapRef} className="map-container"></div>;
I've tried map.render() and map.renderSync() as suggested by the FAQ to no avail.我已经按照常见问题解答的建议尝试了 map.render() 和 map.renderSync() 无济于事。 I've also tried.changed() and.refresh() on the VectorSource itself, .changed() does nothing and.refresh() removes my red marker completely.我还在 VectorSource 本身上尝试了 .changed() 和 .refresh() , .changed() 什么也不做, .refresh() 完全删除了我的红色标记。
Does anyone know where I'm going wrong here?有谁知道我要去哪里错了? I'd like for the map to re-render and show the new location coming from the props and show the red map marker in that location.我希望 map 重新渲染并显示来自道具的新位置,并在该位置显示红色 map 标记。
I'm tempted to just create a new map, ie paste everything I do on initial render into the hook that changes on props change, but that seems sub optimal.我很想创建一个新的 map,即将我在初始渲染中所做的一切粘贴到随着道具变化而变化的钩子中,但这似乎不是最佳的。
For anyone whom this might help, I realised the issue was actually just that useEffect() wasn't using the updated state until the next render of the component.对于这可能会有所帮助的任何人,我意识到问题实际上只是 useEffect() 在组件的下一次渲染之前没有使用更新的 state。 In order for it to use the latest co-ordinates, I assigned the required centre of the map to a var before passing it to the Openlayers view and layout.为了让它使用最新的坐标,我将 map 所需的中心分配给一个 var,然后再将其传递给 Openlayers 视图和布局。
Here's the code that works:这是有效的代码:
function BusinessLocationMap(props) {
// Transform the centre into something openlayers understands
const transformCentre = (centre) => {
if (centre != null) {
return transform(centre, "EPSG:4326", "EPSG:3857");
}
};
const [map, setMap] = useState();
const [centre] = useState([74.31071359697442, 31.588167443954312]);
const [featuresLayer, setFeaturesLayer] = useState();
const [point, setPoint] = useState();
const [feature, setFeature] = useState();
const [transformedCentre] = useState(transformCentre(centre));
// create state ref that can be accessed in OpenLayers onclick callback function
// https://stackoverflow.com/a/60643670
const mapRef = useRef();
mapRef.current = map;
// initialize map on first render - logic formerly put into componentDidMount
useEffect(() => {
console.log("Initialised for the first time");
console.log("Initial Centre used: " + transformedCentre);
// Create a point
var point = new Point(transformedCentre);
setPoint(point);
// points/lines/polygons are features that can be used in the vector layer
var feature = new Feature({
geometry: point,
name: "Your address is shown here",
});
var iconStyle = new Style({
image: new Icon({
src: markerImg,
}),
});
feature.setStyle(iconStyle);
setFeature(feature);
// create vector source itself for the marker on the map
var vectorSource = new VectorSource({
features: [feature],
});
// create and add vector source layer
const initalFeaturesLayer = new VectorLayer({
source: vectorSource,
});
// create the initial view
const initialView = new View({
center: transformedCentre,
zoom: 17,
});
// create map
const locationMap = new Map({
target: mapRef.current,
layers: [
new TileLayer({
source: new OSM(),
}),
initalFeaturesLayer,
],
view: initialView,
controls: [],
});
setMap(locationMap);
setFeaturesLayer(initalFeaturesLayer);
}, []);
// update map if user changes geo location
useEffect(() => {
console.log("Detected change in User geolocation");
if (props.userEnteredLocation) {
var array = props.userEnteredLocation.split(",");
var newCentre = [parseFloat(array[1]), parseFloat(array[0])];
var newTransformedCentre = transformCentre(newCentre);
}
if (map != null) {
point.setCoordinates(newTransformedCentre);
feature.setGeometry(point);
map.setView(
new View({
center: newTransformedCentre,
zoom: 17,
})
);
// set features to map
featuresLayer.setSource(
new VectorSource({
features: [feature],
})
);
}
}, [props.userEnteredLocation]);
//render component
return <div ref={mapRef} className="map-container"></div>;
}
export default BusinessLocationMap;
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.