mapbox / mapbox-maps-flutter

Interactive, thoroughly customizable maps for Flutter powered by Mapbox Maps SDK
https://www.mapbox.com/mobile-maps-sdk
Other
245 stars 93 forks source link

Vector Layer Issue #522

Closed roly151 closed 2 weeks ago

roly151 commented 2 weeks ago

I can't explain my issue, so I recorded it (link below).

I am adding/removing vector layers using a timer to achieve a weather radar animation. The source/layer is added, but the 'shapes' seem to take a moment to refine themselves.

https://www.youtube.com/watch?v=1jT5OKuSISQ

My code to add the layer:

addLayer(String id) async {
    await mapboxController?.style.addSource(
      VectorSource(
        id: id, 
        url: weatherController
            .bomData.value.data!.rain?[currentRadarIndex.value].url,
        minzoom: 3,
        maxzoom: 10,
        scheme: Scheme.XYZ,
      ),
    );

   await mapboxController?.style.addLayerAt(
      FillLayer(
        id: id, 
        sourceId: id, 
        sourceLayer: id, 
      ),
      LayerPosition(at: 22),
    );

    await mapboxController?.style.setStyleLayerProperty(
      id, 
      "fill-color",
      [
        "interpolate",
        ['linear'],
        ['get', 'value'],
        0,
        'hsla(240, 100, 98, 0)',
        0.4,
        '#f5f5ff',
        1.6,
        '#b4b4ff',
        3.1,
        '#7878ff',
        4.7,
        '#1414ff',
        7,
        '#00d8c3',
        10.5,
        '#009690',
        15.8,
        '#006666',
        23.7,
        '#ffff00',
        35.5,
        '#ffc800',
        53.4,
        '#ff9600',
        80.1,
        '#ff6400',
        120.3,
        '#ff0000',
        180.5,
        '#c80000',
        271.1,
        '#780000',
        406.9,
        '#280000'
      ],
    );

  }
evil159 commented 2 weeks ago

HI @roly151, the layer and source can stay on in the style no need to remove/add them each time, you can update the url of the vector source like this

    mapboxMap.style.setStyleSourceProperty(id, "url", weatherController
            .bomData.value.data!.rain?[currentRadarIndex.value].url)

Another option is to put all the weather radar data into a single tileset separated by layers(source layers), then the map would load them all when loading the source, which should improve visual result.

You can merge the weather data into a single tileset with https://github.com/mapbox/tippecanoe.

We have an article about seamless weather animations(albeit in web setting) where you can see layered vector source being used.

roly151 commented 2 weeks ago

HI @roly151, the layer and source can stay on in the style no need to remove/add them each time, you can update the url of the vector source like this

    mapboxMap.style.setStyleSourceProperty(id, "url", weatherController
            .bomData.value.data!.rain?[currentRadarIndex.value].url)

Thanks @evil159 , I'll give this a go. I thought this was only available for geoJson sources! This has been an issue for me for close on a year, so hopefully this works. I will report back tomorrow.

We have an article about seamless weather animations(albeit in web setting) where you can see layered vector source being used.

Is this the article? https://blog.mapbox.com/visualizing-radar-data-with-vector-tiles-117bc5ee9a5a

evil159 commented 2 weeks ago

@roly151 Spot on, sorry, forgot to paste the link to the article. Let us know how it goes, I'll close this issue, feel free to reopen if you have any questions or feedback.

roly151 commented 2 weeks ago

Sorry, I would really appreciate your help again @evil159 - I am an inexperienced coder trying to learn.

I updated my 'changeLayer' code to not remove/add the source or layer, but it only briefly showed one of the rain radar layers ('images') - with the others not showing. So I assume I have to update the source-layer property of the layer?

(I start the timer which updates currentRadarIndex.value, and calls this changeLayer function passing in the layer name) This is an example of the api I am working with. The source-layer is the layer name.

"data":{"rain":[{"time":"2024-05-01T02:40Z","type":"observation","is_duplicated":false,"url":"mapbox://bom-dc-prod.rain-prod-LPR-202405010240","layer":{"name":"202405010240"}}, {"time":"2024-05-01T02:45Z","type":"observation","is_duplicated":false,"url":"mapbox://bom-dc-prod.rain-prod-LPR-202405010245","layer":{"name":"202405010245"}},....]}

'id' passed to ChangeLayer is the next layer name, e.g. 202405010240. I tried this using the code below trying to change the source-id property for the layer, as well as the URL for the source, but I get an error "value must be a string". (id is definitely a string)

changeLayer(String id) async {

    await mapboxController?.style.setStyleSourceProperty(
      'bomSource',
      'url',
      weatherController.bomData.value.data!.rain![currentRadarIndex.value].url!,
    );

    await mapboxController?.style.setStyleLayerProperty(
      'bomLayer',
      'source-layer',
      id,
    );
  }

My other code (slight update to the id of the source and layer since I don't have to add and remove it each time):

void loadLayer() async {
    await mapboxController?.style.addSource(
      VectorSource(
        id: 'bomSource',
        url: weatherController
            .bomData.value.data!.rain?[currentRadarIndex.value].url,
      ),
    );

    addLayer(weatherController
        .bomData.value.data!.rain![currentRadarIndex.value].layer!.name!);

    _startTimer();
  }

  addLayer(String id) async {
    await mapboxController?.style.addLayerAt(
      FillLayer(
        id: 'bomLayer',
        sourceId: 'bomSource',
        sourceLayer: id,
      ),
      LayerPosition(at: 22),
    );

    await mapboxController?.style.setStyleLayerProperty(
      'bomLayer',
      "fill-color",
      [
        "interpolate",
        ['linear'],
        ['get', 'value'],
        0,
        'hsla(240, 100, 98, 0)',
        0.4,
        '#f5f5ff',
        1.6,
        '#b4b4ff',
        3.1,
        '#7878ff',
        4.7,
        '#1414ff',
        7,
        '#00d8c3',
        10.5,
        '#009690',
        15.8,
        '#006666',
        23.7,
        '#ffff00',
        35.5,
        '#ffc800',
        53.4,
        '#ff9600',
        80.1,
        '#ff6400',
        120.3,
        '#ff0000',
        180.5,
        '#c80000',
        271.1,
        '#780000',
        406.9,
        '#280000'
      ],
    );
  }