This repository has been archived by the owner on Jul 5, 2023. It is now read-only.
-
-
Notifications
You must be signed in to change notification settings - Fork 2
/
geo.js
107 lines (95 loc) · 3.07 KB
/
geo.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
/**
* @copyright 2021-2023 Chris Zuber <admin@kernvalley.us>
*/
import { getDeferred } from './promises.js';
export const supported = 'geolocation' in navigator;
export function watch(success, error = console.error, { maximumAge, timeout, signal, enableHighAccuracy } = {}) {
if (! supported) {
error(new DOMException('GeoLocation API not supported'));
return;
} else if (signal instanceof AbortSignal && signal.aborted) {
error(signal.reason || new DOMException('Operation aborted.'));
return;
} else {
const id = navigator.geolocation.watchPosition(success, error, { maximumAge, timeout, enableHighAccuracy });
if (signal instanceof AbortSignal) {
signal.addEventListener('abort', () => {
navigator.geolocation.clearWatch(id);
error(signal.reason);
}, { once: true });
}
return id;
}
}
export async function get({ maximumAge, timeout, signal, enableHighAccuracy } = {}) {
const { resolve, reject, promise } = getDeferred({ signal });
if (! supported) {
reject(new DOMException('GeoLocation API not supported'));
} else if (! (signal instanceof AbortSignal && signal.aborted)) {
navigator.geolocation.getCurrentPosition(resolve, reject, { maximumAge, timeout, enableHighAccuracy });
}
return promise;
}
export async function recordGeoJSON({
enableHighAccuracy = true,
filename = `${new Date().toISOString()}.geojson`,
marker,
maximumAge,
signal,
timeout,
type = 'application/geo+json',
} = {}) {
const { resolve, reject, promise } = getDeferred();
if (! (signal instanceof AbortSignal)) {
reject(new TypeError('signal must be an instance of `AbortSignal`.'));
} else if (signal.aborted) {
reject(signal.reason);
} else if (! supported) {
reject(new DOMException('GeoLocation API not supported.'));
} else {
const coords = [];
if (
marker instanceof HTMLElement && marker.tagName === 'LEAFLET-MARKER'
&& marker.closest('leaflet-map') instanceof HTMLElement
) {
watch(
({ coords: { latitude, longitude }}) => {
coords.push([longitude, latitude]);
marker.geo = { latitude, longitude };
marker.closest('leaflet-map').flyTo({ latitude, longitude });
},
err => console.error(err),
{ signal, enableHighAccuracy, maximumAge, timeout },
);
} else {
watch(
({ coords: { latitude, longitude }}) => coords.push([longitude, latitude]),
err => console.error(err),
{ signal, enableHighAccuracy, maximumAge, timeout },
);
}
signal.addEventListener('abort', () => {
if (coords.length === 0) {
reject(new DOMException('No coordinates recorded.'));
} else {
if (marker instanceof HTMLElement && marker.tagName === 'LEAFLET-MARKER') {
marker.remove();
}
const geo = JSON.stringify({
'type': 'FeatureCollection',
'features': [{
'type': 'Feature',
'geometry': {
'type': 'LineString',
'coordinates': coords,
},
'properties': { 'generated': new Date().toISOString() },
}]
}, null, 4);
const file = new File([geo], filename, { type });
resolve(file);
}
}, { once: true });
}
return promise;
}