save current view in map to url via hash, add about pages and such

This commit is contained in:
Will Freeman
2024-09-30 23:23:10 -05:00
parent 6d8b3ba42f
commit ff0aff59f4
11 changed files with 265 additions and 64 deletions

View File

@@ -0,0 +1,17 @@
<?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 1150 300" 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;">
<g>
<text x="30.118px" y="267.042px" style="font-family:'FrizQuadrataStd', 'Friz Quadrata Std', sans-serif;font-weight:500;font-size:344.475px;fill:rgb(0,128,188);">de</text>
<g transform="matrix(344.475,0,0,344.475,409.04,267.042)">
<path d="M0.023,-0.394L0.071,-0.394L0.071,-0.11C0.071,-0.064 0.077,-0.027 0.033,-0.003L0.033,-0L0.2,-0L0.2,-0.003C0.156,-0.028 0.162,-0.064 0.162,-0.11L0.162,-0.394L0.264,-0.394C0.276,-0.394 0.291,-0.391 0.295,-0.38L0.298,-0.38L0.298,-0.46L0.162,-0.46C0.162,-0.56 0.157,-0.608 0.249,-0.608C0.278,-0.608 0.308,-0.603 0.333,-0.59L0.333,-0.11C0.333,-0.064 0.339,-0.027 0.295,-0.003L0.295,-0L0.462,-0L0.462,-0.003C0.418,-0.027 0.424,-0.064 0.424,-0.11L0.424,-0.674L0.421,-0.674C0.411,-0.663 0.394,-0.656 0.378,-0.656C0.347,-0.656 0.319,-0.674 0.266,-0.674C0.206,-0.674 0.148,-0.654 0.107,-0.608C0.068,-0.564 0.071,-0.525 0.071,-0.46L0.023,-0.394Z" style="fill:rgb(37,37,37);fill-rule:nonzero;"/>
</g>
<g transform="matrix(344.475,0,0,344.475,409.04,267.042)">
</g>
<g transform="matrix(344.475,0,0,344.475,498.604,267.042)">
</g>
<g transform="matrix(344.475,0,0,344.475,1097.99,267.042)">
</g>
<text x="581.278px" y="267.042px" style="font-family:'FrizQuadrataStd', 'Friz Quadrata Std', sans-serif;font-weight:500;font-size:344.475px;fill:rgb(37,37,37);"><tspan x="581.278px " y="267.042px ">o</tspan>ck</text>
</g>
</svg>

After

Width:  |  Height:  |  Size: 1.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 328 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 35 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 43 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 22 KiB

View File

@@ -3,7 +3,9 @@ import { RouterView } from 'vue-router'
import { ref } from 'vue'
const items = [
{ title: 'Home', icon: 'mdi-home', to: '/' },
{ title: 'Map', icon: 'mdi-map', to: '/' },
{ title: 'What is an ALPR?', icon: 'mdi-cctv', to: '/what-is-an-alpr' },
{ title: 'Report an ALPR', icon: 'mdi-map-marker-plus', to: '/report' },
{ title: 'About', icon: 'mdi-information', to: '/about' },
]
const drawer = ref(false)
@@ -18,18 +20,16 @@ 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.png" />
<v-img height="36" width="200" src="/deflock-logo.svg" />
</v-toolbar-title>
<v-spacer></v-spacer>
<template v-if="$vuetify.display.mdAndUp">
<v-btn icon="mdi-magnify" variant="text"></v-btn>
<v-btn disabled icon="mdi-magnify" variant="text"></v-btn>
<v-btn icon="mdi-filter" variant="text"></v-btn>
<v-btn disabled icon="mdi-filter" variant="text"></v-btn>
</template>
<v-btn icon="mdi-dots-vertical" variant="text"></v-btn>
</v-app-bar>
<v-navigation-drawer
@@ -42,7 +42,7 @@ const drawer = ref(false)
:key="item.title"
link
:to="item.to"
>{{ item.title }}</v-list-item>
><v-icon start>{{ item.icon }}</v-icon>{{ item.title }}</v-list-item>
</v-list>
</v-navigation-drawer>

View File

@@ -16,7 +16,17 @@ const router = createRouter({
// this generates a separate chunk (About.[hash].js) for this route
// which is lazy-loaded when the route is visited.
component: () => import('../views/AboutView.vue')
}
},
{
path: '/what-is-an-alpr',
name: 'what-is-an-alpr',
component: () => import('../views/WhatIsAnALPRView.vue')
},
{
path: '/report',
name: 'report',
component: () => import('../views/ReportView.vue')
},
]
})

View File

@@ -1,15 +1,46 @@
<template>
<div class="about">
<h1>This is an about page</h1>
</div>
<v-container>
<h2>Who are we?</h2>
<p>
We are a group of concerned citizens who want to raise awareness about the use of Automated License Plate Readers (ALPRs) in the United States. Our goal is to provide information about ALPRs, their uses, and their implications for privacy and civil liberties.
</p>
<h2>What do we want?</h2>
<p>
Donuts.
</p>
<h2>When do we want them?</h2>
<p>
Now.
</p>
</v-container>
</template>
<style>
@media (min-width: 1024px) {
.about {
min-height: 100vh;
display: flex;
align-items: center;
}
<style scoped>
/* TODO: put this all in one place, also in what-is view */
h2 {
margin-top: 2rem;
}
h3 {
margin-top: 1.25rem;
}
p {
margin-top: 0.5rem;
}
.flex-image {
display: flex;
gap: 1rem;
align-items: center;
margin-top: 0.5rem;
}
/* as you can see, this one is the most updated */
a {
color: var(green);
text-decoration: none;
}
</style>

View File

@@ -1,5 +1,9 @@
<template>
<div class="map-container">
<v-card class="map-notif" v-show="!canRefreshMarkers">
<v-card-title><b>Zoom in to Refresh ALPRs</b></v-card-title>
</v-card>
<!-- use-global-leaflet=false is a workaround for a bug in current version of vue-leaflet -->
<l-map
v-if="center"
@@ -20,7 +24,7 @@
v-for="alpr in alprsInView"
:key="alpr.id"
:lat-lng="[alpr.lat, alpr.lon]"
><l-popup>This is an ALPR! Fuck it!</l-popup></l-marker>
><l-popup>This is an ALPR! More data (such as direction) coming soon.</l-popup></l-marker>
</l-map>
<div v-else>
loading...
@@ -31,7 +35,7 @@
<script setup lang="ts">
import 'leaflet/dist/leaflet.css';
import { LMap, LTileLayer, LMarker, LPopup } from '@vue-leaflet/vue-leaflet';
import { ref, onMounted } from 'vue';
import { ref, onMounted, computed } from 'vue';
import { useRouter } from 'vue-router'
import type { Ref } from 'vue';
import type { BoundingBox } from '@/services/apiService';
@@ -42,45 +46,47 @@ const center: Ref<any|null> = ref(null);
const bounds: Ref<BoundingBox|null> = ref(null);
const router = useRouter();
const alprsInView = 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 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"
// }
// }
]);
function getUserLocation(): Promise<[number, number]> {
@@ -139,15 +145,15 @@ function updateMarkers() {
return;
}
if (zoom.value < 12) {
if (!canRefreshMarkers.value) {
console.log('zoomed out too far');
return;
}
// getALPRs(bounds.value)
// .then((alprs: any) => {
// alprsInView.value = alprs.elements;
// });
getALPRs(bounds.value)
.then((alprs: any) => {
alprsInView.value = alprs.elements;
});
}
onMounted(() => {
@@ -182,4 +188,17 @@ onMounted(() => {
height: calc(100vh - 64px);
overflow: auto;
}
.map-notif {
position: absolute;
text-align: center;
bottom: 32px;
left: 32px;
width: calc(100% - 64px);
z-index: 1000;
background-color: rgba(255, 255, 255, 0.8);
border-radius: 4px;
padding: 4px;
color: #333;
}
</style>

View File

@@ -0,0 +1,65 @@
<template>
<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:
</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>
<!-- <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>
<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>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> -->
</v-container>
</template>
<style scoped>
/* TODO: put this all in one place, also in what-is view */
h2 {
margin-top: 2rem;
}
h3 {
margin-top: 1.25rem;
}
p {
margin-top: 0.5rem;
}
.flex-image {
display: flex;
gap: 1rem;
align-items: center;
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);
}
</style>

View File

@@ -0,0 +1,59 @@
<template>
<v-container>
<p>
<v-img max-height="350" width="100%" cover src="/flock-camera.jpeg" />
</p>
<h2>What is an ALPR</h2>
<p>
An Automated License Plate Reader (ALPR) is a technology that uses cameras and image processing to automatically read vehicle license plates. These cameras can be mounted on police cars, fixed on utility poles, or even positioned on private properties, capturing images of passing vehicles. ALPR systems extract plate numbers, record the time and location of the vehicle, and often cross-reference that information with databases for law enforcement or private monitoring purposes. This data can be used for a range of reasons, from catching stolen vehicles to tracking the movement of specific cars.
</p>
<p>
The primary use of ALPRs is surveillancethey gather data that can help create a detailed record of where a vehicle has been over time. This has raised privacy concerns since the vast majority of drivers are not involved in any crime, yet their movements are being documented.
</p>
<h2>What is NOT an ALPR</h2>
<p>
Not all cameras near roads are ALPRs. Many people mistakenly assume that every traffic camera or intersection camera is an ALPR, but that's not true. Here are some things ALPRs are not:
</p>
<h3>Traffic Cameras</h3>
<div class="flex-image">
<v-img rounded cover aspect-ratio="4/3" width="180" src="/traffic-camera.jpg" />
<p>Standard traffic cameras typically capture live video or images of intersections to monitor traffic flow and manage signals. They do not specifically focus on reading license plates or storing data long-term.</p>
</div>
<h3>Red Light Cameras/Speed Cameras</h3>
<div class="flex-image">
<v-img rounded cover aspect-ratio="4/3" width="180" src="/redlight-camera.jpg" />
<p>These cameras are set up to capture violations, such as running a red light or speeding. They may record plate numbers when a violation is detected, but they do not perform continuous surveillance or collect location data over time.</p>
</div>
<h3>Security Cameras</h3>
<div class="flex-image">
<v-img rounded cover aspect-ratio="4/3" width="180" src="/security-camera.jpg" />
<p>Cameras used by businesses or homeowners for security purposes may capture vehicles incidentally, but they are not specifically designed to automatically read and record license plates.</p>
</div>
</v-container>
</template>
<style scoped>
h2 {
margin-top: 2rem;
}
h3 {
margin-top: 1.25rem;
}
p {
margin-top: 0.5rem;
}
.flex-image {
display: flex;
gap: 1rem;
align-items: center;
margin-top: 0.5rem;
}
</style>