Reputation: 189
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
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
Upvotes: 4
Views: 2416
Reputation: 1247
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>
Upvotes: 0
Reputation: 681
After hours spent on this problem, here is my working solution to access map instance from a store (thanks to https://github.com/vuejs/vue/issues/2637#issuecomment-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, computed } from "@vue/composition-api";
export const state = reactive({
map: null
});
export const setMap = (map) => {
state.map = Object.freeze({ wrapper: map});
};
export const getMap = computed(() => 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/composition-api";
import { MglMap } from "vue-mapbox";
import { initMap } from "./index.js";
export default defineComponent({
components: {
MglMap
},
setup() {
const onMapLoaded = (event) => {
initMap(event);
}
return { onMapLoaded };
}
});
</script>
Upvotes: 1
Reputation: 291
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/recommended way to set non-reactive data: GitHub link
Upvotes: 3
Reputation: 126
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 component'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 component 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 component. 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
Upvotes: 1
Reputation: 7827
I've got the same error. This happens if you either put the map or the marker on an reactive vue.js instance.
Upvotes: 0
Reputation: 189
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 comment doesn't really answer why this happens, but hope it helps someone else that might face the same issue
Upvotes: 1