繁体   English   中英

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

[英]How to refresh/re-render an OpenLayers 6 Map

我有一个 React 组件,我在其中渲染了 Open Layers 6 map。 我将纬度/经度坐标作为道具 (props.userEnteredLocation) 传递给 map,它被转换为开放层期望的格式,以便能够呈现正确的位置。

我的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;

我有两个 React 钩子

  1. 第一个使用红色标记渲染初始 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);
    }, []);

这有效,map 在正确的位置正确渲染正确渲染的地图

  1. 每当代表纬度/经度坐标的道具发生变化时,第二个钩子应该重新渲染 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>;

我已经按照常见问题解答的建议尝试了 map.render() 和 map.renderSync() 无济于事。 我还在 VectorSource 本身上尝试了 .changed() 和 .refresh() , .changed() 什么也不做, .refresh() 完全删除了我的红色标记。

有谁知道我要去哪里错了? 我希望 map 重新渲染并显示来自道具的新位置,并在该位置显示红色 map 标记。

我很想创建一个新的 map,即将我在初始渲染中所做的一切粘贴到随着道具变化而变化的钩子中,但这似乎不是最佳的。

对于这可能会有所帮助的任何人,我意识到问题实际上只是 useEffect() 在组件的下一次渲染之前没有使用更新的 state。 为了让它使用最新的坐标,我将 map 所需的中心分配给一个 var,然后再将其传递给 Openlayers 视图和布局。

这是有效的代码:

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