mirror of
https://github.com/FoggedLens/deflock.git
synced 2026-02-12 15:02:45 +00:00
better map markers
This commit is contained in:
50
webapp/package-lock.json
generated
50
webapp/package-lock.json
generated
@@ -17,6 +17,7 @@
|
||||
"devDependencies": {
|
||||
"@mdi/font": "^7.4.47",
|
||||
"@tsconfig/node20": "^20.1.4",
|
||||
"@types/leaflet": "^1.9.15",
|
||||
"@types/node": "^20.14.5",
|
||||
"@vitejs/plugin-vue": "^5.0.5",
|
||||
"@vue-leaflet/vue-leaflet": "^0.10.1",
|
||||
@@ -25,6 +26,7 @@
|
||||
"npm-run-all2": "^6.2.0",
|
||||
"typescript": "~5.4.0",
|
||||
"vite": "^5.3.1",
|
||||
"vue-leaflet-rotate-marker": "^0.1.0",
|
||||
"vue-tsc": "^2.0.21"
|
||||
}
|
||||
},
|
||||
@@ -669,6 +671,21 @@
|
||||
"integrity": "sha512-/kYRxGDLWzHOB7q+wtSUQlFrtcdUccpfy+X+9iMBpHK8QLLhx2wIPYuS5DYtR9Wa/YlZAbIovy7qVdB1Aq6Lyw==",
|
||||
"dev": true
|
||||
},
|
||||
"node_modules/@types/geojson": {
|
||||
"version": "7946.0.15",
|
||||
"resolved": "https://registry.npmjs.org/@types/geojson/-/geojson-7946.0.15.tgz",
|
||||
"integrity": "sha512-9oSxFzDCT2Rj6DfcHF8G++jxBKS7mBqXl5xrRW+Kbvjry6Uduya2iiwqHPhVXpasAVMBYKkEPGgKhd3+/HZ6xA==",
|
||||
"dev": true
|
||||
},
|
||||
"node_modules/@types/leaflet": {
|
||||
"version": "1.9.15",
|
||||
"resolved": "https://registry.npmjs.org/@types/leaflet/-/leaflet-1.9.15.tgz",
|
||||
"integrity": "sha512-7UuggAuAs+mva66gtf2OTB1nEhzU/9JED93TIaOEgvFMvG/dIGQaukHE7izHo1Zd+Ko1L4ETUw7TBc8yUxevpg==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"@types/geojson": "*"
|
||||
}
|
||||
},
|
||||
"node_modules/@types/node": {
|
||||
"version": "20.16.6",
|
||||
"resolved": "https://registry.npmjs.org/@types/node/-/node-20.16.6.tgz",
|
||||
@@ -1472,6 +1489,15 @@
|
||||
}
|
||||
}
|
||||
},
|
||||
"node_modules/vue-leaflet-rotate-marker": {
|
||||
"version": "0.1.0",
|
||||
"resolved": "https://registry.npmjs.org/vue-leaflet-rotate-marker/-/vue-leaflet-rotate-marker-0.1.0.tgz",
|
||||
"integrity": "sha512-qBrb/ydvl+cuQSZ3cinH2G0nmFNglh5h9qVIFRAlrcjCNqZE1RIEHxwjvxA0CCxdlNFxGeeZy0RFrkdSqNToeg==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"vue": "^3.3.4"
|
||||
}
|
||||
},
|
||||
"node_modules/vue-router": {
|
||||
"version": "4.4.5",
|
||||
"resolved": "https://registry.npmjs.org/vue-router/-/vue-router-4.4.5.tgz",
|
||||
@@ -1872,6 +1898,21 @@
|
||||
"integrity": "sha512-/kYRxGDLWzHOB7q+wtSUQlFrtcdUccpfy+X+9iMBpHK8QLLhx2wIPYuS5DYtR9Wa/YlZAbIovy7qVdB1Aq6Lyw==",
|
||||
"dev": true
|
||||
},
|
||||
"@types/geojson": {
|
||||
"version": "7946.0.15",
|
||||
"resolved": "https://registry.npmjs.org/@types/geojson/-/geojson-7946.0.15.tgz",
|
||||
"integrity": "sha512-9oSxFzDCT2Rj6DfcHF8G++jxBKS7mBqXl5xrRW+Kbvjry6Uduya2iiwqHPhVXpasAVMBYKkEPGgKhd3+/HZ6xA==",
|
||||
"dev": true
|
||||
},
|
||||
"@types/leaflet": {
|
||||
"version": "1.9.15",
|
||||
"resolved": "https://registry.npmjs.org/@types/leaflet/-/leaflet-1.9.15.tgz",
|
||||
"integrity": "sha512-7UuggAuAs+mva66gtf2OTB1nEhzU/9JED93TIaOEgvFMvG/dIGQaukHE7izHo1Zd+Ko1L4ETUw7TBc8yUxevpg==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"@types/geojson": "*"
|
||||
}
|
||||
},
|
||||
"@types/node": {
|
||||
"version": "20.16.6",
|
||||
"resolved": "https://registry.npmjs.org/@types/node/-/node-20.16.6.tgz",
|
||||
@@ -2433,6 +2474,15 @@
|
||||
"@vue/shared": "3.5.8"
|
||||
}
|
||||
},
|
||||
"vue-leaflet-rotate-marker": {
|
||||
"version": "0.1.0",
|
||||
"resolved": "https://registry.npmjs.org/vue-leaflet-rotate-marker/-/vue-leaflet-rotate-marker-0.1.0.tgz",
|
||||
"integrity": "sha512-qBrb/ydvl+cuQSZ3cinH2G0nmFNglh5h9qVIFRAlrcjCNqZE1RIEHxwjvxA0CCxdlNFxGeeZy0RFrkdSqNToeg==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"vue": "^3.3.4"
|
||||
}
|
||||
},
|
||||
"vue-router": {
|
||||
"version": "4.4.5",
|
||||
"resolved": "https://registry.npmjs.org/vue-router/-/vue-router-4.4.5.tgz",
|
||||
|
||||
@@ -20,6 +20,7 @@
|
||||
"devDependencies": {
|
||||
"@mdi/font": "^7.4.47",
|
||||
"@tsconfig/node20": "^20.1.4",
|
||||
"@types/leaflet": "^1.9.15",
|
||||
"@types/node": "^20.14.5",
|
||||
"@vitejs/plugin-vue": "^5.0.5",
|
||||
"@vue-leaflet/vue-leaflet": "^0.10.1",
|
||||
@@ -28,6 +29,7 @@
|
||||
"npm-run-all2": "^6.2.0",
|
||||
"typescript": "~5.4.0",
|
||||
"vite": "^5.3.1",
|
||||
"vue-leaflet-rotate-marker": "^0.1.0",
|
||||
"vue-tsc": "^2.0.21"
|
||||
}
|
||||
}
|
||||
|
||||
10
webapp/public/map-icon.svg
Normal file
10
webapp/public/map-icon.svg
Normal file
@@ -0,0 +1,10 @@
|
||||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
|
||||
<svg width="100%" height="100%" viewBox="0 0 512 512" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" xml:space="preserve" xmlns:serif="http://www.serif.com/" style="fill-rule:evenodd;clip-rule:evenodd;stroke-linejoin:round;stroke-miterlimit:2;">
|
||||
<path d="M215.248,221.461L99.696,43.732C144.935,16.031 198.536,0 256,0C313.464,0 367.065,16.031 412.304,43.732L296.752,221.461C287.138,209.593 272.448,202.001 256,202.001C239.552,202.001 224.862,209.593 215.248,221.461Z" style="fill:rgb(87,87,87);fill-opacity:0.46;"/>
|
||||
<path d="M215.248,221.461L99.696,43.732C144.935,16.031 198.536,0 256,0C313.464,0 367.065,16.031 412.304,43.732L296.752,221.461C287.138,209.593 272.448,202.001 256,202.001C239.552,202.001 224.862,209.593 215.248,221.461ZM217.92,200.242C228.694,192.652 241.831,188.195 256,188.195C270.169,188.195 283.306,192.652 294.08,200.242C294.08,200.242 392.803,48.4 392.803,48.4C352.363,26.364 305.694,13.806 256,13.806C206.306,13.806 159.637,26.364 119.197,48.4L217.92,200.242Z" style="fill:rgb(137,135,135);"/>
|
||||
<g transform="matrix(0.906623,0,0,0.906623,23.9045,22.3271)">
|
||||
<circle cx="256" cy="256" r="57.821" style="fill:rgb(63,84,243);fill-opacity:0.41;"/>
|
||||
<path d="M256,174.25C301.119,174.25 337.75,210.881 337.75,256C337.75,301.119 301.119,337.75 256,337.75C210.881,337.75 174.25,301.119 174.25,256C174.25,210.881 210.881,174.25 256,174.25ZM256,198.179C224.088,198.179 198.179,224.088 198.179,256C198.179,287.912 224.088,313.821 256,313.821C287.912,313.821 313.821,287.912 313.821,256C313.821,224.088 287.912,198.179 256,198.179Z" style="fill:rgb(63,84,243);"/>
|
||||
</g>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 1.8 KiB |
@@ -1,28 +1,25 @@
|
||||
<template>
|
||||
<l-circle-marker :lat-lng="[alpr.lat, alpr.lon]" :radius="7" :color="markerColor">
|
||||
<l-marker-rotate v-if="showFov && hasDirection" :lat-lng="[alpr.lat, alpr.lon]" rotationOrigin="center center" :rotationAngle>
|
||||
<l-popup>
|
||||
<DFMapPopup :alpr="alpr" />
|
||||
</l-popup>
|
||||
<l-icon :icon-url :icon-size :icon-anchor />
|
||||
</l-marker-rotate>
|
||||
<l-circle-marker v-else :lat-lng="[alpr.lat, alpr.lon]" :radius="7" color="#3f54f3">
|
||||
<l-popup>
|
||||
<DFMapPopup :alpr="alpr" />
|
||||
</l-popup>
|
||||
</l-circle-marker>
|
||||
|
||||
<l-polygon
|
||||
:lat-lngs="directionIndicatorPolygonCoordinates"
|
||||
:options="{ color: 'red' }"
|
||||
v-if="showFov && hasDirection"
|
||||
>
|
||||
<!-- TODO: use the same popup -->
|
||||
<l-popup>
|
||||
<DFMapPopup :alpr="alpr" />
|
||||
</l-popup>
|
||||
</l-polygon>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { LCircleMarker, LPolygon, LPopup } from '@vue-leaflet/vue-leaflet';
|
||||
import { LIcon, LPopup, LCircleMarker } from '@vue-leaflet/vue-leaflet';
|
||||
import { LMarkerRotate } from 'vue-leaflet-rotate-marker';
|
||||
import DFMapPopup from '@/components/DFMapPopup.vue';
|
||||
import type { ALPR } from '@/types';
|
||||
import type { PropType } from 'vue';
|
||||
import { computed, defineProps } from 'vue';
|
||||
import { type PointExpression } from 'leaflet';
|
||||
|
||||
const props = defineProps({
|
||||
alpr: {
|
||||
@@ -35,41 +32,9 @@ const props = defineProps({
|
||||
}
|
||||
});
|
||||
|
||||
const markerColor = computed(() => {
|
||||
if (props.alpr.tags.brand === 'Avigilon') {
|
||||
return '#ff5722';
|
||||
}
|
||||
return '#3f54f3';
|
||||
});
|
||||
|
||||
const iconSize: PointExpression = [60, 60];
|
||||
const iconAnchor: PointExpression = [30, 30];
|
||||
const hasDirection = computed(() => props.alpr.tags.direction !== undefined);
|
||||
|
||||
const directionIndicatorPolygonCoordinates = computed(() => {
|
||||
if (!hasDirection.value) {
|
||||
console.warn('ALPR does not have direction tag');
|
||||
return [];
|
||||
}
|
||||
const { lat, lon } = props.alpr;
|
||||
const direction = parseInt(props.alpr.tags.direction);
|
||||
const fov = 30; // Field of view in degrees
|
||||
const distance = 0.0004; // Distance for the triangle points
|
||||
|
||||
const toRadians = (degrees: number) => degrees * (Math.PI / 180);
|
||||
|
||||
const pointL = {
|
||||
lat: lat + distance * Math.cos(toRadians(direction - fov / 2)),
|
||||
lon: lon + distance * Math.sin(toRadians(direction - fov / 2))
|
||||
};
|
||||
|
||||
const pointR = {
|
||||
lat: lat + distance * Math.cos(toRadians(direction + fov / 2)),
|
||||
lon: lon + distance * Math.sin(toRadians(direction + fov / 2))
|
||||
};
|
||||
|
||||
return [
|
||||
[lat, lon],
|
||||
[pointL.lat, pointL.lon],
|
||||
[pointR.lat, pointR.lon]
|
||||
];
|
||||
});
|
||||
const rotationAngle = computed(() => parseInt(props.alpr.tags.direction) || undefined);
|
||||
const iconUrl = computed(() => props.showFov ? `/map-icon.svg` : '/map-icon-simple.svg');
|
||||
</script>
|
||||
|
||||
@@ -5,13 +5,13 @@
|
||||
<v-icon start>mdi-face-recognition</v-icon> <b>Face Recognition</b>
|
||||
</v-list-item>
|
||||
<v-list-item>
|
||||
<v-icon start>mdi-car</v-icon> <b>License Plate</b>
|
||||
<v-icon start>mdi-cctv</v-icon> <b>License Plate Reader</b>
|
||||
</v-list-item>
|
||||
<v-list-item v-if="isFaceRecognition">
|
||||
<v-icon start>mdi-adjust</v-icon> <b>Omnidirectional</b>
|
||||
</v-list-item>
|
||||
<v-list-item v-else>
|
||||
<v-icon start>mdi-cctv</v-icon> <b>Directional {{ alpr.tags.direction ? `(${degreesToCardinal(parseInt(alpr.tags.direction))})` : '' }}</b>
|
||||
<v-icon start>mdi-compass-outline</v-icon> <b>{{ cardinalDirection }}</b>
|
||||
</v-list-item>
|
||||
<v-list-item>
|
||||
<v-icon start>mdi-domain</v-icon> <b>
|
||||
@@ -75,6 +75,10 @@ const kvTags = computed(() => {
|
||||
.map(([key, value]) => ({ key, value: valueTransformations[key]?.(value) ?? value }));
|
||||
});
|
||||
|
||||
const cardinalDirection = computed(() =>
|
||||
props.alpr.tags.direction === undefined ? 'Unknown' : degreesToCardinal(parseInt(props.alpr.tags.direction))
|
||||
);
|
||||
|
||||
function degreesToCardinal(degrees: number): string {
|
||||
const cardinals = ['North', 'Northeast', 'East', 'Southeast', 'South', 'Southwest', 'West', 'Northwest'];
|
||||
return cardinals[Math.round(degrees / 45) % 8];
|
||||
|
||||
Reference in New Issue
Block a user