map-ol-utils 0.1.30 → 0.2.0

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/index.cjs CHANGED
@@ -1,1166 +1,1953 @@
1
- "use strict";
1
+ Object.defineProperty(exports, Symbol.toStringTag, { value: 'Module' });
2
+ //#region \0rolldown/runtime.js
2
3
  var __create = Object.create;
3
4
  var __defProp = Object.defineProperty;
4
- var __defProps = Object.defineProperties;
5
5
  var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
6
- var __getOwnPropDescs = Object.getOwnPropertyDescriptors;
7
6
  var __getOwnPropNames = Object.getOwnPropertyNames;
8
- var __getOwnPropSymbols = Object.getOwnPropertySymbols;
9
7
  var __getProtoOf = Object.getPrototypeOf;
10
8
  var __hasOwnProp = Object.prototype.hasOwnProperty;
11
- var __propIsEnum = Object.prototype.propertyIsEnumerable;
12
- var __defNormalProp = (obj, key, value) => key in obj ? __defProp(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value;
13
- var __spreadValues = (a, b) => {
14
- for (var prop in b || (b = {}))
15
- if (__hasOwnProp.call(b, prop))
16
- __defNormalProp(a, prop, b[prop]);
17
- if (__getOwnPropSymbols)
18
- for (var prop of __getOwnPropSymbols(b)) {
19
- if (__propIsEnum.call(b, prop))
20
- __defNormalProp(a, prop, b[prop]);
21
- }
22
- return a;
23
- };
24
- var __spreadProps = (a, b) => __defProps(a, __getOwnPropDescs(b));
25
- var __export = (target, all) => {
26
- for (var name in all)
27
- __defProp(target, name, { get: all[name], enumerable: true });
28
- };
29
9
  var __copyProps = (to, from, except, desc) => {
30
- if (from && typeof from === "object" || typeof from === "function") {
31
- for (let key of __getOwnPropNames(from))
32
- if (!__hasOwnProp.call(to, key) && key !== except)
33
- __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
34
- }
35
- return to;
36
- };
37
- var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
38
- // If the importer is in node compatibility mode or this is not an ESM
39
- // file that has been converted to a CommonJS file using a Babel-
40
- // compatible transform (i.e. "__esModule" has not been set), then set
41
- // "default" to the CommonJS "module.exports" for node compatibility.
42
- isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
43
- mod
44
- ));
45
- var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
46
- var __async = (__this, __arguments, generator) => {
47
- return new Promise((resolve, reject) => {
48
- var fulfilled = (value) => {
49
- try {
50
- step(generator.next(value));
51
- } catch (e) {
52
- reject(e);
53
- }
54
- };
55
- var rejected = (value) => {
56
- try {
57
- step(generator.throw(value));
58
- } catch (e) {
59
- reject(e);
60
- }
61
- };
62
- var step = (x) => x.done ? resolve(x.value) : Promise.resolve(x.value).then(fulfilled, rejected);
63
- step((generator = generator.apply(__this, __arguments)).next());
64
- });
10
+ if (from && typeof from === "object" || typeof from === "function") {
11
+ for (var keys = __getOwnPropNames(from), i = 0, n = keys.length, key; i < n; i++) {
12
+ key = keys[i];
13
+ if (!__hasOwnProp.call(to, key) && key !== except) {
14
+ __defProp(to, key, {
15
+ get: ((k) => from[k]).bind(null, key),
16
+ enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable
17
+ });
18
+ }
19
+ }
20
+ }
21
+ return to;
65
22
  };
23
+ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(isNodeMode || !mod || !mod.__esModule || !__hasOwnProp.call(mod, "default") ? __defProp(target, "default", {
24
+ value: mod,
25
+ enumerable: true
26
+ }) : target, mod));
27
+
28
+ //#endregion
29
+ const require_tile_loader = require('./tile-loader-D4cn6nMU.cjs');
30
+ let ol_format_MVT_js = require("ol/format/MVT.js");
31
+ ol_format_MVT_js = __toESM(ol_format_MVT_js, 1);
32
+ let ol_TileState_js = require("ol/TileState.js");
33
+ ol_TileState_js = __toESM(ol_TileState_js, 1);
34
+ let ol_source_VectorTile_js = require("ol/source/VectorTile.js");
35
+ ol_source_VectorTile_js = __toESM(ol_source_VectorTile_js, 1);
36
+ let mitt = require("mitt");
37
+ mitt = __toESM(mitt, 1);
38
+ let ol_source_js = require("ol/source.js");
39
+ let ol_layer_Tile_js = require("ol/layer/Tile.js");
40
+ ol_layer_Tile_js = __toESM(ol_layer_Tile_js, 1);
41
+ let ol_format_js = require("ol/format.js");
42
+ let ol_source_WMTS_js = require("ol/source/WMTS.js");
43
+ let ol_tilegrid_js = require("ol/tilegrid.js");
44
+ let ol_layer_js = require("ol/layer.js");
45
+ let ol_tilegrid_WMTS_js = require("ol/tilegrid/WMTS.js");
46
+ ol_tilegrid_WMTS_js = __toESM(ol_tilegrid_WMTS_js, 1);
47
+ let ol_layer_Image_js = require("ol/layer/Image.js");
48
+ ol_layer_Image_js = __toESM(ol_layer_Image_js, 1);
49
+ let ol_source_Raster_js = require("ol/source/Raster.js");
50
+ ol_source_Raster_js = __toESM(ol_source_Raster_js, 1);
51
+ let ol_Map_js = require("ol/Map.js");
52
+ ol_Map_js = __toESM(ol_Map_js, 1);
53
+ let ol_View_js = require("ol/View.js");
54
+ ol_View_js = __toESM(ol_View_js, 1);
55
+ let ol_control_js = require("ol/control.js");
56
+ let gcoord = require("gcoord");
57
+ gcoord = __toESM(gcoord, 1);
58
+ let ol = require("ol");
59
+ let ol_interaction_js = require("ol/interaction.js");
60
+ let ol_extent_js = require("ol/extent.js");
61
+ let ol_events_condition_js = require("ol/events/condition.js");
62
+ let ol_Feature_js = require("ol/Feature.js");
63
+ ol_Feature_js = __toESM(ol_Feature_js, 1);
64
+ let ol_geom_Point_js = require("ol/geom/Point.js");
65
+ ol_geom_Point_js = __toESM(ol_geom_Point_js, 1);
66
+ let ol_layer_Vector_js = require("ol/layer/Vector.js");
67
+ ol_layer_Vector_js = __toESM(ol_layer_Vector_js, 1);
68
+ let ol_source_Vector_js = require("ol/source/Vector.js");
69
+ ol_source_Vector_js = __toESM(ol_source_Vector_js, 1);
70
+ let ol_style_js = require("ol/style.js");
71
+ let ol_interaction_Draw_js = require("ol/interaction/Draw.js");
72
+ ol_interaction_Draw_js = __toESM(ol_interaction_Draw_js, 1);
73
+ let ol_sphere_js = require("ol/sphere.js");
74
+ let ol_format_GeoJSON_js = require("ol/format/GeoJSON.js");
75
+ ol_format_GeoJSON_js = __toESM(ol_format_GeoJSON_js, 1);
76
+ let ol_geom_js = require("ol/geom.js");
77
+ let ol_source_Cluster_js = require("ol/source/Cluster.js");
78
+ ol_source_Cluster_js = __toESM(ol_source_Cluster_js, 1);
79
+ let ol_style_Circle_js = require("ol/style/Circle.js");
80
+ ol_style_Circle_js = __toESM(ol_style_Circle_js, 1);
66
81
 
67
- // src/index.ts
68
- var index_exports = {};
69
- __export(index_exports, {
70
- GeometryType: () => GeometryType,
71
- activeFeatureByUid: () => activeFeatureByUid,
72
- addFeaturesByLayer: () => addFeaturesByLayer,
73
- addMassMarksLayer: () => addMassMarksLayer,
74
- appendFeaturesByLayer: () => appendFeaturesByLayer,
75
- buildMassMarksStyles: () => buildMassMarksStyles,
76
- createAnimationMarker: () => createAnimationMarker,
77
- createBaseLayer: () => createBaseLayer,
78
- createBusinessLayer: () => createBusinessLayer,
79
- createClusterLayer: () => createClusterLayer,
80
- createMap: () => createMap,
81
- createMapInstance: () => createMapInstance,
82
- createMapWorldLayer: () => createMapWorldLayer,
83
- createMassMarksLayer: () => createMassMarksLayer,
84
- createOverlay: () => createOverlay,
85
- createSelectByLayer: () => createSelectByLayer,
86
- createVectorFaceLayer: () => createVectorFaceLayer,
87
- createVectorLineLayer: () => createVectorLineLayer,
88
- createWmtsLayer: () => createWmtsLayer,
89
- createZheJiangLayer: () => createZheJiangLayer,
90
- disposeMap: () => disposeMap,
91
- emitter: () => emitter_default,
92
- getLayerByName: () => getLayerByName,
93
- getLayersDataList: () => getLayersDataList,
94
- getMapInstance: () => getMapInstance,
95
- instance: () => instance,
96
- removeAllLayers: () => removeAllLayers,
97
- removeLayerByName: () => removeLayerByName,
98
- removeOverlays: () => removeOverlays,
99
- resetActiveFeature: () => resetActiveFeature,
100
- resetActiveVector: () => resetActiveVector,
101
- resetMap: () => resetMap,
102
- resetZoomAndCenter: () => resetZoomAndCenter,
103
- setFitViewByCoords: () => setFitViewByCoords,
104
- setFitViewByGeom: () => setFitViewByGeom,
105
- setFitViewByLayer: () => setFitViewByLayer,
106
- updateMarksLayersByStatus: () => updateMarksLayersByStatus
82
+ //#region src/core/types.ts
83
+ let GeometryType = /* @__PURE__ */ function(GeometryType) {
84
+ GeometryType["LineString"] = "LineString";
85
+ GeometryType["MultiLineString"] = "MultiLineString";
86
+ GeometryType["Polygon"] = "Polygon";
87
+ GeometryType["MultiPolygon"] = "MultiPolygon";
88
+ GeometryType["Invalid"] = "Invalid";
89
+ return GeometryType;
90
+ }({});
91
+
92
+ //#endregion
93
+ //#region src/tdt-vts/pk.ts
94
+ const PK_DIGIT_TO_CHAR = [
95
+ "a",
96
+ "d",
97
+ "g",
98
+ "j",
99
+ "m"
100
+ ];
101
+ const PK_CHAR_TO_DIGIT = Object.freeze({
102
+ a: 0,
103
+ d: 1,
104
+ g: 2,
105
+ j: 3,
106
+ m: 4
107
107
  });
108
- module.exports = __toCommonJS(index_exports);
108
+ const PERTURBED_POSITIONS = [
109
+ 9,
110
+ 8,
111
+ 7,
112
+ 6
113
+ ];
114
+ function assertTileInteger(name, value) {
115
+ if (!Number.isSafeInteger(value) || value < 0) throw new TypeError(`${name} 必须是非负安全整数`);
116
+ }
117
+ /**
118
+ * 将 XYZ 瓦片坐标编码为天地图 VTS 使用的 pk 参数。
119
+ *
120
+ * 算法按 main.0f98e6f9.js 中的实现还原:
121
+ * 1. 从 bit=z 到 bit=0 交织 x/y 位;
122
+ * 2. 反转;
123
+ * 3. 将 0-based 位置 9、8、7、6 加一;
124
+ * 4. 0/1/2/3/4 映射为 a/d/g/j/m;
125
+ * 5. 连续字符使用“额外重复次数”压缩。
126
+ */
127
+ const encodeTdtPk = (x, y, z) => {
128
+ assertTileInteger("x", x);
129
+ assertTileInteger("y", y);
130
+ assertTileInteger("z", z);
131
+ if (z > 30) throw new RangeError("当前实现将 z 限制为 0~30;天地图底图通常不超过 18 级");
132
+ const maxCoordinate = 2 ** z;
133
+ if (x >= maxCoordinate || y >= maxCoordinate) throw new RangeError(`z=${z} 时 x/y 必须小于 ${maxCoordinate}`);
134
+ const bigX = BigInt(x);
135
+ const bigY = BigInt(y);
136
+ const digits = [];
137
+ for (let bit = z; bit >= 0; bit -= 1) {
138
+ const mask = 1n << BigInt(bit);
139
+ let digit = 0;
140
+ if ((bigX & mask) !== 0n) digit |= 1;
141
+ if ((bigY & mask) !== 0n) digit |= 2;
142
+ digits.push(digit);
143
+ }
144
+ digits.reverse();
145
+ for (const position of PERTURBED_POSITIONS) if (position < digits.length) {
146
+ const value = digits[position];
147
+ if (value === void 0) throw new Error("pk 中间状态异常");
148
+ digits[position] = value + 1;
149
+ }
150
+ let mapped = "";
151
+ for (const digit of digits) {
152
+ const char = PK_DIGIT_TO_CHAR[digit];
153
+ if (!char) throw new Error(`无法映射 pk 数字:${digit}`);
154
+ mapped += char;
155
+ }
156
+ return mapped.replace(/([adgjm])\1+/g, (run) => {
157
+ return `${run[0]}${run.length - 1}`;
158
+ });
159
+ };
160
+ /** 反解 pk;用于调试、单元测试和核对网络请求。 */
161
+ const decodeTdtPk = (pk) => {
162
+ if (!pk) throw new TypeError("pk 不能为空");
163
+ const transformed = [];
164
+ let cursor = 0;
165
+ while (cursor < pk.length) {
166
+ const char = pk[cursor];
167
+ if (!char || !(char in PK_CHAR_TO_DIGIT)) throw new Error(`pk 包含非法字符:${String(char)}`);
168
+ cursor += 1;
169
+ let repeatText = "";
170
+ while (cursor < pk.length && /\d/.test(pk[cursor] ?? "")) {
171
+ repeatText += pk[cursor];
172
+ cursor += 1;
173
+ }
174
+ const extraRepeats = repeatText ? Number(repeatText) : 0;
175
+ if (!Number.isSafeInteger(extraRepeats) || extraRepeats < 0) throw new Error(`pk 重复次数无效:${repeatText}`);
176
+ const digit = PK_CHAR_TO_DIGIT[char];
177
+ if (digit === void 0) throw new Error(`pk 字符无法映射:${char}`);
178
+ for (let i = 0; i < extraRepeats + 1; i += 1) transformed.push(digit);
179
+ }
180
+ for (const position of [
181
+ 6,
182
+ 7,
183
+ 8,
184
+ 9
185
+ ]) if (position < transformed.length) {
186
+ const value = transformed[position];
187
+ if (value === void 0) throw new Error("pk 中间状态异常");
188
+ const restored = value - 1;
189
+ if (restored < 0 || restored > 3) throw new Error(`pk 在位置 ${position} 的扰动值无效`);
190
+ transformed[position] = restored;
191
+ }
192
+ const digits = transformed.reverse();
193
+ const z = digits.length - 1;
194
+ if (z < 0 || z > 30) throw new RangeError(`pk 推导出的 z=${z} 超出范围`);
195
+ let x = 0n;
196
+ let y = 0n;
197
+ for (let index = 0; index < digits.length; index += 1) {
198
+ const digit = digits[index];
199
+ if (digit === void 0 || digit < 0 || digit > 3) throw new Error(`pk 四叉数字无效:${String(digit)}`);
200
+ const bit = BigInt(z - index);
201
+ if ((digit & 1) !== 0) x |= 1n << bit;
202
+ if ((digit & 2) !== 0) y |= 1n << bit;
203
+ }
204
+ const numberX = Number(x);
205
+ const numberY = Number(y);
206
+ assertTileInteger("反解 x", numberX);
207
+ assertTileInteger("反解 y", numberY);
208
+ return {
209
+ z,
210
+ x: numberX,
211
+ y: numberY
212
+ };
213
+ };
214
+ /**
215
+ * 根据 OpenLayers 的 [z, x, y] 生成最终 VTS 地址,不依赖字符串替换。
216
+ */
217
+ const createTdtVtsUrl = (tileCoord, options) => {
218
+ const [z, rawX, y] = tileCoord;
219
+ const { token, type = "vt", version = "1.0", maxZoom = 18, hosts = [
220
+ "/tile0",
221
+ "/tile1",
222
+ "/tile2"
223
+ ], wrapX = true } = options;
224
+ if (!token || z < 0 || z > maxZoom || y < 0 || hosts.length === 0) return;
225
+ const matrixSize = 2 ** z;
226
+ if (y >= matrixSize) return void 0;
227
+ const x = wrapX ? (rawX % matrixSize + matrixSize) % matrixSize : rawX;
228
+ if (x < 0 || x >= matrixSize) return void 0;
229
+ const host = hosts[Math.abs(x + y) % hosts.length];
230
+ if (!host) return void 0;
231
+ const params = new URLSearchParams({
232
+ t: type,
233
+ tk: token,
234
+ v: version,
235
+ pk: encodeTdtPk(x, y, z)
236
+ });
237
+ return `${host.replace(/\/$/, "")}/vts?${params.toString()}`;
238
+ };
239
+ const redactTdtToken = (url) => {
240
+ try {
241
+ const parsed = new URL(url);
242
+ if (parsed.searchParams.has("tk")) parsed.searchParams.set("tk", "***");
243
+ return parsed.toString();
244
+ } catch {
245
+ return url.replace(/([?&]tk=)[^&]+/i, "$1***");
246
+ }
247
+ };
109
248
 
110
- // src/types.ts
111
- var GeometryType = /* @__PURE__ */ ((GeometryType2) => {
112
- GeometryType2["LineString"] = "LineString";
113
- GeometryType2["MultiLineString"] = "MultiLineString";
114
- GeometryType2["Polygon"] = "Polygon";
115
- GeometryType2["MultiPolygon"] = "MultiPolygon";
116
- GeometryType2["Invalid"] = "Invalid";
117
- return GeometryType2;
118
- })(GeometryType || {});
249
+ //#endregion
250
+ //#region src/tdt-vts/style-loader.ts
251
+ const TDT_VECTOR_SOURCE_ID = "base-tdt-vector-tile";
252
+ function cloneJson(value) {
253
+ return JSON.parse(JSON.stringify(value));
254
+ }
255
+ async function fetchJson(url, signal) {
256
+ const response = await fetch(url, {
257
+ mode: "cors",
258
+ credentials: "omit",
259
+ cache: "default",
260
+ signal
261
+ });
262
+ if (!response.ok) throw new Error(`样式请求失败:HTTP ${response.status} ${response.statusText}`);
263
+ return response.json();
264
+ }
265
+ function parseStyle0(value) {
266
+ if (!value || typeof value !== "object" || Array.isArray(value)) throw new Error("style-0 不是 JSON 对象");
267
+ const style = value;
268
+ if (style.version !== 8) throw new Error(`style-0 version 必须为 8`);
269
+ if (!style.sources || typeof style.sources !== "object") throw new Error("style-0 缺少 sources");
270
+ if (!Array.isArray(style.layers)) throw new Error("style-0 缺少 layers 数组");
271
+ return style;
272
+ }
273
+ function parseStyle1Layers(value) {
274
+ if (Array.isArray(value)) return value;
275
+ if (value && typeof value === "object") {
276
+ const { layers } = value;
277
+ if (Array.isArray(layers)) return layers;
278
+ }
279
+ throw new Error("style-1 必须是图层数组或带 layers 的对象");
280
+ }
281
+ /** 按原 bundle 的 beforeLayerId 语义逐层插入。 */
282
+ const mergeTdtStyleLayers = (baseLayers, extraLayers) => {
283
+ const result = baseLayers.map((layer) => cloneJson(layer));
284
+ const ids = new Set(result.map((layer) => layer.id));
285
+ for (const input of extraLayers) {
286
+ const layer = cloneJson(input);
287
+ if (!layer.id) throw new Error("style-1 存在无 id 图层");
288
+ if (ids.has(layer.id)) throw new Error(`样式图层 id 重复:${layer.id}`);
289
+ const beforeLayerId = typeof layer.beforeLayerId === "string" ? layer.beforeLayerId : "";
290
+ delete layer.beforeLayerId;
291
+ const index = beforeLayerId ? result.findIndex((candidate) => candidate.id === beforeLayerId) : -1;
292
+ if (index >= 0) result.splice(index, 0, layer);
293
+ else result.push(layer);
294
+ ids.add(layer.id);
295
+ }
296
+ return result;
297
+ };
298
+ function resolveUrl(value, baseUrl) {
299
+ try {
300
+ return new URL(value, baseUrl).href;
301
+ } catch {
302
+ return value;
303
+ }
304
+ }
305
+ function resolveStyleResourceUrls(style, styleUrl) {
306
+ if (typeof style.glyphs === "string") style.glyphs = resolveUrl(style.glyphs, styleUrl);
307
+ if (typeof style.sprite === "string") style.sprite = resolveUrl(style.sprite, styleUrl);
308
+ else if (Array.isArray(style.sprite)) style.sprite = style.sprite.map((item) => {
309
+ if (item && typeof item === "object" && typeof item.url === "string") return {
310
+ ...item,
311
+ url: resolveUrl(item.url, styleUrl)
312
+ };
313
+ return item;
314
+ });
315
+ for (const source of Object.values(style.sources)) {
316
+ if (typeof source.url === "string") source.url = resolveUrl(source.url, styleUrl);
317
+ if (Array.isArray(source.tiles)) source.tiles = source.tiles.map((url) => typeof url === "string" ? resolveUrl(url, styleUrl) : url);
318
+ }
319
+ }
320
+ function removeUnsupportedLayers(layers) {
321
+ const skippedLayerIds = [];
322
+ return {
323
+ layers: layers.filter((layer) => {
324
+ if (layer.type === "pie") {
325
+ skippedLayerIds.push(layer.id);
326
+ return false;
327
+ }
328
+ return true;
329
+ }),
330
+ skippedLayerIds
331
+ };
332
+ }
333
+ const loadTdtStyleBundle = async (options) => {
334
+ const sourceId = options.sourceId ?? "base-tdt-vector-tile";
335
+ const [raw0, raw1] = await Promise.all([fetchJson(options.style0Url, options.signal), fetchJson(options.style1Url, options.signal)]);
336
+ const style0 = parseStyle0(raw0);
337
+ const style1Layers = parseStyle1Layers(raw1);
338
+ const style = cloneJson(style0);
339
+ if (!style.sources[sourceId]) throw new Error(`style-0 中不存在 source:${sourceId}`);
340
+ if (style.sources[sourceId]?.type !== "vector") throw new Error(`source ${sourceId} 不是 vector 类型`);
341
+ style.layers = mergeTdtStyleLayers(style.layers, style1Layers);
342
+ const filtered = removeUnsupportedLayers(style.layers);
343
+ style.layers = filtered.layers;
344
+ resolveStyleResourceUrls(style, options.style0Url);
345
+ return {
346
+ style,
347
+ style0LayerCount: style0.layers.length,
348
+ style1LayerCount: style1Layers.length,
349
+ skippedLayerIds: filtered.skippedLayerIds
350
+ };
351
+ };
352
+ const getConstantBackgroundColor = (style) => {
353
+ for (const layer of style.layers) {
354
+ if (layer.type !== "background") continue;
355
+ const value = layer.paint?.["background-color"];
356
+ if (typeof value === "string") return value;
357
+ }
358
+ };
119
359
 
120
- // src/emitter.ts
121
- var import_mitt = __toESM(require("mitt"), 1);
122
- var emitter = (0, import_mitt.default)();
123
- var emitter_default = emitter;
360
+ //#endregion
361
+ //#region src/tdt-vts/worker-client.ts
362
+ const DEFAULT_REQUEST_TIMEOUT_MS = 3e4;
363
+ const createCancellationError = (message) => {
364
+ const error = new Error(message);
365
+ error.name = "AbortError";
366
+ return error;
367
+ };
368
+ var TdtDecoderWorkerClient = class {
369
+ restoreMode;
370
+ worker;
371
+ pending = /* @__PURE__ */ new Map();
372
+ nextId = 1;
373
+ disposed = false;
374
+ requestTimeoutMs;
375
+ constructor(restoreMode, options = {}) {
376
+ this.restoreMode = restoreMode;
377
+ this.requestTimeoutMs = options.requestTimeoutMs ?? DEFAULT_REQUEST_TIMEOUT_MS;
378
+ if (!Number.isFinite(this.requestTimeoutMs) || this.requestTimeoutMs < 0) throw new RangeError("requestTimeoutMs 必须是非负有限数");
379
+ this.worker = options.workerFactory ? options.workerFactory() : new Worker(new URL("./tdt-vts/decoder.worker.mjs", require("url").pathToFileURL(__filename).href), {
380
+ type: "module",
381
+ name: "tdt-private-mvt-decoder"
382
+ });
383
+ this.worker.addEventListener("message", this.handleMessage);
384
+ this.worker.addEventListener("error", this.handleWorkerError);
385
+ }
386
+ decode(url, options = {}) {
387
+ if (this.disposed) return Promise.reject(/* @__PURE__ */ new Error("解码 Worker 已销毁"));
388
+ if (options.signal?.aborted) return Promise.reject(createCancellationError("解码请求已取消"));
389
+ const id = this.nextId;
390
+ this.nextId += 1;
391
+ return new Promise((resolve, reject) => {
392
+ let timeout;
393
+ const handleAbort = () => {
394
+ this.cancelRequest(id, createCancellationError("解码请求已取消"));
395
+ };
396
+ const cleanup = () => {
397
+ if (timeout !== void 0) clearTimeout(timeout);
398
+ options.signal?.removeEventListener("abort", handleAbort);
399
+ };
400
+ this.pending.set(id, {
401
+ resolve,
402
+ reject,
403
+ cleanup
404
+ });
405
+ options.signal?.addEventListener("abort", handleAbort, { once: true });
406
+ if (this.requestTimeoutMs > 0) timeout = setTimeout(() => {
407
+ this.cancelRequest(id, /* @__PURE__ */ new Error("解码请求超时"));
408
+ }, this.requestTimeoutMs);
409
+ const request = {
410
+ type: "decode-tile",
411
+ id,
412
+ url,
413
+ restoreMode: this.restoreMode
414
+ };
415
+ try {
416
+ this.worker.postMessage(request);
417
+ } catch (cause) {
418
+ this.takePending(id)?.reject(cause instanceof Error ? cause : new Error(String(cause)));
419
+ }
420
+ });
421
+ }
422
+ dispose() {
423
+ if (this.disposed) return;
424
+ this.disposed = true;
425
+ this.worker.removeEventListener("message", this.handleMessage);
426
+ this.worker.removeEventListener("error", this.handleWorkerError);
427
+ this.worker.terminate();
428
+ const error = /* @__PURE__ */ new Error("解码 Worker 已销毁");
429
+ for (const request of this.pending.values()) {
430
+ request.cleanup();
431
+ request.reject(error);
432
+ }
433
+ this.pending.clear();
434
+ }
435
+ takePending(id) {
436
+ const pending = this.pending.get(id);
437
+ if (!pending) return void 0;
438
+ this.pending.delete(id);
439
+ pending.cleanup();
440
+ return pending;
441
+ }
442
+ cancelRequest(id, error) {
443
+ const pending = this.takePending(id);
444
+ if (!pending) return;
445
+ const request = {
446
+ type: "cancel-tile",
447
+ id
448
+ };
449
+ try {
450
+ this.worker.postMessage(request);
451
+ } catch {}
452
+ pending.reject(error);
453
+ }
454
+ fail(error) {
455
+ if (this.disposed) return;
456
+ this.disposed = true;
457
+ this.worker.removeEventListener("message", this.handleMessage);
458
+ this.worker.removeEventListener("error", this.handleWorkerError);
459
+ this.worker.terminate();
460
+ for (const request of this.pending.values()) {
461
+ request.cleanup();
462
+ request.reject(error);
463
+ }
464
+ this.pending.clear();
465
+ }
466
+ handleMessage = (event) => {
467
+ const response = event.data;
468
+ if (response.type !== "decode-result") return;
469
+ const pending = this.takePending(response.id);
470
+ if (!pending) return;
471
+ if (response.ok) pending.resolve({
472
+ buffer: response.buffer,
473
+ stats: response.stats
474
+ });
475
+ else pending.reject(new Error(response.error));
476
+ };
477
+ handleWorkerError = (event) => {
478
+ const error = new Error(event.message || "解码 Worker 发生未捕获错误");
479
+ this.fail(error);
480
+ };
481
+ };
124
482
 
125
- // src/create-map.ts
126
- var import_Map = __toESM(require("ol/Map"), 1);
127
- var import_View = __toESM(require("ol/View"), 1);
128
- var import_control = require("ol/control");
483
+ //#endregion
484
+ //#region src/tdt-vts/source.ts
485
+ const createTdtVectorSource = (options) => {
486
+ const decoder = new TdtDecoderWorkerClient(options.restoreMode, options.decoderOptions);
487
+ const format = new ol_format_MVT_js.default({ layerName: "mvt:layer" });
488
+ const source = new ol_source_VectorTile_js.default({
489
+ projection: "EPSG:3857",
490
+ minZoom: options.minZoom ?? 1,
491
+ maxZoom: options.maxZoom ?? 18,
492
+ tileSize: 512,
493
+ wrapX: true,
494
+ format,
495
+ attributions: "© <a href=\"https://www.tianditu.gov.cn/\" target=\"_blank\" rel=\"noopener\">天地图</a>",
496
+ tileUrlFunction(tileCoord) {
497
+ if (!tileCoord) return void 0;
498
+ const [z, x, y] = tileCoord;
499
+ if (z === void 0 || x === void 0 || y === void 0) return void 0;
500
+ return createTdtVtsUrl([
501
+ z,
502
+ x,
503
+ y
504
+ ], {
505
+ token: options.token,
506
+ maxZoom: options.maxZoom ?? 18,
507
+ wrapX: true
508
+ });
509
+ },
510
+ tileLoadFunction(tile, url) {
511
+ const vectorTile = tile;
512
+ vectorTile.setLoader(async (extent, _resolution, projection) => {
513
+ const redactedUrl = redactTdtToken(url);
514
+ try {
515
+ const decoded = await decoder.decode(url);
516
+ const features = format.readFeatures(decoded.buffer, {
517
+ extent,
518
+ featureProjection: projection
519
+ });
520
+ vectorTile.setFeatures(features);
521
+ options.diagnostics?.onDecoded?.(decoded.stats, redactedUrl);
522
+ } catch (cause) {
523
+ const error = cause instanceof Error ? cause : new Error(String(cause));
524
+ options.diagnostics?.onError?.(error, redactedUrl);
525
+ console.error("天地图私有 VTS 加载失败", redactedUrl, error);
526
+ vectorTile.setState(ol_TileState_js.default.ERROR);
527
+ }
528
+ });
529
+ }
530
+ });
531
+ const disposeSource = source.dispose.bind(source);
532
+ source.dispose = () => {
533
+ decoder.dispose();
534
+ disposeSource();
535
+ };
536
+ return {
537
+ source,
538
+ decoder
539
+ };
540
+ };
129
541
 
130
- // src/overlay.ts
131
- var import_gcoord = __toESM(require("gcoord"), 1);
132
- var import_ol = require("ol");
133
- var removeOverlays = (key = "") => {
134
- if (instance) {
135
- const overlays = instance.getOverlays().getArray().filter((overlay) => overlay.get(key || "position"));
136
- overlays.forEach((overlay) => instance.removeOverlay(overlay));
137
- }
542
+ //#endregion
543
+ //#region src/core/emitter.ts
544
+ const emitter = (0, mitt.default)();
545
+
546
+ //#endregion
547
+ //#region src/core/map-context.ts
548
+ /** 当前 OpenLayers 单例。集中存放以避免业务模块之间互相引用。 */
549
+ let instance;
550
+ /** @internal 更新当前地图单例。 */
551
+ const setMapInstance = (map) => {
552
+ instance = map;
138
553
  };
139
- var removeAnimationMarker = () => removeOverlays("_isAnimationMarker");
140
- var createAnimationMarker = (imgUrl, data) => {
141
- removeAnimationMarker();
142
- const { width, height, lnglat, crsForm } = data;
143
- const element = document.createElement("div");
144
- element.innerHTML = `<img src=${imgUrl} height=${height} width=${width} alt="" />`;
145
- const overlay = new import_ol.Overlay({
146
- element,
147
- stopEvent: false,
148
- positioning: "bottom-center",
149
- position: import_gcoord.default.transform(
150
- [+lnglat[0], +lnglat[1]],
151
- crsForm || import_gcoord.default.WGS84,
152
- import_gcoord.default.WGS84
153
- )
154
- });
155
- overlay.set("_isAnimationMarker", true);
156
- instance.addOverlay(overlay);
157
- };
158
- var createOverlay = (config = { id: "popup-container", positioning: "top-center" }) => {
159
- return new import_ol.Overlay(
160
- Object.assign(
161
- {
162
- element: document.getElementById(config.id) || void 0
163
- },
164
- config
165
- )
166
- );
554
+ /** @internal 清空当前地图单例。 */
555
+ const clearMapInstance = () => {
556
+ instance = void 0;
167
557
  };
168
558
 
169
- // src/layer-manager.ts
170
- var resetActiveVector = () => {
171
- removeOverlays();
172
- const layers = instance.getAllLayers();
173
- layers.forEach((layer) => {
174
- const interaction = layer.get("_selectInteraction");
175
- interaction == null ? void 0 : interaction.getFeatures().clear();
176
- });
177
- };
178
- var removeAllLayers = () => {
179
- removeOverlays();
180
- if (instance) {
181
- instance.getAllLayers().forEach((layer) => {
182
- if (!layer.get("_isBaseLayer")) {
183
- const source = layer.getSource();
184
- if (source && source.dispose) {
185
- source.dispose();
186
- }
187
- instance.removeLayer(layer);
188
- layer.dispose();
189
- }
190
- });
191
- }
559
+ //#endregion
560
+ //#region src/core/helper.ts
561
+ const hexToRgba = (hex, alpha) => {
562
+ if (hex.startsWith("#")) {
563
+ let tempHex = hex.replace("#", "");
564
+ if (tempHex.length === 3) tempHex = tempHex[0] + tempHex[0] + tempHex[1] + tempHex[1] + tempHex[2] + tempHex[2];
565
+ return `rgba(${parseInt(tempHex.substring(0, 2), 16)}, ${parseInt(tempHex.substring(2, 4), 16)}, ${parseInt(tempHex.substring(4, 6), 16)}, ${alpha})`;
566
+ } else return hex;
192
567
  };
193
- var resetActiveFeature = () => {
194
- removeOverlays();
195
- const targetLayers = instance.getAllLayers().filter((layer) => layer.get("_isVectorLayer"));
196
- targetLayers.forEach((layer) => {
197
- const selectInteraction = layer.get("_selectInteraction");
198
- if (selectInteraction) {
199
- selectInteraction.dispatchEvent({
200
- type: "select",
201
- selected: [],
202
- mapBrowserEvent: void 0,
203
- deselected: selectInteraction.getFeatures().getArray()
204
- });
205
- selectInteraction.getFeatures().clear();
206
- }
207
- });
208
- };
209
- var activeFeatureByUid = (uid) => {
210
- var _a;
211
- const targetLayers = instance.getAllLayers().filter((layer) => layer.get("_isVectorLayer"));
212
- if (targetLayers.length) {
213
- const targetLayer = targetLayers.find(
214
- (layer) => layer.get("_uuidSet").has(uid) && layer.get("_selectInteraction")
215
- );
216
- if (targetLayer) {
217
- const tempList = ((_a = targetLayer.getSource()) == null ? void 0 : _a.getFeatures()) || [];
218
- const targetFeature = tempList.find(
219
- (feature) => feature.get("_uuid") === uid
220
- );
221
- const selectInteraction = targetLayer.get("_selectInteraction");
222
- if (selectInteraction) {
223
- const collection = selectInteraction.getFeatures().getArray();
224
- const hasFeature = collection.find(
225
- (feature) => feature.get("_uuid") === uid
226
- );
227
- if (!hasFeature) {
228
- selectInteraction.dispatchEvent({
229
- type: "select",
230
- deselected: collection,
231
- selected: [targetFeature],
232
- mapBrowserEvent: void 0
233
- });
234
- selectInteraction.getFeatures().push(targetFeature);
235
- }
236
- }
237
- }
238
- }
568
+ const getLayersDataList = () => instance?.getAllLayers().map((layer) => layer.get("_dataList") || []).flat(2) || [];
569
+ const determineGeometryType = (coordinates) => {
570
+ const getArrayDepth = (arr) => {
571
+ if (!Array.isArray(arr) || arr.length === 0) return 0;
572
+ return 1 + getArrayDepth(arr[0]);
573
+ };
574
+ const isClosedRing = (coords) => {
575
+ if (!Array.isArray(coords) || coords.length < 3) return false;
576
+ const first = coords[0];
577
+ const last = coords[coords.length - 1];
578
+ return first[0] === last[0] && first[1] === last[1];
579
+ };
580
+ const isValidCoordinate = (coord) => {
581
+ return Array.isArray(coord) && coord.length >= 2 && typeof coord[0] === "number" && typeof coord[1] === "number";
582
+ };
583
+ const isValidLineString = (coords) => {
584
+ return Array.isArray(coords) && coords.length >= 2 && coords.every(isValidCoordinate);
585
+ };
586
+ const isValidPolygon = (coords) => {
587
+ if (!Array.isArray(coords)) return false;
588
+ return (getArrayDepth(coords) === 2 ? [coords] : coords).every((ring) => Array.isArray(ring) && ring.length >= 4 && isClosedRing(ring) && ring.every(isValidCoordinate));
589
+ };
590
+ const depth = getArrayDepth(coordinates);
591
+ try {
592
+ if (depth < 2 || !coordinates || coordinates.length === 0) return "Invalid";
593
+ else if (depth === 2 && isValidLineString(coordinates)) return isClosedRing(coordinates) && coordinates.length >= 4 ? "Polygon" : "LineString";
594
+ else if (depth === 3 && Array.isArray(coordinates) && coordinates.every(isValidLineString)) {
595
+ if (isValidPolygon(coordinates)) return "Polygon";
596
+ else if (coordinates.every((arr) => !isClosedRing(arr))) return "MultiLineString";
597
+ else return "Invalid";
598
+ } else if (depth === 4 && Array.isArray(coordinates) && coordinates.every((rings) => isValidPolygon(rings))) return "MultiPolygon";
599
+ else return "Invalid";
600
+ } catch (error) {
601
+ console.error("Error analyzing coordinates:", error);
602
+ return "Invalid";
603
+ }
239
604
  };
240
605
 
241
- // src/create-map.ts
242
- var import_interaction = require("ol/interaction");
606
+ //#endregion
607
+ //#region src/layer/ogc-utils.ts
608
+ const parser = new ol_format_js.WMTSCapabilities();
609
+ const capabilitiesMap = /* @__PURE__ */ new Map();
610
+ const getCapabilities = (url) => {
611
+ return new Promise((resolve) => {
612
+ const capabilities = capabilitiesMap.get(url);
613
+ if (capabilities) resolve(capabilities);
614
+ else fetch(url).then((data) => data.text()).then((text) => {
615
+ const capabilities = parser.read(text);
616
+ capabilitiesMap.set(url, capabilities);
617
+ resolve(capabilities);
618
+ });
619
+ });
620
+ };
621
+ /**
622
+ * 创建WMTS图层
623
+ * @param serverUrl
624
+ */
625
+ const createWmtsLayer = (serverUrl) => async (config) => {
626
+ const { style, format, version, layerName, matrixSet } = config;
627
+ const [workspace, datastore] = layerName.split(":");
628
+ const capabilitiesUrl = `${serverUrl}/${workspace}/${datastore}/gwc/service/wmts?request=GetCapabilities`;
629
+ return new Promise((resolve, reject) => {
630
+ getCapabilities(capabilitiesUrl).then((data) => {
631
+ const options = (0, ol_source_WMTS_js.optionsFromCapabilities)(data, {
632
+ Style: style || "",
633
+ layer: datastore,
634
+ version: version || "1.1.0",
635
+ format: format || "image/png",
636
+ matrixSet: matrixSet || "EPSG:4326"
637
+ });
638
+ if (options) resolve(new ol_layer_Tile_js.default({
639
+ zIndex: 3,
640
+ className: layerName,
641
+ source: new ol_source_js.WMTS(options)
642
+ }));
643
+ else reject(/* @__PURE__ */ new Error("Unable to create TileLayer"));
644
+ });
645
+ });
646
+ };
243
647
 
244
- // src/base-layer.ts
245
- var import_source = require("ol/source");
246
- var import_tilegrid = require("ol/tilegrid");
247
- var import_layer = require("ol/layer");
248
- var import_WMTS = __toESM(require("ol/tilegrid/WMTS"), 1);
648
+ //#endregion
649
+ //#region src/core/constants.ts
650
+ /**
651
+ * 天地图默认访问令牌(仅作缺省值,正式项目请通过参数 / config 覆盖)
652
+ */
653
+ const DEFAULT_TIANDITU_TK = "c77eddc667c5bed016fded560baf93e7";
654
+ /**
655
+ * 浙江省天地图默认访问令牌(仅作缺省值,正式项目请通过参数覆盖)
656
+ */
657
+ const DEFAULT_ZHEJIANG_TOKEN = "3b0cdd02-c366-4363-b6de-081a9f12b364";
249
658
 
250
- // src/constants.ts
251
- var DEFAULT_TIANDITU_TK = "c77eddc667c5bed016fded560baf93e7";
252
- var DEFAULT_ZHEJIANG_TOKEN = "3b0cdd02-c366-4363-b6de-081a9f12b364";
659
+ //#endregion
660
+ //#region src/layer/layer-lifecycle.ts
661
+ /** @internal 从地图移除图层并释放其数据源与自身资源。 */
662
+ const disposeLayer = (map, layer) => {
663
+ const dynamicMarkerTimer = layer.get("_dynamicMarkerTimer");
664
+ if (dynamicMarkerTimer !== void 0) {
665
+ clearTimeout(dynamicMarkerTimer);
666
+ layer.unset("_dynamicMarkerTimer");
667
+ }
668
+ layer.getSource()?.dispose();
669
+ map.removeLayer(layer);
670
+ layer.dispose();
671
+ };
253
672
 
254
- // src/base-layer.ts
255
- var createBaseLayer = (layerName = "hzsyvector_dark") => {
256
- const config = {
257
- zIndex: -5,
258
- preload: 1,
259
- minZoom: 8,
260
- maxZoom: 21,
261
- source: new import_source.XYZ({
262
- tileGrid: new import_tilegrid.TileGrid({
263
- tileSize: 256,
264
- resolutions: [
265
- 0.00549933137253187,
266
- 0.00274966568626595,
267
- 0.00137483284313297,
268
- 687416421566485e-18,
269
- 343708210783242e-18,
270
- 171854105391621e-18,
271
- 859270526958104e-19,
272
- 429635263479052e-19,
273
- 214817631739526e-19,
274
- 107408815869763e-19,
275
- 537044079348816e-20,
276
- 268522039674407e-20,
277
- 134261019837204e-20
278
- ],
279
- origin: [118.122911693886, 31.2869311022836],
280
- extent: [
281
- 116.43263049006,
282
- 28.6201742126026,
283
- 123.705594256347,
284
- 31.9765041681924
285
- ]
286
- }),
287
- projection: "EPSG:4326",
288
- urls: [
289
- `https://cb.hangzhoumap.gov.cn/E36CCEA93443D1495DB9B9F2B2FFE348CB1A367D75176F815040AB19E54CDCA5DAAA25813AF965E2ABD0CC2463DD1223/PBS/rest/services/${layerName}/Mapserver/tile/{z}/{y}/{x}`
290
- ]
291
- }),
292
- properties: {
293
- _isBaseLayer: true,
294
- _layerName: layerName
295
- }
296
- };
297
- return new import_layer.Tile(config);
298
- };
299
- var createMapWorldLayer = (layerName, tk = DEFAULT_TIANDITU_TK) => {
300
- const [name, matrixSet] = layerName.split("_");
301
- const config = {
302
- preload: 1,
303
- zIndex: -10,
304
- cacheSize: 20240,
305
- properties: {
306
- _isBaseLayer: true,
307
- _layerName: layerName
308
- },
309
- source: new import_source.WMTS({
310
- crossOrigin: "anonymous",
311
- projection: "EPSG:4326",
312
- wrapX: true,
313
- layer: name,
314
- style: "default",
315
- version: "1.0.0",
316
- format: "image/png",
317
- matrixSet,
318
- tileGrid: new import_WMTS.default({
319
- tileSize: 256,
320
- origin: [-180, 90],
321
- matrixIds: [
322
- "1",
323
- "2",
324
- "3",
325
- "4",
326
- "5",
327
- "6",
328
- "7",
329
- "8",
330
- "9",
331
- "10",
332
- "11",
333
- "12",
334
- "13",
335
- "14",
336
- "15",
337
- "16",
338
- "17",
339
- "18",
340
- "19"
341
- ],
342
- resolutions: [
343
- 0.703125,
344
- 0.3515625,
345
- 0.17578125,
346
- 0.087890625,
347
- 0.0439453125,
348
- 0.02197265625,
349
- 0.010986328125,
350
- 0.0054931640625,
351
- 0.00274658203125,
352
- 0.001373291015625,
353
- 6866455078125e-16,
354
- 34332275390625e-17,
355
- 171661376953125e-18,
356
- 858306884765625e-19,
357
- 4291534423828125e-20,
358
- 21457672119140625e-21,
359
- 10728836059570312e-21,
360
- 5364418029785156e-21,
361
- 2682209014892578e-21
362
- ]
363
- }),
364
- url: `https://t{0-7}.tianditu.gov.cn/${layerName}/wmts?tk=${tk}`
365
- })
366
- };
367
- return new import_layer.Tile(config);
368
- };
369
- var createZheJiangLayer = (layerName = "emap", tk = DEFAULT_ZHEJIANG_TOKEN) => {
370
- return new import_layer.Tile({
371
- preload: 1,
372
- minZoom: 4,
373
- maxZoom: 20,
374
- zIndex: -10,
375
- cacheSize: 20240,
376
- source: new import_source.XYZ({
377
- wrapX: true,
378
- projection: "EPSG:4326",
379
- crossOrigin: "anonymous",
380
- url: `https://ditu{0-6}.zjzwfw.gov.cn/services/wmts/${layerName}/default/oss/getTile/{z}/{y}/{x}?token=${tk}`
381
- })
382
- });
383
- };
384
- var getLayerByName = (name) => instance.getAllLayers().find((item) => (item.get("_layerName") || item.getClassName()) === name);
385
- var removeLayerByName = (name) => {
386
- const layer = getLayerByName(name);
387
- if (layer) {
388
- const source = layer.getSource();
389
- if (source && source.dispose) {
390
- source.dispose();
391
- }
392
- instance.removeLayer(layer);
393
- layer.dispose();
394
- }
673
+ //#endregion
674
+ //#region src/layer/base-layer.ts
675
+ /**
676
+ * 创建杭州规自地图
677
+ * @param layerName - 'hzsyraster' | 'hzsyvector' | 'hzsyvector_dark'
678
+ */
679
+ const createBaseLayer = (layerName = "hzsyvector_dark") => {
680
+ const config = {
681
+ zIndex: -5,
682
+ preload: 1,
683
+ minZoom: 8,
684
+ maxZoom: 21,
685
+ source: new ol_source_js.XYZ({
686
+ tileGrid: new ol_tilegrid_js.TileGrid({
687
+ tileSize: 256,
688
+ resolutions: [
689
+ .00549933137253187,
690
+ .00274966568626595,
691
+ .00137483284313297,
692
+ .000687416421566485,
693
+ .000343708210783242,
694
+ .000171854105391621,
695
+ 859270526958104e-19,
696
+ 429635263479052e-19,
697
+ 214817631739526e-19,
698
+ 107408815869763e-19,
699
+ 537044079348816e-20,
700
+ 268522039674407e-20,
701
+ 134261019837204e-20
702
+ ],
703
+ origin: [118.122911693886, 31.2869311022836],
704
+ extent: [
705
+ 116.43263049006,
706
+ 28.6201742126026,
707
+ 123.705594256347,
708
+ 31.9765041681924
709
+ ]
710
+ }),
711
+ projection: "EPSG:4326",
712
+ urls: [
713
+ `https://ywtg.citybrain.hangzhou.gov.cn/${layerName}/{z}/{y}/{x}`,
714
+ `https://ywtg.citybrain.hangzhou.gov.cn:9456/${layerName}/{z}/{y}/{x}`,
715
+ `https://ywtg.citybrain.hangzhou.gov.cn:9457/${layerName}/{z}/{y}/{x}`,
716
+ `https://ywtg.citybrain.hangzhou.gov.cn:9458/${layerName}/{z}/{y}/{x}`,
717
+ `https://ywtg.citybrain.hangzhou.gov.cn:9459/${layerName}/{z}/{y}/{x}`
718
+ ]
719
+ }),
720
+ properties: {
721
+ _isBaseLayer: true,
722
+ _layerName: layerName
723
+ }
724
+ };
725
+ return new ol_layer_js.Tile(config);
726
+ };
727
+ /**
728
+ * 创建全国天地图
729
+ * @param layerName - 图层名称
730
+ * @param tk - 天地图TK
731
+ */
732
+ const createMapWorldLayer = (layerName, tk = DEFAULT_TIANDITU_TK) => {
733
+ const [name, matrixSet] = layerName.split("_");
734
+ const config = {
735
+ preload: 1,
736
+ zIndex: -10,
737
+ cacheSize: 20240,
738
+ properties: {
739
+ _isBaseLayer: true,
740
+ _layerName: layerName
741
+ },
742
+ source: new ol_source_js.WMTS({
743
+ crossOrigin: "anonymous",
744
+ projection: "EPSG:4326",
745
+ wrapX: true,
746
+ layer: name,
747
+ style: "default",
748
+ version: "1.0.0",
749
+ format: "image/png",
750
+ matrixSet,
751
+ tileGrid: new ol_tilegrid_WMTS_js.default({
752
+ tileSize: 256,
753
+ origin: [-180, 90],
754
+ matrixIds: [
755
+ "1",
756
+ "2",
757
+ "3",
758
+ "4",
759
+ "5",
760
+ "6",
761
+ "7",
762
+ "8",
763
+ "9",
764
+ "10",
765
+ "11",
766
+ "12",
767
+ "13",
768
+ "14",
769
+ "15",
770
+ "16",
771
+ "17",
772
+ "18",
773
+ "19"
774
+ ],
775
+ resolutions: [
776
+ .703125,
777
+ .3515625,
778
+ .17578125,
779
+ .087890625,
780
+ .0439453125,
781
+ .02197265625,
782
+ .010986328125,
783
+ .0054931640625,
784
+ .00274658203125,
785
+ .001373291015625,
786
+ .0006866455078125,
787
+ .00034332275390625,
788
+ .000171661376953125,
789
+ 858306884765625e-19,
790
+ 4291534423828125e-20,
791
+ 21457672119140625e-21,
792
+ 10728836059570312e-21,
793
+ 5364418029785156e-21,
794
+ 2682209014892578e-21
795
+ ]
796
+ }),
797
+ url: `https://t{0-7}.tianditu.gov.cn/${layerName}/wmts?tk=${tk}`
798
+ })
799
+ };
800
+ return new ol_layer_js.Tile(config);
801
+ };
802
+ /**
803
+ * 创建天地图矢量/影像底图组合。
804
+ * @param tk - 天地图访问令牌
805
+ */
806
+ const baseLayers = (tk) => ({
807
+ baseImgLayer: new ol_layer_js.Tile({
808
+ className: "img-layer",
809
+ source: new ol_source_js.XYZ({
810
+ crossOrigin: "anonymous",
811
+ tileSize: 256,
812
+ url: `https://t{0-7}.tianditu.gov.cn/DataServer?T=img_w&x={x}&y={y}&l={z}&tk=${tk}`
813
+ }),
814
+ zIndex: 1
815
+ }),
816
+ baseCiaLayer: new ol_layer_js.Tile({
817
+ className: "img-layer",
818
+ source: new ol_source_js.XYZ({
819
+ crossOrigin: "anonymous",
820
+ tileSize: 256,
821
+ url: `https://t{0-7}.tianditu.gov.cn/DataServer?T=cia_w&x={x}&y={y}&l={z}&tk=${tk}`
822
+ }),
823
+ zIndex: 2
824
+ }),
825
+ baseVecLayer: new ol_layer_js.Tile({
826
+ className: "vec-layer",
827
+ source: new ol_source_js.XYZ({
828
+ crossOrigin: "anonymous",
829
+ tileSize: 256,
830
+ url: `https://t{0-7}.tianditu.gov.cn/DataServer?T=vec_w&x={x}&y={y}&l={z}&tk=${tk}`
831
+ }),
832
+ zIndex: 1
833
+ }),
834
+ baseCvaLayer: new ol_layer_js.Tile({
835
+ className: "vec-layer",
836
+ source: new ol_source_js.XYZ({
837
+ crossOrigin: "anonymous",
838
+ tileSize: 256,
839
+ url: `https://t{0-7}.tianditu.gov.cn/DataServer?T=cva_w&x={x}&y={y}&l={z}&tk=${tk}`
840
+ }),
841
+ zIndex: 2
842
+ })
843
+ });
844
+ /**
845
+ * 浙江省天地图
846
+ * @param layerName - 图层名称
847
+ * @param tk -
848
+ */
849
+ const createZheJiangLayer = (layerName = "emap", tk = DEFAULT_ZHEJIANG_TOKEN) => {
850
+ return new ol_layer_js.Tile({
851
+ preload: 1,
852
+ minZoom: 4,
853
+ maxZoom: 20,
854
+ zIndex: -10,
855
+ cacheSize: 20240,
856
+ source: new ol_source_js.XYZ({
857
+ wrapX: true,
858
+ projection: "EPSG:4326",
859
+ crossOrigin: "anonymous",
860
+ url: `https://ditu{0-6}.zjzwfw.gov.cn/services/wmts/${layerName}/default/oss/getTile/{z}/{y}/{x}?token=${tk}`
861
+ })
862
+ });
863
+ };
864
+ /**
865
+ * 根据图层名称获取图层
866
+ * @param name
867
+ */
868
+ const getLayerByName = (name) => instance.getAllLayers().find((item) => (item.get("_layerName") || item.getClassName()) === name);
869
+ /**
870
+ * 根据图层名称删除图层
871
+ * @param name
872
+ */
873
+ const removeLayerByName = (name) => {
874
+ const layer = getLayerByName(name);
875
+ if (layer) disposeLayer(instance, layer);
395
876
  };
396
- var changeLayersByNames = (activeNames, allLayerNames) => {
397
- const changeLayers = instance.getAllLayers().filter((item) => allLayerNames.includes(item.getClassName()));
398
- changeLayers.forEach((layer) => {
399
- layer.setVisible(activeNames == null ? void 0 : activeNames.includes(layer.getClassName()));
400
- });
877
+ /**
878
+ * 切换图层的显示、隐藏
879
+ * @param activeNames
880
+ * @param allLayerNames
881
+ */
882
+ const changeLayersByNames = (activeNames, allLayerNames) => {
883
+ instance.getAllLayers().filter((item) => allLayerNames.includes(item.getClassName())).forEach((layer) => {
884
+ layer.setVisible(activeNames?.includes(layer.getClassName()));
885
+ });
401
886
  };
402
887
 
403
- // src/create-map.ts
404
- var instance;
405
- var mapCenter = [119.71512016971076, 30.122490541963536];
406
- var createMapInstance = (config = {}) => {
407
- if (instance) {
408
- return instance;
409
- }
410
- instance = createMap(config);
411
- return instance;
412
- };
413
- var createMap = (config = {}) => {
414
- const innerConfig = Object.assign(
415
- {
416
- zoom: 9.4,
417
- maxZoom: 18,
418
- minZoom: 9.4,
419
- center: mapCenter,
420
- baseLayer: "vec-layer",
421
- projection: "EPSG:4326",
422
- layers: [createBaseLayer()],
423
- constrainResolution: false,
424
- smoothExtentConstraint: false,
425
- tk: DEFAULT_TIANDITU_TK
426
- },
427
- config || {}
428
- );
429
- const map = new import_Map.default({
430
- view: new import_View.default(innerConfig),
431
- controls: (0, import_control.defaults)({
432
- zoom: false,
433
- rotate: false,
434
- attribution: false
435
- }),
436
- interactions: (0, import_interaction.defaults)({
437
- pinchRotate: false,
438
- doubleClickZoom: false,
439
- altShiftDragRotate: false
440
- }),
441
- layers: innerConfig.layers || [createBaseLayer()]
442
- });
443
- mapCenter = innerConfig.center || mapCenter;
444
- map.activeBaseLayer = innerConfig.baseLayer;
445
- map.getLayerByName = getLayerByName;
446
- map.removeLayerByName = removeLayerByName;
447
- map.changeLayersByNames = changeLayersByNames;
448
- map.on("pointermove", (evt) => {
449
- map.getTargetElement().style.cursor = map.hasFeatureAtPixel(evt.pixel) ? "pointer" : "";
450
- });
451
- return map;
452
- };
453
- var disposeMap = () => {
454
- instance.getOverlays().forEach((overlay) => {
455
- instance.removeOverlay(overlay);
456
- });
457
- instance.getInteractions().clear();
458
- const layers = instance.getAllLayers();
459
- layers.forEach((layer) => {
460
- const source = layer.getSource();
461
- if (source && source.dispose) {
462
- source.dispose();
463
- }
464
- instance.removeLayer(layer);
465
- layer.dispose();
466
- });
467
- instance.setTarget("");
468
- instance.dispose();
469
- instance = void 0;
470
- };
471
- var getMapInstance = () => instance;
472
- var resetZoomAndCenter = (center = mapCenter) => {
473
- if (instance) {
474
- const view = instance.getView();
475
- view.animate({
476
- zoom: 9.4,
477
- center,
478
- duration: 1e3
479
- });
480
- }
888
+ //#endregion
889
+ //#region src/layer/raster-layer.ts
890
+ const getDefaultThreadCount = () => Math.max(1, Math.min(4, globalThis.navigator?.hardwareConcurrency ?? 2));
891
+ /** 使用 RGB 比例和目标颜色转换栅格图层。 */
892
+ const changeSource = (layer, rgbColorArray, ratioArray, options = {}) => {
893
+ const rasterSource = new ol_source_Raster_js.default({
894
+ sources: [layer],
895
+ operationType: "image",
896
+ operation: (pixels, data) => {
897
+ const reverseFunc = (pixelArray, operationData) => {
898
+ const operationRatioArray = operationData.ratioArray;
899
+ const operationRgbColorArray = operationData.rgbColorArray;
900
+ if (operationRatioArray && operationRgbColorArray) {
901
+ const [redRatio = 0, greenRatio = 0, blueRatio = 0] = operationRatioArray;
902
+ for (let index = 0; index < pixelArray.length; index += 4) {
903
+ const red = pixelArray[index];
904
+ const green = pixelArray[index + 1];
905
+ const blue = pixelArray[index + 2];
906
+ const grey = red * redRatio + green * greenRatio + blue * blueRatio;
907
+ pixelArray[index] = operationRgbColorArray[0] - grey;
908
+ pixelArray[index + 1] = operationRgbColorArray[1] - grey;
909
+ pixelArray[index + 2] = operationRgbColorArray[2] - grey;
910
+ }
911
+ }
912
+ };
913
+ reverseFunc(pixels[0].data, data);
914
+ return pixels[0];
915
+ },
916
+ threads: options.threads ?? getDefaultThreadCount()
917
+ });
918
+ rasterSource.on("beforeoperations", (event) => {
919
+ event.data.ratioArray = ratioArray;
920
+ event.data.rgbColorArray = rgbColorArray;
921
+ });
922
+ return rasterSource;
923
+ };
924
+ /** 使用 changeSource 创建可显示的 VectorImageLayer。 */
925
+ const changeLayer = (layer, rgbColorArray, ratioArray, options = {}) => new ol_layer_Image_js.default({ source: changeSource(layer, rgbColorArray, ratioArray, options) });
926
+
927
+ //#endregion
928
+ //#region src/overlay/overlay.ts
929
+ /**
930
+ * 移除带指定属性键的 Overlay(默认按 'position')
931
+ * @param key
932
+ */
933
+ const removeOverlays = (key = "") => {
934
+ if (instance) instance.getOverlays().getArray().filter((overlay) => overlay.get(key || "position")).forEach((overlay) => instance.removeOverlay(overlay));
481
935
  };
482
- var resetMap = (config = { center: mapCenter, isClearAll: true }) => {
483
- removeAllLayers();
484
- resetZoomAndCenter(config.center || mapCenter);
936
+ const removeAnimationMarker = () => removeOverlays("_isAnimationMarker");
937
+ /**
938
+ * 创建动画标注 Overlay
939
+ * @param imgUrl
940
+ * @param data
941
+ */
942
+ const createAnimationMarker = (imgUrl, data) => {
943
+ removeAnimationMarker();
944
+ const { width, height, lnglat, crsForm } = data;
945
+ const element = document.createElement("div");
946
+ const image = document.createElement("img");
947
+ image.src = imgUrl;
948
+ image.alt = "";
949
+ if (width !== void 0) image.width = width;
950
+ if (height !== void 0) image.height = height;
951
+ element.append(image);
952
+ const overlay = new ol.Overlay({
953
+ element,
954
+ stopEvent: false,
955
+ positioning: "bottom-center",
956
+ position: gcoord.default.transform([+lnglat[0], +lnglat[1]], crsForm || gcoord.default.WGS84, gcoord.default.WGS84)
957
+ });
958
+ overlay.set("_isAnimationMarker", true);
959
+ instance.addOverlay(overlay);
960
+ };
961
+ /**
962
+ * 创建 Overlay
963
+ * @param config
964
+ */
965
+ const createOverlay = (config = {
966
+ id: "popup-container",
967
+ positioning: "top-center"
968
+ }) => {
969
+ return new ol.Overlay(Object.assign({ element: document.getElementById(config.id) || void 0 }, config));
485
970
  };
486
971
 
487
- // src/helper.ts
488
- var hexToRgba = (hex, alpha) => {
489
- if (hex.startsWith("#")) {
490
- let tempHex = hex.replace("#", "");
491
- if (tempHex.length === 3) {
492
- tempHex = tempHex[0] + tempHex[0] + tempHex[1] + tempHex[1] + tempHex[2] + tempHex[2];
493
- }
494
- const r = parseInt(tempHex.substring(0, 2), 16);
495
- const g = parseInt(tempHex.substring(2, 4), 16);
496
- const b = parseInt(tempHex.substring(4, 6), 16);
497
- return `rgba(${r}, ${g}, ${b}, ${alpha})`;
498
- } else {
499
- return hex;
500
- }
972
+ //#endregion
973
+ //#region src/layer/layer-manager.ts
974
+ /**
975
+ * 重置激活的矢量数据(清空 overlay 与各图层选择交互的要素集合)
976
+ */
977
+ const resetActiveVector = () => {
978
+ removeOverlays();
979
+ instance.getAllLayers().forEach((layer) => {
980
+ layer.get("_selectInteraction")?.getFeatures().clear();
981
+ });
501
982
  };
502
- var getLayersDataList = () => {
503
- var _a;
504
- return ((_a = instance) == null ? void 0 : _a.getAllLayers().map((layer) => layer.get("_dataList") || []).flat(2)) || [];
505
- };
506
- var determineGeometryType = (coordinates) => {
507
- const getArrayDepth = (arr) => {
508
- if (!Array.isArray(arr) || arr.length === 0) return 0;
509
- return 1 + getArrayDepth(arr[0]);
510
- };
511
- const isClosedRing = (coords) => {
512
- if (!Array.isArray(coords) || coords.length < 3) return false;
513
- const first = coords[0];
514
- const last = coords[coords.length - 1];
515
- return first[0] === last[0] && first[1] === last[1];
516
- };
517
- const isValidCoordinate = (coord) => {
518
- return Array.isArray(coord) && coord.length >= 2 && typeof coord[0] === "number" && typeof coord[1] === "number";
519
- };
520
- const isValidLineString = (coords) => {
521
- return Array.isArray(coords) && coords.length >= 2 && coords.every(isValidCoordinate);
522
- };
523
- const isValidPolygon = (coords) => {
524
- if (!Array.isArray(coords)) return false;
525
- const rings = getArrayDepth(coords) === 2 ? [coords] : coords;
526
- return rings.every(
527
- (ring) => Array.isArray(ring) && ring.length >= 4 && isClosedRing(ring) && ring.every(isValidCoordinate)
528
- );
529
- };
530
- const depth = getArrayDepth(coordinates);
531
- try {
532
- if (depth < 2 || !coordinates || coordinates.length === 0) {
533
- return "Invalid" /* Invalid */;
534
- } else if (depth === 2 && isValidLineString(coordinates)) {
535
- return isClosedRing(coordinates) && coordinates.length >= 4 ? "Polygon" /* Polygon */ : "LineString" /* LineString */;
536
- } else if (depth === 3 && Array.isArray(coordinates) && coordinates.every(isValidLineString)) {
537
- if (isValidPolygon(coordinates)) {
538
- return "Polygon" /* Polygon */;
539
- } else if (coordinates.every((arr) => !isClosedRing(arr))) {
540
- return "MultiLineString" /* MultiLineString */;
541
- } else {
542
- return "Invalid" /* Invalid */;
543
- }
544
- } else if (depth === 4 && Array.isArray(coordinates) && coordinates.every((rings) => isValidPolygon(rings))) {
545
- return "MultiPolygon" /* MultiPolygon */;
546
- } else {
547
- return "Invalid" /* Invalid */;
548
- }
549
- } catch (error) {
550
- console.error("Error analyzing coordinates:", error);
551
- return "Invalid" /* Invalid */;
552
- }
983
+ /**
984
+ * 移除覆盖物以及所有非底图自定义图层
985
+ */
986
+ const removeAllLayers = () => {
987
+ removeOverlays();
988
+ if (instance) instance.getAllLayers().forEach((layer) => {
989
+ if (!layer.get("_isBaseLayer")) disposeLayer(instance, layer);
990
+ });
991
+ };
992
+ /**
993
+ * 重置激活 Feature
994
+ */
995
+ const resetActiveFeature = () => {
996
+ removeOverlays();
997
+ instance.getAllLayers().filter((layer) => layer.get("_isVectorLayer")).forEach((layer) => {
998
+ const selectInteraction = layer.get("_selectInteraction");
999
+ if (selectInteraction) {
1000
+ selectInteraction.dispatchEvent({
1001
+ type: "select",
1002
+ selected: [],
1003
+ mapBrowserEvent: void 0,
1004
+ deselected: selectInteraction.getFeatures().getArray()
1005
+ });
1006
+ selectInteraction.getFeatures().clear();
1007
+ }
1008
+ });
1009
+ };
1010
+ /**
1011
+ * 按 _uuid 激活要素
1012
+ * @param uid
1013
+ */
1014
+ const activeFeatureByUid = (uid) => {
1015
+ const targetLayers = instance.getAllLayers().filter((layer) => layer.get("_isVectorLayer"));
1016
+ if (targetLayers.length) {
1017
+ const targetLayer = targetLayers.find((layer) => layer.get("_uuidSet").has(uid) && layer.get("_selectInteraction"));
1018
+ if (targetLayer) {
1019
+ const targetFeature = (targetLayer.getSource()?.getFeatures() || []).find((feature) => feature.get("_uuid") === uid);
1020
+ const selectInteraction = targetLayer.get("_selectInteraction");
1021
+ if (selectInteraction) {
1022
+ const collection = selectInteraction.getFeatures().getArray();
1023
+ if (!collection.find((feature) => feature.get("_uuid") === uid)) {
1024
+ selectInteraction.dispatchEvent({
1025
+ type: "select",
1026
+ deselected: collection,
1027
+ selected: [targetFeature],
1028
+ mapBrowserEvent: void 0
1029
+ });
1030
+ selectInteraction.getFeatures().push(targetFeature);
1031
+ }
1032
+ }
1033
+ }
1034
+ }
553
1035
  };
554
1036
 
555
- // src/ogc-utils.ts
556
- var import_source2 = require("ol/source");
557
- var import_Tile = __toESM(require("ol/layer/Tile"), 1);
558
- var import_format = require("ol/format");
559
- var import_WMTS2 = require("ol/source/WMTS");
560
- var parser = new import_format.WMTSCapabilities();
561
- var capabilitiesMap = /* @__PURE__ */ new Map();
562
- var getCapabilities = (url) => {
563
- return new Promise((resolve) => {
564
- const capabilities = capabilitiesMap.get(url);
565
- if (capabilities) {
566
- resolve(capabilities);
567
- } else {
568
- fetch(url).then((data) => data.text()).then((text) => {
569
- const capabilities2 = parser.read(text);
570
- capabilitiesMap.set(url, capabilities2);
571
- resolve(capabilities2);
572
- });
573
- }
574
- });
575
- };
576
- var createWmtsLayer = (serverUrl) => (config) => __async(null, null, function* () {
577
- const { style, format, version, layerName, matrixSet } = config;
578
- const [workspace, datastore] = layerName.split(":");
579
- const capabilitiesUrl = `${serverUrl}/${workspace}/${datastore}/gwc/service/wmts?request=GetCapabilities`;
580
- return new Promise((resolve, reject) => {
581
- getCapabilities(capabilitiesUrl).then((data) => {
582
- const options = (0, import_WMTS2.optionsFromCapabilities)(data, {
583
- Style: style || "",
584
- layer: datastore,
585
- version: version || "1.1.0",
586
- format: format || "image/png",
587
- matrixSet: matrixSet || "EPSG:4326"
588
- });
589
- if (options) {
590
- resolve(
591
- new import_Tile.default({
592
- zIndex: 3,
593
- className: layerName,
594
- source: new import_source2.WMTS(options)
595
- })
596
- );
597
- } else {
598
- reject(new Error("Unable to create TileLayer"));
599
- }
600
- });
601
- });
1037
+ //#endregion
1038
+ //#region src/map/create-map.ts
1039
+ let mapCenter = [119.71512016971076, 30.122490541963536];
1040
+ const createMapInstance = (config = {}) => {
1041
+ if (instance) return instance;
1042
+ const map = createMap(config);
1043
+ setMapInstance(map);
1044
+ return map;
1045
+ };
1046
+ const createMap = (config = {}) => {
1047
+ const innerConfig = Object.assign({
1048
+ zoom: 9.4,
1049
+ maxZoom: 18,
1050
+ minZoom: 9.4,
1051
+ center: mapCenter,
1052
+ baseLayer: "vec-layer",
1053
+ projection: "EPSG:4326",
1054
+ layers: [createBaseLayer()],
1055
+ constrainResolution: false,
1056
+ smoothExtentConstraint: false,
1057
+ tk: DEFAULT_TIANDITU_TK
1058
+ }, config || {});
1059
+ const map = new ol_Map_js.default({
1060
+ view: new ol_View_js.default(innerConfig),
1061
+ controls: (0, ol_control_js.defaults)({
1062
+ zoom: false,
1063
+ rotate: false,
1064
+ attribution: false
1065
+ }),
1066
+ interactions: (0, ol_interaction_js.defaults)({
1067
+ pinchRotate: false,
1068
+ doubleClickZoom: false,
1069
+ altShiftDragRotate: false
1070
+ }),
1071
+ layers: innerConfig.layers || [createBaseLayer()]
1072
+ });
1073
+ mapCenter = innerConfig.center || mapCenter;
1074
+ map.activeBaseLayer = innerConfig.baseLayer;
1075
+ map.getLayerByName = getLayerByName;
1076
+ map.removeLayerByName = removeLayerByName;
1077
+ map.changeLayersByNames = changeLayersByNames;
1078
+ let pointerMoveFrame;
1079
+ let latestPixel;
1080
+ const cancelPointerMoveFrame = () => {
1081
+ if (pointerMoveFrame === void 0) return;
1082
+ if (typeof globalThis.cancelAnimationFrame === "function") globalThis.cancelAnimationFrame(pointerMoveFrame);
1083
+ else clearTimeout(pointerMoveFrame);
1084
+ pointerMoveFrame = void 0;
1085
+ };
1086
+ map.on("pointermove", (evt) => {
1087
+ latestPixel = evt.pixel;
1088
+ if (pointerMoveFrame !== void 0) return;
1089
+ const updateCursor = () => {
1090
+ pointerMoveFrame = void 0;
1091
+ if (!latestPixel) return;
1092
+ map.getTargetElement().style.cursor = map.hasFeatureAtPixel(latestPixel) ? "pointer" : "";
1093
+ };
1094
+ pointerMoveFrame = typeof globalThis.requestAnimationFrame === "function" ? globalThis.requestAnimationFrame(updateCursor) : setTimeout(updateCursor, 16);
1095
+ });
1096
+ map.set("_disposePointerMove", cancelPointerMoveFrame);
1097
+ return map;
1098
+ };
1099
+ const disposeMap = () => {
1100
+ if (!instance) return;
1101
+ const map = instance;
1102
+ map.get("_disposePointerMove")?.();
1103
+ map.unset("_disposePointerMove");
1104
+ map.getOverlays().forEach((overlay) => {
1105
+ map.removeOverlay(overlay);
1106
+ });
1107
+ map.getInteractions().clear();
1108
+ map.getAllLayers().forEach((layer) => disposeLayer(map, layer));
1109
+ map.setTarget("");
1110
+ map.dispose();
1111
+ clearMapInstance();
1112
+ };
1113
+ /** 兼容别名;复用 map-ol-utils 现有的完整销毁语义。 */
1114
+ const disposeInstance = () => disposeMap();
1115
+ const getMapInstance = () => instance;
1116
+ const resetZoomAndCenter = (center = mapCenter) => {
1117
+ if (instance) instance.getView().animate({
1118
+ zoom: 9.4,
1119
+ center,
1120
+ duration: 1e3
1121
+ });
1122
+ };
1123
+ const resetMap = (config = {
1124
+ center: mapCenter,
1125
+ isClearAll: true
1126
+ }) => {
1127
+ removeAllLayers();
1128
+ resetZoomAndCenter(config.center || mapCenter);
1129
+ };
1130
+
1131
+ //#endregion
1132
+ //#region src/map/view-fit.ts
1133
+ /** 视野自适应的默认参数(padding + 动画时长) */
1134
+ const DEFAULT_FIT_OPTIONS = {
1135
+ padding: [
1136
+ 50,
1137
+ 50,
1138
+ 50,
1139
+ 50
1140
+ ],
1141
+ duration: 1e3
1142
+ };
1143
+ /**
1144
+ * 根据 Array<Coordinate> Fit
1145
+ * @param coords
1146
+ * @param mapInstance
1147
+ * @param fitOptions
1148
+ */
1149
+ const setFitViewByCoords = (coords, mapInstance = instance, fitOptions) => {
1150
+ const view = mapInstance.getView();
1151
+ if (coords.length === 1) view.animate({
1152
+ zoom: 14,
1153
+ duration: 1e3,
1154
+ center: coords[0],
1155
+ ...fitOptions || {}
1156
+ });
1157
+ else {
1158
+ const extent = (0, ol_extent_js.boundingExtent)(coords);
1159
+ view.fit(extent, {
1160
+ ...DEFAULT_FIT_OPTIONS,
1161
+ ...fitOptions || {}
1162
+ });
1163
+ }
1164
+ };
1165
+ /**
1166
+ * 根据 SimpleGeometry Fit
1167
+ * @param geom
1168
+ * @param mapInstance
1169
+ * @param fitOptions
1170
+ */
1171
+ const setFitViewByGeom = (geom, mapInstance = instance, fitOptions) => {
1172
+ mapInstance.getView().fit(geom, {
1173
+ ...DEFAULT_FIT_OPTIONS,
1174
+ ...fitOptions || {}
1175
+ });
1176
+ };
1177
+ /**
1178
+ * 根据 VectorLayer 要素的四至信息 Fit
1179
+ * @param layer
1180
+ * @param mapInstance
1181
+ * @param fitOptions
1182
+ */
1183
+ const setFitViewByLayer = (layer, mapInstance = instance, fitOptions) => {
1184
+ const source = layer.getSource();
1185
+ if (!source || source.isEmpty()) return;
1186
+ const extent = source.getExtent();
1187
+ mapInstance.getView().fit(extent, {
1188
+ ...DEFAULT_FIT_OPTIONS,
1189
+ ...fitOptions || {}
1190
+ });
1191
+ };
1192
+ /** 使用两段缩放动画飞到目标位置。 */
1193
+ const flyToAnimate = (center, zoom) => {
1194
+ const view = instance.getView();
1195
+ const currentZoom = view.getZoom();
1196
+ view.animate({
1197
+ center,
1198
+ duration: 2e3
1199
+ });
1200
+ if (!zoom) view.animate({
1201
+ zoom: currentZoom - 2,
1202
+ duration: 1e3
1203
+ }, {
1204
+ zoom: currentZoom + 2 > 12 ? 12 : currentZoom + 2,
1205
+ duration: 1e3
1206
+ });
1207
+ else view.animate({
1208
+ zoom: zoom - 2,
1209
+ duration: 1e3
1210
+ }, {
1211
+ zoom,
1212
+ duration: 1e3
1213
+ });
1214
+ };
1215
+
1216
+ //#endregion
1217
+ //#region src/layer/marker-layer.ts
1218
+ /** 创建 Marker 文本标注。 */
1219
+ const createText = (item) => new ol_style_js.Text({
1220
+ text: item.text,
1221
+ offsetY: item.offsetY,
1222
+ offsetX: item.offsetX,
1223
+ justify: "center",
1224
+ textAlign: "center",
1225
+ font: "16px PingFangSC-Semibold",
1226
+ fill: new ol_style_js.Fill({ color: "rgba(255, 255, 255, 0.8)" })
1227
+ });
1228
+ /** 创建 Marker 默认态或激活态样式。 */
1229
+ const createIconStyle = (item, active = false) => new ol_style_js.Style({
1230
+ image: new ol_style_js.Icon({
1231
+ scale: item.scale || 1,
1232
+ rotation: item.rotation || 0,
1233
+ anchor: item.anchor || [.5, 1],
1234
+ src: active ? item.activeImg || item.img : item.img
1235
+ }),
1236
+ text: item.showText ? createText(item) : void 0
602
1237
  });
1238
+ /** 创建带 data 属性约定的 Marker Feature。 */
1239
+ const createMarker = (item, config) => {
1240
+ const feature = new ol_Feature_js.default({
1241
+ geometry: new ol_geom_Point_js.default([+item.lng, +item.lat]),
1242
+ data: Object.assign({}, item || {}, { layerName: config.layerName })
1243
+ });
1244
+ feature.setStyle(createIconStyle(item));
1245
+ return feature;
1246
+ };
1247
+ /** 批量创建 Marker 矢量图层。 */
1248
+ const createMarkersLayer = (dataList, config) => {
1249
+ const { layerName, visible = true, zIndex = 10 } = config;
1250
+ const source = new ol_source_Vector_js.default();
1251
+ dataList.forEach((item) => source.addFeature(createMarker(item, config)));
1252
+ return new ol_layer_Vector_js.default({
1253
+ zIndex,
1254
+ visible,
1255
+ source,
1256
+ className: layerName || "marker-layer"
1257
+ });
1258
+ };
1259
+ /** @internal 按当前缩放级别刷新弹性 Marker 的图标。 */
1260
+ const setElasticMarkerStyle = (featureList, currentZoom) => {
1261
+ const imageKey = currentZoom >= 14 ? "largeImg" : currentZoom >= 11 ? "smallImg" : "img";
1262
+ featureList.forEach((feature) => {
1263
+ const config = feature.get("data");
1264
+ if (!config.isSelected) feature.setStyle(createIconStyle({
1265
+ ...config,
1266
+ img: config[imageKey]
1267
+ }, false));
1268
+ });
1269
+ };
1270
+ /** @internal 同步 Marker 选中状态及对应图标样式。 */
1271
+ const setMarkerSelectedState = (feature, selected) => {
1272
+ const config = feature.get("data");
1273
+ const next = {
1274
+ ...config,
1275
+ isSelected: selected
1276
+ };
1277
+ feature.set("data", next);
1278
+ if (config.isElastic) setElasticMarkerStyle([feature], instance.getView().getZoom());
1279
+ else feature.setStyle(createIconStyle(next, selected));
1280
+ };
1281
+ /** 清空外部选择集合并恢复 Marker 未选中样式。 */
1282
+ const changeUnselectStyle = (featureList) => {
1283
+ featureList.forEach((feature) => {
1284
+ setMarkerSelectedState(feature, false);
1285
+ });
1286
+ featureList.clear();
1287
+ };
1288
+ /** 创建随缩放级别切换小图/大图的 Marker 图层。 */
1289
+ const createElasticMarkerLayer = (dataList, config) => {
1290
+ const elasticData = dataList.map((item) => ({
1291
+ ...item,
1292
+ isElastic: true
1293
+ }));
1294
+ const vectorLayer = createMarkersLayer(elasticData, config);
1295
+ const features = vectorLayer.getSource().getFeatures();
1296
+ setElasticMarkerStyle(features, instance.getView().getZoom());
1297
+ instance.getView().on("change:resolution", ({ target }) => {
1298
+ setElasticMarkerStyle(features, target.get("zoom"));
1299
+ });
1300
+ return vectorLayer;
1301
+ };
1302
+ /** 创建单 Marker 图层并直接加入当前地图实例。 */
1303
+ const createMoveMarkerLayer = (dataItem, config) => {
1304
+ const marker = createMarker(dataItem, config);
1305
+ const vectorLayer = new ol_layer_Vector_js.default({
1306
+ className: config.layerName || "ol-layer",
1307
+ source: new ol_source_Vector_js.default({ features: [marker] })
1308
+ });
1309
+ instance.addLayer(vectorLayer);
1310
+ return { vectorLayer };
1311
+ };
603
1312
 
604
- // src/view-fit.ts
605
- var import_extent = require("ol/extent");
606
- var DEFAULT_FIT_OPTIONS = {
607
- padding: [50, 50, 50, 50],
608
- duration: 1e3
609
- };
610
- var setFitViewByCoords = (coords, mapInstance = instance, fitOptions) => {
611
- const view = mapInstance.getView();
612
- if (coords.length === 1) {
613
- view.animate(__spreadValues({
614
- zoom: 14,
615
- duration: 1e3,
616
- center: coords[0]
617
- }, fitOptions || {}));
618
- } else {
619
- const extent = (0, import_extent.boundingExtent)(coords);
620
- view.fit(extent, __spreadValues(__spreadValues({}, DEFAULT_FIT_OPTIONS), fitOptions || {}));
621
- }
1313
+ //#endregion
1314
+ //#region src/interaction/select.ts
1315
+ /**
1316
+ * 处理要素选中:切换激活样式、派发事件、按需自动居中
1317
+ * @param vectorLayer
1318
+ * @param feature
1319
+ */
1320
+ const selectEventHandle = (vectorLayer, feature) => {
1321
+ const data = feature.getProperties();
1322
+ const { activeStyle } = data;
1323
+ feature.setStyle(activeStyle);
1324
+ emitter.emit("selected-feature", data);
1325
+ vectorLayer.set("_hasActive", true);
1326
+ if (vectorLayer.get("_isDynamic")) {
1327
+ const activeImage = activeStyle.getImage();
1328
+ const previousTimer = vectorLayer.get("_dynamicMarkerTimer");
1329
+ if (previousTimer !== void 0) clearTimeout(previousTimer);
1330
+ const timer = setTimeout(() => {
1331
+ vectorLayer.unset("_dynamicMarkerTimer");
1332
+ emitter.emit("dynamic-marker", Object.assign({}, data.rawData || {}, {
1333
+ lnglat: data.lnglat,
1334
+ style: data.style,
1335
+ crsForm: data.crsForm,
1336
+ width: activeImage.getWidth(),
1337
+ height: activeImage.getHeight()
1338
+ }));
1339
+ }, 1e3);
1340
+ vectorLayer.set("_dynamicMarkerTimer", timer);
1341
+ }
1342
+ if (vectorLayer.get("_isAutoFit")) {
1343
+ const view = instance.getView();
1344
+ view.animate({
1345
+ duration: 1e3,
1346
+ zoom: view.getZoom(),
1347
+ center: (0, ol_extent_js.getCenter)(feature.getGeometry().getExtent())
1348
+ });
1349
+ }
622
1350
  };
623
- var setFitViewByGeom = (geom, mapInstance = instance, fitOptions) => {
624
- mapInstance.getView().fit(geom, __spreadValues(__spreadValues({}, DEFAULT_FIT_OPTIONS), fitOptions || {}));
1351
+ /**
1352
+ * 创建点击交互
1353
+ * @param vectorLayer
1354
+ */
1355
+ const createSelectByLayer = (vectorLayer) => {
1356
+ const interaction = new ol_interaction_js.Select({
1357
+ style: null,
1358
+ multi: false,
1359
+ hitTolerance: 10,
1360
+ layers: [vectorLayer],
1361
+ condition: (evt) => {
1362
+ if (!(0, ol_events_condition_js.singleClick)(evt)) return false;
1363
+ let hasFeature = false;
1364
+ instance.forEachFeatureAtPixel(evt.pixel, () => {
1365
+ hasFeature = true;
1366
+ }, { layerFilter: (layer) => layer === vectorLayer });
1367
+ return hasFeature;
1368
+ }
1369
+ });
1370
+ interaction.on("select", (evt) => {
1371
+ const { selected, deselected } = evt;
1372
+ if (selected.length) {
1373
+ const feature = selected[0];
1374
+ if (vectorLayer.get("_isClusterLayer")) {
1375
+ const features = feature.get("features");
1376
+ if (features.length === 1) selectEventHandle(vectorLayer, features[0]);
1377
+ } else selectEventHandle(vectorLayer, feature);
1378
+ }
1379
+ if (deselected.length) {
1380
+ const feature = deselected[0];
1381
+ const data = feature.getProperties();
1382
+ feature.setStyle(data.unActiveStyle);
1383
+ vectorLayer.set("_hasActive", false);
1384
+ }
1385
+ });
1386
+ instance.addInteraction(interaction);
1387
+ vectorLayer.set("_selectInteraction", interaction);
1388
+ return interaction;
625
1389
  };
626
- var setFitViewByLayer = (layer, mapInstance = instance, fitOptions) => {
627
- var _a;
628
- const extent = ((_a = layer.getSource()) == null ? void 0 : _a.getExtent()) || [];
629
- mapInstance.getView().fit(extent, __spreadValues(__spreadValues({}, DEFAULT_FIT_OPTIONS), fitOptions || {}));
1390
+ /** 按多个 className 创建选择交互。 */
1391
+ const createLayerSelectByNames = (layerNames, selectedHandler, unSelectHandler) => {
1392
+ const interaction = new ol_interaction_js.Select({
1393
+ style: null,
1394
+ layers: (layer) => layerNames.includes(layer.getClassName())
1395
+ });
1396
+ interaction.on("select", ({ deselected, selected }) => {
1397
+ if (deselected.length) {
1398
+ const feature = deselected[0];
1399
+ setMarkerSelectedState(feature, false);
1400
+ unSelectHandler?.(feature);
1401
+ }
1402
+ if (selected.length) {
1403
+ const feature = selected[0];
1404
+ setMarkerSelectedState(feature, true);
1405
+ selectedHandler?.(feature);
1406
+ }
1407
+ });
1408
+ return interaction;
630
1409
  };
631
1410
 
632
- // src/select.ts
633
- var import_extent2 = require("ol/extent");
634
- var import_interaction2 = require("ol/interaction");
635
- var import_condition = require("ol/events/condition");
636
- var selectEventHandle = (vectorLayer, feature) => {
637
- const data = feature.getProperties();
638
- const { activeStyle } = data;
639
- feature.setStyle(activeStyle);
640
- emitter_default.emit("selected-feature", data);
641
- vectorLayer.set("_hasActive", true);
642
- if (vectorLayer.get("_isDynamic")) {
643
- const activeImage = activeStyle.getImage();
644
- setTimeout(() => {
645
- emitter_default.emit(
646
- "dynamic-marker",
647
- Object.assign({}, data.rawData || {}, {
648
- lnglat: data.lnglat,
649
- style: data.style,
650
- crsForm: data.crsForm,
651
- width: activeImage.getWidth(),
652
- height: activeImage.getHeight()
653
- })
654
- );
655
- }, 1e3);
656
- }
657
- const isAutoFit = vectorLayer.get("_isAutoFit");
658
- if (isAutoFit) {
659
- const view = instance.getView();
660
- view.animate({
661
- duration: 1e3,
662
- zoom: view.getZoom(),
663
- center: (0, import_extent2.getCenter)(feature.getGeometry().getExtent())
664
- });
665
- }
1411
+ //#endregion
1412
+ //#region src/interaction/draw.ts
1413
+ const formatArea = (polygon) => {
1414
+ const area = (0, ol_sphere_js.getArea)(polygon, { projection: "EPSG:4326" });
1415
+ return area > 1e4 ? `${Math.round(area / 1e6 * 100) / 100} km\xB2` : `${Math.round(area * 100) / 100} m\xB2`;
1416
+ };
1417
+ const formatLength = (line) => {
1418
+ const length = (0, ol_sphere_js.getLength)(line, { projection: "EPSG:4326" });
1419
+ return length > 100 ? `${Math.round(length / 1e3 * 100) / 100} km` : `${Math.round(length * 100) / 100} m`;
1420
+ };
1421
+ const drawDefaultStyle = new ol_style_js.Style({
1422
+ fill: new ol_style_js.Fill({ color: "rgba(255, 255, 255, 0.2)" }),
1423
+ stroke: new ol_style_js.Stroke({
1424
+ color: "rgba(0, 0, 0, 0.5)",
1425
+ lineDash: [10, 10],
1426
+ width: 2
1427
+ }),
1428
+ image: new ol_style_js.Circle({
1429
+ radius: 5,
1430
+ stroke: new ol_style_js.Stroke({ color: "rgba(0, 0, 0, 0.7)" }),
1431
+ fill: new ol_style_js.Fill({ color: "rgba(255, 255, 255, 0.2)" })
1432
+ })
1433
+ });
1434
+ const drawLabelStyleCache = /* @__PURE__ */ new WeakMap();
1435
+ const getOrCreateLabelStyle = (feature) => {
1436
+ const cached = drawLabelStyleCache.get(feature);
1437
+ if (cached) return cached;
1438
+ const style = new ol_style_js.Style({
1439
+ text: new ol_style_js.Text({
1440
+ font: "14px",
1441
+ fill: new ol_style_js.Fill({ color: "rgba(255, 255, 255, 1)" }),
1442
+ backgroundFill: new ol_style_js.Fill({ color: "rgba(0, 0, 0, 0.7)" }),
1443
+ padding: [
1444
+ 3,
1445
+ 3,
1446
+ 3,
1447
+ 3
1448
+ ],
1449
+ textBaseline: "bottom",
1450
+ offsetY: -15
1451
+ }),
1452
+ image: new ol_style_js.RegularShape({
1453
+ radius: 8,
1454
+ points: 3,
1455
+ angle: Math.PI,
1456
+ displacement: [0, 10],
1457
+ fill: new ol_style_js.Fill({ color: "rgba(0, 0, 0, 0.7)" })
1458
+ })
1459
+ });
1460
+ drawLabelStyleCache.set(feature, style);
1461
+ return style;
666
1462
  };
667
- var createSelectByLayer = (vectorLayer) => {
668
- const interaction = new import_interaction2.Select({
669
- style: null,
670
- multi: false,
671
- hitTolerance: 10,
672
- layers: [vectorLayer],
673
- condition: (evt) => {
674
- let hasFeature = false;
675
- instance.forEachFeatureAtPixel(
676
- evt.pixel,
677
- () => {
678
- hasFeature = true;
679
- },
680
- {
681
- layerFilter: (layer) => layer === vectorLayer
682
- }
683
- );
684
- return (0, import_condition.singleClick)(evt) && hasFeature;
685
- }
686
- });
687
- interaction.on("select", (evt) => {
688
- const { selected, deselected } = evt;
689
- if (selected.length) {
690
- const feature = selected[0];
691
- const isClusterLayer = vectorLayer.get("_isClusterLayer");
692
- if (isClusterLayer) {
693
- const features = feature.get("features");
694
- if (features.length === 1) {
695
- selectEventHandle(vectorLayer, features[0]);
696
- }
697
- } else {
698
- selectEventHandle(vectorLayer, feature);
699
- }
700
- }
701
- if (deselected.length) {
702
- const feature = deselected[0];
703
- const data = feature.getProperties();
704
- feature.setStyle(data.unActiveStyle);
705
- vectorLayer.set("_hasActive", false);
706
- }
707
- });
708
- instance.addInteraction(interaction);
709
- vectorLayer.set("_selectInteraction", interaction);
710
- return interaction;
1463
+ /** 为绘制中的线和面追加长度/面积标签。 */
1464
+ const getDrawStyle = (feature, drawStyle = drawDefaultStyle) => {
1465
+ const styles = drawStyle ? [drawStyle] : [];
1466
+ const geometry = feature.getGeometry();
1467
+ let point;
1468
+ let label;
1469
+ if (geometry.getType() === "Polygon") {
1470
+ point = geometry.getInteriorPoint();
1471
+ label = formatArea(geometry);
1472
+ } else if (geometry.getType() === "LineString") {
1473
+ point = new ol_geom_Point_js.default(geometry.getLastCoordinate());
1474
+ label = formatLength(geometry);
1475
+ }
1476
+ if (point && label) {
1477
+ const labelStyle = getOrCreateLabelStyle(feature);
1478
+ labelStyle.setGeometry(point);
1479
+ labelStyle.getText().setText(label);
1480
+ styles.push(labelStyle);
1481
+ }
1482
+ return styles;
711
1483
  };
1484
+ /** 创建绘制交互。 */
1485
+ const createDrawInteraction = (type = "Point", vectorLayer, openTip) => new ol_interaction_Draw_js.default({
1486
+ source: vectorLayer.getSource(),
1487
+ type,
1488
+ style: openTip ? (feature) => getDrawStyle(feature, void 0) : void 0
1489
+ });
712
1490
 
713
- // src/vector-layer.ts
714
- var import_format2 = require("ol/format");
715
- var import_gcoord2 = __toESM(require("gcoord"), 1);
716
- var import_Vector = __toESM(require("ol/layer/Vector"), 1);
717
- var import_Vector2 = __toESM(require("ol/source/Vector"), 1);
718
- var import_style = require("ol/style");
719
- var resolveColor = (data, colorKey, colorMap, fallback) => colorKey ? (colorMap == null ? void 0 : colorMap.get(data[colorKey])) || fallback : fallback;
720
- var assembleGeoJson = (dataList, config) => {
721
- const { key, crsForm } = config;
722
- const tempList = [];
723
- dataList.forEach((item) => {
724
- try {
725
- const raw = item[key];
726
- const pathArray = Array.isArray(raw) ? raw : JSON.parse(raw || "[]");
727
- if (pathArray.length) {
728
- const type = item["geoType"] || determineGeometryType(pathArray);
729
- if (type !== "Invalid" /* Invalid */) {
730
- tempList.push({
731
- type: "Feature",
732
- properties: __spreadValues({}, item),
733
- geometry: {
734
- type,
735
- coordinates: pathArray
736
- }
737
- });
738
- }
739
- }
740
- } catch (e) {
741
- console.error(`\u521B\u5EFA\u7EBF\u72B6\u6570\u636E\u5931\u8D25\uFF1A${e}`);
742
- }
743
- });
744
- return import_gcoord2.default.transform(
745
- { type: "FeatureCollection", features: tempList },
746
- crsForm || import_gcoord2.default.WGS84,
747
- import_gcoord2.default.WGS84
748
- );
749
- };
750
- var createVectorStyle = (feature, config) => {
751
- const {
752
- isLine,
753
- colorMap,
754
- fillColor,
755
- colorKey,
756
- strokeColor,
757
- fillOpacity,
758
- strokeWeight,
759
- activeFillColor,
760
- activeFillOpacity,
761
- activeStrokeColor,
762
- activeStrokeWeight
763
- } = config || {};
764
- const data = feature.getProperties();
765
- const activeStyle = new import_style.Style({
766
- stroke: new import_style.Stroke({
767
- width: activeStrokeWeight || strokeWeight || 4,
768
- color: activeStrokeColor || resolveColor(data, colorKey, colorMap, strokeColor)
769
- })
770
- });
771
- const unActiveStyle = new import_style.Style({
772
- stroke: new import_style.Stroke({
773
- width: strokeWeight || 2,
774
- color: resolveColor(data, colorKey, colorMap, strokeColor)
775
- })
776
- });
777
- if (!isLine) {
778
- activeStyle.setFill(
779
- new import_style.Fill({
780
- color: hexToRgba(
781
- activeFillColor || fillColor || "",
782
- activeFillOpacity || 1
783
- ) || hexToRgba(
784
- resolveColor(data, colorKey, colorMap, fillColor) || "",
785
- fillOpacity || 1
786
- )
787
- })
788
- );
789
- unActiveStyle.setFill(
790
- new import_style.Fill({
791
- color: hexToRgba(
792
- resolveColor(data, colorKey, colorMap, fillColor) || "",
793
- fillOpacity || 1
794
- )
795
- })
796
- );
797
- }
798
- feature.setProperties({
799
- activeStyle,
800
- unActiveStyle
801
- });
802
- return unActiveStyle;
803
- };
804
- var createBusinessLayer = (dataList, config) => {
805
- const { isAutoFit, layerName, openClick } = config;
806
- const geoJson = assembleGeoJson(dataList, config);
807
- const vectorLayer = new import_Vector.default({
808
- zIndex: 5,
809
- className: layerName ? layerName : "ol-layer",
810
- source: new import_Vector2.default({
811
- features: new import_format2.GeoJSON().readFeatures(geoJson).map((feature) => {
812
- feature.setStyle(createVectorStyle(feature, config));
813
- return feature;
814
- })
815
- })
816
- });
817
- if (openClick) {
818
- createSelectByLayer(vectorLayer);
819
- }
820
- vectorLayer.setProperties({
821
- _isCustom: true,
822
- _isAutoFit: isAutoFit,
823
- _isVectorLayer: true,
824
- _vectorConfig: config,
825
- _layerName: layerName,
826
- _dataList: [...dataList],
827
- _uuidSet: new Set(dataList.map((item) => item._uuid) || [])
828
- });
829
- return vectorLayer;
830
- };
831
- var appendFeaturesByLayer = (targetLayer, dataList, crsForm) => {
832
- const vectorSource = targetLayer.getSource();
833
- const tempSet = targetLayer.get("_uuidSet") || /* @__PURE__ */ new Set();
834
- dataList.forEach((item) => tempSet.add(item._uuid));
835
- targetLayer.set("_uuidSet", tempSet);
836
- const { _vectorConfig: config } = targetLayer.getProperties() || {};
837
- const geoJson = assembleGeoJson(
838
- dataList,
839
- Object.assign({}, config, { crsForm })
840
- );
841
- vectorSource.addFeatures(
842
- new import_format2.GeoJSON().readFeatures(geoJson).map((feature) => {
843
- feature.setStyle(createVectorStyle(feature, config));
844
- return feature;
845
- })
846
- );
847
- };
848
- var createVectorFaceLayer = (dataList = [], config) => createBusinessLayer(dataList, Object.assign({}, config, { isLine: false }));
849
- var createVectorLineLayer = (dataList = [], config) => createBusinessLayer(dataList, Object.assign({}, config, { isLine: true }));
1491
+ //#endregion
1492
+ //#region src/layer/geojson-layer.ts
1493
+ /** 直接从 GeoJSON 创建矢量图层。 */
1494
+ const createGeoJsonLayer = (geoJson, style, config) => {
1495
+ const { layerName } = config || {};
1496
+ const layerConfig = Object.assign({
1497
+ className: layerName || "ol-layer",
1498
+ source: new ol_source_Vector_js.default({ features: new ol_format_GeoJSON_js.default().readFeatures(geoJson) }),
1499
+ style: style || new ol_style_js.Style({
1500
+ stroke: new ol_style_js.Stroke({
1501
+ color: "red",
1502
+ lineDash: [10],
1503
+ width: 3
1504
+ }),
1505
+ fill: new ol_style_js.Fill({ color: "rgba(0, 0, 255, 0.1)" })
1506
+ })
1507
+ }, config || {});
1508
+ return new ol_layer_Vector_js.default(layerConfig);
1509
+ };
850
1510
 
851
- // src/mass-marks.ts
852
- var import_ol2 = require("ol");
853
- var import_geom = require("ol/geom");
854
- var import_gcoord3 = __toESM(require("gcoord"), 1);
855
- var import_style2 = require("ol/style");
856
- var import_Vector3 = __toESM(require("ol/layer/Vector"), 1);
857
- var import_Vector4 = __toESM(require("ol/source/Vector"), 1);
858
- var buildMassMarksStyles = (getImgUrlFn) => {
859
- return (iconConfig) => {
860
- const {
861
- baseUrl,
862
- markerIcon,
863
- statusNum = 5,
864
- activeScale = 1.3,
865
- markerSize = [32, 32]
866
- } = iconConfig;
867
- const getMarkerUrl = getImgUrlFn(baseUrl);
868
- const [x, y] = markerSize;
869
- const massMarksStyles = new Array(statusNum * 2);
870
- for (let i = 0; i < statusNum; i++) {
871
- const imageUrl = getMarkerUrl(`${markerIcon}-${i}`, ".webp");
872
- massMarksStyles[i] = new import_style2.Style({
873
- zIndex: 88 + i,
874
- image: new import_style2.Icon({
875
- width: x,
876
- height: y,
877
- src: imageUrl,
878
- anchor: [0.5, 1]
879
- })
880
- });
881
- const activeImage = getMarkerUrl(`${markerIcon}-${i}-active`, ".webp");
882
- massMarksStyles[i + statusNum] = new import_style2.Style({
883
- zIndex: 120,
884
- image: new import_style2.Icon({
885
- width: x * activeScale,
886
- height: y * activeScale,
887
- anchor: [0.5, 1],
888
- src: activeImage ? activeImage : imageUrl
889
- })
890
- });
891
- }
892
- return massMarksStyles;
893
- };
894
- };
895
- var createFeatures = (dataList, styleList = []) => {
896
- return dataList.map((item) => {
897
- const { crsForm } = item;
898
- const coord = import_gcoord3.default.transform(
899
- [+item.lnglat[0], +item.lnglat[1]],
900
- crsForm || import_gcoord3.default.WGS84,
901
- import_gcoord3.default.WGS84
902
- );
903
- const feature = new import_ol2.Feature({
904
- geometry: new import_geom.Point(coord)
905
- });
906
- feature.setProperties(__spreadProps(__spreadValues({}, item), {
907
- unActiveStyle: styleList[item.style],
908
- activeStyle: styleList[item.style + styleList.length / 2]
909
- }));
910
- feature.setStyle(styleList[item.style]);
911
- return feature;
912
- });
913
- };
914
- var addFeaturesByLayer = (targetLayer, dataList, config) => {
915
- const massMarksStyles = targetLayer.get("_massMarksStyles");
916
- const targetSource = targetLayer == null ? void 0 : targetLayer.getSource();
917
- const { clear } = config;
918
- if (clear) {
919
- targetSource == null ? void 0 : targetSource.clear();
920
- }
921
- targetSource == null ? void 0 : targetSource.addFeatures(createFeatures(dataList, massMarksStyles));
922
- };
923
- var createMassMarksLayer = (dataList, styleList = []) => {
924
- const vectorLayer = new import_Vector3.default({
925
- zIndex: 2e3,
926
- source: new import_Vector4.default({
927
- features: createFeatures(dataList, styleList)
928
- })
929
- });
930
- vectorLayer.setProperties({
931
- _isCustom: true,
932
- _isVectorLayer: true,
933
- _isMassMarksLayer: true,
934
- _statusNum: styleList.length / 2,
935
- _dataList: [...dataList],
936
- _uuidSet: new Set(dataList.map((item) => item._uuid) || [])
937
- });
938
- return vectorLayer;
939
- };
940
- var addMassMarksLayer = (getImgUrlFn) => {
941
- return (dataList = [], iconConfig, openClick = true) => {
942
- const {
943
- offset = [0, 0],
944
- baseUrl,
945
- hasLine,
946
- hasFace,
947
- layerName,
948
- isDynamic,
949
- isAutoFit,
950
- statusNum,
951
- markerIcon,
952
- marksStyles,
953
- markerSize,
954
- activeScale,
955
- vectorConfig
956
- } = iconConfig;
957
- const massMarksStyles = marksStyles ? marksStyles : buildMassMarksStyles(getImgUrlFn)({
958
- baseUrl,
959
- markerIcon,
960
- markerSize,
961
- statusNum: statusNum || 5,
962
- activeScale: activeScale || 1.3
963
- });
964
- const massMarksLayer = createMassMarksLayer(dataList, massMarksStyles);
965
- if (openClick) {
966
- massMarksLayer.setProperties({
967
- _offset: offset,
968
- _isAutoFit: isAutoFit
969
- });
970
- createSelectByLayer(massMarksLayer);
971
- }
972
- if (hasLine) {
973
- const vectorLayer = createBusinessLayer(
974
- dataList,
975
- Object.assign(
976
- {},
977
- {
978
- key: "line",
979
- isLine: true,
980
- openClick: false,
981
- strokeWeight: 4,
982
- strokeColor: "rgba(29, 235, 255, 0.8)"
983
- },
984
- vectorConfig || {}
985
- )
986
- );
987
- instance.addLayer(vectorLayer);
988
- }
989
- if (hasFace) {
990
- const vectorLayer = createBusinessLayer(
991
- dataList,
992
- Object.assign(
993
- {},
994
- {
995
- isLine: false,
996
- key: "faceList",
997
- strokeWeight: 1,
998
- openClick: false,
999
- fillColor: "#4247DF",
1000
- strokeStyle: "dashed",
1001
- strokeColor: "#4247DF"
1002
- },
1003
- vectorConfig || {}
1004
- )
1005
- );
1006
- instance.addLayer(vectorLayer);
1007
- }
1008
- massMarksLayer.setProperties({
1009
- _isCustom: true,
1010
- _offset: offset,
1011
- _hasLine: hasLine,
1012
- _hasFace: hasFace,
1013
- className: layerName,
1014
- _layerName: layerName,
1015
- _isVectorLayer: true,
1016
- _isDynamic: isDynamic,
1017
- _massMarksStyles: massMarksStyles
1018
- });
1019
- instance.addLayer(massMarksLayer);
1020
- return massMarksLayer;
1021
- };
1022
- };
1023
- var updateMarksLayersByStatus = (checkedStatusList = []) => {
1024
- const hideStyle = new import_style2.Style({});
1025
- const tempList = [];
1026
- const targetLayers = instance.getAllLayers().filter((layer) => layer.get("_isMassMarksLayer"));
1027
- targetLayers.forEach((layer) => {
1028
- const features = layer.getSource().getFeatures();
1029
- features.forEach((feature) => {
1030
- const data = feature.getProperties();
1031
- if (!checkedStatusList.includes(data.status)) {
1032
- feature.setStyle(hideStyle);
1033
- } else {
1034
- tempList.push(data);
1035
- feature.setStyle(data.unActiveStyle);
1036
- }
1037
- });
1038
- });
1039
- return tempList;
1511
+ //#endregion
1512
+ //#region src/layer/vector-layer.ts
1513
+ /**
1514
+ * 按 colorKey/colorMap 解析颜色,未命中时回退到 fallback
1515
+ */
1516
+ const resolveColor = (data, colorKey, colorMap, fallback) => colorKey ? colorMap?.get(data[colorKey]) || fallback : fallback;
1517
+ /**
1518
+ * 组装业务数据为 GeoJson(坐标统一转 WGS84)
1519
+ * @param dataList
1520
+ * @param config
1521
+ */
1522
+ const assembleGeoJson = (dataList, config) => {
1523
+ const { key, crsForm } = config;
1524
+ const tempList = [];
1525
+ dataList.forEach((item) => {
1526
+ try {
1527
+ const raw = item[key];
1528
+ const pathArray = Array.isArray(raw) ? raw : JSON.parse(raw || "[]");
1529
+ if (pathArray.length) {
1530
+ const type = item["geoType"] || determineGeometryType(pathArray);
1531
+ if (type !== "Invalid") tempList.push({
1532
+ type: "Feature",
1533
+ properties: { ...item },
1534
+ geometry: {
1535
+ type,
1536
+ coordinates: pathArray
1537
+ }
1538
+ });
1539
+ }
1540
+ } catch (e) {
1541
+ console.error(`创建线状数据失败:${e}`);
1542
+ }
1543
+ });
1544
+ return gcoord.default.transform({
1545
+ type: "FeatureCollection",
1546
+ features: tempList
1547
+ }, crsForm || gcoord.default.WGS84, gcoord.default.WGS84);
1548
+ };
1549
+ const createVectorStyle = (feature, config) => {
1550
+ const { isLine, colorMap, fillColor, colorKey, strokeColor, fillOpacity, strokeWeight, activeFillColor, activeFillOpacity, activeStrokeColor, activeStrokeWeight } = config || {};
1551
+ const data = feature.getProperties();
1552
+ const activeStyle = new ol_style_js.Style({ stroke: new ol_style_js.Stroke({
1553
+ width: activeStrokeWeight ?? strokeWeight ?? 4,
1554
+ color: activeStrokeColor || resolveColor(data, colorKey, colorMap, strokeColor)
1555
+ }) });
1556
+ const unActiveStyle = new ol_style_js.Style({ stroke: new ol_style_js.Stroke({
1557
+ width: strokeWeight ?? 2,
1558
+ color: resolveColor(data, colorKey, colorMap, strokeColor)
1559
+ }) });
1560
+ if (!isLine) {
1561
+ activeStyle.setFill(new ol_style_js.Fill({ color: hexToRgba(activeFillColor || fillColor || "", activeFillOpacity ?? fillOpacity ?? 1) || hexToRgba(resolveColor(data, colorKey, colorMap, fillColor) || "", fillOpacity ?? 1) }));
1562
+ unActiveStyle.setFill(new ol_style_js.Fill({ color: hexToRgba(resolveColor(data, colorKey, colorMap, fillColor) || "", fillOpacity ?? 1) }));
1563
+ }
1564
+ feature.setProperties({
1565
+ activeStyle,
1566
+ unActiveStyle
1567
+ });
1568
+ return unActiveStyle;
1569
+ };
1570
+ const readBusinessFeatures = (dataList, config) => {
1571
+ const geoJson = assembleGeoJson(dataList, config);
1572
+ const features = new ol_format_js.GeoJSON().readFeatures(geoJson);
1573
+ const acceptedData = features.map((feature) => {
1574
+ const data = { ...feature.getProperties() };
1575
+ delete data.geometry;
1576
+ return data;
1577
+ });
1578
+ features.forEach((feature) => {
1579
+ feature.setStyle(createVectorStyle(feature, config));
1580
+ });
1581
+ return {
1582
+ features,
1583
+ acceptedData
1584
+ };
1585
+ };
1586
+ /**
1587
+ * 创建业务矢量图层(自动推断线/面,生成默认/激活样式)
1588
+ * @param dataList
1589
+ * @param config
1590
+ */
1591
+ const createBusinessLayer = (dataList, config) => {
1592
+ const { isAutoFit, layerName, openClick } = config;
1593
+ const { features, acceptedData } = readBusinessFeatures(dataList, config);
1594
+ const vectorLayer = new ol_layer_Vector_js.default({
1595
+ zIndex: 5,
1596
+ className: layerName ? layerName : "ol-layer",
1597
+ source: new ol_source_Vector_js.default({ features })
1598
+ });
1599
+ if (openClick) createSelectByLayer(vectorLayer);
1600
+ vectorLayer.setProperties({
1601
+ _isCustom: true,
1602
+ _isAutoFit: isAutoFit,
1603
+ _isVectorLayer: true,
1604
+ _vectorConfig: config,
1605
+ _layerName: layerName,
1606
+ _dataList: acceptedData,
1607
+ _uuidSet: new Set(acceptedData.map((item) => item._uuid))
1608
+ });
1609
+ return vectorLayer;
1610
+ };
1611
+ /**
1612
+ * 追加 Features
1613
+ * @param targetLayer
1614
+ * @param dataList
1615
+ * @param crsForm
1616
+ */
1617
+ const appendFeaturesByLayer = (targetLayer, dataList, crsForm) => {
1618
+ const vectorSource = targetLayer.getSource();
1619
+ const { _vectorConfig: config } = targetLayer.getProperties() || {};
1620
+ const { features, acceptedData } = readBusinessFeatures(dataList, Object.assign({}, config, { crsForm }));
1621
+ vectorSource.addFeatures(features);
1622
+ const uuidSet = new Set(targetLayer.get("_uuidSet") || []);
1623
+ acceptedData.forEach((item) => uuidSet.add(item._uuid));
1624
+ targetLayer.set("_uuidSet", uuidSet);
1625
+ targetLayer.set("_dataList", [...targetLayer.get("_dataList") || [], ...acceptedData]);
1040
1626
  };
1627
+ /**
1628
+ * 创建面状图层
1629
+ * @param dataList
1630
+ * @param config
1631
+ */
1632
+ const createVectorFaceLayer = (dataList = [], config) => createBusinessLayer(dataList, Object.assign({}, config, { isLine: false }));
1633
+ /**
1634
+ * 创建矢量线图层
1635
+ * @param dataList
1636
+ * @param config
1637
+ */
1638
+ const createVectorLineLayer = (dataList = [], config) => createBusinessLayer(dataList, Object.assign({}, config, { isLine: true }));
1041
1639
 
1042
- // src/cluster.ts
1043
- var import_ol3 = require("ol");
1044
- var import_geom2 = require("ol/geom");
1045
- var import_Cluster = __toESM(require("ol/source/Cluster"), 1);
1046
- var import_Circle = __toESM(require("ol/style/Circle"), 1);
1047
- var import_Vector5 = __toESM(require("ol/layer/Vector"), 1);
1048
- var import_Vector6 = __toESM(require("ol/source/Vector"), 1);
1049
- var import_style3 = require("ol/style");
1050
- var createClusterLayer = (dataList, config) => {
1051
- const count = dataList.length;
1052
- const styleCache = {};
1053
- const {
1054
- distance,
1055
- minDistance,
1056
- openClick,
1057
- buildStyle,
1058
- singleStyles,
1059
- computedRadius,
1060
- layerName = "cluster-layer"
1061
- } = config;
1062
- const innerComputedRadius = (size) => Math.pow(size / count, 1 / 18);
1063
- styleCache[1] = singleStyles;
1064
- const innerBuildStyle = (feature) => {
1065
- const size = feature.get("features").length;
1066
- let style = styleCache[size];
1067
- const tempRadius = computedRadius ? computedRadius(size) : innerComputedRadius(size);
1068
- if (!style) {
1069
- style = new import_style3.Style({
1070
- image: new import_Circle.default({
1071
- radius: tempRadius * 20,
1072
- stroke: new import_style3.Stroke({
1073
- width: 2,
1074
- color: `hsla(${180 - tempRadius * 180}, 100%, 40%, 1)`
1075
- }),
1076
- fill: new import_style3.Fill({
1077
- color: `hsla(${180 - tempRadius * 180}, 100%, 50%, 1)`
1078
- })
1079
- }),
1080
- text: new import_style3.Text({
1081
- text: size.toString(),
1082
- fill: new import_style3.Fill({
1083
- color: `hsla(${180 - tempRadius * 180}, 100%, 10%, 1)`
1084
- }),
1085
- textBaseline: "middle"
1086
- })
1087
- });
1088
- styleCache[size] = style;
1089
- }
1090
- if (Array.isArray(style)) {
1091
- const tempFeature = feature.get("features")[0];
1092
- const index = tempFeature.get("styleIndex") || 0;
1093
- tempFeature.setProperties({
1094
- unActiveStyle: style[index],
1095
- activeStyle: style[index + style.length / 2]
1096
- });
1097
- return style[index];
1098
- }
1099
- return style;
1100
- };
1101
- const vectorLayer = new import_Vector5.default({
1102
- zIndex: 200,
1103
- className: layerName,
1104
- source: new import_Cluster.default({
1105
- distance: distance || 80,
1106
- minDistance: minDistance || 0,
1107
- source: new import_Vector6.default({
1108
- features: dataList.map((item) => {
1109
- const feature = new import_ol3.Feature(new import_geom2.Point(item.lnglat));
1110
- feature.setProperties(item);
1111
- return feature;
1112
- })
1113
- })
1114
- }),
1115
- style: (feature) => buildStyle ? buildStyle(feature) : innerBuildStyle(feature)
1116
- });
1117
- vectorLayer.setProperties({
1118
- _isCustom: true,
1119
- _isVectorLayer: true,
1120
- _isClusterLayer: true
1121
- });
1122
- if (openClick) {
1123
- createSelectByLayer(vectorLayer);
1640
+ //#endregion
1641
+ //#region src/layer/mass-marks.ts
1642
+ /**
1643
+ * 构建 MassMarks 样式数组(默认段 + 激活段,长度 statusNum * 2)
1644
+ */
1645
+ const buildMassMarksStyles = (getImgUrlFn) => {
1646
+ return (iconConfig) => {
1647
+ const { baseUrl, markerIcon, statusNum = 5, activeScale = 1.3, markerSize = [32, 32] } = iconConfig;
1648
+ const getMarkerUrl = getImgUrlFn(baseUrl);
1649
+ const [x, y] = markerSize;
1650
+ const massMarksStyles = new Array(statusNum * 2);
1651
+ for (let i = 0; i < statusNum; i++) {
1652
+ const imageUrl = getMarkerUrl(`${markerIcon}-${i}`, ".webp");
1653
+ massMarksStyles[i] = new ol_style_js.Style({
1654
+ zIndex: 88 + i,
1655
+ image: new ol_style_js.Icon({
1656
+ width: x,
1657
+ height: y,
1658
+ src: imageUrl,
1659
+ anchor: [.5, 1]
1660
+ })
1661
+ });
1662
+ const activeImage = getMarkerUrl(`${markerIcon}-${i}-active`, ".webp");
1663
+ massMarksStyles[i + statusNum] = new ol_style_js.Style({
1664
+ zIndex: 120,
1665
+ image: new ol_style_js.Icon({
1666
+ width: x * activeScale,
1667
+ height: y * activeScale,
1668
+ anchor: [.5, 1],
1669
+ src: activeImage ? activeImage : imageUrl
1670
+ })
1671
+ });
1672
+ }
1673
+ return massMarksStyles;
1674
+ };
1675
+ };
1676
+ const createFeatures = (dataList, styleList = []) => {
1677
+ return dataList.map((item) => {
1678
+ const { crsForm } = item;
1679
+ const coord = gcoord.default.transform([+item.lnglat[0], +item.lnglat[1]], crsForm || gcoord.default.WGS84, gcoord.default.WGS84);
1680
+ const feature = new ol.Feature({ geometry: new ol_geom_js.Point(coord) });
1681
+ feature.setProperties({
1682
+ ...item,
1683
+ unActiveStyle: styleList[item.style],
1684
+ activeStyle: styleList[item.style + styleList.length / 2]
1685
+ });
1686
+ feature.setStyle(styleList[item.style]);
1687
+ return feature;
1688
+ });
1689
+ };
1690
+ /**
1691
+ * 向海量点图层增量添加 Features
1692
+ * @param targetLayer
1693
+ * @param dataList
1694
+ * @param config
1695
+ */
1696
+ const addFeaturesByLayer = (targetLayer, dataList, config = {}) => {
1697
+ const massMarksStyles = targetLayer.get("_massMarksStyles");
1698
+ const targetSource = targetLayer?.getSource();
1699
+ const { clear } = config;
1700
+ const features = createFeatures(dataList, massMarksStyles);
1701
+ if (clear) targetSource?.clear();
1702
+ targetSource?.addFeatures(features);
1703
+ const nextData = [...clear ? [] : targetLayer.get("_dataList") || [], ...dataList];
1704
+ targetLayer.set("_dataList", nextData);
1705
+ targetLayer.set("_uuidSet", new Set(nextData.map((item) => item._uuid)));
1706
+ };
1707
+ /**
1708
+ * 创建 massMarksLayer
1709
+ * @param dataList
1710
+ * @param styleList
1711
+ */
1712
+ const createMassMarksLayer = (dataList, styleList = []) => {
1713
+ const vectorLayer = new ol_layer_Vector_js.default({
1714
+ zIndex: 2e3,
1715
+ source: new ol_source_Vector_js.default({ features: createFeatures(dataList, styleList) })
1716
+ });
1717
+ vectorLayer.setProperties({
1718
+ _isCustom: true,
1719
+ _isVectorLayer: true,
1720
+ _isMassMarksLayer: true,
1721
+ _statusNum: styleList.length / 2,
1722
+ _dataList: [...dataList],
1723
+ _uuidSet: new Set(dataList.map((item) => item._uuid) || [])
1724
+ });
1725
+ return vectorLayer;
1726
+ };
1727
+ /**
1728
+ * 添加 massMarksLayer(按需附带线/面图层)
1729
+ * @param getImgUrlFn
1730
+ */
1731
+ const addMassMarksLayer = (getImgUrlFn) => {
1732
+ return (dataList = [], iconConfig, openClick = true) => {
1733
+ const { offset = [0, 0], baseUrl, hasLine, hasFace, layerName, isDynamic, isAutoFit, statusNum, markerIcon, marksStyles, markerSize, activeScale, vectorConfig } = iconConfig;
1734
+ const massMarksStyles = marksStyles ? marksStyles : buildMassMarksStyles(getImgUrlFn)({
1735
+ baseUrl,
1736
+ markerIcon,
1737
+ markerSize,
1738
+ statusNum: statusNum || 5,
1739
+ activeScale: activeScale || 1.3
1740
+ });
1741
+ const massMarksLayer = createMassMarksLayer(dataList, massMarksStyles);
1742
+ if (openClick) {
1743
+ massMarksLayer.setProperties({
1744
+ _offset: offset,
1745
+ _isAutoFit: isAutoFit
1746
+ });
1747
+ createSelectByLayer(massMarksLayer);
1748
+ }
1749
+ if (hasLine) {
1750
+ const vectorLayer = createBusinessLayer(dataList, Object.assign({}, {
1751
+ key: "line",
1752
+ isLine: true,
1753
+ openClick: false,
1754
+ strokeWeight: 4,
1755
+ strokeColor: "rgba(29, 235, 255, 0.8)"
1756
+ }, vectorConfig || {}));
1757
+ instance.addLayer(vectorLayer);
1758
+ }
1759
+ if (hasFace) {
1760
+ const vectorLayer = createBusinessLayer(dataList, Object.assign({}, {
1761
+ isLine: false,
1762
+ key: "faceList",
1763
+ strokeWeight: 1,
1764
+ openClick: false,
1765
+ fillColor: "#4247DF",
1766
+ strokeStyle: "dashed",
1767
+ strokeColor: "#4247DF"
1768
+ }, vectorConfig || {}));
1769
+ instance.addLayer(vectorLayer);
1770
+ }
1771
+ massMarksLayer.setProperties({
1772
+ _isCustom: true,
1773
+ _offset: offset,
1774
+ _hasLine: hasLine,
1775
+ _hasFace: hasFace,
1776
+ className: layerName,
1777
+ _layerName: layerName,
1778
+ _isVectorLayer: true,
1779
+ _isDynamic: isDynamic,
1780
+ _massMarksStyles: massMarksStyles
1781
+ });
1782
+ instance.addLayer(massMarksLayer);
1783
+ return massMarksLayer;
1784
+ };
1785
+ };
1786
+ /**
1787
+ * 按选中状态列表更新海量点显隐
1788
+ * @param checkedStatusList
1789
+ */
1790
+ const updateMarksLayersByStatus = (checkedStatusList = []) => {
1791
+ const hideStyle = new ol_style_js.Style({});
1792
+ const checkedStatuses = new Set(checkedStatusList);
1793
+ const tempList = [];
1794
+ instance.getAllLayers().filter((layer) => layer.get("_isMassMarksLayer")).forEach((layer) => {
1795
+ layer.getSource().getFeatures().forEach((feature) => {
1796
+ const data = feature.getProperties();
1797
+ if (!checkedStatuses.has(data.status)) feature.setStyle(hideStyle);
1798
+ else {
1799
+ tempList.push(data);
1800
+ feature.setStyle(data.unActiveStyle);
1801
+ }
1802
+ });
1803
+ });
1804
+ return tempList;
1805
+ };
1806
+
1807
+ //#endregion
1808
+ //#region src/layer/cluster-layer.ts
1809
+ /**
1810
+ * 创建聚合图层(半径/颜色随聚合数量动态计算)
1811
+ * @param dataList
1812
+ * @param config
1813
+ */
1814
+ const createClusterLayer = (dataList, config) => {
1815
+ const count = dataList.length;
1816
+ const styleCache = {};
1817
+ const { distance, minDistance, openClick, buildStyle, singleStyles, computedRadius, layerName = "cluster-layer" } = config;
1818
+ const innerComputedRadius = (size) => Math.pow(size / count, 1 / 18);
1819
+ styleCache[1] = singleStyles;
1820
+ const innerBuildStyle = (feature) => {
1821
+ const size = feature.get("features").length;
1822
+ let style = styleCache[size];
1823
+ const tempRadius = computedRadius ? computedRadius(size) : innerComputedRadius(size);
1824
+ if (!style) {
1825
+ style = new ol_style_js.Style({
1826
+ image: new ol_style_Circle_js.default({
1827
+ radius: tempRadius * 20,
1828
+ stroke: new ol_style_js.Stroke({
1829
+ width: 2,
1830
+ color: `hsla(${180 - tempRadius * 180}, 100%, 40%, 1)`
1831
+ }),
1832
+ fill: new ol_style_js.Fill({ color: `hsla(${180 - tempRadius * 180}, 100%, 50%, 1)` })
1833
+ }),
1834
+ text: new ol_style_js.Text({
1835
+ text: size.toString(),
1836
+ fill: new ol_style_js.Fill({ color: `hsla(${180 - tempRadius * 180}, 100%, 10%, 1)` }),
1837
+ textBaseline: "middle"
1838
+ })
1839
+ });
1840
+ styleCache[size] = style;
1841
+ }
1842
+ if (Array.isArray(style)) {
1843
+ const index = feature.get("features")[0].get("styleIndex") ?? 0;
1844
+ return style[index];
1845
+ }
1846
+ return style;
1847
+ };
1848
+ const vectorLayer = new ol_layer_Vector_js.default({
1849
+ zIndex: 200,
1850
+ className: layerName,
1851
+ source: new ol_source_Cluster_js.default({
1852
+ distance: distance || 80,
1853
+ minDistance: minDistance || 0,
1854
+ source: new ol_source_Vector_js.default({ features: dataList.map((item) => {
1855
+ const feature = new ol.Feature(new ol_geom_js.Point(item.lnglat));
1856
+ feature.setProperties(item);
1857
+ const index = item.style ?? 0;
1858
+ feature.setProperties({
1859
+ unActiveStyle: singleStyles[index],
1860
+ activeStyle: singleStyles[index + singleStyles.length / 2]
1861
+ });
1862
+ return feature;
1863
+ }) })
1864
+ }),
1865
+ style: (feature) => buildStyle ? buildStyle(feature) : innerBuildStyle(feature)
1866
+ });
1867
+ vectorLayer.setProperties({
1868
+ _isCustom: true,
1869
+ _isVectorLayer: true,
1870
+ _isClusterLayer: true
1871
+ });
1872
+ if (openClick) createSelectByLayer(vectorLayer);
1873
+ return vectorLayer;
1874
+ };
1875
+
1876
+ //#endregion
1877
+ exports.GeometryType = GeometryType;
1878
+ exports.TDT_VECTOR_SOURCE_ID = TDT_VECTOR_SOURCE_ID;
1879
+ exports.TDT_XOR_BYTE_INDEXES = require_tile_loader.TDT_XOR_BYTE_INDEXES;
1880
+ exports.TdtDecoderWorkerClient = TdtDecoderWorkerClient;
1881
+ exports.activeFeatureByUid = activeFeatureByUid;
1882
+ exports.addFeaturesByLayer = addFeaturesByLayer;
1883
+ exports.addMassMarksLayer = addMassMarksLayer;
1884
+ exports.appendFeaturesByLayer = appendFeaturesByLayer;
1885
+ exports.baseLayers = baseLayers;
1886
+ exports.buildMassMarksStyles = buildMassMarksStyles;
1887
+ exports.changeLayer = changeLayer;
1888
+ exports.changeSource = changeSource;
1889
+ exports.changeUnselectStyle = changeUnselectStyle;
1890
+ exports.createAnimationMarker = createAnimationMarker;
1891
+ exports.createBaseLayer = createBaseLayer;
1892
+ exports.createBusinessLayer = createBusinessLayer;
1893
+ exports.createClusterLayer = createClusterLayer;
1894
+ exports.createDrawInteraction = createDrawInteraction;
1895
+ exports.createElasticMarkerLayer = createElasticMarkerLayer;
1896
+ exports.createGeoJsonLayer = createGeoJsonLayer;
1897
+ exports.createIconStyle = createIconStyle;
1898
+ exports.createLayerSelectByNames = createLayerSelectByNames;
1899
+ exports.createMap = createMap;
1900
+ exports.createMapInstance = createMapInstance;
1901
+ exports.createMapWorldLayer = createMapWorldLayer;
1902
+ exports.createMarker = createMarker;
1903
+ exports.createMarkersLayer = createMarkersLayer;
1904
+ exports.createMassMarksLayer = createMassMarksLayer;
1905
+ exports.createMoveMarkerLayer = createMoveMarkerLayer;
1906
+ exports.createOverlay = createOverlay;
1907
+ exports.createSelectByLayer = createSelectByLayer;
1908
+ exports.createTdtVectorSource = createTdtVectorSource;
1909
+ exports.createTdtVtsUrl = createTdtVtsUrl;
1910
+ exports.createText = createText;
1911
+ exports.createVectorFaceLayer = createVectorFaceLayer;
1912
+ exports.createVectorLineLayer = createVectorLineLayer;
1913
+ exports.createWmtsLayer = createWmtsLayer;
1914
+ exports.createZheJiangLayer = createZheJiangLayer;
1915
+ exports.decodeMvt = require_tile_loader.decodeMvt;
1916
+ exports.decodeTdtPk = decodeTdtPk;
1917
+ exports.disposeInstance = disposeInstance;
1918
+ exports.disposeMap = disposeMap;
1919
+ exports.emitter = emitter;
1920
+ exports.encodeStandardMvt = require_tile_loader.encodeStandardMvt;
1921
+ exports.encodeTdtPk = encodeTdtPk;
1922
+ exports.flyToAnimate = flyToAnimate;
1923
+ exports.getConstantBackgroundColor = getConstantBackgroundColor;
1924
+ exports.getDrawStyle = getDrawStyle;
1925
+ exports.getLayerByName = getLayerByName;
1926
+ exports.getLayersDataList = getLayersDataList;
1927
+ exports.getMapInstance = getMapInstance;
1928
+ Object.defineProperty(exports, 'instance', {
1929
+ enumerable: true,
1930
+ get: function () {
1931
+ return instance;
1124
1932
  }
1125
- return vectorLayer;
1126
- };
1127
- // Annotate the CommonJS export names for ESM import in node:
1128
- 0 && (module.exports = {
1129
- GeometryType,
1130
- activeFeatureByUid,
1131
- addFeaturesByLayer,
1132
- addMassMarksLayer,
1133
- appendFeaturesByLayer,
1134
- buildMassMarksStyles,
1135
- createAnimationMarker,
1136
- createBaseLayer,
1137
- createBusinessLayer,
1138
- createClusterLayer,
1139
- createMap,
1140
- createMapInstance,
1141
- createMapWorldLayer,
1142
- createMassMarksLayer,
1143
- createOverlay,
1144
- createSelectByLayer,
1145
- createVectorFaceLayer,
1146
- createVectorLineLayer,
1147
- createWmtsLayer,
1148
- createZheJiangLayer,
1149
- disposeMap,
1150
- emitter,
1151
- getLayerByName,
1152
- getLayersDataList,
1153
- getMapInstance,
1154
- instance,
1155
- removeAllLayers,
1156
- removeLayerByName,
1157
- removeOverlays,
1158
- resetActiveFeature,
1159
- resetActiveVector,
1160
- resetMap,
1161
- resetZoomAndCenter,
1162
- setFitViewByCoords,
1163
- setFitViewByGeom,
1164
- setFitViewByLayer,
1165
- updateMarksLayersByStatus
1166
1933
  });
1934
+ exports.loadAndNormalizeTdtVts = require_tile_loader.loadAndNormalizeTdtVts;
1935
+ exports.loadTdtStyleBundle = loadTdtStyleBundle;
1936
+ exports.mergeTdtStyleLayers = mergeTdtStyleLayers;
1937
+ exports.normalizePrivateGeometry = require_tile_loader.normalizePrivateGeometry;
1938
+ exports.normalizePrivateMvt = require_tile_loader.normalizePrivateMvt;
1939
+ exports.privateTypeToStandard = require_tile_loader.privateTypeToStandard;
1940
+ exports.redactTdtToken = redactTdtToken;
1941
+ exports.removeAllLayers = removeAllLayers;
1942
+ exports.removeLayerByName = removeLayerByName;
1943
+ exports.removeOverlays = removeOverlays;
1944
+ exports.resetActiveFeature = resetActiveFeature;
1945
+ exports.resetActiveVector = resetActiveVector;
1946
+ exports.resetMap = resetMap;
1947
+ exports.resetZoomAndCenter = resetZoomAndCenter;
1948
+ exports.resolveFeatureProperties = require_tile_loader.resolveFeatureProperties;
1949
+ exports.restoreTdtBytes = require_tile_loader.restoreTdtBytes;
1950
+ exports.setFitViewByCoords = setFitViewByCoords;
1951
+ exports.setFitViewByGeom = setFitViewByGeom;
1952
+ exports.setFitViewByLayer = setFitViewByLayer;
1953
+ exports.updateMarksLayersByStatus = updateMarksLayersByStatus;