8.5 KiB
Earth Mobile Center Country Highlight Plan
Goal
移动端打开 Earth 国界图层后,用屏幕中心,也就是当前镜头正对的地球表面位置,自动识别所在国家,并高亮该国家国界。
桌面端仍保持现有 hover 行为。移动端不引入新的国界渲染体系,而是复用已有 country-boundaries.js 的 GeoJSON 命中和 hover 高亮能力。
Criteria for success
- 移动端
layout-mode-mobile下,国界图层开启后,屏幕中心所在国家会自动高亮。 - 移动端旋转、缩放、巡航或自动旋转地球时,高亮会跟随镜头中心更新。
- 屏幕中心落在海洋或没有命中地球时,国家高亮会清除。
- 国界图层关闭时,不执行中心国家识别,也不显示残留高亮。
- 桌面端 pointer hover 行为保持不变。
- 移动端抽屉、搜索、设置、媒体、详情等前景 UI 打开时,不因为用户操作 UI 产生明显误高亮或抖动。
- 中心识别有节流或状态缓存,不把 GeoJSON point-in-polygon 检测放到无条件每帧高频执行。
- 实现后能通过本地静态检查或前端构建,并用移动端 viewport 手动或 Playwright 验证核心场景。
Existing pieces
当前项目已经具备大部分基础能力:
- frontend/public/earth/js/country-boundaries.js
updateCountryBoundaryHover(coords):根据{ lat, lon }命中国家并更新高亮线。clearCountryBoundaryHover():清除当前 hover 高亮。getShowCountryBoundaries():判断国界线图层是否可见。
- frontend/public/earth/js/utils.js
screenToEarthCoords(clientX, clientY, camera, earth, domElement):屏幕坐标 raycast 到地球表面。vector3ToLatLon(vector):地球本地坐标转经纬度。
- frontend/public/earth/js/constants.js
COUNTRY_BOUNDARY_CONFIG已定义普通国界线和 hover 国界线样式。
- 移动端布局状态已经通过
layout-mode-mobilebody class 区分。
因此本需求的核心不是新增图层,而是补一个移动端中心取点控制器。
Non-goals
- 不改变桌面端 hover 交互。
- 不替换
countries-admin0.min.geojson数据源。 - 不新增后端 API。
- 不把国家面填充做成新的 selected country 面状 shader。
- 不为移动端增加永久准星 UI,除非后续产品明确需要视觉准星。
Implementation plan
1. Add a small mobile center hover controller
新增一个轻量函数,建议放在现有主循环附近或单独模块,例如:
frontend/public/earth/js/mobile-center-country-highlight.js
建议导出:
updateMobileCenterCountryHighlight({
camera,
earth,
renderer,
now,
isBlocked,
});
clearMobileCenterCountryHighlight();
职责:
- 判断是否处于移动端。
- 判断国界图层是否开启。
- 判断当前是否被移动端前景 UI 阻塞。
- 对 renderer canvas 中心点做 raycast。
- 命中地球后转经纬度。
- 调用
updateCountryBoundaryHover({ lat, lon })。 - 无命中或禁用时调用
clearCountryBoundaryHover()。
2. Use canvas center, not window center
中心点应基于 renderer canvas rect 计算:
const rect = renderer.domElement.getBoundingClientRect();
const clientX = rect.left + rect.width / 2;
const clientY = rect.top + rect.height / 2;
这样在移动端安全区、地址栏变化、viewport resize 或 canvas 非全屏时仍然准确。
3. Convert center point into country hover coords
复用已有工具:
const point = screenToEarthCoords(clientX, clientY, camera, earth, renderer.domElement);
if (!point) {
clearCountryBoundaryHover();
return;
}
const coords = vector3ToLatLon(point);
updateCountryBoundaryHover(coords);
注意:screenToEarthCoords 返回的是 earth local point,符合 vector3ToLatLon 的输入语义。
4. Gate updates by mobile and foreground UI state
建议新增一个本地判断函数:
function isMobileCenterCountryHighlightBlocked() {
return (
!document.body.classList.contains("layout-mode-mobile") ||
document.body.classList.contains("earth-search-open") ||
document.body.classList.contains("earth-settings-open") ||
document.body.classList.contains("earth-media-open") ||
document.body.classList.contains("earth-info-open")
);
}
如果移动端抽屉只是半收起、且没有覆盖中心视野,可以继续允许中心高亮。若实际体验里抽屉展开会遮挡中心点,再把 drawer open 状态纳入阻塞条件。
5. Throttle and cache center updates
GeoJSON polygon 命中不应该无条件每帧执行。
第一版建议:
throttleMs = 120- 缓存上次经纬度,中心点变化小于
0.05度时跳过。 - 禁用、切回桌面、图层关闭、UI 阻塞时立即清除一次高亮。
伪代码:
if (now - lastUpdateAt < 120) return;
if (Math.abs(coords.lat - lastLat) < 0.05 && Math.abs(coords.lon - lastLon) < 0.05) return;
6. Wire into the Earth animation loop
在 frontend/public/earth/js/main.js 的动画循环中调用:
updateMobileCenterCountryHighlight({
camera,
earth,
renderer,
now: performance.now(),
isBlocked: isMobileCenterCountryHighlightBlocked(),
});
这样自动旋转、手势旋转、缩放和巡航都会自然更新。
7. Keep desktop hover unchanged
桌面 pointer hover 仍然走当前逻辑。
移动端中心高亮只在 layout-mode-mobile 下生效,不应该监听 pointer move,也不应该抢占 desktop hover 状态。
8. Optional visual tuning
第一版复用:
COUNTRY_BOUNDARY_CONFIG.hoverLineColorCOUNTRY_BOUNDARY_CONFIG.hoverLineOpacityCOUNTRY_BOUNDARY_CONFIG.hoverGlowOpacity
如果移动端体验太强,可以后续加独立配置:
mobileCenterHoverLineOpacity
mobileCenterHoverGlowOpacity
但第一版不建议过早分叉样式。
Verification
Static checks
npm前端构建或现有 lint/typecheck 命令通过。rg确认新增函数只在移动端路径调用,不影响桌面 pointer hover。git diff --stat和目标文件 diff 确认改动范围集中。
Manual mobile checks
使用移动端 viewport,例如 390x844:
- 打开 Earth。
- 开启国界图层。
- 转动地球到中国、美国、澳大利亚等大块陆地区域,确认中心国家国界高亮。
- 转动到太平洋或印度洋,确认高亮消失。
- 缩放地球,确认高亮仍跟随中心点。
- 打开移动端搜索、设置、媒体或详情面板,确认没有明显误高亮或抖动。
- 切回桌面 viewport,确认 hover 仍由鼠标位置控制。
Playwright smoke check
如果已有 Playwright 流程,建议补一个移动端 smoke:
- 设置 viewport 为手机尺寸。
- 打开 Earth 页面。
- 开启国界图层。
- 等待国界数据加载。
- 截图确认中心附近国家边界有 hover 高亮线。
这个 smoke 不必断言具体国家名称,因为当前功能核心是视觉高亮;更稳定的自动化可以后续通过暴露 debug state 实现。
Risks and mitigations
Polygon hit cost too高
风险:移动端设备上频繁 featureContains 可能带来卡顿。
缓解:
- 使用
120ms节流。 - 经纬度变化小于阈值时跳过。
- 后续如仍慢,再为 GeoJSON features 预计算 bbox,先 bbox 粗筛再 point-in-polygon。
UI blocking state 不完整
风险:某些移动端前景 UI 没有对应 body class,中心点被遮挡但高亮仍更新。
缓解:
- 第一版覆盖现有主要 class。
- 验证时记录遗漏项,补充到
isMobileCenterCountryHighlightBlocked()。
Desktop hover 被移动端状态污染
风险:移动端中心高亮和桌面 hover 共用 _hoveredFeature 状态。
缓解:
- 只在
layout-mode-mobile下运行中心高亮。 - 切出 mobile 或图层关闭时调用一次
clearCountryBoundaryHover()。 - 不改
updateCountryBoundaryHover()的语义。
Milestones
- 设计落地:完成本 plan,明确目标和验收标准。
- 最小实现:新增移动端中心取点 controller,并接入 animation loop。
- 性能保护:加入节流、经纬度阈值和禁用态清理。
- 验证:本地构建通过,移动端 viewport 手动检查通过。
- 调优:根据截图或真机体验微调阻塞条件和节流阈值。