fix(烟花): 「表情包」那一种在机房电脑上卡成幻灯片
canvas-confetti 画位图粒子是每帧按「位图边长 × scalar」填一个图案矩形,和表情实际多大 无关。原来位图 64px、scalar 5,表情显示 50px,每个粒子每帧却填 320×320,两团 32 个 粒子一帧三百多万像素。改成位图直接画成 50px、scalar 1、矩阵不缩放:显示大小和轨迹 不变(scalar 只管大小不管运动),填的正好是 50×50。 同样画法在无 GPU 的 Chrome 里复现一帧:17ms → 0.5ms(快的 CPU 核上,旧的已经吃满一帧)。 其余九种是圆点、星星、对勾、爱心这类路径,只填图形本身,没有这个问题。 Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
1 parent
95dc2f24e6
commit
f01870c072
1 file changed
+17
-8
@@ -14,28 +14,36 @@ const EMOJI_SVGS = [
|
||||
// 将 emoji SVG 转成 confetti 可用的彩色位图 Shape,缓存后供重复调用复用
|
||||
let emojiShapesPromise: Promise<confetti.Shape[]> | null = null
|
||||
|
||||
/**
|
||||
* 表情在屏幕上的边长(px)。位图就按这个大小画,放的时候 `scalar: 1`、矩阵不缩放。
|
||||
*
|
||||
* **别改回「位图画大、矩阵缩小、scalar 放大」**:canvas-confetti 画位图粒子是每帧
|
||||
* `fillRect(位图边长 × scalar)` 再用图案填,填的矩形和表情实际多大无关。原来位图 64、
|
||||
* scalar 5,表情显示 50px,每个粒子每帧却要填 320×320 —— 两团 32 个粒子一帧三百多万像素,
|
||||
* 机房电脑(显卡弱、Chrome 常走软件渲染)放到这一种就卡(用户 2026-11 反馈)。
|
||||
* 现在填的正好是 50×50,同样大小、同样轨迹,像素少到四十分之一。
|
||||
*/
|
||||
const EMOJI_PX = 50
|
||||
|
||||
function svgToBitmapShape(svg: string): Promise<confetti.Shape> {
|
||||
return new Promise((resolve, reject) => {
|
||||
const blob = new Blob([svg], { type: 'image/svg+xml' })
|
||||
const url = URL.createObjectURL(blob)
|
||||
const img = new Image()
|
||||
img.onload = async () => {
|
||||
const renderSize = 64
|
||||
const baseUnit = 10
|
||||
const canvas = document.createElement('canvas')
|
||||
canvas.width = renderSize
|
||||
canvas.height = renderSize
|
||||
canvas.width = EMOJI_PX
|
||||
canvas.height = EMOJI_PX
|
||||
const ctx = canvas.getContext('2d')!
|
||||
ctx.drawImage(img, 0, 0, renderSize, renderSize)
|
||||
ctx.drawImage(img, 0, 0, EMOJI_PX, EMOJI_PX)
|
||||
URL.revokeObjectURL(url)
|
||||
|
||||
try {
|
||||
const bitmap = await createImageBitmap(canvas)
|
||||
const scale = baseUnit / renderSize
|
||||
resolve({
|
||||
type: 'bitmap',
|
||||
bitmap,
|
||||
matrix: [scale, 0, 0, scale, (-renderSize * scale) / 2, (-renderSize * scale) / 2],
|
||||
matrix: [1, 0, 0, 1, -EMOJI_PX / 2, -EMOJI_PX / 2],
|
||||
} as unknown as confetti.Shape)
|
||||
} catch (e) {
|
||||
reject(e)
|
||||
@@ -415,7 +423,8 @@ export function useFireworks() {
|
||||
const options: confetti.Options = {
|
||||
shapes: emojiShapes,
|
||||
flat: true,
|
||||
scalar: 5,
|
||||
// 大小在位图里(EMOJI_PX),这里放大的话填的矩形跟着放大,见 EMOJI_PX
|
||||
scalar: 1,
|
||||
particleCount: 16,
|
||||
spread: 360,
|
||||
startVelocity: 40,
|
||||
|
||||
Reference in new issue
Block a user