最新消息:雨落星辰是一个专注网站SEO优化、网站SEO诊断、搜索引擎研究、网络营销推广、网站策划运营及站长类的自媒体原创博客

openlayers - I having trouble with both geolocation and vector features appearing at the same location but only one working at a

programmeradmin3浏览0评论

I am working on a React component using OpenLayers to render a map with GeoJSON features and track the user's geolocation. The map initializes, but:

  • The GeoJSON features do not render.

  • Clicking "Track Position" does not update the map with the user's location.

I have checked the GeoJSON format and ensured the vectorSource and vectorLayer are set up correctly.

// ShareMap.js - OpenLayers in React
import React, { Component, createRef } from 'react';
import { Feature, Map, View } from 'ol';
import TileLayer from 'ol/layer/WebGLTile';
import { OSM, Vector as VectorSource } from 'ol/source';
import { Vector as VectorLayer } from 'ol/layer';
import { defaults as defaultInteraction } from 'ol/interaction';
import GeoJSON from 'ol/format/GeoJSON';
import { fromLonLat } from 'ol/proj';
import { Point } from 'ol/geom';
import { Circle as CircleStyle, Fill, Stroke, Style } from 'ol/style';
import 'ol/ol.css';
import 'ol-ext/dist/ol-ext.min.css';
import { Crosshair2Icon } from 'lucide-react';

class ShareMap extends Component {
    mapRef = createRef();

    vectorSource = new VectorSource({ wrapX: false });

    vectorLayer = new VectorLayer({
        source: this.vectorSource,
        style: () => new Style({
            image: new CircleStyle({
                radius: 6,
                fill: new Fill({ color: 'blue' }),
                stroke: new Stroke({ color: 'white', width: 2 }),
            }),
        }),
    });

    constructor(props) {
        super(props);
        this.state = { isLoading: true, isTrack: false };
    }

    renderGeoLocation = async () => {
        const map = this.mapRef.current?.map;
        if (!map && !this.state.isTrack) return;

        const pointStyle = new Style({
            image: new CircleStyle({
                radius: 8,
                fill: new Fill({ color: '#3399CC' }),
                stroke: new Stroke({ color: '#fff', width: 2 }),
            }),
        });

        const userFeature = new Feature();
        userFeature.setStyle(pointStyle);

        const getUserCoords = () => {
            return new Promise((resolve) => {
                if (!navigator?.geolocation) return resolve([]);

                navigator.geolocation.getCurrentPosition(
                    (pos) => resolve([pos.coords.longitude, pos.coords.latitude]),
                    (error) => {
                        alert(`ERROR: ${error.message}`);
                        resolve([]);
                    },
                    { enableHighAccuracy: true }
                );
            });
        };

        const coords = await getUserCoords();
        if (!coords.length) return;

        const transformedCoords = fromLonLat(coords);
        userFeature.setGeometry(new Point(transformedCoords));

        this.vectorSource.clear();
        this.vectorSource.addFeature(userFeature);

        this.setState({ isTrack: false });
    };

    renderGeoJsonData = () => {
        try {
            const map = this.mapRef?.current?.map;
            if (this.props.geoJson && map) {
                this.vectorSource.clear();
                const features = new GeoJSON().readFeatures(JSON.parse(this.props.geoJson));
                if (features.length > 0) {
                    this.vectorSource.addFeatures(features);
                }
            }
            this.vectorSource.changed();
        } catch (err) {
            console.error(err);
        }
    };

    mapRender = () => {
        const map = new Map({
            interactions: defaultInteraction(),
            target: 'mapShare',
            layers: [new TileLayer({ source: new OSM() }), this.vectorLayer],
            view: new View({ center: fromLonLat([0, 0]), zoom: 5 }),
        });

        this.mapRef.current = { map };
        this.renderGeoLocation();
        this.renderGeoJsonData();
    };

    componentDidMount() {
        if (!this.mapRef?.current?.map) this.mapRender();
    }

    componentDidUpdate(prevProps, prevState) {
        if (prevState.isTrack !== this.state.isTrack) {
            this.state.isTrack && this.renderGeoLocation();
        }
    }

    trackPosition = () => {
        this.setState({ isTrack: true });
    };

    render() {
        return (
            <div className="h-full w-full relative flex items-center justify-center">
                <button
                    type="button"
                    className="flex items-center space-x-2 absolute right-4 top-5 rounded-lg bg-white p-2 shadow z-50 hover:bg-gray-50"
                    onClick={this.trackPosition}
                >
                    <Crosshair2Icon />
                    <span className="text-sm">Track Position</span>
                </button>

                <div id="mapShare" className="h-full w-full"></div>
            </div>
        );
    }
}

export default ShareMap;

What I Have Tried:

  • Verified GeoJSON structure using an online validator.

  • Ensured vectorSource.addFeatures() is called with valid features.

  • Called vectorSource.changed() to force a re-render.

  • We need to both render at same time when both location is same

与本文相关的文章

发布评论

评论列表(0)

  1. 暂无评论