Skip to content

Commit

Permalink
Frontent: fix pins and auto panning
Browse files Browse the repository at this point in the history
  • Loading branch information
bierik committed Sep 7, 2024
1 parent 8495eff commit 6f4df49
Show file tree
Hide file tree
Showing 5 changed files with 56 additions and 65 deletions.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added frontend/assets/icons/twemoji--brain.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
16 changes: 16 additions & 0 deletions frontend/components/Navigation.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
<template>
<div class="fixed bottom-0 flex h-16 w-screen bg-white" style="z-index: 9999">
<nuxt-link
active-class="bg-blue-200"
class="flex grow items-center justify-center"
:to="{ name: 'index' }"
><Icon size="40" name="icon-park:radar-two"
/></nuxt-link>
<nuxt-link
active-class="bg-blue-200"
class="flex grow items-center justify-center"
:to="{ name: 'map' }"
><Icon size="40" name="icon-park:map-draw"
/></nuxt-link>
</div>
</template>
73 changes: 15 additions & 58 deletions frontend/pages/index.vue
Original file line number Diff line number Diff line change
Expand Up @@ -2,28 +2,30 @@
<div
v-for="(radarPoint, index) in radarPoints"
:key="index"
class="absolute size-4 origin-center rounded-full bg-blue-400"
class="absolute size-4 origin-center rounded-full bg-blue-400 opacity-80"
:style="radarPoint"
style="z-index: 9999"
/>
<div id="map" class="h-screen w-screen" />
<div class="flex h-screen snap-x snap-mandatory overflow-x-auto bg-black">
<img
v-for="photoInProximity in photosInProximity"
:key="photoInProximity.id"
:src="photoInProximity.image_url"
class="snap-center object-contain"
/>
</div>
<Navigation />
</template>
<script setup>
import { map as lodashMap } from "lodash-es";
import {
useGeolocation,
useDeviceOrientation,
useWindowSize,
} from "@vueuse/core";
import { computed, toValue } from "vue";
import "leaflet/dist/leaflet.css";
import L from "leaflet";
const { coords } = useGeolocation();
const { alpha } = useDeviceOrientation();
const { data } = useFetchPhotos(coords, 1000);
const { width, height } = useWindowSize();
const router = useRouter();
const orientation = computed(() => toValue(alpha) * (Math.PI / 180));
const windowCenter = computed(() => ({
Expand All @@ -32,14 +34,10 @@ const windowCenter = computed(() => ({
}));
const radius = computed(() => toValue(width) / 2 - 16);
const pointsInProximity = computed(() =>
lodashMap(toValue(data), "coordinates"),
);
const radarPoints = computed(() => {
return toValue(pointsInProximity).map((point) => {
return (toValue(data) || []).map(({ coordinates: { lat, lon } }) => {
const beta = Math.tanh(
(point.lat - toValue(coords).latitude) /
(point.lon - toValue(coords).longitude),
(lat - toValue(coords).latitude) / (lon - toValue(coords).longitude),
);
const tangentPoint = {
x:
Expand All @@ -52,53 +50,12 @@ const radarPoints = computed(() => {
Math.sin(toValue(beta) + toValue(orientation) - Math.PI / 2),
};
return {
transform: `translate(${tangentPoint.x - 16}px, ${tangentPoint.y - 16}px)`,
transform: `translate(${tangentPoint.x - 16}px, ${tangentPoint.y - 16}px) scale(1.2)`,
};
});
});
const initialZoom = 20;
const layer = {
url: "https://wmts.geo.admin.ch/1.0.0/ch.swisstopo.pixelkarte-farbe/default/current/3857/{z}/{x}/{y}.jpeg",
attribution: "© swisstopo",
};
let map = null;
const me = L.marker();
const photosLayer = L.layerGroup();
onMounted(() => {
map = L.map("map", { zoomControl: false });
L.tileLayer(layer.url, { attribution: layer.attribution }).addTo(map);
photosLayer.addTo(map);
me.addTo(map);
});
watch(coords, ({ latitude, longitude }) => {
me.setLatLng([latitude, longitude]);
map.setView(new L.LatLng(latitude, longitude), initialZoom);
const photosInProximity = computed(() => {
return (toValue(data) || []).filter((o) => o.distance <= 400);
});
function placePhotos(photos) {
photosLayer.clearLayers();
photos.forEach(({ coordinates: { lat, lon }, image_url, iiif_url }) => {
const marker = L.marker([lat, lon]).bindPopup(
`<img src="${image_url}" />`,
{
maxWidth: 200,
minWidth: 200,
maxHeight: 200,
minHeight: 200,
},
);
marker.on("popupopen", function () {
const popupContent = document.querySelector(".leaflet-popup-content");
popupContent.addEventListener("click", () => {
router.push({ name: "iiif", query: { manifestURL: iiif_url } });
});
});
marker.addTo(photosLayer);
});
}
watch(data, placePhotos);
</script>
32 changes: 25 additions & 7 deletions frontend/pages/map/index.vue
Original file line number Diff line number Diff line change
@@ -1,42 +1,60 @@
<template>
<div id="map" class="h-screen w-screen" />
<Navigation />
</template>
<script setup>
import "leaflet/dist/leaflet.css";
import L from "leaflet";
import { useGeolocation } from "@vueuse/core";
import { useGeolocation, watchOnce } from "@vueuse/core";
import pinIconPath from "~/assets/icons/twemoji--brain.png";
import meIconPath from "~/assets/icons/fluent-emoji--person-zombie.png";
const { coords } = useGeolocation();
const router = useRouter();
const initialZoom = 20;
const pinIcon = L.icon({
iconUrl: pinIconPath,
iconSize: [38, 38],
iconAnchor: [0, 38],
popupAnchor: [19, -38],
});
const meIcon = L.icon({
iconUrl: meIconPath,
iconSize: [38, 38],
iconAnchor: [0, 38],
popupAnchor: [19, -38],
});
const layer = {
url: "https://wmts.geo.admin.ch/1.0.0/ch.swisstopo.pixelkarte-farbe/default/current/3857/{z}/{x}/{y}.jpeg",
attribution: "© swisstopo",
};
let map = null;
const me = L.marker();
const me = L.marker([], { icon: meIcon });
const { data } = useFetchPhotos(coords, 1000);
const photosLayer = L.layerGroup();
onMounted(() => {
map = L.map("map", { zoomControl: false, dragging: false, tap: false });
map.dragging.disable();
map = L.map("map", { zoomControl: false });
L.tileLayer(layer.url, { attribution: layer.attribution }).addTo(map);
photosLayer.addTo(map);
me.addTo(map);
});
watch(coords, ({ latitude, longitude }) => {
me.setLatLng([latitude, longitude]);
map.setView(new L.LatLng(latitude, longitude), initialZoom);
});
watchOnce(coords, ({ latitude, longitude }) => {
map.setView(new L.LatLng(latitude, longitude), 30);
});
function placePhotos(photos) {
photosLayer.clearLayers();
photos.forEach(({ coordinates: { lat, lon }, image_url, iiif_url }) => {
const marker = L.marker([lat, lon]).bindPopup(
const marker = L.marker([lat, lon], { icon: pinIcon }).bindPopup(
`<img src="${image_url}" />`,
{
maxWidth: 200,
Expand Down

0 comments on commit 6f4df49

Please sign in to comment.