💬

ローカルサーバでスマートフォンブラウザから端末の向きを検出する

2022/08/29に公開

結論から

httpsサーバじゃないといけない

カメラを利用するのにも必要だったので、以前の記事を参考に

https://qiita.com/tkyko13/items/1871d906736ac88a1f35

$ openssl req -newkey rsa:2048 -new -nodes -x509 -days 3650 -keyout key.pem -out cert.pem

で、鍵作ったあと

$ http-server -S -C cert.pem

or

server.js
const fs = require('fs')
const express = require('express');
const app = express();
const https = require('https');
const options = {
  key:  fs.readFileSync('./key.pem'),
  cert: fs.readFileSync('./cert.pem')
};
const server = https.createServer(options, app);
const PORT = process.env.PORT || 3000;

// ルート
app.get('/' , function(req, res){
    res.sendFile(__dirname+'/public/index.html');
});

// サーバの立ち上げ
server.listen(PORT, () => {
  console.log('listening on https://localhost:' + PORT);
});

動作した環境

  • iOS15.6.1(iPhone8)
    • safari
    • chrome
  • Android12(Pixel 6a)
    • chrome
  • Node.js v16.15.1
    • express v4.18.1

スマートフォンブラウザで向き取得するための参考サイト

https://developer.mozilla.org/ja/docs/Web/Events/Detecting_device_orientation

https://qiita.com/kob58im/items/17059ab51dc93503994b

https://openprocessing.org/sketch/1156927

ここらへんだけを見るとすぐ使えそうに思えたけども、コードコピペしてもローカルサーバだとこんなエラー

IMG_3488.PNG

CodePenやOpenProcessingなんかだとうまくいく

あと、Netlifyにアップしたらうまくできたし、たぶんGitHub pagesでもできると思う

が、今回動作させたい環境でインターネット使えるか怪しかったので、ローカルサーバで動作させてみたかった

注意点

ローカルサーバ関係ないが、スマフォの向き情報を取得するための許可をもらうための処理の

//. ユーザーに「許可」を求めるダイアログを表示
          DeviceOrientationEvent.requestPermission().then(function (response) {
            if (response === 'granted') {
              // 許可
            }
          }).catch(function (e) {
            alert(e);
            console.error(e);
          });

この処理は、ボタンクリックした後に処理します

サンプルコード集

p5jsを使って画面に傾きをテキスト表示

<!DOCTYPE html>
<html lang="en">

<head>
  <meta charset="UTF-8">
  <meta http-equiv="X-UA-Compatible" content="IE=edge">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>スマフォ向き取得テスト</title>
</head>

<body>

  <button id="btn">クリック</button>

  <ul>
    <li id="rx"></li>
    <li id="ry"></li>
    <li id="rz"></li>
  </ul>

  <script src="https://cdnjs.cloudflare.com/ajax/libs/p5.js/1.4.2/p5.min.js"></script>
  <script>
    function setup() {
      frameRate(10);

      select('#btn').mousePressed(() => {
        if (window.DeviceOrientationEvent) {
          //. ユーザーに「許可」を求めるダイアログを表示
          DeviceOrientationEvent.requestPermission().then(function (response) {
            if (response === 'granted') {
              // 許可
              select('#btn').hide();
            }
          }).catch(function (e) {
            alert(e);
            console.error(e);
          });
        }
      });
    }

    function draw() {
      const rx = round(rotationX * 100) / 100;
      const ry = round(rotationY * 100) / 100;
      const rz = round(rotationZ * 100) / 100;
      select('#rx').html(rx);
      select('#ry').html(ry);
      select('#rz').html(rz);
    }

  </script>
</body>

</html>

p5jsだと許可もらったあとは rotationX で扱えます

その他は、こちら

socket.ioでサーバに共有

サーバ側(Node.js)

npm i socket.io express
const fs = require('fs')
const express = require('express');
const app = express();
const path = require('path');
const https = require('https');
const options = {
  key:  fs.readFileSync('./key.pem'),
  cert: fs.readFileSync('./cert.pem')
};
const server = https.createServer(options, app);
const io = require('socket.io')(server);
const PORT = process.env.PORT || 3000;

// app.get('/', express.static(path.join(__dirname, '/public/index.html')));
app.get('/' , function(req, res){
    res.sendFile(__dirname+'/public/index.html');
});
// app.use('/public', express.static(path.join(__dirname, '/public')));

io.on('connection',function(socket){
    socket.on('rotation',function(rot){
        console.log('rx:' + rot.x + ',  ry:'+rot.y+',  rz:'+rot.z);
    });
});

// サーバの立ち上げ
server.listen(PORT, () => {
  console.log('listening on https://localhost:' + PORT);
});

クライアント側(html,js)

index.html
<!DOCTYPE html>
<html lang="en">

<head>
  <meta charset="UTF-8">
  <meta http-equiv="X-UA-Compatible" content="IE=edge">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <style>
    html, body {
      margin: 0;
      padding: 0;
    }
    canvas {
      display: block;
    }
  </style>
  <title>スマフォ向き取得テスト</title>
</head>

<body>
  <script src="/socket.io/socket.io.js"></script>
  <script src="https://cdnjs.cloudflare.com/ajax/libs/p5.js/1.4.2/p5.min.js"></script>
  <script>
    const socket = io();

    let rots = {};
    let textArea;

    function setup() {
      if (DeviceOrientationEvent && DeviceOrientationEvent.requestPermission) {
        const btn = createButton('クリックして許可', () => {
          //. ユーザーに「許可」を求めるダイアログを表示
          DeviceOrientationEvent.requestPermission().then(function (response) {
            if (response === 'granted') {
              // 許可
              btn.hide();
            }
          }).catch(function (e) {
            alert(e);
            console.error(e);
          });
        });
      }

      // createCanvas(windowWidth, windowHeight);
      textArea = createElement('textArea');
      textArea.position(10, 10);
      textArea.style('width:95%;height:95vh');

      socket.on('rotation', (rot) => {
        // console.log(rot);
        rots[rot.id] = rot;
      });
    }

    function draw() {
      textArea.html(JSON.stringify(rots, null, ' '));
    }

    function deviceMoved() {
      const rx = round(rotationX * 100) / 100;
      const ry = round(rotationY * 100) / 100;
      const rz = round(rotationZ * 100) / 100;
      socket.emit('rotation', {
        x: rx,
        y: ry,
        z: rz
      });
    }

  </script>
</body>

</html>

p5jsだと、デバイス端末が動いたときだけ送るってこともできます

Discussion