fix(timer): 分段弧光点居中置顶 + 拉大与进度弧间距

- 光点移到段中点(am=(a0+a1)/2),两端粗细对称;重构为两遍绘制,
  光点统一后绘浮于所有弧之上,不再被相邻圆头吞掉;加大加亮成珠状
- glowPad 6→18 与 _drawSetArcs pad 同步,arcR 外移 3→14,
  分段弧与进度弧间距 -1 → +10dpr(size=420),呼吸光环不重叠
This commit is contained in:
2026-08-12 10:34:54 +08:00
parent f1ad3eeb95
commit b6d94b21cd
2 changed files with 58 additions and 23 deletions
+41 -23
View File
@@ -105,8 +105,11 @@ Component({
const cx = w / 2
const cy = h / 2
// reserve room for the glowing end dot so its shadow isn't clipped
const glowPad = 6 * dpr
// Reserve room for the glowing end dot's shadow AND the outer set-progress
// band (circuit mode). _drawSetArcs derives its band radius from this same
// pad, so increasing it here also widens the gap between the countdown
// arc and the set band. 18dpr gives a ~10dpr visible gap (size=420).
const glowPad = 18 * dpr
const radius = (size - ringWidth) / 2 * dpr - glowPad
const lw = ringWidth * dpr
@@ -252,8 +255,9 @@ Component({
const cy = (size / 2) * dpr
// Same radius math as _draw(): the countdown arc sits at `radius`; the
// set band wraps just outside it so the two read as concentric layers.
const radius = ((size - ringWidth) / 2) * dpr - 6 * dpr
const arcR = radius + (ringWidth / 2) * dpr + 3 * dpr
// NOTE: the -18*dpr pad MUST stay in sync with glowPad in _draw().
const radius = ((size - ringWidth) / 2) * dpr - 18 * dpr
const arcR = radius + (ringWidth / 2) * dpr + 14 * dpr
const arcW = 8 * dpr
const band = arcW / 2 + 3 * dpr
@@ -274,6 +278,10 @@ Component({
const gap = (2.5 * Math.PI) / 180
const startAngle = -Math.PI / 2
// Pass 1: draw every segment arc. Breathing dots are collected and painted
// in pass 2, AFTER all arcs, so a dot always floats ON TOP of its segment
// instead of being partially buried under neighbouring round caps.
const dots = []
for (let i = 1; i <= sets; i++) {
const a0 = startAngle + (i - 1) * segAngle + gap / 2
const a1 = startAngle + i * segAngle - gap / 2
@@ -294,28 +302,38 @@ Component({
ctx.stroke()
ctx.globalAlpha = 1
// Glowing endpoint dot on the emphasized segment.
if (emphasized) {
const dx = cx + arcR * Math.cos(a1)
const dy = cy + arcR * Math.sin(a1)
const dotR = (arcW / 2) * (paused ? 1 : 0.85 + 0.35 * p)
const glowColor = i === active ? primaryColor : successColor
ctx.save()
ctx.shadowColor = glowColor
ctx.shadowBlur = 8 * dpr
ctx.globalAlpha = paused ? 0.9 : 0.55 + 0.45 * p
ctx.beginPath()
ctx.arc(dx, dy, dotR, 0, Math.PI * 2)
ctx.fillStyle = glowColor
ctx.fill()
ctx.restore()
// white core for a "light bulb" feel
ctx.beginPath()
ctx.arc(dx, dy, dotR * 0.45, 0, Math.PI * 2)
ctx.fillStyle = 'rgba(255,255,255,0.85)'
ctx.fill()
const am = (a0 + a1) / 2
dots.push({
x: cx + arcR * Math.cos(am),
y: cy + arcR * Math.sin(am),
color: i === active ? primaryColor : successColor
})
}
}
// Pass 2: glowing dot on each emphasized segment, drawn over every arc.
// Placed at the segment MIDDLE (not the a1 end): a dot pinned to the
// trailing end made that end look visibly thicker than the round-cap
// start, so both ends of the arc stay symmetric. Slightly larger than
// the band width so it reads as a bead riding on top of the arc.
for (const dot of dots) {
const dotR = (arcW / 2) * (paused ? 1.3 : 1.15 + 0.25 * p)
ctx.save()
ctx.shadowColor = dot.color
ctx.shadowBlur = 8 * dpr
ctx.globalAlpha = paused ? 0.95 : 0.7 + 0.3 * p
ctx.beginPath()
ctx.arc(dot.x, dot.y, dotR, 0, Math.PI * 2)
ctx.fillStyle = dot.color
ctx.fill()
ctx.restore()
// white core for a "light bulb" feel
ctx.beginPath()
ctx.arc(dot.x, dot.y, dotR * 0.45, 0, Math.PI * 2)
ctx.fillStyle = 'rgba(255,255,255,0.9)'
ctx.fill()
}
},
_startSetPulse() {