Canvas 实时绘制半透明线段

284 阅读1分钟

关于绘制半透明线段会遇到的问题可以参考 Canvas踩坑(1)实时透明线 - 掘金 (juejin.cn)

其中提到了两种实现方式, 此篇文章采用双层canvas(topCanvas, bottomCanvas)实现:

  1. 假设需要绘制0.5透明度的线段。绘制线段时, 在topCanvas绘制不透明线段, 同时设置 topCanvas css 为 opacity: 0.5。
  2. 当绘制完成, 设置 bottomCanvas.globalAlpha = 0.5 (如果实际情况复杂, 可以谨慎点在这之前加bottomCanvas.beginPath()), 然后将topCanvas绘制到bottomCanvas: bottomCtx.drawImage(topCanvas, 0, 0)
  3. 最后清空 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>