1. 程式人生 > >canvas視覺化效果之內陰影效果

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

# canvas視覺化效果之內陰影效果 # 楔子 在之前的一個軌道交通視覺化專案中,運用到了很多繪製技巧。 可以參考 之前的一篇文章 《[利用canvas陰影功能與雙線技巧繪製軌道交通大屏專案效果](https://mp.weixin.qq.com/s/zpaHwkiKYWpKwdZptwEU_g)》 ![](https://p3-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/72fa4e990dea4836b8d96ade7b7e1102~tplv-k3u1fbpfcp-zoom-1.image) 效果圖中的軌道,就同時存在外發光和內發光效果的效果。 # 外發光效果 我們知道外發光效果是很容易實現的,直接通過設定陰影效果即可達到。比如我們隨便繪製一條線段,加上陰影效果,看起來就是外發光的效果: ``` 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(); ``` 效果圖如下: ![](https://p3-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/c93615096ae9496f9a74b17028a19cbf~tplv-k3u1fbpfcp-zoom-1.image) 如果繪製圓形效果如下: ![](https://p3-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/812ee8a5926b419aa2836d1c0fd81c40~tplv-k3u1fbpfcp-zoom-1.image) 上面的程式碼都容易理解,就是通過shadowBlur產生漸變陰影的效果。 預設的陰影,我們稱之為外陰影,意思都是影象嚮往展開的陰影效果。 # 內陰影 接下來的問題可能就變得有點難度。如果我們需要如下的一個內陰影的效果呢? ![](https://p3-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/db6adb3f23e149f2b19970dcafa1d02d~tplv-k3u1fbpfcp-zoom-1.image) 有人說,簡單,一個漸變就搞定了。 那再看看下面這個影象呢? ![](https://p3-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/21eb1f63966c48379193c3f85fc5c6db~tplv-k3u1fbpfcp-zoom-1.image) 還是沒問題,還是可以通過漸變來搞定,只是漸變的stop設定要麻煩一點罷了。 如果在複雜一些的圖形呢,比如下面的線段效果: ![](https://p3-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/f84493d06d084c49863bece934b1a744~tplv-k3u1fbpfcp-zoom-1.image) 對於上面的線段的內陰影效果,就很難使用簡單的漸變來實現了。 # 如何繪製內陰影效果 要實現上面的內陰影效果,首先還是使用shadowBlur引數,然後把ctx的globalCompositeOperation引數設定為“source-out” 即可。 試試如下程式碼: ```javascript 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(); ``` 最終繪製的效果就是上面的線段圖的效果: ![](https://p3-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/3a579029f08b4189874a8935e39b7ffd~tplv-k3u1fbpfcp-zoom-1.image) # 同時繪製內外陰影效果 如果修改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(); ``` 繪製的效果如下: ![](https://p3-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/81560d93982241d19a8576b953aa0f5f~tplv-k3u1fbpfcp-zoom-1.image) # 內陰影的缺陷 上述方法實現的內陰影顏色的顏色只能和繪製主體一樣的顏色,而不能像外陰影的顏色一樣,可以自由定義。 比如把上述程式碼中的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(); ``` 最終的效果如下圖所示: ![](https://p3-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/e3ea4a32d1f44851b73dd123f1e53a91~tplv-k3u1fbpfcp-zoom-1.image) 從圖上可以看出只有外陰影顏色改變了,內陰影使用的本體的顏色。 # 實現閃爍的效果 基於上面的實現,我們可以實現一個陰影閃爍的效果,只需要不斷更改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; } } ``` ··· ![](https://p3-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/44b06db67cdf4647937d92001882c33d~tplv-k3u1fbpfcp-zoom-1.image) 如果做一些疊加繪製,還可以實現如下效果: ``` 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; } } ``` ![](https://p3-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/422a06a7a4ce421db3f0f7527f841875~tplv-k3u1fbpfcp-zoom-1.image) # 結語 至此文章已經到達尾聲,我們可以總結一下繪製內陰影效果所用到的技術點 1. [CanvasRenderingContext2D.globalCompositeOperation](https://developer.mozilla.org/zh-CN/docs/Web/API/CanvasRenderingContext2D/globalCompositeOperation) 1. [CanvasRenderingContext2D.shadowBlur](https://developer.mozilla.org/zh-CN/docs/Web/API/CanvasRenderingContext2D/shadowBlur) 其中[globalCompositeOperation](https://developer.mozilla.org/zh-CN/docs/Web/API/CanvasRenderingContext2D/globalCompositeOperation)是一個有意思的屬性,通過設定不同的引數,可以實現很多不同的效果。比如如下的效果就用到了這個屬性: ![image.png](https://p3-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/6f50f0d5d0f84c83b0b1b0e1c1ebcb5f~tplv-k3u1fbpfcp-zoom-1.image) 有興趣的讀者可以關注往期更多的文章。 如果對視覺化感興趣,可以和我交流,微信541002349. 另外關注公眾號“ITMan彪叔” 可以及時收到更多有價值的