網頁感應器

使用 Generic Sensor API 取得裝置端感應器,例如加速計、陀螺儀和磁力儀。

Alex Shalamov
Alex Shalamov
Mikhail Pozdnyakov
Mikhail Pozdnyakov

如今,感應器資料已廣泛應用於許多平台專屬應用程式,用於沉浸式遊戲、健身追蹤,以及擴增或虛擬實境等用途。將特定平台和網頁應用程式之間的差距縮小,是不是很棒呢?輸入 Generic Sensor API,網頁版!

什麼是 Generic Sensor API?

Generic Sensor API 是一組介面,可將感應器裝置公開給網路平台。API 包含 Sensor 介面和一組具體的 感應器類別使用基礎介面可以簡化實作和規格 處理具體感應器類別的流程舉例來說,請查看 Gyroscope 類別。太小了!核心功能由基礎介面指定,而 Gyroscope 只會使用三個代表角速度的屬性擴充功能。

部分感應器類別介面能與實際的硬體感應器 (例如加速計或 陀螺儀類別。這些稱為低層級感應器。其他感應器 (稱為融合感應器) 會合併多個低階感應器的資料,以便提供指令碼原本需要計算的資訊。舉例來說,AbsoluteOrientation 感應器會根據從加速計、陀螺儀和磁力計取得的資料,提供可立即使用的四乘四旋轉矩陣。

您或許認為網路平台已經提供感應器資料,您絕對沒錯!舉例來說,DeviceMotionDeviceOrientation 事件會公開動作感應器資料。為什麼需要新的 API?

與現有的介面相比,通用感應器 API 提供許多優點:

  • 通用感應器 API 是一種感應器架構,可輕鬆透過新的感應器類別擴充,而每個類別都會保留通用介面。為一種感應器類型撰寫的用戶端程式碼 就能重複運用,只需做出極少的修改就好!
  • 您可以設定感應器。舉例來說,您可以設定適合應用程式需求的取樣頻率。
  • 你可以偵測平台上是否有感應器。
  • 感應器讀數具有高精確度的時間戳記,可與應用程式中的其他活動進行更佳同步。
  • 感應器資料模型和座標系統已明確定義,讓瀏覽器供應商能夠導入可互通的解決方案。
  • 以通用感應器為基礎的介面不會繫結至 DOM (也就是說,它們既不是 navigator 也不是 window 物件),這為日後在服務 worker 中使用 API,或在無頭 JavaScript 執行階段 (例如嵌入式裝置) 中實作 API 開啟了機會。
  • 安全性和隱私權是通用感應器 API 的首要考量,與舊版感應器 API 相比,通用感應器 API 提供更完善的安全性。 權限 API
  • 自動與螢幕座標保持同步: 適用於AccelerometerGyroscopeLinearAccelerationSensorAbsoluteOrientationSensorRelativeOrientationSensorMagnetometer

可用的一般感應器 API

在撰寫文章時,您可以運用多種感應器進行實驗,

動作感應器:

  • Accelerometer
  • Gyroscope
  • LinearAccelerationSensor
  • AbsoluteOrientationSensor
  • RelativeOrientationSensor
  • GravitySensor

環境感應器:

  • AmbientLightSensor (在 Chromium 的 #enable-generic-sensor-extra-classes 旗標後方)。
  • Magnetometer (Chromium 中 #enable-generic-sensor-extra-classes 標記後面)。

特徵偵測

硬體 API 的功能偵測相當棘手,因為您必須同時偵測瀏覽器是否支援相關介面,以及裝置是否具備對應的感應器。檢查瀏覽器是否支援介面很簡單。(將 Accelerometer 替換為上述提及的任何其他介面)。

if ('Accelerometer' in window) {
  // The `Accelerometer` interface is supported by the browser.
  // Does the device have an accelerometer, though?
}

為真正有意義的特徵偵測結果,你也需要嘗試與感應器連線。 以下範例說明如何執行這項操作。

let accelerometer = null;
try {
  accelerometer = new Accelerometer({ frequency: 10 });
  accelerometer.onerror = (event) => {
    // Handle runtime errors.
    if (event.error.name === 'NotAllowedError') {
      console.log('Permission to access sensor was denied.');
    } else if (event.error.name === 'NotReadableError') {
      console.log('Cannot connect to the sensor.');
    }
  };
  accelerometer.onreading = (e) => {
    console.log(e);
  };
  accelerometer.start();
} catch (error) {
  // Handle construction errors.
  if (error.name === 'SecurityError') {
    console.log('Sensor construction was blocked by the Permissions Policy.');
  } else if (error.name === 'ReferenceError') {
    console.log('Sensor is not supported by the User Agent.');
  } else {
    throw error;
  }
}

聚合物

如果瀏覽器不支援 Generic Sensor API, polyfill。polyfill 可讓您只載入相關感應器的實作項目。

// Import the objects you need.
import { Gyroscope, AbsoluteOrientationSensor } from './src/motion-sensors.js';

// And they're ready for use!
const gyroscope = new Gyroscope({ frequency: 15 });
const orientation = new AbsoluteOrientationSensor({ frequency: 60 });

這些感應器是什麼?如何使用這些報表?

感應器可能需要簡短的介紹。如果您熟悉感應器,可以直接跳至動手編碼專區。否則,請繼續閱讀,瞭解每個支援的感應器。

加速計和線性加速度感應器

加速計感應器測量結果

Accelerometer 感應器會在三個軸 (X、Y 和 Z) 上測量裝置的加速度。這種感應器是一種 慣性感應器,也就是當裝置處於自由下降狀態時, 加速速度為 0 m/s2,如果裝置平放在桌子上,則加速 向上方向 (Z 軸) 將等於地球重心,例如 × +9.8 m/s2 是測量將裝置向上推進的桌子有哪些力道如果將裝置推送到 右側,X 軸的加速度為正值;如果裝置加速 再往左方右移。

加速度計可用於計步、動作感應或簡單的裝置方向。在大多數的情況下,加速計測量會與其他來源的資料 建立融合感應器,例如方向感應器。

LinearAccelerationSensor 會測量套用至代管感應器的裝置加速度,不含重力影響。當裝置處於靜止狀態時 (例如平放在桌上),感應器會在三個軸上測量 ≈ 0 m/s2 的加速度。

重力感應器

使用者目前可透過下列方式手動取得靠近重力感應器的讀數 手動檢查 AccelerometerLinearAccelerometer 讀數,但這可能會很麻煩 並視這些感應器提供的值準確性而定。Android 這類平台 為作業系統提供重力讀數,應該比較低廉 並根據使用者的硬體提供更精確的值,也更容易用於 API 作業原則 GravitySensor 傳回效果 裝置 X、Y 和 Z 軸的加速度。

陀螺儀

陀螺儀感應器測量結果

Gyroscope 感應器會以每秒弧度為單位,測量裝置本地 X、Y 和 Z 軸的角速度。大多數消費性裝置都配備機械式 (MEMS) 陀螺儀,這是一種慣性感應器,可根據慣性科氏力測量旋轉率。MEMS 陀螺儀容易發生漂移,這是因為感應器的引力靈敏度會使感應器的內部機械系統變形。使用相對高頻率的陀螺儀,例如:因此,相較於其他感應器,可能會耗用更多電力。

方向感應器

絕對方向感應器測量結果

AbsoluteOrientationSensor 是融合感應器,可測量裝置相對於地球座標系統的旋轉角度,而 RelativeOrientationSensor 則會提供資料,代表裝置上動作感應器相對於靜止參考座標系統的旋轉角度。

所有現代 3D JavaScript 架構都支援四元數旋轉矩陣代表旋轉角度; 不過,如果直接使用 WebGL,就能輕鬆地在 OrientationSensorquaternion 資源populateMatrix() 方法。 以下提供部分程式碼片段:

three.js

let torusGeometry = new THREE.TorusGeometry(7, 1.6, 4, 3, 6.3);
let material = new THREE.MeshBasicMaterial({ color: 0x0071c5 });
let torus = new THREE.Mesh(torusGeometry, material);
scene.add(torus);

// Update mesh rotation using quaternion.
const sensorAbs = new AbsoluteOrientationSensor();
sensorAbs.onreading = () => torus.quaternion.fromArray(sensorAbs.quaternion);
sensorAbs.start();

// Update mesh rotation using rotation matrix.
const sensorRel = new RelativeOrientationSensor();
let rotationMatrix = new Float32Array(16);
sensor_rel.onreading = () => {
  sensorRel.populateMatrix(rotationMatrix);
  torus.matrix.fromArray(rotationMatrix);
};
sensorRel.start();

BABYLON

const mesh = new BABYLON.Mesh.CreateCylinder('mesh', 0.9, 0.3, 0.6, 9, 1, scene);
const sensorRel = new RelativeOrientationSensor({ frequency: 30 });
sensorRel.onreading = () => mesh.rotationQuaternion.FromArray(sensorRel.quaternion);
sensorRel.start();

WebGL

// Initialize sensor and update model matrix when new reading is available.
let modMatrix = new Float32Array([1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1]);
const sensorAbs = new AbsoluteOrientationSensor({ frequency: 60 });
sensorAbs.onreading = () => sensorAbs.populateMatrix(modMatrix);
sensorAbs.start();

// Somewhere in rendering code, update vertex shader attribute for the model
gl.uniformMatrix4fv(modMatrixAttr, false, modMatrix);

方向感應器可用於各種用途,例如沉浸式遊戲、擴增和虛擬實境。

如要進一步瞭解動作感應器、進階用途和相關規定,請參閱動作感應器說明文件

與螢幕座標同步

根據預設,系統會解析空間感應器的讀數 會有一個與裝置繫結的本機座標系統,不會將螢幕方向轉換成 讓他們使用服務帳戶

裝置座標系統
裝置座標系統

不過,許多用途 (例如遊戲或擴增和虛擬實境) 都需要在與螢幕方向綁定的座標系統中解析感應器讀數。

螢幕座標系統
螢幕座標系統

先前,將感應器讀數重新對應至螢幕座標時,必須在 JavaScript 中實作。 這種做法效率低落,而且還大幅增加了網路的複雜度 應用程式程式碼;網頁應用程式必須觀察螢幕方向變更並執行座標 感應器讀數的變換速度,這對歐拉角或感應器來說不是件容易的事 四元數

Generic Sensor API 提供更簡單可靠的解決方案!當地座標系統可針對所有定義的空間感應器類別進行設定:AccelerometerGyroscopeLinearAccelerationSensorAbsoluteOrientationSensorRelativeOrientationSensorMagnetometer。透過將 referenceFrame 選項傳遞至感應器物件建構函式,使用者 會定義傳回的讀數是否會解析為 裝置screen 座標。

// Sensor readings are resolved in the Device coordinate system by default.
// Alternatively, could be RelativeOrientationSensor({referenceFrame: "device"}).
const sensorRelDevice = new RelativeOrientationSensor();

// Sensor readings are resolved in the Screen coordinate system. No manual remapping is required!
const sensorRelScreen = new RelativeOrientationSensor({ referenceFrame: 'screen' });

開始編寫程式碼吧!

通用感應器 API 非常簡單易用!Sensor 介面提供 start()stop() 方法,用於控制感應器狀態,以及多個事件處理常式,用於接收感應器啟用、錯誤和新可用讀數的通知。具體的感應器類別通常會將特定的讀數屬性新增至基底 類別

開發環境

在開發期間,您可以透過 localhost 使用感應器。如果您是為 行動裝置, 設定 通訊埠轉送 ,就可以開始使用!

程式碼準備就緒後,請將程式碼部署至支援 HTTPS 的伺服器。 GitHub Pages 是透過 HTTPS 提供,因此非常適合用來分享示範。

3D 模型旋轉

在這個簡單的範例中,我們會使用絕對方向感應器的資料,修改 3D 模型的旋轉四元數。model 是具有 quaternion 屬性的 three.js Object3D 類別例項。 下方的程式碼片段 螢幕方向手機 示範,示範如何利用絕對方向感應器旋轉 3D 模型。

function initSensor() {
  sensor = new AbsoluteOrientationSensor({ frequency: 60 });
  sensor.onreading = () => model.quaternion.fromArray(sensor.quaternion);
  sensor.onerror = (event) => {
    if (event.error.name == 'NotReadableError') {
      console.log('Sensor is not available.');
    }
  };
  sensor.start();
}

裝置的方向會反映在 WebGL 場景中的 3D model 旋轉。

感應器更新 3D 模型的方向
感應器更新 3D 模型的方向

Punchmeter

以下程式碼片段是從punchmeter 示範中擷取,說明如何在假設裝置一開始處於靜止狀態的情況下,使用線性加速度感應器來計算裝置的最高速度。

this.maxSpeed = 0;
this.vx = 0;
this.ax = 0;
this.t = 0;

/* … */

this.accel.onreading = () => {
  let dt = (this.accel.timestamp - this.t) * 0.001; // In seconds.
  this.vx += ((this.accel.x + this.ax) / 2) * dt;

  let speed = Math.abs(this.vx);

  if (this.maxSpeed < speed) {
    this.maxSpeed = speed;
  }

  this.t = this.accel.timestamp;
  this.ax = this.accel.x;
};

計算的目前速度是加速度函數積分的近似值。

用於測量運算速度的網頁應用程式
衝高速度的測量

使用 Chrome 開發人員工具覆寫及覆寫感應器

在某些情況下,您不必使用實體裝置就能操作通用感應器 API。Chrome 開發人員工具可提供模擬裝置方向的絕佳支援。

Chrome 開發人員工具,用於覆寫虛擬手機的自訂方向資料
使用 Chrome 開發人員工具模擬裝置螢幕方向

隱私權與安全性

感應器讀取資料屬於機密資料,可能會受到惡意網頁的各種攻擊影響。 實作通用感應器 API 會強制執行幾項限制,以降低潛在的安全性 和隱私權風險有意使用 API 的開發人員必須考量這些限制,因此讓我們簡單列出這些限制。

僅限 HTTPS

由於 Generic Sensor API 是強大的功能,瀏覽器只能在安全的情況下使用。換句話說,如要使用 Generic Sensor API,您必須透過 HTTPS 存取網頁。在開發期間,您可以透過 http://localhost 執行這項操作,但在實際工作環境中 你的伺服器必須採用 HTTPS如需最佳做法和指南,請參閱安全無虞系列。

權限政策整合

通用感應器 API 中的權限政策整合功能,可控管影格感應器資料的存取權。

根據預設,Sensor 物件只能在主框架或同源子框架中建立,因此可防止跨來源 iframe 未經授權就讀取感應器資料。這項預設行為 即可直接啟用或停用對應的項目 政策控管功能

下方程式碼片段說明如何授予跨來源 iframe 的加速計資料存取權。 現在可以在這裡建立 AccelerometerLinearAccelerationSensor 物件

<iframe src="https://third-party.com" allow="accelerometer" />

感應器讀取資料功能可暫停傳送

您只能透過可見的網頁存取感應器讀數,亦即使用者實際瀏覽網頁時 能有效回應內容此外,就算使用者 焦點變更為跨來源子頁框這可避免父項框架推斷使用者輸入內容。

後續步驟

目前有一組指定的感應器類別可在近期內實作,例如: 環境光度感應器鄰近感應器;但多虧了強大的 通用感應器架構我們預期,會有更多的新類別代表各種不同的類別 感應器類型

未來另一個重要的工作領域,是改善通用感應器 API 本身。通用感應器規格目前是候選推薦規格,也就是說,我們仍有時間進行修正,並提供開發人員需要的新功能。

您可以提供協助!

感應器規格已達到候選推薦的成熟度,因此非常歡迎網頁和瀏覽器開發人員提供意見回饋。請告訴我們您認為哪些功能很適合加入,或是您想修改目前 API 中的哪些內容。

也歡迎您提出規格問題 視為 Chrome 實作的錯誤

資源

特別銘謝

本文由 Joe MedleyKayce Basques 審查。主頁橫幅製作者: Misko (來源:) Wikimedia Commons