专题的多圆显示区:前台按并集裁剪迷雾
上一批把显示区改成了「一组圆」,这一批让前台真正认多个圆。 - clip-path 从 circle() 换成 path():circle() 只表达得了一个圆。每个圆一段 圆弧子路径、**同绕向**(sweep=0),nonzero 填充规则下多段自然取并集, 重叠处不会互相挖洞。 - 拼路径的活单独放 fog-clip.js(rond-map.js 是个大 IIFE,函数取不出来), 这样能直接跑 node 单测;layout 里必须排在 rond-map.js 之前加载。 - 顺带清掉已经死掉的 fitCircle:多圆之后「圆心 + 半径」表达不了,留着就是 两套并行的贴合口径。fitParams 现在只给 fitBBox(单圆时外接矩形正是那个 圆的外接正方形,视野等价)。 - 守卫改名 TestTopicFogIsClippedToAreas,钉住两端(模板发 fogAreas ↔ 脚本认 fogAreas)与两处顺序(裁剪注册在 applyFit 之后、fog-clip.js 在 rond-map.js 之前);fogAreas 必须**无条件**下发(空数组 = 不限区域),不要包在条件里。 - verify.sh 挂进前端单测:以前只靠人记得手动跑 = 等于没有。找不到 node 直接 失败而不是跳过(跳过会让验收看着全绿、实际一行前端脚本都没验)。 验证(临时两圆专题,SQL 造的,已删): - fog-clip.test.js 15 条:把生成的 path 解析回圆弧再验几何,含绕向一致性与 半径 0/负数的夹取。 - 端到端像素验证:自校准出「CSS 容器坐标 → 图像像素」(scale≈2、offset≈19.2, 正是 site_cdp 的 --clip 外扩 10px×scale,别再手算);三张掩码图证明并集语义 —— A 独有点只有 A 亮、B 独有点只有 B 亮、**重叠中心两圆都亮且并集也亮 (无洞)**,整体集合差异 0.013%。 - 迷雾掩码:86,776 个像素,按两圆并集的解析式判 **圆外 0 个**;两个圆内分别 有 52,609 / 46,757 个迷雾像素 ⇒ 第二个圆真的被认了,不是只看第一个。
This commit is contained in:
@@ -265,25 +265,33 @@ func TestDateInputsGoThroughAttachAll(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
// ---------- 专题的迷雾要和「区域」成对:模板传 fogArea、地图脚本认 fogArea ----------
|
||||
// ---------- 专题的迷雾要和「显示区」成对:模板传 fogAreas、地图脚本认 fogAreas ----------
|
||||
//
|
||||
// 2026-10-10 用户实测发现:专题圈了区域,迷雾却还是全局的。而管理页原本的说明写的是
|
||||
// 「区域内的世界迷雾由地图按视野自动呈现,不需要单独圈选」—— **文档与实现不一致**
|
||||
// (迷雾一直是全局瓦片,完全不认区域),这种「说明写了、实现没做」最容易蒙混过关。
|
||||
//
|
||||
// 这条守卫钉住两端与一处顺序:
|
||||
// ① topic.html 必须把专题区域传给地图;
|
||||
// ② rond-map.js 必须实现圆形收口(单独 pane + clip-path,不能裁默认 tilePane——底图在里面);
|
||||
// ③ 裁剪圆的注册必须排在 applyFit() 之后:视图还没定时 latLngToContainerPoint() 会抛
|
||||
// 这条守卫钉住两端与两处顺序:
|
||||
// ① topic.html 必须把专题显示区传给地图(且**无条件**传,不限区域时是空数组);
|
||||
// ② rond-map.js 必须实现收口(单独 pane + clip-path,不能裁默认 tilePane——底图在里面)
|
||||
// 且多圆要交给 fog-clip.js 的 pathFor;
|
||||
// ③ fog-clip.js 必须在 rond-map.js **之前**加载(否则 window.rondFogClip 还没有);
|
||||
// ④ 裁剪的注册必须排在 applyFit() 之后:视图还没定时 latLngToContainerPoint() 会抛
|
||||
// 「Set map center and zoom first.」,那行异常会把后面的图层添加一起打断
|
||||
// (实测:pane 建好了、迷雾瓦片一张都没有)。
|
||||
func TestTopicFogIsClippedToArea(t *testing.T) {
|
||||
func TestTopicFogIsClippedToAreas(t *testing.T) {
|
||||
tpl, err := tmplFS.ReadFile("templates/topic.html")
|
||||
if err != nil {
|
||||
t.Fatalf("读取 topic.html 失败: %v", err)
|
||||
}
|
||||
if !strings.Contains(string(tpl), "fogArea:") {
|
||||
t.Error("topic.html 没把专题区域(fogArea)传给地图 —— 迷雾不会被收口到那个圆内")
|
||||
body := string(tpl)
|
||||
if !strings.Contains(body, "fogAreas:") {
|
||||
t.Error("topic.html 没把专题显示区(fogAreas)传给地图 —— 迷雾不会被收口")
|
||||
}
|
||||
// 无条件传(不要包在 {{if .Topic.HasArea}} 里):条件分支是「有区域忘了新增分支」
|
||||
// 这类漏传的温床,而空数组对脚本来说就是「不限区域」,没必要分两条路。
|
||||
if !strings.Contains(body, "fogAreas: {{.Topic.AreasJSON}}") {
|
||||
t.Error("fogAreas 应当无条件下发 {{.Topic.AreasJSON}}(不限区域时为空数组),别包在条件里")
|
||||
}
|
||||
|
||||
js, err := staticFS.ReadFile("static/js/rond-map.js")
|
||||
@@ -291,9 +299,9 @@ func TestTopicFogIsClippedToArea(t *testing.T) {
|
||||
t.Fatalf("读取 rond-map.js 失败: %v", err)
|
||||
}
|
||||
src := string(js)
|
||||
for _, needle := range []string{"opts.fogArea", "createPane('rondFog')", "clipPath"} {
|
||||
for _, needle := range []string{"opts.fogAreas", "createPane('rondFog')", "clipPath", "rondFogClip.pathFor"} {
|
||||
if !strings.Contains(src, needle) {
|
||||
t.Errorf("rond-map.js 里缺 %q —— 迷雾的圆形收口没实现或被改掉了", needle)
|
||||
t.Errorf("rond-map.js 里缺 %q —— 迷雾的收口没实现或被改掉了", needle)
|
||||
}
|
||||
}
|
||||
// 顺序:注册点必须排在 `var applyFit = function` 之后 —— 放早了(比如塞在迷雾图层那段里)
|
||||
@@ -304,6 +312,27 @@ func TestTopicFogIsClippedToArea(t *testing.T) {
|
||||
t.Error("applyFogClip 的注册必须排在 applyFit 定义(也就是视图设定)之后 —— " +
|
||||
"视图未定时算裁剪圆会抛错,并把后面的图层添加一起打断")
|
||||
}
|
||||
|
||||
// 多圆路径拼在 fog-clip.js 里,它必须在 rond-map.js 之前加载
|
||||
clip, err := staticFS.ReadFile("static/js/fog-clip.js")
|
||||
if err != nil {
|
||||
t.Fatalf("读取 fog-clip.js 失败: %v", err)
|
||||
}
|
||||
if !strings.Contains(string(clip), "rondFogClip") {
|
||||
t.Error("fog-clip.js 没有暴露 rondFogClip —— rond-map.js 拿不到路径构造函数")
|
||||
}
|
||||
layout, err := tmplFS.ReadFile("templates/layout.html")
|
||||
if err != nil {
|
||||
t.Fatalf("读取 layout.html 失败: %v", err)
|
||||
}
|
||||
lay := string(layout)
|
||||
iClip := strings.Index(lay, "/static/js/fog-clip.js")
|
||||
iMap := strings.Index(lay, "/static/js/rond-map.js")
|
||||
if iClip < 0 {
|
||||
t.Error("layout.html 没引入 fog-clip.js —— 专题的多圆裁剪会静默退化成「不裁剪」")
|
||||
} else if iMap < 0 || iClip > iMap {
|
||||
t.Error("fog-clip.js 必须排在 rond-map.js 之前加载")
|
||||
}
|
||||
}
|
||||
|
||||
// ---------- 字阶纪律:app.css 与模板内联样式都只走令牌 ----------
|
||||
|
||||
Reference in New Issue
Block a user