关于绘制半透明线段会遇到的问题可以参考 Canvas踩坑(1)实时透明线 - 掘金 (juejin.cn)
其中提到了两种实现方式, 此篇文章采用双层canvas(topCanvas, bottomCanvas)实现:
- 假设需要绘制0.5透明度的线段。绘制线段时, 在topCanvas绘制不透明线段, 同时设置 topCanvas css 为 opacity: 0.5。
- 当绘制完成, 设置
bottomCanvas.globalAlpha = 0.5(如果实际情况复杂, 可以谨慎点在这之前加bottomCanvas.beginPath()), 然后将topCanvas绘制到bottomCanvas:bottomCtx.drawImage(topCanvas, 0, 0) - 最后清空 topCanvas
以下是完整代码:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>双层canvas绘制半透明实时线</title>
</head>
<body>
<div
style="
position: absolute;
top: 0;
left: 0;
border: 1px solid black;
z-index: 0;
"
>
<canvas
id="bottomCanvas"
width="5000"
height="5000"
style="position: absolute; top: 0; left: 0; z-index: 0"
></canvas>
<canvas
id="topCanvas"
width="5000"
height="5000"
style="position: relative; z-index: 1; opacity: 0"
></canvas>
</div>
<input
id="opacity"
type="number"
style="position: relative; z-index: 1"
value="1"
title="设置透明度"
/>
</body>
<script>
window.onload = () => {
const bottomCanvas = document.getElementById("bottomCanvas");
const bottomCtx = bottomCanvas.getContext("2d");
const topCanvas = document.getElementById("topCanvas");
const topCtx = topCanvas.getContext("2d");
const opacityEle = document.getElementById("opacity");
let isDrawing = false;
topCtx.lineWidth = 5;
topCanvas.addEventListener("mousedown", (e) => {
isDrawing = true;
const opacity = parseFloat(opacityEle.value);
topCtx.beginPath();
topCtx.moveTo(e.clientX, e.clientY);
topCanvas.setAttribute(
"style",
`position: relative; z-index: 1;opacity: ${opacity};`
);
});
window.addEventListener("mousemove", (e) => {
if (!isDrawing) return;
topCtx.lineTo(e.clientX, e.clientY);
topCtx.stroke();
});
window.addEventListener("mouseup", () => {
if (!isDrawing) return;
const opacity = parseFloat(opacityEle.value);
bottomCtx.globalAlpha = opacity;
bottomCtx.drawImage(topCanvas, 0, 0);
topCtx.clearRect(0, 0, 5000, 5000);
isDrawing = false;
});
};
</script>
</html>