From ef88e600e347bc1bce0934c638d9ae5b04c6dac5 Mon Sep 17 00:00:00 2001 From: Franzz Date: Mon, 20 Apr 2026 00:42:45 +0200 Subject: [PATCH] Marker layer alternative --- lib/Spot.php | 6 +- src/components/project.vue | 160 +++++++++++++++++----------- src/components/projectMediaLink.vue | 2 +- src/components/projectPopup.vue | 15 +-- src/components/projectPost.vue | 7 +- src/components/spotIcon.vue | 7 +- src/components/spotIconStack.vue | 22 ++++ 7 files changed, 138 insertions(+), 81 deletions(-) create mode 100644 src/components/spotIconStack.vue diff --git a/lib/Spot.php b/lib/Spot.php index b4b8c36..3406e0f 100755 --- a/lib/Spot.php +++ b/lib/Spot.php @@ -288,7 +288,11 @@ class Spot extends Main $iIndex = 0; $iMaxIndex = count($asMessages) - 1; foreach($asMedias as $asMedia) { - if($asMedia['latitude']!='' && $asMedia['longitude']!='') $asGeoMedias[] = $asMedia; + if($asMedia['latitude']!='' && $asMedia['longitude']!='') { + $asMedia['lat_dms'] = self::decToDms($asMedia['latitude'], 'lat'); + $asMedia['lon_dms'] = self::decToDms($asMedia['longitude'], 'lon'); + $asGeoMedias[] = $asMedia; + } elseif($bHasMsg) { while($iIndex <= $iMaxIndex && $asMedia['unix_time'] > $asMessages[$iIndex]['unix_time']) $iIndex++; diff --git a/src/components/project.vue b/src/components/project.vue index 78517df..5880560 100644 --- a/src/components/project.vue +++ b/src/components/project.vue @@ -10,6 +10,7 @@ import waitforimages from 'jquery.waitforimages'; import lightbox from '../scripts/lightbox.js'; import SpotIcon from './spotIcon.vue'; +import SpotIconStack from './spotIconStack.vue'; import SpotButton from './spotButton.vue'; import ProjectPost from './projectPost.vue'; import ProjectPopup from './projectPopup.vue'; @@ -19,7 +20,6 @@ export default { SpotIcon, SpotButton, ProjectPost, - ProjectPopup, Simplebar }, data() { @@ -30,6 +30,7 @@ export default { lastUpdate: { unix_time: 0, relative_time: '', formatted_time: ''}, feedPanelOpen: false, settingsPanelOpen: false, + markers: {messages: null, medias: null}, markerSize: {width: 32, height: 32}, currProject: {}, modeHisto: false, @@ -38,7 +39,6 @@ export default { nlLoading: false, baseMaps: {}, baseMap: null, - messages: null, map: null, hikes: { colors:{'main':'#00ff78', 'off-track':'#0000ff', 'hitchhiking':'#FF7814'}, @@ -190,7 +190,8 @@ export default { const aoMarkers = await this.spot.get2('markers', {id_project: this.currProject.id}); this.baseMap = null; this.baseMaps = aoMarkers.maps; - this.messages = aoMarkers.messages; + this.markers.messages = aoMarkers.messages; + this.markers.medias = aoMarkers.medias; this.lastUpdate = aoMarkers.last_update; //console.log(this.baseMaps); @@ -271,7 +272,7 @@ export default { type:'geojson', data: { type: 'FeatureCollection', - features: this.convertMsgToFeatures(this.messages) + features: this.convertMsgToFeatures(this.markers.messages) } }); this.map.addLayer({ @@ -284,16 +285,60 @@ export default { this.openMarkerPopup(e.features[0]); }); + /* + this.markers.messages.forEach(msg => { + const el = document.createElement('div'); + + const app = createApp(SpotIconStack, {iconMain: 'message', iconSub:'message-in', iconSubClasses:'fa-rotate-270'}); + app.mount(el); + + new Marker({element: el, anchor: 'bottom'}) + .setLngLat([msg.longitude, msg.latitude]) + .addTo(this.map); + }); + */ + + //Medias + this.markers.medias.forEach(msg => { + const $Marker = document.createElement('div'); + const app = createApp(SpotIconStack, {iconMain: 'message', iconSub:'image'}); + app.mount($Marker); + + const $Popup = document.createElement('div'); + const popupElement = new Popup({ + anchor: 'bottom', + offset: [0, this.markerSize.height * -1], + closeButton: false + }) + .setDOMContent($Popup) + .setLngLat([msg.longitude, msg.latitude]) + .setMaxWidth(300) + .addTo(this.map) + ; + console.log(msg); + const popupContent = createApp(ProjectPopup, { + options: msg, + medias: [msg], + project: this.currProject + }); + popupContent.provide('spot', this.spot).mount($Popup); + + new Marker({element: $Marker, anchor: 'bottom'}) + .setLngLat([msg.longitude, msg.latitude]) + .setPopup(popupElement) + .addTo(this.map); + }); + //Centering map let bOpenFeedPanel = !this.mobile; let oBounds = new LngLatBounds(); if( this.currProject.mode == this.spot.consts.modes.blog && - this.messages.length > 0 && + this.markers.messages.length > 0 && this.$parent.hash.items[2] != 'message' ) { //Fit to last message - let oLastMsg = this.messages[this.messages.length - 1]; + let oLastMsg = this.markers.messages[this.markers.messages.length - 1]; oBounds.extend(new LngLat(oLastMsg.longitude, oLastMsg.latitude)); } else { @@ -343,6 +388,50 @@ export default { } })); }, + openMarkerPopup(oFeature) { + this.closeMarkerPopup(); + + //Convert ID Message to feature + if(typeof oFeature == 'number') { + const oMatchingFeatures = this.map.querySourceFeatures('markers', { + filter: ['==', ['get', 'id_message'], oFeature] + }); + + if(!oMatchingFeatures.length) { + console.warn('Marker not found: ', oFeature); + return; + } + else oFeature = oMatchingFeatures[0]; + } + + const $Popup = document.createElement('div'); + this.popup.element = new Popup({ + anchor: 'bottom', + offset: [0, this.markerSize.height * -1], + closeButton: false + }) + .setDOMContent($Popup) + .setLngLat(oFeature.geometry.coordinates) + .setMaxWidth(300) + .addTo(this.map); + + this.popup.content = createApp(ProjectPopup, { + options: oFeature.properties, + medias: JSON.parse(oFeature.properties.medias || '[]'), + project: this.currProject + }); + this.popup.content.provide('spot', this.spot).mount($Popup); + }, + closeMarkerPopup() { + if(this.popup.content) { + this.popup.content.unmount(); + this.popup.content = null; + } + if(this.popup.element) { + this.popup.element.remove(); + this.popup.element = null; + } + }, async getNextFeed() { if(!this.feed.outOfData && !this.feed.loading) { //Get next chunk @@ -396,69 +485,14 @@ export default { }); } + //TODO medias + //Message Last Update this.lastUpdate = aoData.last_update; //Reschedule this.setFeedUpdateTimer(this.refreshRate); }, - openMarkerPopup(oFeature) { - this.closeMarkerPopup(); - - //Convert ID Message to feature - if(typeof oFeature == 'number') { - const oMatchingFeatures = this.map.querySourceFeatures('markers', { - filter: ['==', ['get', 'id_message'], oFeature] - }); - - if(!oMatchingFeatures.length) { - console.warn('Marker not found: ', oFeature); - return; - } - else oFeature = oMatchingFeatures[0]; - } - - const $Popup = document.createElement('div'); - this.popup.element = new Popup({ - anchor: 'bottom', - offset: [0, this.markerSize.height * -1], - closeButton: false - }) - .setDOMContent($Popup) - .setLngLat(oFeature.geometry.coordinates) - .setMaxWidth(300) - .addTo(this.map); - - const rProp = ref(oFeature.properties); - - const vPopup = defineComponent({ - extends: ProjectPopup, - setup: () => { - provide('spot', this.spot); - return { - options: rProp.value, - medias: JSON.parse(rProp.value.medias || '""'), - spot: this.spot, - project: this.currProject - }; - } - }); - - nextTick(() => { - this.popup.content = createApp(vPopup); - this.popup.content.mount($Popup); - }); - }, - closeMarkerPopup() { - if(this.popup.content) { - this.popup.content.unmount(); - this.popup.content = null; - } - if(this.popup.element) { - this.popup.element.remove(); - this.popup.element = null; - } - }, panToBetweenPanels(oLngLat, iZoom, fCallback) { const iXOffset = (this.settingsPanelOpen?getOuterWidth(this.$refs.settings):0) - (this.feedPanelOpen?getOuterWidth(this.$refs.feed):0); diff --git a/src/components/projectMediaLink.vue b/src/components/projectMediaLink.vue index c21ef96..603e63b 100644 --- a/src/components/projectMediaLink.vue +++ b/src/components/projectMediaLink.vue @@ -57,7 +57,7 @@ export default { - + diff --git a/src/components/projectPopup.vue b/src/components/projectPopup.vue index f02dd76..8087a2f 100644 --- a/src/components/projectPopup.vue +++ b/src/components/projectPopup.vue @@ -12,17 +12,12 @@ export default { projectMediaLink, projectRelTime }, - //props: { - // options: Object, - //}, - data() { - return { - } + props: { + options: Object, + medias: Array, + project: Object }, - //inject: ['options', 'medias', 'spot', 'project'], - mounted() { - - } + inject: ['spot'] } diff --git a/src/components/projectPost.vue b/src/components/projectPost.vue index 60425b6..9a6ee91 100644 --- a/src/components/projectPost.vue +++ b/src/components/projectPost.vue @@ -1,5 +1,6 @@ \ No newline at end of file diff --git a/src/components/spotIconStack.vue b/src/components/spotIconStack.vue new file mode 100644 index 0000000..875c3c8 --- /dev/null +++ b/src/components/spotIconStack.vue @@ -0,0 +1,22 @@ + + + \ No newline at end of file