visgl / deck.gl

WebGL2 powered visualization framework
https://deck.gl
MIT License
12.29k stars 2.09k forks source link

[Bug]MapboxOverlay error when set interleaved=true on mapbox-gl@3.6.0 #9086

Closed linze99 closed 3 months ago

linze99 commented 3 months ago

Description

When setting interleaved=true, deck.gl raise an exception: undefined is not an object (evaluating 'mapboxLayer.implementation.setProps') and the line features on mapbox are dispeared.

截屏2024-08-15 16 03 39

Flavors

Expected Behavior

截屏2024-08-15 16 03 11

Steps to Reproduce

I created a demo project at https://codepen.io/Ze-Lin-the-encoder/pen/eYXXdZd

mapboxgl.accessToken = "accesstoken";

const map = new mapboxgl.Map({
  container: "map", // container ID
  center: [-74.09199, 40.69302], // starting position [lng, lat]
  zoom: 20, // starting zoom
  pitch: 45
});

const { MapboxOverlay } = deck;
const data = [
  {
    geometry: {
      coordinates: [
        [-74.09395914600337, 40.69299152131947],
        [-74.0925962068635, 40.69141229325328],
        [-74.09088773385702, 40.69250392955112],
        [-74.09242343993016, 40.69422140112198]
      ],
      type: "LineString"
    },
    type: "Feature",
    properties: {}
  }
];

const overlay = new MapboxOverlay({
  interleaved: true,
  layers: [
    new deck.GeoJsonLayer({
      id: "linelayer",
      data: data,
      filled: false,
      _full3d: true,
      stroked: true,
      billboard: true,
      getFillColor: [160, 160, 180, 200],
      getLineColor: [250, 0, 0],
      getLineWidth: 3
    })
  ]
});
map.addControl(overlay);

Environment

Logs

No response

linze99 commented 3 months ago

I think this is because mapbox has changed the return value of Map.getLayer() function: the versions before 3.6.0 are:

    getLayer<T extends LayerSpecification>(id: string): T | undefined {
        if (!this._isValidId(id)) {
            return null;
        }

        //it returns a layer object
        const layer = this.style.getOwnLayer(id);
        return layer ? layer.serialize() as T : undefined;
    }

but from version 3.6.0:

    getLayer<T extends LayerSpecification | CustomLayerInterface>(id: string): T | undefined {
        if (!this._isValidId(id)) {
            return null;
        }

        const layer = this.style.getOwnLayer(id);
        if (!layer) return;

        //it returns an implementation directly
        if (layer.type === 'custom') return (layer as CustomStyleLayer).implementation as T;

        return layer.serialize() as T;
    }

so i changed the resolveLayers() function to this:

  // Step 2: add missing layers
  for (const layer of layers) {
    const mapboxLayer = map.getLayer(layer.id) as MapboxLayer<Layer>;
    if (mapboxLayer) {
      // @ts-expect-error not typed
      mapboxLayer.setProps(layer.props);
      //mapboxLayer.implementation.setProps(layer.props);
    } else {
      map.addLayer(
        new MapboxLayer({id: layer.id, deck}),
        // @ts-expect-error beforeId is not defined in LayerProps
        layer.props.beforeId
      );
    }
  }

it works fine!

Pessimistress commented 3 months ago

Thanks for investigating this. I'll release a patch to handle this change.

mdugue commented 3 months ago

@Pessimistress that would be awesome!! Can you share any update on the progress?