JSFiddle - React, Tailwind, and code Playground
HTML
<h1>Draw stroke on HTML canvas with different levels of opacity</h1>
<h2>Desired result</h2>
<img src="http://goo.gl/SJjL5U" />
<h2>Non-solution 1, 'darken' blend mode, opaque pixels</h2>
<canvas id="cv-darken-opaque" width="280" height="80"></canvas>
<h2>Non-solution 1, 'darken' blend mode, transparent pixels</h2>
<canvas id="cv-darken-transparent" width="280" height="80"></canvas>
<h2>Non-solution 2, 'destination-out' compositing operator</h2>
<canvas id="cv-destination-out" width="280" height="80"></canvas>
CSS
canvas {
display: block;
}
h1 {
font-family: Arial, sans-serif;
font-size: 14px;
}
h2 {
font-family: Arial, sans-serif;
font-size: 12px;
}
JavaScript
var lineDarkenOpaque = function (cx, x0, y0, x1, y1, a) {
var r, g, b;
r = Math.round(a * 0 + 1 * 255 * (1 - a));
g = Math.round(a * 0 + 1 * 255 * (1 - a));
b = Math.round(a * 255 + 1 * 255 * (1 - a));
cx.strokeStyle = 'rgb(' + r + ',' + g + ',' + b + ')';
cx.globalCompositeOperation = 'darken';
console.log(cx.strokeStyle);
cx.beginPath();
cx.moveTo(x0, y0);
cx.lineTo(x1, y1);
cx.stroke();
};
var lineDarkenTransparent = function (cx, x0, y0, x1, y1, a) {
cx.strokeStyle = 'rgba(0,0,255,' + a + ')';
cx.globalCompositeOperation = 'darken';
console.log(cx.strokeStyle);
cx.beginPath();
cx.moveTo(x0, y0);
cx.lineTo(x1, y1);
cx.stroke();
};
var lineDestinationOut = function (cx, x0, y0, x1, y1, a) {
cx.strokeStyle = 'rgba(0,0,255,' + a + ')';
cx.globalCompositeOperation = 'destination-out';
console.log(cx.strokeStyle);
cx.beginPath();
cx.moveTo(x0, y0);
cx.lineTo(x1, y1);
cx.stroke();
cx.strokeStyle = 'rgba(0,0,255,' + a + ')';
cx.globalCompositeOperation = 'source-over';
console.log(cx.strokeStyle);
cx.beginPath();
cx.moveTo(x0, y0);
cx.lineTo(x1, y1);
cx.stroke();
};
var runTest = function (canvasId, lineFn) {
var cv, cx;
cv = document.getElementById(canvasId);
cx = cv.getContext('2d');
cx.lineCap = 'round';
cx.lineJoin = 'round';
cx.lineWidth = 40;
lineFn(cx, 20, 20, 100, 20, 0.4);
lineFn(cx, 100, 20, 180, 20, 0.1);
lineFn(cx, 180, 20, 260, 20, 0.4);
lineFn(cx, 260, 20, 220, 60, 0.1);
};
runTest('cv-darken-opaque', lineDarkenOpaque);
runTest('cv-darken-transparent', lineDarkenTransparent);
runTest('cv-destination-out', lineDestinationOut);