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/README.md +223 -45
- package/dist/index.cjs +1907 -1120
- package/dist/index.d.cts +475 -134
- package/dist/index.d.mts +661 -0
- package/dist/index.mjs +1830 -0
- package/dist/tdt-vts/decoder.worker.cjs +46 -0
- package/dist/tdt-vts/decoder.worker.d.cts +1 -0
- package/dist/tdt-vts/decoder.worker.d.mts +1 -0
- package/dist/tdt-vts/decoder.worker.mjs +47 -0
- package/dist/tile-loader-CtZwCurI.mjs +630 -0
- package/dist/tile-loader-D4cn6nMU.cjs +683 -0
- package/package.json +20 -12
- package/dist/index.d.ts +0 -320
- package/dist/index.js +0 -1096
package/dist/index.cjs
CHANGED
|
@@ -1,1166 +1,1953 @@
|
|
|
1
|
-
|
|
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
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
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
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
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
|
-
|
|
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
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
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
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
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
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
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
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
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
|
-
|
|
140
|
-
|
|
141
|
-
|
|
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
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
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
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
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
|
-
|
|
242
|
-
|
|
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
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
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
|
-
|
|
251
|
-
|
|
252
|
-
|
|
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
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
}
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
|
|
357
|
-
|
|
358
|
-
|
|
359
|
-
|
|
360
|
-
|
|
361
|
-
|
|
362
|
-
|
|
363
|
-
|
|
364
|
-
|
|
365
|
-
|
|
366
|
-
|
|
367
|
-
|
|
368
|
-
|
|
369
|
-
|
|
370
|
-
|
|
371
|
-
|
|
372
|
-
|
|
373
|
-
|
|
374
|
-
|
|
375
|
-
|
|
376
|
-
|
|
377
|
-
|
|
378
|
-
|
|
379
|
-
|
|
380
|
-
|
|
381
|
-
|
|
382
|
-
|
|
383
|
-
|
|
384
|
-
|
|
385
|
-
|
|
386
|
-
|
|
387
|
-
|
|
388
|
-
|
|
389
|
-
|
|
390
|
-
|
|
391
|
-
|
|
392
|
-
|
|
393
|
-
|
|
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
|
-
|
|
397
|
-
|
|
398
|
-
|
|
399
|
-
|
|
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
|
-
|
|
404
|
-
|
|
405
|
-
|
|
406
|
-
|
|
407
|
-
|
|
408
|
-
|
|
409
|
-
|
|
410
|
-
|
|
411
|
-
|
|
412
|
-
|
|
413
|
-
|
|
414
|
-
|
|
415
|
-
|
|
416
|
-
|
|
417
|
-
|
|
418
|
-
|
|
419
|
-
|
|
420
|
-
|
|
421
|
-
|
|
422
|
-
|
|
423
|
-
|
|
424
|
-
|
|
425
|
-
|
|
426
|
-
|
|
427
|
-
|
|
428
|
-
|
|
429
|
-
|
|
430
|
-
|
|
431
|
-
|
|
432
|
-
|
|
433
|
-
|
|
434
|
-
|
|
435
|
-
|
|
436
|
-
|
|
437
|
-
|
|
438
|
-
|
|
439
|
-
|
|
440
|
-
|
|
441
|
-
|
|
442
|
-
|
|
443
|
-
|
|
444
|
-
|
|
445
|
-
|
|
446
|
-
|
|
447
|
-
|
|
448
|
-
|
|
449
|
-
|
|
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
|
-
|
|
483
|
-
|
|
484
|
-
|
|
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
|
-
|
|
488
|
-
|
|
489
|
-
|
|
490
|
-
|
|
491
|
-
|
|
492
|
-
|
|
493
|
-
|
|
494
|
-
|
|
495
|
-
|
|
496
|
-
|
|
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
|
-
|
|
503
|
-
|
|
504
|
-
|
|
505
|
-
|
|
506
|
-
|
|
507
|
-
|
|
508
|
-
|
|
509
|
-
|
|
510
|
-
|
|
511
|
-
|
|
512
|
-
|
|
513
|
-
|
|
514
|
-
|
|
515
|
-
|
|
516
|
-
|
|
517
|
-
|
|
518
|
-
|
|
519
|
-
|
|
520
|
-
|
|
521
|
-
|
|
522
|
-
|
|
523
|
-
|
|
524
|
-
|
|
525
|
-
|
|
526
|
-
|
|
527
|
-
|
|
528
|
-
|
|
529
|
-
|
|
530
|
-
|
|
531
|
-
|
|
532
|
-
|
|
533
|
-
|
|
534
|
-
|
|
535
|
-
|
|
536
|
-
|
|
537
|
-
|
|
538
|
-
|
|
539
|
-
|
|
540
|
-
|
|
541
|
-
|
|
542
|
-
|
|
543
|
-
|
|
544
|
-
|
|
545
|
-
|
|
546
|
-
|
|
547
|
-
|
|
548
|
-
|
|
549
|
-
|
|
550
|
-
|
|
551
|
-
|
|
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
|
-
|
|
556
|
-
|
|
557
|
-
|
|
558
|
-
|
|
559
|
-
|
|
560
|
-
|
|
561
|
-
|
|
562
|
-
|
|
563
|
-
|
|
564
|
-
|
|
565
|
-
|
|
566
|
-
|
|
567
|
-
|
|
568
|
-
|
|
569
|
-
|
|
570
|
-
|
|
571
|
-
|
|
572
|
-
|
|
573
|
-
|
|
574
|
-
|
|
575
|
-
|
|
576
|
-
|
|
577
|
-
|
|
578
|
-
|
|
579
|
-
|
|
580
|
-
|
|
581
|
-
|
|
582
|
-
|
|
583
|
-
|
|
584
|
-
|
|
585
|
-
|
|
586
|
-
|
|
587
|
-
|
|
588
|
-
|
|
589
|
-
|
|
590
|
-
|
|
591
|
-
|
|
592
|
-
|
|
593
|
-
|
|
594
|
-
|
|
595
|
-
|
|
596
|
-
|
|
597
|
-
|
|
598
|
-
|
|
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
|
-
|
|
605
|
-
|
|
606
|
-
|
|
607
|
-
|
|
608
|
-
|
|
609
|
-
|
|
610
|
-
|
|
611
|
-
|
|
612
|
-
|
|
613
|
-
|
|
614
|
-
|
|
615
|
-
|
|
616
|
-
|
|
617
|
-
|
|
618
|
-
|
|
619
|
-
|
|
620
|
-
|
|
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
|
-
|
|
624
|
-
|
|
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
|
-
|
|
627
|
-
|
|
628
|
-
|
|
629
|
-
|
|
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
|
-
|
|
633
|
-
|
|
634
|
-
|
|
635
|
-
|
|
636
|
-
|
|
637
|
-
|
|
638
|
-
|
|
639
|
-
|
|
640
|
-
|
|
641
|
-
|
|
642
|
-
|
|
643
|
-
|
|
644
|
-
|
|
645
|
-
|
|
646
|
-
|
|
647
|
-
|
|
648
|
-
|
|
649
|
-
|
|
650
|
-
|
|
651
|
-
|
|
652
|
-
|
|
653
|
-
|
|
654
|
-
|
|
655
|
-
|
|
656
|
-
|
|
657
|
-
|
|
658
|
-
|
|
659
|
-
|
|
660
|
-
|
|
661
|
-
|
|
662
|
-
|
|
663
|
-
|
|
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
|
-
|
|
668
|
-
|
|
669
|
-
|
|
670
|
-
|
|
671
|
-
|
|
672
|
-
|
|
673
|
-
|
|
674
|
-
|
|
675
|
-
|
|
676
|
-
|
|
677
|
-
|
|
678
|
-
|
|
679
|
-
|
|
680
|
-
|
|
681
|
-
|
|
682
|
-
|
|
683
|
-
|
|
684
|
-
|
|
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
|
-
|
|
714
|
-
|
|
715
|
-
|
|
716
|
-
|
|
717
|
-
|
|
718
|
-
|
|
719
|
-
|
|
720
|
-
|
|
721
|
-
|
|
722
|
-
|
|
723
|
-
|
|
724
|
-
|
|
725
|
-
|
|
726
|
-
|
|
727
|
-
|
|
728
|
-
|
|
729
|
-
|
|
730
|
-
|
|
731
|
-
|
|
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
|
-
|
|
852
|
-
|
|
853
|
-
|
|
854
|
-
|
|
855
|
-
|
|
856
|
-
|
|
857
|
-
|
|
858
|
-
|
|
859
|
-
|
|
860
|
-
|
|
861
|
-
|
|
862
|
-
|
|
863
|
-
|
|
864
|
-
|
|
865
|
-
|
|
866
|
-
|
|
867
|
-
|
|
868
|
-
|
|
869
|
-
|
|
870
|
-
|
|
871
|
-
|
|
872
|
-
|
|
873
|
-
|
|
874
|
-
|
|
875
|
-
|
|
876
|
-
|
|
877
|
-
|
|
878
|
-
|
|
879
|
-
|
|
880
|
-
|
|
881
|
-
|
|
882
|
-
|
|
883
|
-
|
|
884
|
-
|
|
885
|
-
|
|
886
|
-
|
|
887
|
-
|
|
888
|
-
|
|
889
|
-
|
|
890
|
-
|
|
891
|
-
|
|
892
|
-
|
|
893
|
-
|
|
894
|
-
|
|
895
|
-
|
|
896
|
-
|
|
897
|
-
|
|
898
|
-
|
|
899
|
-
|
|
900
|
-
|
|
901
|
-
|
|
902
|
-
|
|
903
|
-
|
|
904
|
-
|
|
905
|
-
|
|
906
|
-
|
|
907
|
-
|
|
908
|
-
|
|
909
|
-
|
|
910
|
-
|
|
911
|
-
|
|
912
|
-
|
|
913
|
-
|
|
914
|
-
|
|
915
|
-
|
|
916
|
-
|
|
917
|
-
|
|
918
|
-
|
|
919
|
-
|
|
920
|
-
|
|
921
|
-
|
|
922
|
-
|
|
923
|
-
|
|
924
|
-
|
|
925
|
-
|
|
926
|
-
|
|
927
|
-
|
|
928
|
-
|
|
929
|
-
|
|
930
|
-
|
|
931
|
-
|
|
932
|
-
|
|
933
|
-
|
|
934
|
-
|
|
935
|
-
|
|
936
|
-
|
|
937
|
-
|
|
938
|
-
|
|
939
|
-
|
|
940
|
-
|
|
941
|
-
|
|
942
|
-
|
|
943
|
-
|
|
944
|
-
|
|
945
|
-
|
|
946
|
-
|
|
947
|
-
|
|
948
|
-
|
|
949
|
-
|
|
950
|
-
|
|
951
|
-
|
|
952
|
-
|
|
953
|
-
|
|
954
|
-
|
|
955
|
-
|
|
956
|
-
|
|
957
|
-
|
|
958
|
-
|
|
959
|
-
|
|
960
|
-
|
|
961
|
-
|
|
962
|
-
|
|
963
|
-
|
|
964
|
-
|
|
965
|
-
|
|
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
|
-
|
|
1043
|
-
|
|
1044
|
-
|
|
1045
|
-
|
|
1046
|
-
|
|
1047
|
-
|
|
1048
|
-
|
|
1049
|
-
|
|
1050
|
-
|
|
1051
|
-
|
|
1052
|
-
|
|
1053
|
-
|
|
1054
|
-
|
|
1055
|
-
|
|
1056
|
-
|
|
1057
|
-
|
|
1058
|
-
|
|
1059
|
-
|
|
1060
|
-
|
|
1061
|
-
|
|
1062
|
-
|
|
1063
|
-
|
|
1064
|
-
|
|
1065
|
-
|
|
1066
|
-
|
|
1067
|
-
|
|
1068
|
-
|
|
1069
|
-
|
|
1070
|
-
|
|
1071
|
-
|
|
1072
|
-
|
|
1073
|
-
|
|
1074
|
-
|
|
1075
|
-
|
|
1076
|
-
|
|
1077
|
-
|
|
1078
|
-
|
|
1079
|
-
|
|
1080
|
-
|
|
1081
|
-
|
|
1082
|
-
|
|
1083
|
-
|
|
1084
|
-
|
|
1085
|
-
|
|
1086
|
-
|
|
1087
|
-
|
|
1088
|
-
|
|
1089
|
-
|
|
1090
|
-
|
|
1091
|
-
|
|
1092
|
-
|
|
1093
|
-
|
|
1094
|
-
|
|
1095
|
-
|
|
1096
|
-
|
|
1097
|
-
|
|
1098
|
-
|
|
1099
|
-
|
|
1100
|
-
|
|
1101
|
-
|
|
1102
|
-
|
|
1103
|
-
|
|
1104
|
-
|
|
1105
|
-
|
|
1106
|
-
|
|
1107
|
-
|
|
1108
|
-
|
|
1109
|
-
|
|
1110
|
-
|
|
1111
|
-
|
|
1112
|
-
|
|
1113
|
-
|
|
1114
|
-
|
|
1115
|
-
|
|
1116
|
-
|
|
1117
|
-
|
|
1118
|
-
|
|
1119
|
-
|
|
1120
|
-
|
|
1121
|
-
|
|
1122
|
-
|
|
1123
|
-
|
|
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;
|