UNPKG

one

Version:

One is a React framework for web, iOS, and Android apps.

129 lines (126 loc) • 4.12 kB
import { validateListener } from "./validate.mjs"; const emptyAvailability = { accelerometer: false, gyroscope: false, magnetometer: false, deviceMotion: false }; const availability = { ...emptyAvailability }; const listeners = /* @__PURE__ */ new Set(); let observing = false; let attitude; function vector(x, y, z, scale = 1) { return [ x, y, z ].every((value) => typeof value === "number" && Number.isFinite(value)) ? { x: x * scale, y: y * scale, z: z * scale } : void 0; } function receive(event) { const total = event.accelerationIncludingGravity, linear = event.acceleration, rate = event.rotationRate; const acceleration = vector(total?.x, total?.y, total?.z, -1 / 9.80665); const user = vector(linear?.x, linear?.y, linear?.z, -1 / 9.80665); const rotation = vector(rate?.beta, rate?.gamma, rate?.alpha, Math.PI / 180); availability.accelerometer = !!acceleration; availability.gyroscope = !!rotation; availability.deviceMotion = !!user; const gravity = acceleration && user ? { x: acceleration.x - user.x, y: acceleration.y - user.y, z: acceleration.z - user.z } : void 0; for (const listener of [...listeners]) { if (!listeners.has(listener)) continue; const value = listener.sensor === "accelerometer" ? acceleration : listener.sensor === "gyroscope" ? rotation : listener.sensor === "deviceMotion" ? user : void 0; if (!value || event.timeStamp - listener.last < listener.intervalMs) continue; listener.last = event.timeStamp; const reading = { sensor: listener.sensor, timestampMs: performance.timeOrigin + event.timeStamp, value }; if (listener.sensor === "deviceMotion") Object.assign(reading, { gravity, userAcceleration: user, rotationRate: rotation, attitude }); listener.onReading(reading); } if (!listeners.size) stopObserving(); } function orient(event) { const a = event.alpha, b = event.beta, c = event.gamma; if (!vector(a, b, c)) { attitude = void 0; return; } const z = a * Math.PI / 180, x = b * Math.PI / 180, y = c * Math.PI / 180; attitude = { x: Math.atan2(Math.sin(x), Math.cos(x) * Math.cos(y)), y: Math.asin(Math.max(-1, Math.min(1, Math.cos(x) * Math.sin(y)))), z: Math.atan2(Math.sin(z) * Math.cos(y) + Math.cos(z) * Math.sin(x) * Math.sin(y), Math.cos(z) * Math.cos(y) - Math.sin(z) * Math.sin(x) * Math.sin(y)) }; } function stopObserving() { if (!observing) return; window.removeEventListener("devicemotion", receive); window.removeEventListener("deviceorientation", orient); observing = false; attitude = void 0; } function observe() { if (observing || typeof window === "undefined") return; observing = true; window.addEventListener("devicemotion", receive); window.addEventListener("deviceorientation", orient); } const Motion = Object.freeze({ getAvailability: () => { if (typeof window === "undefined" || !window.DeviceMotionEvent) return { ...emptyAvailability }; observe(); return { ...availability }; }, addListener: (sensor, intervalMs, onReading, onError) => { validateListener(sensor, intervalMs, onReading, onError); if (typeof window === "undefined") return () => {}; if (sensor === "magnetometer" || !window.DeviceMotionEvent) { onError("E_MOTION_UNAVAILABLE", "Motion.addListener: sensor is unavailable"); return () => {}; } observe(); const listener = { sensor, intervalMs, last: -Infinity, onReading, onError }; listeners.add(listener); const constructor = window.DeviceMotionEvent; if (constructor.requestPermission) { const fail = (message) => { if (!listeners.delete(listener)) return; if (!listeners.size) stopObserving(); onError("E_MOTION_PERMISSION", message); }; try { constructor.requestPermission().then((permission) => { if (permission !== "granted") fail("Motion.addListener: motion permission is required"); }).catch((error) => fail(String(error))); } catch (error) { fail(String(error)); } } return () => { listeners.delete(listener); if (!listeners.size) stopObserving(); }; } }); export { Motion }; //# sourceMappingURL=index.mjs.map