3

How can I add Mapbox expressions inside mapboxgl.Marker() like this one:

"icon-size": ['interpolate', ['linear'], ['zoom'], 10, 1, 15, 0.5]

(I copied this expression from here: https://stackoverflow.com/a/61036364/5220885)

n00b
  • 336
  • 1
  • 5
  • 12

2 Answers2

7

Markers don't support expressions. They are HTML elements, and behave completely differently.

You would have to fake it, along these lines:

  1. Add a handler to the map's zoom event so you can update as the map zooms in and out.
  2. Calculate a size, using regular old JavaScript.
  3. Apply that size using CSS.

Something like this:

map.on('zoom', () => {
    const scalePercent = 1 + (map.getZoom() - 8)  * 0.4;
    const svgElement = marker.getElement().children[0];
    svgElement.style.transform = `scale(${scalePercent})`;
    svgElement.style.transformOrigin = 'bottom';
});

Codepen here: https://codepen.io/stevebennett/pen/MWyXjmR?editors=1001

n00b
  • 336
  • 1
  • 5
  • 12
Steve Bennett
  • 114,604
  • 39
  • 168
  • 219
  • I've edited your code which wasn't working because of '%' in scale (I've divided scalePercent by 100) and added new css style which I thought was important to prevent marker from moving up and down when zooming also you should upgrade codepen link to reflect new changes ;) – n00b Sep 16 '20 at 06:54
  • Interesting, looks like Chrome doesn't like percentage scales. Firefox was cool with it. – Steve Bennett Sep 16 '20 at 08:06
  • 1
    Neither did Safari, but looking at the W3 standard it appears that it is not normal to use percentage, could you verify: https://www.w3.org/TR/css-transforms-2/#propdef-scale – n00b Sep 16 '20 at 08:39
  • @Steve Bennett can you explain how you arrived at your scalePercent formula? – Ken Lin Mar 01 '21 at 03:39
  • 1
    @KenLin I don't know how he came up with it but maybe explaining it might help: `1 + (zoomLevel - R) * scaleFactor` where `zoomLevel` is the current zoom level that Mapbox gives us, R is the zoom level at which you want the scale to be 1 so it will be the starting point and `scaleFactor` (not sure this is the best naming but anyways...) is just a number that tells how much the marker should scale based on the zoomLevel; It's easier if you experiment different values and see the results; I've actually not used this formula as It does not do exactly what I want, I might write an answer on that – n00b Mar 21 '21 at 17:40
1

As @SteveBennett sayed:

Markers don't support expressions. They are HTML elements, and behave completely differently.

assuming you are using html native elements as markers, to have some classes and using them in styling markers, you can use this code after adding markers to map:

      for (const el of yourMarkerElements) {
        let lat = ...;
        let long = ...;

        new Marker({ element: el, anchor: 'bottom-right' })
          .setLngLat(new LngLat(long, lat))
          .addTo(map);
      }

      // use following:
      const that = this;
      map.on('zoom', () => {
        const zoom = map.getZoom();
        for (const el of yourMarkerElements) {
          if (zoom <= 10) { el.classList.remove('zoom-10'); } else { el.classList.add('zoom-10'); }
          if (zoom <= 11) { el.classList.remove('zoom-11'); } else { el.classList.add('zoom-11'); }
          if (zoom <= 12) { el.classList.remove('zoom-12'); } else { el.classList.add('zoom-12'); }
          if (zoom <= 13) { el.classList.remove('zoom-13'); } else { el.classList.add('zoom-13'); }
          if (zoom <= 14) { el.classList.remove('zoom-14'); } else { el.classList.add('zoom-14'); }
          if (zoom <= 15) { el.classList.remove('zoom-15'); } else { el.classList.add('zoom-15'); }
          if (zoom <= 16) { el.classList.remove('zoom-16'); } else { el.classList.add('zoom-16'); }
        }
      });
afruzan
  • 1,454
  • 19
  • 20