Porównaj commity

...

4 Commity

Autor SHA1 Wiadomość Data
Anthony Catel 1b8e97ed82 Fix searchbox css 2022-03-30 12:08:14 +02:00
Anthony Catel 018168af8d Map: add comments 2022-03-30 11:17:30 +02:00
Anthony Catel ba573ed2fd Add support for compressed URL 2022-03-30 10:28:20 +02:00
Anthony Catel 633033b4d1 Various type fix 2022-03-30 09:33:56 +02:00
3 zmienionych plików z 93 dodań i 16 usunięć

Wyświetl plik

@ -10,6 +10,7 @@
"@types/google.maps": "^3.48.3", "@types/google.maps": "^3.48.3",
"@vitejs/plugin-vue": "^2.2.4", "@vitejs/plugin-vue": "^2.2.4",
"@vueuse/core": "^8.2.0", "@vueuse/core": "^8.2.0",
"fflate": "^0.7.3",
"js-base64": "^3.5.2", "js-base64": "^3.5.2",
"tailwindcss": "^3.0.23", "tailwindcss": "^3.0.23",
"tatween": "^0.2.0", "tatween": "^0.2.0",

Wyświetl plik

@ -1,7 +1,7 @@
<template> <template>
<div class="w-full h-full"> <div class="w-full h-full">
<input ref="pacinput" class="controls" :class="[mapLoaded ? '' : 'hidden']" type="text" placeholder="Search Box"> <input ref="pacinput" id="pac-input" class="controls" :class="[mapLoaded ? '' : 'hidden']" type="text" placeholder="Search Box">
<div class="w-full h-full" id="map"></div> <div class="w-full h-full" ref="mapel"></div>
</div> </div>
</template> </template>
@ -10,7 +10,7 @@
import { Base64 } from 'js-base64' import { Base64 } from 'js-base64'
import { onMounted, ref, watch, computed } from 'vue'; import { onMounted, ref, watch, computed } from 'vue';
import { watchDebounced } from '@vueuse/core' import { watchDebounced } from '@vueuse/core'
import { zlibSync, unzlibSync } from 'fflate';
const DEFAULT_MAP_POSITION = [48.862895, 2.286978, 18] const DEFAULT_MAP_POSITION = [48.862895, 2.286978, 18]
@ -35,9 +35,10 @@
const arrPoly = ref<google.maps.LatLng[]>([]) const arrPoly = ref<google.maps.LatLng[]>([])
const mapLoaded = ref(false); const mapLoaded = ref(false);
const pacinput = ref() const pacinput = ref()
const mapel = ref()
let currentMap : google.maps.Map | undefined; let currentMap : google.maps.Map;
let currentPolygon : google.maps.Polygon | undefined; let currentPolygon : google.maps.Polygon;
onMounted(() => { onMounted(() => {
loader.loadCallback(e => { loader.loadCallback(e => {
@ -46,7 +47,7 @@
return; return;
} }
currentMap = new google.maps.Map(document.getElementById("map"), { currentMap = new google.maps.Map(mapel.value, {
zoom: mapPosition.value[2], zoom: mapPosition.value[2],
center: { center: {
lat: mapPosition.value[0], lat: mapPosition.value[0],
@ -62,20 +63,23 @@
searchBox.addListener('places_changed', () => { searchBox.addListener('places_changed', () => {
const places = searchBox.getPlaces(); const places = searchBox.getPlaces();
if (places.length == 0) { if (!places || places.length == 0) {
return; return;
} }
const place = places[0]; const place = places[0];
currentMap.setCenter(place.geometry.location); if (place.geometry?.location) {
currentMap.setCenter(place.geometry.location);
}
currentMap.setZoom(17); currentMap.setZoom(17);
reset(); reset();
}); });
currentMap.addListener('bounds_changed', function() { currentMap.addListener('bounds_changed', function() {
searchBox.setBounds(currentMap.getBounds()); searchBox.setBounds(currentMap.getBounds()!);
}); });
currentMap.addListener('center_changed', mapUpdated); currentMap.addListener('center_changed', mapUpdated);
currentMap.addListener('zoom_changed', mapUpdated); currentMap.addListener('zoom_changed', mapUpdated);
@ -107,13 +111,21 @@
["insert_at", "remove_at", "set_at"].forEach(ev => google.maps.event.addListener(poly.getPath(), ev, surfaceUpdated)); ["insert_at", "remove_at", "set_at"].forEach(ev => google.maps.event.addListener(poly.getPath(), ev, surfaceUpdated));
updatePolygonColor(); updatePolygonColor();
mapLoaded.value = true; mapLoaded.value = true;
}); });
}) })
/*
Get the polygon color from the density value.
This is a simple linear interpolation between
green and red on the Hue space.
*/
const getHue = (val: number) => { const getHue = (val: number) => {
const min = 0.1; const min = 0.1;
/*
Clamp "max density" because any value
above 3.0 should be considered "red"
*/
const max = 3.0; const max = 3.0;
// inv lerp from the density // inv lerp from the density
@ -138,9 +150,17 @@
const pos = currentMap.getCenter(); const pos = currentMap.getCenter();
const zoom = currentMap.getZoom(); const zoom = currentMap.getZoom();
if (!pos || !zoom) {
return;
}
mapPosition.value = [pos.lat(), pos.lng(), zoom]; mapPosition.value = [pos.lat(), pos.lng(), zoom];
} }
/*
Add a new point to our polygon
using the lat/lng position clicked on the map.
*/
const mapClicked = (ev: any) => { const mapClicked = (ev: any) => {
currentPolygon.getPath().push(ev.latLng); currentPolygon.getPath().push(ev.latLng);
} }
@ -148,6 +168,10 @@
const surfaceUpdated = () => { const surfaceUpdated = () => {
arrPoly.value = currentPolygon.getPath().getArray().slice(); arrPoly.value = currentPolygon.getPath().getArray().slice();
/*
Compute the surface area of our polygon.
google.maps.geometry.spherical.computeArea() returns the area in square meters
*/
emits('surfaceUpdate', google.maps.geometry.spherical.computeArea(currentPolygon.getPath())); emits('surfaceUpdate', google.maps.geometry.spherical.computeArea(currentPolygon.getPath()));
} }
@ -159,23 +183,34 @@
updatePolygonColor(); updatePolygonColor();
} }
/*
Deserialize out URL hash
*/
const loadHash = (hash: string) => { const loadHash = (hash: string) => {
if (hash[0] != 'b') { if (hash[0] != 'b' && hash[0] != 'c') {
return loadLegacyHash(hash); return loadLegacyHash(hash);
} }
const buf = Base64.toUint8Array(hash.substr(1)); const isCompressed = hash[0] == 'c';
let buf = Base64.toUint8Array(hash.substr(1));
if (!buf) { if (!buf) {
return; return;
} }
if (isCompressed) {
buf = unzlibSync(buf)
}
/* Extract meta data (density, position & zoom) */
const meta = new Float32Array(buf.buffer, 0, 4); const meta = new Float32Array(buf.buffer, 0, 4);
/* Extract polygon path */
const data = new Float32Array(buf.buffer, 4*4); const data = new Float32Array(buf.buffer, 4*4);
currentMap.setCenter({lat: meta[1], lng: meta[2]}); currentMap.setCenter({lat: meta[1], lng: meta[2]});
currentMap.setZoom(meta[3]); currentMap.setZoom(meta[3]);
const path = []; const path : google.maps.LatLngLiteral[] = [];
for (let i = 0; i < data.length; i += 2) { for (let i = 0; i < data.length; i += 2) {
path.push({ path.push({
lat: data[i], lat: data[i],
@ -191,6 +226,11 @@
emits('densityChange', meta[0]); emits('densityChange', meta[0]);
} }
/*
This is the legacy hash decoder.
We keep it around so that original
links posted online keep working
*/
const loadLegacyHash = (hash: string) => { const loadLegacyHash = (hash: string) => {
const opt = hash.split(';'); const opt = hash.split(';');
const curPosition = opt.pop(); const curPosition = opt.pop();
@ -201,8 +241,8 @@
currentMap.setZoom(parseInt(cursetting[2])); currentMap.setZoom(parseInt(cursetting[2]));
} }
const density = parseFloat(opt.pop()) || 1; const density = parseFloat(opt.pop() ?? '') || 1;
const path = []; const path : google.maps.LatLngLiteral[] = [];
for (let i = 0; i < opt.length; i++) { for (let i = 0; i < opt.length; i++) {
const coord = opt[i].split(','); const coord = opt[i].split(',');
@ -224,6 +264,21 @@
currentPolygon.getPath().clear(); currentPolygon.getPath().clear();
} }
/*
Generate URL hash from various data.
- density
- Map position (center position as lat/lng & zoom value)
- Our polygon path as lat/lng points
The generated buffer is then compressed (if needed) and Base64'd.
We consider every value to be a float and serialize
our data into a binary array with no extra information.
0 4 8 12 16 ....
[density][position lat][position long][zoom][...polygon points]
*/
const hash = computed(() => { const hash = computed(() => {
const buf = new Float32Array(arrPoly.value.length*2+4); const buf = new Float32Array(arrPoly.value.length*2+4);
buf[0] = props.density; buf[0] = props.density;
@ -233,11 +288,27 @@
buf[4+i*2] = arrPoly.value[i].lat(); buf[4+i*2] = arrPoly.value[i].lat();
buf[4+i*2+1] = arrPoly.value[i].lng(); buf[4+i*2+1] = arrPoly.value[i].lng();
} }
return 'b' + Base64.fromUint8Array(new Uint8Array(buf.buffer), true);
let outbuf = new Uint8Array(buf.buffer);
const isCompressed = outbuf.byteLength >= 150;
if (isCompressed) {
outbuf = zlibSync(outbuf, { level: 9 });
}
/*
*/
return (isCompressed ? 'c' : 'b') + Base64.fromUint8Array(outbuf, true);
}) })
watch(() => props.density, () => updatePolygonColor()); watch(() => props.density, () => updatePolygonColor());
/*
Debounce the URL hash update
otherwise it would flood the browser history whenever the user
moves the polygon around
*/
watchDebounced(hash, watchDebounced(hash,
(hashval: string) => emits('hashChange', hashval), (hashval: string) => emits('hashChange', hashval),
{ debounce: 300 }) { debounce: 300 })

Wyświetl plik

@ -596,6 +596,11 @@ fastq@^1.6.0:
dependencies: dependencies:
reusify "^1.0.4" reusify "^1.0.4"
fflate@^0.7.3:
version "0.7.3"
resolved "https://registry.yarnpkg.com/fflate/-/fflate-0.7.3.tgz#288b034ff0e9c380eaa2feff48c787b8371b7fa5"
integrity sha512-0Zz1jOzJWERhyhsimS54VTqOteCNwRtIlh8isdL0AXLo0g7xNTfTL7oWrkmCnPhZGocKIkWHBistBrrpoNH3aw==
fill-range@^7.0.1: fill-range@^7.0.1:
version "7.0.1" version "7.0.1"
resolved "https://registry.yarnpkg.com/fill-range/-/fill-range-7.0.1.tgz#1919a6a7c75fe38b2c7c77e5198535da9acdda40" resolved "https://registry.yarnpkg.com/fill-range/-/fill-range-7.0.1.tgz#1919a6a7c75fe38b2c7c77e5198535da9acdda40"