Manage map initialization sequence better + Fix map/project radio buttons
This commit is contained in:
@@ -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 {
|
||||
<div class="settings-section">
|
||||
<h1><SpotIcon :icon="'project'" :classes="'fa-fw'" :text="spot.lang('hikes')" /></h1>
|
||||
<div class="settings-section-body">
|
||||
<div class="radio" v-for="project in projects">
|
||||
<input type="radio" :id="project.id" :value="project.codename" v-model="$parent.hash.items[0]" />
|
||||
<label :for="project.id">
|
||||
<div class="radio" v-for="project in projects" :key="'project-'+project.id">
|
||||
<input type="radio" :id="'project-'+project.id" :value="project.codename" v-model="$parent.hash.items[0]" />
|
||||
<label :for="'project-'+project.id">
|
||||
<span>{{ project.name }}</span>
|
||||
<a class="download" :href="project.gpxfilepath" :title="spot.lang('track_download')" @click.stop="()=>{}">
|
||||
<SpotIcon :icon="'download'" :classes="'push-left'" />
|
||||
@@ -654,9 +659,9 @@ export default {
|
||||
<div class="settings-section">
|
||||
<h1><SpotIcon :icon="'map'" :classes="'fa-fw'" :text="spot.lang('maps')" /></h1>
|
||||
<div class="settings-section-body">
|
||||
<div class="radio" v-for="bm in baseMaps">
|
||||
<input type="radio" :id="bm.id_map" :value="bm.codename" v-model="baseMap" />
|
||||
<label :for="bm.id_map">{{ this.spot.lang('map_'+bm.codename) }}</label>
|
||||
<div class="radio" v-for="bm in baseMaps" :key="'map-'+bm.id_map">
|
||||
<input type="radio" :id="'map-'+bm.id_map" :value="bm.codename" v-model="baseMap" />
|
||||
<label :for="'map-'+bm.id_map">{{ this.spot.lang('map_'+bm.codename) }}</label>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -40,6 +40,9 @@ export default {
|
||||
<spotIcon :icon="'coords'" :classes="'fa-fw fa-lg'" :margin="true" />
|
||||
<projectMapLink :options="options" />
|
||||
</p>
|
||||
<p class="altitude" v-if="options.altitude">
|
||||
<spotIcon :icon="'altitude'" :classes="'fa-fw fa-lg'" :text="options.altitude+'m'" />
|
||||
</p>
|
||||
<p class="time">
|
||||
<projectRelTime :icon="timeIcon" :localTime="options.formatted_time_local" :siteTime="options.formatted_time" :offset="options.day_offset" />
|
||||
<span v-if="project.mode==spot.consts.modes.blog"> ({{ options.relative_time }})</span>
|
||||
|
||||
@@ -18,10 +18,12 @@ $post-hover: $default-hover;
|
||||
$post-bg: $default-bg;
|
||||
|
||||
$message: hsl(109, 45%, 27%);
|
||||
$message-flashy: hsl(148, 100%, 50%);
|
||||
$message-hover: color.adjust($message, $lightness: -10%, $space: hsl);
|
||||
$message-bg: color.adjust($message, $lightness: 60%, $space: hsl);
|
||||
|
||||
$media: hsl(214, 45%, 27%);
|
||||
$media-flashy: hsl(193, 100%, 50%);
|
||||
$media-hover: color.adjust($media, $lightness: -10%, $space: hsl);
|
||||
$media-bg: color.adjust($media, $lightness: 60%, $space: hsl);
|
||||
$media-bg-light: color.adjust($media, $lightness: 60%, $alpha: -0.4, $space: hsl);
|
||||
@@ -38,7 +40,7 @@ $download-hover: #0078A8;
|
||||
|
||||
//Legend colors
|
||||
$legend: $default;
|
||||
$main-track: #00ff78;
|
||||
$main-track: $message-flashy;
|
||||
$off-track: #0000ff;
|
||||
$hitchhiking: #ff7814;
|
||||
|
||||
|
||||
@@ -71,7 +71,9 @@
|
||||
.#{variables.$fa-css-prefix}-post:before { content: functions.fa-content(variables.$fa-var-comment); }
|
||||
.#{variables.$fa-css-prefix}-media:before { content: functions.fa-content(variables.$fa-var-photo-video); }
|
||||
.#{variables.$fa-css-prefix}-video:before { content: functions.fa-content(variables.$fa-var-film); }
|
||||
.#{variables.$fa-css-prefix}-video-in:before { content: functions.fa-content(variables.$fa-var-film); }
|
||||
.#{variables.$fa-css-prefix}-image:before { content: functions.fa-content(variables.$fa-var-image); }
|
||||
.#{variables.$fa-css-prefix}-image-in:before { content: functions.fa-content(variables.$fa-var-image); }
|
||||
.#{variables.$fa-css-prefix}-message:before { content: functions.fa-content(variables.$fa-var-map-marker); }
|
||||
.#{variables.$fa-css-prefix}-message-in:before { content: functions.fa-content(variables.$fa-var-shoe-prints); }
|
||||
.#{variables.$fa-css-prefix}-time:before { content: functions.fa-content(variables.$fa-var-clock); }
|
||||
|
||||
@@ -51,20 +51,6 @@
|
||||
}
|
||||
}
|
||||
|
||||
.message {
|
||||
margin: 0;
|
||||
}
|
||||
.signature {
|
||||
margin: var.$elem-spacing 0 0 0;
|
||||
text-align: right;
|
||||
font-style: italic;
|
||||
|
||||
img {
|
||||
vertical-align: baseline;
|
||||
margin: 0 0.2em calc((1em - 24px)/2) 0;
|
||||
position: relative;
|
||||
}
|
||||
}
|
||||
.header {
|
||||
padding: 0 var.$block-spacing;
|
||||
position: relative;
|
||||
@@ -91,6 +77,7 @@
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.body {
|
||||
clear: both;
|
||||
padding: 0em var.$block-spacing var.$block-spacing;
|
||||
@@ -191,6 +178,22 @@
|
||||
&.post {
|
||||
.body {
|
||||
padding: 0em 1em 0.5em;
|
||||
|
||||
.message {
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
.signature {
|
||||
margin: var.$elem-spacing 0 0 0;
|
||||
text-align: right;
|
||||
font-style: italic;
|
||||
|
||||
img {
|
||||
vertical-align: baseline;
|
||||
margin: 0 0.2em calc((1em - 24px)/2) 0;
|
||||
position: relative;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -218,6 +221,17 @@
|
||||
background: color.$media-bg-light;
|
||||
}
|
||||
|
||||
.drill-icon {
|
||||
font-size: 3em;
|
||||
|
||||
.fa-drill-image {
|
||||
color: transparent;
|
||||
}
|
||||
.fa-drill-video {
|
||||
color: color.$over-img-bg;
|
||||
}
|
||||
}
|
||||
|
||||
&:hover {
|
||||
.drill-icon {
|
||||
.fa-drill-image, .fa-drill-video {
|
||||
@@ -229,17 +243,6 @@
|
||||
opacity: 0;
|
||||
}
|
||||
}
|
||||
|
||||
.drill-icon {
|
||||
font-size: 3em;
|
||||
|
||||
.fa-drill-image {
|
||||
color: transparent;
|
||||
}
|
||||
.fa-drill-video {
|
||||
color: color.$over-img-bg;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
img {
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
@use "fa/variables";
|
||||
@use "var";
|
||||
@use "color";
|
||||
|
||||
@@ -35,23 +36,30 @@
|
||||
}
|
||||
}
|
||||
|
||||
.fa-stack {
|
||||
.fa-message {
|
||||
.#{variables.$fa-css-prefix}-stack {
|
||||
.#{variables.$fa-css-prefix}-message {
|
||||
font-size: 32px;
|
||||
text-shadow: color.$over-img-shadow 3px 3px 3px;
|
||||
color: color.$main-track;
|
||||
color: color.$message-flashy;
|
||||
}
|
||||
.fa-message-in {
|
||||
.#{variables.$fa-css-prefix}-media {
|
||||
@extend .#{variables.$fa-css-prefix}-message;
|
||||
color: color.$media-flashy;
|
||||
}
|
||||
.#{variables.$fa-css-prefix}-message-in {
|
||||
font-size: 13px;
|
||||
color: color.$message;
|
||||
top: 1px;
|
||||
}
|
||||
.fa-track-start, .fa-track-end {
|
||||
.#{variables.$fa-css-prefix}-media-in {
|
||||
color: color.$media;
|
||||
}
|
||||
.#{variables.$fa-css-prefix}-track-start, .#{variables.$fa-css-prefix}-track-end {
|
||||
color: color.$track-start;
|
||||
font-size: 14px;
|
||||
top: 1px;
|
||||
}
|
||||
.fa-track-end {
|
||||
.#{variables.$fa-css-prefix}-track-end {
|
||||
color: color.$track-end;
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user