Rebuild Leaflet map components from scratch.
This commit is contained in:
parent
e3513049df
commit
d51a4ca3d1
|
@ -16,10 +16,10 @@
|
|||
"@fullcalendar/luxon2": "^5.10.2",
|
||||
"@fullcalendar/timegrid": "^5.9.0",
|
||||
"@fullcalendar/vue3": "^5.11",
|
||||
"@vue-leaflet/vue-leaflet": "*",
|
||||
"@vue/compat": "^3.2.45",
|
||||
"@vuelidate/core": "^2.0.0",
|
||||
"@vuelidate/validators": "^2.0.0",
|
||||
"@vueuse/core": "^9.6.0",
|
||||
"axios": "^1",
|
||||
"bootstrap": "^4.6.0 <5",
|
||||
"bootstrap-notify": "^3.1.3",
|
||||
|
@ -1970,14 +1970,10 @@
|
|||
"resolved": "https://registry.npmjs.org/@types/parse5/-/parse5-5.0.3.tgz",
|
||||
"integrity": "sha512-kUNnecmtkunAoQ3CnjmMkzNU/gtxG8guhi+Fk2U/kOpIKjIMKnXGp4IJCgQJrXSgMsWYimYG4TGjz/UzbGEBTw=="
|
||||
},
|
||||
"node_modules/@vue-leaflet/vue-leaflet": {
|
||||
"version": "0.7.0",
|
||||
"resolved": "https://registry.npmjs.org/@vue-leaflet/vue-leaflet/-/vue-leaflet-0.7.0.tgz",
|
||||
"integrity": "sha512-YY1bcg+7ftGZk4ihCOckOSFMfuhimGxEpPabtpBpaaaquABliB0dkANNFx5d8Y5Vadko5Yjc8Vq74hb/dg4gQw==",
|
||||
"peerDependencies": {
|
||||
"leaflet": "^1.6.0",
|
||||
"vue": "^3.0.0"
|
||||
}
|
||||
"node_modules/@types/web-bluetooth": {
|
||||
"version": "0.0.16",
|
||||
"resolved": "https://registry.npmjs.org/@types/web-bluetooth/-/web-bluetooth-0.0.16.tgz",
|
||||
"integrity": "sha512-oh8q2Zc32S6gd/j50GowEjKLoOVOwHP/bWVjKJInBwQqdOYMdPrf1oVlelTlyfFK3CKxL1uahMDAr+vy8T7yMQ=="
|
||||
},
|
||||
"node_modules/@vue/compat": {
|
||||
"version": "3.2.45",
|
||||
|
@ -2183,6 +2179,89 @@
|
|||
}
|
||||
}
|
||||
},
|
||||
"node_modules/@vueuse/core": {
|
||||
"version": "9.6.0",
|
||||
"resolved": "https://registry.npmjs.org/@vueuse/core/-/core-9.6.0.tgz",
|
||||
"integrity": "sha512-qGUcjKQXHgN+jqXEgpeZGoxdCbIDCdVPz3QiF1uyecVGbMuM63o96I1GjYx5zskKgRI0FKSNsVWM7rwrRMTf6A==",
|
||||
"dependencies": {
|
||||
"@types/web-bluetooth": "^0.0.16",
|
||||
"@vueuse/metadata": "9.6.0",
|
||||
"@vueuse/shared": "9.6.0",
|
||||
"vue-demi": "*"
|
||||
},
|
||||
"funding": {
|
||||
"url": "https://github.com/sponsors/antfu"
|
||||
}
|
||||
},
|
||||
"node_modules/@vueuse/core/node_modules/vue-demi": {
|
||||
"version": "0.13.11",
|
||||
"resolved": "https://registry.npmjs.org/vue-demi/-/vue-demi-0.13.11.tgz",
|
||||
"integrity": "sha512-IR8HoEEGM65YY3ZJYAjMlKygDQn25D5ajNFNoKh9RSDMQtlzCxtfQjdQgv9jjK+m3377SsJXY8ysq8kLCZL25A==",
|
||||
"hasInstallScript": true,
|
||||
"bin": {
|
||||
"vue-demi-fix": "bin/vue-demi-fix.js",
|
||||
"vue-demi-switch": "bin/vue-demi-switch.js"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=12"
|
||||
},
|
||||
"funding": {
|
||||
"url": "https://github.com/sponsors/antfu"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"@vue/composition-api": "^1.0.0-rc.1",
|
||||
"vue": "^3.0.0-0 || ^2.6.0"
|
||||
},
|
||||
"peerDependenciesMeta": {
|
||||
"@vue/composition-api": {
|
||||
"optional": true
|
||||
}
|
||||
}
|
||||
},
|
||||
"node_modules/@vueuse/metadata": {
|
||||
"version": "9.6.0",
|
||||
"resolved": "https://registry.npmjs.org/@vueuse/metadata/-/metadata-9.6.0.tgz",
|
||||
"integrity": "sha512-sIC8R+kWkIdpi5X2z2Gk8TRYzmczDwHRhEFfCu2P+XW2JdPoXrziqsGpDDsN7ykBx4ilwieS7JUIweVGhvZ93w==",
|
||||
"funding": {
|
||||
"url": "https://github.com/sponsors/antfu"
|
||||
}
|
||||
},
|
||||
"node_modules/@vueuse/shared": {
|
||||
"version": "9.6.0",
|
||||
"resolved": "https://registry.npmjs.org/@vueuse/shared/-/shared-9.6.0.tgz",
|
||||
"integrity": "sha512-/eDchxYYhkHnFyrb00t90UfjCx94kRHxc7J1GtBCqCG4HyPMX+krV9XJgVtWIsAMaxKVU4fC8NSUviG1JkwhUQ==",
|
||||
"dependencies": {
|
||||
"vue-demi": "*"
|
||||
},
|
||||
"funding": {
|
||||
"url": "https://github.com/sponsors/antfu"
|
||||
}
|
||||
},
|
||||
"node_modules/@vueuse/shared/node_modules/vue-demi": {
|
||||
"version": "0.13.11",
|
||||
"resolved": "https://registry.npmjs.org/vue-demi/-/vue-demi-0.13.11.tgz",
|
||||
"integrity": "sha512-IR8HoEEGM65YY3ZJYAjMlKygDQn25D5ajNFNoKh9RSDMQtlzCxtfQjdQgv9jjK+m3377SsJXY8ysq8kLCZL25A==",
|
||||
"hasInstallScript": true,
|
||||
"bin": {
|
||||
"vue-demi-fix": "bin/vue-demi-fix.js",
|
||||
"vue-demi-switch": "bin/vue-demi-switch.js"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=12"
|
||||
},
|
||||
"funding": {
|
||||
"url": "https://github.com/sponsors/antfu"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"@vue/composition-api": "^1.0.0-rc.1",
|
||||
"vue": "^3.0.0-0 || ^2.6.0"
|
||||
},
|
||||
"peerDependenciesMeta": {
|
||||
"@vue/composition-api": {
|
||||
"optional": true
|
||||
}
|
||||
}
|
||||
},
|
||||
"node_modules/@webassemblyjs/ast": {
|
||||
"version": "1.11.1",
|
||||
"resolved": "https://registry.npmjs.org/@webassemblyjs/ast/-/ast-1.11.1.tgz",
|
||||
|
@ -11972,11 +12051,10 @@
|
|||
"resolved": "https://registry.npmjs.org/@types/parse5/-/parse5-5.0.3.tgz",
|
||||
"integrity": "sha512-kUNnecmtkunAoQ3CnjmMkzNU/gtxG8guhi+Fk2U/kOpIKjIMKnXGp4IJCgQJrXSgMsWYimYG4TGjz/UzbGEBTw=="
|
||||
},
|
||||
"@vue-leaflet/vue-leaflet": {
|
||||
"version": "0.7.0",
|
||||
"resolved": "https://registry.npmjs.org/@vue-leaflet/vue-leaflet/-/vue-leaflet-0.7.0.tgz",
|
||||
"integrity": "sha512-YY1bcg+7ftGZk4ihCOckOSFMfuhimGxEpPabtpBpaaaquABliB0dkANNFx5d8Y5Vadko5Yjc8Vq74hb/dg4gQw==",
|
||||
"requires": {}
|
||||
"@types/web-bluetooth": {
|
||||
"version": "0.0.16",
|
||||
"resolved": "https://registry.npmjs.org/@types/web-bluetooth/-/web-bluetooth-0.0.16.tgz",
|
||||
"integrity": "sha512-oh8q2Zc32S6gd/j50GowEjKLoOVOwHP/bWVjKJInBwQqdOYMdPrf1oVlelTlyfFK3CKxL1uahMDAr+vy8T7yMQ=="
|
||||
},
|
||||
"@vue/compat": {
|
||||
"version": "3.2.45",
|
||||
|
@ -12124,6 +12202,46 @@
|
|||
}
|
||||
}
|
||||
},
|
||||
"@vueuse/core": {
|
||||
"version": "9.6.0",
|
||||
"resolved": "https://registry.npmjs.org/@vueuse/core/-/core-9.6.0.tgz",
|
||||
"integrity": "sha512-qGUcjKQXHgN+jqXEgpeZGoxdCbIDCdVPz3QiF1uyecVGbMuM63o96I1GjYx5zskKgRI0FKSNsVWM7rwrRMTf6A==",
|
||||
"requires": {
|
||||
"@types/web-bluetooth": "^0.0.16",
|
||||
"@vueuse/metadata": "9.6.0",
|
||||
"@vueuse/shared": "9.6.0",
|
||||
"vue-demi": "*"
|
||||
},
|
||||
"dependencies": {
|
||||
"vue-demi": {
|
||||
"version": "0.13.11",
|
||||
"resolved": "https://registry.npmjs.org/vue-demi/-/vue-demi-0.13.11.tgz",
|
||||
"integrity": "sha512-IR8HoEEGM65YY3ZJYAjMlKygDQn25D5ajNFNoKh9RSDMQtlzCxtfQjdQgv9jjK+m3377SsJXY8ysq8kLCZL25A==",
|
||||
"requires": {}
|
||||
}
|
||||
}
|
||||
},
|
||||
"@vueuse/metadata": {
|
||||
"version": "9.6.0",
|
||||
"resolved": "https://registry.npmjs.org/@vueuse/metadata/-/metadata-9.6.0.tgz",
|
||||
"integrity": "sha512-sIC8R+kWkIdpi5X2z2Gk8TRYzmczDwHRhEFfCu2P+XW2JdPoXrziqsGpDDsN7ykBx4ilwieS7JUIweVGhvZ93w=="
|
||||
},
|
||||
"@vueuse/shared": {
|
||||
"version": "9.6.0",
|
||||
"resolved": "https://registry.npmjs.org/@vueuse/shared/-/shared-9.6.0.tgz",
|
||||
"integrity": "sha512-/eDchxYYhkHnFyrb00t90UfjCx94kRHxc7J1GtBCqCG4HyPMX+krV9XJgVtWIsAMaxKVU4fC8NSUviG1JkwhUQ==",
|
||||
"requires": {
|
||||
"vue-demi": "*"
|
||||
},
|
||||
"dependencies": {
|
||||
"vue-demi": {
|
||||
"version": "0.13.11",
|
||||
"resolved": "https://registry.npmjs.org/vue-demi/-/vue-demi-0.13.11.tgz",
|
||||
"integrity": "sha512-IR8HoEEGM65YY3ZJYAjMlKygDQn25D5ajNFNoKh9RSDMQtlzCxtfQjdQgv9jjK+m3377SsJXY8ysq8kLCZL25A==",
|
||||
"requires": {}
|
||||
}
|
||||
}
|
||||
},
|
||||
"@webassemblyjs/ast": {
|
||||
"version": "1.11.1",
|
||||
"resolved": "https://registry.npmjs.org/@webassemblyjs/ast/-/ast-1.11.1.tgz",
|
||||
|
|
|
@ -17,10 +17,10 @@
|
|||
"@fullcalendar/luxon2": "^5.10.2",
|
||||
"@fullcalendar/timegrid": "^5.9.0",
|
||||
"@fullcalendar/vue3": "^5.11",
|
||||
"@vue-leaflet/vue-leaflet": "*",
|
||||
"@vue/compat": "^3.2.45",
|
||||
"@vuelidate/core": "^2.0.0",
|
||||
"@vuelidate/validators": "^2.0.0",
|
||||
"@vueuse/core": "^9.6.0",
|
||||
"axios": "^1",
|
||||
"bootstrap": "^4.6.0 <5",
|
||||
"bootstrap-notify": "^3.1.3",
|
||||
|
|
|
@ -0,0 +1,61 @@
|
|||
<template>
|
||||
<div id="leaflet-container" ref="map">
|
||||
<slot v-if="$map" :map="$map"/>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<style lang="scss">
|
||||
@import 'leaflet/dist/leaflet.css';
|
||||
|
||||
.leaflet-container {
|
||||
height: 300px;
|
||||
z-index: 0;
|
||||
}
|
||||
</style>
|
||||
|
||||
<script setup>
|
||||
import {onMounted, provide, ref} from "vue";
|
||||
import L from "leaflet";
|
||||
import {get, set, templateRef} from "@vueuse/core";
|
||||
|
||||
const props = defineProps({
|
||||
attribution: String
|
||||
});
|
||||
|
||||
const $container = templateRef('map');
|
||||
const $map = ref();
|
||||
|
||||
provide('map', $map);
|
||||
|
||||
onMounted(() => {
|
||||
// Fix issue with Leaflet icons being built in Webpack
|
||||
// https://github.com/Leaflet/Leaflet/issues/4968
|
||||
delete L.Icon.Default.prototype._getIconUrl;
|
||||
L.Icon.Default.mergeOptions({
|
||||
iconRetinaUrl: require('leaflet/dist/images/marker-icon-2x.png'),
|
||||
iconUrl: require('leaflet/dist/images/marker-icon.png'),
|
||||
shadowUrl: require('leaflet/dist/images/marker-shadow.png')
|
||||
});
|
||||
|
||||
// Init map
|
||||
const map = L.map(get($container));
|
||||
map.setView([40, 0], 1);
|
||||
set($map, map);
|
||||
|
||||
// Add tile layer
|
||||
const tileUrl = 'https://cartodb-basemaps-{s}.global.ssl.fastly.net/{theme}_all/{z}/{x}/{y}.png';
|
||||
const tileAttribution = 'Map tiles by Carto, under CC BY 3.0. Data by OpenStreetMap, under ODbL.';
|
||||
|
||||
L.tileLayer(tileUrl, {
|
||||
theme: App.theme,
|
||||
attribution: tileAttribution,
|
||||
}).addTo(map);
|
||||
|
||||
/*
|
||||
// Add fullscreen control
|
||||
const fullscreenControl = new L.Control.Fullscreen();
|
||||
map.addControl(fullscreenControl)
|
||||
*/
|
||||
|
||||
});
|
||||
</script>
|
|
@ -1,63 +1,38 @@
|
|||
<template>
|
||||
<l-map v-if="mapPoints.length < 3000" style="height: 300px; z-index: 0;" :zoom="1" :center="[40, 0]">
|
||||
<l-tile-layer :url="tileUrl" :attribution="tileAttribution"></l-tile-layer>
|
||||
<l-marker v-for="l in mapPoints" :key="l.hash"
|
||||
:lat-lng="{lat: l.location.lat, lng: l.location.lon}">
|
||||
<l-tooltip>
|
||||
IP: {{ l.ip }}<br>
|
||||
Country: {{ l.location.country }}<br>
|
||||
Region: {{ l.location.region }}<br>
|
||||
City: {{ l.location.city }}<br>
|
||||
Time connected: {{ l.connected_time }}<br>
|
||||
User Agent: {{ l.user_agent }}
|
||||
</l-tooltip>
|
||||
</l-marker>
|
||||
</l-map>
|
||||
<inner-map v-if="visibleListeners.length < 3000"
|
||||
:attribution="attribution">
|
||||
<map-point v-for="l in visibleListeners" :key="l.hash"
|
||||
:position="[l.location.lat, l.location.lon]">
|
||||
<translate key="l-ip">IP</translate>
|
||||
: {{ l.ip }}<br>
|
||||
<translate key="l-country">Country</translate>
|
||||
: {{ l.location.country }}<br>
|
||||
<translate key="l-region">Region</translate>
|
||||
: {{ l.location.region }}<br>
|
||||
<translate key="l-city">City</translate>
|
||||
: {{ l.location.city }}<br>
|
||||
<translate key="l-time">Time</translate>
|
||||
: {{ l.connected_time }}<br>
|
||||
<translate key="l-ua">User Agent</translate>
|
||||
: {{ l.user_agent }}
|
||||
</map-point>
|
||||
</inner-map>
|
||||
</template>
|
||||
|
||||
<style lang="css">
|
||||
@import '../../../../../node_modules/leaflet/dist/leaflet.css';
|
||||
</style>
|
||||
<script setup>
|
||||
import InnerMap from "./InnerMap.vue";
|
||||
import MapPoint from "./MapPoint.vue";
|
||||
import {computed} from "vue";
|
||||
import _ from "lodash";
|
||||
|
||||
<script>
|
||||
import L from 'leaflet';
|
||||
import {LMap, LMarker, LTileLayer, LTooltip} from '@vue-leaflet/vue-leaflet';
|
||||
import _ from 'lodash';
|
||||
const props = defineProps({
|
||||
attribution: String,
|
||||
listeners: Array,
|
||||
});
|
||||
|
||||
export default {
|
||||
name: 'StationReportsListenersMap',
|
||||
props: {
|
||||
attribution: String,
|
||||
listeners: Array,
|
||||
},
|
||||
components: {
|
||||
LMap,
|
||||
LTileLayer,
|
||||
LMarker,
|
||||
LTooltip
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
tileUrl: 'https://cartodb-basemaps-{s}.global.ssl.fastly.net/' + App.theme + '_all/{z}/{x}/{y}.png',
|
||||
tileAttribution: 'Map tiles by Carto, under CC BY 3.0. Data by OpenStreetMap, under ODbL.',
|
||||
}
|
||||
},
|
||||
mounted() {
|
||||
// Fix issue with Leaflet icons being built in Webpack
|
||||
// https://github.com/Leaflet/Leaflet/issues/4968
|
||||
delete L.Icon.Default.prototype._getIconUrl;
|
||||
L.Icon.Default.mergeOptions({
|
||||
iconRetinaUrl: require('leaflet/dist/images/marker-icon-2x.png'),
|
||||
iconUrl: require('leaflet/dist/images/marker-icon.png'),
|
||||
shadowUrl: require('leaflet/dist/images/marker-shadow.png')
|
||||
});
|
||||
},
|
||||
computed: {
|
||||
mapPoints() {
|
||||
return _.filter(this.listeners, function (l) {
|
||||
return null !== l.location.lat && null !== l.location.lon;
|
||||
});
|
||||
}
|
||||
}
|
||||
};
|
||||
const visibleListeners = computed(() => {
|
||||
return _.filter(props.listeners, function (l) {
|
||||
return null !== l.location.lat && null !== l.location.lon;
|
||||
});
|
||||
});
|
||||
</script>
|
||||
|
|
|
@ -0,0 +1,37 @@
|
|||
<template>
|
||||
<div ref="popup-content">
|
||||
<slot/>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import {get, set, templateRef} from '@vueuse/core';
|
||||
import {inject, onUnmounted, ref, toRaw, watch} from 'vue';
|
||||
|
||||
const props = defineProps({
|
||||
position: Array
|
||||
});
|
||||
|
||||
const $map = inject('map');
|
||||
const $marker = ref();
|
||||
|
||||
const map = toRaw(get($map));
|
||||
const marker = L.marker(props.position);
|
||||
marker.addTo(map);
|
||||
set($marker, marker);
|
||||
|
||||
const popup = new L.Popup();
|
||||
const $popupContent = templateRef('popup-content');
|
||||
watch(
|
||||
$popupContent,
|
||||
(content) => {
|
||||
popup.setContent(content);
|
||||
marker.bindPopup(popup);
|
||||
},
|
||||
{immediate: true}
|
||||
);
|
||||
|
||||
onUnmounted(() => {
|
||||
get($marker).remove();
|
||||
});
|
||||
</script>
|
|
@ -0,0 +1,5 @@
|
|||
<template>
|
||||
<slot/>
|
||||
</template>
|
||||
|
||||
<script setup></script>
|
Loading…
Reference in New Issue