专题页的迷雾按专题圈的区域收口

以前专题的中心/半径只用来定视图,迷雾图层一直是全局的;管理页那句
「迷雾由地图按视野自动呈现,不需要单独圈选」其实是把「没做」写成了
「不用做」。现在专题圈了区域时,迷雾只在那个圆内显示。

做法是给迷雾单独一个 pane(zIndex 250,底图 200 之上)再对该 pane 做
clip-path: circle()——不能直接裁 tilePane,底图也在里面,会把地图一起挖空。

两个坑:
- 圆心必须先 project() 到底图坐标系(与 fitCircle 一致),否则整体偏移;
- 裁剪圆的注册必须排在 applyFit() 之后:视图未定时 latLngToContainerPoint()
  会抛「Set map center and zoom first.」,把后续图层添加一起打断——实测
  表现是 pane 建好了、迷雾瓦片一张都不出来,而且不报错。

迷雾是累积快照、没有时间维度,所以只按区域收口,不按专题的时间范围收口。
守卫 TestTopicFogIsClippedToArea 钉住两端与注册顺序。
This commit is contained in:
tamakyi
2026-10-10 10:41:27 +08:00
parent cd69efe8f1
commit eb35abb7f2
7 changed files with 122 additions and 4 deletions
+31 -1
View File
@@ -704,9 +704,31 @@
// 专题可以在管理页关掉迷雾(opts.showFog=false),此时图层、浓度滑杆、图层开关都不出现。
var wantFog = opts.showFog !== false;
var fogLayer = null;
/* 专题可以圈一个区域(opts.fogArea = {lat, lon, radiusKm}):此时迷雾只在该圆内显示。
做法是给迷雾**单独一个 pane** 再对这个 pane 做圆形 clip-path —— 不能直接裁默认的
tilePane,底图也在那里面,会把地图一起裁掉。
圆心必须跟 fitCircle 一样先 project() 到底图坐标系,否则会整体偏出几百米。
clip-path 不认识的老浏览器只是「不裁剪」(退回全局迷雾),不会出错。 */
var fogPane = null, applyFogClip = null;
if (wantFog && cfg.fog && cfg.fog.blocks > 0 && opts.fogArea && opts.fogArea.radiusKm > 0) {
map.createPane('rondFog');
fogPane = map.getPane('rondFog');
fogPane.style.zIndex = 250; // 底图瓦片 200 之上、覆盖物 400 之下
fogPane.style.pointerEvents = 'none';
var fogC = project(opts.fogArea.lat, opts.fogArea.lon, def.crs);
var fogCenter = L.latLng(fogC[0], fogC[1]);
var fogNorth = L.latLng(fogCenter.lat + (opts.fogArea.radiusKm * 1000) / 111320, fogCenter.lng);
applyFogClip = function () {
var p = map.latLngToContainerPoint(fogCenter);
var r = Math.max(1, p.distanceTo(map.latLngToContainerPoint(fogNorth)));
var v = 'circle(' + r.toFixed(1) + 'px at ' + p.x.toFixed(1) + 'px ' + p.y.toFixed(1) + 'px)';
fogPane.style.clipPath = v;
fogPane.style.webkitClipPath = v;
};
}
if (wantFog && cfg.fog && cfg.fog.blocks > 0) {
fogLayer = L.tileLayer('/tiles/fog/{z}/{x}/{y}?crs=' + def.crs + '&v=' + cfg.fog.ver, {
minZoom: 3, maxZoom: 18, opacity: 0.9
minZoom: 3, maxZoom: 18, opacity: 0.9, pane: fogPane ? 'rondFog' : 'tilePane'
});
}
var overlayDefs = {};
@@ -759,6 +781,14 @@
};
applyFit();
// 圈了区域的专题:迷雾只在该圆内显示。必须**等视图定下来之后**再算裁剪圆 ——
// 视图没定时 latLngToContainerPoint() 会抛「Set map center and zoom first.」,
// 那行异常会把后面的图层添加一起打断(实测:pane 建好了、迷雾瓦片一张都没有)。
if (applyFogClip) {
map.on('move zoom viewreset resize', applyFogClip);
applyFogClip();
}
var st = state4(map, points, group, def.crs, true);
st.clustered = true;
st.pad = 0.15;