LocationPreview/src/App.svelte

236 lines
5.3 KiB
Svelte
Raw Normal View History

2021-08-09 01:44:09 +03:00
<script lang="ts">
import L from 'leaflet';
import { onMount } from 'svelte';
let MAPBOX_ACCESS_TOKEN: string | undefined = void 0;
let error: string | undefined = void 0;
let followLocation = true;
let darkMode = false;
let map: L.Map | undefined = void 0;
2021-10-03 23:19:14 +03:00
const mapLayers = () => ({
2021-08-09 01:44:09 +03:00
dark: L.tileLayer('https://api.mapbox.com/styles/v1/{id}/tiles/{z}/{x}/{y}?access_token={accessToken}', {
attribution: 'Map data &copy; <a href="https://www.openstreetmap.org/copyright">OpenStreetMap</a> contributors, Imagery © <a href="https://www.mapbox.com/">Mapbox</a>',
maxZoom: 18,
id: 'mapbox/dark-v10',
tileSize: 512,
zoomOffset: -1,
accessToken: MAPBOX_ACCESS_TOKEN,
}),
light: L.tileLayer('https://api.mapbox.com/styles/v1/{id}/tiles/{z}/{x}/{y}?access_token={accessToken}', {
attribution: 'Map data &copy; <a href="https://www.openstreetmap.org/copyright">OpenStreetMap</a> contributors, Imagery © <a href="https://www.mapbox.com/">Mapbox</a>',
maxZoom: 18,
id: 'mapbox/light-v10',
tileSize: 512,
zoomOffset: -1,
accessToken: MAPBOX_ACCESS_TOKEN,
}),
2021-10-03 23:19:14 +03:00
});
2021-08-09 01:44:09 +03:00
const locationCircleLayerGroup = L.layerGroup();
$: if (map) {
locationCircleLayerGroup.addTo(map);
}
const geolocation = navigator.geolocation;
if (!geolocation) {
error = 'Geolocation not available';
}
let geoWatchHandle: ReturnType<InstanceType<typeof Geolocation>["watchPosition"]> | undefined = void 0;
if (window.matchMedia) {
window.matchMedia('(prefers-color-scheme: dark)').addEventListener('change', e => {
if (!darkMode && e.matches) {
darkMode = true;
}
else if (darkMode && !e.matches) {
darkMode = false;
}
});
}
onMount(async () => {
const matResp = await fetch('/MAPBOX_ACCESS_TOKEN.txt');
MAPBOX_ACCESS_TOKEN = (await matResp.text()).trim();
map = L.map('mapid', {
zoomDelta: 1,
zoomSnap: 0.25,
}).setView([0, 0], 1);
});
// Set light or dark mode MapBox layer
$: {
if (map) {
if (!darkMode) {
2021-10-03 23:19:14 +03:00
mapLayers().light.addTo(map);
2021-08-09 01:44:09 +03:00
}
else {
2021-10-03 23:19:14 +03:00
mapLayers().dark.addTo(map);
2021-08-09 01:44:09 +03:00
}
}
}
let coords: GeolocationCoordinates | undefined = void 0;
$: if (coords) {
locationCircleLayerGroup.clearLayers();
L.circle({lat: coords.latitude, lng: coords.longitude, alt: coords.altitude}, {
radius: coords.accuracy,
opacity: 0.2,
}).addTo(locationCircleLayerGroup);
L.circle([coords.latitude, coords.longitude], {
radius: 10,
opacity: 0.75,
}).addTo(locationCircleLayerGroup);
}
else {
locationCircleLayerGroup.clearLayers();
}
2021-10-03 23:30:47 +03:00
const locationFollowLogic = {
follow: false,
coords: void 0,
setFollow: function(shouldFollow: boolean) {
this.follow = shouldFollow;
},
2021-10-03 23:38:33 +03:00
update: function(coords: GeolocationCoordinates | undefined) {
2021-10-03 23:30:47 +03:00
this.coords = coords;
2021-10-03 23:38:33 +03:00
if (map && this.follow) {
if (this.coords) {
map.fitBounds(
L.latLng(this.coords.latitude, this.coords.longitude).toBounds(this.coords.accuracy * 2),
{
animate: true,
duration: 1,
},
);
}
else {
map.setZoom(1, {
animate: true,
duration: 5,
});
}
2021-10-03 23:30:47 +03:00
}
},
};
$: locationFollowLogic.setFollow(followLocation);
$: locationFollowLogic.update(coords);
2021-08-09 01:44:09 +03:00
function onPosition(e: GeolocationPosition) {
error = void 0;
coords = e.coords;
}
function onLocationButtonClick() {
if (geoWatchHandle === void 0) {
geoWatchHandle = geolocation.watchPosition(onPosition, (e) => {
setTimeout(() => {geoWatchHandle = void 0;}, 0);
if (e.code === e.PERMISSION_DENIED) {
error = 'Geolocation Permission Denied';
}
else if (e.code === e.POSITION_UNAVAILABLE) {
error = 'Geolocation Unavailable';
}
else {
error = `Unknown Error: ${e}`;
}
}, {
enableHighAccuracy: true,
});
}
else {
geolocation.clearWatch(geoWatchHandle);
geoWatchHandle = void 0;
setTimeout(() => {
coords = void 0;
}, 1000);
}
}
function toggleFollowLocation() {
followLocation = !followLocation;
}
</script>
<main>
<h1>Location Preview</h1>
{#if error}
<p class="error">{error}</p>
{/if}
{#if coords}
<div id="coordsDiv">
<table>
<tr>
<th>Field</th>
<th>Value</th>
</tr>
<tr>
<td>Latitude</td>
<td>{coords.latitude}</td>
</tr>
<tr>
<td>Longitude</td>
<td>{coords.longitude}</td>
</tr>
<tr>
<td>Accuracy</td>
<td>{Math.round(coords.accuracy)} m</td>
</tr>
</table>
</div>
{/if}
<div id="button-area">
{#key geoWatchHandle}
2021-10-03 23:30:47 +03:00
<button on:click={onLocationButtonClick}>{geoWatchHandle !== (void 0) ? "Stop Watching" : "Find Location"}</button>
2021-08-09 01:44:09 +03:00
{/key}
{#key followLocation}
<button on:click={toggleFollowLocation}>{followLocation ? "Stop Zooming to Location" : "Zoom to Location"}</button>
{/key}
</div>
<div id="mapid"></div>
</main>
<style>
main {
text-align: center;
padding: 1em;
margin: 0 auto;
}
h1 {
color: #ff3e00;
text-transform: uppercase;
font-size: 2em;
font-weight: 100;
}
p.error {
font-size: 1.25em;
color: #D32F2F;
border-left: 5px #D32F2F solid;
margin-left: auto;
margin-right: auto;
}
#mapid {
height: 300px;
max-width: 700px;
margin-left: auto;
margin-right: auto;
}
#coordsDiv {
display: flex;
justify-content: center;
}
#coordsDiv table {
border-collapse: collapse;
}
#coordsDiv td {
border: 1px solid black;
padding: 8px;
}
</style>