PK创意闹新春,我正在参加「春节创意投稿大赛」,详情请看:春节创意投稿大赛
炸掘金
在我小的时候,逢年过节,我就是村里名副其实的“炮王”,炸"玻璃瓶"、炸"鱼"、炸"石头"、炸"粪坑"……
不知不觉,我已经到了30好几,到了年节我再也不是“炮王”。
但今年,我准备干一票大的:把 “掘金” 给炸了!
说到做到!我,代码暴徒,肆无忌惮!
光炸网页端还不够!把它们 APP
也给端了!
手把手带你写
1. 需要了解的前置知识
- 德劳内三角化:又被称为
Delaunay
三角网,是一种将平面或曲面分割成N
个不交叉三角形的图形学处理技术。
(我们用它把掘金打成碎片!) animejs
:一款被广泛使用的前端动画库。
(我们用它把掘金扔向深渊!)
2. 如何点“炮仗”?
我不生产爆炸物,我是炮仗的搬运工。
“炮仗”部分的实现来自掘友 @creen青春 的一篇文章:用svg实现鞭炮计时器
简单来说,分三步:
- 用
svg
技术画一个 🧨。 - 用
animejs
绘制引线变短动画。 - 用
animejs
绘制火星移动动画。
详细玩法,还请大家移步原帖:用svg实现鞭炮计时器
3. 如何产生爆炸效果?
哪有什么爆炸?只有发光变大的
div
而已。
效果唬人的爆炸光波,闪光弹效果,实现起来可太容易了!
我们只需要让一个宽高为 0px
的 div
膨胀到整个屏幕大小,然后再缓缓缩小它即可。
为了增加爆炸发生时的“炫目感”,我们可以让背景在这个过程中也快速变黑,然后缓缓退散。
代码如下:
// 生成时间轴
const timeline = animejs.timeline()
// 爆炸光波div放大并变亮(其实是变白)
timeline.add({
targets: sparkRef.current,
backgroundColor: {
value: '#fff',
duration: 300
},
width: 1 * Math.max(bodyClientHeight, bodyClientWidth),
height: 1 * Math.max(bodyClientHeight, bodyClientWidth),
duration: 1000
})
// 背景变暗
timeline.add({
targets: maskRef.current,
backgroundColor: `rgba(0,0,0,0.8)`,
duration: 800,
easing: 'easeInOutCirc',
}, '-=1000')
// 爆炸光波div缩小,并逐渐变透明
timeline.add({
targets: sparkRef.current,
width: 0,
height: 0,
opacity: 0,
duration: 3000,
easing: 'easeInOutCirc',
})
// 背景变得透明
timeline.add({
targets: maskRef.current,
backgroundColor: `rgba(0,0,0,0)`,
duration: 3000,
opacity: 0,
easing: 'easeInOutCirc',
}, '-=3000')
4. 如何让掘金“破碎”?
先了解一下“德劳内三角化”到底有什么功效。
如上图所示,“德劳内三角化”可以让一堆散落的点,连成若干个互相不交叉的三角形。因此,我们的思路如下:
通过这种算法实现,我们可以通过在一个矩形上附加若干个点,然后实现它被“打碎”的效果。
在这个基础上,为了让它“破碎”得更有真实感,我们可以增加一些层次感。
我们围绕中心点画若干个同心圆,然后在这个几个同心圆的圆弧周围画若干个点,这样就能营造出一种玻璃碎裂的感觉。如下:
最后效果就能打成中间密集,四周稀疏的效果。
5. 如何让碎片跌落深远?
在做这一步之前,我们得把 第4步
产生的点进行进行剪切,我的做法是“把它们剪切成若干个 canvas
画布”。
我们所要做的,有以下几个步骤:
-
- 计算出每个三角形最小
canvas
矩形的大小和位置。
- 计算出每个三角形最小
-
- 通过canvas.drawImage()方法渲染出它们应该渲染的部分。
-
- 通过canvas.2DContext.clip()方法剪切出三角形形状。
我将这样的碎片定义为 Fragment
:
export interface Box {
x: number,
y: number,
w: number,
h: number
}
export default class Fragment {
public pointA: Array<number>; // 三角形顶点A
public pointB: Array<number>; // 三角形顶点B
public pointC: Array<number>; // 三角形顶点C
public box: Box; // 盒子
public centroid: Array<number>; // 中心
public canvas: HTMLCanvasElement; // canvas 元素
public ctx: CanvasRenderingContext2D | null; // canvas 2d ctx
// ...代码过多,有兴趣的可以看源码
}
那么要怎么让给这些 canvas
坠落向深远呢?
也是需要三步:
- 翻转动画
- 不断变小
- 向中心点靠拢
代码如下:
timeline.add({
targets: fragment.canvas,
scale: {
value: 0,
duration: 1000, // 变小
},
opacity: { // 变透明
value: 0,
duration: 400,
delay: delay + 600
},
left: canvasWidth/2 - fragment.box.w/2, // 移动向中心
top: canvasHeight/2 - fragment.box.h/2, // 移动向中心
rotateX: { // X轴翻转
value: rx,
duration: 400,
delay: delay + 600
},
rotateY: { // Y轴翻转
value: ry,
duration: 400,
delay: delay + 600
},
easing:'cubicBezier(0.420, 0.000, 1.000, 1.000)', // 贝塞尔曲线,缓=>快=>缓
duration: 1000,
}, delay);
获取源码
源码地址: github.com/zhangshichu…