• 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彪叔” 可以及时收到更多有价值的文章。

  • 相关阅读:
    Windows平板优化设置
    MAC OS UI设计
    使用bat/vbs/ahk对Windows下进行自动化操作
    C#在高性能计算领域为什么性能却如此不尽人意
    自定义多重搜索
    CF797E Array Queries
    标记永久化学习笔记
    P7200 [COCI2019-2020#1] Lutrija
    P1075 [NOIP2012 普及组] 质因数分解
    基础数论重学笔记
  • 原文地址:https://www.cnblogs.com/flyfox1982/p/14171581.html
Copyright © 2020-2023  润新知