自适应范围/时机澄清 + 适应视图与 Y 轴自适应互不干扰 + 吸附跟随时间偏移
一、澄清「自适应范围与时机」(并修正记忆里不完善的表述)
* 准确说法:「额外要求视界内至少有一个可见数据点」这句不完善,完整规则是:
- 首个网格显示内容时对它做完整自适应 —— **Y 轴与时间轴都**匹配自己的数据范围;
- 只有一个数据点的信号必须显示在网格**中间**,保证其可见
(FitSinglePointSignal:数据点居中、时间跨度 1s、Y 轴跨度 1);
- **后续新增网格只做 Y 轴自适应,不再调整时间轴**。
* Documents/agent_mem.md 相应章节(§9.30 正文、§11.2 第 58/60 条)已按此改写。
二、修复「适应视图」与「Y 轴自适应」互相干扰
* 根因:两条自适应路径的留白不同 —— 整段自适应(ComputeLaneRange → PadRange)用 6%,
「选区 Y 轴自适应」(AutoRangeLaneToView)用 5%。视界未变时两者本应完全相等,
于是「点过适应视图 → 打开 Y 轴自适应」会算出不同区间、网格被无意义重绘
(实测切一次 143513 像素),反向操作同样(137326 像素)。
* 修法:新增 DataModel.hpp 的 PadValueRange() 作为**唯一**留白实现(含退化区间规则
max(1, |值|×0.1)),PadRange 与 AutoRangeLaneToView 共用它。
* 结果:「适应视图 → 开自适应 → 关自适应 → 再适应视图」四个步骤上生效区间逐位相同,
绘图区逐像素 0 差异;而真正改变视界(缩放)时仍然正常重绘。
三、修复「适应视图」在单点信号上让数据点“飞了”
* FitAll() 开头先尝试 FitSinglePointSignal():仅一个网格、且唯一可见信号只有一个有效
数据点时,走与首次加载完全相同的单点初始视图(数据点居中、时间跨度 1s、Y 跨度 1),
并保持幂等(重复点击像素不变)。
四、修复光标吸附未考虑「调整 → 时间轴偏移」
* 根因:采样点 k 画在 time[k] + offsetTime 处,而光标存的也是显示时间,
但吸附一直在源时间空间查找 —— 设过时间轴偏移后吸附会落到历史位置。
* 修法:SignalSnapEnabled / HasVisibleSample / NearestSnapSample / LocalSampleSpacing
全部增加 timeShift 形参:可见性与点数统计比较 time[k] + timeShift;
NearestSnapSample 内部用 time - timeShift 回源空间查找、返回时再加回去;
UpdateAutoScatterStyles(自动点线)同步传入 offsetTime,保持与吸附判定同源。
五、验证(离屏 .preflight/check:SW_HIDE 窗口、不注入真实鼠标键盘、进程/线程 BELOW_NORMAL)
39/39 通过(连跑 3 次稳定):
[A] 四个步骤的生效区间逐位相同 + 绘图区逐像素 0 差异(对照组:真缩放重绘 79581 像素);
[B] 单点信号的适应视图与首次加载一致(1s/1、居中、幂等);
[C] 首个网格自适应时间轴、后续新增/隐藏信号都不再改动时间轴;
[D] 偏移 +0.3 时吸到“画面上的点”,偏移 0 行为不变,偏移把点移出视界时不吸附;
[E] 回归:单点默认样式(点线 + 最大线宽)与“2…16 点不再改点线”均保持。
A/B:回退三项修复 ⇒ 7 项如实失败(含 143513 / 137326 像素的重绘症状)。
make release 零警告(用户正运行 Target.exe,链接用临时 -o 名字验证通过)。
六、规则同步
Documents/agent_mem.md 新增 §9.31、§11.2 第 58–63 条(含修正后的自适应范围/时机规则)
与变更日志。
This commit is contained in:
1 parent
57cc714c1d
commit
68d8b7ede6
5 files changed
+202
-80
No files matched your search
+75
-11
@@ -1620,16 +1620,18 @@ GDI+ 抗锯齿逐段扫描这些**近竖直、满幅**的边,代价爆炸(
|
||||
|
||||
- **N = `GridMinorCellCount()`**:网格底衬一横排的小格数,与 `PaintLane`/`PaintTimeAxis`
|
||||
用**同一套** `NiceStep(span, kTimeTickTarget)` + 五等分算出(所以不随缩放等级大幅变化)。
|
||||
- **`SignalSnapEnabled(axis, signal)`**(用户 2026-10-15 的定义):
|
||||
- **`SignalSnapEnabled(axis, signal, timeShift)`**(用户 2026-10-15 的定义):
|
||||
**当且仅当**该信号在**当前一屏**内的数据点个数 `< N × 4` 时开启吸附;
|
||||
判据随视界实时重算 ⇒ 疏密变化的信号“移到稀疏区自动吸附、移回稠密区自动自由移动”。
|
||||
⚠️ 额外要求视界内**至少有一个可见数据点**(否则“0 < N×4”会把“数据全在视界之外”的信号
|
||||
误判成稀疏,白切一次点线且没有任何可吸附对象)。
|
||||
⚠️ 可见性与点个数一律按**显示时间**(`采样时刻 + timeShift`,`timeShift` = 该信号的
|
||||
`offsetTime`)判断;且要求视界内**至少有一个可见数据点**(否则“0 < N×4”会把“数据全在
|
||||
视界之外”的信号误判成稀疏,白切一次点线且没有任何可吸附对象)。
|
||||
⚠️ 性能:总数不足阈值时直接返回(配合 `sparseTimes` 二分);否则只统计可见下标区间内的
|
||||
有限值并**攒够阈值即早退**,扫描窗口还有 `threshold × 64` 的上限(防 NaN 长循环)。
|
||||
- **`SnapTimeToSample`**:判定**只针对鼠标所在网格**(`LaneAtY(m_mouseY)`)——
|
||||
同一个时间轴上,一个网格达到稀疏标准、另一个没有时,只在前者吸附;
|
||||
同网格内**所有符合判定的信号**的数据点都参与比较。
|
||||
⚠️ 一切判定与查找都在**显示时间**(`采样时刻 + offsetTime`)空间进行,详见 §9.31。
|
||||
**吸附半径 = 一个网格小格的宽度**(与判定同源),且**不超过半个局部采样间距**
|
||||
⇒ 数据点很稀疏(一屏只有一两个点)时光标在点之间仍可自由移动(吸附 ≠ 卡住)。
|
||||
⚠️ `LocalSampleSpacing` 对 `finiteCount <= 1` 必须返回 0(“数据点间距无定义”),
|
||||
@@ -1662,6 +1664,49 @@ GDI+ 抗锯齿逐段扫描这些**近竖直、满幅**的边,代价爆炸(
|
||||
|
||||
---
|
||||
|
||||
### 9.31 自适应范围/时机澄清 + 适应视图与 Y 轴自适应互不干扰 + 吸附跟随时间偏移(本轮,起源设备)
|
||||
|
||||
> 本轮四项(用户 2026-10-15 第三轮):① 澄清“自适应范围/时机”的准确说法(并修正记忆里不完善的表述);
|
||||
> ② 「适应视图」与「Y 轴自适应」互相干扰(相互切换都会重绘、区间会变);
|
||||
> ③ 「适应视图」在单点信号上让数据点“飞了”;④ 光标吸附没有考虑「调整 → 时间轴偏移」。
|
||||
> 离屏验证 **39/39 通过**(连跑 3 次稳定),A/B 回退三项修复后 **7 项如实失败**。
|
||||
|
||||
#### 一、自适应范围/时机的准确说法(用户澄清)
|
||||
|
||||
* **首个网格**显示内容时做完整自适应:**Y 轴与时间轴都**匹配自己的数据范围;
|
||||
* **只有一个数据点**的信号必须显示在网格**中间**(`FitSinglePointSignal()`:居中 + 1s + 1);
|
||||
⚠️ **工具栏「适应视图」也要走这条路**(仅一个网格 + 唯一可见信号为单点时),
|
||||
否则数据点会被挤到网格边缘、看起来“飞了”。
|
||||
* **后续新增网格**只做 **Y 轴**自适应(`ReapplyGlobalAutoFitIfEnabled`),**不再调整时间轴**。
|
||||
⇒ 记忆里“额外要求视界内至少有一个可见数据点”这句是**不完善**的表述,完整含义见上
|
||||
(“可见”指的是单点信号要被居中摆在网格里而不是挪出视界)。
|
||||
|
||||
#### 二、「适应视图」与「Y 轴自适应」互不干扰(`PadValueRange`)
|
||||
|
||||
- **根因**:两条自适应路径的**留白不同** —— 整段自适应(`ComputeLaneRange` → `PadRange`)用
|
||||
**6%**,「选区 Y 轴自适应」(`AutoRangeLaneToView`)用 **5%**。视界未变时两者本应完全相等,
|
||||
于是“点过适应视图 → 打开 Y 轴自适应”会算出不同区间、网格被无意义重绘(实测 **143513 像素**),
|
||||
反向操作同样(**137326 像素**)。
|
||||
- **修法**:新增 `DataModel.hpp` 的 **`PadValueRange()`**(含退化区间规则)作为**唯一**留白实现,
|
||||
`PadRange` 与 `AutoRangeLaneToView` 都调它。
|
||||
- 验证:`[A]` 在“适应视图 → 开自适应 → 关自适应 → 再适应视图”四个步骤上断言
|
||||
**生效区间逐位相同**且**绘图区逐像素 0 差异**(含对照组:真缩放会重绘 79581 像素)。
|
||||
⚠️ 断言必须用 `ComputeLaneRange` 取**生效区间** —— `autoRange == true` 时
|
||||
`Lane::yMin/yMax` 只是初始占位值(±1),直接读它会得到假失败。
|
||||
|
||||
#### 三、吸附跟随「调整 → 时间轴偏移」
|
||||
|
||||
- **根因**:采样点 k 画在 `time[k] + offsetTime` 处,而光标存的也是**显示时间**,
|
||||
但吸附一直在**源时间**空间查找 —— 设过时间轴偏移后,吸附会落到历史位置(用户报告)。
|
||||
- **修法**:`SignalSnapEnabled` / `HasVisibleSample` / `NearestSnapSample` / `LocalSampleSpacing`
|
||||
全部增加 `timeShift` 形参:可见性与点数统计比 `time[k] + timeShift`,
|
||||
`NearestSnapSample` 内部用 `time - timeShift` 回源空间查找、返回时再加回去
|
||||
⇒ `SnapTimeToSample` 拿到的 `candidate` 是**画面上的**时刻;`UpdateAutoScatterStyles` 同步传 `offsetTime`。
|
||||
- 验证:`[D]` 偏移 +0.3 时“靠近画面上的点”必须吸到 `源时刻 + 0.3`;偏移=0 时行为不变;
|
||||
偏移把点移出视界时不开启吸附也不吸(不会吸到看不见的位置)。
|
||||
|
||||
---
|
||||
|
||||
## 10. 变更日志(本文件维护记录)
|
||||
|
||||
| 日期 | 设备/模型 | 摘要 |
|
||||
@@ -1705,6 +1750,7 @@ GDI+ 抗锯齿逐段扫描这些**近竖直、满幅**的边,代价爆炸(
|
||||
| 2026-10-15 | DeepSeek-V4.1-Flash(**起源设备**) | **信号列表滚动越界绘制 + 边沿统计面板「显示冻结」(详见 §9.28)**。① **列表把组名/信号名画到筛选框上**(MF4 多信号场景):根因是 `UiText` 走 GDI `DrawTextW`,**GDI 文本不遵循 GDI+ 的 `SetClip`** —— 被滚出视口的「部分可见」行会把文字画到列表上方的筛选框上(`UiFillRect` 的大面积不透明矩形走 GDI `FillRect` 同理)。修法:`PaintUtil` 新增 **`UiTextClipped`**(同一 HDC `SaveDC` + `IntersectClipRect` + `RestoreDC`;`UiText` 转发 `clip=nullptr`,行为不变),`SignalPanel` 新增 `PaintRowText`(裁到 `m_listRect`)/ `FillRowRect`(夹到 `m_listRect`),分组行与信号行的全部文本与行底色均改走它们。② **边沿统计面板在不移动鼠标时显示冻结**:面板像素图层缓存键(`PanelSlotKey`)**不含**面板上显示的统计数字,而统计是**分帧推进**的中间结果 ⇒ 推进不会让键变化 ⇒ 面板一直贴旧像素 ⇒ 显示停在「统计中…」/中间值,**只有移动鼠标**(改变面板层序/悬停/鼠标坐标等其它键)才重绘并显示早已算完的正确结果(扫描推进本身没停)。修法:`PanelSlotKey` 内按面板实际显示的条目回调 `EdgeCountsFor`/`EdgeCenterCountsFor` 并把 `(rising, falling, complete)` mix 进键。验证:新增离屏 `.preflight/check`(`SW_HIDE` + 不注入真实输入 + `BELOW_NORMAL`)**39/39 通过**(连跑两次稳定):`[A]` 40 信号滚轮下滚后「列表上方区域逐像素 0 变化」且「列表内部仍有变化」(修复前 **1571 像素被污染**)、`[B]` 3 信号 × 300 万采样下两种统计面板的**缓存键持续变化**且**无鼠标输入即完成**(修复前键不变化)、`[C]` 真实 `MF4-Record.MF4`(**124 信号 / 3 条时间轴**)同样 0 像素变化;**并做了 A/B**(`git stash` 回退修复后 `[A]/[B]` 如实失败);`make release` 零警告。 |
|
||||
| 2026-10-15 | DeepSeek-V4.1-Flash(**起源设备**) | **全局 Y 轴自适应跟随网格结构 + 组名悬浮 + 稀疏信号默认点线 + 单点光标吸附 + 放大自动点线(详见 §9.29)**。① **新网格不继承全局 Y 轴自适应**:`RebuildLanes` 对新出现的信号返回默认 `LaneCarry()` ⇒ `fitYToSelection=false`;修法:重建前先算 `previousAllAutoFit`(非空且**每个**网格都开着 = 全局开启的正式定义),`LaneCarry` 加 `matched` 标记,新信号用它当默认;并新增 `ReapplyGlobalAutoFitIfEnabled()` 在 **`Layout()`(网格数变化)/`RefreshLanes()`(信号数变化)/`SplitLane()`** 之后立即重算 ⇒ 新勾选(按**当前视界**自适应)、取消显示(剩余信号重新收敛)、拆分(每份各自自适应)三项全覆盖。② **组名悬浮**:新增 `SignalPanel::StickyGroupRowIndex()` + `PaintStickyGroupRow()`(不透明底 + 底部边界线),`RowRect` 加 `m_rowYOverrideActive/Y` 覆盖行顶部(行内所有几何的唯一来源);判据 = 分组行已在列表上边界之上且本组最后一行仍在列表内;常规循环**跳过**被钉住的行(否则画两次)。③ **稀疏信号默认样式**:新增 `ApplySparseDefaultStyle`(1 个有效点 → 点线 + **最大线宽 10px**;2..16 → 点线 + 2px),在 `BuildSignalGroup`/`InsertDerivedSignal` 两处调用;线宽常量统一到 `DataModel.hpp`(`kSignalLineWidthMin/Max`)并被 SignalPanel 滑块引用;`ComputeStats` 输出 `firstFiniteIndex`、`SignalData` 新增 `singlePointTime`。④ **单点光标吸附**:`SnapTimeToSample` 新增半径分支(`kCursorSnapPointRadiusPixels=8` 逻辑像素)吸附 `singlePointTime`,半径外自由移动(**吸附而非卡住**)。⑤ **放大自动点线**:`SignalStyle` 新增 `autoScatterActive/autoScatterSavedMode/autoScatterUserOverride`,`AxisSparseInView`(间距 > 半个绘图区宽度,与吸附上门限同源,**单点轴不算稀疏**)+ `UpdateAutoScatterStyles()`(在 `SetTimeView` 等四处调用)⇒ 进入阈值自动切点线、退出阈值恢复原样式,**用户手动改过则不恢复**(判定必须放在恢复判断**之前**,否则用户改完紧接着缩出去会被覆盖)。验证:新增离屏 `.preflight/check` **65/65 通过**(连跑 3 次稳定,覆盖 7 组断言;含“钉住行与自然位置逐像素一致”“单点吸附半径内外”“用户手动改样式后退出不覆盖”),**A/B**:临时禁用六个机制后 **21 项如实失败**;`make release` 零警告。 |
|
||||
| 2026-10-15 | DeepSeek-V4.1-Flash(**起源设备**) | **组名平滑悬浮 + 单点信号初始视图 + 光标吸附统一判定(自动点线同源)(详见 §9.30)**。① **组名悬浮平滑化**:位置改为 `StickyGroupRowTop = min(列表上边界, 本组最后一行下边界 − 组名高度)` ⇒ 组名随最后一行**自然滚出**(不再突然消失),且下边界永不越过下一个分组行的自然位置 ⇒ **不再遮住下一组名**(旧实现固定钉在列表上边界会把下一组名盖住,让别人以为后面的信号属于上一组);**折叠的分组不悬浮**(随滚动自然划过);底部边界线只在真的“浮”起来时才画。② **单点信号初始视图**:新增 `PlotView::FitSinglePointSignal()`(无任何信号被勾选、勾选的第一个信号只有 1 个有效点时生效)—— 数据点居中、**时间跨度 1s**、**Y 跨度 1**,并置 `autoRange=false`/`fitYToSelection=false`;`Application::SynchronizeView` 首次勾选时先试它、失败才 `FitAll()`;`AutoRangeLaneToView` 的退化区间改为 `PadRange` 同款留白 `max(1,|v|×0.1)`。③ **吸附判定统一**(用户给出的唯一判据):新增 `GridMinorCellCount()`(网格一横排小格数 N,与网格绘制同源)+ `SignalSnapEnabled()`(**当且仅当**某信号在当前一屏内的数据点 `< N×4` 才开启吸附,随视界实时重算 ⇒ 疏密信号自适应),`SnapTimeToSample` **只按鼠标所在网格**判定、同网格内所有符合判定的信号数据点都参与、吸附半径 = 一个网格小格宽且不超过半个局部采样间距(吸附≠卡住);旧的 `SampleSpacingPixels`(6px 下门限+半屏宽上门限)**已删除**。④ **自动点线改为与吸附判定完全同源**(`UpdateAutoScatterStyles` 调 `SignalSnapEnabled`),旧 `AxisSparseInView` **已删除**;进入阈值自动切点线、不再满足自动恢复、用户手动改过则不恢复。⑤ **需求作废**:“2…16 个有效采样点默认点线 + 2px”**已取消**(只保留“1 个有效点 → 点线 + 最大线宽”);`SignalData::singlePointTime` 升级为 **`sparseTimes`/`sparseValues`**(有效点 ≤ 1024 时全部缓存,供吸附与单点视图使用)。验证:新增离屏 `.preflight/check` **55/55 通过**(连跑 3 次稳定;覆盖组名悬浮四种场景、单点初始视图、吸附判定/网格作用域/多信号/动态切换/单点半径、自动点线同源与用户覆盖);**A/B** 禁用三项机制 ⇒ **14 项如实失败**;`make release` 零警告。 |
|
||||
| 2026-10-15 | DeepSeek-V4.1-Flash(**起源设备**) | **自适应范围/时机澄清 + 适应视图与 Y 轴自适应互不干扰 + 吸附跟随时间偏移(详见 §9.31)**。① **澄清“自适应范围/时机”**(修正记忆里“额外要求视界内至少有一个可见数据点”这句不完善的表述):**首个网格**显示内容时 **Y 轴与时间轴都**自适应;只有一个数据点的信号要**居中显示在网格里**(`FitSinglePointSignal`:居中 + 时间跨度 1s + Y 跨度 1);**后续新增网格只做 Y 轴自适应、不再调整时间轴**。② **「适应视图」与「Y 轴自适应」互相干扰**:根因是两条自适应路径**留白不同**(`PadRange` 6% vs `AutoRangeLaneToView` 5%)⇒ 视界未变时也会算出不同区间、网格被无意义重绘(实测切一次 **143513** 像素、反向 **137326** 像素)。修法:新增 `DataModel.hpp` 的 **`PadValueRange()`** 作为唯一留白实现(含退化区间 `max(1,|v|×0.1)`),`PadRange` 与 `AutoRangeLaneToView` 共用 ⇒ 四个步骤(适应视图→开自适应→关自适应→再适应视图)**区间逐位相同且绘图区逐像素 0 差异**。③ **「适应视图」在单点信号上让数据点“飞了”**:`FitAll()` 开头先试 `FitSinglePointSignal()`(仅一个网格 + 唯一可见信号为单点),与首次加载效果一致且幂等。④ **吸附跟随「调整 → 时间轴偏移」**:采样点画在 `time[k] + offsetTime` 处而光标存的是显示时间,旧实现按源时刻吸附 ⇒ 落到历史位置;修法:`SignalSnapEnabled`/`HasVisibleSample`/`NearestSnapSample`/`LocalSampleSpacing` 全部加 `timeShift`,查找时 `time - timeShift` 回源空间、返回时加回去,`UpdateAutoScatterStyles` 同步传 `offsetTime`。验证:离屏 `.preflight/check` **39/39 通过**(连跑 3 次稳定;含像素级零变化断言与“真缩放会重绘”对照组);**A/B** 回退三项修复 ⇒ **7 项如实失败**(含 143513/137326 像素重绘症状);`make release` 零警告。 |
|
||||
|
||||
---
|
||||
|
||||
@@ -1925,24 +1971,42 @@ GDI+ 抗锯齿逐段扫描这些**近竖直、满幅**的边,代价爆炸(
|
||||
58. ⚠️ **光标吸附的判定只有一套定义(§9.30)**:某信号在当前一屏内的数据点个数
|
||||
`< N × 4`(N = `GridMinorCellCount()`,网格一横排的小格数,与网格绘制同源)时
|
||||
才为它开启吸附;判据**随视界实时重算**(疏密变化的信号自动在稀疏区吸附、稠密区自由)。
|
||||
⚠️ 额外要求视界内**至少有一个可见数据点**;
|
||||
⚠️ 可见性与点数一律按**显示时间**(`采样时刻 + offsetTime`)判断
|
||||
(`SignalSnapEnabled/HasVisibleSample/NearestSnapSample/LocalSampleSpacing` 都带 `timeShift`);
|
||||
视界内至少要有**一个可见数据点**(否则不开启)。
|
||||
⚠️ 判定**只针对鼠标所在网格**(`SnapTimeToSample` 用 `LaneAtY(m_mouseY)`);
|
||||
⚠️ 吸附半径 = **一个网格小格宽**,且**不超过半个局部采样间距**(吸附 ≠ 卡住光标);
|
||||
⚠️ 旧的 `SampleSpacingPixels`(6px 下门限 + 半屏宽上门限)**已删除,不要再恢复**。
|
||||
⚠️ 吸附半径 = **一个网格小格宽**,且**不超过半个局部采样间距**(吸附 ≠ 卡住光标)。
|
||||
⚠️ 旧的 `SampleSpacingPixels`(6px 下门限 + 半屏宽上门限)**已删除,不要再恢复**;
|
||||
且吸附必须落在**画面上**的数据点(源时刻 + `offsetTime`),不能吸到历史位置。
|
||||
⚠️「放大自动切点线」必须**与吸附判定完全同源**(`UpdateAutoScatterStyles` 调
|
||||
`SignalSnapEnabled`),不要再引入“采样间距 > 半屏宽”之类的独立判据。
|
||||
⚠️ `SignalData` 用 **`sparseTimes` / `sparseValues`**(有效点 ≤ 1024 时缓存全部有效点)
|
||||
支撑吸附与单点初始视图;**不要**在鼠标移动时扫描整条采样数组。
|
||||
⚠️ `LocalSampleSpacing` 对 `finiteCount <= 1` 必须返回 0(数据点间距无定义),
|
||||
否则单点信号永远吸不住。
|
||||
⚠️「放大自动切点线」必须**与吸附判定完全同源**(`UpdateAutoScatterStyles` 调
|
||||
`SignalSnapEnabled`,同样传入 `offsetTime`),不要再引入“采样间距 > 半屏宽”之类的独立判据。
|
||||
⚠️ 判定与查找都在**显示时间**空间:`NearestSnapSample` 内部按 `timeShift` 换算回源空间、
|
||||
返回时再加回去,因此存在「调整 → 时间轴偏移」时也能吸到画面上的数据点。
|
||||
59. ⚠️ **「2…16 个有效采样点用点线 + 2px」的需求已作废**(用户 2026-10-15 明确取消)。
|
||||
仍保留:**只有一个有效采样点** → 「点线」+ **最大线宽**;其余信号保持默认「线段 + 1px」。
|
||||
需要“提示数据点位置”的场景一律由 §9.30 的“放大自动点线”承担(同源判定)。
|
||||
60. ⚠️ **单点信号的初始视图**:当前无任何信号被勾选、而勾选的第一个信号只有**一个**有效数据点时,
|
||||
必须走 `FitSinglePointSignal()`(数据点居中、**时间跨度 1s**、**Y 轴跨度 1**),
|
||||
不要再落到 `FitAll()` 的整段自适应(时间轴会覆盖整条时间列、Y 区间退化成几乎为 0)。
|
||||
同时 `AutoRangeLaneToView` 的退化区间要按 `PadRange` 同款留白 `max(1, |v|×0.1)`。
|
||||
61. ⚠️ **组名悬浮的位置公式(勿改回“固定钉在列表上边界”)**:
|
||||
60. ⚠️ **自适应的范围与时机(用户 2026-10-15 澄清,这是“可见”要求的准确含义)**:
|
||||
* **首个网格**显示内容时,要对它做完整自适应 —— **Y 轴与时间轴都**匹配自己的数据范围;
|
||||
* **只有一个数据点**的信号必须显示在网格**中间**(否则时间轴覆盖整条时间列、
|
||||
Y 区间退化成几乎为 0,数据点被挤到边缘甚至看不出位置)。
|
||||
✓ 走 `FitSinglePointSignal()`(数据点居中、**时间跨度 1s**、**Y 轴跨度 1**);
|
||||
⚠️ **工具栏「适应视图」也要走这条路**(仅一个网格 + 唯一可见信号为单点时),
|
||||
否则用户点“适应视图”后数据点会“飞了”。
|
||||
* **后续新增网格**只做 **Y 轴**自适应,**不再调整时间轴**(`ReapplyGlobalAutoFitIfEnabled`
|
||||
挂在 `Layout`/`RefreshLanes`/`SplitLane`,这些路径都不碰 `Tab().ViewMin/ViewMax`)。
|
||||
* 退化区间(恒定值 / 单点)的留白统一为 `max(1, |值|×0.1)`。
|
||||
62. ⚠️ **幅值留白只能有一个来源**:`PadValueRange()`(`DataModel.hpp`,6%)。
|
||||
整段自适应(`ComputeLaneRange`)与「选区 Y 轴自适应」(`AutoRangeLaneToView`)
|
||||
**必须共用它** —— 两处各自硬编码(6% / 5%)时,「点过适应视图后再打开 Y 轴自适应」
|
||||
会算出不同区间 ⇒ 网格被无意义地重绘一次(实测 ~14 万像素)。
|
||||
反向(关掉自适应再点适应视图)同样会变。统一后这两种操作在视界未变时**像素级零变化**。
|
||||
63. ⚠️ **组名悬浮的位置公式(勿改回“固定钉在列表上边界”)**:
|
||||
`min(列表上边界, 本组最后一行下边界 − 组名高度)` ⇒
|
||||
组名随最后一行**平滑滚出**(不突然消失),且下边界永不越过下一个分组行的自然位置
|
||||
⇒ **不可能遮住下一个组名**;**折叠的分组不悬浮**(随滚动自然划过)。
|
||||
|
||||
Reference in new issue
Block a user