網頁感應器

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

Alex Shalamov
Alex Shalamov
Mikhail Pozdnyakov
Mikhail Pozdnyakov

現今許多特定平台的應用程式都使用感應器資料,以實現各種用途,例如 身歷其境的遊戲、健身追蹤,以及擴增或虛擬實境。適合全家人使用嗎? 平台專屬和網頁應用程式之間的差異?輸入 Generic Sensor API,網頁版!

什麼是 Generic Sensor API?

Generic Sensor API 是一組介面 感應器裝置連線至網路平台。API 包含 Sensor 介面和一組具體的 感應器類別使用基礎介面可以簡化實作和規格 處理具體感應器類別的流程例如,看看 Gyroscope 類別。太小了! 核心功能是由基本介面指定,而 Gyroscope 只是透過三個 屬性。

部分感應器類別介面能與實際的硬體感應器 (例如加速計或 陀螺儀類別。這些稱為低階感應器。其他感應器,以下稱為 fusion 感應器,合併低階資料 感應器來公開指令碼需要計算的資訊。舉例來說, AbsoluteOrientation 感應器 提供立即可用的四張四輪旋轉矩陣,其資料是以 加速計、陀螺儀和磁力儀。

您或許認為網路平台已經提供感應器資料,您絕對沒錯!適用對象 執行個體、DeviceMotionDeviceOrientation。 事件暴露出動作感應器資料。為什麼需要新的 API?

相較於現有介面,Generic Sensor API 提供許多好處:

  • Generic Sensor API 是感應器架構,可以運用新的感應器類別輕鬆擴充,並 每個類別會保留一般介面為一種感應器類型撰寫的用戶端程式碼 就能重複運用,只需做出極少的修改就好!
  • 您可以設定感應器。舉例來說,您可以設定合適的取樣頻率 應用程式需求
  • 你可以偵測平台上是否有感應器。
  • 感應器讀取資料有高精度的時間戳記,可更有效地同步處理與其他資料 應用程式中的活動。
  • 感應器資料模型和座標系統明確定義,可讓瀏覽器廠商 並實作互通的解決方案
  • 一般感應器介面未繫結至 DOM (也就是說,這些介面不是 navigator) 而非 window 物件),未來開創在服務中使用 API 的機會 或在無頭 JavaScript 執行階段 (如嵌入式) 中實作 裝置。
  • 一般感應器優先考量安全性和隱私權 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 陀螺儀 避免感應器的重力敏感度降低感應器的靈敏度 內部機械系統使用相對高頻率的陀螺儀,例如:10 秒 kHz 因此比起其他感應器,耗電量可能會更高。

螢幕方向感應器

絕對方向感應器測量結果

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' });

編寫程式碼吧!

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

開發環境

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

程式碼準備就緒後,請將程式碼部署至支援 HTTPS 的伺服器。 GitHub 頁面採用 HTTPS,因此非常適合用來分享 示範。

3D 模型旋轉

在這個簡單的範例中,我們使用絕對方向感應器資料來修改旋轉角度 3D 模型的四元數model 是 Three.js 含有標籤的 Object3D 類別例項 quaternion 屬性。 下方的程式碼片段 螢幕方向手機 示範,示範如何利用絕對方向感應器旋轉 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 示範 說明如何使用線性加速感應器計算測溫 裝置的初始狀態會保持不變。

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 開發人員工具覆寫及覆寫感應器

在某些情況下,您不需要實體裝置就能使用 Generic Sensor API。Chrome 開發人員工具 都非常支持 模擬裝置螢幕方向

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

隱私權與安全性

感應器讀取資料屬於機密資料,可能會受到惡意網頁的各種攻擊影響。 實作通用感應器 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" />

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

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

後續步驟

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

未來工作的另一個重要領域是改善 Generic Sensor API 本身,也就是一般 感應器規格目前為候選建議,這表示還來得及時間 加以修正,並提供開發人員需要的新功能。

讓我們來幫忙!

感應器規格已達上限 候選建議 因此非常感謝網路和瀏覽器開發人員提供的意見。我們 知道哪些功能適合新增 或是有什麼需要修改 現有 API。

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

資源

特別銘謝

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