Posted at

canvasで半透明な線を書く方法

More than 3 years have passed since last update.

いろいろ検索してみたけど、canvasで半透明な線を書く方法が見つからなかったので、透明な線が引けるお絵かきツールのソースを読んでまとめました。


方法その1

var last_image, pos, down = false;

var canvas;
var ctx = canvas.getContext('2d');
var getPos = function(evt) {
var rect = canvas.getBoundingClientRect();
return {
x: (evt.clientX - rect.left),
y: (evt.clientY - rect.top)
};
};

canvas.addEventListener('mousedown', function (e) {
down = true;
last_image = ctx.getImageData(0, 0, canvas.width, canvas.height);
ctx.beginPath();
pos = getPos(e);
ctx.moveTo(pos.x, pos.y);
}, false);
window.addEventListener('mousemove', function (e) {
if (!down) return;
ctx.putImageData(last_image, 0, 0);
pos = getPos(e);
ctx.lineTo(pos.x, pos.y);
ctx.stroke();
}, false);
window.addEventListener('mouseup', function (e) {
if (!down) return;
ctx.putImageData(last_image, 0, 0);
pos = getPos(e);
ctx.lineTo(pos.x, pos.y);
ctx.stroke();
ctx.closePath();
down = false;
}, false);

この方法は、canvasの状態を保存しておいて、mousemoveで次の線を引く時に保存しておいたcanvasに戻してから引き直すといった方法です。

canvasを元の状態に戻しても、pathはそのままなので描き始めから半透明で書くことができます。

canvasを一つしか使いたくない場合はこの方法がオススメです。


方法その2

var last_image, pos, down = false, last_pos;

var myCanvas, mainCanvas;
var myCtx = myCanvas.getContext('2d');
var mainCtx = mainCanvas.getContext('2d');

var getPos = function(evt) {
var rect = mainCanvas.getBoundingClientRect();
return {
x: (evt.clientX - rect.left),
y: (evt.clientY - rect.top)
};
};

mainCanvas.addEventListener('mousedown', function (e) {
down = true;
myCtx.clearRect(0, 0, myCanvas.width, myCanvas.height);
myCtx.save();
last_image = mainCtx.getImageData(0, 0, mainCanvas.width, mainCanvas.height);

last_pos = getPos(e);
mainCtx.globalAlpha = myCtx.globalAlpha;
myCtx.globalAlpha = 1.0;
}, false);
window.addEventListener('mousemove', function (e) {
if (!down) return;
myCtx.beginPath();
myCtx.moveTo(last_pos.x, last_pos.y);
last_pos = getPos(e);
myCtx.lineTo(last_pos.x, last_pos.y);
myCtx.closePath();
myCtx.stroke();

mainCtx.putImageData(last_image, 0, 0);
mainCtx.drawImage(myCanvas, 0, 0);
}, false);
window.addEventListener('mouseup', function (e) {
if (!down) return;
myCtx.beginPath();
myCtx.moveTo(last_pos.x, last_pos.y);
last_pos = getPos(e);
myCtx.lineTo(last_pos.x, last_pos.y);
myCtx.stroke();
myCtx.closePath();
myCtx.restore();

mainCtx.save();
mainCtx.putImageData(last_image, 0, 0);
mainCtx.drawImage(myCanvas, 0, 0);
mainCtx.restore();

down = false;
}, false);

この方法は、その1を少し応用したもので、描画用のcanvasに描いて、それを表示用に半透明にしてコピーするといった感じです。

canvasが2つ必要ですが、一筆の間に色や太さを帰ることができるメリットがあります。


まとめ

一筆で半透明な線を書くには、一旦canvasを保存しておいて、描画するたびに元に戻す作業が必要みたいです。(?)