north-star / commit
pasta time with north orientation
src/app.js | 76 ++++++++++++++++++++++++++------------------------------------ 1 file changed, 32 insertions(+), 44 deletions(-) diff --git a/src/app.js b/src/app.js index 5952b78..3daec94 100644 --- a/src/app.js +++ b/src/app.js @@ -27,6 +27,7 @@ const getShortestDelta = (fromAngle, toAngle) => ((toAngle - fromAngle + 540) % const normalizeAngle = (angle) => ((angle % 360) + 360) % 360; const RENDER_INTERVAL_MS = 180; const LOCATION_SYNC_INTERVAL_MS = 3000; +const HEADING_CORRECTION_DEG = 0; /** * @typedef {Object} Position @@ -391,61 +392,48 @@ navigator.geolocation.watchPosition(async (pos) => { }, (err) => { console.error('Error getting geolocation', err); }); -window.addEventListener('deviceorientationabsolute', (event) => { - // Some browsers expose absolute compass heading as webkitCompassHeading. - // Others expose alpha that needs conversion and screen-orientation compensation. - const getScreenOrientationAngle = () => { - if (window.screen?.orientation && typeof window.screen.orientation.angle === 'number') { - return window.screen.orientation.angle; - } - if (typeof window.orientation === 'number') { - return window.orientation; - } - return 0; - }; +const getScreenOrientationAngle = () => { + if (window.screen?.orientation && typeof window.screen.orientation.angle === 'number') { + return window.screen.orientation.angle; + } + if (typeof window.orientation === 'number') { + return window.orientation; + } + return 0; +}; - const getHeadingFromEvent = (orientationEvent) => { - if (typeof orientationEvent.webkitCompassHeading === 'number') { - return normalizeAngle(orientationEvent.webkitCompassHeading); - } - if (orientationEvent.alpha === null) { - return null; - } - // Convert alpha to compass-style heading (clockwise from North). - return normalizeAngle(360 - orientationEvent.alpha); - }; +const getHeadingFromEvent = (orientationEvent) => { + // iOS Safari: already compass heading of the top of the screen. + if (typeof orientationEvent.webkitCompassHeading === 'number') { + return normalizeAngle(orientationEvent.webkitCompassHeading); + } + if (orientationEvent.alpha === null) { + return null; + } + + // Generic alpha -> compass heading, then compensate screen rotation. + const alphaHeading = normalizeAngle(360 - orientationEvent.alpha); + return normalizeAngle(alphaHeading + getScreenOrientationAngle()); +}; + +let hasAbsoluteOrientation = false; + +window.addEventListener('deviceorientationabsolute', (event) => { const heading = getHeadingFromEvent(event); if (heading === null) return; - selfHeading = normalizeAngle(heading + getScreenOrientationAngle()); + hasAbsoluteOrientation = true; + selfHeading = normalizeAngle(heading + HEADING_CORRECTION_DEG); }); window.addEventListener('deviceorientation', (event) => { - const getScreenOrientationAngle = () => { - if (window.screen?.orientation && typeof window.screen.orientation.angle === 'number') { - return window.screen.orientation.angle; - } - if (typeof window.orientation === 'number') { - return window.orientation; - } - return 0; - }; - - const getHeadingFromEvent = (orientationEvent) => { - if (typeof orientationEvent.webkitCompassHeading === 'number') { - return normalizeAngle(orientationEvent.webkitCompassHeading); - } - if (orientationEvent.alpha === null) { - return null; - } - return normalizeAngle(360 - orientationEvent.alpha); - }; + if (hasAbsoluteOrientation) return; const heading = getHeadingFromEvent(event); if (heading === null) return; - selfHeading = normalizeAngle(heading + getScreenOrientationAngle()); + selfHeading = normalizeAngle(heading + HEADING_CORRECTION_DEG); }); const participantsRef = ref(db, `rooms/${roomId}/participants`); @@ -620,7 +608,7 @@ const render = () => { // Rotate the arrow toward the other participant and use their color. const dx = target.position.lon - selfParticipant.position.lon; const dy = target.position.lat - selfParticipant.position.lat; - const rawAngle = Math.atan2(dy, dx) * (180 / Math.PI) + 90; + const rawAngle = Math.atan2(dx, dy) * (180 / Math.PI); // Consider the heading of the device to rotate the arrow accordingly const targetAngle = normalizeAngle(rawAngle - selfHeading);