炫酷粒子表白 | 听说女神都想谈恋爱了!

最近听女神说想谈恋爱了,?(? ? ?) 嘿嘿,一定不能放过这个机会,给她来个不一样的表白。

那么咱们就一起来把这个粒子系统玩出花来吧

演示地址:

https://es2049.studio/work-show/textPraticle/

如何将一系列的粒子组成一句表白呢?

实现原理其实很简单,Canvas 中有个 getImageData 的方法,可以得到一个矩形范围所有像素点数据。那么我们就试试来获取一个文字的形状吧。

第一步,用 measureText 的方法来计算出文字适当的尺寸和位置。

// 创建一个跟画布等比例的 canvas

const width = 100;

const height = ~~(width * this.height / this.width); // this.width , this.height 说整个画布的尺寸

const offscreenCanvas    =document.createElement(‘canvas‘);

const offscreenCanvasCtx    =offscreenCanvas.getContext(‘2d‘);

offscreenCanvas.setAttribute(‘width‘, width);

offscreenCanvas.setAttribute(‘height‘, height);

// 在这离屏 canvas 中将我们想要的文字 textAll 绘制出来后,再计算它合适的尺寸

offscreenCanvasCtx.fillStyle = ‘#000‘;

offscreenCanvasCtx.font = ‘bold 10px Arial‘;

constmeasure=offscreenCanvasCtx.measureText(textAll); // 测量文字,用来获取宽度

const size = 0.8;

// 宽高分别达到屏幕0.8时的size

const fSize=Math.min(height * size * 10 / lineHeight, width * size * 10 / measure.width);  // 10像素字体行高 lineHeight=7 magic

offscreenCanvasCtx.font = `bold ${fSize}px Arial`;

// 根据计算后的字体大小,在将文字摆放到适合的位置,文字的坐标起始位置在左下方

const measureResize    =offscreenCanvasCtx.measureText(textAll);

// 文字起始位置在左下方

let left = (width - measureResize.width) / 2;

const bottom=(height + fSize / 10 * lineHeight) / 2;

offscreenCanvasCtx.fillText(textAll, left, bottom);

咱们可以 appendChild 到 body 里看眼

同学们注意,我要开始变形了 [推眼镜] 。

getImageData 获取的像素数据是一个 Uint8ClampedArray (值是 0 - 255 的数组),4 个数一组分别对应一个像素点的 R G B A 值。我们只需要判断 i * 4 + 3 不为 0 就可以得到需要的字体形状数据了。

// texts 所有的单词分别获取 data ,上文的 textAll 是 texts 加一起

Object.values(texts).forEach(item => {

offscreenCanvasCtx.clearRect(0, 0, width, height);

offscreenCanvasCtx.fillText(item.text, left, bottom);

left += offscreenCanvasCtx.measureText(item.text).width;

const data = offscreenCanvasCtx.getImageData(0, 0, width, height);

const points = [];

// 判断第 i * 4 + 3 位是否为0,获得相对的 x,y 坐标(使用时需乘画布的实际长宽, y 坐标也需要取反向)

for (let i = 0, max = data.width * data.height; i < max; i++) {

if (data.data[i * 4 + 3]) {

points.push({

x: (i % data.width) / data.width,

y: (i / data.width) / data.height

});

}

}

// 保存到一个对象,用于后面的绘制

geometry.push({

color: item.hsla,

points

});

})

制定场景,绘制图形

文字图形的获取方式以及搞定了,那么咱们就可以把内容整体输出了。咱们定义一个简单的脚本格式。

// hsla 格式方便以后做色彩变化的扩展

const color1 = {h:197,s:‘100%‘,l:‘50%‘,a:‘80%‘};

const color2 = {h:197,s:‘100%‘,l:‘50%‘,a:‘80%‘};

// lifeTime 祯数

const Actions = [

{lifeTime:60,text:[{text:3,hsla:color1}]},

{lifeTime:60,text:[{text:2,hsla:color1}]},

{lifeTime:60,text:[{text:1,hsla:color1}],

{lifeTime:120,text:[

{text:‘I‘,hsla:color1},

{text:‘??‘,hsla:color2},

{text:‘Y‘,hsla:color1},

{text:‘O‘,hsla:color1},

{text:‘U‘,hsla:color1}

]},

];

根据预设的脚本解析出每个场景的图形,加一个 tick 判断是否到了 lifeTime 切换到下一个图形重新绘制图形。

function draw() {

this.tick++;

if (this.tick >= this.actions[this.actionIndex].lifeTime) {

this.nextAction();

}

this.clear();

this.renderParticles(); // 绘制点

this.raf = requestAnimationFrame(this.draw);

}

function nextAction() {

....//切换场景 balabala..

this.setParticle(); // 随机将点设置到之前得到的 action.geometry.points 上

}

这样咱们基本的功能已经完成了。

能不能再给力一点

说好的粒子系统,现在只是 context.arc 简单的画了一点。那咱们就来加个粒子系统吧。

class PARTICLE {

// x,y,z 为当前的坐标,vx,vy,vz 则是3个方向的速度

constructor(center) {

this.center = center;

this.x = 0;

this.y = 0;

this.z = 0;

this.vx = 0;

this.vy = 0;

this.vz = 0;

}

// 设置这些粒子需要运动到的终点(下一个位置)

setAxis(axis) {

this.nextX = axis.x;

this.nextY = axis.y;

this.nextZ = axis.z;

this.color = axis.color;

}

step() {

// 弹力模型 距离目标越远速度越快

this.vx += (this.nextX - this.x) * SPRING;

this.vy += (this.nextY - this.y) * SPRING;

this.vz += (this.nextZ - this.z) * SPRING;

// 摩擦系数 让粒子可以趋向稳定

this.vx *= FRICTION;

this.vy *= FRICTION;

this.vz *= FRICTION;

this.x += this.vx;

this.y += this.vy;

this.z += this.vz;

}

getAxis2D() {

this.step();

// 3D 坐标下的 2D 偏移,暂且只考虑位置,不考虑大小变化

const scale = FOCUS_POSITION / (FOCUS_POSITION + this.z);

return {

x: this.center.x + (this.x * scale),

y: this.center.y - (this.y * scale),

};

}

}

大功告成!

既然是 3D 的粒子,其实这上面还有不是文章可做,同学们可以发挥想象力来点更酷炫的。

还有什么好玩的

上面是将粒子摆成文字。那咱们当然也可以直接写公式摆出个造型。

// Actions 中用 func 代替 texts

{

lifeTime: 100,

func: (radius) => {

const i = Math.random() * 1200;

let x = (i - 1200 / 2) / 300;

let y = Math.sqrt(Math.abs(x)) - Math.sqrt(Math.cos(x)) * Math.cos(30 * x);

return {

x: x * radius / 2,

y: y * radius / 2,

z: ~~(Math.random() * 30),

color: color3

};

}

}

再把刚才文字转换形状的方法用一下

{

lifeTime: Infinity,

func: (width, height) => {

if(!points.length){

const img = document.getElementById("tulip");

constoffscreenCanvas = document.createElement(‘canvas‘);

constoffscreenCanvasCtx = offscreenCanvas.getContext(‘2d‘);

const imgWidth = 200;

const imgHeight = 200;

offscreenCanvas.setAttribute(‘width‘, imgWidth);

offscreenCanvas.setAttribute(‘height‘, imgHeight);

offscreenCanvasCtx.drawImage( img, 0, 0, imgWidth, imgHeight);

let imgData=offscreenCanvasCtx.getImageData( 0, 0, imgWidth, imgHeight);

for ( let i = 0, max = imgData.width * imgData.height; i < max; i++) {

if (imgData.data[i * 4 + 3]) {

points.push({

x: (i % imgData.width) / imgData.width,

y: (i / imgData.width) / imgData.height

});

}

}

}

const p= points[~~(Math.random() * points.length)]

const radius = Math.min(width * 0.8, height * 0.8);

return {

x: p.x * radius - radius / 2,

y: (1 - p.y) * radius - radius / 2,

z: ~~(Math.random() * 30),

color: color3

};

}

}

完美 ??

然后咱也可以用 drawImage 绘制图片来代替 arc 画点。

等等!!前面的效果总觉得哪里不对劲,好像有些卡 。

优化小提示

1、分层。如果还需要增加一些其他的内容到 Canvas 中的话,可以考虑拆出多个 Canvas 来做。

2、减少属性设置。包括 lineWidth、fillStyle 等等。Canvas 上下文是很复杂的一个对象,当你调它的一些属性设置时消耗的性能还是不少的。arc 之类的画图方法也要减少。

3、离屏绘制。不用 arc 画点,要怎么办。上面的延迟其实就是每次画点时都调用了一遍 fillStyle、arc。但是当我们绘制图片 drawImage 时,性能明显会好上很多。drawImage 除了直接绘图片外,还能绘制另一个 Canvas,所以我们提前将这些点画到一个不在屏幕上的 Canvas 里就可以了。

4、减少 js 计算,避免堵塞进程,可以使用 web worker。当然咱们目前的计算完全用不上这个

我这使用了 3000 个粒子,对比下使用离屏绘制前后的帧率。

总结

现在唯一限制你的就是想象力了。大家一起去征服老板,征服女神!

参考:

  • deformable particles

    https://codepen.io/airen/pen/owRMoY

  • Canvas 参考手册

    http://www.w3school.com.cn/tags/html_ref_canvas.asp

  • y=sqrt(abs(x))-sqrt(cos(x))*cos(40x)

作者:ES2049

来源:https://juejin.im/post/5bdfe1dbe51d45054771f9d4

原文地址:https://www.cnblogs.com/Highdoudou/p/10101778.html

时间: 2024-10-29 19:05:35

炫酷粒子表白 | 听说女神都想谈恋爱了!的相关文章

一款炫酷Loading动画--加载成功

简介 昨天在简书上看到一篇文章,介绍了一个加载动画的实现过程 一款Loading动画的实现思路(一) 只可惜原动画是IOS上制作的,而看了一下,作者的实现思路比较复杂,于是趁着空闲写了一个Android版本,这篇文章将给大家介绍一下实现过程. 首先让我们来看一下动画效果 动画结构分析 从上面的gif图中可以看到,这个加载动画有成功,失败两种状态,由于Gif速度比较快,我们再来分别看一张慢图 1.成功状态加载动画 成功动画的状态转移描述如下: 1.加载过程,画蓝色圆环,当进度为100%时,圆环完成

iOS动画开发之五——炫酷的粒子效果

iOS动画开发之五--炫酷的粒子效果 在上几篇博客中,我们对UIView层的动画以及iOS的核心动画做了介绍,基本已经可以满足iOS应用项目中所有的动画需求,如果你觉得那些都还不够炫酷,亦或是你灵光一现,想用UIKit框架写出一款炫酷的休闲游戏,那个有一个东西可以帮到你:iOS的粒子效果引擎. 一.粒子发射器 iOS中的粒子效果有两部分组成,一部分为发射器,设置例子发射的宏观属性,另一部分是粒子单元,用于设置相应的粒子属性.粒子发射器是基于Layer层,没错,又是Layer,他的全名叫做: CA

JParticles 2.0 发布,打造炫酷的粒子特效

JParticles 2.0 发布,打造炫酷的粒子特效.不好意思哈,在这么繁花似锦的世界里,标题不得不取得吸引眼球一点哈,不然...还是不啰嗦了,我们进入正题吧 简单介绍一下 JParticles 2.0 版本之前还叫 Particleground.js,相信在用的朋友应该不会陌生,关于 1.x 版本的宣传文案可以移步看这里哈,或许可以帮助你了解 JParticles 2.0 的一些东西. 我们一贯的理念 我们(我/笑哭)一贯的理念是信仰:"The Write Less, Do More&quo

「珍藏」老司机为你推荐10个炫酷的开源库,看完的人都收藏了

前言 技术群里面经常有人问到一些炫酷的UI效果实现方法,有时候我都是给一个相同或者相似效果的Github链接,有同学私信给我说,大佬,怎么这些效果你都能找到?你是怎么搜索的,或者有其他什么秘方?会利用Google.百度等搜索工具搜索是一方面,另一个重要的方面是:记录搜藏,当看到一个炫酷的效果的时候,记得收藏起来,记录到自己云笔记或者收藏夹里,看得多了,印象就比较深刻,当遇到类似效果的时候,到自己记录收藏的地方找就是了.今天为大家推荐我所收藏的一些炫酷实用的效果的开源库(选择其中10个). 1.D

html5轻量级炫酷js粒子动画库插件

这是一款基于html5 canvas的轻量级炫酷js粒子动画库插件.该粒子动画库js插件可以设置粒子的形状.旋转.分布.颜色等属性,还可以动态添加粒子,效果非常酷. 同样的例子效果还有:HTML5 Canvas彩色的光粒子模拟粒子运动动画效果. 在线演示:http://www.htmleaf.com/Demo/201501301300.html 下载地址:http://www.htmleaf.com/html5/html5-canvas/201501301299.html

10大炫酷的HTML5文字动画特效欣赏

文字是网页中最基本的元素,在CSS2.0时代,我们只能在网页上展示静态的文字,只能改变他的大小和颜色,显得枯燥无味.随着HTML5的发展,现在网页中的文字样式变得越来越丰富了,甚至出现了文字动画,HTML5和CSS3的强大之处就在于此.本文分享的10款炫酷的HTML5文字动画特效非常不错,一起来看看吧. 1.HTML5 Canvas粒子效果文字动画特效 之前我们分享过很多超酷的文字特效,其中也有利用HTML5和CSS3的.今天我们要来分享一款基于HTML5 Canvas的文字特效,输入框中输入想

『HTML5梦幻之旅』 - 炫酷的节日贺卡

刚过完春节,想必大家收到了各种祝福和贺卡吧-Y某我今年也为同学和家人准备了贺卡.不一样的是,我的贺卡可不是made from树,而是一行行代码凝聚而来的. 考虑到本次开发需要的功能不多,所以就没有用库件了,利用纯Html5 Canvas API来完成本次梦幻之旅:节日贺卡.虽然用到的Canvas API不多,但是效果还是蛮理想的- 首先上截图吧: 哎呀,看到了截图,各位是不是领悟了传说中的炫酷华丽(luàn qī bā zāo)? 测试地址:http://wyh.wjjsoft.com/demo

前端交互开发微体验--总结了一些国内外炫酷的网站

前端交互开发微体验 关于首屏灵动小效果,微交互提升页面生机: 一.关于首屏视频播放 http://designmodo.com/startup/ 感官体验:科技感,高大上,酷 综合评价:如页面请求不多且视频占空小的情况下使用.一般为首屏轮播图的情况下使用,前两张轮播为图片,最后为视频,多给视频一些加载时间.还有就是非首屏使用. 推荐指数:★★★☆☆     二.Hover时实现图片随着鼠标方向而变动 http://atieva.com/ https://labs.invisionapp.com/

视频编辑SDK---我们只提供API,任你自由设计炫酷的功能

做视频APP, 在于差异化,个性的APP; 你做一个别人一样功能的APP, 很难占领市场. 基于此.我们的SDK完全以API的形式,至于界面和操作炫酷的功能,任你自由发挥, 视频编辑:即类似秒拍,美拍,快手,小影等APP中对音视频做剪切/裁剪/分离/合并/标记/贴纸/叠加/滤镜等操作. 我们有Android版本基本视频编辑SDK: https://github.com/LanSoSdk/LanSoEditor_common 主要功能有: 1,使用在音视频的: 裁剪,剪切,分离,合并,转换,拼接,