代码之家  ›  专栏  ›  技术社区  ›  Julius Dzidzevičius

HTML5画布-无法在掩码上应用源代码

  •  0
  • Julius Dzidzevičius  · 技术社区  · 7 年前

    对不起,我是画布新手,不知道如何用谷歌搜索出来。问题是,若前一层(夜空)存在,我无法在遮罩上绘制。

    以下是两个片段:

    const canvas = document.querySelector('#board canvas');
        const ctx = canvas.getContext('2d');
        const { width: w, height: h } = canvas;
    
        // first layer
    
        ctx.fillStyle = 'black';
        ctx.fillRect(0, 0, w, h);
        ctx.fillStyle = '#555';
    
        let x, y, radius;
        for (let i = 0; i < 550; i++) {
          x = Math.random() * w;
          y = Math.random() * h;
          radius = Math.random() * 3;
          ctx.beginPath();
          ctx.arc(x, y, radius, 0, Math.PI * 2, false);
          ctx.fill();
        }
        
        // destination
    
        ctx.font = 'bold 70pt monospace';
        ctx.fillStyle = 'black';
        ctx.fillText('FOO', 10, 60);
        ctx.fillText('BAR', 10, 118);
        ctx.fill();
        
        // source 
    
        ctx.globalCompositeOperation = 'source-atop';
    
        for (let i = 0; i < 6; i++) {
          ctx.fillStyle = `hsl(${i * (250 / 6)}, 90%, 55%)`;
          ctx.fillRect(0, i * 20, 200, 20);
        }
    <div id="board">
      <canvas width="640" height="480"></canvas>
    
    </div>

    预期结果 (但第一层是夜空):

    const canvas = document.querySelector('#board canvas');
        const ctx = canvas.getContext('2d');
        const { width: w, height: h } = canvas;
        
        // destination
    
        ctx.font = 'bold 70pt monospace';
        ctx.fillStyle = 'black';
        ctx.fillText('FOO', 10, 60);
        ctx.fillText('BAR', 10, 118);
        ctx.fill();
        
        // source 
    
        ctx.globalCompositeOperation = 'source-atop';
    
        for (let i = 0; i < 6; i++) {
          ctx.fillStyle = `hsl(${i * (250 / 6)}, 90%, 55%)`;
          ctx.fillRect(0, i * 20, 200, 20);
        }
    <div id="board">
      <canvas width="640" height="480"></canvas>
    </div>
    1 回复  |  直到 7 年前
        1
  •  2
  •   Kaiido NickSlash    7 年前
    • 合成将影响整个上下文。
    • source-atop 模式将仅在存在现有像素的位置绘制(即仅在alpha>0的位置)。
    • 绘制背景时,上下文的所有像素的alpha值都设置为1。

    这意味着source Top不会在完全不透明的图像上生成任何内容。

    一旦您理解了这些要点,很明显您需要单独进行合成。
    例如,可以在不同的屏幕外画布上绘制,然后使用该画布在主画布上绘制 ctx.drawImage(canvas, x, y) .

    const canvas = document.querySelector('#board canvas');
    const ctx = canvas.getContext('2d');
    const {
      width: w,
      height: h
    } = canvas;
    
    // background
    ctx.fillStyle = 'black';
    ctx.fillRect(0, 0, w, h);
    ctx.fillStyle = '#555';
    
    let x, y, radius;
    for (let i = 0; i < 550; i++) {
      x = Math.random() * w;
      y = Math.random() * h;
      radius = Math.random() * 3;
      ctx.beginPath();
      ctx.arc(x, y, radius, 0, Math.PI * 2, false);
      ctx.fill();
    }
    
    
    // text compositing on an off-screen context
    const ctx2 = Object.assign(document.createElement('canvas'), {
        width: 200,
        height: 120
      }).getContext('2d');
    // text
    ctx2.font = 'bold 70pt monospace';
    ctx2.fillStyle = 'black';
    ctx2.fillText('FOO', 10, 60);
    ctx2.fillText('BAR', 10, 118);
    
    ctx2.globalCompositeOperation = 'source-atop';
    // rainbow
    for (let i = 0; i < 6; i++) {
      ctx2.fillStyle = `hsl(${i * (250 / 6)}, 90%, 55%)`;
      ctx2.fillRect(0, i * 20, 200, 20);
    }
    // now draw our off-screen canvas on the main one
    ctx.drawImage(ctx2.canvas, 0, 0);
    <div id="board">
      <canvas width="640" height="480"></canvas>
    
    </div>

    或者,由于这是您的合成中唯一的合成,您也可以在相同的基础上进行所有合成,但可以使用其他合成模式: destination-over .
    此模式将绘制 在…的后面 现有内容,这意味着您必须实际绘制背景 之后 你完成了合成。

    const canvas = document.querySelector('#board canvas');
    const ctx = canvas.getContext('2d');
    const {
      width: w,
      height: h
    } = canvas;
    //
    // text compositing on a clear context
    drawText();
    // will draw only where the text has been drawn
    ctx.globalCompositeOperation = 'source-atop';
    drawRainbow();
    // from here we will draw behind
    ctx.globalCompositeOperation = 'destination-over';
    // so we need to first draw the stars, otherwise they'll be behind
    drawStars();
    //And finally the sky black background
    drawSky();
    
    //... reset
    ctx.globalCompositeOperation = 'source-over';
    
    function drawSky() {
      ctx.fillStyle = 'black';
      ctx.fillRect(0, 0, w, h);
    }
    
    function drawStars() {
      ctx.fillStyle = '#555';
      let x, y, radius;
      for (let i = 0; i < 550; i++) {
        x = Math.random() * w;
        y = Math.random() * h;
        radius = Math.random() * 3;
        ctx.beginPath();
        ctx.arc(x, y, radius, 0, Math.PI * 2, false);
        ctx.fill();
      }
    }
    
    function drawText()  {
      ctx.font = 'bold 70pt monospace';
      ctx.fillStyle = 'black';
      ctx.fillText('FOO', 10, 60);
      ctx.fillText('BAR', 10, 118);
    }
    
    function drawRainbow() {
      for (let i = 0; i < 6; i++) {
        ctx.fillStyle = `hsl(${i * (250 / 6)}, 90%, 55%)`;
        ctx.fillRect(0, i * 20, 200, 20);
      }
    }
    <div id="board">
      <canvas width="640" height="480"></canvas>
    </div>