mirror of
https://github.com/FoggedLens/deflock.git
synced 2026-05-10 19:34:51 +02:00
dockerize
This commit is contained in:
+1
-7
@@ -20,16 +20,10 @@ const drawer = ref(false)
|
||||
<v-app-bar-nav-icon variant="text" @click.stop="drawer = !drawer"></v-app-bar-nav-icon>
|
||||
|
||||
<v-toolbar-title>
|
||||
<v-img height="36" width="200" src="/deflock-logo.svg" />
|
||||
<v-img height="36" width="130" src="/deflock-logo.svg" />
|
||||
</v-toolbar-title>
|
||||
|
||||
<v-spacer></v-spacer>
|
||||
|
||||
<template v-if="$vuetify.display.mdAndUp">
|
||||
<v-btn disabled icon="mdi-magnify" variant="text"></v-btn>
|
||||
|
||||
<v-btn disabled icon="mdi-filter" variant="text"></v-btn>
|
||||
</template>
|
||||
</v-app-bar>
|
||||
|
||||
<v-navigation-drawer
|
||||
|
||||
@@ -0,0 +1,9 @@
|
||||
a {
|
||||
font-weight: bold;
|
||||
color: rgb(18, 151, 195);
|
||||
text-decoration: none;
|
||||
}
|
||||
|
||||
a:hover {
|
||||
text-decoration: underline;
|
||||
}
|
||||
|
||||
@@ -0,0 +1,39 @@
|
||||
<template>
|
||||
<div style="position: relative">
|
||||
<v-btn @click="copyToClipboard" variant="plain" flat class="copy-button">
|
||||
<v-icon>mdi-content-copy</v-icon>
|
||||
</v-btn>
|
||||
<code ref="codeContent">
|
||||
<slot></slot>
|
||||
</code>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { ref } from 'vue';
|
||||
|
||||
const codeContent = ref<HTMLElement | null>(null);
|
||||
|
||||
function copyToClipboard() {
|
||||
if (codeContent.value) {
|
||||
navigator.clipboard.writeText(codeContent.value.innerText);
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
code {
|
||||
background-color: #f4f4f4;
|
||||
padding: 0.5rem;
|
||||
border-radius: 0.25rem;
|
||||
display: block;
|
||||
margin-top: 0.5rem;
|
||||
}
|
||||
|
||||
.copy-button {
|
||||
position: absolute;
|
||||
right: 0;
|
||||
top: 0;
|
||||
z-index: 1000;
|
||||
}
|
||||
</style>
|
||||
@@ -1,14 +1,44 @@
|
||||
import axios from "axios";
|
||||
|
||||
export interface BoundingBox {
|
||||
export interface BoundingBoxLiteral {
|
||||
minLat: number;
|
||||
maxLat: number;
|
||||
minLng: number;
|
||||
maxLng: number;
|
||||
}
|
||||
|
||||
export class BoundingBox implements BoundingBoxLiteral {
|
||||
minLat: number;
|
||||
maxLat: number;
|
||||
minLng: number;
|
||||
maxLng: number;
|
||||
|
||||
constructor({minLat, maxLat, minLng, maxLng}: BoundingBoxLiteral) {
|
||||
this.minLat = minLat;
|
||||
this.maxLat = maxLat;
|
||||
this.minLng = minLng;
|
||||
this.maxLng = maxLng;
|
||||
}
|
||||
|
||||
updateFromOther(boundingBoxLiteral: BoundingBoxLiteral) {
|
||||
this.minLat = boundingBoxLiteral.minLat;
|
||||
this.maxLat = boundingBoxLiteral.maxLat;
|
||||
this.minLng = boundingBoxLiteral.minLng;
|
||||
this.maxLng = boundingBoxLiteral.maxLng;
|
||||
}
|
||||
|
||||
isSubsetOf(other: BoundingBoxLiteral) {
|
||||
return (
|
||||
this.minLat >= other.minLat &&
|
||||
this.maxLat <= other.maxLat &&
|
||||
this.minLng >= other.minLng &&
|
||||
this.maxLng <= other.maxLng
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
const apiService = axios.create({
|
||||
baseURL: "http://localhost:8080",
|
||||
baseURL: window.location.hostname === "localhost" ? "http://localhost:8080/api" : "/api",
|
||||
headers: {
|
||||
"Content-Type": "application/json",
|
||||
},
|
||||
|
||||
@@ -20,11 +20,14 @@
|
||||
name="OpenStreetMap"
|
||||
></l-tile-layer>
|
||||
<l-marker
|
||||
@click="console.log('marker clicked')"
|
||||
v-for="alpr in alprsInView"
|
||||
:key="alpr.id"
|
||||
:lat-lng="[alpr.lat, alpr.lon]"
|
||||
><l-popup>This is an ALPR! More data (such as direction) coming soon.</l-popup></l-marker>
|
||||
><l-popup>
|
||||
<h2>ALPR</h2>
|
||||
<p v-if="alpr.tags.brand || alpr.tags.operator"><strong>Brand: </strong><a target="_blank" :href="`https://www.wikidata.org/wiki/${alpr.tags['brand:wikidata'] || alpr.tags['operator:wikidata']}`">{{ alpr.tags.brand || alpr.tags.operator || 'Unknown' }}</a></p>
|
||||
<p v-if="alpr.tags.direction"><strong>Faces: {{ degreesToCardinal(alpr.tags.direction) }}</strong></p>
|
||||
</l-popup></l-marker>
|
||||
</l-map>
|
||||
<div v-else>
|
||||
loading...
|
||||
@@ -38,7 +41,7 @@ import { LMap, LTileLayer, LMarker, LPopup } from '@vue-leaflet/vue-leaflet';
|
||||
import { ref, onMounted, computed } from 'vue';
|
||||
import { useRouter } from 'vue-router'
|
||||
import type { Ref } from 'vue';
|
||||
import type { BoundingBox } from '@/services/apiService';
|
||||
import { BoundingBox } from '@/services/apiService';
|
||||
import { getALPRs } from '@/services/apiService';
|
||||
|
||||
const zoom: Ref<number> = ref(12);
|
||||
@@ -48,46 +51,8 @@ const router = useRouter();
|
||||
|
||||
const canRefreshMarkers = computed(() => zoom.value >= 10);
|
||||
|
||||
const alprsInView: Ref<any[]> = ref([
|
||||
// {
|
||||
// "type": "node",
|
||||
// "id": 12187369976,
|
||||
// "lat": 34.6616103,
|
||||
// "lon": -86.4870137,
|
||||
// "tags": {
|
||||
// "brand": "Flock Safety",
|
||||
// "brand:wikidata": "Q108485435",
|
||||
// "camera:mount": "pole",
|
||||
// "camera:type": "fixed",
|
||||
// "direction": "335",
|
||||
// "man_made": "surveillance",
|
||||
// "operator": "Flock Safety",
|
||||
// "operator:wikidata": "Q108485435",
|
||||
// "surveillance": "traffic",
|
||||
// "surveillance:type": "ALPR",
|
||||
// "surveillance:zone": "traffic"
|
||||
// }
|
||||
// },
|
||||
// {
|
||||
// "type": "node",
|
||||
// "id": 12187369977,
|
||||
// "lat": 34.6615727,
|
||||
// "lon": -86.4881948,
|
||||
// "tags": {
|
||||
// "brand": "Flock Safety",
|
||||
// "brand:wikidata": "Q108485435",
|
||||
// "camera:mount": "pole",
|
||||
// "camera:type": "fixed",
|
||||
// "direction": "295",
|
||||
// "man_made": "surveillance",
|
||||
// "operator": "Flock Safety",
|
||||
// "operator:wikidata": "Q108485435",
|
||||
// "surveillance": "traffic",
|
||||
// "surveillance:type": "ALPR",
|
||||
// "surveillance:zone": "traffic"
|
||||
// }
|
||||
// }
|
||||
]);
|
||||
const alprsInView: Ref<any[]> = ref([]);
|
||||
const bboxForLastRequest: Ref<BoundingBox|null> = ref(null);
|
||||
|
||||
function getUserLocation(): Promise<[number, number]> {
|
||||
return new Promise((resolve, reject) => {
|
||||
@@ -115,18 +80,22 @@ function mapLoaded(map: any) {
|
||||
}
|
||||
|
||||
function updateBounds(newBounds: any) {
|
||||
bounds.value = {
|
||||
updateURL();
|
||||
|
||||
const newBoundingBox = new BoundingBox({
|
||||
minLat: newBounds.getSouth(),
|
||||
maxLat: newBounds.getNorth(),
|
||||
minLng: newBounds.getWest(),
|
||||
maxLng: newBounds.getEast(),
|
||||
};
|
||||
});
|
||||
bounds.value = newBoundingBox;
|
||||
|
||||
if (bboxForLastRequest.value && newBoundingBox.isSubsetOf(bboxForLastRequest.value)) {
|
||||
console.debug('new bounds are a subset of the last request, skipping');
|
||||
return;
|
||||
}
|
||||
|
||||
updateMarkers();
|
||||
|
||||
if (center.value) {
|
||||
updateURL();
|
||||
}
|
||||
}
|
||||
|
||||
function updateURL() {
|
||||
@@ -153,14 +122,19 @@ function updateMarkers() {
|
||||
getALPRs(bounds.value)
|
||||
.then((alprs: any) => {
|
||||
alprsInView.value = alprs.elements;
|
||||
bboxForLastRequest.value = bounds.value;
|
||||
});
|
||||
}
|
||||
|
||||
function degreesToCardinal(degrees: number): string {
|
||||
const cardinals = ['N', 'NE', 'E', 'SE', 'S', 'SW', 'W', 'NW'];
|
||||
return cardinals[Math.round(degrees / 45) % 8];
|
||||
}
|
||||
|
||||
onMounted(() => {
|
||||
const hash = router.currentRoute.value.hash;
|
||||
if (hash) {
|
||||
const parts = hash.split('/');
|
||||
console.log('parts', parts);
|
||||
if (parts.length === 3 && parts[0].startsWith('#map')) {
|
||||
const zoomLevelString = parts[0].replace('#map=', '');
|
||||
zoom.value = parseInt(zoomLevelString, 10);
|
||||
@@ -168,8 +142,6 @@ onMounted(() => {
|
||||
lat: parseFloat(parts[1]),
|
||||
lng: parseFloat(parts[2]),
|
||||
};
|
||||
console.log('center', center.value);
|
||||
console.log('zoom', zoom.value);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -196,9 +168,9 @@ onMounted(() => {
|
||||
left: 32px;
|
||||
width: calc(100% - 64px);
|
||||
z-index: 1000;
|
||||
background-color: rgba(255, 255, 255, 0.8);
|
||||
background-color: rgba(0, 0, 0, 0.8);
|
||||
border-radius: 4px;
|
||||
padding: 4px;
|
||||
color: #333;
|
||||
color: #eee;
|
||||
}
|
||||
</style>
|
||||
|
||||
@@ -2,33 +2,85 @@
|
||||
<v-container>
|
||||
<h2>How to Report an ALPR</h2>
|
||||
<p>
|
||||
If you've spotted an ALPR in your area, you can help us track it by reporting it to our database. Here's how you can do it:
|
||||
If you've spotted an ALPR in your area, you can help us track it by reporting it to OpenStreetMap, where we source our information. Here's how you can do it:
|
||||
</p>
|
||||
|
||||
<h3>Coming Soon</h3>
|
||||
<p>
|
||||
We're working on a way for you to report ALPRs directly from this site. Check back soon for updates!
|
||||
</p>
|
||||
<p>
|
||||
Until then, you can report them on OpenStreetMap. <a href="https://wiki.openstreetmap.org/wiki/Tag:man_made%3Dsurveillance" target="_blank">Learn how to add ALPRs to OpenStreetMap</a>.
|
||||
</p>
|
||||
<v-alert
|
||||
variant="tonal"
|
||||
type="warning"
|
||||
class="my-6"
|
||||
title="Are you sure it's an ALPR?"
|
||||
>
|
||||
<p>
|
||||
Before you report an ALPR, please read our <router-link style="color: unset !important" to="/what-is-an-alpr">guide on what ALPRs look like</router-link> to make sure you're reporting the right thing.
|
||||
</p>
|
||||
</v-alert>
|
||||
|
||||
<!-- <p>
|
||||
If you can do so safely, take a picture of the ALPR camera. Make sure the camera is visible in the image, and try to capture any identifying information, such as the brand name or any logos.
|
||||
</p>
|
||||
<div class="ml-4 mt-4">
|
||||
<h3>1. Create an OpenStreetMap Account</h3>
|
||||
<p>
|
||||
<a href="https://www.openstreetmap.org/user/new" target="_blank">Sign up for an OpenStreetMap account</a> in order to submit changes.
|
||||
</p>
|
||||
|
||||
<h3>Step 2: Note the Location</h3>
|
||||
<p>
|
||||
Record the location of the ALPR camera. You can use your phone's GPS to get the coordinates, or note the nearest address or intersection.
|
||||
</p>
|
||||
<h3>2. Find the ALPR's Location on OpenStreetMap</h3>
|
||||
<p>
|
||||
<a href="https://www.openstreetmap.org" target="_blank">Launch OpenStreetMap</a> and search for the location of the ALPR. You can use the search bar at the top of the page to find the location.
|
||||
</p>
|
||||
|
||||
<h3>Step 3: Submit the Report</h3>
|
||||
<p>
|
||||
Click the "Report" button below to submit your report. You'll be asked to upload the picture you took and provide the location information. Your report will help us build a more comprehensive database of ALPRs in the United States.
|
||||
</p> -->
|
||||
<h3>3. Add the ALPR to OpenStreetMap</h3>
|
||||
<p>
|
||||
Once you've found the location of the ALPR, click the <strong>Edit</strong> button in the top left corner of the page. This will open the OpenStreetMap editor, where you can add the ALPR to the map.
|
||||
</p>
|
||||
|
||||
<v-img src="/edit-map.png" />
|
||||
|
||||
<p>
|
||||
To add the ALPR, click the <strong>Point</strong> button in the top left corner of the editor, then click on the location of the ALPR on the map. In the popup that appears, paste the following tags:
|
||||
</p>
|
||||
|
||||
<DFCode>
|
||||
man_made=surveillance<br>
|
||||
surveillance:type=ALPR<br>
|
||||
camera:mount=pole<br>
|
||||
camera:type=fixed<br>
|
||||
surveillance=traffic<br>
|
||||
surveillance:zone=traffic<br>
|
||||
</DFCode>
|
||||
|
||||
<v-img class="my-4" src="/paste-tags.png" />
|
||||
|
||||
<p>
|
||||
If you've identified the brand of the ALPR as Flock Safety, then you can also add the following tags:
|
||||
</p>
|
||||
<DFCode>
|
||||
operator=Flock Safety<br>
|
||||
operator:wikidata=Q108485435<br>
|
||||
brand=Flock Safety<br>
|
||||
brand:wikidata=Q108485435<br>
|
||||
</DFCode>
|
||||
|
||||
<h3>4. Adjust the Direction</h3>
|
||||
|
||||
<v-img src="/adjust-angle.png" />
|
||||
|
||||
<p>
|
||||
If you know the direction that the ALPR is facing, you can use the up and down arrows to set the direction it faces.
|
||||
</p>
|
||||
|
||||
<h3>5. Submit Your Changes</h3>
|
||||
<p>
|
||||
Once you've added the ALPR to the map, click the <strong>Save</strong> button in the top left corner of the editor. You'll be asked to provide a brief description of your changes. Once you've submitted your changes, the ALPR will be added to OpenStreetMap.
|
||||
</p>
|
||||
|
||||
</div>
|
||||
</v-container>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import DFCode from '@/components/DFCode.vue';
|
||||
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
/* TODO: put this all in one place, also in what-is view */
|
||||
h2 {
|
||||
@@ -50,16 +102,11 @@ p {
|
||||
margin-top: 0.5rem;
|
||||
}
|
||||
|
||||
a {
|
||||
color: var(--v-primary-base);
|
||||
text-decoration: none;
|
||||
}
|
||||
|
||||
a:hover {
|
||||
text-decoration: underline;
|
||||
}
|
||||
|
||||
a:visited {
|
||||
color: var(--v-primary-base);
|
||||
code {
|
||||
background-color: #f4f4f4;
|
||||
padding: 0.5rem;
|
||||
border-radius: 0.25rem;
|
||||
display: block;
|
||||
margin-top: 0.5rem;
|
||||
}
|
||||
</style>
|
||||
|
||||
Reference in New Issue
Block a user