canvas可視化效果之內陰影效果


canvas可視化效果之內陰影效果

楔子

在之前的一個軌道交通可視化項目中,運用到了很多繪制技巧。 可以參考 之前的一篇文章 《利用canvas陰影功能與雙線技巧繪制軌道交通大屏項目效果

效果圖中的軌道,就同時存在外發光和內發光效果的效果。

外發光效果

我們知道外發光效果是很容易實現的,直接通過設置陰影效果即可達到。比如我們隨便繪制一條線段,加上陰影效果,看起來就是外發光的效果:

      ctx.clearRect(0,0,canvas.width,canvas.height);
      ctx.shadowBlur= 20;
      ctx.shadowOffsetX = 0;
      ctx.shadowOffsetY = 0;
      ctx.shadowColor="red";
      ctx.lineCap = "round";
      ctx.lineJoin  = "round";
      ctx.lineWidth = 10;
      ctx.strokeStyle = "blue";
      ctx.beginPath();
      ctx.moveTo(300,300);
      ctx.lineTo(750,300);
      ctx.quadraticCurveTo(800,300,800,350);
      ctx.lineTo(800,450);
      ctx.quadraticCurveTo(800,500,750,500);
      ctx.lineTo(300,500);
      ctx.stroke();

效果圖如下:

如果繪制圓形效果如下:

上面的代碼都容易理解,就是通過shadowBlur產生漸變陰影的效果。 默認的陰影,我們稱之為外陰影,意思都是圖像向往展開的陰影效果。

內陰影

接下來的問題可能就變得有點難度。如果我們需要如下的一個內陰影的效果呢?

有人說,簡單,一個漸變就搞定了。 那再看看下面這個圖像呢?

還是沒問題,還是可以通過漸變來搞定,只是漸變的stop設置要麻煩一點罷了。 如果在復雜一些的圖形呢,比如下面的線段效果:

對於上面的線段的內陰影效果,就很難使用簡單的漸變來實現了。

如何繪制內陰影效果

要實現上面的內陰影效果,首先還是使用shadowBlur參數,然后把ctx的globalCompositeOperation參數設置為“source-out” 即可。 試試如下代碼:

 ctx.globalCompositeOperation = 'source-out';
     ctx.beginPath();
     ctx.beginPath();
    ctx.moveTo(300,300);
    ctx.lineTo(750,300);
    ctx.quadraticCurveTo(800,300,800,350);
    ctx.lineTo(800,450);
    ctx.quadraticCurveTo(800,500,750,500);
    ctx.lineTo(300,500);
    ctx.lineCap = "round";
     ctx.shadowBlur =15;
     ctx.lineWidth = 20;
     ctx.shadowColor="blue";
     ctx.fillStyle = 'red';
     ctx.strokeStyle = 'red';
     ctx.stroke();

最終繪制的效果就是上面的線段圖的效果:

同時繪制內外陰影效果

如果修改globalCompositeOperation為“xor”,我們還可以得到既有內陰影又有外陰影的效果。 代碼如下:

 ctx.globalCompositeOperation = 'xor';
     ctx.beginPath();
     ctx.beginPath();
    ctx.moveTo(300,300);
    ctx.lineTo(750,300);
    ctx.quadraticCurveTo(800,300,800,350);
    ctx.lineTo(800,450);
    ctx.quadraticCurveTo(800,500,750,500);
    ctx.lineTo(300,500);
    ctx.lineCap = "round";
     ctx.shadowBlur =15;
     ctx.lineWidth = 20;
     ctx.shadowColor="red";
     ctx.fillStyle = 'red';
     ctx.strokeStyle = 'red';
     ctx.stroke();

繪制的效果如下:

內陰影的缺陷

上述方法實現的內陰影顏色的顏色只能和繪制主體一樣的顏色,而不能像外陰影的顏色一樣,可以自由定義。 比如把上述代碼中的shadowColor改成blue,只有外陰影的顏色改變了:

 ctx.globalCompositeOperation = 'xor';
     ctx.beginPath();
     ctx.beginPath();
    ctx.moveTo(300,300);
    ctx.lineTo(750,300);
    ctx.quadraticCurveTo(800,300,800,350);
    ctx.lineTo(800,450);
    ctx.quadraticCurveTo(800,500,750,500);
    ctx.lineTo(300,500);
    ctx.lineCap = "round";
     ctx.shadowBlur =15;
     ctx.lineWidth = 20;
     ctx.shadowColor="red";
     ctx.fillStyle = 'red';
     ctx.strokeStyle = 'red';
     ctx.stroke();

最終的效果如下圖所示:

從圖上可以看出只有外陰影顏色改變了,內陰影使用的本體的顏色。

實現閃爍的效果

基於上面的實現,我們可以實現一個陰影閃爍的效果,只需要不斷更改shadowBlur的值,代碼如下:
···
setInterval(()=>{
xor();
},10)

let shadowBlur = 5;
let offset = 0.5;



function xor(){
  ctx.clearRect(0,0,canvas.width,canvas.height);
  ctx.globalCompositeOperation = 'xor';
  ctx.shadowBlur= shadowBlur;
  ctx.shadowOffsetX = 0;
  ctx.shadowOffsetY = 0;
  ctx.shadowColor="red";
  ctx.lineCap = "round";
  ctx.lineJoin  = "round";
  ctx.lineWidth = 10;
  ctx.strokeStyle = "blue";
  ctx.beginPath();
  ctx.moveTo(300,300);
  ctx.lineTo(750,300);
  ctx.quadraticCurveTo(800,300,800,350);
  ctx.lineTo(800,450);
  ctx.quadraticCurveTo(800,500,750,500);
  ctx.lineTo(300,500);
  ctx.stroke();
  // ctx.stroke();
  
  ctx.globalCompositeOperation = 'xor';
  ctx.shadowBlur=shadowBlur / 10.0;
  ctx.shadowOffsetX=0;
  ctx.shadowOffsetY=0;
  ctx.shadowColor="blue";
  ctx.lineWidth =1;
  // ctx.stroke();

  shadowBlur += offset;
  if(shadowBlur > 15 || shadowBlur < 1){
    offset *= -1;
  }
}

···

如果做一些疊加繪制,還可以實現如下效果:

   function xor(){
      ctx.clearRect(0,0,canvas.width,canvas.height);
      ctx.globalCompositeOperation = 'xor';
      ctx.shadowBlur= shadowBlur;
      ctx.shadowOffsetX = 0;
      ctx.shadowOffsetY = 0;
      ctx.shadowColor="red";
      ctx.lineCap = "round";
      ctx.lineJoin  = "round";
      ctx.lineWidth = 20;
      ctx.strokeStyle = "red";
      ctx.beginPath();
      ctx.moveTo(300,300);
      ctx.lineTo(750,300);
      ctx.quadraticCurveTo(800,300,800,350);
      ctx.lineTo(800,450);
      ctx.quadraticCurveTo(800,500,750,500);
      ctx.lineTo(300,500);
      ctx.stroke();
      // ctx.stroke();
      
      ctx.globalCompositeOperation = 'destination-out';
      ctx.shadowBlur=shadowBlur / 10.0;
      ctx.shadowOffsetX=0;
      ctx.shadowOffsetY=0;
      ctx.shadowColor="red";
      ctx.lineWidth =5;
      ctx.stroke();

      shadowBlur += offset;
      if(shadowBlur > 15 || shadowBlur < 1){
        offset *= -1;
      }
    }

結語

至此文章已經到達尾聲,我們可以總結一下繪制內陰影效果所用到的技術點

  1. CanvasRenderingContext2D.globalCompositeOperation
  2. CanvasRenderingContext2D.shadowBlur

其中globalCompositeOperation是一個有意思的屬性,通過設置不同的參數,可以實現很多不同的效果。比如如下的效果就用到了這個屬性:
image.png

有興趣的讀者可以關注往期更多的文章。

如果對可視化感興趣,可以和我交流,微信541002349. 另外關注公眾號“ITMan彪叔” 可以及時收到更多有價值的文章。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM