简体   繁体   English

如何刷新/重新渲染 OpenLayers 6 Map

[英]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 钩子

  1. The first of which renders the initial map with a red marker and sets the state.第一个使用红色标记渲染初始 map 并设置 state。
// 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 在正确的位置正确渲染正确渲染的地图

  1. The second hook should re-render the map whenever the prop representing lat/long coordinates changes, I can see in the console that the state does indeed change whenever new coordinates are passed into the props, but the map itself doesn't seem to update每当代表纬度/经度坐标的道具发生变化时,第二个钩子应该重新渲染 map,我可以在控制台中看到 state 确实会在新坐标传递到道具时发生变化,但 Z1D78DC8ED51214E518B5114 本身似乎没有更新
// 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.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM