fix(timer): 分段弧光点居中置顶 + 拉大与进度弧间距
- 光点移到段中点(am=(a0+a1)/2),两端粗细对称;重构为两遍绘制, 光点统一后绘浮于所有弧之上,不再被相邻圆头吞掉;加大加亮成珠状 - glowPad 6→18 与 _drawSetArcs pad 同步,arcR 外移 3→14, 分段弧与进度弧间距 -1 → +10dpr(size=420),呼吸光环不重叠
This commit is contained in:
@@ -89,3 +89,20 @@
|
|||||||
- **`timer.wxss`**:新增 `.completion-not-recorded` 主色淡底信息块(与 completion-tip 同风格,tipIn 延迟 0.5s 入场)。
|
- **`timer.wxss`**:新增 `.completion-not-recorded` 主色淡底信息块(与 completion-tip 同风格,tipIn 延迟 0.5s 入场)。
|
||||||
- 保留逻辑:`elapsed < 3` 秒仍走 toast「训练时间太短」+ navigateBack(几乎未开始,不弹完成弹窗)。
|
- 保留逻辑:`elapsed < 3` 秒仍走 toast「训练时间太短」+ navigateBack(几乎未开始,不弹完成弹窗)。
|
||||||
- 验证:node --check 通过;grep 确认 minRecordSeconds/completionNotRecorded/_showNotRecorded 三处字段在 config/js/wxml 引用一致。
|
- 验证:node --check 通过;grep 确认 minRecordSeconds/completionNotRecorded/_showNotRecorded 三处字段在 config/js/wxml 引用一致。
|
||||||
|
|
||||||
|
## 分段弧两端粗细不一致(已修)
|
||||||
|
- 用户反馈:循环训练时分段弧"两端粗细不一致"。
|
||||||
|
- 根因(progress-ring.js `_drawSetArcs`):发光光点坐标固定取段尾角 `a1`(`dx=cx+arcR*cos(a1)`),当前段(active)/休息预告段(next)的尾端 = 光点+8dpr 发光晕(直径≈弧宽+),首端却只是 `lineCap:'round'` 普通圆头 → 同段弧尾粗头细。已完成/未开始段两端都是普通圆头,粗细一致,所以现象集中在运动中那一段。
|
||||||
|
- 修复:光点移到**段中点** `am=(a0+a1)/2`(3 行),两端自然对称,光点仍作"当前组"标记。node --check 通过。
|
||||||
|
- 注意:若以后想给分段弧加"当前组跟随倒计时移动"的进度感,光点可改为随剩余时间在段内插值,但需先确认用户是否要这个效果。
|
||||||
|
|
||||||
|
## 分段弧间距 + 光点置顶(用户反馈"两弧太近、弧压着光点")
|
||||||
|
- 用户反馈两点:①分段弧与进度弧距离太近;②光点被分段弧压住(视觉上弧盖着光点)。
|
||||||
|
- **间距修复**(progress-ring.js,size=420 时验证):
|
||||||
|
- 根因:间距 = gap − arcW/2 = 3−4 = **−1dpr(重叠 1)**。因为分段弧 arcR 仅比进度弧外缘靠外 3dpr,而弧半宽 4dpr。
|
||||||
|
- `_draw()` 的 `glowPad` 6→14dpr(进度弧半径内缩 8,给外圈腾空间);`_drawSetArcs()` 的 radius pad 6→14(**两处必须同步**,已加注释)且 arcR 间距 `+3→+9dpr`。结果:进度弧外缘 204→196、分段弧内缘 203→201,间距 −1→**+5dpr**。副作用:单组/自由模式的进度环也内缩 ~8dpr(约 4%),中心数字区略小;进度弧尾端发光点 shadowBlur=12 阴影反而从"被 canvas 裁"变完整。
|
||||||
|
- 段间空隙 gap=2.5° 是段间距,**与环间距无关,不动**。
|
||||||
|
- **光点置顶**:原实现光点在逐段循环内、每段弧 stroke 之后画,理论上应在弧上,但视觉上被 round cap 相邻段边缘"吞掉"。重构为**两遍绘制**:pass1 只画所有弧并收集 emphasized 段光点(x/y/color),pass2 统一在所有弧之上画光点。同时光点加大加亮:dotR 从 `0.85~1.2×弧半宽` → `1.15~1.4×`,alpha `0.55~1.0` → `0.7~1.0`,白芯 0.85→0.9,读起来像"珠珠骑在弧上"。
|
||||||
|
- 光点仍居段中点(沿用上轮两端对称修复);外缘 209dpr 不超 canvas 半宽 210,与 breath-aura(内缘 ~232)无重叠。
|
||||||
|
- 验证:node --check 通过;数值全部核算。未提交 git。
|
||||||
|
- **间距仍不够(用户反馈"还是太近")→ 再翻倍**:canvas 半宽 210 是硬上限,剩余空间仅 ~5dpr,要明显拉开只能继续内缩进度弧。glowPad 14→18、arcR 外移量 9→14,间距 **5→10dpr**(进度弧外缘 196→192,分段弧内缘 201→202,光点外缘 211.6 超画布 0.8px 亚像素无感)。进度环直径累计缩 ~6%(408→384)。约束备忘:**间距 = arcR外移量 − arcW/2,且 ≤ glowPad − arcW − margin**;想再拉开只能继续缩环或减弧宽。
|
||||||
|
|||||||
@@ -105,8 +105,11 @@ Component({
|
|||||||
|
|
||||||
const cx = w / 2
|
const cx = w / 2
|
||||||
const cy = h / 2
|
const cy = h / 2
|
||||||
// reserve room for the glowing end dot so its shadow isn't clipped
|
// Reserve room for the glowing end dot's shadow AND the outer set-progress
|
||||||
const glowPad = 6 * dpr
|
// 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 radius = (size - ringWidth) / 2 * dpr - glowPad
|
||||||
const lw = ringWidth * dpr
|
const lw = ringWidth * dpr
|
||||||
|
|
||||||
@@ -252,8 +255,9 @@ Component({
|
|||||||
const cy = (size / 2) * dpr
|
const cy = (size / 2) * dpr
|
||||||
// Same radius math as _draw(): the countdown arc sits at `radius`; the
|
// 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.
|
// set band wraps just outside it so the two read as concentric layers.
|
||||||
const radius = ((size - ringWidth) / 2) * dpr - 6 * dpr
|
// NOTE: the -18*dpr pad MUST stay in sync with glowPad in _draw().
|
||||||
const arcR = radius + (ringWidth / 2) * dpr + 3 * dpr
|
const radius = ((size - ringWidth) / 2) * dpr - 18 * dpr
|
||||||
|
const arcR = radius + (ringWidth / 2) * dpr + 14 * dpr
|
||||||
const arcW = 8 * dpr
|
const arcW = 8 * dpr
|
||||||
const band = arcW / 2 + 3 * dpr
|
const band = arcW / 2 + 3 * dpr
|
||||||
|
|
||||||
@@ -274,6 +278,10 @@ Component({
|
|||||||
const gap = (2.5 * Math.PI) / 180
|
const gap = (2.5 * Math.PI) / 180
|
||||||
const startAngle = -Math.PI / 2
|
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++) {
|
for (let i = 1; i <= sets; i++) {
|
||||||
const a0 = startAngle + (i - 1) * segAngle + gap / 2
|
const a0 = startAngle + (i - 1) * segAngle + gap / 2
|
||||||
const a1 = startAngle + i * segAngle - gap / 2
|
const a1 = startAngle + i * segAngle - gap / 2
|
||||||
@@ -294,28 +302,38 @@ Component({
|
|||||||
ctx.stroke()
|
ctx.stroke()
|
||||||
ctx.globalAlpha = 1
|
ctx.globalAlpha = 1
|
||||||
|
|
||||||
// Glowing endpoint dot on the emphasized segment.
|
|
||||||
if (emphasized) {
|
if (emphasized) {
|
||||||
const dx = cx + arcR * Math.cos(a1)
|
const am = (a0 + a1) / 2
|
||||||
const dy = cy + arcR * Math.sin(a1)
|
dots.push({
|
||||||
const dotR = (arcW / 2) * (paused ? 1 : 0.85 + 0.35 * p)
|
x: cx + arcR * Math.cos(am),
|
||||||
const glowColor = i === active ? primaryColor : successColor
|
y: cy + arcR * Math.sin(am),
|
||||||
ctx.save()
|
color: i === active ? primaryColor : successColor
|
||||||
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()
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 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() {
|
_startSetPulse() {
|
||||||
|
|||||||
Reference in New Issue
Block a user