raintee-maputils 1.0.15 → 1.0.17
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.js +741 -741
- package/dist/index.js.map +1 -1
- package/index.js +10 -7
- package/package.json +2 -3
- package/src/CustomOptionsControl.js +0 -169
- package/src/CustomToggleControl.js +0 -126
- package/src/RainteeConstants.js +0 -820
- package/src/RainteeGISUtil.js +0 -149
- package/src/RainteeSourceMapTool.js +0 -104
- package/src/RasterLayerController.js +0 -262
- package/src/TerrainToggleControl.js +0 -127
- package/src/useDrawCache.js +0 -61
package/dist/index.js
CHANGED
|
@@ -1,298 +1,3 @@
|
|
|
1
|
-
class CustomOptionsControl {
|
|
2
|
-
constructor(args) {
|
|
3
|
-
const { options, onConfirm } = args;
|
|
4
|
-
|
|
5
|
-
this._container = null;
|
|
6
|
-
this._map = null;
|
|
7
|
-
|
|
8
|
-
this._options = options || [];
|
|
9
|
-
this._onConfirm = onConfirm || (() => { });
|
|
10
|
-
|
|
11
|
-
if (!this._options || !Array.isArray(this._options)) {
|
|
12
|
-
console.error('请传入有效的 options 参数(数组)');
|
|
13
|
-
}
|
|
14
|
-
}
|
|
15
|
-
|
|
16
|
-
onAdd(map) {
|
|
17
|
-
this._map = map;
|
|
18
|
-
|
|
19
|
-
// 创建控件外层容器
|
|
20
|
-
this._container = document.createElement('div');
|
|
21
|
-
this._container.className = 'mapboxgl-ctrl mapboxgl-ctrl-group custom-options-control';
|
|
22
|
-
|
|
23
|
-
// 创建主按钮(初始只显示“三维模型”文字,点击展开)
|
|
24
|
-
const mainButton = document.createElement('button');
|
|
25
|
-
mainButton.style.cssText = `
|
|
26
|
-
width: 100%;
|
|
27
|
-
height: 100%;
|
|
28
|
-
padding: 0.25rem 0.5rem;
|
|
29
|
-
margin: 0;
|
|
30
|
-
border: 1px solid #ccc;
|
|
31
|
-
background: white;
|
|
32
|
-
border-radius: 4px;
|
|
33
|
-
cursor: pointer;
|
|
34
|
-
font-size: 14px;
|
|
35
|
-
text-align: left;
|
|
36
|
-
`;
|
|
37
|
-
mainButton.textContent = '三维模型';
|
|
38
|
-
mainButton.addEventListener('click', () => this._toggleExpanded());
|
|
39
|
-
|
|
40
|
-
this._container.appendChild(mainButton);
|
|
41
|
-
|
|
42
|
-
// 创建隐藏的选项面板(默认不显示)
|
|
43
|
-
this._panel = document.createElement('div');
|
|
44
|
-
this._panel.style.display = 'none';
|
|
45
|
-
this._panel.style.padding = '10px';
|
|
46
|
-
this._container.appendChild(this._panel);
|
|
47
|
-
|
|
48
|
-
// 创建选项列表和按钮组
|
|
49
|
-
this._renderOptionsPanel();
|
|
50
|
-
|
|
51
|
-
return this._container;
|
|
52
|
-
}
|
|
53
|
-
|
|
54
|
-
_toggleExpanded() {
|
|
55
|
-
const isExpanded = this._panel.style.display !== 'none';
|
|
56
|
-
this._setExpanded(!isExpanded);
|
|
57
|
-
}
|
|
58
|
-
|
|
59
|
-
_setExpanded(isExpanded) {
|
|
60
|
-
this._panel.style.display = isExpanded ? 'block' : 'none';
|
|
61
|
-
}
|
|
62
|
-
|
|
63
|
-
_renderOptionsPanel() {
|
|
64
|
-
// 清空面板内容
|
|
65
|
-
this._panel.innerHTML = '';
|
|
66
|
-
|
|
67
|
-
// 创建复选框选项列表
|
|
68
|
-
this._options.forEach((opt) => {
|
|
69
|
-
const optionDiv = document.createElement('div');
|
|
70
|
-
optionDiv.style.marginBottom = '6px';
|
|
71
|
-
|
|
72
|
-
const label = document.createElement('label');
|
|
73
|
-
label.style.display = 'flex';
|
|
74
|
-
label.style.alignItems = 'center';
|
|
75
|
-
label.style.cursor = 'pointer';
|
|
76
|
-
|
|
77
|
-
const checkbox = document.createElement('input');
|
|
78
|
-
checkbox.type = 'checkbox';
|
|
79
|
-
checkbox.value = opt.value;
|
|
80
|
-
checkbox.style.marginRight = '8px';
|
|
81
|
-
|
|
82
|
-
// 绑定选中状态
|
|
83
|
-
checkbox.checked = this._getSelectedOption(opt.value);
|
|
84
|
-
checkbox.addEventListener('change', () => this._toggleOption(opt.value));
|
|
85
|
-
|
|
86
|
-
const span = document.createElement('span');
|
|
87
|
-
span.textContent = opt.label;
|
|
88
|
-
|
|
89
|
-
label.appendChild(checkbox);
|
|
90
|
-
label.appendChild(span);
|
|
91
|
-
optionDiv.appendChild(label);
|
|
92
|
-
this._panel.appendChild(optionDiv);
|
|
93
|
-
});
|
|
94
|
-
|
|
95
|
-
// 创建按钮组:取消 / 确定
|
|
96
|
-
const buttonGroup = document.createElement('div');
|
|
97
|
-
buttonGroup.style.marginTop = '12px';
|
|
98
|
-
buttonGroup.style.display = 'flex';
|
|
99
|
-
buttonGroup.style.gap = '8px';
|
|
100
|
-
buttonGroup.style.justifyContent = 'flex-end';
|
|
101
|
-
|
|
102
|
-
const cancelButton = document.createElement('button');
|
|
103
|
-
cancelButton.textContent = '取消';
|
|
104
|
-
cancelButton.style.cssText = `
|
|
105
|
-
padding: 6px 12px;
|
|
106
|
-
background: #ccc;
|
|
107
|
-
border: none;
|
|
108
|
-
border-radius: 4px;
|
|
109
|
-
cursor: pointer;
|
|
110
|
-
width: auto;
|
|
111
|
-
`;
|
|
112
|
-
cancelButton.addEventListener('click', () => this._handleCancel());
|
|
113
|
-
|
|
114
|
-
const confirmButton = document.createElement('button');
|
|
115
|
-
confirmButton.textContent = '确定';
|
|
116
|
-
confirmButton.style.cssText = `
|
|
117
|
-
padding: 6px 12px;
|
|
118
|
-
background: #007cba;
|
|
119
|
-
color: white;
|
|
120
|
-
border: none;
|
|
121
|
-
border-radius: 4px;
|
|
122
|
-
cursor: pointer;
|
|
123
|
-
width: auto;
|
|
124
|
-
`;
|
|
125
|
-
confirmButton.addEventListener('click', () => this._handleConfirm());
|
|
126
|
-
|
|
127
|
-
buttonGroup.appendChild(cancelButton);
|
|
128
|
-
buttonGroup.appendChild(confirmButton);
|
|
129
|
-
this._panel.appendChild(buttonGroup);
|
|
130
|
-
}
|
|
131
|
-
|
|
132
|
-
_getSelectedOption(value) {
|
|
133
|
-
return this._selectedOptions?.includes(value) || false;
|
|
134
|
-
}
|
|
135
|
-
|
|
136
|
-
_toggleOption(value) {
|
|
137
|
-
if (!this._selectedOptions) this._selectedOptions = [];
|
|
138
|
-
|
|
139
|
-
const idx = this._selectedOptions.indexOf(value);
|
|
140
|
-
if (idx > -1) {
|
|
141
|
-
this._selectedOptions.splice(idx, 1);
|
|
142
|
-
} else {
|
|
143
|
-
this._selectedOptions.push(value);
|
|
144
|
-
}
|
|
145
|
-
|
|
146
|
-
// 可选:重新渲染复选框状态(如果需要动态更新 UI,但目前 onchange 已处理)
|
|
147
|
-
}
|
|
148
|
-
|
|
149
|
-
_handleConfirm() {
|
|
150
|
-
this._setExpanded(false);
|
|
151
|
-
|
|
152
|
-
this._onConfirm({
|
|
153
|
-
selectedOptions: this._selectedOptions || [],
|
|
154
|
-
unselectedOptions: this._options.filter((item) => !this._selectedOptions?.includes(item.value)),
|
|
155
|
-
allOptions: this._options,
|
|
156
|
-
});
|
|
157
|
-
}
|
|
158
|
-
|
|
159
|
-
_handleCancel() {
|
|
160
|
-
this._setExpanded(false);
|
|
161
|
-
}
|
|
162
|
-
|
|
163
|
-
onRemove() {
|
|
164
|
-
if (this._container && this._container.parentNode) {
|
|
165
|
-
this._container.parentNode.removeChild(this._container);
|
|
166
|
-
}
|
|
167
|
-
}
|
|
168
|
-
}
|
|
169
|
-
|
|
170
|
-
// 自定义控件类:ToggleControl
|
|
171
|
-
class ToggleControl {
|
|
172
|
-
/**
|
|
173
|
-
* 构造函数
|
|
174
|
-
* @param {Object} options
|
|
175
|
-
* @param {string} options.name - 控件名称(用于识别,可选展示)
|
|
176
|
-
* @param {string} options.field - 控制的字段名,对应 map.SourceMap[field]
|
|
177
|
-
* @param {boolean} options.defaultValue - 默认值(当 field 未定义时使用)
|
|
178
|
-
* @param {string} options.svgIcon - SVG 图标字符串,例如 '<svg>...</svg>'
|
|
179
|
-
* @param {Function} [options.onToggle] - 可选的回调函数,状态切换后调用,参数为最新的布尔值
|
|
180
|
-
*/
|
|
181
|
-
constructor({ name, field, defaultValue = false, svgIcon, onToggle }) {
|
|
182
|
-
this.name = name;
|
|
183
|
-
this.field = field;
|
|
184
|
-
this.defaultValue = defaultValue;
|
|
185
|
-
this.svgIcon = svgIcon;
|
|
186
|
-
this.onToggle = onToggle; // ✅ 新增:回调函数
|
|
187
|
-
|
|
188
|
-
// 控件容器
|
|
189
|
-
this._container = null;
|
|
190
|
-
this._button = null;
|
|
191
|
-
this.isActive = false; // 当前是否为激活状态(高亮/true)
|
|
192
|
-
}
|
|
193
|
-
|
|
194
|
-
// Mapbox 要求的 onAdd 方法
|
|
195
|
-
onAdd(map) {
|
|
196
|
-
this.map = map;
|
|
197
|
-
|
|
198
|
-
// 创建外层容器 div
|
|
199
|
-
this._container = document.createElement('div');
|
|
200
|
-
this._container.className = 'mapboxgl-ctrl mapboxgl-ctrl-group';
|
|
201
|
-
|
|
202
|
-
// 创建 button 元素
|
|
203
|
-
this._button = document.createElement('button');
|
|
204
|
-
this._button.type = 'button';
|
|
205
|
-
this._button.innerHTML = this.svgIcon;
|
|
206
|
-
|
|
207
|
-
// 设置按钮样式
|
|
208
|
-
this._button.style.cursor = 'pointer';
|
|
209
|
-
this._button.style.border = 'none';
|
|
210
|
-
this._button.style.background = 'none';
|
|
211
|
-
this._button.style.padding = '0';
|
|
212
|
-
this._button.style.display = 'flex';
|
|
213
|
-
this._button.style.alignItems = 'center';
|
|
214
|
-
this._button.style.justifyContent = 'center';
|
|
215
|
-
|
|
216
|
-
// 初始化状态
|
|
217
|
-
this.updateStatus();
|
|
218
|
-
|
|
219
|
-
// 绑定点击事件
|
|
220
|
-
this._button.addEventListener('click', () => {
|
|
221
|
-
this.toggle();
|
|
222
|
-
});
|
|
223
|
-
|
|
224
|
-
this._container.appendChild(this._button);
|
|
225
|
-
|
|
226
|
-
return this._container;
|
|
227
|
-
}
|
|
228
|
-
|
|
229
|
-
// Mapbox 要求的 onRemove 方法
|
|
230
|
-
onRemove() {
|
|
231
|
-
if (this._container && this._container.parentNode) {
|
|
232
|
-
this._container.parentNode.removeChild(this._container);
|
|
233
|
-
}
|
|
234
|
-
this.map = null;
|
|
235
|
-
this._container = null;
|
|
236
|
-
this._button = null;
|
|
237
|
-
}
|
|
238
|
-
|
|
239
|
-
// 更新控件状态(根据当前 field 值)
|
|
240
|
-
updateStatus() {
|
|
241
|
-
// 从 map.SourceMap 中获取当前 field 的值,如果不存在则使用 defaultValue
|
|
242
|
-
let currentValue = this.defaultValue;
|
|
243
|
-
|
|
244
|
-
if (
|
|
245
|
-
this.map &&
|
|
246
|
-
this.map.SourceMap &&
|
|
247
|
-
typeof this.map.SourceMap[this.field] === 'boolean'
|
|
248
|
-
) {
|
|
249
|
-
currentValue = this.map.SourceMap[this.field];
|
|
250
|
-
}
|
|
251
|
-
|
|
252
|
-
this.isActive = currentValue; // true 表示激活,false 表示未激活
|
|
253
|
-
|
|
254
|
-
// 更新按钮样式
|
|
255
|
-
if (this.isActive) {
|
|
256
|
-
this._button.style.opacity = '1';
|
|
257
|
-
this._button.style.filter = 'none';
|
|
258
|
-
} else {
|
|
259
|
-
this._button.style.opacity = '0.4';
|
|
260
|
-
this._button.style.filter = 'grayscale(100%)';
|
|
261
|
-
}
|
|
262
|
-
}
|
|
263
|
-
|
|
264
|
-
// 切换状态
|
|
265
|
-
toggle() {
|
|
266
|
-
// 获取当前值
|
|
267
|
-
let currentValue = this.defaultValue;
|
|
268
|
-
|
|
269
|
-
if (
|
|
270
|
-
this.map &&
|
|
271
|
-
this.map.SourceMap &&
|
|
272
|
-
typeof this.map.SourceMap[this.field] === 'boolean'
|
|
273
|
-
) {
|
|
274
|
-
currentValue = this.map.SourceMap[this.field];
|
|
275
|
-
}
|
|
276
|
-
|
|
277
|
-
// 切换值
|
|
278
|
-
const newValue = !currentValue;
|
|
279
|
-
|
|
280
|
-
// 更新到 map.SourceMap 中
|
|
281
|
-
if (this.map && this.map.SourceMap) {
|
|
282
|
-
this.map.SourceMap[this.field] = newValue;
|
|
283
|
-
}
|
|
284
|
-
|
|
285
|
-
// 更新内部状态
|
|
286
|
-
this.isActive = newValue;
|
|
287
|
-
|
|
288
|
-
// 更新 UI 样式
|
|
289
|
-
this.updateStatus();
|
|
290
|
-
|
|
291
|
-
// ✅ 调用回调函数(如果传入了 onToggle),并传入最新的值
|
|
292
|
-
this.onToggle?.(newValue); // 安全调用,仅当函数存在时才执行
|
|
293
|
-
}
|
|
294
|
-
}
|
|
295
|
-
|
|
296
1
|
const predefineColorSet = {
|
|
297
2
|
'默认单色预设': [{
|
|
298
3
|
Property: '默认',
|
|
@@ -5621,501 +5326,796 @@ var Segment = class _Segment {
|
|
|
5621
5326
|
const seg = this.prev.consumedBy || this.prev;
|
|
5622
5327
|
this._beforeState = seg.afterState();
|
|
5623
5328
|
}
|
|
5624
|
-
return this._beforeState;
|
|
5329
|
+
return this._beforeState;
|
|
5330
|
+
}
|
|
5331
|
+
afterState() {
|
|
5332
|
+
if (this._afterState !== void 0) return this._afterState;
|
|
5333
|
+
const beforeState = this.beforeState();
|
|
5334
|
+
this._afterState = {
|
|
5335
|
+
rings: beforeState.rings.slice(0),
|
|
5336
|
+
windings: beforeState.windings.slice(0),
|
|
5337
|
+
multiPolys: []
|
|
5338
|
+
};
|
|
5339
|
+
const ringsAfter = this._afterState.rings;
|
|
5340
|
+
const windingsAfter = this._afterState.windings;
|
|
5341
|
+
const mpsAfter = this._afterState.multiPolys;
|
|
5342
|
+
for (let i = 0, iMax = this.rings.length; i < iMax; i++) {
|
|
5343
|
+
const ring = this.rings[i];
|
|
5344
|
+
const winding = this.windings[i];
|
|
5345
|
+
const index = ringsAfter.indexOf(ring);
|
|
5346
|
+
if (index === -1) {
|
|
5347
|
+
ringsAfter.push(ring);
|
|
5348
|
+
windingsAfter.push(winding);
|
|
5349
|
+
} else windingsAfter[index] += winding;
|
|
5350
|
+
}
|
|
5351
|
+
const polysAfter = [];
|
|
5352
|
+
const polysExclude = [];
|
|
5353
|
+
for (let i = 0, iMax = ringsAfter.length; i < iMax; i++) {
|
|
5354
|
+
if (windingsAfter[i] === 0) continue;
|
|
5355
|
+
const ring = ringsAfter[i];
|
|
5356
|
+
const poly = ring.poly;
|
|
5357
|
+
if (polysExclude.indexOf(poly) !== -1) continue;
|
|
5358
|
+
if (ring.isExterior) polysAfter.push(poly);
|
|
5359
|
+
else {
|
|
5360
|
+
if (polysExclude.indexOf(poly) === -1) polysExclude.push(poly);
|
|
5361
|
+
const index = polysAfter.indexOf(ring.poly);
|
|
5362
|
+
if (index !== -1) polysAfter.splice(index, 1);
|
|
5363
|
+
}
|
|
5364
|
+
}
|
|
5365
|
+
for (let i = 0, iMax = polysAfter.length; i < iMax; i++) {
|
|
5366
|
+
const mp = polysAfter[i].multiPoly;
|
|
5367
|
+
if (mpsAfter.indexOf(mp) === -1) mpsAfter.push(mp);
|
|
5368
|
+
}
|
|
5369
|
+
return this._afterState;
|
|
5370
|
+
}
|
|
5371
|
+
/* Is this segment part of the final result? */
|
|
5372
|
+
isInResult() {
|
|
5373
|
+
if (this.consumedBy) return false;
|
|
5374
|
+
if (this._isInResult !== void 0) return this._isInResult;
|
|
5375
|
+
const mpsBefore = this.beforeState().multiPolys;
|
|
5376
|
+
const mpsAfter = this.afterState().multiPolys;
|
|
5377
|
+
switch (operation_default.type) {
|
|
5378
|
+
case "union": {
|
|
5379
|
+
const noBefores = mpsBefore.length === 0;
|
|
5380
|
+
const noAfters = mpsAfter.length === 0;
|
|
5381
|
+
this._isInResult = noBefores !== noAfters;
|
|
5382
|
+
break;
|
|
5383
|
+
}
|
|
5384
|
+
case "intersection": {
|
|
5385
|
+
let least;
|
|
5386
|
+
let most;
|
|
5387
|
+
if (mpsBefore.length < mpsAfter.length) {
|
|
5388
|
+
least = mpsBefore.length;
|
|
5389
|
+
most = mpsAfter.length;
|
|
5390
|
+
} else {
|
|
5391
|
+
least = mpsAfter.length;
|
|
5392
|
+
most = mpsBefore.length;
|
|
5393
|
+
}
|
|
5394
|
+
this._isInResult = most === operation_default.numMultiPolys && least < most;
|
|
5395
|
+
break;
|
|
5396
|
+
}
|
|
5397
|
+
case "xor": {
|
|
5398
|
+
const diff = Math.abs(mpsBefore.length - mpsAfter.length);
|
|
5399
|
+
this._isInResult = diff % 2 === 1;
|
|
5400
|
+
break;
|
|
5401
|
+
}
|
|
5402
|
+
case "difference": {
|
|
5403
|
+
const isJustSubject = (mps) => mps.length === 1 && mps[0].isSubject;
|
|
5404
|
+
this._isInResult = isJustSubject(mpsBefore) !== isJustSubject(mpsAfter);
|
|
5405
|
+
break;
|
|
5406
|
+
}
|
|
5407
|
+
}
|
|
5408
|
+
return this._isInResult;
|
|
5409
|
+
}
|
|
5410
|
+
};
|
|
5411
|
+
|
|
5412
|
+
// src/geom-in.ts
|
|
5413
|
+
var RingIn = class {
|
|
5414
|
+
poly;
|
|
5415
|
+
isExterior;
|
|
5416
|
+
segments;
|
|
5417
|
+
bbox;
|
|
5418
|
+
constructor(geomRing, poly, isExterior) {
|
|
5419
|
+
if (!Array.isArray(geomRing) || geomRing.length === 0) {
|
|
5420
|
+
throw new Error("Input geometry is not a valid Polygon or MultiPolygon");
|
|
5421
|
+
}
|
|
5422
|
+
this.poly = poly;
|
|
5423
|
+
this.isExterior = isExterior;
|
|
5424
|
+
this.segments = [];
|
|
5425
|
+
if (typeof geomRing[0][0] !== "number" || typeof geomRing[0][1] !== "number") {
|
|
5426
|
+
throw new Error("Input geometry is not a valid Polygon or MultiPolygon");
|
|
5427
|
+
}
|
|
5428
|
+
const firstPoint = precision.snap({ x: new BigNumber(geomRing[0][0]), y: new BigNumber(geomRing[0][1]) });
|
|
5429
|
+
this.bbox = {
|
|
5430
|
+
ll: { x: firstPoint.x, y: firstPoint.y },
|
|
5431
|
+
ur: { x: firstPoint.x, y: firstPoint.y }
|
|
5432
|
+
};
|
|
5433
|
+
let prevPoint = firstPoint;
|
|
5434
|
+
for (let i = 1, iMax = geomRing.length; i < iMax; i++) {
|
|
5435
|
+
if (typeof geomRing[i][0] !== "number" || typeof geomRing[i][1] !== "number") {
|
|
5436
|
+
throw new Error("Input geometry is not a valid Polygon or MultiPolygon");
|
|
5437
|
+
}
|
|
5438
|
+
const point = precision.snap({ x: new BigNumber(geomRing[i][0]), y: new BigNumber(geomRing[i][1]) });
|
|
5439
|
+
if (point.x.eq(prevPoint.x) && point.y.eq(prevPoint.y)) continue;
|
|
5440
|
+
this.segments.push(Segment.fromRing(prevPoint, point, this));
|
|
5441
|
+
if (point.x.isLessThan(this.bbox.ll.x)) this.bbox.ll.x = point.x;
|
|
5442
|
+
if (point.y.isLessThan(this.bbox.ll.y)) this.bbox.ll.y = point.y;
|
|
5443
|
+
if (point.x.isGreaterThan(this.bbox.ur.x)) this.bbox.ur.x = point.x;
|
|
5444
|
+
if (point.y.isGreaterThan(this.bbox.ur.y)) this.bbox.ur.y = point.y;
|
|
5445
|
+
prevPoint = point;
|
|
5446
|
+
}
|
|
5447
|
+
if (!firstPoint.x.eq(prevPoint.x) || !firstPoint.y.eq(prevPoint.y)) {
|
|
5448
|
+
this.segments.push(Segment.fromRing(prevPoint, firstPoint, this));
|
|
5449
|
+
}
|
|
5450
|
+
}
|
|
5451
|
+
getSweepEvents() {
|
|
5452
|
+
const sweepEvents = [];
|
|
5453
|
+
for (let i = 0, iMax = this.segments.length; i < iMax; i++) {
|
|
5454
|
+
const segment = this.segments[i];
|
|
5455
|
+
sweepEvents.push(segment.leftSE);
|
|
5456
|
+
sweepEvents.push(segment.rightSE);
|
|
5457
|
+
}
|
|
5458
|
+
return sweepEvents;
|
|
5459
|
+
}
|
|
5460
|
+
};
|
|
5461
|
+
var PolyIn = class {
|
|
5462
|
+
multiPoly;
|
|
5463
|
+
exteriorRing;
|
|
5464
|
+
interiorRings;
|
|
5465
|
+
bbox;
|
|
5466
|
+
constructor(geomPoly, multiPoly) {
|
|
5467
|
+
if (!Array.isArray(geomPoly)) {
|
|
5468
|
+
throw new Error("Input geometry is not a valid Polygon or MultiPolygon");
|
|
5469
|
+
}
|
|
5470
|
+
this.exteriorRing = new RingIn(geomPoly[0], this, true);
|
|
5471
|
+
this.bbox = {
|
|
5472
|
+
ll: { x: this.exteriorRing.bbox.ll.x, y: this.exteriorRing.bbox.ll.y },
|
|
5473
|
+
ur: { x: this.exteriorRing.bbox.ur.x, y: this.exteriorRing.bbox.ur.y }
|
|
5474
|
+
};
|
|
5475
|
+
this.interiorRings = [];
|
|
5476
|
+
for (let i = 1, iMax = geomPoly.length; i < iMax; i++) {
|
|
5477
|
+
const ring = new RingIn(geomPoly[i], this, false);
|
|
5478
|
+
if (ring.bbox.ll.x.isLessThan(this.bbox.ll.x)) this.bbox.ll.x = ring.bbox.ll.x;
|
|
5479
|
+
if (ring.bbox.ll.y.isLessThan(this.bbox.ll.y)) this.bbox.ll.y = ring.bbox.ll.y;
|
|
5480
|
+
if (ring.bbox.ur.x.isGreaterThan(this.bbox.ur.x)) this.bbox.ur.x = ring.bbox.ur.x;
|
|
5481
|
+
if (ring.bbox.ur.y.isGreaterThan(this.bbox.ur.y)) this.bbox.ur.y = ring.bbox.ur.y;
|
|
5482
|
+
this.interiorRings.push(ring);
|
|
5483
|
+
}
|
|
5484
|
+
this.multiPoly = multiPoly;
|
|
5485
|
+
}
|
|
5486
|
+
getSweepEvents() {
|
|
5487
|
+
const sweepEvents = this.exteriorRing.getSweepEvents();
|
|
5488
|
+
for (let i = 0, iMax = this.interiorRings.length; i < iMax; i++) {
|
|
5489
|
+
const ringSweepEvents = this.interiorRings[i].getSweepEvents();
|
|
5490
|
+
for (let j = 0, jMax = ringSweepEvents.length; j < jMax; j++) {
|
|
5491
|
+
sweepEvents.push(ringSweepEvents[j]);
|
|
5492
|
+
}
|
|
5493
|
+
}
|
|
5494
|
+
return sweepEvents;
|
|
5625
5495
|
}
|
|
5626
|
-
|
|
5627
|
-
|
|
5628
|
-
|
|
5629
|
-
|
|
5630
|
-
|
|
5631
|
-
|
|
5632
|
-
|
|
5633
|
-
|
|
5634
|
-
const ringsAfter = this._afterState.rings;
|
|
5635
|
-
const windingsAfter = this._afterState.windings;
|
|
5636
|
-
const mpsAfter = this._afterState.multiPolys;
|
|
5637
|
-
for (let i = 0, iMax = this.rings.length; i < iMax; i++) {
|
|
5638
|
-
const ring = this.rings[i];
|
|
5639
|
-
const winding = this.windings[i];
|
|
5640
|
-
const index = ringsAfter.indexOf(ring);
|
|
5641
|
-
if (index === -1) {
|
|
5642
|
-
ringsAfter.push(ring);
|
|
5643
|
-
windingsAfter.push(winding);
|
|
5644
|
-
} else windingsAfter[index] += winding;
|
|
5496
|
+
};
|
|
5497
|
+
var MultiPolyIn = class {
|
|
5498
|
+
isSubject;
|
|
5499
|
+
polys;
|
|
5500
|
+
bbox;
|
|
5501
|
+
constructor(geom, isSubject) {
|
|
5502
|
+
if (!Array.isArray(geom)) {
|
|
5503
|
+
throw new Error("Input geometry is not a valid Polygon or MultiPolygon");
|
|
5645
5504
|
}
|
|
5646
|
-
|
|
5647
|
-
|
|
5648
|
-
|
|
5649
|
-
if (windingsAfter[i] === 0) continue;
|
|
5650
|
-
const ring = ringsAfter[i];
|
|
5651
|
-
const poly = ring.poly;
|
|
5652
|
-
if (polysExclude.indexOf(poly) !== -1) continue;
|
|
5653
|
-
if (ring.isExterior) polysAfter.push(poly);
|
|
5654
|
-
else {
|
|
5655
|
-
if (polysExclude.indexOf(poly) === -1) polysExclude.push(poly);
|
|
5656
|
-
const index = polysAfter.indexOf(ring.poly);
|
|
5657
|
-
if (index !== -1) polysAfter.splice(index, 1);
|
|
5658
|
-
}
|
|
5505
|
+
try {
|
|
5506
|
+
if (typeof geom[0][0][0] === "number") geom = [geom];
|
|
5507
|
+
} catch (ex) {
|
|
5659
5508
|
}
|
|
5660
|
-
|
|
5661
|
-
|
|
5662
|
-
|
|
5509
|
+
this.polys = [];
|
|
5510
|
+
this.bbox = {
|
|
5511
|
+
ll: { x: new BigNumber(Number.POSITIVE_INFINITY), y: new BigNumber(Number.POSITIVE_INFINITY) },
|
|
5512
|
+
ur: { x: new BigNumber(Number.NEGATIVE_INFINITY), y: new BigNumber(Number.NEGATIVE_INFINITY) }
|
|
5513
|
+
};
|
|
5514
|
+
for (let i = 0, iMax = geom.length; i < iMax; i++) {
|
|
5515
|
+
const poly = new PolyIn(geom[i], this);
|
|
5516
|
+
if (poly.bbox.ll.x.isLessThan(this.bbox.ll.x)) this.bbox.ll.x = poly.bbox.ll.x;
|
|
5517
|
+
if (poly.bbox.ll.y.isLessThan(this.bbox.ll.y)) this.bbox.ll.y = poly.bbox.ll.y;
|
|
5518
|
+
if (poly.bbox.ur.x.isGreaterThan(this.bbox.ur.x)) this.bbox.ur.x = poly.bbox.ur.x;
|
|
5519
|
+
if (poly.bbox.ur.y.isGreaterThan(this.bbox.ur.y)) this.bbox.ur.y = poly.bbox.ur.y;
|
|
5520
|
+
this.polys.push(poly);
|
|
5663
5521
|
}
|
|
5664
|
-
|
|
5522
|
+
this.isSubject = isSubject;
|
|
5665
5523
|
}
|
|
5666
|
-
|
|
5667
|
-
|
|
5668
|
-
|
|
5669
|
-
|
|
5670
|
-
|
|
5671
|
-
|
|
5672
|
-
switch (operation_default.type) {
|
|
5673
|
-
case "union": {
|
|
5674
|
-
const noBefores = mpsBefore.length === 0;
|
|
5675
|
-
const noAfters = mpsAfter.length === 0;
|
|
5676
|
-
this._isInResult = noBefores !== noAfters;
|
|
5677
|
-
break;
|
|
5678
|
-
}
|
|
5679
|
-
case "intersection": {
|
|
5680
|
-
let least;
|
|
5681
|
-
let most;
|
|
5682
|
-
if (mpsBefore.length < mpsAfter.length) {
|
|
5683
|
-
least = mpsBefore.length;
|
|
5684
|
-
most = mpsAfter.length;
|
|
5685
|
-
} else {
|
|
5686
|
-
least = mpsAfter.length;
|
|
5687
|
-
most = mpsBefore.length;
|
|
5688
|
-
}
|
|
5689
|
-
this._isInResult = most === operation_default.numMultiPolys && least < most;
|
|
5690
|
-
break;
|
|
5691
|
-
}
|
|
5692
|
-
case "xor": {
|
|
5693
|
-
const diff = Math.abs(mpsBefore.length - mpsAfter.length);
|
|
5694
|
-
this._isInResult = diff % 2 === 1;
|
|
5695
|
-
break;
|
|
5696
|
-
}
|
|
5697
|
-
case "difference": {
|
|
5698
|
-
const isJustSubject = (mps) => mps.length === 1 && mps[0].isSubject;
|
|
5699
|
-
this._isInResult = isJustSubject(mpsBefore) !== isJustSubject(mpsAfter);
|
|
5700
|
-
break;
|
|
5524
|
+
getSweepEvents() {
|
|
5525
|
+
const sweepEvents = [];
|
|
5526
|
+
for (let i = 0, iMax = this.polys.length; i < iMax; i++) {
|
|
5527
|
+
const polySweepEvents = this.polys[i].getSweepEvents();
|
|
5528
|
+
for (let j = 0, jMax = polySweepEvents.length; j < jMax; j++) {
|
|
5529
|
+
sweepEvents.push(polySweepEvents[j]);
|
|
5701
5530
|
}
|
|
5702
5531
|
}
|
|
5703
|
-
return
|
|
5532
|
+
return sweepEvents;
|
|
5704
5533
|
}
|
|
5705
5534
|
};
|
|
5535
|
+
var difference = (geom, ...moreGeoms) => operation_default.run("difference", geom, moreGeoms);
|
|
5536
|
+
precision.set;
|
|
5537
|
+
|
|
5538
|
+
// index.ts
|
|
5539
|
+
function difference2(features) {
|
|
5540
|
+
const geoms = [];
|
|
5541
|
+
geomEach(features, (geom) => {
|
|
5542
|
+
geoms.push(geom.coordinates);
|
|
5543
|
+
});
|
|
5544
|
+
if (geoms.length < 2) {
|
|
5545
|
+
throw new Error("Must have at least two features");
|
|
5546
|
+
}
|
|
5547
|
+
const properties = features.features[0].properties || {};
|
|
5548
|
+
const differenced = difference(geoms[0], ...geoms.slice(1));
|
|
5549
|
+
if (differenced.length === 0) return null;
|
|
5550
|
+
if (differenced.length === 1) return polygon(differenced[0], properties);
|
|
5551
|
+
return multiPolygon(differenced, properties);
|
|
5552
|
+
}
|
|
5553
|
+
|
|
5554
|
+
/**
|
|
5555
|
+
* 传入一个 features 数组(至少包含两个要素),
|
|
5556
|
+
* 计算第二个要素(features[1])中,不在第一个要素(features[0])内部的部分,
|
|
5557
|
+
* 即:features[1] 减去 features[0],返回这一部分(GeoJSON Feature)。
|
|
5558
|
+
*
|
|
5559
|
+
* @param {Array<turf.Feature>} features - GeoJSON Feature 数组,至少包含两个要素
|
|
5560
|
+
* @returns {turf.Feature | null} - 返回 features[1] 减去 features[0] 的部分,如果出错或无效返回 null
|
|
5561
|
+
*/
|
|
5562
|
+
function getFeatureOutsidePart(features) {
|
|
5563
|
+
if (!Array.isArray(features) || features.length < 2) {
|
|
5564
|
+
console.error('Input must be an array of at least two GeoJSON Features.');
|
|
5565
|
+
return null;
|
|
5566
|
+
}
|
|
5567
|
+
|
|
5568
|
+
// 我们要计算的是:featureB - featureA,即 featureB 的外部部分(不在 featureA 中的部分)
|
|
5569
|
+
const differenceResult = difference2(featureCollection(features));
|
|
5570
|
+
|
|
5571
|
+
if (!differenceResult) {
|
|
5572
|
+
console.warn('Difference result is empty or invalid. The second feature may be fully inside the first one.');
|
|
5573
|
+
return null; // 两者无差异,或者输入几何有问题
|
|
5574
|
+
}
|
|
5575
|
+
|
|
5576
|
+
return differenceResult; // 返回的就是 features[1] 在 features[0] 外部的部分
|
|
5577
|
+
}
|
|
5578
|
+
const RT_FitBoundsMapbox = (map, featureCollection) => {
|
|
5579
|
+
try {
|
|
5580
|
+
if (!map || !featureCollection) {
|
|
5581
|
+
console.error('RT_FitBoundsMapbox: map 或 featureCollection 参数不能为空');
|
|
5582
|
+
return;
|
|
5583
|
+
}
|
|
5584
|
+
|
|
5585
|
+
|
|
5586
|
+
const boundsArray = bbox(featureCollection); // [minLng, minLat, maxLng, maxLat]
|
|
5587
|
+
|
|
5588
|
+
if (!boundsArray || boundsArray.length !== 4) {
|
|
5589
|
+
console.error('RT_FitBoundsMapbox: 无法计算有效的包围盒');
|
|
5590
|
+
return;
|
|
5591
|
+
}
|
|
5592
|
+
|
|
5593
|
+
const [minLng, minLat, maxLng, maxLat] = boundsArray;
|
|
5594
|
+
|
|
5595
|
+
const bounds = [
|
|
5596
|
+
[minLng, minLat], // 左下角
|
|
5597
|
+
[maxLng, maxLat] // 右上角
|
|
5598
|
+
];
|
|
5599
|
+
|
|
5600
|
+
map.fitBounds(bounds, {
|
|
5601
|
+
padding: 20, // 可选:边距(单位像素)
|
|
5602
|
+
maxZoom: 15, // 可选:最大缩放级别,避免太近
|
|
5603
|
+
duration: 1000, // 可选:动画时长(毫秒)
|
|
5604
|
+
easing: (t) => {
|
|
5605
|
+
return t;
|
|
5606
|
+
}
|
|
5607
|
+
});
|
|
5608
|
+
} catch (error) {
|
|
5609
|
+
console.error('RT_FitBoundsMapbox: 拟合地图边界时出错', error);
|
|
5610
|
+
}
|
|
5611
|
+
|
|
5612
|
+
};
|
|
5613
|
+
const RT_FitBoundsMapboxNative = (map, featureCollection) => {
|
|
5614
|
+
try {
|
|
5615
|
+
if (!map || !featureCollection) {
|
|
5616
|
+
console.error('RT_FitBoundsMapbox: map 或 featureCollection 参数不能为空');
|
|
5617
|
+
return;
|
|
5618
|
+
}
|
|
5619
|
+
|
|
5620
|
+
// ✅ 手写函数:计算 FeatureCollection 的 Bounding Box [minLng, minLat, maxLng, maxLat]
|
|
5621
|
+
const calculateBoundingBox = (featureCollection) => {
|
|
5622
|
+
let minLng = Infinity;
|
|
5623
|
+
let minLat = Infinity;
|
|
5624
|
+
let maxLng = -Infinity;
|
|
5625
|
+
let maxLat = -Infinity;
|
|
5626
|
+
|
|
5627
|
+
// 遍历每个 feature
|
|
5628
|
+
for (const feature of featureCollection.features) {
|
|
5629
|
+
const coords = feature.geometry.coordinates;
|
|
5630
|
+
|
|
5631
|
+
// 递归遍历坐标(支持 Point、LineString、Polygon、Multi 等)
|
|
5632
|
+
const traverseCoordinates = (coords) => {
|
|
5633
|
+
if (!Array.isArray(coords)) return;
|
|
5634
|
+
|
|
5635
|
+
// 判断坐标类型:
|
|
5636
|
+
if (typeof coords[0] === 'number') {
|
|
5637
|
+
// 🟢 这是一个点 [lng, lat]
|
|
5638
|
+
const [lng, lat] = coords;
|
|
5639
|
+
if (lng < minLng) minLng = lng;
|
|
5640
|
+
if (lng > maxLng) maxLng = lng;
|
|
5641
|
+
if (lat < minLat) minLat = lat;
|
|
5642
|
+
if (lat > maxLat) maxLat = lat;
|
|
5643
|
+
} else if (Array.isArray(coords[0])) {
|
|
5644
|
+
// 🔵 可能是 LineString、Polygon、MultiPoint 等(嵌套数组)
|
|
5645
|
+
for (const subCoords of coords) {
|
|
5646
|
+
traverseCoordinates(subCoords);
|
|
5647
|
+
}
|
|
5648
|
+
}
|
|
5649
|
+
// 注意:更复杂的 GeometryCollection 或 MultiPolygon 也按类似方式递归,但此处已覆盖大部分情况
|
|
5650
|
+
};
|
|
5651
|
+
|
|
5652
|
+
traverseCoordinates(coords);
|
|
5653
|
+
}
|
|
5654
|
+
|
|
5655
|
+
// 如果没有有效的点(比如 featureCollection 为空或没有坐标)
|
|
5656
|
+
if (
|
|
5657
|
+
minLng === Infinity ||
|
|
5658
|
+
minLat === Infinity ||
|
|
5659
|
+
maxLng === -Infinity ||
|
|
5660
|
+
maxLat === -Infinity
|
|
5661
|
+
) {
|
|
5662
|
+
console.error('RT_FitBoundsMapbox: 未找到有效的坐标点');
|
|
5663
|
+
return null;
|
|
5664
|
+
}
|
|
5665
|
+
|
|
5666
|
+
return [minLng, minLat, maxLng, maxLat];
|
|
5667
|
+
};
|
|
5668
|
+
|
|
5669
|
+
// ✅ 调用手写函数,计算 bounding box
|
|
5670
|
+
const boundsArray = calculateBoundingBox(featureCollection);
|
|
5671
|
+
|
|
5672
|
+
if (!boundsArray) {
|
|
5673
|
+
console.error('RT_FitBoundsMapbox: 无法计算有效的包围盒');
|
|
5674
|
+
return;
|
|
5675
|
+
}
|
|
5676
|
+
|
|
5677
|
+
const [minLng, minLat, maxLng, maxLat] = boundsArray;
|
|
5678
|
+
|
|
5679
|
+
const bounds = [
|
|
5680
|
+
[minLng, minLat], // 左下角
|
|
5681
|
+
[maxLng, maxLat] // 右上角
|
|
5682
|
+
];
|
|
5683
|
+
console.log(`output->bounds`, bounds);
|
|
5684
|
+
bounds.forEach(item => {
|
|
5685
|
+
item.forEach((i, index) => {
|
|
5686
|
+
item[index] = Number((i).toFixed(6));
|
|
5687
|
+
});
|
|
5688
|
+
});
|
|
5689
|
+
// ✅ 调用 Mapbox 的 fitBounds
|
|
5690
|
+
map.fitBounds(bounds, {
|
|
5691
|
+
padding: 50, // 可选:边距(单位像素)
|
|
5692
|
+
maxZoom: 15, // 可选:最大缩放级别,避免太近
|
|
5693
|
+
duration: 1000, // 可选:动画时长(毫秒)
|
|
5694
|
+
});
|
|
5695
|
+
|
|
5696
|
+
} catch (error) {
|
|
5697
|
+
console.error('RT_FitBoundsMapbox: 拟合地图边界时出错', error);
|
|
5698
|
+
}
|
|
5699
|
+
};
|
|
5706
5700
|
|
|
5707
|
-
|
|
5708
|
-
|
|
5709
|
-
|
|
5710
|
-
|
|
5711
|
-
|
|
5712
|
-
|
|
5713
|
-
|
|
5714
|
-
|
|
5715
|
-
|
|
5716
|
-
|
|
5717
|
-
|
|
5718
|
-
|
|
5719
|
-
|
|
5720
|
-
|
|
5721
|
-
|
|
5722
|
-
|
|
5723
|
-
|
|
5724
|
-
|
|
5725
|
-
|
|
5726
|
-
|
|
5727
|
-
|
|
5728
|
-
|
|
5729
|
-
|
|
5730
|
-
|
|
5731
|
-
|
|
5732
|
-
|
|
5733
|
-
|
|
5734
|
-
|
|
5735
|
-
|
|
5736
|
-
|
|
5737
|
-
|
|
5738
|
-
|
|
5739
|
-
|
|
5740
|
-
|
|
5741
|
-
|
|
5742
|
-
|
|
5743
|
-
|
|
5744
|
-
}
|
|
5745
|
-
|
|
5746
|
-
|
|
5747
|
-
|
|
5748
|
-
|
|
5749
|
-
|
|
5750
|
-
|
|
5751
|
-
|
|
5752
|
-
|
|
5753
|
-
|
|
5754
|
-
|
|
5755
|
-
|
|
5756
|
-
|
|
5757
|
-
|
|
5758
|
-
|
|
5759
|
-
|
|
5760
|
-
|
|
5761
|
-
|
|
5762
|
-
|
|
5763
|
-
|
|
5764
|
-
|
|
5765
|
-
|
|
5766
|
-
|
|
5767
|
-
|
|
5768
|
-
|
|
5769
|
-
|
|
5770
|
-
|
|
5771
|
-
|
|
5772
|
-
|
|
5773
|
-
|
|
5774
|
-
|
|
5775
|
-
|
|
5776
|
-
|
|
5777
|
-
|
|
5778
|
-
|
|
5779
|
-
|
|
5780
|
-
|
|
5781
|
-
|
|
5782
|
-
|
|
5783
|
-
|
|
5784
|
-
|
|
5785
|
-
|
|
5786
|
-
|
|
5787
|
-
|
|
5788
|
-
|
|
5789
|
-
|
|
5790
|
-
|
|
5791
|
-
|
|
5792
|
-
|
|
5793
|
-
|
|
5794
|
-
|
|
5795
|
-
|
|
5796
|
-
|
|
5797
|
-
|
|
5798
|
-
|
|
5799
|
-
}
|
|
5800
|
-
|
|
5801
|
-
|
|
5802
|
-
|
|
5803
|
-
|
|
5804
|
-
|
|
5805
|
-
|
|
5806
|
-
|
|
5807
|
-
|
|
5808
|
-
|
|
5809
|
-
|
|
5810
|
-
|
|
5811
|
-
|
|
5812
|
-
|
|
5813
|
-
|
|
5814
|
-
|
|
5815
|
-
|
|
5816
|
-
}
|
|
5817
|
-
|
|
5818
|
-
}
|
|
5819
|
-
getSweepEvents() {
|
|
5820
|
-
const sweepEvents = [];
|
|
5821
|
-
for (let i = 0, iMax = this.polys.length; i < iMax; i++) {
|
|
5822
|
-
const polySweepEvents = this.polys[i].getSweepEvents();
|
|
5823
|
-
for (let j = 0, jMax = polySweepEvents.length; j < jMax; j++) {
|
|
5824
|
-
sweepEvents.push(polySweepEvents[j]);
|
|
5825
|
-
}
|
|
5826
|
-
}
|
|
5827
|
-
return sweepEvents;
|
|
5828
|
-
}
|
|
5829
|
-
};
|
|
5830
|
-
var difference = (geom, ...moreGeoms) => operation_default.run("difference", geom, moreGeoms);
|
|
5831
|
-
precision.set;
|
|
5701
|
+
var RainteeGISUtil = /*#__PURE__*/Object.freeze({
|
|
5702
|
+
__proto__: null,
|
|
5703
|
+
RT_FitBoundsMapbox: RT_FitBoundsMapbox,
|
|
5704
|
+
RT_FitBoundsMapboxNative: RT_FitBoundsMapboxNative,
|
|
5705
|
+
getFeatureOutsidePart: getFeatureOutsidePart
|
|
5706
|
+
});
|
|
5707
|
+
|
|
5708
|
+
const treeDataAdapter = (data) => {
|
|
5709
|
+
let i = 0;
|
|
5710
|
+
let treeData = [];
|
|
5711
|
+
let checkedKeys = [];
|
|
5712
|
+
data.forEach((item) => {
|
|
5713
|
+
let kvs = item.id.split(';').map(kvstr => kvstr.split('='));
|
|
5714
|
+
let groups = kvs.find(item => item[0] === 'Main')[1].split('/');
|
|
5715
|
+
let layerName = kvs.find(item => item[0] === 'CN')[1];
|
|
5716
|
+
let currentNode = treeData;
|
|
5717
|
+
groups.forEach((group, index) => {
|
|
5718
|
+
currentNode.find(item => item.label === group) || i++;
|
|
5719
|
+
currentNode.find(item => item.label === group) || currentNode.push({
|
|
5720
|
+
id: i,
|
|
5721
|
+
label: group,
|
|
5722
|
+
children: []
|
|
5723
|
+
});
|
|
5724
|
+
currentNode = currentNode.find(item => item.label === group).children;
|
|
5725
|
+
});
|
|
5726
|
+
i++;
|
|
5727
|
+
currentNode.push({
|
|
5728
|
+
id: i,
|
|
5729
|
+
label: layerName,
|
|
5730
|
+
fullLayerName: groups.length === 0 ? layerName : groups.join('-') + '-' + layerName,
|
|
5731
|
+
layerId: item.id,
|
|
5732
|
+
opacity: '1.0',
|
|
5733
|
+
});
|
|
5734
|
+
if (item.layout && item.layout.visibility == 'visible') {
|
|
5735
|
+
checkedKeys.push(i);
|
|
5736
|
+
}
|
|
5737
|
+
});
|
|
5738
|
+
return { treeData, checkedKeys }
|
|
5739
|
+
};
|
|
5740
|
+
const treeDataAdapterNext = (data) => {
|
|
5741
|
+
let i = 0;
|
|
5742
|
+
let treeData = [];
|
|
5743
|
+
let checkedKeys = [];
|
|
5744
|
+
data.forEach((item) => {
|
|
5745
|
+
let kvs = item.id.split(';').map(kvstr => kvstr.split('='));
|
|
5746
|
+
let groups = kvs.find(item => item[0] === 'Main')[1].split('/');
|
|
5747
|
+
let layerName = kvs.find(item => item[0] === 'CN')[1];
|
|
5748
|
+
let currentNode = treeData;
|
|
5749
|
+
groups.length === 0 ? layerName : groups.join('-') + '-' + layerName;
|
|
5750
|
+
groups.forEach((group, index) => {
|
|
5751
|
+
currentNode.find(item => item.label === group) || i++;
|
|
5752
|
+
currentNode.find(item => item.label === group) || currentNode.push({
|
|
5753
|
+
id: `TreeId=${i};`,
|
|
5754
|
+
label: group,
|
|
5755
|
+
children: []
|
|
5756
|
+
});
|
|
5757
|
+
currentNode = currentNode.find(item => item.label === group).children;
|
|
5758
|
+
});
|
|
5759
|
+
i++;
|
|
5760
|
+
currentNode.push({
|
|
5761
|
+
id: item.id,
|
|
5762
|
+
label: layerName,
|
|
5763
|
+
fullLayerName: getLayerIdFidld(item.id, 'Main') + '-' + getLayerIdFidld(item.id, 'CN'),
|
|
5764
|
+
layerId: item.id,
|
|
5765
|
+
opacity: '1.0',
|
|
5766
|
+
});
|
|
5767
|
+
if (item.layout && item.layout.visibility == 'visible') {
|
|
5768
|
+
checkedKeys.push(i);
|
|
5769
|
+
}
|
|
5770
|
+
});
|
|
5771
|
+
return { treeData, checkedKeys }
|
|
5772
|
+
};
|
|
5773
|
+
const getLayerIdFidld = (str, field) => {
|
|
5774
|
+
let kvs = str.split(';').map(kvstr => kvstr.split('='));
|
|
5775
|
+
let layerId = kvs.find(item => item[0] === field)[1];
|
|
5776
|
+
return layerId
|
|
5777
|
+
};
|
|
5778
|
+
/**
|
|
5779
|
+
* 生成唯一ID字符串
|
|
5780
|
+
* @param {string} projectId 项目ID
|
|
5781
|
+
* @param {string} objectTypeId 对象种类ID
|
|
5782
|
+
* @param {string} groupId 对象分组ID
|
|
5783
|
+
* @param {string} objectId 对象ID
|
|
5784
|
+
* @returns {string} 唯一ID字符串
|
|
5785
|
+
*/
|
|
5786
|
+
const GenerateUniqueId = (
|
|
5787
|
+
projectId,
|
|
5788
|
+
objectTypeId,
|
|
5789
|
+
groupId,
|
|
5790
|
+
objectId
|
|
5791
|
+
) => {
|
|
5792
|
+
// 将参数组合成一个字符串
|
|
5793
|
+
const combinedString = `${projectId}|${objectTypeId}|${groupId}|${objectId}`;
|
|
5794
|
+
|
|
5795
|
+
// 使用简单的哈希函数生成固定长度的字符串
|
|
5796
|
+
let hash = 0;
|
|
5797
|
+
for (let i = 0; i < combinedString.length; i++) {
|
|
5798
|
+
const char = combinedString.charCodeAt(i);
|
|
5799
|
+
hash = (hash << 5) - hash + char;
|
|
5800
|
+
hash = hash & hash; // Convert to 32bit integer
|
|
5801
|
+
}
|
|
5802
|
+
|
|
5803
|
+
// 转换为16进制字符串并补零到8位
|
|
5804
|
+
const hexHash = (hash >>> 0).toString(16).padStart(8, "0");
|
|
5805
|
+
|
|
5806
|
+
// 添加前缀和分隔符增强可读性
|
|
5807
|
+
return `UID-${projectId.slice(0, 2)}-${objectTypeId.slice(
|
|
5808
|
+
0,
|
|
5809
|
+
2
|
|
5810
|
+
)}-${groupId.slice(0, 2)}-${hexHash}`;
|
|
5811
|
+
};
|
|
5832
5812
|
|
|
5833
|
-
|
|
5834
|
-
|
|
5835
|
-
|
|
5836
|
-
|
|
5837
|
-
|
|
5838
|
-
|
|
5839
|
-
|
|
5840
|
-
throw new Error("Must have at least two features");
|
|
5841
|
-
}
|
|
5842
|
-
const properties = features.features[0].properties || {};
|
|
5843
|
-
const differenced = difference(geoms[0], ...geoms.slice(1));
|
|
5844
|
-
if (differenced.length === 0) return null;
|
|
5845
|
-
if (differenced.length === 1) return polygon(differenced[0], properties);
|
|
5846
|
-
return multiPolygon(differenced, properties);
|
|
5847
|
-
}
|
|
5813
|
+
var RainteeSourceMapTool = /*#__PURE__*/Object.freeze({
|
|
5814
|
+
__proto__: null,
|
|
5815
|
+
GenerateUniqueId: GenerateUniqueId,
|
|
5816
|
+
getLayerIdFidld: getLayerIdFidld,
|
|
5817
|
+
treeDataAdapter: treeDataAdapter,
|
|
5818
|
+
treeDataAdapterNext: treeDataAdapterNext
|
|
5819
|
+
});
|
|
5848
5820
|
|
|
5849
|
-
|
|
5850
|
-
|
|
5851
|
-
|
|
5852
|
-
|
|
5853
|
-
|
|
5854
|
-
|
|
5855
|
-
|
|
5856
|
-
|
|
5857
|
-
|
|
5858
|
-
|
|
5859
|
-
|
|
5860
|
-
|
|
5821
|
+
class CustomOptionsControl {
|
|
5822
|
+
constructor(args) {
|
|
5823
|
+
const { options, onConfirm } = args;
|
|
5824
|
+
|
|
5825
|
+
this._container = null;
|
|
5826
|
+
this._map = null;
|
|
5827
|
+
|
|
5828
|
+
this._options = options || [];
|
|
5829
|
+
this._onConfirm = onConfirm || (() => { });
|
|
5830
|
+
|
|
5831
|
+
if (!this._options || !Array.isArray(this._options)) {
|
|
5832
|
+
console.error('请传入有效的 options 参数(数组)');
|
|
5833
|
+
}
|
|
5861
5834
|
}
|
|
5862
5835
|
|
|
5863
|
-
|
|
5864
|
-
|
|
5836
|
+
onAdd(map) {
|
|
5837
|
+
this._map = map;
|
|
5865
5838
|
|
|
5866
|
-
|
|
5867
|
-
|
|
5868
|
-
|
|
5839
|
+
// 创建控件外层容器
|
|
5840
|
+
this._container = document.createElement('div');
|
|
5841
|
+
this._container.className = 'mapboxgl-ctrl mapboxgl-ctrl-group custom-options-control';
|
|
5842
|
+
|
|
5843
|
+
// 创建主按钮(初始只显示“三维模型”文字,点击展开)
|
|
5844
|
+
const mainButton = document.createElement('button');
|
|
5845
|
+
mainButton.style.cssText = `
|
|
5846
|
+
width: 100%;
|
|
5847
|
+
height: 100%;
|
|
5848
|
+
padding: 0.25rem 0.5rem;
|
|
5849
|
+
margin: 0;
|
|
5850
|
+
border: 1px solid #ccc;
|
|
5851
|
+
background: white;
|
|
5852
|
+
border-radius: 4px;
|
|
5853
|
+
cursor: pointer;
|
|
5854
|
+
font-size: 14px;
|
|
5855
|
+
text-align: left;
|
|
5856
|
+
`;
|
|
5857
|
+
mainButton.textContent = '三维模型';
|
|
5858
|
+
mainButton.addEventListener('click', () => this._toggleExpanded());
|
|
5859
|
+
|
|
5860
|
+
this._container.appendChild(mainButton);
|
|
5861
|
+
|
|
5862
|
+
// 创建隐藏的选项面板(默认不显示)
|
|
5863
|
+
this._panel = document.createElement('div');
|
|
5864
|
+
this._panel.style.display = 'none';
|
|
5865
|
+
this._panel.style.padding = '10px';
|
|
5866
|
+
this._container.appendChild(this._panel);
|
|
5867
|
+
|
|
5868
|
+
// 创建选项列表和按钮组
|
|
5869
|
+
this._renderOptionsPanel();
|
|
5870
|
+
|
|
5871
|
+
return this._container;
|
|
5869
5872
|
}
|
|
5870
5873
|
|
|
5871
|
-
|
|
5872
|
-
|
|
5873
|
-
|
|
5874
|
-
|
|
5875
|
-
if (!map || !featureCollection) {
|
|
5876
|
-
console.error('RT_FitBoundsMapbox: map 或 featureCollection 参数不能为空');
|
|
5877
|
-
return;
|
|
5878
|
-
}
|
|
5874
|
+
_toggleExpanded() {
|
|
5875
|
+
const isExpanded = this._panel.style.display !== 'none';
|
|
5876
|
+
this._setExpanded(!isExpanded);
|
|
5877
|
+
}
|
|
5879
5878
|
|
|
5879
|
+
_setExpanded(isExpanded) {
|
|
5880
|
+
this._panel.style.display = isExpanded ? 'block' : 'none';
|
|
5881
|
+
}
|
|
5880
5882
|
|
|
5881
|
-
|
|
5883
|
+
_renderOptionsPanel() {
|
|
5884
|
+
// 清空面板内容
|
|
5885
|
+
this._panel.innerHTML = '';
|
|
5882
5886
|
|
|
5883
|
-
|
|
5884
|
-
|
|
5885
|
-
|
|
5887
|
+
// 创建复选框选项列表
|
|
5888
|
+
this._options.forEach((opt) => {
|
|
5889
|
+
const optionDiv = document.createElement('div');
|
|
5890
|
+
optionDiv.style.marginBottom = '6px';
|
|
5891
|
+
|
|
5892
|
+
const label = document.createElement('label');
|
|
5893
|
+
label.style.display = 'flex';
|
|
5894
|
+
label.style.alignItems = 'center';
|
|
5895
|
+
label.style.cursor = 'pointer';
|
|
5896
|
+
|
|
5897
|
+
const checkbox = document.createElement('input');
|
|
5898
|
+
checkbox.type = 'checkbox';
|
|
5899
|
+
checkbox.value = opt.value;
|
|
5900
|
+
checkbox.style.marginRight = '8px';
|
|
5901
|
+
|
|
5902
|
+
// 绑定选中状态
|
|
5903
|
+
checkbox.checked = this._getSelectedOption(opt.value);
|
|
5904
|
+
checkbox.addEventListener('change', () => this._toggleOption(opt.value));
|
|
5905
|
+
|
|
5906
|
+
const span = document.createElement('span');
|
|
5907
|
+
span.textContent = opt.label;
|
|
5908
|
+
|
|
5909
|
+
label.appendChild(checkbox);
|
|
5910
|
+
label.appendChild(span);
|
|
5911
|
+
optionDiv.appendChild(label);
|
|
5912
|
+
this._panel.appendChild(optionDiv);
|
|
5913
|
+
});
|
|
5914
|
+
|
|
5915
|
+
// 创建按钮组:取消 / 确定
|
|
5916
|
+
const buttonGroup = document.createElement('div');
|
|
5917
|
+
buttonGroup.style.marginTop = '12px';
|
|
5918
|
+
buttonGroup.style.display = 'flex';
|
|
5919
|
+
buttonGroup.style.gap = '8px';
|
|
5920
|
+
buttonGroup.style.justifyContent = 'flex-end';
|
|
5921
|
+
|
|
5922
|
+
const cancelButton = document.createElement('button');
|
|
5923
|
+
cancelButton.textContent = '取消';
|
|
5924
|
+
cancelButton.style.cssText = `
|
|
5925
|
+
padding: 6px 12px;
|
|
5926
|
+
background: #ccc;
|
|
5927
|
+
border: none;
|
|
5928
|
+
border-radius: 4px;
|
|
5929
|
+
cursor: pointer;
|
|
5930
|
+
width: auto;
|
|
5931
|
+
`;
|
|
5932
|
+
cancelButton.addEventListener('click', () => this._handleCancel());
|
|
5933
|
+
|
|
5934
|
+
const confirmButton = document.createElement('button');
|
|
5935
|
+
confirmButton.textContent = '确定';
|
|
5936
|
+
confirmButton.style.cssText = `
|
|
5937
|
+
padding: 6px 12px;
|
|
5938
|
+
background: #007cba;
|
|
5939
|
+
color: white;
|
|
5940
|
+
border: none;
|
|
5941
|
+
border-radius: 4px;
|
|
5942
|
+
cursor: pointer;
|
|
5943
|
+
width: auto;
|
|
5944
|
+
`;
|
|
5945
|
+
confirmButton.addEventListener('click', () => this._handleConfirm());
|
|
5946
|
+
|
|
5947
|
+
buttonGroup.appendChild(cancelButton);
|
|
5948
|
+
buttonGroup.appendChild(confirmButton);
|
|
5949
|
+
this._panel.appendChild(buttonGroup);
|
|
5950
|
+
}
|
|
5951
|
+
|
|
5952
|
+
_getSelectedOption(value) {
|
|
5953
|
+
return this._selectedOptions?.includes(value) || false;
|
|
5954
|
+
}
|
|
5955
|
+
|
|
5956
|
+
_toggleOption(value) {
|
|
5957
|
+
if (!this._selectedOptions) this._selectedOptions = [];
|
|
5958
|
+
|
|
5959
|
+
const idx = this._selectedOptions.indexOf(value);
|
|
5960
|
+
if (idx > -1) {
|
|
5961
|
+
this._selectedOptions.splice(idx, 1);
|
|
5962
|
+
} else {
|
|
5963
|
+
this._selectedOptions.push(value);
|
|
5886
5964
|
}
|
|
5887
5965
|
|
|
5888
|
-
|
|
5966
|
+
// 可选:重新渲染复选框状态(如果需要动态更新 UI,但目前 onchange 已处理)
|
|
5967
|
+
}
|
|
5889
5968
|
|
|
5890
|
-
|
|
5891
|
-
|
|
5892
|
-
[maxLng, maxLat] // 右上角
|
|
5893
|
-
];
|
|
5969
|
+
_handleConfirm() {
|
|
5970
|
+
this._setExpanded(false);
|
|
5894
5971
|
|
|
5895
|
-
|
|
5896
|
-
|
|
5897
|
-
|
|
5898
|
-
|
|
5899
|
-
easing: (t) => {
|
|
5900
|
-
return t;
|
|
5901
|
-
}
|
|
5972
|
+
this._onConfirm({
|
|
5973
|
+
selectedOptions: this._selectedOptions || [],
|
|
5974
|
+
unselectedOptions: this._options.filter((item) => !this._selectedOptions?.includes(item.value)),
|
|
5975
|
+
allOptions: this._options,
|
|
5902
5976
|
});
|
|
5903
|
-
} catch (error) {
|
|
5904
|
-
console.error('RT_FitBoundsMapbox: 拟合地图边界时出错', error);
|
|
5905
5977
|
}
|
|
5906
5978
|
|
|
5907
|
-
|
|
5908
|
-
|
|
5909
|
-
|
|
5910
|
-
|
|
5911
|
-
|
|
5912
|
-
|
|
5979
|
+
_handleCancel() {
|
|
5980
|
+
this._setExpanded(false);
|
|
5981
|
+
}
|
|
5982
|
+
|
|
5983
|
+
onRemove() {
|
|
5984
|
+
if (this._container && this._container.parentNode) {
|
|
5985
|
+
this._container.parentNode.removeChild(this._container);
|
|
5913
5986
|
}
|
|
5987
|
+
}
|
|
5988
|
+
}
|
|
5989
|
+
|
|
5990
|
+
// 自定义控件类:ToggleControl
|
|
5991
|
+
class CustomToggleControl {
|
|
5992
|
+
/**
|
|
5993
|
+
* 构造函数
|
|
5994
|
+
* @param {Object} options
|
|
5995
|
+
* @param {string} options.name - 控件名称(用于识别,可选展示)
|
|
5996
|
+
* @param {string} options.field - 控制的字段名,对应 map.SourceMap[field]
|
|
5997
|
+
* @param {boolean} options.defaultValue - 默认值(当 field 未定义时使用)
|
|
5998
|
+
* @param {string} options.svgIcon - SVG 图标字符串,例如 '<svg>...</svg>'
|
|
5999
|
+
* @param {Function} [options.onToggle] - 可选的回调函数,状态切换后调用,参数为最新的布尔值
|
|
6000
|
+
*/
|
|
6001
|
+
constructor({ name, field, defaultValue = false, svgIcon, onToggle }) {
|
|
6002
|
+
this.name = name;
|
|
6003
|
+
this.field = field;
|
|
6004
|
+
this.defaultValue = defaultValue;
|
|
6005
|
+
this.svgIcon = svgIcon;
|
|
6006
|
+
this.onToggle = onToggle; // ✅ 新增:回调函数
|
|
5914
6007
|
|
|
5915
|
-
//
|
|
5916
|
-
|
|
5917
|
-
|
|
5918
|
-
|
|
5919
|
-
|
|
5920
|
-
|
|
6008
|
+
// 控件容器
|
|
6009
|
+
this._container = null;
|
|
6010
|
+
this._button = null;
|
|
6011
|
+
this.isActive = false; // 当前是否为激活状态(高亮/true)
|
|
6012
|
+
}
|
|
6013
|
+
|
|
6014
|
+
// Mapbox 要求的 onAdd 方法
|
|
6015
|
+
onAdd(map) {
|
|
6016
|
+
this.map = map;
|
|
5921
6017
|
|
|
5922
|
-
|
|
5923
|
-
|
|
5924
|
-
|
|
6018
|
+
// 创建外层容器 div
|
|
6019
|
+
this._container = document.createElement('div');
|
|
6020
|
+
this._container.className = 'mapboxgl-ctrl mapboxgl-ctrl-group';
|
|
5925
6021
|
|
|
5926
|
-
|
|
5927
|
-
|
|
5928
|
-
|
|
6022
|
+
// 创建 button 元素
|
|
6023
|
+
this._button = document.createElement('button');
|
|
6024
|
+
this._button.type = 'button';
|
|
6025
|
+
this._button.innerHTML = this.svgIcon;
|
|
5929
6026
|
|
|
5930
|
-
|
|
5931
|
-
|
|
5932
|
-
|
|
5933
|
-
|
|
5934
|
-
|
|
5935
|
-
|
|
5936
|
-
|
|
5937
|
-
|
|
5938
|
-
} else if (Array.isArray(coords[0])) {
|
|
5939
|
-
// 🔵 可能是 LineString、Polygon、MultiPoint 等(嵌套数组)
|
|
5940
|
-
for (const subCoords of coords) {
|
|
5941
|
-
traverseCoordinates(subCoords);
|
|
5942
|
-
}
|
|
5943
|
-
}
|
|
5944
|
-
// 注意:更复杂的 GeometryCollection 或 MultiPolygon 也按类似方式递归,但此处已覆盖大部分情况
|
|
5945
|
-
};
|
|
6027
|
+
// 设置按钮样式
|
|
6028
|
+
this._button.style.cursor = 'pointer';
|
|
6029
|
+
this._button.style.border = 'none';
|
|
6030
|
+
this._button.style.background = 'none';
|
|
6031
|
+
this._button.style.padding = '0';
|
|
6032
|
+
this._button.style.display = 'flex';
|
|
6033
|
+
this._button.style.alignItems = 'center';
|
|
6034
|
+
this._button.style.justifyContent = 'center';
|
|
5946
6035
|
|
|
5947
|
-
|
|
5948
|
-
|
|
6036
|
+
// 初始化状态
|
|
6037
|
+
this.updateStatus();
|
|
5949
6038
|
|
|
5950
|
-
|
|
5951
|
-
|
|
5952
|
-
|
|
5953
|
-
|
|
5954
|
-
maxLng === -Infinity ||
|
|
5955
|
-
maxLat === -Infinity
|
|
5956
|
-
) {
|
|
5957
|
-
console.error('RT_FitBoundsMapbox: 未找到有效的坐标点');
|
|
5958
|
-
return null;
|
|
5959
|
-
}
|
|
6039
|
+
// 绑定点击事件
|
|
6040
|
+
this._button.addEventListener('click', () => {
|
|
6041
|
+
this.toggle();
|
|
6042
|
+
});
|
|
5960
6043
|
|
|
5961
|
-
|
|
5962
|
-
};
|
|
6044
|
+
this._container.appendChild(this._button);
|
|
5963
6045
|
|
|
5964
|
-
|
|
5965
|
-
|
|
6046
|
+
return this._container;
|
|
6047
|
+
}
|
|
5966
6048
|
|
|
5967
|
-
|
|
5968
|
-
|
|
5969
|
-
|
|
6049
|
+
// Mapbox 要求的 onRemove 方法
|
|
6050
|
+
onRemove() {
|
|
6051
|
+
if (this._container && this._container.parentNode) {
|
|
6052
|
+
this._container.parentNode.removeChild(this._container);
|
|
5970
6053
|
}
|
|
6054
|
+
this.map = null;
|
|
6055
|
+
this._container = null;
|
|
6056
|
+
this._button = null;
|
|
6057
|
+
}
|
|
5971
6058
|
|
|
5972
|
-
|
|
6059
|
+
// 更新控件状态(根据当前 field 值)
|
|
6060
|
+
updateStatus() {
|
|
6061
|
+
// 从 map.SourceMap 中获取当前 field 的值,如果不存在则使用 defaultValue
|
|
6062
|
+
let currentValue = this.defaultValue;
|
|
5973
6063
|
|
|
5974
|
-
|
|
5975
|
-
|
|
5976
|
-
|
|
5977
|
-
|
|
5978
|
-
|
|
5979
|
-
|
|
5980
|
-
|
|
5981
|
-
item[index] = Number((i).toFixed(6));
|
|
5982
|
-
});
|
|
5983
|
-
});
|
|
5984
|
-
// ✅ 调用 Mapbox 的 fitBounds
|
|
5985
|
-
map.fitBounds(bounds, {
|
|
5986
|
-
padding: 50, // 可选:边距(单位像素)
|
|
5987
|
-
maxZoom: 15, // 可选:最大缩放级别,避免太近
|
|
5988
|
-
duration: 1000, // 可选:动画时长(毫秒)
|
|
5989
|
-
});
|
|
6064
|
+
if (
|
|
6065
|
+
this.map &&
|
|
6066
|
+
this.map.SourceMap &&
|
|
6067
|
+
typeof this.map.SourceMap[this.field] === 'boolean'
|
|
6068
|
+
) {
|
|
6069
|
+
currentValue = this.map.SourceMap[this.field];
|
|
6070
|
+
}
|
|
5990
6071
|
|
|
5991
|
-
|
|
5992
|
-
|
|
6072
|
+
this.isActive = currentValue; // true 表示激活,false 表示未激活
|
|
6073
|
+
|
|
6074
|
+
// 更新按钮样式
|
|
6075
|
+
if (this.isActive) {
|
|
6076
|
+
this._button.style.opacity = '1';
|
|
6077
|
+
this._button.style.filter = 'none';
|
|
6078
|
+
} else {
|
|
6079
|
+
this._button.style.opacity = '0.4';
|
|
6080
|
+
this._button.style.filter = 'grayscale(100%)';
|
|
6081
|
+
}
|
|
5993
6082
|
}
|
|
5994
|
-
|
|
5995
|
-
|
|
5996
|
-
|
|
5997
|
-
|
|
5998
|
-
|
|
5999
|
-
|
|
6000
|
-
|
|
6001
|
-
|
|
6002
|
-
|
|
6003
|
-
|
|
6004
|
-
|
|
6005
|
-
|
|
6006
|
-
let checkedKeys = [];
|
|
6007
|
-
data.forEach((item) => {
|
|
6008
|
-
let kvs = item.id.split(';').map(kvstr => kvstr.split('='));
|
|
6009
|
-
let groups = kvs.find(item => item[0] === 'Main')[1].split('/');
|
|
6010
|
-
let layerName = kvs.find(item => item[0] === 'CN')[1];
|
|
6011
|
-
let currentNode = treeData;
|
|
6012
|
-
groups.forEach((group, index) => {
|
|
6013
|
-
currentNode.find(item => item.label === group) || i++;
|
|
6014
|
-
currentNode.find(item => item.label === group) || currentNode.push({
|
|
6015
|
-
id: i,
|
|
6016
|
-
label: group,
|
|
6017
|
-
children: []
|
|
6018
|
-
});
|
|
6019
|
-
currentNode = currentNode.find(item => item.label === group).children;
|
|
6020
|
-
});
|
|
6021
|
-
i++;
|
|
6022
|
-
currentNode.push({
|
|
6023
|
-
id: i,
|
|
6024
|
-
label: layerName,
|
|
6025
|
-
fullLayerName: groups.length === 0 ? layerName : groups.join('-') + '-' + layerName,
|
|
6026
|
-
layerId: item.id,
|
|
6027
|
-
opacity: '1.0',
|
|
6028
|
-
});
|
|
6029
|
-
if (item.layout && item.layout.visibility == 'visible') {
|
|
6030
|
-
checkedKeys.push(i);
|
|
6083
|
+
|
|
6084
|
+
// 切换状态
|
|
6085
|
+
toggle() {
|
|
6086
|
+
// 获取当前值
|
|
6087
|
+
let currentValue = this.defaultValue;
|
|
6088
|
+
|
|
6089
|
+
if (
|
|
6090
|
+
this.map &&
|
|
6091
|
+
this.map.SourceMap &&
|
|
6092
|
+
typeof this.map.SourceMap[this.field] === 'boolean'
|
|
6093
|
+
) {
|
|
6094
|
+
currentValue = this.map.SourceMap[this.field];
|
|
6031
6095
|
}
|
|
6032
|
-
|
|
6033
|
-
|
|
6034
|
-
|
|
6035
|
-
|
|
6036
|
-
|
|
6037
|
-
|
|
6038
|
-
|
|
6039
|
-
data.forEach((item) => {
|
|
6040
|
-
let kvs = item.id.split(';').map(kvstr => kvstr.split('='));
|
|
6041
|
-
let groups = kvs.find(item => item[0] === 'Main')[1].split('/');
|
|
6042
|
-
let layerName = kvs.find(item => item[0] === 'CN')[1];
|
|
6043
|
-
let currentNode = treeData;
|
|
6044
|
-
groups.length === 0 ? layerName : groups.join('-') + '-' + layerName;
|
|
6045
|
-
groups.forEach((group, index) => {
|
|
6046
|
-
currentNode.find(item => item.label === group) || i++;
|
|
6047
|
-
currentNode.find(item => item.label === group) || currentNode.push({
|
|
6048
|
-
id: `TreeId=${i};`,
|
|
6049
|
-
label: group,
|
|
6050
|
-
children: []
|
|
6051
|
-
});
|
|
6052
|
-
currentNode = currentNode.find(item => item.label === group).children;
|
|
6053
|
-
});
|
|
6054
|
-
i++;
|
|
6055
|
-
currentNode.push({
|
|
6056
|
-
id: item.id,
|
|
6057
|
-
label: layerName,
|
|
6058
|
-
fullLayerName: getLayerIdFidld(item.id, 'Main') + '-' + getLayerIdFidld(item.id, 'CN'),
|
|
6059
|
-
layerId: item.id,
|
|
6060
|
-
opacity: '1.0',
|
|
6061
|
-
});
|
|
6062
|
-
if (item.layout && item.layout.visibility == 'visible') {
|
|
6063
|
-
checkedKeys.push(i);
|
|
6096
|
+
|
|
6097
|
+
// 切换值
|
|
6098
|
+
const newValue = !currentValue;
|
|
6099
|
+
|
|
6100
|
+
// 更新到 map.SourceMap 中
|
|
6101
|
+
if (this.map && this.map.SourceMap) {
|
|
6102
|
+
this.map.SourceMap[this.field] = newValue;
|
|
6064
6103
|
}
|
|
6065
|
-
});
|
|
6066
|
-
return { treeData, checkedKeys }
|
|
6067
|
-
};
|
|
6068
|
-
const getLayerIdFidld = (str, field) => {
|
|
6069
|
-
let kvs = str.split(';').map(kvstr => kvstr.split('='));
|
|
6070
|
-
let layerId = kvs.find(item => item[0] === field)[1];
|
|
6071
|
-
return layerId
|
|
6072
|
-
};
|
|
6073
|
-
/**
|
|
6074
|
-
* 生成唯一ID字符串
|
|
6075
|
-
* @param {string} projectId 项目ID
|
|
6076
|
-
* @param {string} objectTypeId 对象种类ID
|
|
6077
|
-
* @param {string} groupId 对象分组ID
|
|
6078
|
-
* @param {string} objectId 对象ID
|
|
6079
|
-
* @returns {string} 唯一ID字符串
|
|
6080
|
-
*/
|
|
6081
|
-
const GenerateUniqueId = (
|
|
6082
|
-
projectId,
|
|
6083
|
-
objectTypeId,
|
|
6084
|
-
groupId,
|
|
6085
|
-
objectId
|
|
6086
|
-
) => {
|
|
6087
|
-
// 将参数组合成一个字符串
|
|
6088
|
-
const combinedString = `${projectId}|${objectTypeId}|${groupId}|${objectId}`;
|
|
6089
6104
|
|
|
6090
|
-
|
|
6091
|
-
|
|
6092
|
-
for (let i = 0; i < combinedString.length; i++) {
|
|
6093
|
-
const char = combinedString.charCodeAt(i);
|
|
6094
|
-
hash = (hash << 5) - hash + char;
|
|
6095
|
-
hash = hash & hash; // Convert to 32bit integer
|
|
6096
|
-
}
|
|
6105
|
+
// 更新内部状态
|
|
6106
|
+
this.isActive = newValue;
|
|
6097
6107
|
|
|
6098
|
-
|
|
6099
|
-
|
|
6108
|
+
// 更新 UI 样式
|
|
6109
|
+
this.updateStatus();
|
|
6100
6110
|
|
|
6101
|
-
|
|
6102
|
-
|
|
6103
|
-
|
|
6104
|
-
|
|
6105
|
-
)}-${groupId.slice(0, 2)}-${hexHash}`;
|
|
6106
|
-
};
|
|
6107
|
-
|
|
6108
|
-
var RainteeSourceMapTool = /*#__PURE__*/Object.freeze({
|
|
6109
|
-
__proto__: null,
|
|
6110
|
-
GenerateUniqueId: GenerateUniqueId,
|
|
6111
|
-
getLayerIdFidld: getLayerIdFidld,
|
|
6112
|
-
treeDataAdapter: treeDataAdapter,
|
|
6113
|
-
treeDataAdapterNext: treeDataAdapterNext
|
|
6114
|
-
});
|
|
6111
|
+
// ✅ 调用回调函数(如果传入了 onToggle),并传入最新的值
|
|
6112
|
+
this.onToggle?.(newValue); // 安全调用,仅当函数存在时才执行
|
|
6113
|
+
}
|
|
6114
|
+
}
|
|
6115
6115
|
|
|
6116
6116
|
// RasterLayerController.js
|
|
6117
6117
|
|
|
6118
|
-
class
|
|
6118
|
+
class RasterLayerControl {
|
|
6119
6119
|
constructor() {
|
|
6120
6120
|
this._panel = null;
|
|
6121
6121
|
this._isOpen = false;
|
|
@@ -6562,5 +6562,5 @@ const useDrawCache = () => {
|
|
|
6562
6562
|
}
|
|
6563
6563
|
};
|
|
6564
6564
|
|
|
6565
|
-
export { CustomOptionsControl,
|
|
6565
|
+
export { CustomOptionsControl, CustomToggleControl, RainteeConstants, RainteeGISUtil, RainteeSourceMapTool, RasterLayerControl, TerrainToggleControl, useDrawCache };
|
|
6566
6566
|
//# sourceMappingURL=index.js.map
|