canvas+WebSocket(node.js)で画像にポインタを表示する[Firefox限定]

canvas上でマウスクリックしたポインタと背景画像を画像合成して,
WebSocketで送信するサンプルアプリを作成しました.
とりあえずFirefox限定です.

Chromeだと合成した画像が表示されません.
StackOverFlowでimg.onload = function() {}でイケると書いてありましたが,
動きませんでした.

動作

  • クライアント画面のcanvas上でマウスクリックをするとjpegの背景画像と,ポインタを表示する
  • マウスクリックをトリガに背景画像とポインタを合成して,WebSocketサーバに送信する
  • WebSocketサーバは受信した画像を全クライアントへブロードキャストする
  • 全クライアントからポインタ情報を送信可能

構成

  • WebSocketサーバ:node.js + ws
  • HTTPサーバ:node.js + express

WebSocketサーバ(localhost:8080) <-> Clients(Firefox) <-> HTTPサーバ(localhost:8080)

実行手順

  • コードを以下の通り配置する
/hoge
 SampleWebSocketServer.js
 SimpleWebSocketServer.js
/hoge/public
 SampleWebSocketCanvasClient.html
 backgtround.jpg
  • 2つのコンソールで以下を実行する
node SimpleWebSocket.js
node SimpleWebServer.js

Code

SimpleWebServer.js(HTTPサーバ)
var express = require("express"),
	app = express();

app.configure(function() {
	app.use(express.static(__dirname + "/public"));
});

app.use(express.logger("dev"));

app.listen(8000);
SampleWebSocketServer.js(WebSocketサーバ)
var WebSocketServer = require("ws").Server;
var clients = [];

function initialize() {

	wss = new WebSocketServer({port:8080});
	wss.on("connection", function(ws) {

		clients.push(ws);
		ws.on("message", function(data, flags) {
			var type;

			// Check binary
			if(flags.binary) {
				console.log("binary");
				type = "binary";
				broadcast(data, flags.binary);
			} else {
				console.log("text");
				type = "text";
				broadcast(data. flags.binary);
			}
		});

		// Broadcast
		function broadcast(data, flag) {
			clients.forEach(function (client, i) {
				client.send(data, {binary:flag, mask:false});
			});
		}

		ws.on("close", function() {
			console.log("disconnected");
			clients = clients.filter(function (client) {
				return (client === ws) ? false : true;
			});
		});
});
}

initialize();
SampleWebSocketCanvasClient.html(クライアント)
<!DOCTYPE HTML>
<html lang="ja-JP">
<head>
	<meta charset="UTF-8">
	<script type="text/javascript">

	// constant
	var canvasFrameEndX = 300;
	var canvasFrameEndY = 300;

	// canvas
	var canvas;
	var context;
	var saveImage;

	// global variables
	var img;
	var host = "ws://localhost:8080";
	var ws = new WebSocket(host);

	function initialize() {

		// DOM
		img = document.getElementById("img");
		canvas = document.getElementById("canvas");
		// Canvas context
		context  = canvas.getContext("2d");

		// 画像の読み込み
		canvas.addEventListener('mousedown', function(e) {
			clear();
			var x;
			var y;

			if(e.hasOwnProperty("offsetX")) {
				x = e.offsetX;
				y = e.offsetX;
			} else {
				// for Firefox
				x = e.layerX;
				y = e.layerY;
			}
			draw(x, y);
			
		}, false);

		// Canvas
		context.strokeStyle = '#FF0000';
		context.lineWidth = 5;
		context.strokeStyle ="";

		// WebSocket
		ws.onopen = function() {
			console.log("WebSocket connect");
			ws.onmessage = function(e) {
				if(e.data instanceof Blob) {
					console.log("blob");
					img.src =
						(URL || WebKit).createObjectURL(e.data);
				} else if(typeof e.data === "string") {
					console.log("string");
					console.log(e.data);
				}
			};
		};

	}
	function clear() {
		context.clearRect(0, 0, canvasFrameEndX, canvasFrameEndY);
	}
	function draw(x, y) {
		var background = new Image();
		background.src = "background.jpg";
		background.onload = function() {
			// img.onloadに入れても動かない
		};
		context.drawImage(background, 0, 0);		
		context.strokeRect(x, y, 50, 50);

		/***
		  canvas に絵を書くコード
		***/
		var type = 'image/png';
		// canvas から DataURL で画像を出力
		var dataurl = canvas.toDataURL(type);
		// DataURL のデータ部分を抜き出し、Base64からバイナリに変換
		var bin = atob(dataurl.split(',')[1]);
		// 空の Uint8Array ビューを作る
		var buffer = new Uint8Array(bin.length);
		// Uint8Array ビューに 1 バイトずつ値を埋める
		for (var i = 0; i < bin.length; i++) {
		  buffer[i] = bin.charCodeAt(i);
		}
		// Uint8Array ビューのバッファーを抜き出し、それを元に Blob を作る
		var blob = new Blob([buffer.buffer], {type: type});
		//console.log(blob);
		ws.send(blob);
	}

	window.addEventListener("load", initialize, false);
	</script>
	<title>canvas sample</title>
	<style type="text/css">
	#canvasdiv {
		width: 300px;
		border-style: solid;
		border-color: green;
	}
	#canvas {
		width: 300px;
		border-style: solid;
		border-color: red;
	}
	#recieveimage {
		width: 300px;
		border-style: solid;
		border-color: blue;
	}

	</style>
</head>
<body>
<div id="canvasdiv">
	<canvas id="canvas" width="300px" height="300px"></canvas>
</div>
overlay
<div id="recieveimage">
	<img src="data:image/jpeg,base64" id="img" width="300px"/>
</div>
</body>
</html>