Canvas + CSS3实现可视化项目开场动画

Vue大屏流光动画实战:从CSS3到Canvas的进阶技巧 本文深入探讨了在Vue框架下实现大屏流光动画的三种核心技术路径:CSS3、SVG与Canvas。文章通过实战代码,详细对比了各自的优劣与适用场景,并重点分享了Canvas实现高性能、数据驱动动画的进阶技巧,旨在帮助开发者打造兼具酷炫视觉效果与流畅性能的数据大屏应用。 阅读详情

一、背景:

在最近的可视化项目中,视觉设计采用钢铁的写实风格,整体页面布局为左中右,动效需要实现在刚进入页面时,左右板块撞向中间板块,产生撞击光效和火花飞散的动画效果。

二、实现思路:

需要考虑以下几个方面:

  1. 整体页面的布局,左中右三个板块需要独立,分别绝对定位,不要耦合在一起;
  2. 使用css3实现撞击动效;
  3. 使用canvas绘制撞击后的火光和火花,光效可以径向渐变,火花飞舞的运动轨迹分别是左右方向的匀减速运动,上下方向的匀减速和匀加速,最后到飞舞消散的过程,粒子大小随机

三、实现过程:

  1. 撞击效果的实现

  主要使用到CSS3 的animation和translate3d

 (1)animation的属性解析

          name :要绑定到选择器的关键帧的名称

          duration :动画指定需要多少秒或毫秒完成

          timing-function :设置动画将如何完成一个周期

          delay :设置动画在启动前的延迟间隔

          iteration-count :定义动画的播放次数

          direction :指定是否应该轮流反向播放动画

          fill-mode :规定当动画不播放时,要应用到元素的样式

          play-state: 指定动画是否正在运行或已暂停

 (2)translate3d() css函数在三维空间中重新定位一个元素。

          语法:translate3d(tx,ty,tz) 

           tx——表示平移矢量的横坐标的<length>值。

           ty——表示平移向量的纵坐标的<length>值。

           tz——表示平移矢量的z分量的<length>值。

<div class="dataBoard-left animated bounceInLeft" id="aniLeft">
  <left-page/>
</div>
<div class="dataBoard-center">
  <graph/>
</div>
<div class="dataBoard-right animated bounceInRight" id="aniRight">
  <right-page/>
</div>
.animated {
  animation: 0.8s cubic-bezier(0.94,0,1,1);
  animation-fill-mode: both;
  animation-delay:0.3s;
}
@keyframes bounceInLeft {
  0% {
    opacity: 0;
    transform: translate3d(-100%, 0, 0);
  }
  to {
    opacity: 1;
    transform: none;
  }
}
.bounceInLeft {
  animation-name: bounceInLeft;
}
@keyframes bounceInRight {
  0% {
    opacity: 0;
    transform: translate3d(100%, 0, 0);
  }
  to {
    opacity: 1;
    transform: none;
  }
}
.bounceInRight {
  animation-name: bounceInRight;
} 

2. 撞击火光和火花的实现

(1)画光,光效是两个对称的圆,然后做径向渐变

  Grad.addColorStop定义了两个渐变的色阶

function drawLight(x,y,direction) {
  var grad=cxt.createRadialGradient(x,y,0,x,y,1000);
  grad.addColorStop(0,"rgba(255,180,0,0.4)");       
  grad.addColorStop(1,"rgba(255,180,0,0)");
  cxt.fillStyle=grad;     
 
  cxt.beginPath();
  cxt.arc(x,y,1000,0,Math.PI*2,direction);
  cxt.closePath();
  cxt.fill();
}

(2)画粒子,声明粒子类

                 class Spark {
                    constructor() {
                        this.startX = 600; //初始位置
                        this.startY = 100;
                        this.radius = 5;
                        this.radiusY = 1;
                        this.radiusOffset = 0;
                        this.radiusA = 0.1;
                        this.v0x = 2; //初始速度
                        this.v0y = 10;
                        this.speedAY = 4; //加速度
                        this.speedAX = -0.5;
                        this.speedX = 2; //实时速度
                        this.speedY = 10;
                        this.offsetX = 0;
                        this.offsetY = 0;
                        this.t = 0;
                        this.color = "#0000FF";
                        this.tY = 0;
                        this.time = 0;
                        this.dirDown = 0;
                        this.dirUp = 1;
                        this.dir = 0; //上下方向状态
                        this.cycleYTimes = 0;
                        this.waiteTime = 0;
                        this.startTime = 0;
                        this.trail = [];
                        this.dirLeft = 0;
                        this.dirRight = 1;
                        this.dirX = 1; //水平方向状态
                    }
                    calc(){
                        if (this.dirX == this.dirLeft) {
                            this.trail.push({
                              x: (this.startX - this.offsetX), 
                              y: (this.startY + this.offsetY)});
                        } else {
                            this.trail.push({
                              x: (this.startX + this.offsetX), 
                              y: (this.startY + this.offsetY)});
                        }
                        if(this.trail.length >2){
                            this.trail.splice(0,1);
                        }
                    }
                }

3)批量生产多个粒子

               for (var i = 0; i < 200;i++) {
                    var spark = new Spark();
                    spark.startY = 100 + Math.random() * 1800;
                    spark.v0x = 10 + Math.random() * 8;
                    spark.speedX = spark.v0x;
                    spark.radius = 2 + Math.random() * 15;
                    spark.radiusY = 1 + Math.random() * 2;
                    let randomDirX = Math.random() * 2;
                    if (randomDirX < 1) {
                        //向左面飞的
                        spark.startX = this.startLeft;
                        spark.dirX = 0;
                        spark.dir = 0;
                    } else {
                        //向右面飞的
                        spark.startX = this.startRight;
                        spark.dirX = 1;
                        spark.dir = 1;
                        spark.speedY = spark.v0x - 1;
                    }
                    
                    spark.startTime = Math.random() * 10;
                    spark.color = "#fff";
                    sparks.push(spark);
                }

(4)画粒子,粒子是根据随机数计算出的半径绘制的小椭圆,然后加上外发光的阴影

       ellipse(x, y, radiusX, radiusY, rotation, startAngle, endAngle, anticlockwise)

      参数:(起点x,  起点y, 半径x,  半径y,  旋转的角度,起始角,结果角,方向)

               function drawBall(spark) {
                    cxt.shadowBlur = 20;
                    cxt.shadowColor="#fff"; 
                    cxt.fillStyle=spark.color;
                    cxt.beginPath();
                    if (spark.dirX == spark.dirLeft) {
                        cxt.ellipse(
                            spark.startX - spark.offsetX,
                            spark.startY + spark.offsetY,
                            spark.radius + spark.radiusOffset,
                            spark.radiusY + spark.radiusOffset,
                            0,
                            0,
                            Math.PI*2,
                            true
                        );
                    } else {
                        cxt.ellipse(
                            spark.startX + spark.offsetX,
                            spark.startY + spark.offsetY,
                            spark.radius + spark.radiusOffset,
                            spark.radiusY + spark.radiusOffset,
                            0,
                            0,
                            Math.PI*2,
                            true);
                    }
                    cxt.closePath();
                    cxt.fill();
                }

(5)画轨迹,

         核心公式:v0t+1/2at*t

         水平方向,向左和向右飞的粒子作匀减速运动

         垂直方向,向左和向右飞的粒子在固定幅度内上下运动

function update(spark){
  if (spark.waiteTime >spark.startTime) {
    if (spark.speedX >0) {
      if (spark.cycleYTimes <3){
        if (spark.dir == spark.dirDown) {
          if (spark.speedY >-spark.v0y) {
            spark.offsetY = spark.v0y * spark.tY - 0.5 * spark.tY * spark.tY * 
            spark.speedAY;
            spark.speedY -= spark.speedAY;
          } else {
            spark.offsetY = spark.v0y * spark.tY - 0.5 * spark.tY * spark.tY * 
            spark.speedAY;
 
            spark.dir = spark.dirUp;
            spark.tY = 0;
            spark.speedY += spark.speedAY;
            spark.cycleYTimes++;
          }
         } else if (spark.dir == spark.dirUp) {
            if (spark.speedY <spark.v0y) {
              spark.offsetY = -(spark.v0y * spark.tY - 0.5 * spark.tY * spark.tY * 
              spark.speedAY);
              spark.speedY += spark.speedAY;
            } else {
            spark.offsetY = -(spark.v0y * spark.tY - 0.5 * spark.tY * spark.tY * 
            spark.speedAY);
 
              spark.dir = spark.dirDown;
              spark.tY = 0;
              spark.speedY -= spark.speedAY;
              spark.cycleYTimes++;
             }
           }
          }
          spark.time++;

          spark.offsetX = spark.v0x * spark.t + 0.5 * spark.t * spark.t * spark.speedAX;
          spark.speedX += spark.speedAX;
          spark.t += 1;
          spark.tY++;
          spark.calc();
          drawBall(spark);
          }
        }
        spark.waiteTime++;
   }

(6)执行动画,每隔30毫秒清理一次画布

               function play(){
                    cxt.clearRect(0,0,5760,1890);
 
                    for (let i = 0;i < sparks.length;i++) {
                        update(sparks[i]);
                    }
 
                }
                drawLight(this.startLeft,950,true)
                drawLight(this.startRight,950,false)
                setInterval(play,30);

四、完成效果

 

 

 

五、注意事项

五、注意事项

1.为了保证动画时间点的准确性和连续性,不要设置setTimeOut定时器去卡动画时间,这样可能不准,应当监听css动画的结束状态,然后开始绘制canvas动画;

2.canvas画布的层级需要提到最高,但是注意,动画结束后应及时清理掉canvas画布,否则画布会一直停留在页面上,阻挡页面元素的点击等事件;

3.每次切换浏览器的标签页选中状态,应将动画状态重置,重新加载动画,但是不要重新刷新页面,这样会出现等待白屏,影响用户体验,用到的方法是监听浏览器标签页的可视状态(visibilitychange)。

 document.addEventListener('visibilitychange', function() {})

【高频考点精讲】前端工程师必会的10种Canvas动画实现技巧 🧑‍🏫:全栈老李📅:2025 年 6 月🧑‍💻:前端初学者、进阶开发者🚀:本文由全栈老李原创,转载请注明出处。最近在B站直播写代码时,有个水友问我:"老李啊,现在Three.js这么火,Canvas是不是要被淘汰了?" 我当场就笑了——这就好比问"有了电饭煲还要不要学煮粥"一样。今天咱们就来聊聊Canvas动画那些事儿,看完你就会明白为什么大厂面试还在考这个。(全栈老李友情提示:文末有面试题彩蛋哦~) 阅读详情

相关推荐

HTML5 Canvas 3D旋转动画与CSS3模糊发光特效实战源码

Canvas元素创建后,其内部坐标系统自动初始化为以左上角为原点的标准二维平面:坐标轴正方向起始点X向右0Y向下0这意味着:- 点(100, 50)表示距离左侧100像素、顶部50像素的位置;- 所有路径命令(如)均基于此坐标系统执行;- 图形的旋转中心默认也是(0, 0),除非显式调整坐标原点。// 绘制一个红色矩形,位于 (50, 30)代码逻辑逐行解析。

weixin_35886636的博客 1046

分享一个超炫酷的css开场动画

分享一个超炫酷的css开场动画。

2401_82752568的博客 1378

HTML5 Canvas与JavaScript实现动画人物走动

第四章重点讲解了CSS3动画与过渡属性的原理及优势,同时,通过案例分析,我们了解了如何在实际项目中运用这些知识来创建丰富多彩的动画效果。在下一章中,我们将结合HTML5 Canvas和JavaScript,探索如何制作更为复杂和互动的人物走行动画。通过本章的学习,我们不仅掌握了一门强大的动画工具,而且还对动画制作的内在逻辑有了更深入的了解,为进一步的学习打下了坚实的基础。

weixin_29443363的博客 1334

数据可视化中CSS实现四个边角特效实现

在数据可视化大屏中,我们看到人家的到做的很炫酷,如下图,中div四个边角的特殊颜色边角是怎么实现的呢,下面本人通过两种方式进行实现。 方式一 <body> <h1 class="title">css实现矩形边角加粗</h1> <div class="main"> <span></span> <span></span> <span></span> &

杨得朝的博客 2891

HTML5+CSS3实现3D雷达扫描动画特效项目实战

最后送大家一份【避坑指南】:问题正确做法图像模糊用设Canvas尺寸,别用CSS动画卡顿用+ 时间差驱动没有立体感父容器加子元素变形失败检查是否正确移动端体验差添加响应式断点 + 减少动画复杂度用户反感动画尊重这种高度集成的设计思路,正引领着智能可视化设备向更可靠、更高效的方向演进。🎯当你下次接到“做个炫酷雷达动画”的需求时,不要再慌张地说“要不要引入Three.js?

weixin_31749299的博客 623

HTML5 Canvas扑克牌洗牌动画项目详解

Canvas是HTML5中一个非常强大的API,它提供了一个通过JavaScript脚本绘制图形的画布。Canvas API通过一个HTML<canvas>元素提供了绘图功能,通过它可以绘制矩形、圆形、图像、文字、线条等各种图形。基本图形绘制:利用Canvas提供的API,我们可以绘制各种基本图形,如矩形、圆形、多边形等。路径绘制:通过路径我们可以绘制更复杂的图形,路径是由多个点和线段构成。样式设置:我们还可以给图形设置样式,包括颜色、填充、边框样式等。

weixin_35871529的博客 1254

可视化设计-------css总结

可视化设计中的css总结 用css 实现可视化的过程中的一些方法 总结 蒙版文字 利用css中的相对定位和绝对定位,实现元素的两层组合,底层显示图片或者其他重要信息,顶层蒙版显示对底层的简易介绍之类的次要信息 css代码 .box{ position: relative; height: 200px; width: 300px } ...

liuguoxionglang的博客 978

HTML5 Canvas波浪动画特效的实现与应用

Canvas是由苹果公司于2004年引入的Web技术,后来被纳入HTML5标准。它特别适合于绘制图表、游戏图形、数据可视化等场合。Canvas提供了丰富的API来进行图形绘制。

weixin_30923011的博客 1003

css动画效果和canvas

.

dedsec0x的博客 2210

构建自适应音乐可视化应用:webAudio、Canvas、CSS3的综合运用

WebAudio API是一种高级的音频处理方法,允许开发者在浏览器中进行音频内容的合成、处理、分析以及播放。它提供了一套完整的音频节点系统,这些节点可以被连接起来形成音频路由图,从而实现复杂的音频处理。WebAudio API支持多声道输出,具有高保真音频渲染能力,并且能够实现精准的音频时间控制。它广泛应用于游戏、音乐播放器、音频可视化以及交互式音频应用程序中。Canvas是HTML5中的一项重要技术,它为开发者提供了一个通过脚本动态绘制图形的能力。一个<canvas>

weixin_42594427的博客 738

HTML5+CSS3实现圆形波浪百分比加载动画特效

在 JavaScript 中,表示进度最直接的方式是使用一个浮点数变量progress,其取值范围应严格限定在[0, 1]或[0, 100]区间内。推荐使用[0, 1]归一化形式,便于后续进行数学运算和动画插值计算。// 私有属性,存储当前进度(0.0 ~ 1.0)// 回调函数,用于通知视图更新// 边界校验:强制限制在 [0, 1] 范围内// 触发视图更新钩子代码逻辑逐行解读:第3行:定义私有字段_progress,初始值为0,表示任务尚未开始。

weixin_35982453的博客 889

canvas 制作动画(上)

实际上,画布中的动画与一般的动画在理论上并没有太大的区别。深入研究动画的本质可以发现:动画只是一连串的图像,每个图像之间的差别非常微小,并且它们以极快的速度连续显示。其中的奥妙就在于,每秒钟显示的图像非常多,人的肉眼通常认为自己看到的是一个正在运动的物体,而不是一张张连续显示的静态图像。其原理就像翻书一样,如果翻书的速度足够快,一些小图形看上去就好像在运动。当然,你不能在画布中翻页,因此需要采用其他方法来创建动画效果。仔细思考一下,你就会发现当使用代码创建动画时,只有一张纸可用,这张纸就是计算机屏幕。这意味

p1967914901的博客 2549

如何使用 HTML5 的 Canvas + JavaScript 实现从文字到图像的Canvas粒子动画?

本文介绍了一个基于Canvas的粒子动画实现过程。文章从基础HTML结构搭建开始,详细讲解了Canvas元素的初始化、画布尺寸的动态适配,以及粒子系统的构建。重点展示了如何通过JavaScript类定义粒子对象,实现粒子运动效果和拖尾视觉效果,并解析了将文字转换为粒子的关键技术。

1289

Canvas vs SVG vs CSS3:四种箭头动画实现方案对比与性能分析

本文深入对比了CSS3、SVG、JS+DOM和Canvas四种实现Web动画的技术方案。通过一个具体的“脉动箭头”动画案例,从核心原理、代码实现、性能表现及适用场景多维度剖析,为开发者提供了清晰的技术选型指南。其中,CSS3方案凭借其声明式语法和GPU加速,在实现简单UI动画时展现出卓越的性能和开发效率。

gray5的博客 484

基于Canvas的收益率曲线进度条动画特效实现

回头看整个实现过程,我们做的远不止“画一条线”这么简单:用预计算解决性能瓶颈用坐标变换实现数据到视觉的精准映射用进度动画 + 颜色渐变增强叙事感染力用分层绘制 + 局部更新保证流畅体验这些技术细节最终服务于一个目标:让用户在0.5秒内感受到“这条曲线是有生命力的”。而这,正是现代金融产品区别于传统报表的核心竞争力所在。📈所以,当你下次面对一个看似普通的图表需求时,不妨多问一句:“我们能不能让它‘呼吸’起来?” 🌬️。

weixin_35995661的博客 1056

Canvas粒子图形变形动画特效完整实现代码

Canvas 是 HTML5 提供的一种基于像素的绘图技术,允许开发者通过 JavaScript 直接操作位图,实现复杂的图形绘制与动画效果。它在现代网页开发中扮演着重要角色,尤其适用于需要高性能、高自由度的视觉表现场景,如游戏、数据可视化和交互式动画。与 SVG 的矢量图形方式不同,Canvas 更适合大量图形对象的实时渲染;相比 WebGL,Canvas 又具备更低的学习门槛和更便捷的 2D 操作能力。

weixin_33622085的博客 1137

gka多模板实战:从CSS到Canvas,打造跨平台动画效果

gka是一款高效、高性能的帧动画生成工具,支持多种模板输出,帮助开发者轻松创建跨平台动画效果。无论是Web端的CSS动画,还是需要更高性能的Canvas动画,gka都能提供简单易用的解决方案。 ## 为什么选择gka多模板动画方案? 在现代前端开发中,动画效果是提升用户体验的关键要素。然而不同平台、不同场景对动画的需求各不相同: - **CSS动画**:适合简单的页面元素动画,实现简单,兼容

gitblog_00950的博客 881

UE5 C++教程(一、基本结构)

虚幻API由三块组成,分别是Runtime,Developer utilitiew,functionality for the Editor,大多数游戏性编程只使用运行时模块,最常见的三个是Corn、CornUObject和Engine。

skycol的博客 1万+

扫盲贴:Svg动画和Canvas动画有什么区别

SVG(Scalable Vector Graphics)动画是指使用SVG技术创建的可缩放矢量图形进行动画效果的展示。SVG动画可以通过CSS或JavaScript来实现,常见的SVG动画包括以下几种类型:CSS动画:使用CSS的@keyframes规则和animation属性来定义和控制SVG元素的动画效果。可以通过指定关键帧和动画属性来实现平移、旋转、缩放、淡入淡出等动画效果。

贝格前端工场的博客 1406

2026 AI浏览器Agent终极对比:BrowserAct、agentBrowser、PP-Browser 谁更适合落地?(安装+实战+场景全覆盖)

1.不要盲目追求最新框架:很多人跟风用agentBrowser,结果业务是多步骤复杂办公流程,反而不如BrowserAct稳定;2.风控场景优先PP-Browser:但凡需要登录账号、频繁访问正规平台,无脑选PP-Browser,能避开99%的封禁问题;3.AI批量解析优先agentBrowser:做知识库爬取、网页内容总结、批量问答,省Token就是省成本,长期使用性价比碾压另外两者;4.个人开发调试优先BrowserAct:容错高、日志全、调试简单,新手上手最快,不容易报错翻车。

十年老程序猿,AI 疯狂研究专家,前沿硬核知识分享 328

嵌入式Linux&Android开发-TP调试

目录 一、修改DTS,添加新的I2C设备 二、修改Makefile,Kconfig 三、tp调试时的问题排查 一、修改DTS,添加新的I2C设备 &i2c4 { status = "okay"; clock-frequency = <400000>; gslX680@40 { compatible = "gslX680"; reg = <0x40>; touch-gpio = <&gp

嵌入式成长手册 571
上一篇: GIS地图描边特效的实现
下一篇: vue.config.js配置
小天使娜娜
博客等级 码龄8年 103粉丝 41原创
评论 3
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值