代码地址如下:
http://www.demodashi.com/demo/11636.html

前言

之前在某网站上看到了一个canvas绘制的动画效果,虽然组成的元素很简单,只有点和线,但是视觉效果却非常炫丽,当下就非常想自己把他实现一遍。因为工作原因这个想法搁置了一段时间,前不久忽然想起来,就抽空完成了这个demo,下面是demo的截图,想要看动态效果的小伙伴可以戳旁边的链接:canvas绘制绚丽的点线动画效果

运行效果图

下面就简单介绍一下完成这个demo的思路

需要掌握的基础知识

  1. canvas绘制点与线的api
  2. 理解JavaScript中“类”

需求分析

  1. 随机产生并向随机方向以随机的速度匀速移动
  2. 未点击时,点的总数保持不变;点击时在点击的位置产生数个新的点
  3. 点与点之间在一定距离内有细线连接
  4. 鼠标在画面中移动时,能够与其他点产生互动

编写代码(文章末尾有源码)

点的实现

由于在整个demo中需要使用到大量的点,所以使用一个Dot类来负责产生点的实例以及这个点的所有行为

  1. // 声明一个Dot对象
  2. var Dots = function () {
  3. this.canvas; // canvas节点
  4. this.ctx; // canvas绘图上下文
  5. this.x; // 横向坐标
  6. this.y; // 纵向坐标
  7. this.r; // dot半径
  8. this.sx; // 单位时间水平移动距离
  9. this.sy; // 单位时间纵向移动距离
  10. };

Dot的原型链中需要有一下两个方法:init() 与 update()

  1. Dots.prototype = {
  2. init: function(){...},
  3. update: function(){...}
  4. }

init()

Dots实例的初始化方法,在canvas中绘制一个点,并确定这个Dots实例移动的方向与速度(由sx与sy决定,即确定sx与sy的值)

update()

更新dot的位置,通过不断调用其的update方法,使其产生运动的效果,并且判断dot所处的位置是否已经超出canvas的边界,若超出则调用其init()方法,使其重生在canvas内

如何绘制一个点?

点的本质是一个实心圆,所以绘制一个点就是绘制一个填充了颜色的圆

  1. this.ctx.beginPath(); // 开启绘制路径
  2. this.ctx.arc(this.x, this.y, this.r, 0, 2*Math.PI); // 绘制圆 参数依次为 圆的横坐标/纵坐标/半径/绘制圆的起始位置/绘制圆的弧度大小
  3. this.ctx.fillStyle = "rgba(255,255,255,.8)"; // 设置填充颜色
  4. this.ctx.fill(); // 填充颜色
  5. this.ctx.closePath(); // 关闭绘制路径

让点移动起来

如果让你实现一个动画,你可能会想到通过定时器setTimeout或者setInterval的方式来实现,时间设定越短动画也就越流畅,但是使用定时器会有这么几个问题出现:

  1. 当有耗时任务时,定时器任务会等待耗时任务结束,js引擎空闲时再去执行
  2. 当设定时间非常短时,可能会出现掉帧现象,产生动画不连贯的感受

那么有什么方法可以解决这个问题呢?答案是使用全局函数requestAnimFrame()

requestAnimFrame的字面意思是“请求动画帧”,作用是根据GPU的渲染频率来执行方法内的js代码,这样就不会出现上面使用定时器而导致的两个可能的问题

  1. // dot移动效果
  2. function animateUpdate() {
  3. dot.update(); // 更新dot的当前位置
  4. requestAnimFrame(animateUpdate);
  5. }
  6. requestAnimFrame(animateUpdate);

绘制点与点之间的连线

将产生的点存放在一个数组中,就得到了一个当前所有点实例的集合,通过for循环的嵌套,将数组中的每个点进行两两比较,当点与点之间的距离达到预先设置的临界值时,即可绘制连线

如何绘制一条线?

  1. ctx.beginPath(); // 开启绘制路径
  2. ctx.moveTo(x, y); // 设置线的起始位置
  3. ctx.lineTo(dx, dy); // 设置线的结束位置
  4. ctx.strokeStyle = 'rgb(255,255,255)'; // 设置绘制线条的颜色
  5. ctx.strokeWidth = 1; // 设置绘制线条的宽度
  6. ctx.stroke(); // 绘制
  7. ctx.closePath(); // 关闭绘制路径

如何实现线条的淡入淡出效果?

设置reba颜色值可实现带透明度的颜色,透明度的计算方式为,(临界值距离 - 实际距离) / 临界值距离,这样就可以实现两点距离越远线条颜色越淡。再通过动画不停渲染,就可以造成视觉上淡入淡出的效果

  1. ctx.strokeStyle = 'rgba(255,255,255,'+(dotsDistance-s)/dotsDistance+')';

实现鼠标交互

添加点击事件 click 事件监听器,当点击时实例化多个Dots对象,并将其添加到上文保存点的数组中,这样既可将新产生的点与原有的点产生联系。需要注意的是,产生点的位置应该为点击的位置,由于demo中的canvas是全屏显示的,所以只需要获取鼠标点的pageX / pageY,如果canvas并非全屏,则需要获取到的点产生的位置应该是相对于canvas的位置,而不能直接使用pageX / pageY, 并且需要判断是否在canvas内,如果不在则不产生新点

  1. document.addEventListener('click', createDot); // 添加点击事件
  2. function createDot(e) { // 点击事件方法
  3. var tx = e.pageX,
  4. ty = e.pageY; // 获取点击位置
  5. if ((tx > 0 && tx < width) && (ty > 0 && ty < height)) { // 判断是都在canvas内 width和height为canvas宽高
  6. for (var i = 0; i < 5; i ++) {
  7. var dot = new Dots();
  8. dotsArr.push(dot);
  9. dot.init(canvas, tx, ty);
  10. } // 循环创建5个点 并添加到数组中
  11. }
  12. };

如何实现鼠标在canvas中移动的交互效果?

首先添加 mousemove 的事件监听器,其他步骤与上面点击的代码相同,唯一不同的是,确定点击在canvas内后不能创建新的点。现在为Dots对象添加一个新的原型链方法mouseDot()用于更新需要跟踪鼠标移动的点的位置

  1. mouseDot: function (x, y) {
  2. this.x = x * 2;
  3. this.y = y * 2; // 这里的2是屏幕的devicePixelRatio 是一个全局熟悉 在retain屏幕下 devicePixelRatio=2 标识浏览器会用两个像素点去绘制原先的一个像素 这样会导致绘图不清晰 之后会专门写一篇关于这个问题的文章 感兴趣的小伙伴可以持续关注
  4. this.ctx.beginPath();
  5. this.ctx.arc(this.x, this.y, this.r + 0.5, 0, 2*Math.PI);
  6. this.ctx.fillStyle = "rgba(255,0,0,.8)";
  7. this.ctx.fill();
  8. this.ctx.closePath();
  9. }
  1. document.addEventListener('mousemove', moveDot);
  2. function moveDot(e) {
  3. var tx = e.pageX,
  4. ty = e.pageY;
  5. if ((tx > 0 && tx < width) && (ty > 0 && ty < height)) {
  6. dot.mouseDot(tx, ty); // 更新跟踪点的位置 小伙伴们可以思考一下这里的dot对于的是dotsArr中的哪一个点
  7. }
  8. };

性能优化

以上就是canvas实现绚丽点线效果的基本思路啦!但是还有一个问题需要优化,看过demo的小伙伴可能已经发现了,刚开始不断点击的时候会不断产生点,但是当点的数量到达一定程度的时候就会发现:不管怎么点击,画面中的点的数量基本保持不变

其实在之前看到的网站上,点的数量是可以无上限增加的。但是点的数量不断增加会严重消耗性能,导致动画效果卡顿严重,无法直视,同时点太多也十分的不美观,于是demo就对这一情况做了优化:

当点的数量增加到预设的最大值时,每新增一个点,就会舍弃掉点数组中最先添加进去的点

至于是如何实现的,小伙伴们可以在源码中寻找答案哦!

代码结构图

文件结构类别如下



神奇的canvas——点与线绘制的绚丽动画效果

代码地址如下:
http://www.demodashi.com/demo/11636.html

注:本文著作权归作者,由demo大师代发,拒绝转载,转载需要作者授权

神奇的canvas——点与线绘制的绚丽动画效果的更多相关文章

  1. 神奇的canvas——巧用 canvas 为图片添加水印

    代码地址如下:http://www.demodashi.com/demo/11637.html 很久之前写过一篇关于 canvas 的文章,是通过 canvas 来实现一个绚丽的动画效果,不管看过没看 ...

  2. HTML5 Canvas(实战:绘制饼图2 Tooltip)

    继上一篇HTML5 Canvas(实战:绘制饼图)之后,笔者研究了一下如何给饼图加鼠标停留时显示的提示框. Plot对象 在开始Coding之前,笔者能够想到的最easy的方式,就是给饼图的每一个区域 ...

  3. canvas自适应圆形时钟绘制

    前面的话 前面介绍过canvas粒子时钟的绘制,本文将详细介绍canvas自适应圆形时钟绘制 效果演示 最终自适应圆形时钟的效果如下所示 功能分析 下面来分析一下该圆形时钟的功能 [1]静态背景 对于 ...

  4. 第165天:canvas绘制圆环旋转动画

    canvas绘制圆环旋转动画——面向对象版 1.HTML 注意引入Konva.js库 <!DOCTYPE html> <html lang="en"> &l ...

  5. Canvas:橡皮筋线条绘制

    Canvas:橡皮筋线条绘制 效果演示 实现要点 事件监听 [说明]: 在Canvas中检测鼠标事件是非常简单的,可以在canvas中添加一个事件监听器,当事件发生时,浏览器就会调用这个监听器. 我们 ...

  6. C# 波浪线绘制

    波浪线效果如上 界面绘制操作 private Point? _startPoint = null; private void ContainerCanvas_OnPreviewMouseLeftBut ...

  7. canvas绘制折线路径动画

    最近有读者加我微信咨询这个问题: 其中的效果是一个折线路径动画效果,如下图所示: 要实现以上路径动画,一般可以使用svg的动画功能.或者使用canvas绘制,结合路径数学计算来实现. 如果用canva ...

  8. 基于canvas实现物理运动效果与动画效果(一)

    一.为什么要写这篇文章 某年某月某时某种原因,我在慕课网上看到了一个大神实现了关于小球的抛物线运动的代码,心中很是欣喜,故而写这篇文章来向这位大神致敬,同时也为了弥补自己在运动效果和动画效果制作方面的 ...

  9. Chart 绘制,自带动画效果

    package com.example.canvasdemo; import android.annotation.SuppressLint; import android.content.Conte ...

随机推荐

  1. 控件gridview的属性全集

    1. GridView控件的属性 表10.6 GridView控件的行为属性 属性 描述 AllowPaging 指示该控件是否支持分页. AllowSorting 指示该控件是否支持排序. Auto ...

  2. [thinkphp]验证码不显示: 图像因存在错误无法显示

    我只想说,该死的BOM FUKKKKK!!!!!!!!

  3. Spring Cloud 常用依赖

    <!-- 将微服务provider侧注册进eureka --> <dependency> <groupId>org.springframework.cloud< ...

  4. Vim求生

    [TOC] Vim 是从 vi 发展出来的一个文本编辑器.其代码补完.编译及错误跳转等方便编程的功能特别丰富,在程序员中被广泛使用.和 Emacs 并列成为类 Unix 系统用户最喜欢的编辑器. —— ...

  5. Manacher【SP7586】NUMOFPAL - Number of Palindromes

    Description 求一个串中包含几个回文串. Input 输入一个字符串\(S\) Output 包含的回文串的个数. 看到题解里面有人人写回文自动机. 有必要那么麻烦嘛 emmm 我们直接跑\ ...

  6. NOIP2018提高组模拟题(六)

    购物(shop) Description 小林来到商店中进行购物.商店里一共有 n 件物品,第 i 件物品的价格为 a[i] 元.小林总共需要购买 m 件物品,他希望他所花费的钱最少,请你计算出最小 ...

  7. Linux命令之file

    file [选项] [文件名] 确认文件类型 (1).常用选项 magic file指的是哪些具有特殊文件格式的文件 -b,--brief 不列出文件名称 -c,--checking-printout ...

  8. 1353表达式括号匹配(stack)

    [题目描述] 假设一个表达式有英文字母(小写).运算符(+,—,*,/)和左右小(圆)括号构成,以“@”作为表达式的结束符.请编写一个程序检查表达式中的左右圆括号是否匹配,若匹配,则返回“YES”:否 ...

  9. (转载)UIKIt力学教程

    转载自:http://www.cocoachina.com/ios/20131226/7614.html 这篇文章还可以在这里找到 英语,   Ray:这篇教程节选自 iOS 7 教程集,它是 iOS ...

  10. Hibernate4 No Session found for current thread

    Hibernate4 与 spring3 集成之后, 如果在取得session 的地方使用了getCurrentSession, 可能会报一个错:“No Session found for curre ...