html怎么加粒子特效,使用Canvas给DOM元素添加粒子效果

让我们来看看如何将的自由度与HTML元素结合起来,使Web页面在视觉上有更好的效果。具体地说,我们将创建一个基于HTML-to-particle的效果,但同样的技术也可以用于实现很多类型的效果。

在开始之前,可以通过Repo获取源代码。

创建初始的元素

首先,让我们创建一个HTML元素。这里创建了一个带有简单样式效果的按钮,事实上它可以是任何一个HTML元素。

建议使用Chrome、Firefox或Edge等现代浏览器查看这些Demo效果。

但是,如何让canvas“看到”这个元素,以便使用canvas来 操作每个像素 呢?为了实现这一点,需要对HTML元素进行快照 —— 就像“打印屏幕”一样,但只对希望在canvas中操作的特定元素(比如说按钮)进行快照。

创建canvas版本的元素

尽管浏览器到目前还无法实现这一点,但庆幸的是允许我们通过JavaScript来操作它,较为出名的html2canvas库就可以。我们所要做的就是加载这个库,然后调用html2canvas(element),它将返回一个Promise以及一个canvas版本的元素。是不是很棒。

上面这个示例,我们有一个HTML版本和Canvas版本的按钮。我们可以使用Canvas版本作为我们的“屏幕快照”,并将其作为信息的来涨势,例如特定像素位置的颜色。

a8463b6bdefb248fda49bc9ec8b9e885.png

从Canvas中获取数据

为此,我们创建一个新函数来获取Canvas中特定位置的像素信息。我们也不需要显示从Canvas中得到的颜色数据,因为我们显示原始的HTML元素。

function getColorAtPoint(e) {

// 获取鼠标点击位置的坐标

let x = e.offsetX;

let y = e.offsetY;

// 获取该位置上颜色数据

let rgbaColorArr = ctx.getImageData(x, y, 1, 1).data;

// rgbaColorArr相关的处理

}

现在我们需要使用这些信息创建一个Canvas的粒子效果。

创建Canvas粒子效果

我们还没有使用Canvas来放置粒子,因为我们想要保留html2canvas的canvas用于访问颜色信息。接下来创建粒子效果的函数。

var particleCanvas, particleCtx;

function createParticleCanvas() {

// 创建用于粒子效果的Canvas

particleCanvas = document.createElement("canvas");

particleCtx = particleCanvas.getContext("2d");

// Canvas的大小

particleCanvas.width = window.innerWidth;

particleCanvas.height = window.innerHeight;

// Canvas的位置

particleCanvas.style.position = "absolute";

particleCanvas.style.top = "0";

particleCanvas.style.left = "0";

// 设置Canvas在元素的上面

particleCanvas.style.zIndex = "1001";

// 确保它下面的其他元素是可点击的

particleCanvas.style.pointerEvents = "none";

// 把Canvas添加到页面中

document.body.appendChild(particleCanvas);

}

获取坐标数据

我们还需要从本地坐标系统得到颜色相关的数据 —— 不仅仅是按钮的左上角,而且全局坐标的位置(相对整个Web页面),这样做是为了在Canvas的正确地方创建粒子。

我们可以这样做:

btn.addEventListener("click", e => {

// 获取颜色数据

let localX = e.offsetX;

let localY = e.offsetY;

let rgbaColorArr = ctx.getImageData(localX, localY, 1, 1).data;

// 根据window获取按钮的位置

let bcr = btn.getBoundingClientRect();

let globalX = bcr.left + localX;

let globalY = bcr.top + localY;

// 使用window的位置获取颜色数据,创建一个粒子

createParticleAtPoint(globalX, globalY, rgbaColorArr);

});

创建一个粒子原型

我们还可以创建一个基本粒子,是一个带有参数的绘图函数:

/* 圆形爆炸的粒子效果 */

var ExplodingParticle = function() {

// 设置想要的粒子动画的时长

this.animationDuration = 1000; // in ms

// 设置粒子的速度

this.speed = {

x: -5 + Math.random() * 10,

y: -5 + Math.random() * 10

};

// 粒子大小

this.radius = 5 + Math.random() * 5;

// 为粒子设定一个最大的生存时间

this.life = 30 + Math.random() * 10;

this.remainingLife = this.life;

// 这个函数稍后将会调用动画相关的逻辑

this.draw = ctx => {

let p = this;

if(this.remainingLife > 0

&& this.radius > 0) {

// 在当前位置绘制一个圆

ctx.beginPath();

ctx.arc(p.startX, p.startY, p.radius, 0, Math.PI * 2);

ctx.fillStyle = "rgba(" + this.rgbArray[0] + ',' + this.rgbArray[1] + ',' + this.rgbArray[2] + ", 1)";

ctx.fill();

// 更新粒子的位置和生命

p.remainingLife--;

p.radius -= 0.25;

p.startX += p.speed.x;

p.startY += p.speed.y;

}

}

}

创建一个粒子工厂

我们还需要一个基于一些坐标和颜色信息的函数,这个函数主要用来创建这些粒子,确保我们将它们添加到创建的粒子数组中:

var particles = [];

function createParticleAtPoint(x, y, colorData) {

let particle = new ExplodingParticle();

particle.rgbArray = colorData;

particle.startX = x;

particle.startY = y;

particle.startTime = Date.now();

particles.push(particle);

}

添加动画逻辑

我们还需要一种方法,让创建出来的粒子动起来。

function update() {

// 清除旧粒子

if(typeof particleCtx !== "undefined") {

particleCtx.clearRect(0, 0, window.innerWidth, window.innerHeight);

}

// 在新位置绘制所有粒子

for(let i = 0; i < particles.length; i++) {

particles[i].draw(particleCtx);

// 如果最后一个粒子完成动画,清除旧的粒子

if(i === particles.length - 1) {

let percent = (Date.now() - particles[i].startTime) / particles.animationDuration;

if(percent > 1) {

particles = [];

}

}

}

// 动画性能

window.requestAnimationFrame(update);

}

window.requestAnimationFrame(update);

把这几个部分放在一起,现在可以基于HTML元素创建粒子。当我们点击它时,可以看到效果。

25156c3690ac73040a6d22b078f09c3c.gif

如果我们想要点击整个按钮会爆炸,而不仅是一个像素。我们只需要修改我们的点击函数。

let reductionFactor = 17;

btn.addEventListener("click", e => {

// 获取按钮的颜色数据

let width = btn.offsetWidth;

let height = btn.offsetHeight

let colorData = ctx.getImageData(0, 0, width, height).data;

// 跟踪重复了多少次(为了减少创建的粒子总数)

let count = 0;

// 遍历按钮的每个位置并创建一个粒子

for(let localX = 0; localX < width; localX++) {

for(let localY = 0; localY < height; localY++) {

if(count % reductionFactor === 0) {

let index = (localY * width + localX) * 4;

let rgbaColorArr = colorData.slice(index, index + 4);

let bcr = btn.getBoundingClientRect();

let globalX = bcr.left + localX;

let globalY = bcr.top + localY;

createParticleAtPoint(globalX, globalY, rgbaColorArr);

}

count++;

}

}

});

9d70e0ace9be9f176acb491f4ab0f213.gif

现在Web方面的限制相对较少,因为我们知道我们可以添加像canvas来创建更多的自由性。

通过使用边缘检测来判断元素是否超出容器边界(即隐藏在视图之外),并在元素超出边界时创建粒子。这样可以有更多的创意。

这样的一个过程可以写一篇文章来阐述,因为在Web浏览器中对元素的定位是复杂的,但是我写了一个叫做Disintegration的小插件,其中包括对这类事情的处理。

Disintegrate插件

Disintegrate是开源的,它处理了一些Web浏览器兼容这个效果的代码。它还允许多个元素在同一个页面上应用此效果,如果需要,可以忽略指定的颜色,以及处理过程中不同重要时刻的事件。

我们只需要在按钮上声明data-distype="contains",将使我们的元素超出容器边界时,粒子将被创建。比如下面这个Demo效果。

9b302f2052e20558afa0d67e92324354.gif

使用Disintegrate的另一个效果。允许使用self-contained的粒子动画,比如我们之前所做的按钮效果。通过动画容器和主元素本身,可以创建更有趣的粒子效果。

4b736187129aa73e40c5e18352d7205e.gif

然而,这种方法确实有其局限性(Disintegrate也是如此)。例如,它只能在IE11运行,因此在此之前缺乏ponter-events事件的支持。由于html2canvas的限制,Disintegration也不支持我们想要的所有DOM元素。我发现最受限的是CSS的transform和clip-path。

如果你想要安装Disintegrate,可以使用npm install disintegrate进行安装。或者可以在disintegrate.init()之前手动引用html2canvas.js和disintegrate.js。

Disintegrate是一个新写的插件,还有一些需要进行改进。如果你愿意,可以给Disintegrate和html2canvas提供相关的建议。

如何在你的项目中使用这个功能,或者说使用它们来扩展Web的功能,有较好的建议或想法的话,欢迎在下面的评论中与我们一起分享。

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值