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;
}
}
结语
至此文章已经到达尾声,我们可以总结一下绘制内阴影效果所用到的技术点
其中globalCompositeOperation是一个有意思的属性,通过设置不同的参数,可以实现很多不同的效果。比如如下的效果就用到了这个属性:
有兴趣的读者可以关注往期更多的文章。
如果对可视化感兴趣,可以和我交流,微信541002349. 另外关注公众号“ITMan彪叔” 可以及时收到更多有价值的文章。
相关文章
- [操作系统] 字节序中的大端序和小端序的区别
- [MySQL]事务的MVCC原理与幻读
- [PHP] PHP PDO与mysql的连接单例防止超时情况处理
- [PHP]使用preg_replace来转换手机号中间四位为* 或者进行复杂字符替换
- [PHP]抽象类和接口的区别
- [Php] windows下使用composer出现SHA384 is not supported by your openssl extension
- [labuladong算法小抄]手把手带你刷二叉树(第一期)
- [PHP] 新版本PHP7.4与新版本MySQL8认证问题
- [PHP] error_reporting(0)可以屏蔽Fatal error错误
- [PHP] PDO对象与mysql的连接超时
- [uniapp] 解决推送时报错plus not defined
- [PHP] time_wait与长连接短连接
- [PHP] Ubuntu快速安装起PHP7.4
- [PHP] CentOS下搭建下PHP的运行环境
- [日常] 修复了grub引导问题
- [labuladong算法小抄]如何判断回文链表
- [MySQL] docker下安装使用mysql配置主从复制
- [日常] lscpu查看cpu的详细信息
- [日常] 高并发抢购方案的思考
- [日常] 免费的文本比较工具Meld使用