diff --git a/src/components/project.vue b/src/components/project.vue index 2c72318..1b2669f 100644 --- a/src/components/project.vue +++ b/src/components/project.vue @@ -72,9 +72,9 @@ export default { }, watch: { baseMap(sNewBaseMap, sOldBaseMap) { - if(this.map.isStyleLoaded()) { - if(sOldBaseMap) this.map.setLayoutProperty(sOldBaseMap, 'visibility', 'none'); - if(sNewBaseMap) this.map.setLayoutProperty(sNewBaseMap, 'visibility', 'visible'); + if(this.map?.isStyleLoaded()) { + if(sOldBaseMap && this.map.getLayer(sOldBaseMap)) this.map.setLayoutProperty(sOldBaseMap, 'visibility', 'none'); + if(sNewBaseMap && this.map.getLayer(sNewBaseMap)) this.map.setLayoutProperty(sNewBaseMap, 'visibility', 'visible'); } }, }, @@ -190,45 +190,25 @@ export default { const oMarkersPromise = this.spot.get2('markers', {id_project: this.currProject.id}); const oTrackPromise = this.spot.get2('geojson', {id_project: this.currProject.id}); - //Get Map Info - const aoMarkers = await oMarkersPromise; - this.baseMap = null; - this.baseMaps = aoMarkers.maps; - this.markers.messages = aoMarkers.messages; - this.markers.medias = aoMarkers.medias; - this.lastUpdate = aoMarkers.last_update; - - //Base maps (raster tiles) - let asSources = {}; - let asLayers = []; - for(const asBaseMap of this.baseMaps) { - asSources[asBaseMap.codename] = { - type: 'raster', - tiles: [asBaseMap.pattern], - tileSize: asBaseMap.tile_size - }; - asLayers.push({ - id: asBaseMap.codename, - type: 'raster', - source: asBaseMap.codename, - 'layout': {'visibility': 'none'}, - minZoom: asBaseMap.min_zoom, - maxZoom: asBaseMap.max_zoom - }); - } - - //Map + //Build Map if(this.map) this.map.remove(); this.map = new Map({ container: 'map', style: { version: 8, - sources: asSources, - layers: asLayers + sources: {}, + layers: [] }, attributionControl: false }); - const oMarkerImagePromise = this.map.loadImage('images/footprint_mapbox.png'); + + //Parse Map Info + const aoMarkers = await oMarkersPromise; + this.baseMaps = aoMarkers.maps; + this.baseMap = this.baseMaps.find((asBM) => asBM.default_map)?.codename ?? null; + this.markers.messages = aoMarkers.messages; + this.markers.medias = aoMarkers.medias; + this.lastUpdate = aoMarkers.last_update; //Force wait for load event await new Promise((resolve) => { @@ -236,11 +216,39 @@ export default { else this.map.once('load', resolve); }); - //Default Basemap - this.baseMap = this.baseMaps.filter((asBM) => asBM.default_map)[0].codename; + //Base maps (raster tiles) + for(const asBaseMap of this.baseMaps) { + this.map.addSource(asBaseMap.codename, { + type: 'raster', + tiles: [asBaseMap.pattern], + tileSize: asBaseMap.tile_size + }); + this.map.addLayer({ + id: asBaseMap.codename, + type: 'raster', + source: asBaseMap.codename, + 'layout': {'visibility': asBaseMap.codename == this.baseMap ? 'visible' : 'none'}, + minZoom: asBaseMap.min_zoom, + maxZoom: asBaseMap.max_zoom + }); + } - //Get track + //Add track const oTrack = await oTrackPromise; + this.addTrack(oTrack); + + //Centering map + await this.positionMap(oTrack); + + //Add Markers + this.addMarkers(); + + //Force wait for idle event + await new Promise((resolve) => { + this.map.once('idle', resolve); + }); + }, + addTrack(oTrack) { this.map.addSource('track', { 'type': 'geojson', 'data': oTrack @@ -248,9 +256,9 @@ export default { //Color mapping let asColorMapping = ['match', ['get', 'type']]; - for(const sHikeType in this.hikes.colors) { + for(const [sHikeType, sColor] of Object.entries(this.hikes.colors)) { asColorMapping.push(sHikeType); - asColorMapping.push(this.hikes.colors[sHikeType]); + asColorMapping.push(sColor); } asColorMapping.push('black'); //fallback value @@ -268,9 +276,9 @@ export default { 'line-width': this.hikes.width } }); - - //Markers - this.map.addImage('markerIcon', (await oMarkerImagePromise).data); + }, + async addMarkers() { + this.map.addImage('markerIcon', (await this.map.loadImage('images/footprint_mapbox.png')).data); this.map.addSource('markers', { type:'geojson', data: { @@ -305,7 +313,7 @@ export default { //TODO Use same way of displaying markers (so that openMarkerPopup works on all markers) this.markers.medias.forEach(msg => { const $Marker = document.createElement('div'); - const app = createApp(SpotIconStack, {iconMain: 'message', iconSub:'image'}); + const app = createApp(SpotIconStack, {iconMain: 'media', iconSub: msg.subtype+'-in'}); app.mount($Marker); const $Popup = document.createElement('div'); @@ -332,21 +340,22 @@ export default { .setPopup(popupElement) .addTo(this.map); }); - - //Centering map + }, + async positionMap(oTrack) { let bOpenFeedPanel = !this.mobile; let oBounds = new LngLatBounds(); - if( + + if( //Blog Mode: Fit to last message this.currProject.mode == this.spot.consts.modes.blog && this.markers.messages.length > 0 && this.$parent.hash.items[2] != 'message' ) { - //Fit to last message + let oLastMsg = this.markers.messages[this.markers.messages.length - 1]; oBounds.extend(new LngLat(oLastMsg.longitude, oLastMsg.latitude)); } - else { - //Fit to track + else { //Pre/Histo Mode: Fit to track + for(const iFeatureId in oTrack.features) { oBounds = oTrack.features[iFeatureId].geometry.coordinates.reduce( (bounds, coord) => { @@ -356,6 +365,7 @@ export default { ); } } + const iFeedPanelPadding = bOpenFeedPanel?(getOuterWidth(this.$refs.feed)/2):0; await this.map.fitBounds( oBounds, @@ -373,11 +383,6 @@ export default { //Toggle only when map is ready, for the tilt effet this.toggleFeedPanel(bOpenFeedPanel); - - //Force wait for idle event - await new Promise((resolve) => { - this.map.once('idle', resolve); - }); }, convertMsgToFeatures(oMsg) { return oMsg.map(oMsg => ({ @@ -640,9 +645,9 @@ export default {

-
- -