@caoguo/maplibre-pipeline 0.0.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/burst/index.cjs +708 -0
- package/dist/burst/index.cjs.map +1 -0
- package/dist/burst/index.d.cts +74 -0
- package/dist/burst/index.d.ts +74 -0
- package/dist/burst/index.js +4 -0
- package/dist/burst/index.js.map +1 -0
- package/dist/burstClass-CGMjcAYy.d.cts +161 -0
- package/dist/burstClass-Cf2p71LE.d.ts +161 -0
- package/dist/chunk-CDEYJ67B.js +80 -0
- package/dist/chunk-CDEYJ67B.js.map +1 -0
- package/dist/chunk-GCDA7KJM.js +289 -0
- package/dist/chunk-GCDA7KJM.js.map +1 -0
- package/dist/chunk-GEJRE2OR.js +351 -0
- package/dist/chunk-GEJRE2OR.js.map +1 -0
- package/dist/chunk-HCT6NSNS.js +532 -0
- package/dist/chunk-HCT6NSNS.js.map +1 -0
- package/dist/chunk-HIRNJVCV.js +13 -0
- package/dist/chunk-HIRNJVCV.js.map +1 -0
- package/dist/chunk-J3AEVXT4.js +164 -0
- package/dist/chunk-J3AEVXT4.js.map +1 -0
- package/dist/chunk-QVY4WJLM.js +256 -0
- package/dist/chunk-QVY4WJLM.js.map +1 -0
- package/dist/chunk-VA2TQWL3.js +340 -0
- package/dist/chunk-VA2TQWL3.js.map +1 -0
- package/dist/chunk-YBLESEN4.js +133 -0
- package/dist/chunk-YBLESEN4.js.map +1 -0
- package/dist/chunk-YS2ICFVK.js +101 -0
- package/dist/chunk-YS2ICFVK.js.map +1 -0
- package/dist/graph/index.cjs +382 -0
- package/dist/graph/index.cjs.map +1 -0
- package/dist/graph/index.d.cts +211 -0
- package/dist/graph/index.d.ts +211 -0
- package/dist/graph/index.js +4 -0
- package/dist/graph/index.js.map +1 -0
- package/dist/health/index.cjs +348 -0
- package/dist/health/index.cjs.map +1 -0
- package/dist/health/index.d.cts +210 -0
- package/dist/health/index.d.ts +210 -0
- package/dist/health/index.js +3 -0
- package/dist/health/index.js.map +1 -0
- package/dist/index.cjs +2295 -0
- package/dist/index.cjs.map +1 -0
- package/dist/index.d.cts +10 -0
- package/dist/index.d.ts +10 -0
- package/dist/index.js +12 -0
- package/dist/index.js.map +1 -0
- package/dist/leakage/index.cjs +358 -0
- package/dist/leakage/index.cjs.map +1 -0
- package/dist/leakage/index.d.cts +212 -0
- package/dist/leakage/index.d.ts +212 -0
- package/dist/leakage/index.js +3 -0
- package/dist/leakage/index.js.map +1 -0
- package/dist/nlpg/index.cjs +136 -0
- package/dist/nlpg/index.cjs.map +1 -0
- package/dist/nlpg/index.d.cts +51 -0
- package/dist/nlpg/index.d.ts +51 -0
- package/dist/nlpg/index.js +3 -0
- package/dist/nlpg/index.js.map +1 -0
- package/dist/style/index.cjs +379 -0
- package/dist/style/index.cjs.map +1 -0
- package/dist/style/index.d.cts +119 -0
- package/dist/style/index.d.ts +119 -0
- package/dist/style/index.js +4 -0
- package/dist/style/index.js.map +1 -0
- package/dist/topology/index.cjs +317 -0
- package/dist/topology/index.cjs.map +1 -0
- package/dist/topology/index.d.cts +69 -0
- package/dist/topology/index.d.ts +69 -0
- package/dist/topology/index.js +4 -0
- package/dist/topology/index.js.map +1 -0
- package/dist/types/index.cjs +15 -0
- package/dist/types/index.cjs.map +1 -0
- package/dist/types/index.d.cts +214 -0
- package/dist/types/index.d.ts +214 -0
- package/dist/types/index.js +3 -0
- package/dist/types/index.js.map +1 -0
- package/package.json +81 -0
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/types/index.ts"],"names":[],"mappings":";AA0BO,IAAM,cAAA,GAA0C;AAAA,EACrD,KAAA;AAAA,EACA,OAAA;AAAA,EACA,UAAA;AAAA,EACA,SAAA;AAAA,EACA,OAAA;AAAA,EACA;AACF","file":"chunk-HIRNJVCV.js","sourcesContent":["/**\n * 草果地图管网组件包 - 类型定义\n *\n * 地下管网 MVP 数据模型:\n * - 节点(Node):管段的交汇点/设备点(阀门/泵/表/源头)\n * - 管段(Pipe/Edge):连接两个节点的物理管线\n * - 用户(User):连接到节点的消费方(居民/商业/工业)\n *\n * 拓扑数据结构参见 PRD phase-1-pipeline §4.1.2\n */\n\n// ============================================================\n// 一、管线类型(基础设施大类)\n// ============================================================\n/**\n * 管网大类\n * - gas:燃气\n * - water:供水\n * - drainage:排水\n * - heating:供热\n * - power:电力(管沟)\n * - telecom:通信(管沟)\n */\nexport type PipelineType = 'gas' | 'water' | 'drainage' | 'heating' | 'power' | 'telecom';\n\n/** 所有支持的管线大类(便于运行时校验) */\nexport const PIPELINE_TYPES: readonly PipelineType[] = [\n 'gas',\n 'water',\n 'drainage',\n 'heating',\n 'power',\n 'telecom',\n] as const;\n\n// ============================================================\n// 二、节点(Node)\n// ============================================================\n/**\n * 节点类型\n * - junction:普通连接点(三通/四通/弯头等)\n * - valve:阀门(可关闭以隔离故障段)\n * - pump:泵站(供水加压/供热循环)\n * - meter:计量表/用户表\n * - source:源头(制水厂/燃气门站/热源厂)\n * - tank:储水罐/储气罐\n * - junction_box:电缆/光缆接线井\n */\nexport type NodeKind =\n | 'junction'\n | 'valve'\n | 'pump'\n | 'meter'\n | 'source'\n | 'tank'\n | 'junction_box';\n\n/** 阀门子类型 */\nexport type ValveType = 'gate' | 'butterfly' | 'check' | 'pressure_reduction' | 'control';\n\n/** 阀门状态(用于爆管推演隔离方案) */\nexport type ValveStatus = 'open' | 'closed' | 'partial';\n\n// ============================================================\n// 三、管段(Pipe/Edge)\n// ============================================================\n/**\n * 管段材质\n * - cast_iron:铸铁(旧管网主力)\n * - ductile_iron:球墨铸铁(当前主流)\n * - steel:钢管(高压/燃气主干)\n * - pe:聚乙烯(PE,现代供水/燃气)\n * - pvc:聚氯乙烯(PVC,排水)\n * - concrete:混凝土(排水/给水主干)\n * - hdpe:高密度聚乙烯\n * - copper:铜管(室内引入管)\n * - unknown:未知\n */\nexport type PipeMaterial =\n | 'cast_iron'\n | 'ductile_iron'\n | 'steel'\n | 'pe'\n | 'pvc'\n | 'concrete'\n | 'hdpe'\n | 'copper'\n | 'unknown';\n\n/**\n * 管段状态\n * - normal:正常运行\n * - aging:老化(建议关注)\n * - damaged:损坏(泄漏/破裂)\n * - under_repair:维修中(部分阀门/路段暂停使用)\n * - abandoned:废弃\n * - unknown:未知\n */\nexport type PipeStatus =\n | 'normal'\n | 'aging'\n | 'damaged'\n | 'under_repair'\n | 'abandoned'\n | 'unknown';\n\n// ============================================================\n// 四、设备附加属性(管段 / 节点公用扩展)\n// ============================================================\nexport interface PipeProperties {\n /** 公称直径(mm),如 DN150 = 150 */\n diameter?: number;\n /** 管材 */\n material?: PipeMaterial;\n /** 安装日期(ISO 字符串) */\n installDate?: string;\n /** 工作压力(MPa) */\n pressure?: number;\n /** 最高允许压力(MPa) */\n ratedPressure?: number;\n /** 当前状态 */\n status?: PipeStatus;\n /** 埋深(m) */\n depth?: number;\n /** 建设单位 */\n owner?: string;\n /** 自由扩展(运维记录/检测报告 URL 等) */\n extra?: Record<string, unknown>;\n}\n\nexport interface NodeProperties {\n /** 设备编号 */\n code?: string;\n /** 阀门类型(仅 valve) */\n valveType?: ValveType;\n /** 阀门状态(仅 valve) */\n valveStatus?: ValveStatus;\n /** 流量/供气能力(m³/h,仅 source/pump) */\n capacity?: number;\n /** 安装日期 */\n installDate?: string;\n /** 产权单位 */\n owner?: string;\n /** 海拔(m,用于地形修正) */\n elevation?: number;\n /** 自由扩展 */\n extra?: Record<string, unknown>;\n}\n\n// ============================================================\n// 五、节点(Node)\n// ============================================================\n/**\n * 管网节点\n * position 为 [lng, lat](GeoJSON 习惯),不是 [lat, lng]\n */\nexport interface PipelineNode {\n id: string;\n /** 节点类型 */\n kind: NodeKind;\n /** 经度(WGS84) */\n lng: number;\n /** 纬度(WGS84) */\n lat: number;\n /** 所属管线大类(燃气/供水等) */\n pipelineType?: PipelineType;\n /** 行政区/区域(用于层级钻取) */\n region?: string;\n /** 自定义属性 */\n properties?: NodeProperties;\n}\n\n// ============================================================\n// 六、管段(Pipe/Edge)\n// ============================================================\n/**\n * 管网管段\n * from_node / to_node 是有向连接,但物理上双向导通。\n * 地理 LineString 用 [[lng,lat], ...] 表示。\n */\nexport interface PipelinePipe {\n id: string;\n /** 起点节点 id */\n fromNode: string;\n /** 终点节点 id */\n toNode: string;\n /** 管段类型,固定为 'pipe'(预留扩展如 'channel'/'duct') */\n type: 'pipe';\n /** 所属管线大类 */\n pipelineType?: PipelineType;\n /** 区域编码(用于 LOD 按需加载) */\n region?: string;\n /** 几何(可选,未提供时按 from/to 拉直线) */\n geometry?: [number, number][];\n /** 长度(m),可选,由 geometry 计算 */\n length?: number;\n /** 管段属性 */\n properties?: PipeProperties;\n}\n\n// ============================================================\n// 七、用户/建筑(爆管推演影响分析用)\n// ============================================================\n/**\n * 用户类型\n * - residential:居民\n * - commercial:商业\n * - industrial:工业\n * - important:重要用户(医院/学校/政府部门/消防)\n */\nexport type UserKind = 'residential' | 'commercial' | 'industrial' | 'important';\n\nexport interface PipelineUser {\n id: string;\n /** 用户名 */\n name?: string;\n /** 类型 */\n kind: UserKind;\n /** 所属节点 id(直接或间接连接) */\n nodeId?: string;\n /** 位置 */\n lng: number;\n lat: number;\n /** 区域 */\n region?: string;\n /** 人口/用量(可选) */\n scale?: number;\n /** 备注 */\n note?: string;\n}\n\n// ============================================================\n// 八、完整管网拓扑\n// ============================================================\n/**\n * 管网拓扑数据集(完整 MVP 输入)\n * - nodes:节点列表\n * - pipes:管段列表\n * - users:用户列表(可选,爆管推演需要)\n */\nexport interface PipelineTopologyDataset {\n nodes: PipelineNode[];\n pipes: PipelinePipe[];\n users?: PipelineUser[];\n}\n\n// ============================================================\n// 九、事件载荷(包内统一事件类型)\n// ============================================================\n/** 选中节点 */\nexport interface NodeSelectEvent {\n node: PipelineNode;\n /** 在鼠标事件中的屏幕坐标(可选) */\n point?: { x: number; y: number };\n}\n\n/** 选中管段 */\nexport interface PipeSelectEvent {\n pipe: PipelinePipe;\n point?: { x: number; y: number };\n}\n\n/** 钻取事件(区域层级下钻) */\nexport interface DrillDownEvent {\n /** 上一级区域 */\n from: string | null;\n /** 目标区域 */\n to: string;\n}\n\n// ============================================================\n// 十、可视化着色规则(caoguo-pipeline 主题)\n// ============================================================\n/**\n * 着色模式(管线渲染)\n * - type:按管线大类着色(燃气黄/供水蓝等)\n * - diameter:按管径着色(PRD §4.1.4)\n * - status:按管段状态着色\n * - material:按管材着色\n * - health:按健康度着色(PipelineHealth 集成)\n * - uniform:单一颜色\n */\nexport type ColorByMode =\n | 'type'\n | 'diameter'\n | 'status'\n | 'material'\n | 'health'\n | 'uniform';\n"]}
|
|
@@ -0,0 +1,164 @@
|
|
|
1
|
+
import { paintPipeBy } from './chunk-QVY4WJLM.js';
|
|
2
|
+
|
|
3
|
+
// src/topology/PipelineTopology.ts
|
|
4
|
+
var PipelineTopology = class {
|
|
5
|
+
map;
|
|
6
|
+
dataset;
|
|
7
|
+
colorBy;
|
|
8
|
+
layerPrefix;
|
|
9
|
+
pipelineTypes;
|
|
10
|
+
layerIds = [];
|
|
11
|
+
nodeListeners = /* @__PURE__ */ new Set();
|
|
12
|
+
pipeListeners = /* @__PURE__ */ new Set();
|
|
13
|
+
drillListeners = /* @__PURE__ */ new Set();
|
|
14
|
+
constructor(options) {
|
|
15
|
+
this.map = options.map;
|
|
16
|
+
this.dataset = options.dataset;
|
|
17
|
+
this.colorBy = options.colorBy ?? "type";
|
|
18
|
+
this.pipelineTypes = options.pipelineTypes;
|
|
19
|
+
this.layerPrefix = options.layerPrefix ?? "cg-topo";
|
|
20
|
+
}
|
|
21
|
+
/** 渲染管段+节点到地图 */
|
|
22
|
+
render() {
|
|
23
|
+
this.clear();
|
|
24
|
+
const mlMap = this.map.instance;
|
|
25
|
+
const prefix = this.layerPrefix;
|
|
26
|
+
const pipeGeoJSON = {
|
|
27
|
+
type: "FeatureCollection",
|
|
28
|
+
features: this.dataset.pipes.filter((p) => {
|
|
29
|
+
if (this.pipelineTypes?.length && !this.pipelineTypes.includes(p.pipelineType)) {
|
|
30
|
+
return false;
|
|
31
|
+
}
|
|
32
|
+
return true;
|
|
33
|
+
}).flatMap((p) => {
|
|
34
|
+
const from = this.dataset.nodes.find((n) => n.id === p.fromNode);
|
|
35
|
+
const to = this.dataset.nodes.find((n) => n.id === p.toNode);
|
|
36
|
+
if (!from || !to) return [];
|
|
37
|
+
const coords = p.geometry && p.geometry.length >= 2 ? p.geometry : [
|
|
38
|
+
[from.lng, from.lat],
|
|
39
|
+
[to.lng, to.lat]
|
|
40
|
+
];
|
|
41
|
+
return [
|
|
42
|
+
{
|
|
43
|
+
type: "Feature",
|
|
44
|
+
geometry: { type: "LineString", coordinates: coords },
|
|
45
|
+
properties: {
|
|
46
|
+
pipeId: p.id,
|
|
47
|
+
pipelineType: p.pipelineType ?? "",
|
|
48
|
+
diameter: p.properties?.diameter ?? 0,
|
|
49
|
+
status: p.properties?.status ?? "unknown",
|
|
50
|
+
material: p.properties?.material ?? "unknown"
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
];
|
|
54
|
+
})
|
|
55
|
+
};
|
|
56
|
+
const nodeGeoJSON = {
|
|
57
|
+
type: "FeatureCollection",
|
|
58
|
+
features: this.dataset.nodes.filter((n) => {
|
|
59
|
+
if (this.pipelineTypes?.length && !this.pipelineTypes.includes(n.pipelineType)) {
|
|
60
|
+
return false;
|
|
61
|
+
}
|
|
62
|
+
return true;
|
|
63
|
+
}).map((n) => ({
|
|
64
|
+
type: "Feature",
|
|
65
|
+
geometry: { type: "Point", coordinates: [n.lng, n.lat] },
|
|
66
|
+
properties: { nodeId: n.id, kind: n.kind, pipelineType: n.pipelineType ?? "" }
|
|
67
|
+
}))
|
|
68
|
+
};
|
|
69
|
+
mlMap.addSource(`${prefix}-pipes-src`, pipeGeoJSON);
|
|
70
|
+
mlMap.addSource(`${prefix}-nodes-src`, nodeGeoJSON);
|
|
71
|
+
mlMap.addLayer({
|
|
72
|
+
id: `${prefix}-pipes-line`,
|
|
73
|
+
type: "line",
|
|
74
|
+
source: `${prefix}-pipes-src`,
|
|
75
|
+
paint: {
|
|
76
|
+
"line-color": paintPipeBy(this.colorBy, { types: this.pipelineTypes }),
|
|
77
|
+
"line-width": 2,
|
|
78
|
+
"line-opacity": 0.85
|
|
79
|
+
}
|
|
80
|
+
});
|
|
81
|
+
mlMap.addLayer({
|
|
82
|
+
id: `${prefix}-nodes-pt`,
|
|
83
|
+
type: "circle",
|
|
84
|
+
source: `${prefix}-nodes-src`,
|
|
85
|
+
paint: {
|
|
86
|
+
"circle-radius": 4,
|
|
87
|
+
"circle-color": "#f59e0b",
|
|
88
|
+
"circle-stroke-width": 1.5,
|
|
89
|
+
"circle-stroke-color": "#ffffff"
|
|
90
|
+
}
|
|
91
|
+
});
|
|
92
|
+
this.layerIds.push(`${prefix}-pipes-line`, `${prefix}-nodes-pt`);
|
|
93
|
+
}
|
|
94
|
+
/** 切换着色模式 */
|
|
95
|
+
setColorBy(mode) {
|
|
96
|
+
this.colorBy = mode;
|
|
97
|
+
const mlMap = this.map.instance;
|
|
98
|
+
if (mlMap.setPaintProperty) {
|
|
99
|
+
try {
|
|
100
|
+
mlMap.setPaintProperty(
|
|
101
|
+
`${this.layerPrefix}-pipes-line`,
|
|
102
|
+
"line-color",
|
|
103
|
+
paintPipeBy(mode, { types: this.pipelineTypes })
|
|
104
|
+
);
|
|
105
|
+
} catch {
|
|
106
|
+
}
|
|
107
|
+
}
|
|
108
|
+
}
|
|
109
|
+
/** 清空所有图层 */
|
|
110
|
+
clear() {
|
|
111
|
+
for (const id of this.layerIds) {
|
|
112
|
+
this.map.removeLayer(id);
|
|
113
|
+
}
|
|
114
|
+
this.layerIds = [];
|
|
115
|
+
}
|
|
116
|
+
/** 销毁组件 */
|
|
117
|
+
destroy() {
|
|
118
|
+
this.clear();
|
|
119
|
+
this.nodeListeners.clear();
|
|
120
|
+
this.pipeListeners.clear();
|
|
121
|
+
this.drillListeners.clear();
|
|
122
|
+
}
|
|
123
|
+
/** 订阅节点点击事件 */
|
|
124
|
+
onNodeSelect(fn) {
|
|
125
|
+
this.nodeListeners.add(fn);
|
|
126
|
+
return () => this.nodeListeners.delete(fn);
|
|
127
|
+
}
|
|
128
|
+
/** 订阅管段点击事件 */
|
|
129
|
+
onPipeSelect(fn) {
|
|
130
|
+
this.pipeListeners.add(fn);
|
|
131
|
+
return () => this.pipeListeners.delete(fn);
|
|
132
|
+
}
|
|
133
|
+
/** 订阅钻取事件 */
|
|
134
|
+
onDrillDown(fn) {
|
|
135
|
+
this.drillListeners.add(fn);
|
|
136
|
+
return () => this.drillListeners.delete(fn);
|
|
137
|
+
}
|
|
138
|
+
/** 高亮连通路径(基于节点 ID) */
|
|
139
|
+
highlightConnectivity(centerId) {
|
|
140
|
+
const adj = /* @__PURE__ */ new Map();
|
|
141
|
+
for (const p of this.dataset.pipes) {
|
|
142
|
+
if (!adj.has(p.fromNode)) adj.set(p.fromNode, /* @__PURE__ */ new Set());
|
|
143
|
+
if (!adj.has(p.toNode)) adj.set(p.toNode, /* @__PURE__ */ new Set());
|
|
144
|
+
adj.get(p.fromNode).add(p.toNode);
|
|
145
|
+
adj.get(p.toNode).add(p.fromNode);
|
|
146
|
+
}
|
|
147
|
+
const visited = /* @__PURE__ */ new Set();
|
|
148
|
+
const stack = [centerId];
|
|
149
|
+
while (stack.length > 0) {
|
|
150
|
+
const cur = stack.pop();
|
|
151
|
+
if (visited.has(cur)) continue;
|
|
152
|
+
visited.add(cur);
|
|
153
|
+
const neighbors = adj.get(cur) ?? /* @__PURE__ */ new Set();
|
|
154
|
+
for (const n of neighbors) {
|
|
155
|
+
if (!visited.has(n)) stack.push(n);
|
|
156
|
+
}
|
|
157
|
+
}
|
|
158
|
+
return visited;
|
|
159
|
+
}
|
|
160
|
+
};
|
|
161
|
+
|
|
162
|
+
export { PipelineTopology };
|
|
163
|
+
//# sourceMappingURL=chunk-J3AEVXT4.js.map
|
|
164
|
+
//# sourceMappingURL=chunk-J3AEVXT4.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/topology/PipelineTopology.ts"],"names":[],"mappings":"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","file":"chunk-J3AEVXT4.js","sourcesContent":["/**\n * PipelineTopology 类 - 占位(待 M4 W3-W4 实现)\n *\n * 本文件作为 Phase 1 管线拓扑编辑器的入口 stub,后续完整实现包含:\n * - 拓扑渲染(管段/节点按类型着色)\n * - 层级钻取(区域→街道→小区→楼栋)\n * - 设备卡片(点击节点/管段弹出属性面板)\n * - 连通性高亮(选中管线后高亮上下游)\n * - 搜索定位(按编号/地址/区域)\n * - 分层控制(按管径/材质/年代/状态)\n */\n\nimport type { Map as CaoguoMap } from '@caoguo/maplibre';\nimport type {\n PipelineTopologyDataset,\n ColorByMode,\n PipelineType,\n NodeSelectEvent,\n PipeSelectEvent,\n DrillDownEvent,\n} from '../types';\nimport { paintPipeBy } from '../style/paintRules';\n\nexport interface PipelineTopologyOptions {\n map: CaoguoMap;\n dataset: PipelineTopologyDataset;\n /** 默认着色模式 */\n colorBy?: ColorByMode;\n /** 仅显示指定管线类型(空 = 全显示) */\n pipelineTypes?: PipelineType[];\n /** 层 ID 前缀 */\n layerPrefix?: string;\n}\n\ntype NodeListener = (e: NodeSelectEvent) => void;\ntype PipeListener = (e: PipeSelectEvent) => void;\ntype DrillListener = (e: DrillDownEvent) => void;\n\n/**\n * PipelineTopology 组件(占位 stub)\n *\n * Phase 1 MVP 实现进度:\n * - [x] 渲染数据接入\n * - [ ] 层级钻取(M4 W3-W4 后续完善)\n * - [ ] 设备卡片(M4 W3-W4 后续完善)\n * - [ ] 连通性高亮(M5 W3-W4 后续完善)\n * - [ ] 搜索定位(M5 W3-W4 后续完善)\n * - [ ] 分层控制(M5 W3-W4 后续完善)\n */\nexport class PipelineTopology {\n private map: CaoguoMap;\n private dataset: PipelineTopologyDataset;\n private colorBy: ColorByMode;\n private layerPrefix: string;\n private pipelineTypes?: PipelineType[];\n private layerIds: string[] = [];\n private nodeListeners = new Set<NodeListener>();\n private pipeListeners = new Set<PipeListener>();\n private drillListeners = new Set<DrillListener>();\n\n constructor(options: PipelineTopologyOptions) {\n this.map = options.map;\n this.dataset = options.dataset;\n this.colorBy = options.colorBy ?? 'type';\n this.pipelineTypes = options.pipelineTypes;\n this.layerPrefix = options.layerPrefix ?? 'cg-topo';\n }\n\n /** 渲染管段+节点到地图 */\n render(): void {\n this.clear();\n const mlMap = (this.map as unknown as {\n instance: {\n addSource: (id: string, source: unknown) => void;\n addLayer: (layer: unknown) => void;\n getSource: (id: string) => unknown;\n };\n }).instance;\n const prefix = this.layerPrefix;\n\n const pipeGeoJSON: GeoJSON.FeatureCollection<GeoJSON.LineString> = {\n type: 'FeatureCollection',\n features: this.dataset.pipes\n .filter((p) => {\n if (this.pipelineTypes?.length && !this.pipelineTypes.includes(p.pipelineType as PipelineType)) {\n return false;\n }\n return true;\n })\n .flatMap((p) => {\n const from = this.dataset.nodes.find((n) => n.id === p.fromNode);\n const to = this.dataset.nodes.find((n) => n.id === p.toNode);\n if (!from || !to) return [];\n const coords: [number, number][] =\n p.geometry && p.geometry.length >= 2\n ? (p.geometry as [number, number][])\n : [\n [from.lng, from.lat],\n [to.lng, to.lat],\n ];\n return [\n {\n type: 'Feature' as const,\n geometry: { type: 'LineString' as const, coordinates: coords },\n properties: {\n pipeId: p.id,\n pipelineType: p.pipelineType ?? '',\n diameter: p.properties?.diameter ?? 0,\n status: p.properties?.status ?? 'unknown',\n material: p.properties?.material ?? 'unknown',\n },\n },\n ];\n }),\n };\n\n const nodeGeoJSON: GeoJSON.FeatureCollection<GeoJSON.Point> = {\n type: 'FeatureCollection',\n features: this.dataset.nodes\n .filter((n) => {\n if (this.pipelineTypes?.length && !this.pipelineTypes.includes(n.pipelineType as PipelineType)) {\n return false;\n }\n return true;\n })\n .map((n) => ({\n type: 'Feature' as const,\n geometry: { type: 'Point' as const, coordinates: [n.lng, n.lat] },\n properties: { nodeId: n.id, kind: n.kind, pipelineType: n.pipelineType ?? '' },\n })),\n };\n\n mlMap.addSource(`${prefix}-pipes-src`, pipeGeoJSON);\n mlMap.addSource(`${prefix}-nodes-src`, nodeGeoJSON);\n mlMap.addLayer({\n id: `${prefix}-pipes-line`,\n type: 'line',\n source: `${prefix}-pipes-src`,\n paint: {\n 'line-color': paintPipeBy(this.colorBy, { types: this.pipelineTypes }) as never,\n 'line-width': 2,\n 'line-opacity': 0.85,\n },\n });\n mlMap.addLayer({\n id: `${prefix}-nodes-pt`,\n type: 'circle',\n source: `${prefix}-nodes-src`,\n paint: {\n 'circle-radius': 4,\n 'circle-color': '#f59e0b',\n 'circle-stroke-width': 1.5,\n 'circle-stroke-color': '#ffffff',\n },\n });\n this.layerIds.push(`${prefix}-pipes-line`, `${prefix}-nodes-pt`);\n }\n\n /** 切换着色模式 */\n setColorBy(mode: ColorByMode): void {\n this.colorBy = mode;\n const mlMap = (this.map as unknown as {\n instance: { setPaintProperty: (id: string, prop: string, value: unknown) => void };\n }).instance;\n if (mlMap.setPaintProperty) {\n try {\n mlMap.setPaintProperty(\n `${this.layerPrefix}-pipes-line`,\n 'line-color',\n paintPipeBy(mode, { types: this.pipelineTypes }) as never\n );\n } catch {\n // ignore\n }\n }\n }\n\n /** 清空所有图层 */\n clear(): void {\n for (const id of this.layerIds) {\n this.map.removeLayer(id);\n }\n this.layerIds = [];\n }\n\n /** 销毁组件 */\n destroy(): void {\n this.clear();\n this.nodeListeners.clear();\n this.pipeListeners.clear();\n this.drillListeners.clear();\n }\n\n /** 订阅节点点击事件 */\n onNodeSelect(fn: NodeListener): () => void {\n this.nodeListeners.add(fn);\n return () => this.nodeListeners.delete(fn);\n }\n\n /** 订阅管段点击事件 */\n onPipeSelect(fn: PipeListener): () => void {\n this.pipeListeners.add(fn);\n return () => this.pipeListeners.delete(fn);\n }\n\n /** 订阅钻取事件 */\n onDrillDown(fn: DrillListener): () => void {\n this.drillListeners.add(fn);\n return () => this.drillListeners.delete(fn);\n }\n\n /** 高亮连通路径(基于节点 ID) */\n highlightConnectivity(centerId: string): Set<string> {\n const adj = new Map<string, Set<string>>();\n for (const p of this.dataset.pipes) {\n if (!adj.has(p.fromNode)) adj.set(p.fromNode, new Set());\n if (!adj.has(p.toNode)) adj.set(p.toNode, new Set());\n adj.get(p.fromNode)!.add(p.toNode);\n adj.get(p.toNode)!.add(p.fromNode);\n }\n\n const visited = new Set<string>();\n const stack = [centerId];\n while (stack.length > 0) {\n const cur = stack.pop()!;\n if (visited.has(cur)) continue;\n visited.add(cur);\n const neighbors = adj.get(cur) ?? new Set();\n for (const n of neighbors) {\n if (!visited.has(n)) stack.push(n);\n }\n }\n return visited;\n }\n}\n"]}
|
|
@@ -0,0 +1,256 @@
|
|
|
1
|
+
// src/style/pipelineTheme.ts
|
|
2
|
+
var PIPELINE_TYPE_COLORS = {
|
|
3
|
+
gas: "#f59e0b",
|
|
4
|
+
// 琥珀(燃气)
|
|
5
|
+
water: "#3b82f6",
|
|
6
|
+
// 蓝(供水)
|
|
7
|
+
drainage: "#6b7280",
|
|
8
|
+
// 灰(排水)
|
|
9
|
+
heating: "#ef4444",
|
|
10
|
+
// 红(供热)
|
|
11
|
+
power: "#8b5cf6",
|
|
12
|
+
// 紫(电力管沟)
|
|
13
|
+
telecom: "#10b981"
|
|
14
|
+
// 绿(通信管沟)
|
|
15
|
+
};
|
|
16
|
+
var PIPELINE_TYPE_LABELS = {
|
|
17
|
+
gas: "\u71C3\u6C14\u7BA1",
|
|
18
|
+
water: "\u4F9B\u6C34\u7BA1",
|
|
19
|
+
drainage: "\u6392\u6C34\u7BA1",
|
|
20
|
+
heating: "\u4F9B\u70ED\u7BA1",
|
|
21
|
+
power: "\u7535\u529B\u7BA1\u6C9F",
|
|
22
|
+
telecom: "\u901A\u4FE1\u7BA1\u6C9F"
|
|
23
|
+
};
|
|
24
|
+
var PIPELINE_TYPE_ICONS = {
|
|
25
|
+
gas: "\u{1F525}",
|
|
26
|
+
water: "\u{1F4A7}",
|
|
27
|
+
drainage: "\u{1F6B0}",
|
|
28
|
+
heating: "\u{1F534}",
|
|
29
|
+
power: "\u26A1",
|
|
30
|
+
telecom: "\u{1F4E1}"
|
|
31
|
+
};
|
|
32
|
+
var PIPE_STATUS_COLORS = {
|
|
33
|
+
normal: "#4ade80",
|
|
34
|
+
// 绿
|
|
35
|
+
aging: "#fbbf24",
|
|
36
|
+
// 黄
|
|
37
|
+
damaged: "#ef4444",
|
|
38
|
+
// 红
|
|
39
|
+
under_repair: "#8b5cf6",
|
|
40
|
+
// 紫
|
|
41
|
+
abandoned: "#4b5563",
|
|
42
|
+
// 深灰
|
|
43
|
+
unknown: "#6b7280"
|
|
44
|
+
// 灰
|
|
45
|
+
};
|
|
46
|
+
var PIPE_STATUS_META = {
|
|
47
|
+
normal: { label: "\u6B63\u5E38", animation: "none" },
|
|
48
|
+
aging: { label: "\u8001\u5316", animation: "none" },
|
|
49
|
+
damaged: { label: "\u635F\u574F", animation: "pulse" },
|
|
50
|
+
under_repair: { label: "\u7EF4\u4FEE\u4E2D", animation: "dashed" },
|
|
51
|
+
abandoned: { label: "\u5E9F\u5F03", animation: "none" },
|
|
52
|
+
unknown: { label: "\u672A\u77E5", animation: "none" }
|
|
53
|
+
};
|
|
54
|
+
var PIPE_MATERIAL_COLORS = {
|
|
55
|
+
cast_iron: "#94a3b8",
|
|
56
|
+
// 蓝灰(旧铸铁)
|
|
57
|
+
ductile_iron: "#0ea5e9",
|
|
58
|
+
// 天蓝(球墨铸铁)
|
|
59
|
+
steel: "#64748b",
|
|
60
|
+
// 钢蓝
|
|
61
|
+
pe: "#22c55e",
|
|
62
|
+
// 绿(PE 现代管材)
|
|
63
|
+
pvc: "#a78bfa",
|
|
64
|
+
// 紫(PVC)
|
|
65
|
+
concrete: "#a8a29e",
|
|
66
|
+
// 米灰(混凝土)
|
|
67
|
+
hdpe: "#16a34a",
|
|
68
|
+
// 深绿(HDPE)
|
|
69
|
+
copper: "#d97706",
|
|
70
|
+
// 橙(铜)
|
|
71
|
+
unknown: "#6b7280"
|
|
72
|
+
};
|
|
73
|
+
var NODE_KIND_ICONS = {
|
|
74
|
+
junction: "M -6 0 L 6 0 M 0 -6 L 0 6",
|
|
75
|
+
// 十字
|
|
76
|
+
valve: "M -8 -4 L 8 4 M 0 -4 L 0 4",
|
|
77
|
+
// X
|
|
78
|
+
pump: "M -6 0 A 6 6 0 1 0 6 0 A 6 6 0 1 0 -6 0",
|
|
79
|
+
// 圆
|
|
80
|
+
meter: "M -6 -6 L 6 -6 L 6 6 L -6 6 Z",
|
|
81
|
+
// 方
|
|
82
|
+
source: "M 0 -10 L 6 6 L -6 6 Z",
|
|
83
|
+
// 三角
|
|
84
|
+
tank: "M -8 -6 Q 0 -10 8 -6 L 8 6 L -8 6 Z",
|
|
85
|
+
// 圆角
|
|
86
|
+
junction_box: "M -7 -4 L 7 -4 L 7 4 L -7 4 Z"
|
|
87
|
+
// 小方
|
|
88
|
+
};
|
|
89
|
+
var NODE_KIND_COLORS = {
|
|
90
|
+
junction: "#94a3b8",
|
|
91
|
+
valve: "#ef4444",
|
|
92
|
+
// 阀门=红(控制关键)
|
|
93
|
+
pump: "#f59e0b",
|
|
94
|
+
meter: "#3b82f6",
|
|
95
|
+
source: "#22c55e",
|
|
96
|
+
tank: "#06b6d4",
|
|
97
|
+
junction_box: "#8b5cf6"
|
|
98
|
+
};
|
|
99
|
+
var HEALTH_LEVEL_COLORS = {
|
|
100
|
+
excellent: "#22c55e",
|
|
101
|
+
// 绿 80-100
|
|
102
|
+
good: "#3b82f6",
|
|
103
|
+
// 蓝 60-80
|
|
104
|
+
fair: "#eab308",
|
|
105
|
+
// 黄 40-60
|
|
106
|
+
poor: "#f97316",
|
|
107
|
+
// 橙 20-40
|
|
108
|
+
critical: "#ef4444"
|
|
109
|
+
// 红 0-20
|
|
110
|
+
};
|
|
111
|
+
var HEALTH_LEVEL_LABELS = {
|
|
112
|
+
excellent: "\u4F18",
|
|
113
|
+
good: "\u826F",
|
|
114
|
+
fair: "\u4E2D",
|
|
115
|
+
poor: "\u5DEE",
|
|
116
|
+
critical: "\u5371"
|
|
117
|
+
};
|
|
118
|
+
function healthLevel(score) {
|
|
119
|
+
if (score >= 80) return "excellent";
|
|
120
|
+
if (score >= 60) return "good";
|
|
121
|
+
if (score >= 40) return "fair";
|
|
122
|
+
if (score >= 20) return "poor";
|
|
123
|
+
return "critical";
|
|
124
|
+
}
|
|
125
|
+
function pipelineTypeColor(type) {
|
|
126
|
+
if (!type) return "#94a3b8";
|
|
127
|
+
return PIPELINE_TYPE_COLORS[type];
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
// src/style/paintRules.ts
|
|
131
|
+
function paintPipeByType(types) {
|
|
132
|
+
if (!types || types.length === 0) {
|
|
133
|
+
return [
|
|
134
|
+
"match",
|
|
135
|
+
["get", "pipelineType"],
|
|
136
|
+
...Object.entries(PIPELINE_TYPE_COLORS).flatMap(([k, v]) => [k, v]),
|
|
137
|
+
"#94a3b8"
|
|
138
|
+
];
|
|
139
|
+
}
|
|
140
|
+
return [
|
|
141
|
+
"match",
|
|
142
|
+
["get", "pipelineType"],
|
|
143
|
+
...types.flatMap((t) => [t, PIPELINE_TYPE_COLORS[t]]),
|
|
144
|
+
"#94a3b8"
|
|
145
|
+
];
|
|
146
|
+
}
|
|
147
|
+
function paintPipeByDiameter() {
|
|
148
|
+
return [
|
|
149
|
+
"interpolate",
|
|
150
|
+
["linear"],
|
|
151
|
+
["coalesce", ["get", "diameter"], 0],
|
|
152
|
+
0,
|
|
153
|
+
"#4ade80",
|
|
154
|
+
// 极细管 绿
|
|
155
|
+
50,
|
|
156
|
+
"#4ade80",
|
|
157
|
+
// DN50 以下 绿(支管)
|
|
158
|
+
150,
|
|
159
|
+
"#60a5fa",
|
|
160
|
+
// DN150 蓝(配水管)
|
|
161
|
+
300,
|
|
162
|
+
"#f59e0b",
|
|
163
|
+
// DN300 黄(干管)
|
|
164
|
+
600,
|
|
165
|
+
"#ef4444",
|
|
166
|
+
// DN600+ 红(主管)
|
|
167
|
+
1500,
|
|
168
|
+
"#7f1d1d"
|
|
169
|
+
// 极大管 深红
|
|
170
|
+
];
|
|
171
|
+
}
|
|
172
|
+
function paintPipeByStatus() {
|
|
173
|
+
return [
|
|
174
|
+
"match",
|
|
175
|
+
["coalesce", ["get", "status"], "unknown"],
|
|
176
|
+
...Object.entries(PIPE_STATUS_COLORS).flatMap(([k, v]) => [k, v]),
|
|
177
|
+
"#6b7280"
|
|
178
|
+
];
|
|
179
|
+
}
|
|
180
|
+
function paintPipeByMaterial() {
|
|
181
|
+
return [
|
|
182
|
+
"match",
|
|
183
|
+
["coalesce", ["get", "material"], "unknown"],
|
|
184
|
+
...Object.entries(PIPE_MATERIAL_COLORS).flatMap(([k, v]) => [k, v]),
|
|
185
|
+
"#6b7280"
|
|
186
|
+
];
|
|
187
|
+
}
|
|
188
|
+
function paintPipeByHealth() {
|
|
189
|
+
return [
|
|
190
|
+
"step",
|
|
191
|
+
["coalesce", ["get", "healthScore"], 100],
|
|
192
|
+
HEALTH_LEVEL_COLORS.critical,
|
|
193
|
+
// <20
|
|
194
|
+
20,
|
|
195
|
+
HEALTH_LEVEL_COLORS.poor,
|
|
196
|
+
40,
|
|
197
|
+
HEALTH_LEVEL_COLORS.fair,
|
|
198
|
+
60,
|
|
199
|
+
HEALTH_LEVEL_COLORS.good,
|
|
200
|
+
80,
|
|
201
|
+
HEALTH_LEVEL_COLORS.excellent
|
|
202
|
+
];
|
|
203
|
+
}
|
|
204
|
+
function paintPipeBy(mode, opts) {
|
|
205
|
+
switch (mode) {
|
|
206
|
+
case "type":
|
|
207
|
+
return paintPipeByType(opts?.types);
|
|
208
|
+
case "diameter":
|
|
209
|
+
return paintPipeByDiameter();
|
|
210
|
+
case "status":
|
|
211
|
+
return paintPipeByStatus();
|
|
212
|
+
case "material":
|
|
213
|
+
return paintPipeByMaterial();
|
|
214
|
+
case "health":
|
|
215
|
+
return paintPipeByHealth();
|
|
216
|
+
case "uniform":
|
|
217
|
+
default:
|
|
218
|
+
return "#60a5fa";
|
|
219
|
+
}
|
|
220
|
+
}
|
|
221
|
+
function paintNodeByKind() {
|
|
222
|
+
return [
|
|
223
|
+
"match",
|
|
224
|
+
["get", "kind"],
|
|
225
|
+
"junction",
|
|
226
|
+
"#94a3b8",
|
|
227
|
+
"valve",
|
|
228
|
+
"#ef4444",
|
|
229
|
+
"pump",
|
|
230
|
+
"#f59e0b",
|
|
231
|
+
"meter",
|
|
232
|
+
"#3b82f6",
|
|
233
|
+
"source",
|
|
234
|
+
"#22c55e",
|
|
235
|
+
"tank",
|
|
236
|
+
"#06b6d4",
|
|
237
|
+
"junction_box",
|
|
238
|
+
"#8b5cf6",
|
|
239
|
+
"#cbd5e1"
|
|
240
|
+
];
|
|
241
|
+
}
|
|
242
|
+
function paintPipeWidthByDiameter(minWidth = 1.5, maxWidth = 6) {
|
|
243
|
+
return [
|
|
244
|
+
"interpolate",
|
|
245
|
+
["linear"],
|
|
246
|
+
["coalesce", ["get", "diameter"], 100],
|
|
247
|
+
0,
|
|
248
|
+
minWidth,
|
|
249
|
+
1500,
|
|
250
|
+
maxWidth
|
|
251
|
+
];
|
|
252
|
+
}
|
|
253
|
+
|
|
254
|
+
export { HEALTH_LEVEL_COLORS, HEALTH_LEVEL_LABELS, NODE_KIND_COLORS, NODE_KIND_ICONS, PIPELINE_TYPE_COLORS, PIPELINE_TYPE_ICONS, PIPELINE_TYPE_LABELS, PIPE_MATERIAL_COLORS, PIPE_STATUS_COLORS, PIPE_STATUS_META, healthLevel, paintNodeByKind, paintPipeBy, paintPipeByDiameter, paintPipeByHealth, paintPipeByMaterial, paintPipeByStatus, paintPipeByType, paintPipeWidthByDiameter, pipelineTypeColor };
|
|
255
|
+
//# sourceMappingURL=chunk-QVY4WJLM.js.map
|
|
256
|
+
//# sourceMappingURL=chunk-QVY4WJLM.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/style/pipelineTheme.ts","../src/style/paintRules.ts"],"names":[],"mappings":"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","file":"chunk-QVY4WJLM.js","sourcesContent":["/**\n * 草果地图管网专用样式 - `caoguo-pipeline`\n *\n * 设计目标:\n * - 行业辨识度高:燃气=琥珀、供水=蓝、供热=红、电力=紫、通信=绿、排水=灰\n * - 状态语义强:正常/老化/损坏/维修中 各有专属色 + 动画\n * - 与 caoguo-dark/light 主题协调:在亮/暗模式下都可读\n *\n * 颜色规范依据 PRD §4.5。\n */\n\nimport type { PipelineType, PipeMaterial, PipeStatus, NodeKind } from '../types';\n\n/** 管线大类配色(caoguo-pipeline) */\nexport const PIPELINE_TYPE_COLORS: Record<PipelineType, string> = {\n gas: '#f59e0b', // 琥珀(燃气)\n water: '#3b82f6', // 蓝(供水)\n drainage: '#6b7280', // 灰(排水)\n heating: '#ef4444', // 红(供热)\n power: '#8b5cf6', // 紫(电力管沟)\n telecom: '#10b981', // 绿(通信管沟)\n};\n\n/** 管线大类的中文标签(地图图例/卡片显示) */\nexport const PIPELINE_TYPE_LABELS: Record<PipelineType, string> = {\n gas: '燃气管',\n water: '供水管',\n drainage: '排水管',\n heating: '供热管',\n power: '电力管沟',\n telecom: '通信管沟',\n};\n\n/** 管线大类的 Emoji 图标(轻量可视化标识,用于卡片/Tag) */\nexport const PIPELINE_TYPE_ICONS: Record<PipelineType, string> = {\n gas: '🔥',\n water: '💧',\n drainage: '🚰',\n heating: '🔴',\n power: '⚡',\n telecom: '📡',\n};\n\n/** 管段状态配色 */\nexport const PIPE_STATUS_COLORS: Record<PipeStatus, string> = {\n normal: '#4ade80', // 绿\n aging: '#fbbf24', // 黄\n damaged: '#ef4444', // 红\n under_repair: '#8b5cf6', // 紫\n abandoned: '#4b5563', // 深灰\n unknown: '#6b7280', // 灰\n};\n\n/** 状态的语义 + 动画 */\nexport const PIPE_STATUS_META: Record<\n PipeStatus,\n { label: string; animation?: 'pulse' | 'dashed' | 'none' }\n> = {\n normal: { label: '正常', animation: 'none' },\n aging: { label: '老化', animation: 'none' },\n damaged: { label: '损坏', animation: 'pulse' },\n under_repair: { label: '维修中', animation: 'dashed' },\n abandoned: { label: '废弃', animation: 'none' },\n unknown: { label: '未知', animation: 'none' },\n};\n\n/** 管材配色(maplibre style 用) */\nexport const PIPE_MATERIAL_COLORS: Record<PipeMaterial, string> = {\n cast_iron: '#94a3b8', // 蓝灰(旧铸铁)\n ductile_iron: '#0ea5e9', // 天蓝(球墨铸铁)\n steel: '#64748b', // 钢蓝\n pe: '#22c55e', // 绿(PE 现代管材)\n pvc: '#a78bfa', // 紫(PVC)\n concrete: '#a8a29e', // 米灰(混凝土)\n hdpe: '#16a34a', // 深绿(HDPE)\n copper: '#d97706', // 橙(铜)\n unknown: '#6b7280',\n};\n\n/** 节点图标(用 SVG path 描点,地图渲染层用) */\nexport const NODE_KIND_ICONS: Record<NodeKind, string> = {\n junction: 'M -6 0 L 6 0 M 0 -6 L 0 6', // 十字\n valve: 'M -8 -4 L 8 4 M 0 -4 L 0 4', // X\n pump: 'M -6 0 A 6 6 0 1 0 6 0 A 6 6 0 1 0 -6 0', // 圆\n meter: 'M -6 -6 L 6 -6 L 6 6 L -6 6 Z', // 方\n source: 'M 0 -10 L 6 6 L -6 6 Z', // 三角\n tank: 'M -8 -6 Q 0 -10 8 -6 L 8 6 L -8 6 Z', // 圆角\n junction_box: 'M -7 -4 L 7 -4 L 7 4 L -7 4 Z',// 小方\n};\n\n/** 节点配色(默认按 type 衍生) */\nexport const NODE_KIND_COLORS: Record<NodeKind, string> = {\n junction: '#94a3b8',\n valve: '#ef4444', // 阀门=红(控制关键)\n pump: '#f59e0b',\n meter: '#3b82f6',\n source: '#22c55e',\n tank: '#06b6d4',\n junction_box: '#8b5cf6',\n};\n\n/** 健康度等级配色(PipelineHealth 用) */\nexport const HEALTH_LEVEL_COLORS: Record<string, string> = {\n excellent: '#22c55e', // 绿 80-100\n good: '#3b82f6', // 蓝 60-80\n fair: '#eab308', // 黄 40-60\n poor: '#f97316', // 橙 20-40\n critical: '#ef4444', // 红 0-20\n};\n\n/** 健康等级 label */\nexport const HEALTH_LEVEL_LABELS: Record<string, string> = {\n excellent: '优',\n good: '良',\n fair: '中',\n poor: '差',\n critical: '危',\n};\n\n/**\n * 健康度 → 等级(保留闭区间,遵守 PRD §4.4.2)\n * @param score 0-100 健康分\n */\nexport function healthLevel(score: number): 'excellent' | 'good' | 'fair' | 'poor' | 'critical' {\n if (score >= 80) return 'excellent';\n if (score >= 60) return 'good';\n if (score >= 40) return 'fair';\n if (score >= 20) return 'poor';\n return 'critical';\n}\n\n/** 按管线类型取默认色(兜底用) */\nexport function pipelineTypeColor(type: PipelineType | undefined): string {\n if (!type) return '#94a3b8';\n return PIPELINE_TYPE_COLORS[type];\n}\n","/**\n * 管网 MapLibre paint 规则(caoguo-pipeline)\n *\n * 把\"管线/节点如何着色\"的业务规则翻译成 MapLibre style spec,\n * 业务方可直接 addLayer / setPaintProperty 使用。\n *\n * 规则集:\n * - 管线按管线大类着色(type)\n * - 管线按管径着色(diameter,PRD §4.1.4)\n * - 管线按状态着色(status)\n * - 管线按材质着色(material)\n * - 管线按健康度着色(health,PipelineHealth 集成)\n *\n * 节点按节点类型着色 + 图标。\n */\n\nimport type {\n PipelineType,\n PipeMaterial,\n PipeStatus,\n ColorByMode,\n} from '../types';\nimport { PIPELINE_TYPE_COLORS, PIPE_STATUS_COLORS, HEALTH_LEVEL_COLORS, PIPE_MATERIAL_COLORS } from './pipelineTheme';\n\n/**\n * MapLibre style spec 的 color function DSL(typed),\n * 业务方可直接 `map.addLayer({type:'line', paint: {'line-color': rule} })`\n *\n * MapLibre 表达式其实接受 string | number | 嵌套数组,所以我们用 unknown 让 TS 放行\n */\nexport type PaintRule = unknown;\n\n/** 管线按\"管线大类\"着色 */\nexport function paintPipeByType(types?: PipelineType[]): PaintRule {\n if (!types || types.length === 0) {\n // 全部类型都涂色\n return [\n 'match',\n ['get', 'pipelineType'],\n ...Object.entries(PIPELINE_TYPE_COLORS).flatMap(([k, v]) => [k, v]),\n '#94a3b8',\n ];\n }\n return [\n 'match',\n ['get', 'pipelineType'],\n ...types.flatMap((t) => [t, PIPELINE_TYPE_COLORS[t]]),\n '#94a3b8',\n ];\n}\n\n/** 管线按\"管径\"渐变着色(PRD §4.1.4) */\nexport function paintPipeByDiameter(): PaintRule {\n return [\n 'interpolate',\n ['linear'],\n ['coalesce', ['get', 'diameter'], 0],\n 0, '#4ade80', // 极细管 绿\n 50, '#4ade80', // DN50 以下 绿(支管)\n 150, '#60a5fa', // DN150 蓝(配水管)\n 300, '#f59e0b', // DN300 黄(干管)\n 600, '#ef4444', // DN600+ 红(主管)\n 1500, '#7f1d1d', // 极大管 深红\n ];\n}\n\n/** 管线按\"状态\"着色 */\nexport function paintPipeByStatus(): PaintRule {\n return [\n 'match',\n ['coalesce', ['get', 'status'], 'unknown'],\n ...Object.entries(PIPE_STATUS_COLORS).flatMap(([k, v]) => [k, v]),\n '#6b7280',\n ];\n}\n\n/** 管线按\"材质\"着色 */\nexport function paintPipeByMaterial(): PaintRule {\n return [\n 'match',\n ['coalesce', ['get', 'material'], 'unknown'],\n ...Object.entries(PIPE_MATERIAL_COLORS).flatMap(([k, v]) => [k, v]),\n '#6b7280',\n ];\n}\n\n/** 管线按\"健康度\"着色(健康分 0-100,规则按 healthLevel 离散) */\nexport function paintPipeByHealth(): PaintRule {\n return [\n 'step',\n ['coalesce', ['get', 'healthScore'], 100],\n HEALTH_LEVEL_COLORS.critical, // <20\n 20, HEALTH_LEVEL_COLORS.poor,\n 40, HEALTH_LEVEL_COLORS.fair,\n 60, HEALTH_LEVEL_COLORS.good,\n 80, HEALTH_LEVEL_COLORS.excellent,\n ];\n}\n\n/** 根据模式返回 paint rule 工厂 */\nexport function paintPipeBy(mode: ColorByMode, opts?: { types?: PipelineType[] }): PaintRule {\n switch (mode) {\n case 'type':\n return paintPipeByType(opts?.types);\n case 'diameter':\n return paintPipeByDiameter();\n case 'status':\n return paintPipeByStatus();\n case 'material':\n return paintPipeByMaterial();\n case 'health':\n return paintPipeByHealth();\n case 'uniform':\n default:\n return '#60a5fa';\n }\n}\n\n/** 节点按 kind 着色(maplibre style circle-color 用) */\nexport function paintNodeByKind(): PaintRule {\n return [\n 'match',\n ['get', 'kind'],\n 'junction', '#94a3b8',\n 'valve', '#ef4444',\n 'pump', '#f59e0b',\n 'meter', '#3b82f6',\n 'source', '#22c55e',\n 'tank', '#06b6d4',\n 'junction_box', '#8b5cf6',\n '#cbd5e1',\n ];\n}\n\n/** 默认管段宽度(按管径递推) */\nexport function paintPipeWidthByDiameter(minWidth = 1.5, maxWidth = 6): PaintRule {\n return [\n 'interpolate',\n ['linear'],\n ['coalesce', ['get', 'diameter'], 100],\n 0, minWidth,\n 1500, maxWidth,\n ];\n}\n"]}
|