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是一个有意思的属性,通过设置不同的参数,可以实现很多不同的效果。比如如下的效果就用到了这个属性:

有兴趣的读者可以关注往期更多的文章。

如果对可视化感兴趣,可以和我交流,微信541002349. 另外关注公众号“ITMan彪叔” 可以及时收到更多有价值的文章。

canvas可视化效果之内阴影效果的更多相关文章

  1. 【HTML5】Web Audio API打造超炫的音乐可视化效果

    HTML5真是太多炫酷的东西了,其中Web Audio API算一个,琢磨着弄了个音乐可视化的demo,先上效果图: 项目演示:别说话,点我!  源码已经挂到github上了,有兴趣的同学也可以去st ...

  2. 13个可实现超棒数据可视化效果的Javascript框架

    随着商业及其相关需求的发展,数据成为越来越重要的元素之一,为了更加直观和明显的展示商业潜在的趋势和内在的特性,我们需要使用图表和图形的方式来直观动态的展示数据内在秘密,在今天的这篇文章中我们推荐12款 ...

  3. WPF,Silverlight与XAML读书笔记第三十九 - 可视化效果之3D图形

    原文:WPF,Silverlight与XAML读书笔记第三十九 - 可视化效果之3D图形 说明:本系列基本上是<WPF揭秘>的读书笔记.在结构安排与文章内容上参照<WPF揭秘> ...

  4. BI工具数据可视化效果哪家强?我选这款!

    BI工具是商业智能(Business Intelligence)软件的英文缩写.目前,商业智能通常被理解为将企业中现有的数据转化为知识,帮助企业做出明智的业务经营决策的工具. 企业经常会为如何选择BI ...

  5. CodePen 作品秀:Canvas 粒子效果文本动画

    作品名称——Shape Shifter,基于 Canvas 的粒子图形变换实验.在页面下方的输入框输入文本,上面就会进行变换出对应的粒子效果文本动画. CodePen 作品秀系列向大家展示来自 Cod ...

  6. WPF元素可视化效果

    在WPF中设置元素的可视化效果主要用到BlurEffect类和DropShadowEffect类.(目前只学到这两个,哈哈) 1.BlurEffect类 命名空间: System.Windows.Me ...

  7. HTML5大数据可视化效果(二)可交互地铁线路图

    前言 最近特别忙,承蒙大伙关照,3D机房的项目一个接着一个,领了一帮小弟,搞搞传帮带,乌飞兔走,转眼已经菊黄蟹肥……有个小弟很不错,勤奋好学,很快就把API都摸透了,自己折腾着做了个HTML5的魔都的 ...

  8. HTML5 Canvas动画效果演示

    HTML5 Canvas动画效果演示 主要思想: 首先要准备一张有连续帧的图片,然后利用HTML5 Canvas的draw方法在不同的时间 间隔绘制不同的帧,这样看起来就像动画在播放. 关键技术点: ...

  9. HTML5 Canvas动画效果演示 - 流浪的鱼 - 博客频道 - CSDN.NET

    HTML5 Canvas动画效果演示 - 流浪的鱼 - 博客频道 - CSDN.NET HTML5 Canvas动画效果演示

随机推荐

  1. 「CF645E」 Intellectual Inquiry

    题目链接 CF645E 题意 有一个长为\(n\)的由小写字母组成的字符串,需要用小写字母再填\(m\)位,使最后的字符串中本质不同的子串数量尽量多,答案对\(10^9+7\)取模. 本题数据:\(n ...

  2. CF1156D 0-1-Tree

    路径考虑顺序. 显然合法的路径只有以下两种: 一段 \(0\) 加一段 \(1\) 或一段 \(1\) 加一段 \(0\). 全 \(0\) 或全 \(1\). 用并查集将边权为 \(0\) 和 \( ...

  3. 【POJ 1845】Sumdiv——数论 质因数 + 分治 + 快速幂

    (题面来自luogu) 题目描述 输入两个正整数a和b,求a^b的所有因子之和.结果太大,只要输出它对9901的余数. 输入格式 仅一行,为两个正整数a和b(0≤a,b≤50000000). 输出格式 ...

  4. 为什么学完C语言觉得好像没学一般?

    不少同学从Hello world学到文件操作之后,回顾感觉会又不会? 学会了又感觉没学会?这种不踏实.模糊虚无的感觉?   原因在于编程不同于理论学科,你听懂和理解了理论就可以运用. 比如历史地理,看 ...

  5. uni-app p-table下时间转换的问题

    问题描述: 从后台获取时间戳,转成日期格式,出现NaN的问题 uni的p-table插件 解决思路

  6. spring-boot-starter

    Spring Boot Starter 是在 SpringBoot 组件中被提出来的一种概念,stackoverflow 上面已经有人概括了这个 starter 是什么东西,想看完整的回答戳 这里. ...

  7. C++ 虚基类的定义、功能、规定

    原文声明:http://blog.sina.com.cn/s/blog_93b45b0f01011pkz.html 虚继承和虚基类的定义是非常的简单的,同时也是非常容易判断一个继承是否是虚继承的,虽然 ...

  8. OpenCV击中击不中HMTxingt变换最容易理解的解释

    OpenCV击中击不中变换是几个形态变换中相对比较拗口.不容易理解的,给初学者理解带来了很多困难,虽然网上也有许多的公开资料,原理和算法基本上介绍比较清晰,但是是要OpenCV进行形态变换大多还是说得 ...

  9. 第7.7节 案例详解:Python类继承机制

    本节实现一个类继承的小程序,下面一边结合代码一边介绍相关继承的知识.例子以车.汽车为例,车为父类.汽车为子类. 一.    定义父类Vehicle class Vehicle():    def __ ...

  10. Java安全之Unsafe类

    Java安全之Unsafe类 0x00 前言 前面使用到的一些JNI编程和Javaagent等技术,其实在安全里面的运用非常的有趣和微妙,这个已经说过很多次.后面还会发现一些比较有意思的技术,比如AS ...