タッチデバイスで画面を押したときの圧力を Web ブラウザ + JavaScript で取得する

## 概要

- スマートフォンやタブレットの画面を押したときの強さを Web ブラウザで取得する
- Touch Events Level 2 という JavaScript API で圧力を取得する
- iPhone 等の感圧タッチ (3D Touch, Force Touch) に対応

## Touch Events Level 2
- タッチ関連で touchstart, touchend, touchmove, touchcancel というイベントが発生する
- イベント発生時に Touch インターフェースや TouchList インターフェースを利用することができる
- Touch.force で圧力を取得することができる (値は0.0〜1.0の間になる)
- 参考: [Touch Events \- Level 2](https://w3c.github.io/touch-events/)

## ソースコード

```html
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>Your touch device information</title>
<meta name="viewport" content="width=device-width,initial-scale=1.0">

<style>
  html, body, div { padding: 0; margin: 0; border 0; }
  html, body { width: 100%; height: 100%; }
</style>

<script>

// 表示領域をクリアする
function clear(id) {
  document.getElementById(id).textContent = "";
}

// 表示領域に情報を追加する
function add(id, key, value) {
  const e = document.createElement("div");
  document.getElementById(id).appendChild(e);
  e.textContent = key + "=[" + value + "]";
}

// ブラウザ情報を表示する
function set_info() {
  const keys = [
    "window.navigator.userAgent",
    "window.navigator.maxTouchPoints",
    "window.parent.screen.width",
    "window.parent.screen.height",
    "window.screen.width",
    "window.screen.height",
  ];
  for (var key of keys) {
    add("information-area", key, eval(key));
  }
}

// タッチデバイスの情報を表示する
function handle_touch(event) {
  clear("touch-area");
  try {
    for (var i=0; i<event.touches.length; i++) {
      var touch = event.touches.item(i);
      // Touch.force: 圧力を0.0〜1.0の値で取得する
      add("touch-area", "Touch[" + i + "].force", touch.force);
      add("touch-area", "Touch[" + i + "].clientX", touch.clientX);
      add("touch-area", "Touch[" + i + "].clientY", touch.clientY);
    }
  } catch(e) {
    add("touch-area", "error", e);
  }
}

window.onload = function() {
  set_info();
  // 画面に触れはじめたときのイベントに関数を登録
  document.body.addEventListener("touchstart", handle_touch);
  // 画面上で移動しているときのイベントに関数を登録
  document.body.addEventListener("touchmove", handle_touch);
};

</script>

</head>
<body>

<h1>Your touch device information</h1>

<div id="area">
  <div id="information-area"></div>
  <div id="touch-area"></div>
</div>

</body>
</html>
```

## いくつかのデバイスで挙動を確認する

### 挙動確認結果一覧

| 端末 | OS | Web ブラウザ | force 値が取得できるか | 備考 |
|------|------|------|----------|------|
|iPhone X|iOS 12|Safari|取得できる|3D Touch 搭載端末|
|iPhone X|iOS 12|Google Chrome|取得できる|3D Touch 搭載端末|
|iPhone X|iOS 13|Safari|取得できる|3D Touch 搭載端末|
|iPhone X|iOS 13|Google Chrome|取得できる|3D Touch 搭載端末|
|iPhone XR|iOS 12|Safari|常に force=0|3D Touch 非搭載端末|
|iPhone XS Max|iOS 12|Safari|取得できる|3D Touch 搭載端末|
|iPhone Pro 11|iOS 13|Safari|常に force=0|3D Touch 非搭載端末|
|iPhone Pro 11|iOS 13|Google Chrome|常に force=0|3D Touch 非搭載端末|
|iPad Pro (11-inch)|iOS 12|Safari|常に force=0|3D Touch 非搭載端末|
|iPad Pro (11-inch)<br>+ Apple Pencil|iOS 12|Safari|取得できる|3D Touch 非搭載端末だが、Apple Pencil を利用して圧力が取得できる|
|iPad Pro (11-inch)<br>+ Apple Pencil|iPadOS 13|Safari|取得できる|3D Touch 非搭載端末だが、Apple Pencil を利用して圧力が取得できる|
|iPad Pro (11-inch)<br>+ Apple Pencil|iPadOS 13|Google Chrome|取得できる|3D Touch 非搭載端末だが、Apple Pencil を利用して圧力が取得できる|
|Xperia XZ|Android 7.0|Google Chrome|取得できる| |

以下にいくつかスクリーンショット付きのサンプルを置いておく。

### iPhone X + iOS 12 + Safari

複数の指による圧力を取得できている。

![iphone-safari.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/139365/fcbf49b2-8a6c-a6ba-2fed-4dd0a020a7de.jpeg)

### Xperia XZ + Android 7.0 + Google Chrome

複数の指による圧力を取得できている。

![xperiaxz-android-chrome.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/139365/3a2c0c8e-6e90-ea5b-2807-721298ebb86f.jpeg)

### iPad Pro (11-inch) + iOS 12 + Safari

複数の指を認識しているが、圧力は取得できていない。
iPad Pro では指による Force Touch (3D Touch) が利用できないらしい。

![ipad-safari.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/139365/047e2f3a-3d4b-84a5-c5ce-9ebaa7d73d01.jpeg)

### iPad Pro (11-inch) + iOS 12 + Safari + Apple Pencil (2nd Generation)

Apple Pencil による圧力を取得できている。

![ipad-safari-pencil.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/139365/18f786b5-af6b-391c-8162-2347169df784.jpeg)

## 参考資料
- [Touch Events](https://www.w3.org/TR/touch-events/)
- [Touch Events \- Level 2](https://w3c.github.io/touch-events/)
- [Touch events \- Web API \| MDN](https://developer.mozilla.org/ja/docs/Web/API/Touch_events)