Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Changing map-style causes layers to disappear #248

Open
Shadercloud opened this issue Jan 27, 2025 · 3 comments
Open

Changing map-style causes layers to disappear #248

Shadercloud opened this issue Jan 27, 2025 · 3 comments

Comments

@Shadercloud
Copy link

Here is an example of the problem (click "Change Style" button): https://codesandbox.io/p/sandbox/3hm8nm (it's using a test api key). The red route line will disappear. Along with this console warning:

Unable to perform style diff: Unimplemented: setSprite.. Rebuilding the style from scratch.

One would expect that changing the map style would not affect anything except the map style. This seems to be a problem with the underlying behaviour of the mapbox API. However one would expect that the Vue component should be able to handle this occurrance. If one has to manually load the layers back onto the map every time the style is changed (using the map instance directly) then there is really no point to having the component at all.

<script setup>
import { ref } from "vue";
import {
  MapboxMap,
  MapboxSource,
  MapboxLayer,
} from "@studiometa/vue-mapbox-gl";
import "mapbox-gl/dist/mapbox-gl.css";

const mapCenter = ref([-1.159535, 51.08822]);
const mapStyle = ref("mapbox://styles/mapbox/streets-v11");

const Change = () => {
  console.log(mapStyle.value);
  if (mapStyle.value === "mapbox://styles/mapbox/streets-v11")
    mapStyle.value = "mapbox://styles/mapbox/satellite-v9";
  else mapStyle.value = "mapbox://styles/mapbox/streets-v11";
};

const route = ref({
  id: "route",
  type: "geojson",
  data: {
    type: "Feature",
    properties: {},
    geometry: {
      type: "LineString",
      coordinates: [
        [-1.158535, 51.08822],
        [-1.158546, 51.08838],
        [-1.1585, 51.08878],
        [-1.158, 51.08978],
      ],
    },
  },
});

const layer = ref({
  id: "layer",
  type: "line",
  source: "route",
  layout: {
    "line-join": "round",
    "line-cap": "round",
  },
  paint: {
    "line-color": "#F00",
    "line-width": 8,
  },
});
</script>

<template>
  <div>Demo Map</div>
  <div><button @click="Change">Change Style</button></div>
  <MapboxMap
    style="height: 400px"
    access-token="..."
    :map-style="mapStyle"
    :center="mapCenter"
    :zoom="15"
  >
    <MapboxSource id="route" :options="route" />
    <MapboxLayer id="layer" :options="layer" />
  </MapboxMap>
</template>
@Shadercloud
Copy link
Author

Note that one "fix" i've found for is to add mapStyle as a key for MapboxMap for example:

<template>
  <div>Demo Map</div>
  <div><button @click="Change">Change Style</button></div>
  <MapboxMap
    :key="mapStyle"
    style="height: 400px"
    access-token="..."
    :map-style="mapStyle"
    :center="mapCenter"
    :zoom="15"
  >
    <MapboxSource id="route" :options="route" />
    <MapboxLayer id="layer" :options="layer" />
  </MapboxMap>
</template>

@titouanmathis
Copy link
Collaborator

It is a "known bug" of Mapbox, when the style of a map is changed, any custom layer needs to be readded to the map. See mapbox/mapbox-gl-js#10534 and mapbox/mapbox-gl-js#8326 and this paragraph in the documentation:

Switch styles at runtime

You can also change the style any time after initializing the map using the Map setStyle method. If you added any layers at runtime, you will need to re-add layers after the new style is loaded.

I had a quick look at how this could be addressed in the components directly, but it is not really simple as the setStyle() method is not async while the change of style is. We could use the styledata event to re-add the layers after the style change is finished, but for now it does not seem reliable enough to have a single and simple solution.

Your workaround is the simplest for now.

@Shadercloud
Copy link
Author

I wonder if it would be easier to get rid of the MapboxSource and MapboxLayer components completely and just feed that data MapboxMap via props. Then it would easier to redraw all sources layers when the map was changed.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants