PK创意闹新春,我正在参加「春节创意投稿大赛」,详情请看:春节创意投稿大赛
介绍
canvas 是 html 中的一个标签,画布的含义,功能上和 window 系统自带的 画图 工具类似,唯一不同的是需要我们使用 js 来渲染我们需要的效果
入门三板斧
- 在 DOM 上定义一个带有长宽属性的 canvas 标签
<canvas id="canvas" width="300px" height="300px" style="background:#000"></canvas>
为了直观的看到效果,给定一个背景色
- 通过 js 获取到对应的 canvas 上的 “画笔” 引用,后续我们在 canvas 所有的绘制操作,基本上都是需要通过这个 “画笔”
let cx = document.getElementById('canvas').getContext('2d')
如代码,我们拿到了 2D 的画笔
- 使用 “画笔” 绘制我们需要的图形,比如基础的线、圆、矩阵等
// 画圆
function drawArc(x, y, r) {
cx.beginPath();
cx.arc(x, y, r, 0, 2 * Math.PI);
cx.fill();
}
// 画线
function drawLine(startX, startY, endX, endY) {
cx.beginPath();
cx.moveTo(startX, startY);
cx.lineTo(endX, endY);
cx.stroke();
cx.closePath()
}
// 画笔自带的矩阵绘制函数 cx.fillRect(x, y, width, height)
drawArc(50,50,10);
drawLine(50, 70, 50, 200);
cx.fillRect(100,100,50,100)
注意:在画布中的坐标系,已在上图中用红色线条标记出来。以画布的左上角为原点,往右为 x,往下为 y
因为画布的特性是一张纸,我们在上面的所有绘制操作,都会影响到上一次绘制的结果,即为覆盖绘制。举个例子,就如 PS 的图层,我们的每次操作,都是绘制在新建的,最顶部的图层之上;但不如 PS 的是,没法对之前的图层做修改。
好了,现在我们对 canvas 有了一定的了解,开始动手做点小东西
绘制烟花
我们熟知的烟花效果分 2 个阶段:① 是烟花快速上升 ② 是烟花上升到某个点后,炸开,形成的火花四散然后消失
烟花有一个最大的效果,就是尾焰拖拽。这里有两种实现的思路:
① 每次的轨迹绘制,前半部分,使用实线,后半部分,使用渐变的透明线;
② 利用画布的覆盖绘制的特性,每帧绘制之前,全图层覆盖一个有有透明度的背景色,每次覆盖后,画布上的图形都会变淡。
本次示例考虑采用方案 ②,定时为整个画布叠加透明背景色,剩下的只需要考虑点的位置绘制
绘制上升阶段的动画
获取到页面的可视高度,设置为烟花的起点,获取到随机的上升高度,设置一个每次上升的速度(即每帧上升几个像素点)
let hz = 1000 / 75;
fireUp(200, 2);
function fireUp(x, r) {
let y = window.innerHeight;
ramdomTop = parseInt(Math.random() * 500) + 100;
let cleanT = setInterval(() => clean(), hz*1.2);
let time = setInterval(() => {
if (y < ramdomTop) {
// clearInterval(time);
y = window.innerHeight;
}
y -= 4;
drawPoint(new Point(x, y, r))
}, hz);
}
绘制烟花四散的效果
核心就是使用 Math.sin(), Math.cos() 计算每个角度的 x, y 坐标,然后修改中心点,就得到了指定坐标四周各个角度的坐标关系,我们根据这个关系均等份的计算出各角度的匀速运动轨迹
// 计算四周的点位数据
function caculatePoints(px, py, step, maxR) {
/**
* [p1-x]
* [p2-x]
*/
let arrs = [];
for (let i = step; i <= 360; i += step) {
arrs.push(new Point(Math.cos(Math.PI / 180 * i).toFixed(4),
Math.sin(Math.PI / 180 * i).toFixed(4),
2));
}
let arrs2 = [];
for (let i = 1; i < maxR; i++) {
arrs2.push(arrs.map(n => new Point(n.x * i + px, n.y * i + py, n.r, n.color)));
}
return arrs2;
}
烟花绽放的 function 里插入这个函数的调用
效果如图示:
五颜六色的绽放轨迹
效果实现了,全白的烟花一下子就看腻了,给烟花的绽放效果添加一个随机的颜色
因为绽放后,每个轨迹上的效果,一般是同色,或者是相近的颜色,才会符合实际,这个功能适合添加在四周点生成的函数内
修改使用 Point 对象,绑定 color。再定义一个生成随机 RGB 的函数
function Point(x, y, r = 2, color = '#fff') {
return {
x: x,
y: y,
r: r,
color: color
}
}
let rgb = function() {
let str = ['1', '2', '3', '4', '5', '6', '7', '8', '9', 'a', 'b', 'c', 'd', 'e', 'f'];
return {
ramdon() {
let color = '#';
for (let i = 0; i < 6; i++) {
color += str[parseInt(Math.floor(Math.random() * 16))]
}
return color;
}
}
}();
caculatePoints() 在创建 Point 实例的时候传入随机 RGB,改动如下
改动后的效果如下:
重头戏
费这么大劲做个 DOME 自己看多难受,这不得搬上掘金当背景?
加上随机的放烟花,以及限定最大的烟花数量,首页美化后的样式:
油猴链接
脚本做的简简单单,安装就能实现同款效果
改进
为烟花的效果增加更多的随机值,比如上升的速率,炸开后的运动半径
待改进
绽放的效果还是有些僵硬,继续研究重力的加速度,安排上去之后应该会更加漂亮
原创文章,未经允许,禁止转载
create by:安逸的咸鱼