mapbox / mapbox-gl-js

Interactive, thoroughly customizable maps in the browser, powered by vector tiles and WebGL
https://docs.mapbox.com/mapbox-gl-js/
Other
11.07k stars 2.21k forks source link

`geojson.updateData()` cause existing points disappear #13279

Open WeiminWangKolmostar opened 6 days ago

WeiminWangKolmostar commented 6 days ago

mapbox-gl-js version: 3.6.0

browser: chrome 128.0.6613.137

Steps to Trigger Behavior

  1. Add a geojson data source with dynamic: true
  2. Add a layer with the geojson data as source
  3. Add 1000 points to the source with geojson.updateData()
  4. Update one point of the source with geojson.updateData() burstly.

Expected Behavior

The step 4 sometimes may cause the existing points disappear.

Reproduce Code:

const map = new mapboxgl.Map({
            container: 'map', // container ID
            style: "mapbox://styles/mapbox/streets-v12",
            zoom: 12, // starting zoom
            center: [-77.432, 25.0306] // starting position
        });

        map.on('load', () => {
            // Add a data source containing one point feature.
            map.addSource('points', {
                type: 'geojson',
                data: {
                    type: "FeatureCollection",
                    features: [],
                },
                dynamic: true, // allow data to be updated
            });

            // Add a layer to use the image to represent the data.
            map.addLayer({
                id: 'points',
                type: "circle",
                source: 'points',
                paint: {
                    'circle-color': ['coalesce', ["get", "color"], ['to-color', "#000"]],
                    'circle-radius': ["get", "size"],
                },
            });

            map.on('render', () => {
                console.log('render', Date.now(), map.querySourceFeatures("points").length);
            });
            const points = new Array(1000).fill(0).map((_, i) => ({
                id: i,
                lat: 25.0306 + Math.random() * 0.1,
                lon: -77.432 + Math.random() * 0.1,
                notes: `Point ${i}`,
            }));

            map.getSource('points').updateData({
                "type": "FeatureCollection",
                "features": points.map(point => ({
                    "id": point.id,
                    "type": "Feature",
                    "properties": {
                        "description": point.notes || "",
                        "color": point.color || "#000",
                        "size": point.size || 4,
                    },
                    "geometry": {
                        "type": "Point",
                        "coordinates": [point.lon, point.lat],
                    },
                })),
            });

            function update() {
                let s = map.getSource('points');

                console.log('source', Date.now(), {
                    _coalesce: s._coalesce,
                    size: s._data.features.length,
                }, map.querySourceFeatures("points").length);

                s.updateData({
                    "type": "FeatureCollection",
                    "features": [
                        {
                            "id": points.length,
                            "type": "Feature",
                            "properties": {
                                "description": "",
                                "color": "#000",
                                "size": Math.random() * 10,
                            },
                            "geometry": {
                                "type": "Point",
                                "coordinates": [-77.432 + Math.random() * 0.1, 25.0306 + Math.random() * 0.1],
                            },
                        }
                    ],
                });
            }
            for (let i = 0; i < 30; i++) {
                update();
            }

            setTimeout(() => {
                update();
            }, 1);
        });
stepankuzmin commented 5 days ago

Hi @WeiminWangKolmostar,

Have you tried adding data via setData in step 3? cc @mourner

mourner commented 5 days ago

@stepankuzmin it should work with only updateData in any case. Must be some kind of a race condition, need to look into it...