Initial commit

This commit is contained in:
2023-10-08 20:43:45 +02:00
commit 5a39fec5ad
16 changed files with 5975 additions and 0 deletions

79
src/app.css Normal file
View File

@ -0,0 +1,79 @@
html, body {
font-family: system-ui, -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Oxygen, Ubuntu, Cantarell, 'Open Sans', 'Helvetica Neue', sans-serif;
margin: 0;
padding: 0;
width: 100vw;
height: 100vh;
background-color: #eee;
}
* {
font-synthesis: none;
text-rendering: optimizeLegibility;
-webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale;
-webkit-text-size-adjust: 100%;
box-sizing: border-box;
margin: 0;
padding: 0;
}
#app {
max-width: 1280px;
margin: 0 auto;
padding: 32px;
height: 100%;
}
ul, ol {
margin-left: 1rem;
}
ul li, ol li {
margin-bottom: 4px;
}
dl {
margin: 0;
padding: 0;
}
dl dt {
font-weight: 700;
}
dl dd {
margin: 0 0 12px 0;
}
.card {
background-color: #fff;
padding: 12px;
margin-bottom: 12px;
}
.card h2 {
margin-bottom: 12px;
padding-bottom: 6px;
border-bottom: 1px solid #ddd;
font-size: 22px;
}
.input {
min-width: 100px;
padding: 2px 4px;
font: inherit;
border: 1px solid #888;
border-radius: 4px;
background-color: #fff;
}
*:last-child { margin-bottom: 0; }
@media (prefers-color-scheme: dark) {
html, body {
background-color: #333;
color: #eee;
}
a { color: #ade; }
.card { background-color: #444; }
.card h2 { border-color: #333; }
}

8
src/app.js Normal file
View File

@ -0,0 +1,8 @@
import './app.css';
import App from './app.svelte';
const app = new App({
target: document.getElementById('app'),
});
export default app;

116
src/app.svelte Normal file
View File

@ -0,0 +1,116 @@
<script>
/* global L */
import { onMount } from 'svelte';
import { latLngToDMS, latLngToDecimal, latLngToExif } from './conversion.js';
import { getAppleUrl, getDuckDuckGoUrl, getGoogleUrl } from './urls.js';
let map;
let mapDiv;
let marker;
let coords = L.latLng(51.507, -0.1275);
function updateMap() {
map.setView(coords);
marker.setLatLng(coords);
}
onMount(() => {
map = L.map(mapDiv).setView(coords, 9);
L.tileLayer('https://tile.openstreetmap.org/{z}/{x}/{y}.png', {
maxZoom: 19,
attribution: '&copy; <a href="http://www.openstreetmap.org/copyright">OpenStreetMap</a>',
}).addTo(map);
L.polyline([ [ -90, 0 ], [ 90, 0 ] ]).addTo(map);
L.polyline([ [ 0, -180 ], [ 0, 180 ] ]).addTo(map);
marker = L.marker(coords).addTo(map);
map.on('click', event => {
coords = event.latlng;
updateMap();
});
});
</script>
<main class="grid">
<div class="info">
<section class="card">
<h2>Coordinates</h2>
<dl>
<dt>Decimal</dt>
<dd>{latLngToDecimal(coords)}</dd>
<dt>DMS</dt>
<dd>{latLngToDMS(coords)}</dd>
<dt>EXIF</dt>
<dd>{latLngToExif(coords)}</dd>
</dl>
</section>
<section class="card">
<h2>Go to</h2>
<div class="coordinate-input">
<input
class="input"
type="number"
step={0.25}
bind:value={coords.lat}
on:change={updateMap}
/>
<input
class="input"
type="number"
step={0.25}
bind:value={coords.lng}
on:change={updateMap}
/>
</div>
</section>
<section class="card">
<h2>Open in</h2>
<ul>
<li><a href={getAppleUrl(coords)} target="_blank">Apple Maps</a></li>
<li><a href={getGoogleUrl(coords)} target="_blank">Google Maps</a></li>
<li><a href={getDuckDuckGoUrl(coords)} target="_blank">DuckDuckGo</a></li>
</ul>
</section>
<p>
Star gpstool on
<a href="https://github.com/garraflavatra/gpstool" target="_blank" rel="noopener noreferrer">
GitHub
</a>
</p>
</div>
<div class="map" bind:this={mapDiv} />
</main>
<style>
.grid {
display: grid;
grid-template: 1fr / 250px 1fr;
height: 100%;
gap: 12px;
}
@media (max-width: 750px) {
.grid {
grid-template: 1fr 2fr / 1fr;
}
}
.info {
overflow: scroll;
}
.coordinate-input {
display: grid;
gap: 8px;
grid-template: 1fr / 1fr 1fr;
}
</style>

37
src/conversion.js Normal file
View File

@ -0,0 +1,37 @@
export function latLngToDecimal({ lat, lng }) {
const precision = 5;
return `${lat.toFixed(precision)}; ${lng.toFixed(precision)}`;
}
// DMS = degrees, minutes, seconds
function decimalToDMS(coord) {
const negative = coord < 0;
coord = Math.abs(coord);
const degrees = Math.trunc(coord);
let minutes = (coord - degrees) * 60;
const seconds = Math.trunc((minutes - Math.trunc(minutes)) * 60);
minutes = Math.trunc(minutes);
return { degrees, minutes, seconds, negative };
}
export function latLngToDMS({ lat, lng }) {
lat = decimalToDMS(lat);
lng = decimalToDMS(lng);
const latRef = lat.negative ? 'S' : 'N';
const lngRef = lng.negative ? 'W' : 'E';
return `${lat.degrees}°${lat.minutes}'${lat.seconds}"${latRef} ` +
`${lng.degrees}°${lng.minutes}'${lng.seconds}"${lngRef}`;
}
export function latLngToExif({ lat, lng }) {
lat = decimalToDMS(lat);
lng = decimalToDMS(lng);
const latRef = lat.negative ? 'S' : 'N';
const lngRef = lng.negative ? 'W' : 'E';
return `${lat.degrees},${lat.minutes}.${lat.seconds}${latRef} ` +
`${lng.degrees},${lng.minutes}.${lng.seconds}${lngRef}`;
}

17
src/urls.js Normal file
View File

@ -0,0 +1,17 @@
import { latLngToDMS } from './conversion.js';
export function getAppleUrl({ lat, lng }) {
return `https://maps.apple.com/?address=${lat},${lng}`;
}
export function getGoogleUrl(latlng) {
return `https://www.google.com/maps/place/${encodeURIComponent(
latLngToDMS(latlng)
)}`;
}
export function getDuckDuckGoUrl(latlng) {
return `https://duckduckgo.com/?q=${encodeURIComponent(
latLngToDMS(latlng)
)}&iaxm=maps`;
}

2
src/vite-env.d.ts vendored Normal file
View File

@ -0,0 +1,2 @@
/// <reference types="svelte" />
/// <reference types="vite/client" />