feat: 粒子源-目标颜色区分+流速按流量比例
- 边轨迹: linearGradient src青绿→dst红色 - 粒子: src青绿(#2ec4b6)→dst红色(#e63946)渐变 - 粒子速度: speedMul=0.5+1.5*ratio, 高流量边粒子更快 - 粒子数量: 3+6*ratio, 高流量边更多粒子 - 发光增强: shadowBlur=5, opacity=0.6+0.4*weight Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
@@ -2823,26 +2823,31 @@ function renderTrafficCrossfade() {
|
|||||||
const ratio = Math.min(1, e.count / maxCount);
|
const ratio = Math.min(1, e.count / maxCount);
|
||||||
const alpha = 0.4 + 0.6 * e.weight;
|
const alpha = 0.4 + 0.6 * e.weight;
|
||||||
|
|
||||||
// Bezier curve
|
// Edge trace with source→destination color gradient
|
||||||
|
const grad = ctx.createLinearGradient(cached.p1x, cached.p1y, cached.p2x, cached.p2y);
|
||||||
|
grad.addColorStop(0, 'rgba(46,196,182,' + alpha.toFixed(2) + ')'); // src: teal
|
||||||
|
grad.addColorStop(1, 'rgba(230,57,70,' + alpha.toFixed(2) + ')'); // dst: red
|
||||||
ctx.beginPath();
|
ctx.beginPath();
|
||||||
ctx.moveTo(cached.p1x, cached.p1y);
|
ctx.moveTo(cached.p1x, cached.p1y);
|
||||||
ctx.quadraticCurveTo(cached.midX, cached.midY, cached.p2x, cached.p2y);
|
ctx.quadraticCurveTo(cached.midX, cached.midY, cached.p2x, cached.p2y);
|
||||||
ctx.strokeStyle = 'rgba(67,97,238,' + alpha.toFixed(2) + ')';
|
ctx.strokeStyle = grad;
|
||||||
ctx.lineWidth = 1.5 + 4 * ratio;
|
ctx.lineWidth = 1.5 + 4 * ratio;
|
||||||
ctx.stroke();
|
ctx.stroke();
|
||||||
|
|
||||||
// Particles flowing along curve (Date.now() driven, continuous)
|
// Particles: source(teal)→destination(red), speed ∝ traffic volume
|
||||||
const nP = Math.ceil(3 + 5 * ratio);
|
const speedMul = 0.5 + 1.5 * ratio; // higher traffic → faster particles
|
||||||
|
const nP = Math.ceil(3 + 6 * ratio);
|
||||||
for (let pi = 0; pi < nP; pi++) {
|
for (let pi = 0; pi < nP; pi++) {
|
||||||
const pt = ((Date.now() / 2000 + pi / nP) % 1);
|
const pt = ((Date.now() / 2000 * speedMul + pi / nP) % 1);
|
||||||
const px = (1-pt)*(1-pt)*cached.p1x + 2*(1-pt)*pt*cached.midX + pt*pt*cached.p2x;
|
const px = (1-pt)*(1-pt)*cached.p1x + 2*(1-pt)*pt*cached.midX + pt*pt*cached.p2x;
|
||||||
const py = (1-pt)*(1-pt)*cached.p1y + 2*(1-pt)*pt*cached.midY + pt*pt*cached.p2y;
|
const py = (1-pt)*(1-pt)*cached.p1y + 2*(1-pt)*pt*cached.midY + pt*pt*cached.p2y;
|
||||||
const r = Math.round(67 + 163*pt), g = Math.round(97 - 40*pt), b = Math.round(238 - 168*pt);
|
// src teal→dst red gradient
|
||||||
|
const cr = Math.round(46 + 184*pt), cg = Math.round(196 - 139*pt), cb = Math.round(182 - 112*pt);
|
||||||
ctx.beginPath();
|
ctx.beginPath();
|
||||||
ctx.arc(px, py, 2 + 3*ratio, 0, Math.PI*2);
|
ctx.arc(px, py, 2 + 3*ratio, 0, Math.PI*2);
|
||||||
ctx.fillStyle = 'rgba(' + r + ',' + g + ',' + b + ',' + (0.5+0.5*e.weight) + ')';
|
ctx.fillStyle = 'rgba(' + cr + ',' + cg + ',' + cb + ',' + (0.6+0.4*e.weight) + ')';
|
||||||
ctx.shadowColor = 'rgba(' + r + ',' + g + ',' + b + ',0.5)';
|
ctx.shadowColor = 'rgba(' + cr + ',' + cg + ',' + cb + ',0.6)';
|
||||||
ctx.shadowBlur = 4;
|
ctx.shadowBlur = 5;
|
||||||
ctx.fill();
|
ctx.fill();
|
||||||
ctx.shadowBlur = 0;
|
ctx.shadowBlur = 0;
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user