feat: 实现墨丝效果,spreading阶段粒子间绘制渐变曲线连线
This commit is contained in:
@@ -465,6 +465,67 @@ function drawParticle(
|
||||
}
|
||||
}
|
||||
|
||||
function drawInkStrings(
|
||||
ctx: CanvasRenderingContext2D,
|
||||
particles: Particle[],
|
||||
config: ResponsiveConfig,
|
||||
): void {
|
||||
const spreading = particles.filter(
|
||||
p => p.phase === 'spreading' && p.age >= p.delay
|
||||
);
|
||||
if (spreading.length < 2) {
|
||||
return;
|
||||
}
|
||||
|
||||
const threshold = config.connectionDistance * config.inkStringThreshold;
|
||||
|
||||
ctx.save();
|
||||
ctx.lineCap = 'round';
|
||||
for (let i = 0; i < spreading.length; i++) {
|
||||
const a = spreading[i];
|
||||
if (!a) {
|
||||
continue;
|
||||
}
|
||||
for (let j = i + 1; j < spreading.length; j++) {
|
||||
const b = spreading[j];
|
||||
if (!b) {
|
||||
continue;
|
||||
}
|
||||
const dx = a.x - b.x;
|
||||
const dy = a.y - b.y;
|
||||
const dist = Math.sqrt(dx * dx + dy * dy);
|
||||
if (dist < threshold && dist > 0) {
|
||||
const distRatio = 1 - dist / threshold;
|
||||
const alpha = distRatio * 0.15 * Math.min(a.opacity, b.opacity);
|
||||
|
||||
const useAccent = ACCENT_TONES.includes(a.toneIndex) || ACCENT_TONES.includes(b.toneIndex);
|
||||
const rgb = useAccent ? TONES[3].rgb : TONES[0].rgb;
|
||||
|
||||
const mx = (a.x + b.x) / 2;
|
||||
const my = (a.y + b.y) / 2;
|
||||
const perpX = -dy / dist;
|
||||
const perpY = dx / dist;
|
||||
const curvature = (Math.random() - 0.5) * dist * 0.2;
|
||||
const cpx = mx + perpX * curvature;
|
||||
const cpy = my + perpY * curvature;
|
||||
|
||||
const grad = ctx.createLinearGradient(a.x, a.y, b.x, b.y);
|
||||
grad.addColorStop(0, `rgba(${rgb}, ${alpha * 0.3})`);
|
||||
grad.addColorStop(0.5, `rgba(${rgb}, ${alpha})`);
|
||||
grad.addColorStop(1, `rgba(${rgb}, ${alpha * 0.3})`);
|
||||
|
||||
ctx.beginPath();
|
||||
ctx.moveTo(a.x, a.y);
|
||||
ctx.quadraticCurveTo(cpx, cpy, b.x, b.y);
|
||||
ctx.strokeStyle = grad;
|
||||
ctx.lineWidth = Math.max(0.2, distRatio * 1.5);
|
||||
ctx.stroke();
|
||||
}
|
||||
}
|
||||
}
|
||||
ctx.restore();
|
||||
}
|
||||
|
||||
function drawConnections(
|
||||
ctx: CanvasRenderingContext2D,
|
||||
particles: Particle[],
|
||||
@@ -683,6 +744,7 @@ export function InkDataMorph({
|
||||
}
|
||||
|
||||
drawConnections(ctx, finalParticles, config.connectionDistance);
|
||||
drawInkStrings(ctx, finalParticles, config);
|
||||
}, []);
|
||||
|
||||
useEffect(() => {
|
||||
@@ -746,6 +808,7 @@ export function InkDataMorph({
|
||||
}
|
||||
|
||||
drawConnections(ctx, particles, config.connectionDistance);
|
||||
drawInkStrings(ctx, particles, config);
|
||||
|
||||
if (allComplete) {
|
||||
animationRef.current = undefined;
|
||||
|
||||
Reference in New Issue
Block a user