canvas可視化效果之內(nèi)陰影效果
楔子
在之前的一個(gè)軌道交通可視化項(xiàng)目中禽炬,運(yùn)用到了很多繪制技巧襟士。 可以參考 之前的一篇文章 《利用canvas陰影功能與雙線技巧繪制軌道交通大屏項(xiàng)目效果》
效果圖中的軌道,就同時(shí)存在外發(fā)光和內(nèi)發(fā)光效果的效果彪腔。
外發(fā)光效果
我們知道外發(fā)光效果是很容易實(shí)現(xiàn)的稚疹,直接通過(guò)設(shè)置陰影效果即可達(dá)到病毡。比如我們隨便繪制一條線段,加上陰影效果中狂,看起來(lái)就是外發(fā)光的效果:
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();
效果圖如下:
如果繪制圓形效果如下:
上面的代碼都容易理解凫碌,就是通過(guò)shadowBlur產(chǎn)生漸變陰影的效果。 默認(rèn)的陰影胃榕,我們稱之為外陰影盛险,意思都是圖像向往展開(kāi)的陰影效果。
內(nèi)陰影
接下來(lái)的問(wèn)題可能就變得有點(diǎn)難度。如果我們需要如下的一個(gè)內(nèi)陰影的效果呢苦掘?
有人說(shuō)换帜,簡(jiǎn)單,一個(gè)漸變就搞定了鹤啡。 那再看看下面這個(gè)圖像呢惯驼?
還是沒(méi)問(wèn)題,還是可以通過(guò)漸變來(lái)搞定揉忘,只是漸變的stop設(shè)置要麻煩一點(diǎn)罷了跳座。 如果在復(fù)雜一些的圖形呢,比如下面的線段效果:
對(duì)于上面的線段的內(nèi)陰影效果泣矛,就很難使用簡(jiǎn)單的漸變來(lái)實(shí)現(xiàn)了疲眷。
如何繪制內(nèi)陰影效果
要實(shí)現(xiàn)上面的內(nèi)陰影效果,首先還是使用shadowBlur參數(shù)您朽,然后把ctx的globalCompositeOperation參數(shù)設(shè)置為“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();
最終繪制的效果就是上面的線段圖的效果:
同時(shí)繪制內(nèi)外陰影效果
如果修改globalCompositeOperation為“xor”,我們還可以得到既有內(nèi)陰影又有外陰影的效果哗总。 代碼如下:
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();
繪制的效果如下:
內(nèi)陰影的缺陷
上述方法實(shí)現(xiàn)的內(nèi)陰影顏色的顏色只能和繪制主體一樣的顏色几颜,而不能像外陰影的顏色一樣,可以自由定義讯屈。 比如把上述代碼中的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();
最終的效果如下圖所示:
從圖上可以看出只有外陰影顏色改變了,內(nèi)陰影使用的本體的顏色涮母。
實(shí)現(xiàn)閃爍的效果
基于上面的實(shí)現(xiàn)谆趾,我們可以實(shí)現(xiàn)一個(gè)陰影閃爍的效果,只需要不斷更改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;
}
}
···
如果做一些疊加繪制沪蓬,還可以實(shí)現(xiàn)如下效果:
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;
}
}
結(jié)語(yǔ)
至此文章已經(jīng)到達(dá)尾聲,我們可以總結(jié)一下繪制內(nèi)陰影效果所用到的技術(shù)點(diǎn)
其中globalCompositeOperation是一個(gè)有意思的屬性来候,通過(guò)設(shè)置不同的參數(shù)跷叉,可以實(shí)現(xiàn)很多不同的效果。比如如下的效果就用到了這個(gè)屬性:
有興趣的讀者可以關(guān)注往期更多的文章营搅。
如果對(duì)可視化感興趣云挟,可以和我交流,微信541002349. 另外關(guān)注公眾號(hào)“ITMan彪叔” 可以及時(shí)收到更多有價(jià)值的文章转质。