"use strict"; const common_vendor = require("../../../common/vendor.js"); const _sfc_main = /* @__PURE__ */ common_vendor.defineComponent({ __name: "crush-canvas", props: { crushSignal: {} }, setup(__props) { const CRUSH_ITEMS = { egg: { colors: ["#FFEB3B", "#FFF59D", "#FFFFFF", "#FFD54F", "#FFC107"], sparkColors: ["#FFFFFF", "#FFF9C4", "#FFEE58"], shapes: ["circle", "circle", "circle"], debrisCount: 20, sparkCount: 16, sparkleCount: 5, speedMin: 3, speedMax: 6, sizeMin: 4, sizeMax: 10, gravity: 0.34, flashColor: "#FFFDE7", shockwaveColor: "rgba(255, 224, 130, 0.85)" }, walnut: { colors: ["#5D4037", "#795548", "#8D6E63", "#A1887F", "#3E2723"], sparkColors: ["#FFCC80", "#FFB74D", "#FFE0B2"], shapes: ["square", "triangle", "rect"], debrisCount: 22, sparkCount: 18, sparkleCount: 5, speedMin: 2.8, speedMax: 5, sizeMin: 4, sizeMax: 9, gravity: 0.42, flashColor: "#FFE0B2", shockwaveColor: "rgba(255, 167, 38, 0.8)" }, can: { colors: ["#90A4AE", "#CFD8DC", "#B0BEC5", "#78909C", "#ECEFF1", "#607D8B"], sparkColors: ["#FFFFFF", "#E1F5FE", "#B3E5FC"], shapes: ["rect", "rect", "triangle", "square"], debrisCount: 24, sparkCount: 20, sparkleCount: 6, speedMin: 4, speedMax: 7, sizeMin: 3, sizeMax: 11, gravity: 0.36, flashColor: "#FFFFFF", shockwaveColor: "rgba(207, 216, 220, 0.9)" }, balloon: { colors: ["#FF5252", "#FF4081", "#E040FB", "#7C4DFF", "#536DFE", "#448AFF", "#FFEB3B", "#69F0AE", "#FF6E40"], sparkColors: ["#FFFFFF", "#FF80AB", "#82B1FF", "#FFFF8D"], shapes: ["rect", "rect", "square"], debrisCount: 28, sparkCount: 18, sparkleCount: 8, speedMin: 4, speedMax: 7.5, sizeMin: 4, sizeMax: 8, gravity: 0.14, flashColor: "#FCE4EC", shockwaveColor: "rgba(255, 64, 129, 0.85)", confetti: true } }; const PHYSICS = { AIR_RESISTANCE: 0.985, SPARK_RESISTANCE: 0.92, DEBRIS_DECAY: 0.018, SPARK_DECAY: 0.035, SPARKLE_DECAY: 0.045, FLASH_DECAY: 0.11, SHOCKWAVE_DECAY: 0.045 }; const canvasNode = common_vendor.ref(null); const ctx = common_vendor.ref(null); const canvasWidth = common_vendor.ref(240); const canvasHeight = common_vendor.ref(240); const dpr = common_vendor.ref(1); const rafId = common_vendor.ref(null); const renderRunning = common_vendor.ref(false); const debrisList = common_vendor.ref([]); const sparkList = common_vendor.ref([]); const sparkleList = common_vendor.ref([]); const flashList = common_vendor.ref([]); const shockwaves = common_vendor.ref([]); const instance = common_vendor.getCurrentInstance(); const props = __props; common_vendor.watch( () => props.crushSignal, (sig) => { if (sig) triggerCrush(sig.type); } ); common_vendor.onMounted(() => { initCanvas(); }); common_vendor.onBeforeUnmount(() => { cleanup(); }); function initCanvas() { setTimeout(() => { if (!instance) return; const query = common_vendor.index.createSelectorQuery().in(instance); query.select("#crush").fields({ node: true, size: true }).exec((res) => { if (!res || !res[0] || !res[0].node) { common_vendor.index.__f__("warn", "at training/pages/components/crush-canvas.vue:239", "[crush-canvas] canvas 2d not supported on this platform"); return; } const canvas = res[0].node; const width = res[0].width; const height = res[0].height; const systemInfo = common_vendor.index.getSystemInfoSync(); const pixelRatio = systemInfo.pixelRatio || 1; canvas.width = width * pixelRatio; canvas.height = height * pixelRatio; const context = canvas.getContext("2d"); context.scale(pixelRatio, pixelRatio); canvasNode.value = canvas; ctx.value = context; canvasWidth.value = width; canvasHeight.value = height; dpr.value = pixelRatio; }); }, 200); } function triggerCrush(itemType) { if (!ctx.value || !canvasNode.value) return; const item = CRUSH_ITEMS[itemType]; if (!item) return; const centerX = canvasWidth.value / 2; const centerY = canvasHeight.value / 2; const maxR = Math.min(canvasWidth.value, canvasHeight.value); flashList.value.push({ x: centerX, y: centerY, radius: maxR * 0.12, maxRadius: maxR * 0.62, color: item.flashColor, life: 1, decay: PHYSICS.FLASH_DECAY }); shockwaves.value.push({ x: centerX, y: centerY, radius: 12, maxRadius: maxR * 0.62, color: item.shockwaveColor, width: 5, life: 1, decay: PHYSICS.SHOCKWAVE_DECAY }); shockwaves.value.push({ x: centerX, y: centerY, radius: 4, maxRadius: maxR * 0.42, color: item.shockwaveColor, width: 3, life: 1, decay: PHYSICS.SHOCKWAVE_DECAY * 1.3 }); for (let i = 0; i < item.debrisCount; i++) { const angle = Math.PI * 2 * i / item.debrisCount + (Math.random() - 0.5) * 0.7; const speed = item.speedMin + Math.random() * (item.speedMax - item.speedMin); const size = item.sizeMin + Math.random() * (item.sizeMax - item.sizeMin); const color = item.colors[Math.floor(Math.random() * item.colors.length)]; const shape = item.shapes[Math.floor(Math.random() * item.shapes.length)]; const confetti = !!item.confetti; const vy0 = confetti ? Math.sin(angle) * speed - 2.5 : Math.sin(angle) * speed; debrisList.value.push({ x: centerX, y: centerY, vx: Math.cos(angle) * speed, vy: vy0, size, color, shape, rotation: Math.random() * Math.PI * 2, rotationSpeed: (Math.random() - 0.5) * (confetti ? 0.5 : 0.3), life: 1, decay: PHYSICS.DEBRIS_DECAY * (confetti ? 0.7 : 1), gravity: item.gravity, glow: !confetti, // 彩纸不发光,实色碎片发光 swing: confetti ? 0.6 + Math.random() * 1.2 : 0, age: Math.random() * Math.PI * 2 }); } for (let i = 0; i < item.sparkCount; i++) { const angle = Math.random() * Math.PI * 2; const speed = item.speedMax * (0.9 + Math.random() * 0.8); const color = item.sparkColors[Math.floor(Math.random() * item.sparkColors.length)]; sparkList.value.push({ x: centerX, y: centerY, px: centerX, py: centerY, vx: Math.cos(angle) * speed, vy: Math.sin(angle) * speed, size: 1.5 + Math.random() * 2, color, life: 1, decay: PHYSICS.SPARK_DECAY * (0.8 + Math.random() * 0.6), gravity: item.gravity * 0.3 }); } for (let i = 0; i < item.sparkleCount; i++) { const r = maxR * (0.08 + Math.random() * 0.32); const a = Math.random() * Math.PI * 2; const color = item.sparkColors[Math.floor(Math.random() * item.sparkColors.length)]; sparkleList.value.push({ x: centerX + Math.cos(a) * r, y: centerY + Math.sin(a) * r, size: 10 + Math.random() * 16, rotation: Math.random() * Math.PI, spin: (Math.random() - 0.5) * 0.16, color, life: 1 + Math.random() * 0.4, // 错峰出现 decay: PHYSICS.SPARKLE_DECAY * (0.8 + Math.random() * 0.5) }); } ensureRenderLoop(); } function ensureRenderLoop() { if (renderRunning.value) return; renderRunning.value = true; renderLoop(); } function renderLoop() { if (!canvasNode.value || !ctx.value) { renderRunning.value = false; return; } const w = canvasWidth.value; const h = canvasHeight.value; for (let i = debrisList.value.length - 1; i >= 0; i--) { const p = debrisList.value[i]; p.vy += p.gravity; p.vx *= PHYSICS.AIR_RESISTANCE; p.vy *= PHYSICS.AIR_RESISTANCE; p.x += p.vx; p.y += p.vy; p.age += 0.2; if (p.swing > 0) p.x += Math.sin(p.age) * p.swing; p.rotation += p.rotationSpeed; p.life -= p.decay; if (p.life <= 0 || p.x < -60 || p.x > w + 60 || p.y > h + 60) { debrisList.value.splice(i, 1); } } for (let i = sparkList.value.length - 1; i >= 0; i--) { const s = sparkList.value[i]; s.px = s.x; s.py = s.y; s.vy += s.gravity; s.vx *= PHYSICS.SPARK_RESISTANCE; s.vy *= PHYSICS.SPARK_RESISTANCE; s.x += s.vx; s.y += s.vy; s.life -= s.decay; if (s.life <= 0) sparkList.value.splice(i, 1); } for (let i = sparkleList.value.length - 1; i >= 0; i--) { const sp = sparkleList.value[i]; sp.rotation += sp.spin; sp.life -= sp.decay; if (sp.life <= 0) sparkleList.value.splice(i, 1); } for (let i = flashList.value.length - 1; i >= 0; i--) { const f = flashList.value[i]; f.radius += (f.maxRadius - f.radius) * 0.35; f.life -= f.decay; if (f.life <= 0) flashList.value.splice(i, 1); } for (let i = shockwaves.value.length - 1; i >= 0; i--) { const sw = shockwaves.value[i]; sw.radius += (sw.maxRadius - sw.radius) * 0.16; sw.life -= sw.decay; if (sw.life <= 0) shockwaves.value.splice(i, 1); } draw(); const alive = debrisList.value.length > 0 || sparkList.value.length > 0 || sparkleList.value.length > 0 || flashList.value.length > 0 || shockwaves.value.length > 0; if (alive) { rafId.value = canvasNode.value.requestAnimationFrame(renderLoop); } else { rafId.value = null; renderRunning.value = false; } } function draw() { const c = ctx.value; const w = canvasWidth.value; const h = canvasHeight.value; c.clearRect(0, 0, w, h); c.globalCompositeOperation = "source-over"; shockwaves.value.forEach((sw) => { c.beginPath(); c.arc(sw.x, sw.y, sw.radius, 0, Math.PI * 2); c.strokeStyle = applyAlphaToRgba(sw.color, Math.min(1, sw.life)); c.lineWidth = sw.width * sw.life; c.stroke(); }); c.globalCompositeOperation = "lighter"; flashList.value.forEach((f) => { const grd = c.createRadialGradient(f.x, f.y, 0, f.x, f.y, f.radius); const a = Math.min(1, f.life); grd.addColorStop(0, hexToRgba(f.color, 0.95 * a)); grd.addColorStop(0.4, hexToRgba(f.color, 0.5 * a)); grd.addColorStop(1, hexToRgba(f.color, 0)); c.fillStyle = grd; c.beginPath(); c.arc(f.x, f.y, f.radius, 0, Math.PI * 2); c.fill(); }); c.globalCompositeOperation = "source-over"; debrisList.value.forEach((p) => { const alpha = Math.min(1, p.life); const currentSize = p.size * (0.65 + p.life * 0.35); if (p.glow) { c.fillStyle = hexToRgba(p.color, alpha * 0.22); c.beginPath(); c.arc(p.x, p.y, currentSize * 1.9, 0, Math.PI * 2); c.fill(); } c.fillStyle = hexToRgba(p.color, alpha); drawDebrisShape(c, p, currentSize); }); c.globalCompositeOperation = "lighter"; sparkList.value.forEach((s) => { const a = Math.min(1, s.life); c.strokeStyle = hexToRgba(s.color, a * 0.8); c.lineWidth = s.size * a; c.lineCap = "round"; c.beginPath(); c.moveTo(s.px, s.py); c.lineTo(s.x, s.y); c.stroke(); c.fillStyle = hexToRgba(s.color, a); c.beginPath(); c.arc(s.x, s.y, s.size * a, 0, Math.PI * 2); c.fill(); }); sparkleList.value.forEach((sp) => { const t = Math.max(0, Math.min(1, sp.life)); const scale = Math.sin(Math.min(1, sp.life) * Math.PI); if (scale <= 0.02) return; const a = t; drawStar(c, sp.x, sp.y, sp.size * scale, sp.size * scale * 0.32, sp.rotation, hexToRgba(sp.color, a)); }); c.globalCompositeOperation = "source-over"; } function drawDebrisShape(c, p, size) { switch (p.shape) { case "circle": c.beginPath(); c.arc(p.x, p.y, size, 0, Math.PI * 2); c.fill(); break; case "square": c.save(); c.translate(p.x, p.y); c.rotate(p.rotation); c.fillRect(-size, -size, size * 2, size * 2); c.restore(); break; case "rect": c.save(); c.translate(p.x, p.y); c.rotate(p.rotation); c.fillRect(-size * 1.6, -size * 0.5, size * 3.2, size); c.restore(); break; case "triangle": c.save(); c.translate(p.x, p.y); c.rotate(p.rotation); c.beginPath(); c.moveTo(0, -size); c.lineTo(size, size); c.lineTo(-size, size); c.closePath(); c.fill(); c.restore(); break; } } function drawStar(c, cx, cy, outerR, innerR, rotation, fill) { const points = 4; c.save(); c.translate(cx, cy); c.rotate(rotation); c.beginPath(); for (let i = 0; i < points * 2; i++) { const r = i % 2 === 0 ? outerR : innerR; const a = Math.PI * i / points; const x = Math.cos(a) * r; const y = Math.sin(a) * r; if (i === 0) c.moveTo(x, y); else c.lineTo(x, y); } c.closePath(); c.fillStyle = fill; c.fill(); c.restore(); } function hexToRgba(hex, alpha) { const r = parseInt(hex.slice(1, 3), 16); const g = parseInt(hex.slice(3, 5), 16); const b = parseInt(hex.slice(5, 7), 16); return `rgba(${r}, ${g}, ${b}, ${alpha})`; } function applyAlphaToRgba(rgba, alphaMultiplier) { const match = rgba.match(/rgba?\(([^)]+)\)/); if (!match) return rgba; const parts = match[1].split(",").map((s) => s.trim()); const r = parts[0]; const g = parts[1]; const b = parts[2]; const a = parts[3] ? parseFloat(parts[3]) : 1; return `rgba(${r}, ${g}, ${b}, ${a * alphaMultiplier})`; } function cleanup() { if (rafId.value !== null && canvasNode.value) { try { canvasNode.value.cancelAnimationFrame(rafId.value); } catch (_) { } rafId.value = null; } renderRunning.value = false; debrisList.value = []; sparkList.value = []; sparkleList.value = []; flashList.value = []; shockwaves.value = []; } return (_ctx, _cache) => { return {}; }; } }); const Component = /* @__PURE__ */ common_vendor._export_sfc(_sfc_main, [["__scopeId", "data-v-e11c993f"]]); wx.createComponent(Component); //# sourceMappingURL=../../../../.sourcemap/mp-weixin/training/pages/components/crush-canvas.js.map