0
votes

I've been working with mapboxgl for a while, and I need to change the color of an circle based on the user's location. The circle starts with a color, if the user is on top of the circle, it changes to another color, and based on the interaction that the user has with the application, it changes the color again.

This is my source and layer data:

      const pontosCircle = pontos.map((pointRoute) => ({
        id: pointRoute.order,
        type: 'Feature',
        properties: { collected: 0, name: pointRoute.order },
        geometry: { type: 'Point', coordinates: pointRoute.coordinates }
      }));

      const sourceId = 'pontos';
      const source = {
        type: 'geojson',
        data: {
          type: 'FeatureCollection',
          features: pontosCircle
        }
      };
      const layerCircles = {
        id: 'pontosRota',
        type: 'circle',
        source: sourceId,
        paint: {
          'circle-color': [
            'case',
            ['==', ['get', 'collected'], 0],
            'rgba(235, 68, 90, .8)',
            ['==', ['get', 'collected'], 1],
            'rgba(17, 105, 54, .8)',
            ['==', ['get', 'collected'], 2],
            '#ffffff',
            '#000000'
          ],
          'circle-stroke-width': 2,
          'circle-stroke-color': [
            'case',
            ['==', ['get', 'collected'], 0],
            'rgba(235, 68, 90, .8)',
            ['==', ['get', 'collected'], 1],
            'rgba(17, 105, 54, .8)',
            ['==', ['get', 'collected'], 2],
            '#ffffff',
            '#000000'
          ],
          'circle-radius': {
            stops: [
              [0, 0],
              [20, metersToPixelsAtMaxZoom(rota.raioColeta, rota.pontos[0].ponto.coordinates[1])]
            ],
            base: 2
          }
        }
      };
      const layerLabels = {
        id: 'pontosRota-labels',
        type: 'symbol',
        source: sourceId,
        layout: {
          'text-field': '{name}',
          'text-size': 14
        }
      };

And this is the code that loads the layer/source into mapbox:


      if (!map.getSource(sourceId)) {
        map.addSource(sourceId, source);
      }
      if (!map.getLayer(layerCircles.id) && !map.getLayer(layerLabels.id)) {
        map.addLayer(layerCircles);
        map.addLayer(layerLabels);
      }

I tried a lot of examples that could help me change the property collected from the data, but couldn't get it to work. Should i remove all of the layers and sources everytime that I need to change the data, or is there another way to paint only one of the circles?

1

1 Answers

1
votes

I think that the setData() method that is available for GeoJSON sources in Mapbox GL JS is what you are looking for. The method allows you to update the underlying source data and triggers a map re-render. The data-driven styling should then kick in and style your updates layers as desired.

https://docs.mapbox.com/mapbox-gl-js/api/sources/#geojsonsource#setdata

Here is a pseudo-code example

map.getSource("source-id").setData(updatedGeoJSONData);

I'm in the process of putting together a Mapbox Developers Handbook that will include guides on this kind of stuff. It isn't done yet but you can follow along for updates and get notified when it is released here.