> ## Documentation Index
> Fetch the complete documentation index at: https://www.worldmonitor.app/docs/llms.txt
> Use this file to discover all available pages before exploring further.

# 实时系统、地图与性能

> AIS 中继背压、ONNX 能力检测、地图叠加层、条件数据加载、Web Worker 分析、虚拟滚动、跨模块数据流以及 World Monitor 使用的刷新间隔，说明实时数据如何在浏览器中保持流畅且不过载，面向评估平台的工程师与希望参与贡献的开发者阅读。

本页属于[设计哲学](https://www.worldmonitor.app/docs/zh/architecture.md)指南，该页索引全部主题。部署拓扑、目录结构与 CI/CD 请参阅 [`ARCHITECTURE.md`](https://github.com/koala73/worldmonitor/blob/main/ARCHITECTURE.md)。

***

## 实时系统

### AIS 中继背压架构

AIS 船舶追踪中继维护到 AISStream.io 的持久 WebSocket 连接，在高峰海运流量时每秒可投递数百条位置报告。如果没有流控，慢消费者（例如网络状况差的客户端）会导致中继消息队列的无界内存增长。

中继实现了**三水位背压系统**：

| 水位 | 阈值 | 行为 |
| - | - | - |
| **低** | 1,000 条消息 | 正常运行 — 所有消息入队 |
| **高** | 4,000 条消息 | 警告状态 — 驱逐最旧消息腾出空间 |
| **硬上限** | 8,000 条消息 | 溢出 — 丢弃新消息直到队列排至高水位以下 |

此外，中继将追踪船舶总数上限设为 20,000 个位置（每个 MMSI 的最新位置）。辅助**密度单元**系统将位置聚合到 2°×2° 地理网格单元（最多 5,000 个单元）中，在完整船舶列表超出渲染能力时提供概览可视化。

船舶历史轨迹上限为每船 30 个位置点。新位置到达时，最旧轨迹点被驱逐。这创建了"彗尾"可视化，展示近期移动方向而无无界内存增长。

中继还在前端和中继服务器之间实现 HMAC 认证，防止未授权客户端消费昂贵的 AIS 数据流。

### ONNX Runtime 能力检测

浏览器端 ML 管道（嵌入、NER、情感、摘要）使用 ONNX Runtime Web 进行推理。模型执行速度因浏览器和设备及可用硬件加速而异。

系统在初始化时使用级联能力检测策略：

```
WebGPU (fastest)  →  WebGL (fast)  →  WASM + SIMD (baseline)
```

1. **WebGPU** — 通过 `navigator.gpu` 存在性检测。提供 GPU 加速推理，延迟最低。Chrome 113+ 和 Edge 113+ 可用
2. **WebGL** — WebGPU 不可用时的回退。通过 WebGL 计算着色器使用现有 GPU。所有现代浏览器可用
3. **WASM + SIMD** — 仅 CPU 回退。探测 `SharedArrayBuffer` 和 WASM SIMD 可用性。SIMD 对向量操作比普通 WASM 快约 2–4 倍

`deviceMemory` API 守卫在低内存设备（RAM \<4GB 的手机）上完全排除 ML 管道，防止加载 384 维 float32 嵌入模型与地图渲染器和实时视频流并发时的内存溢出崩溃。

***

## 地图与可视化

### 地缘政治边界叠加

地图支持带关联元数据的类型化地缘政治边界多边形。每个边界携带一个 `boundaryType` 判别字段（`demilitarized`、`ceasefire`、`disputed`、`armistice`），控制渲染样式和弹窗内容。

**朝鲜非军事区** — 第一个实现的边界是朝鲜非军事区，定义为源自 OpenStreetMap Way 369265305 和《朝鲜停战协定》第一条分界线的 43 点闭合环多边形。在平面地图上，它以 `GeoJsonLayer` 渲染，带半透明蓝色填充和带标签的工具提示。在 3D 地球仪上，它作为冲突图层下的 `polygonsData` 渲染。该边界有专门的帮助条目和图层开关，仅默认在 `full` 变体上启用。

边界系统设计为可扩展 — 额外的地缘政治边界（克什米尔实际控制线、戈兰高地、北塞浦路斯绿线）可添加到 `GEOPOLITICAL_BOUNDARIES` 常量并配以适当类型，将自动在两种地图引擎上渲染。

### CII 等值线热力图

国家不稳定性指数可在两种地图引擎上投影为全覆盖等值线图层，根据每个国家的实时 CII 评分（0–100）以五段色阶为每个国家多边形着色：

| 评分范围 | 等级 | 颜色 |
| - | - | - |
| 0–30 | 低 | 绿色 |
| 31–50 | 正常 | 黄色 |
| 51–65 | 升高 | 橙色 |
| 66–80 | 高 | 红色 |
| 81–100 | 关键 | 深红 |

在**平面地图**（deck.gl）上，`GeoJsonLayer` 通过 `getLevel()` 阈值函数将 ISO 3166-1 alpha-2 国家代码映射为固定 RGBA 值。更新由单调版本计数器（`ciiScoresVersion`）触发 — 图层在每次渲染传递时比较计数器，仅在其递增时重新计算填充色，避免 O(n) 数据展开。

在 **3D 地球仪**（globe.gl）上，CII 国家多边形与地缘政治边界合并到同一个 `polygonsData` 数组中。每个多边形对象中的 `_kind` 判别字段（`'boundary' | 'cii'`）让单个 `.polygonCapColor()` 回调为两种类型分发渲染逻辑。CII 多边形以 `polygonAltitude: 0.002` 渲染（低于冲突区轮廓使用的 `0.006` 高度），防止视觉 Z-fighting。

国家 GeoJSON 从共享的 `getCountriesGeoJson()` 函数惰性加载，首次抓取后缓存，并在 CII 图层和国家检测射线投射服务间共享。

### 统一图层开关目录

所有地图图层开关定义 — 图标、本地化键、回退显示标签和支持的渲染器类型 — 合并到单一共享注册表（`src/config/map-layer-definitions.ts`）。每个条目通过 `renderers: MapRenderer[]` 字段声明其支持的地图渲染器（例如，`dayNight` 仅平面，`ciiChoropleth` 平面和地球仪均支持），防止两个地图组件显示不一致的图层选项。

`def()` 工厂函数减少了每条目的样板代码。变体特定的图层排序（`VARIANT_LAYER_ORDER`）为六个仪表盘变体定义显示顺序，而无需重复定义本身。添加新地图图层只需一条注册表条目 — 平面地图和 3D 地球仪均自动从此目录派生其开关面板。

同一注册表还承载了高采用率图层的 v1 图层说明目录。每个精选说明记录用途、提供商/来源、新鲜度预期、置信度说明、限制、相关面板/操作和接地路径；不支持的图层有意回退到通用卡片，使 UI 永不暗示虚构的新鲜度或置信度值。

***

## 条件数据加载

API 调用成本高昂。系统仅对**已启用图层**抓取数据，减少不必要的网络流量和速率限制消耗。

### 图层感知加载

当图层关闭时：

* 不对该数据源进行 API 调用
* 不调度刷新间隔
* WebSocket 连接关闭（AIS）

当图层开启时：

* 立即抓取数据
* 开始刷新间隔
* 切换按钮上显示加载指示器

### 未配置服务

某些数据源需要 API 密钥（AIS 中继、Cloudflare Radar）。如果未配置凭证：

* 图层开关完全隐藏
* 无失败请求污染控制台
* 用户只看到可用的图层

这在未配置完整 API 访问权限部署时防止混淆。

***

## 性能优化

仪表盘实时处理数千数据点。多种技术保持 UI 在重数据负载下仍响应。

### 用于分析的 Web Worker

CPU 密集操作在专用 Web Worker 中运行以避免阻塞主线程：

| 操作 | 复杂度 | Worker？ |
| - | - | - |
| 新闻聚类（Jaccard） | O(n²) | 是 |
| 关联检测 | O(n × m) | 是 |
| DOM 渲染 | O(n) | 主线程 |

Worker 管理器实现：

* **惰性初始化**：首次使用时生成 Worker
* **10 秒就绪超时**：Worker 初始化失败则拒绝
* **30 秒请求超时**：防止卡住操作挂起
* **自动清理**：致命错误时终止 Worker

### 虚拟滚动

大型列表（100+ 新闻条目）使用虚拟化渲染：

**固定高度模式**（VirtualList）：

* 仅渲染视口中可见条目 + 3 条目 overscan 缓冲
* 元素池化 — 复用 DOM 节点而非创建新节点
* 不可见占位器维持滚动位置而无需渲染所有条目

**可变高度模式**（WindowedList）：

* 基于分块的渲染（每块 10 条目）
* 滚动时渲染分块，带 1 分块缓冲
* CSS containment 用于性能隔离

这将 DOM 节点数从数千减少到约 30，显著提升滚动性能。

### 请求去重

短窗口内的相同请求被去重：

* 行情报价将多个标的代码批量到单次 API 调用
* 并发图层切换不会产生重复抓取
* `Promise.allSettled` 确保一个失败请求不会阻塞其他

### 高效数据更新

刷新数据时：

* **增量更新**：仅变化条目触发重新渲染
* **过期同时重新验证**：抓取完成前显示旧数据
* **增量压缩**：基线存储 7 天/30 天增量，而非原始历史

***

## 跨模块集成

情报模块不孤立运行。数据在系统间流动以实现复合分析。

### 数据流架构

```
News Feeds → Clustering → Velocity Analysis → Hotspot Correlation
                ↓                                    ↓
         Topic Extraction                    CII Information Score
                ↓                                    ↓
         Keyword Monitors              Strategic Risk Overview
                                                     ↑
Military Flights → Near-Hotspot Detection ──────────┤
                                                     ↑
AIS Vessels → Chokepoint Monitoring ────────────────┤
                                                     ↑
ACLED/GDELT → Protest Events ───────────────────────┤
                       ↓
                CII Unrest Score
```

### 模块依赖

| 消费模块 | 数据来源 | 集成 |
| - | - | - |
| **CII 动荡评分** | ACLED、GDELT 抗议 | 事件计数、伤亡 |
| **CII 安全评分** | 军事航班、船舶 | 热点附近活动 |
| **CII 信息评分** | 新闻聚类 | 速率、关键词匹配 |
| **战略风险** | CII、收敛性、级联 | 复合评分 |
| **相关资产** | 新闻位置推断 | 管道/电缆邻近度 |
| **地理收敛** | 所有地理定位事件 | 多类型聚类 |

### 告警传播

当阈值被跨越时：

1. **来源模块** 生成告警（例如 CII 激增）
2. **告警合并** 与相关告警（相同国家/地区）
3. **战略风险** 接收复合告警
4. **UI 更新** 标题栏徽章和面板指示器

这确保单一升级（例如乌克兰军事航班 + 抗议 + 新闻激增）作为一个连贯信号呈现，而非三个独立告警。

***

## 刷新间隔

不同数据源基于波动性和 API 约束以不同频率更新。

### 轮询计划

| 数据类型 | 间隔 | 理由 |
| - | - | - |
| **新闻订阅源** | 5 分钟 | 平衡新鲜度与速率限制 |
| **股票报价** | 1 分钟 | 市场时段需近实时 |
| **加密价格** | 1 分钟 | 24/7 市场，高波动 |
| **预测** | 5 分钟 | 概率缓慢变化 |
| **地震** | 5 分钟 | USGS 每 5 分钟更新 |
| **天气警报** | 10 分钟 | NWS 警报频率 |
| **航班延误** | 10 分钟 | FAA 状态更新节奏 |
| **互联网中断** | 60 分钟 | BGP 事件罕见 |
| **经济数据** | 30 分钟 | FRED 数据日内很少变化 |
| **军事追踪** | 5 分钟 | 活动模式需及时更新 |
| **PizzINT** | 10 分钟 | 客流变化缓慢 |

### 实时流

AIS 船舶追踪使用 WebSocket 实现真正实时：

* **连接**：到 Railway 中继的持久 WebSocket
* **消息**：船舶发射时的位置更新
* **重连**：自动配合指数退避（5s → 10s → 20s）

### 用户控制

时间范围选择器影响显示数据，不影响抓取频率：

| 选择 | 效果 |
| - | - |
| **1 小时** | 仅显示过去 60 分钟事件 |
| **6 小时** | 显示过去 6 小时事件 |
| **24 小时** | 显示过去一天事件 |
| **7 天** | 显示所有近期事件 |

历史筛选在客户端 — 所有数据均已抓取，仅用于显示筛选。


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.