Add a Locus Pro-style toolbar readout: DMS coords + sunrise/sunset
The topbar's coordinate display was plain decimal degrees ("48.14611,
17.17722") — switched to DMS (48°08'46"N 17°10'38"E), the more
GPS-unit-like format Locus Pro itself uses, and made it click-to-copy
(plain decimal, since that's what pastes cleanly into another map/GPS
app — not the DMS text actually shown).
Added sunrise/sunset + a countdown to whichever's next, for the same
map-center point the coordinates already describe. Vendored SunCalc
(BSD-2-Clause, github.com/mourner/suncalc) rather than hand-rolling
the astronomical math — small, dependency-free, and correctness here
has real pitfalls (equation of time, refraction, polar day/night) a
first-pass reimplementation would risk getting subtly wrong.
Also added a test asserting every public/js/*.js module has a
versioned importmap entry in layout.erb — caught that overlays.js
(from the previous commit) was missing one, which would have quietly
skipped ASSET_VERSION's cache-busting for that file after every
deploy.
This commit is contained in:
1 parent
c5b4a9ffb2
commit
dce5fd87da
8 files changed
+696
-3
No files matched your search
+33
-1
@@ -15,6 +15,7 @@ import { NotesControl } from "/js/notes.js";
|
||||
import { PluginsControl } from "/js/plugins.js";
|
||||
import { LocateControl } from "/js/locate.js";
|
||||
import { LAYERS_ICON, HILLSHADE_ICON } from "/js/icons.js";
|
||||
import { formatCoords, formatSunInfo } from "/js/sun.js";
|
||||
import { notifySidePanelOpen, onlyOneSidePanelOpen } from "/js/panels.js";
|
||||
import { isLoggedIn } from "/js/auth.js";
|
||||
import HomeButton from "/vendor/npmap-home-button/home-button.esm.js";
|
||||
@@ -540,11 +541,42 @@ map.once("style.load", () => {
|
||||
const coordsLabel = document.querySelector(".topbar__coords");
|
||||
const updateCoords = () => {
|
||||
const { lng, lat } = map.getCenter();
|
||||
coordsLabel.textContent = `${lat.toFixed(5)}, ${lng.toFixed(5)}`;
|
||||
coordsLabel.textContent = formatCoords(lat, lng);
|
||||
};
|
||||
updateCoords();
|
||||
map.on("move", updateCoords);
|
||||
|
||||
// Plain decimal degrees, not the DMS text actually shown — that's what
|
||||
// pastes cleanly into another map/GPS app, which is the whole point of
|
||||
// copying a coordinate in the first place.
|
||||
coordsLabel.title = "Click to copy coordinates";
|
||||
coordsLabel.addEventListener("click", async () => {
|
||||
const { lng, lat } = map.getCenter();
|
||||
try {
|
||||
await navigator.clipboard.writeText(`${lat.toFixed(6)}, ${lng.toFixed(6)}`);
|
||||
} catch {
|
||||
return; // clipboard API unavailable (e.g. an insecure context) — nothing to fall back to
|
||||
}
|
||||
coordsLabel.textContent = "Copied!";
|
||||
setTimeout(updateCoords, 1000);
|
||||
});
|
||||
|
||||
// Sunrise/sunset for the same center point the coords above already show —
|
||||
// on moveend (not every "move" frame, unlike updateCoords: the sun position
|
||||
// barely moves between two nearby spots, not worth recomputing constantly)
|
||||
// plus a periodic tick so the "Xh Ym to sunset" countdown keeps counting
|
||||
// down even while the map sits still.
|
||||
const sunLabel = document.querySelector(".topbar__sun");
|
||||
const updateSun = () => {
|
||||
const { lng, lat } = map.getCenter();
|
||||
const info = formatSunInfo(lat, lng);
|
||||
sunLabel.textContent = info ?? "";
|
||||
sunLabel.hidden = info === null;
|
||||
};
|
||||
updateSun();
|
||||
map.on("moveend", updateSun);
|
||||
setInterval(updateSun, 60000);
|
||||
|
||||
const sidebar = document.getElementById("sidebar");
|
||||
|
||||
// Grouped into the TODO's planned 4-module menu (Explorer / Offline hub /
|
||||
|
||||
Reference in new issue
Block a user