fix: 增强粒子视觉效果——发光粒子+加粗边缘+更高不透明度

- 粒子尺寸3-7px, 红色发光(shadowBlur=6)
- 边缘线加粗到1.5-5.5px, 不透明度0.3-0.8
- 粒子生成率提高(4/边/生命周期)

Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
TianXuan Developer
2026-07-25 09:09:28 +08:00
parent bcf447db37
commit 613f7d2d50
@@ -2818,13 +2818,13 @@ function renderTrafficContinuous(totalSpan, minTs, maxTs) {
return pt;
};
// Spawn new particles
// Spawn new particles — higher rate for denser visual
const now = _trafficCurrentTime;
const particleLifetime = Math.max(3, Math.min(8, totalSpan * 0.1));
const spawnInterval = Math.max(0.02, particleLifetime / 8); // spawn ~8 particles per edge per lifetime
const particleLifetime = Math.max(4, Math.min(10, totalSpan * 0.15));
const spawnRate = Math.max(0.03, particleLifetime / 4); // 4 particles per edge per lifetime
activeEdges.forEach(e => {
const key = e.source + '|' + e.target;
if (!_trafficSpawnTimers[key] || now - _trafficSpawnTimers[key] > spawnInterval / Math.max(1, e.count)) {
if (!_trafficSpawnTimers[key] || now - _trafficSpawnTimers[key] > spawnRate) {
_trafficSpawnTimers[key] = now;
_trafficParticles.push({
source: e.source, target: e.target,
@@ -2835,10 +2835,10 @@ function renderTrafficContinuous(totalSpan, minTs, maxTs) {
}
});
// Update & render particles
// Update & render particles — bright, visible dots
const toRemove = [];
_trafficParticles.forEach((p, i) => {
p.progress += p.speed * Math.min(0.1, (1 / 60) * _trafficSpeed * 2);
p.progress += p.speed * (1/60) * _trafficSpeed * 3;
if (p.progress >= 1) { toRemove.push(i); return; }
const srcC = coords[p.source]; const dstC = coords[p.target];
@@ -2848,33 +2848,35 @@ function renderTrafficContinuous(totalSpan, minTs, maxTs) {
if (!p1 || !p2) { toRemove.push(i); return; }
const midX = (p1.x + p2.x) / 2;
const midY = (p1.y + p2.y) / 2 - Math.abs(p2.x - p1.x) * 0.1;
const midY = (p1.y + p2.y) / 2 - Math.abs(p2.x - p1.x) * 0.12;
// Fade trail
const t = p.progress;
const px = (1-t)*(1-t)*p1.x + 2*(1-t)*t*midX + t*t*p2.x;
const py = (1-t)*(1-t)*p1.y + 2*(1-t)*t*midY + t*t*p2.y;
const size = 2 + 2.5 * (p.count / maxCount);
const alpha = 0.5 + 0.5 * (1 - Math.abs(t - 0.5) * 2); // brightest at midpoint
const size = 3 + 4 * (p.count / maxCount);
// Glow
_trafficCanvasCtx.shadowColor = 'rgba(230,57,70,0.8)';
_trafficCanvasCtx.shadowBlur = 6;
_trafficCanvasCtx.beginPath();
_trafficCanvasCtx.arc(px, py, size, 0, Math.PI * 2);
_trafficCanvasCtx.fillStyle = `rgba(230,57,70,${alpha.toFixed(2)})`;
_trafficCanvasCtx.fillStyle = '#ff4444';
_trafficCanvasCtx.fill();
_trafficCanvasCtx.shadowBlur = 0;
});
for (let i = toRemove.length - 1; i >= 0; i--) _trafficParticles.splice(toRemove[i], 1);
// Draw active edge traces (faint background)
activeEdges.forEach(e => {
// Draw active edge traces (background lines)
activeEdges.slice(0, 200).forEach(e => {
const srcC = coords[e.source]; const dstC = coords[e.target];
if (!srcC || !dstC) return;
const p1 = getPixel(e.source, srcC[0], srcC[1]);
const p2 = getPixel(e.target, dstC[0], dstC[1]);
if (!p1 || !p2) return;
const midX = (p1.x + p2.x) / 2;
const midY = (p1.y + p2.y) / 2 - Math.abs(p2.x - p1.x) * 0.1;
const alpha = 0.15 + 0.3 * (e.count / maxCount);
const width = 0.8 + 2 * (e.count / maxCount);
const midY = (p1.y + p2.y) / 2 - Math.abs(p2.x - p1.x) * 0.12;
const alpha = 0.3 + 0.5 * (e.count / maxCount);
const width = 1.5 + 4 * (e.count / maxCount);
_trafficCanvasCtx.beginPath();
_trafficCanvasCtx.moveTo(p1.x, p1.y);
_trafficCanvasCtx.quadraticCurveTo(midX, midY, p2.x, p2.y);