Add track popups
This commit is contained in:
@@ -8,7 +8,7 @@ class Settings
|
|||||||
const DB_NAME = 'spot';
|
const DB_NAME = 'spot';
|
||||||
const DB_ENC = 'utf8mb4';
|
const DB_ENC = 'utf8mb4';
|
||||||
const TEXT_ENC = 'UTF-8';
|
const TEXT_ENC = 'UTF-8';
|
||||||
const TIMEZONE = 'Europe/Paris';
|
const TIMEZONE = 'Europe/Zurich';
|
||||||
const MAIL_SERVER = '';
|
const MAIL_SERVER = '';
|
||||||
const MAIL_FROM = '';
|
const MAIL_FROM = '';
|
||||||
const MAIL_USER = '';
|
const MAIL_USER = '';
|
||||||
|
|||||||
@@ -51,7 +51,6 @@ export default {
|
|||||||
createElem(sType) {
|
createElem(sType) {
|
||||||
this.spot.get2('admin_create', {type: sType})
|
this.spot.get2('admin_create', {type: sType})
|
||||||
.then((aoNewElemTypes) => {
|
.then((aoNewElemTypes) => {
|
||||||
console.log(aoNewElemTypes);
|
|
||||||
for(const [sType, aoNewElems] of Object.entries(aoNewElemTypes)) {
|
for(const [sType, aoNewElems] of Object.entries(aoNewElemTypes)) {
|
||||||
for(const [iKey, oNewElem] of Object.entries(aoNewElems)) {
|
for(const [iKey, oNewElem] of Object.entries(aoNewElems)) {
|
||||||
oNewElem.type = sType;
|
oNewElem.type = sType;
|
||||||
@@ -60,7 +59,7 @@ export default {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
.catch((sMsg) => {console.log(sMsg);this.spot.onFeedback('error', sMsg, {'create':sType});});
|
.catch((sMsg) => {this.spot.onFeedback('error', sMsg, {'create':sType});});
|
||||||
},
|
},
|
||||||
deleteElem(oElem) {
|
deleteElem(oElem) {
|
||||||
const asInputs = {
|
const asInputs = {
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
<script>
|
<script>
|
||||||
import 'maplibre-gl/dist/maplibre-gl.css';
|
import 'maplibre-gl/dist/maplibre-gl.css';
|
||||||
import { Map, NavigationControl, Marker, LngLatBounds, LngLat } from 'maplibre-gl';
|
import { Map, NavigationControl, Marker, LngLatBounds, LngLat, Popup } from 'maplibre-gl';
|
||||||
|
import { createApp, defineComponent, nextTick, ref, defineCustomElement, provide, inject } from 'vue';
|
||||||
import simplebar from 'simplebar-vue';
|
import simplebar from 'simplebar-vue';
|
||||||
|
|
||||||
import autosize from 'autosize';
|
import autosize from 'autosize';
|
||||||
@@ -14,12 +14,14 @@ import lightbox from '../scripts/lightbox.js';
|
|||||||
import SpotIcon from './spotIcon.vue';
|
import SpotIcon from './spotIcon.vue';
|
||||||
import SpotButton from './spotButton.vue';
|
import SpotButton from './spotButton.vue';
|
||||||
import ProjectPost from './projectPost.vue';
|
import ProjectPost from './projectPost.vue';
|
||||||
|
import ProjectPopup from './projectPopup.vue';
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
components: {
|
components: {
|
||||||
SpotIcon,
|
SpotIcon,
|
||||||
SpotButton,
|
SpotButton,
|
||||||
ProjectPost,
|
ProjectPost,
|
||||||
|
ProjectPopup,
|
||||||
simplebar
|
simplebar
|
||||||
},
|
},
|
||||||
data() {
|
data() {
|
||||||
@@ -73,7 +75,7 @@ export default {
|
|||||||
watch: {
|
watch: {
|
||||||
baseMap(sNewBaseMap, sOldBaseMap) {
|
baseMap(sNewBaseMap, sOldBaseMap) {
|
||||||
if(sOldBaseMap) this.map.setLayoutProperty(sOldBaseMap, 'visibility', 'none');
|
if(sOldBaseMap) this.map.setLayoutProperty(sOldBaseMap, 'visibility', 'none');
|
||||||
this.map.setLayoutProperty(sNewBaseMap, 'visibility', 'visible');
|
if(sNewBaseMap) this.map.setLayoutProperty(sNewBaseMap, 'visibility', 'visible');
|
||||||
},
|
},
|
||||||
projectCodename(sNewCodeName, sOldCodeName) {
|
projectCodename(sNewCodeName, sOldCodeName) {
|
||||||
console.log('change in projectCodename: '+sNewCodeName);
|
console.log('change in projectCodename: '+sNewCodeName);
|
||||||
@@ -158,6 +160,7 @@ export default {
|
|||||||
async initMap() {
|
async initMap() {
|
||||||
//Get Map Info
|
//Get Map Info
|
||||||
const aoMarkers = await this.spot.get2('markers', {id_project: this.project.id});
|
const aoMarkers = await this.spot.get2('markers', {id_project: this.project.id});
|
||||||
|
this.baseMap = null;
|
||||||
this.baseMaps = aoMarkers.maps;
|
this.baseMaps = aoMarkers.maps;
|
||||||
this.messages = aoMarkers.messages;
|
this.messages = aoMarkers.messages;
|
||||||
|
|
||||||
@@ -193,7 +196,10 @@ export default {
|
|||||||
});
|
});
|
||||||
|
|
||||||
this.map.once('load', async () => {
|
this.map.once('load', async () => {
|
||||||
//Track
|
//Default Basemap
|
||||||
|
this.baseMap = this.baseMaps.filter((asBM) => asBM.default_map)[0].codename;
|
||||||
|
|
||||||
|
//Get track
|
||||||
const oTrack = await this.spot.get2('geojson', {id_project: this.project.id});
|
const oTrack = await this.spot.get2('geojson', {id_project: this.project.id});
|
||||||
this.map.addSource('track', {
|
this.map.addSource('track', {
|
||||||
'type': 'geojson',
|
'type': 'geojson',
|
||||||
@@ -224,9 +230,91 @@ export default {
|
|||||||
});
|
});
|
||||||
|
|
||||||
//Markers
|
//Markers
|
||||||
|
let aoMarkerSource = {type:'geojson', data:{type: 'FeatureCollection', features: []}};
|
||||||
for(const oMsg of this.messages) {
|
for(const oMsg of this.messages) {
|
||||||
new Marker().setLngLat(new LngLat(oMsg.longitude, oMsg.latitude)).addTo(this.map);
|
aoMarkerSource.data.features.push({
|
||||||
|
'type': 'Feature',
|
||||||
|
'properties': {
|
||||||
|
...oMsg,
|
||||||
|
...{'description': ''}
|
||||||
|
},
|
||||||
|
'geometry': {
|
||||||
|
'type': 'Point',
|
||||||
|
'coordinates': [oMsg.longitude, oMsg.latitude]
|
||||||
}
|
}
|
||||||
|
});
|
||||||
|
//Tooltip
|
||||||
|
/*
|
||||||
|
let $Tooltip = $($('<div>', {'class':'info-window'})
|
||||||
|
.append($('<h1>')
|
||||||
|
.addIcon('fa-message fa-lg', true)
|
||||||
|
.append($('<span>').text(this.spot.lang('post_message')+' '+this.spot.lang('counter', oMsg.displayed_id)))
|
||||||
|
.append($('<span>', {'class':'message-type'}).text('('+oMsg.type+')'))
|
||||||
|
)
|
||||||
|
.append($('<div>', {'class':'separator'}))
|
||||||
|
.append($('<p>', {'class':'coordinates'})
|
||||||
|
.addIcon('fa-coords fa-fw fa-lg', true)
|
||||||
|
.append(this.getGoogleMapsLink(oMsg))
|
||||||
|
)
|
||||||
|
.append($('<p>', {'class':'time'})
|
||||||
|
.addIcon('fa-time fa-fw fa-lg', true)
|
||||||
|
.append(oMsg.formatted_time+(this.project.mode==this.spot.consts.modes.blog?' ('+oMsg.relative_time+')':''))))[0];
|
||||||
|
|
||||||
|
const vTooltip = h(SpotIcon, {icon:'project', 'classes':'fa-fw', text:'hikes'});
|
||||||
|
|
||||||
|
//let vTooltip = h(SpotIcon, {icon:'project', 'classes':'fa-fw', text:'hikes'});
|
||||||
|
|
||||||
|
oPopup.setDOMContent(vTooltip);
|
||||||
|
|
||||||
|
new Marker({
|
||||||
|
element: $('<div style="width:'+this.markerSize.width+'px;height:'+this.markerSize.height+'px;"><span class="fa-stack"><i class="fa fa-message fa-stack-2x"></i><i class="fa fa-message-in fa-rotate-270 fa-stack-1x"></i></span></div>')[0],
|
||||||
|
anchor: 'bottom'
|
||||||
|
})
|
||||||
|
.setLngLat(new LngLat(oMsg.longitude, oMsg.latitude))
|
||||||
|
.setPopup(oPopup)
|
||||||
|
.addTo(this.map)
|
||||||
|
;
|
||||||
|
*/
|
||||||
|
}
|
||||||
|
this.map.addSource('markers', aoMarkerSource);
|
||||||
|
const image = await this.map.loadImage('https://maplibre.org/maplibre-gl-js/docs/assets/custom_marker.png');
|
||||||
|
this.map.addImage('markerIcon', image.data);
|
||||||
|
this.map.addLayer({
|
||||||
|
'id': 'markers',
|
||||||
|
'type': 'symbol',
|
||||||
|
'source': 'markers',
|
||||||
|
'layout': {
|
||||||
|
//'icon-anchor': 'bottom',
|
||||||
|
'icon-image': 'markerIcon'
|
||||||
|
//'icon-overlap': 'always'
|
||||||
|
}
|
||||||
|
});
|
||||||
|
this.map.on("click", "markers", (e) => {
|
||||||
|
var oPopup = new Popup({
|
||||||
|
anchor: 'bottom',
|
||||||
|
offset: [0, this.markerSize.height * -1],
|
||||||
|
closeButton: false
|
||||||
|
})
|
||||||
|
.setHTML('<div id="popup"></div>')
|
||||||
|
.setLngLat(e.lngLat)
|
||||||
|
.addTo(this.map);
|
||||||
|
|
||||||
|
let rProp = ref(e.features[0].properties);
|
||||||
|
const vPopup = defineComponent({
|
||||||
|
extends: ProjectPopup,
|
||||||
|
setup: () => {
|
||||||
|
console.log(rProp.value);
|
||||||
|
provide('options', rProp.value);
|
||||||
|
provide('spot', this.spot);
|
||||||
|
provide('project', this.project);
|
||||||
|
return {'options': rProp.value, 'spot':this.spot, 'project':this.project};
|
||||||
|
}
|
||||||
|
});
|
||||||
|
nextTick(() => {
|
||||||
|
createApp(vPopup).mount("#popup");
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
|
||||||
//Centering map
|
//Centering map
|
||||||
let bOpenFeedPanel = !this.mobile;
|
let bOpenFeedPanel = !this.mobile;
|
||||||
@@ -242,7 +330,6 @@ export default {
|
|||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
//Fit to track
|
//Fit to track
|
||||||
console.log('Fit to track');
|
|
||||||
for(const iFeatureId in oTrack.features) {
|
for(const iFeatureId in oTrack.features) {
|
||||||
oBounds = oTrack.features[iFeatureId].geometry.coordinates.reduce(
|
oBounds = oTrack.features[iFeatureId].geometry.coordinates.reduce(
|
||||||
(bounds, coord) => {
|
(bounds, coord) => {
|
||||||
@@ -269,9 +356,6 @@ export default {
|
|||||||
|
|
||||||
//Toggle only when map is ready, for the tilt effet
|
//Toggle only when map is ready, for the tilt effet
|
||||||
this.toggleFeedPanel(bOpenFeedPanel);
|
this.toggleFeedPanel(bOpenFeedPanel);
|
||||||
|
|
||||||
//Default Basemap
|
|
||||||
this.baseMap = this.baseMaps.filter((asBM)=>asBM.default_map)[0].codename;
|
|
||||||
});
|
});
|
||||||
|
|
||||||
this.map.on('idle', () => {
|
this.map.on('idle', () => {
|
||||||
@@ -282,6 +366,14 @@ export default {
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
},
|
||||||
|
getGoogleMapsLink(asInfo) {
|
||||||
|
return $('<a>', {
|
||||||
|
href:'https://www.google.com/maps/place/'+asInfo.lat_dms+'+'+asInfo.lon_dms+'/@'+asInfo.latitude+','+asInfo.longitude+',10z',
|
||||||
|
title: this.spot.lang('see_on_google'),
|
||||||
|
target: '_blank',
|
||||||
|
rel: 'noreferrer noopener'
|
||||||
|
}).text(asInfo.lat_dms+' '+asInfo.lon_dms);
|
||||||
},
|
},
|
||||||
async getNextFeed() {
|
async getNextFeed() {
|
||||||
if(!this.feed.outOfData && !this.feed.loading) {
|
if(!this.feed.outOfData && !this.feed.loading) {
|
||||||
|
|||||||
50
src/components/projectPopup.vue
Normal file
50
src/components/projectPopup.vue
Normal file
@@ -0,0 +1,50 @@
|
|||||||
|
<script>
|
||||||
|
import { options } from 'lightbox2';
|
||||||
|
import projectMapLink from './projectMapLink.vue';
|
||||||
|
import spotIcon from './spotIcon.vue';
|
||||||
|
import projectRelTime from './projectRelTime.vue';
|
||||||
|
|
||||||
|
export default {
|
||||||
|
components: {
|
||||||
|
spotIcon,
|
||||||
|
projectMapLink,
|
||||||
|
projectRelTime
|
||||||
|
},
|
||||||
|
//props: {
|
||||||
|
// options: Object,
|
||||||
|
//},
|
||||||
|
data() {
|
||||||
|
return {
|
||||||
|
}
|
||||||
|
},
|
||||||
|
//inject: ['options', 'spot', 'project'],
|
||||||
|
mounted() {
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<template>
|
||||||
|
<div class="info-window">
|
||||||
|
<h1>
|
||||||
|
<spotIcon :icon="'message'" :classes="'fa-lg'" :text="spot.lang('post_message')+' '+spot.lang('counter', options.displayed_id)" />
|
||||||
|
<span class="message-type">({{ options.type }})</span>
|
||||||
|
</h1>
|
||||||
|
<div class="separator"></div>
|
||||||
|
<p class="coordinates">
|
||||||
|
<spotIcon :icon="'coords'" :classes="'fa-fw fa-lg'" :margin="true" />
|
||||||
|
<projectMapLink :options="options" />
|
||||||
|
</p>
|
||||||
|
<p class="time">
|
||||||
|
<spotIcon :icon="'time'" :classes="'fa-fw fa-lg'" :text="options.formatted_time" />
|
||||||
|
<span v-if="project.mode==spot.consts.modes.blog"> ({{ options.relative_time }})</span>
|
||||||
|
</p>
|
||||||
|
<p class="timezone" v-if="options.day_offset != '0'">
|
||||||
|
<spotIcon :icon="'timezone'" :classes="'fa-fw fa-lg'" :margin="true" />
|
||||||
|
<projectRelTime :localTime="options.formatted_time_local" :offset="options.day_offset" />
|
||||||
|
</p>
|
||||||
|
<p class="weather" v-if="options.weather_icon && options.weather_icon!='unknown'" :title="options.weather_cond==''?'':spot.lang(options.weather_cond)">
|
||||||
|
<spotIcon :icon="options.weather_icon" :classes="'fa-fw fa-lg'" :text="options.weather_temp+'°C'" />
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
@@ -10,7 +10,8 @@ export default {
|
|||||||
|
|
||||||
<template>
|
<template>
|
||||||
<span>
|
<span>
|
||||||
{{ localTime.substr(-5) }}
|
<span>{{ localTime.substring(-5) }}</span>
|
||||||
<sup v-if="offset != '0'" :title="offset+' '+spot.lang('unit_day')+' ('+localTime.substr(0, 5)+')'">{{ ' '+offset }}</sup>
|
<sup v-if="offset != '0'" :title="offset+' '+spot.lang('unit_day')+' ('+localTime.substring(0, 5)+')'">{{ ' '+offset }}</sup>
|
||||||
|
<span> {{ spot.lang('local_time', ' ').trim() }}</span>
|
||||||
</span>
|
</span>
|
||||||
</template>
|
</template>
|
||||||
@@ -6,7 +6,7 @@
|
|||||||
width: 100%;
|
width: 100%;
|
||||||
|
|
||||||
/* Leaflet Popup */
|
/* Leaflet Popup */
|
||||||
.leaflet-popup-content {
|
.maplibregl-popup-content {
|
||||||
|
|
||||||
h1 {
|
h1 {
|
||||||
font-size: 1.4em;
|
font-size: 1.4em;
|
||||||
|
|||||||
Reference in New Issue
Block a user