画像ストリーミング表示っぽいものを作ってみます。
この辺りの続きです。 Node.js v8.4.0
です
とりあえずポーリングで対応
フロント側のJavaScriptで定期的に画像を更新するようにします。
ctx.clearRect()
とctx.beginPath()
で描画をリセットできます。
(canvasあんまり触ってないから使い方怪しいかも)
'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を使ったらいい感じに表示されました。
<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>
コードも結構短くなった。
'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
'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}`));
'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変換した画像データを送る
みたいな機能も検討したいです。