前端canvas训练营第一期:鼠标交互粒子背景效果(代码片段)

没头发的米糊 没头发的米糊     2022-12-04     165

关键词:

一、引言

这是一个全新的系列,在这个系列中,我将通过一系列实际案例,和你一起学习、研究Canvas,从而掌握编写 Canvas 特效的能力。

HTML5 canvas 元素用于图形的绘制,通过脚本 (通常是JavaScript)来完成。
canvas 标签只是图形容器,您必须使用脚本来绘制图形。
你可以通过多种方法使用 canvas 绘制路径,盒、圆、字符以及添加图像。

这是一个注重实际案例的系列教程,我希望能够通过具体的案例,而非抽象的文档和解释带你学习 Canvas 这项技术。那么废话不多说,我们直接看这次的案例吧。

二、案例介绍

这是在很多博客网站上都非常常见的背景特效,在空旷的画布上,有非常多的随机运动的点,这些点在运动时如果距离足够近,则会产生连线。当鼠标移入时,也会为周围的点创建连线,同时与鼠标相连的点会受到鼠标的牵引。
我们可以将这个案例轻松地划分为三个由易到难的实现阶段:

  1. 简单效果:即完成点的自由运动、以及连线的自动产生。
  2. 复杂效果:鼠标移入时,完成鼠标与周围点的连线。
  3. 最终效果:鼠标移动时,与鼠标相连的点受到牵引。

在学习完这篇文章后,我建议你至少掌握到第二阶段,最终效果是否能够掌握取决于你是否有兴趣。

三、逐步实现

1. 文件创建

首先,创建一个html文件:

<!DOCTYPE html>
<html lang="cn">
<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <link rel="stylesheet" href="style.css">
    <script src="script.js" defer></script>
    <title>Document</title>
</head>
<body>
    <canvas id="canvas"></canvas>
</body>
</html>

同时,创建对应的CSS文件:

*
    margin: 0;
    padding: 0;


body
    background-color: #333;
    overflow: hidden;


#canvas
    position:fixed;
    left:0;
    top:0;

最后,创建一个js文件,接下来,我们将在js文件中进行编辑。

2. 简单效果的实现

因为这是本系列的第一期,因此我会比较啰嗦地讲一些 Canvas 的方法调用。
首先,我们需要创建一个 canvas 对象。

var canvas = document.getElementById("canvas");
canvas.width = window.innerWidth;
canvas.height = window.innerHeight;
var ctx = canvas.getContext("2d");

首先,我们需要找到 Canvas 对象,然后为 Canvas 对象设置宽高。
接下来,我们需要获取到 Canvascontext 对象。getContext("2d") 对象是内建的 HTML5 对象,拥有多种绘制路径、矩形、圆形、字符以及添加图像的方法。我们在进行绘制时,需要调用它上面的属性和方法。

var particles = []
var count = parseInt(canvas.height/150*canvas.width/150);
var maxDis = 150;

接下来,我们创建一个particles数组,用来存储所有的粒子对象,然后规定粒子的数目在每150*150像素一颗,最后定义连线的最大距离是150像素。
在完成了上面一系列准备动作以后,我们需要设计一个 Particle 类。

class Particle
    constructor(x,y) 
        this.x = x;
        this.y = y;
        this.directionY = 0.5 - Math.random();
        this.directionX = 0.5 - Math.random();
    

我们首先定义了Particle类的构造方法,它定义了位置xy,速度变量directionXdirectionY
接下来,我们需要设计一个更新方法,用于更新粒子下一步的状态:

    update() 
        this.x += this.directionX;
        this.y += this.directionY;
    

最后,我们需要为粒子对象设计一个draw方法,draw函数里直接调用了canvas的方法,用于在视图上绘制粒子:

    draw() 
        ctx.beginPath();
        ctx.arc(this.x,this.y,2,0,Math.PI*2);
        ctx.fillStyle = "white";
        ctx.fill();
    

这个方法中,我们使用了一开始拿到的context对象,利用这个对象上的属性和方法绘制粒子。在绘制粒子时,我们首先调用ctx.beginPath();表示开始绘制,接下来调用ctx.arc(this.x,this.y,2,0,Math.PI*2);在粒子所在的位置绘制一个半径为2的圆,最后使用ctx.stroke();表明绘制结束。

在canvas中绘制圆形, 我们将使用以下方法:
arc(x,y,r,start,stop)

通过以上几个方法,我们就完成了Particle类的定义,完整的代码如下:

class Particle
    constructor(x,y) 
        this.x = x;
        this.y = y;
        this.directionY = 0.5 - Math.random();
        this.directionX = 0.5 - Math.random();
    
    update() 
        this.x += this.directionX;
        this.y += this.directionY;
    
    draw() 
        ctx.beginPath();
        ctx.arc(this.x,this.y,2,0,Math.PI*2);
        ctx.fillStyle = "white";
        ctx.fill();
    

接下来,我们需要实现一个创建粒子的方法:

function createParticle()
    let x = Math.random() * canvas.width;
    let y = Math.random() * canvas.height;
    particles.push(new Particle(x, y));

我们每创建一个粒子,就将粒子放进我们的particles数组里。
下面,我们实现一个处理粒子的方法:

function handleParticle()
    particles.forEach((element,index) => 
        element.update();
        element.draw();
        if(element.x < 0 || element.x > canvas.width)
            element.directionX = - element.directionX;
        
        if(element.y < 0 || element.y > canvas.height) 
            element.directionY = - element.directionY;
        
        particles.forEach((aElement,index) => 
    		distance = Math.sqrt( Math.pow(element.x - aElement.x,2) + Math.pow(element.y - aElement.y,2) );
    		if(distance < maxDis) 
        		ctx.beginPath();
        		ctx.strokeStyle = "rgba(255,255,255," + (1 - distance / maxDis) + ")";
        		ctx.moveTo(element.x,element.y);
        		ctx.lineTo(aElement.x,aElement.y);
        		ctx.lineWidth = 1;
        		ctx.stroke();
    		
		)
    ); 

在粒子的处理函数中,我们通过forEach函数遍历每个粒子,然后分别调用粒子的update方法和draw方法,更新粒子的状态,并且绘制粒子。之后再做检查,如果粒子超出了canvas元素的边界,则通过改变它的速度方向使其反弹回去。

之后,我们还需要再进行一次内部遍历,检查当前粒子与其他粒子的距离,如果距离小于maxDis,则绘制粒子之间的线段。绘制的颜色可以将透明度设置为与距离有关,绘制的方法与上面的draw函数有异曲同工之妙,这里就不再啰嗦。

最后,我们通过调用一个定时器来完成粒子的动态效果:

function draw()
    ctx.clearRect(0,0,canvas.width,canvas.height);
    //清空画布内容
    if(particles.length < count) 
        createParticle();
    
    handleParticle();


setInterval(draw,10);

至此,我们已经完成了简单效果,即完成点的自由运动、以及连线的自动产生。这是实现了简单效果的完整代码:

var canvas = document.getElementById("canvas");
canvas.width = window.innerWidth;
canvas.height = window.innerHeight;
var ctx = canvas.getContext("2d");
var particles = []
var count = parseInt(canvas.height/150*canvas.width/150);
var maxDis = 150;

class Particle
    constructor(x,y) 
        this.x = x;
        this.y = y;
        this.directionY = 0.5 - Math.random();
        this.directionX = 0.5 - Math.random();
    
    update() 
        this.x += this.directionX;
        this.y += this.directionY;
    
    draw() 
        ctx.beginPath();
        ctx.arc(this.x,this.y,2,0,Math.PI*2);
        ctx.fillStyle = "white";
        ctx.fill();
    


function createParticle()
    let x = Math.random() * canvas.width;
    let y = Math.random() * canvas.height;
    particles.push(new Particle(x, y));


function handleParticle()
    particles.forEach((element,index) => 
        element.update();
        element.draw();
        if(element.x < 0 || element.x > canvas.width)
            element.directionX = - element.directionX;
        
        if(element.y < 0 || element.y > canvas.height) 
            element.directionY = - element.directionY;
        
        particles.forEach((aElement,index) => 
            distance = Math.sqrt( Math.pow(element.x - aElement.x,2) + Math.pow(element.y - aElement.y,2) );
            if(distance < maxDis) 
                ctx.beginPath();
                ctx.strokeStyle = "rgba(255,255,255," + (1 - distance / maxDis) + ")";
                ctx.moveTo(element.x,element.y);
                ctx.lineTo(aElement.x,aElement.y);
                ctx.lineWidth = 1;
                ctx.stroke();
            
        )
    ); 


function draw()
    ctx.clearRect(0,0,canvas.width,canvas.height);
    if(particles.length < count) 
        createParticle();
    
    handleParticle();


setInterval(draw,10);

3. 复杂效果的实现

实现简单效果以后,接下来,我们将演示如何实现复杂一些的效果,即鼠标移入时,完成鼠标与周围点的连线。
这个功能其实不难,在实现时最重要的在于获取当前的鼠标位置
这里我们选择使用全局变量mouseXmouseY来保存鼠标信息。同时设定一个鼠标捕获最大距离maxMouseDis

var mouseX = -1,mouseY = -1;
var maxMouseDis = 250;

同时,通过为canvas对象添加如下的鼠标事件,

canvas.addEventListener("mousemove",function(e) 
    mouseX = e.clientX;
    mouseY = e.clientY;
)
canvas.addEventListener("mouseout",function()
    mouseX = -1;
    mouseY = -1;
)

当鼠标在canvas元素上移动时,会实时更新鼠标位置,一旦鼠标移出canvas元素,我们就将mouseXmouseY置为-1作为标记。
添加完鼠标事件后,我们还需要设计一个鼠标处理函数:

function handleMouse()
    if(mouseX == -1 || mouseY == -1) return;
    particles.forEach((element,index) => 
        let distance = Math.sqrt( Math.pow(element.x - mouseX,2) + Math.pow(element.y - mouseY,2) );
        if(distance < maxMouseDis) 
            ctx.beginPath();
            ctx.strokeStyle = "rgba(255,255,255," + (1 - distance / maxMouseDis) + ")";
            ctx.moveTo(element.x,element.y);
            ctx.lineTo(mouseX,mouseY);
            ctx.lineWidth = 1;
            ctx.stroke();
        
    )

handleMouse函数中,我们需要遍历所有的粒子,一旦鼠标与粒子之间的距离小于设定的maxMouseDis,则开始连线,连线方式与上面handleParticle中一致。
最后,不要忘记在定时器函数draw中添加handleMouse

function draw()
    ctx.clearRect(0,0,canvas.width,canvas.height);
    if(particles.length < count) 
        createParticle();
    
    handleParticle();
    handleMouse();

通过上面一系列操作,我们已经完成了复杂效果,即鼠标移入时,完成鼠标与周围点的连线。这是完整的代码:

var canvas = document.getElementById("canvas");
canvas.width = window.innerWidth;
canvas.height = window.innerHeight;
var ctx = canvas.getContext("2d");
var particles = []
var count = parseInt(canvas.height/150*canvas.width/150);
var maxDis = 150;
var maxMouseDis = 250;
var mouseX = -1,mouseY = -1;

class Particle
    constructor(x,y) 
        this.x = x;
        this.y = y;
        this.directionY = 0.5 - Math.random();
        this.directionX = 0.5 - Math.random();
    
    update() 
        this.x += this.directionX;
        this.y += this.directionY;
    
    draw() 
        ctx.beginPath();
        ctx.arc(this.x,this.y,2,0,Math.PI*2);
        ctx.fillStyle = "white";
        ctx.fill();
    


function createParticle()
    let x = Math.random() * canvas.width;
    openharmony-基于arkui(js)实现移动粒子效果背景(代码片段)

...种网页背景,线条能自发的运动,并且可以让这些线条向鼠标聚集,就觉得挺有意思的,让我们来试着用鸿蒙JS来实现这个炫酷的背景吧!效果演示实现步骤1.创建canvas标签设置画布的大小,背景颜色,以及触摸事件。<divclass=&... 查看详情

前端特效demo|值得收藏的6个html5canvas实用案例

 HTML5动画在Canvas上得到了充分的发挥,我们VIP视频也分享过很多相关的动画特效制作视频,这次给大家带来6款超炫酷的HTML5canvas动画的demo,一起来看看吧~ 文内附有时钟效果代码demo下载地址,感兴趣的小伙伴们可以收藏... 查看详情

七款炫酷的页面特效

...款利用HTML5 Canvas模拟出来的30000个粒子动画,当你用鼠标在canvas画布上移动时,鼠标周围的一些粒子就会跟着你移动,并形成一定的图案,就像你在玩沙画一样,效果非常不错。这里,我们应用了一些HTML5的特性,让这个粒子... 查看详情

关于canvas粒子特效实现分析

...围内随机波动粒子的位置是随机的粒子的个数是固定的当鼠标移动时,在鼠标周围产生特定的粒子并连线,向四周移动,达到一定条件消失。参考了知乎登录首页ca 查看详情

前端例程20220913:粒子飘落效果动画背景(代码片段)

演示原理使用JS动态创建块元素作为粒子,动态设置其位置、大小、颜色等属性,动态设置每个粒子的动画。代码<!DOCTYPEhtml><htmllang="en"><head><metacharset="UTF-8"><metaname="viewport& 查看详情

canvas粒子效果

varcanvas=document.createElement(‘canvas‘);varcxt=canvas.getContext(‘2d‘);varW=canvas.width=500;varH=canvas.height=200;varstr=‘Grewer,点击此处‘;cxt.textBaseline=‘top‘;cxt.font=‘60px宋体‘varsw=cxt.measureTex 查看详情

canvas+javascript制作图片粒子效果

 首先看一下源图和转换成粒子效果的对比图:   左侧图片为源图,右侧图片为粒子效果图。该效果是在Canvas画布上制作的。将图片制作成粒子效果相对而言是比较简单的。重点了解两个知识点即可1:图片是通过imag... 查看详情

unity每日灵感第一期:ipointer_?_handler接口实现有趣的鼠标交互(代码片段)

...用的好玩的点子,或者尚未实现的有趣功能复刻。第一期:EventSystems中的IPointerClickHandler、IPointerEnterHandler、IPointerExitHandler等...对鼠标回调事件的检测和函数控制。目录一、接口及其函数方法总结〇EventSystems①IPointerClickHa... 查看详情

canvas实现的粒子效果

前言:我的这个share很简单,没什么技术水准,主要是我自己觉得canvas这个标签很cool!,简单实用又能装X,而且又能实现很多看起来很炫的东西。 一关于canvas<canvas>是一个可以使用脚本(通常为JavaScript)在其中绘制图形的&n... 查看详情

暑假训练第一期---思维题1

A-LittleRobberGirl’sZooCodeForces686BTimeLimit:2000MSMemoryLimit:262144KB64bitIOFormat:%I64d&%I64uDescriptionLittleRobberGirllikestoscareanimalsinherzooforfun.Shedecidedtoarrangetheanimalsinarowin 查看详情

博客背景随着鼠标动的效果实现

在博客侧边栏公告中加上如下这段js:<!---导入js库---><scriptsrc="//cdn.bootcss.com/canvas-nest.js/1.0.0/canvas-nest.min.js"><canvasid="c_n4"width="860"height="958"style="position:fixed;top:0px;left:0px;z-in 查看详情

使用html5canvas创建动态粒子网格动画

最近看到一个粒子网格动画挺炫的,自己也就做了一个,当背景挺不错的。CSDN不能上传超过2M的图片,所以就简单截了一个静态图片:可以点击这里查看动画.下面就开始说怎么实现这个效果吧:首先当然是添加一个canvas了:<c... 查看详情

团队管理_第一期干部训练营心得

活动一:传数字游戏 游戏规则:一个班分成几个小组,每个小组平均10人以上,然后各个小组内站成一列,老师会给最后面的人一个数字,然后后面的人把数字按照队列排序一个一个传上来,然后传到第一个人时,第一个人... 查看详情

背景粒子动态变化动画

        varcanvas=document.getElementById("cas");  varctx=canvas.getContext("2d");  resize();  window.onresize=resize;  functionresize()    canvas.width=window.innerWidt 查看详情

canvas把数据转为粒子特效(代码片段)

...前经常在一些网站看到一些特别炫酷的特效,例如文字呈粒子状的特效,或图片的蒙太奇效果,刚巧找了相关的canvas动画研究了一些,因此在这里做一个简单的总结。  思路  一个像素点是由四个值组成的 RGBA,第一个... 查看详情

canvas粒子系统的构建

...从最基本的imageData对象的理论知识说开去,详细介绍canvas粒子系统的构建 效果演示  下面是实例效果演示,博文结尾有全部源码  imageData  关于图像数据imageData共有3个方法,包括getImageData()、putImageData()、createImag... 查看详情

canvas动画之二--创建动态粒子网格动画(代码片段)

最近看到一个粒子网格动画挺炫的,自己也就做了一个,当背景挺不错的。CSDN不能上传超过2M的图片,所以就简单截了一个静态图片:可以点击这里查看动画.下面就开始说怎么实现这个效果吧:首先当然是添... 查看详情

canvas粒子系统的构建

...从最基本的imageData对象的理论知识说开去,详细介绍canvas粒子系统的构建 效果演示  下面是实例效果演示,博文结尾有全部源码 imageData  关于图像数据imageData共有3个方法,包括getImageData()、putImageData()、createImageData(... 查看详情