最新消息:雨落星辰是一个专注网站SEO优化、网站SEO诊断、搜索引擎研究、网络营销推广、网站策划运营及站长类的自媒体原创博客

javascript - Mapbox style changesbreaks on zoom when a layer is added - Stack Overflow

programmeradmin1浏览0评论

I have a mapbox map, initialized with the outdoors-v9 style (tried other styles, same behavior). When I add a layer to the map - a marker or a geojson source and zoom the map, the style changes or breaks, I'm not sure which.

This is the map before the zoom

and after the zoom

here are the functions that init the map and add markers

mapboxgl.accessToken = "pk.*******";


buildMap: function() {
  const _self = this;
  _self.map = new mapboxgl.Map({
    container: "map",
    style: "mapbox://styles/mapbox/outdoors-v9",
    center: [-95.712891, 37.09024],
    zoom: 3
  });

  _self.map.on('load', function() {
    _self.map.addSource('route', {
      'type': 'geojson',
      'data': {
            "type": "FeatureCollection",
            "features": []
      } 
    });

    _self.map.addLayer({
        'id': 'route',
        'source': 'route',
        'type': 'line',
        'layout': {
          'line-join': 'round',
          'line-cap': 'round'
        },
        'paint': {
          'line-color': '#47576A',
          'line-width': 3
        }
      });
  });
}

...

const coords = [addressData.longitude, addressData.latitude];

const marker = new mapboxgl.Marker().setLngLat(coords).addTo(this.map);

I am using Vue.js to render the map. Mapbox version v0.45.0

Any help or leads are highly appreciated

I have a mapbox map, initialized with the outdoors-v9 style (tried other styles, same behavior). When I add a layer to the map - a marker or a geojson source and zoom the map, the style changes or breaks, I'm not sure which.

This is the map before the zoom

and after the zoom

here are the functions that init the map and add markers

mapboxgl.accessToken = "pk.*******";


buildMap: function() {
  const _self = this;
  _self.map = new mapboxgl.Map({
    container: "map",
    style: "mapbox://styles/mapbox/outdoors-v9",
    center: [-95.712891, 37.09024],
    zoom: 3
  });

  _self.map.on('load', function() {
    _self.map.addSource('route', {
      'type': 'geojson',
      'data': {
            "type": "FeatureCollection",
            "features": []
      } 
    });

    _self.map.addLayer({
        'id': 'route',
        'source': 'route',
        'type': 'line',
        'layout': {
          'line-join': 'round',
          'line-cap': 'round'
        },
        'paint': {
          'line-color': '#47576A',
          'line-width': 3
        }
      });
  });
}

...

const coords = [addressData.longitude, addressData.latitude];

const marker = new mapboxgl.Marker().setLngLat(coords).addTo(this.map);

I am using Vue.js to render the map. Mapbox version v0.45.0

Any help or leads are highly appreciated

Share Improve this question asked Jun 12, 2018 at 19:19 Vladimir AtanasovVladimir Atanasov 1991 silver badge9 bronze badges 2
  • Small update, seems like the issue happens only when I push the instance of the marker to a vuejs data object. Still no idea why this happens – Vladimir Atanasov Commented Jun 16, 2018 at 9:31
  • before you write the map object into your ponent, add _isVue = true: const map = new mapboxgl.Map({...}); map._isVue = true; this.map = map; – wendt88 Commented Jul 15, 2020 at 8:07
Add a ment  | 

6 Answers 6

Reset to default 4

Vue data() properties are reactive, they have getters and setters, so, when loading map object or adding vector tiles layer (geojson), Vue tries to add getters & setters to the map & map.layers which causes vue & vue-dev-tools to crash and mess up the map.

If you enable any raster layer, it would work successfully because raster tiles are loaded via the mapbox.css whereas vector tiles being geojson, are added to the map object.

Easiest solution would be to define a non-reactive variable in vue and then re-use it everywhere.

// edit: A correct/remended way to set non-reactive data: GitHub link

Seems the issue was related with the fact that I'm pushing the marker instance to an observable (a vuejs data field). After pushing the marker instance to an array, the issue disappeared. This ment doesn't really answer why this happens, but hope it helps someone else that might face the same issue

I just faced this issue and realized that I didn't follow the documentation exactly as it was described (jumped right on to coding without reading properly). And the documentation says:

Storing Map object

Take note that it's generally bad idea to add to Vuex or ponent's data anything but primitive types and plain objects. Vue adds getters and setters to every property, so if you add Map object to Vuex store or ponent data, it may lead to weird bugs. If you want to store map object, store it as non-reactive property like in example below.

The problem was that I had also registered "map" inside the "data" object of my Vue ponent. But in the example code it's not declared in data, only in the "create" function.

https://soal.github.io/vue-mapbox/guide/basemap.html#map-loading

After hours spent on this problem, here is my working solution to access map instance from a store (thanks to https://github./vuejs/vue/issues/2637#issuement-331913620):

const state = reactive({
  map: Object.freeze({ wrapper: /* PUT THE MAP INSTANCE HERE */ });
});

Here is an example with Vue Composition Api:

index.js

import { reactive, puted } from "@vue/position-api";

export const state = reactive({
  map: null
});

export const setMap = (map) => {
  state.map = Object.freeze({ wrapper: map});
};

export const getMap = puted(() => state.map.wrapper);

export const initMap = (event) => {
  setMap(event.map);

  // now you can access to map instance from the "getMap" getter!
  getMap.value.addSource("satellite-source", {
    type: "raster",
    url: "mapbox://mapbox.satellite",
  }); 
  getMap.value.addLayer({
    id: "satellite-layer",
    type: "raster",
    source: "satellite-source"
  });
};

App.vue

<template>
  <MglMap :accessToken="..." :mapStyle="..." @load="onMapLoaded" />
</template>


<script>
import { defineComponent } from "@vue/position-api";
import { MglMap } from "vue-mapbox";
import { initMap } from "./index.js";

export default defineComponent({
  ponents: {
    MglMap
  },
  setup() {
    const onMapLoaded = (event) => {
      initMap(event);
    }

    return { onMapLoaded };
  }
});
</script>

I've got the same error. This happens if you either put the map or the marker on an reactive vue.js instance.

Short and quick answer.

Explanation is similar to @mlb's answer. So you freeze the object to prevent the map from disorientated and for any actions done to the map, call back the data with an extra Object key which in case is 'wrapper'.

<template><MglMap :accessToken="..." :mapStyle="..." @load="onMapLoaded" /></template>
    
<script>  
methods: {  
 onMapLoaded(event) {
   this.mapboxEvent = Object.freeze({wrapper: event.map});
 },
 panMap(event) {
   this.mapboxEvent.wrapper.panTo([lng, lat], {duration: 1000, zoom: 14});
 }
}
</script>
发布评论

评论列表(0)

  1. 暂无评论