north-star / commit
adding a calibrate north button
src/app.js | 38 ++++++++++++++++++++++++++++++++++---- src/index.html | 7 +++++-- src/style.css | 14 +++++++++++--- 3 files changed, 50 insertions(+), 9 deletions(-) diff --git a/src/app.js b/src/app.js index e05b4d9..ba73a95 100644 --- a/src/app.js +++ b/src/app.js @@ -13,6 +13,7 @@ const selfColorInput = document.getElementById('self-color-input'); const roomCurrent = document.getElementById('room-current'); const inviteRoomLink = document.getElementById('invite-room-link'); const joinRoomLink = document.getElementById('join-room-link'); +const calibrateHeadingLink = document.getElementById('calibrate-heading-link'); const inviteRoomStatus = document.getElementById('invite-room-status'); const createRoomLink = document.getElementById('create-room-link'); const participantsPanel = document.getElementById('participants-panel'); @@ -25,9 +26,17 @@ const arrow = document.getElementById('default-arrow'); document.head.appendChild(Object.assign(document.createElement("link"), { rel: "icon", href: "data:image/svg+xml,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 100 100'><text y='.9em' font-size='90'>" + arrow.innerText + "</text></svg>" })) const getShortestDelta = (fromAngle, toAngle) => ((toAngle - fromAngle + 540) % 360) - 180; const normalizeAngle = (angle) => ((angle % 360) + 360) % 360; +const normalizeSignedAngle = (angle) => { + const normalized = normalizeAngle(angle); + return normalized > 180 ? normalized - 360 : normalized; +}; const RENDER_INTERVAL_MS = 180; const LOCATION_SYNC_INTERVAL_MS = 3000; -const HEADING_CORRECTION_DEG = 0; +const HEADING_CORRECTION_STORAGE_KEY = 'north-star-heading-correction-deg'; +let headingCorrectionDeg = (() => { + const parsed = Number(localStorage.getItem(HEADING_CORRECTION_STORAGE_KEY)); + return Number.isFinite(parsed) ? parsed : 0; +})(); let GIT_COMMIT = 'local-dev'; try { const commitModule = await import('./commit.js'); @@ -75,6 +84,7 @@ const selfPosition = { }; // Heading, assume north orientation by default, but if we get a heading from the device, use that to rotate the arrow accordingly let selfHeading = 0; +let lastRawHeading = null; const firebaseConfig = { apiKey: "AIzaSyA4G7e13Gt1XAIds1Y63X_RFw-2O48iCLM", @@ -217,6 +227,24 @@ if (joinRoomLink) { }); } +if (calibrateHeadingLink) { + calibrateHeadingLink.addEventListener('click', (event) => { + event.preventDefault(); + + if (lastRawHeading === null) { + alert('Heading sensor is not ready yet. Try again in a moment.'); + return; + } + + // Make current phone-forward direction equal to north (0 deg). + headingCorrectionDeg = normalizeSignedAngle(-lastRawHeading); + localStorage.setItem(HEADING_CORRECTION_STORAGE_KEY, String(headingCorrectionDeg)); + selfHeading = normalizeAngle(lastRawHeading + headingCorrectionDeg); + + setInviteStatus('North calibrated'); + }); +} + const NAME_STORAGE_KEY = 'north-star-self-name'; const COLOR_STORAGE_KEY = 'north-star-self-color'; const PARTICIPANT_VISIBILITY_STORAGE_KEY = 'north-star-participant-visibility'; @@ -433,7 +461,8 @@ window.addEventListener('deviceorientationabsolute', (event) => { if (heading === null) return; hasAbsoluteOrientation = true; - selfHeading = normalizeAngle(heading + HEADING_CORRECTION_DEG); + lastRawHeading = heading; + selfHeading = normalizeAngle(heading + headingCorrectionDeg); }); window.addEventListener('deviceorientation', (event) => { @@ -442,7 +471,8 @@ window.addEventListener('deviceorientation', (event) => { const heading = getHeadingFromEvent(event); if (heading === null) return; - selfHeading = normalizeAngle(heading + HEADING_CORRECTION_DEG); + lastRawHeading = heading; + selfHeading = normalizeAngle(heading + headingCorrectionDeg); }); const participantsRef = ref(db, `rooms/${roomId}/participants`); @@ -644,7 +674,7 @@ const render = () => { document.body.style.backgroundColor = selfParticipant.color; // output debug info - logDebug(`Name: ${selfParticipant.name} | Position: ${selfParticipant.position.lat.toFixed(1)}, ${selfParticipant.position.lon.toFixed(1)} | Heading: ${selfHeading.toFixed(2)}° | Real participants: ${participants.length} | Commit: ${GIT_COMMIT}`); + logDebug(`Name: ${selfParticipant.name} | Position: ${selfParticipant.position.lat.toFixed(1)}, ${selfParticipant.position.lon.toFixed(1)} | Heading: ${selfHeading.toFixed(2)}° | Corr: ${headingCorrectionDeg.toFixed(1)}° | Real participants: ${participants.length} | Commit: ${GIT_COMMIT}`); }; await syncSelfParticipant(); diff --git a/src/index.html b/src/index.html index 54861a6..67ab0ed 100644 --- a/src/index.html +++ b/src/index.html @@ -25,8 +25,11 @@ </form> <div id="default-arrow" style="display: none;" class="arrow">⇡</div> <div id="content"> - <button id="participants-toggle" class="participants-toggle" type="button" aria-expanded="true">Hide - Participants</button> + <div class="panel-actions"> + <button id="calibrate-heading-link" class="participants-toggle" type="button">Calibrate North</button> + <button id="participants-toggle" class="participants-toggle" type="button" aria-expanded="true">Hide + Participants</button> + </div> <aside id="participants-panel" class="participants-panel" aria-label="Participants"></aside> </div> <div> diff --git a/src/style.css b/src/style.css index f8a3c8a..d50226b 100644 --- a/src/style.css +++ b/src/style.css @@ -158,10 +158,18 @@ a { z-index: 1; } -.participants-toggle { +.panel-actions { position: absolute; + left: 10px; right: 10px; top: 8px; + display: flex; + justify-content: space-between; + align-items: center; + z-index: 4; +} + +.participants-toggle { padding: 6px 10px; border: 0; border-radius: 8px; @@ -169,7 +177,6 @@ a { color: #f8fafc; font-size: 12px; font-weight: 700; - z-index: 4; } .participants-panel { @@ -291,7 +298,8 @@ a { } @media (max-width: 720px) { - .participants-toggle { + .panel-actions { + left: 6px; right: 6px; top: 6px; }