4
8

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 5 years have passed since last update.

Socket.ioを使ってサーバーの画像が更新されたらブラウザ側も更新させるメモ

Last updated at Posted at 2017-09-10

画像ストリーミング表示っぽいものを作ってみます。

この辺りの続きです。 Node.js v8.4.0です

とりあえずポーリングで対応

フロント側のJavaScriptで定期的に画像を更新するようにします。
ctx.clearRect()ctx.beginPath()で描画をリセットできます。

(canvasあんまり触ってないから使い方怪しいかも)

public/app.js
'use strict';

const canvas = document.getElementById('myCanvas');
if(!canvas || !canvas.getContext) console.log('canvasが使えないよ');

const draw = () => {
    const ctx = canvas.getContext('2d');
    const img = new Image();
    img.src = `img.jpeg?date=${new Date()}`;
    img.onload = () => ctx.drawImage(img, 0, 0);
    return ctx;
}

document.body.addEventListener('click',draw);
setInterval(()=>{
    const ctx = draw();
    ctx.clearRect(0,0,640,600);
    ctx.beginPath();
    console.log('更新');
}, 5000);

img.srcのパス指定でimg.jpeg?date=${new Date()}としていますが、おなじパスだとブラウザによってはキャッシュされてしまうことがあるのでおなじパスにならないようにしてます。

この状態だと結構カクカクします。

CreateJSを利用して性能アップ

このカクカクする感じを解消しようと試してましたが、CreateJSを使ったらいい感じに表示されました。

index.html
<html>
<head>
    <meta charset="utf-8" />
    <title>Nefry BT Camera</title>
</head>

<body style="background-color:#D0D0D0;">
    <canvas id="myCanvas" width="640" height="480" style="background-color:#FFFFFF;"></canvas>
    <script src="https://code.createjs.com/easeljs-0.8.2.min.js"></script>
    <script src="/public/app.js"></script>
</body>
</html>

コードも結構短くなった。

public/app.js
'use strict';

const stage = new createjs.Stage('myCanvas');
const socket = io();

const draw = () => {
    const bmp = new createjs.Bitmap(`/img.jpeg?date=${new Date()}`);
    stage.addChild(bmp);
    createjs.Ticker.on('tick', () => stage.update());
    console.log(`update: ${new Date()}`);
}

setInterval(()=>draw(), 5000);

ICSさんの記事が参考になりました。

Socket.ioを使って画像変更を検知

現状だとポーリングなので余計なリクエストが発生してしまっています。

Socket.ioを使って画像変更を検知します。

↑の記事の続きなのでsocket.ioを追加でインストールします。

npm i --save socket.io
server.js
'use strict';

const fs = require('fs');
const app = require('express')();
const http = require('http').Server(app);
const io = require('socket.io')(http);
const express = require('express');
const PORT = process.env.PORT || 3000;
app.use(express.static(__dirname));

io.on('connection', (socket) => console.log('a user connected')); //socket.ioのコネクション

app.get('/', (req, res) => res.sendFile('./index.thml'));
app.post('/', (req, res) => {
    let buffers = [];
    let cnt = 0;

    req.on('data', (chunk) => {
        buffers.push(chunk);
        console.log(++cnt);
    });

    req.on('end', () => {
        console.log(`[done] Image upload`);
        req.rawBody = Buffer.concat(buffers);
        //書き込み
        fs.writeFile('./img.jpeg', req.rawBody, 'utf-8',(err) => {
            if(err) return;
            console.log(`[done] Image save`);
            io.sockets.emit('new message',{message: `[done] Image save`}); //画像が更新されたことを通知
        });
    });
});
 
http.listen(PORT, () => console.log(`listening on *:${PORT}`));
public/app.js
'use strict';

const stage = new createjs.Stage('myCanvas');
const socket = io();

const draw = () => {
    const bmp = new createjs.Bitmap(`/img.jpeg?date=${new Date()}`);
    stage.addChild(bmp);
    createjs.Ticker.on('tick', () => stage.update());
    console.log(`update: ${new Date()}`);
}

socket.on('new message', (msg) => draw());

draw(); //初期実行

サーバー側で画像の更新があったらnew messageのイベントが発火し、フロント側ではこのイベントをキャッチしたら画像の更新処理を行います。

これで画像がストリーム表示っぽくなりました。

所感

とりあえずカメラに写っている部屋などを外から監視する仕組みが作れそうです。
socket.ioで直接base64変換した画像データを送るみたいな機能も検討したいです。

4
8
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
4
8

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?