my-openlayer 2.1.1 → 2.1.3
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/MyOl.js +14 -11
- package/core/Line.js +4 -3
- package/core/MapTools.js +5 -5
- package/core/MeasureHandler.js +2 -1
- package/core/Point.js +5 -4
- package/core/Polygon.js +4 -3
- package/core/SelectHandler.d.ts +14 -8
- package/core/SelectHandler.js +97 -41
- package/core/VueTemplatePoint.js +4 -4
- package/index.d.ts +1 -1
- package/package.json +1 -1
- package/types.d.ts +18 -1
- package/utils/ErrorHandler.d.ts +14 -0
- package/utils/ErrorHandler.js +41 -15
- package/utils/ValidationUtils.d.ts +0 -4
- package/utils/ValidationUtils.js +11 -10
package/MyOl.js
CHANGED
|
@@ -34,6 +34,9 @@ class MyOl {
|
|
|
34
34
|
this.configManager = new ConfigManager();
|
|
35
35
|
// 合并配置(处理 undefined 情况)
|
|
36
36
|
this.options = ConfigManager.mergeOptions(MyOl.DefaultOptions, options || {});
|
|
37
|
+
// 初始化日志配置(默认关闭,级别为 error)
|
|
38
|
+
this.errorHandler.setEnabled(this.options.enableLog ?? false);
|
|
39
|
+
this.errorHandler.setLogLevel(this.options.logLevel ?? 'error');
|
|
37
40
|
// 参数验证
|
|
38
41
|
this.validateConstructorParams(id, this.options);
|
|
39
42
|
// 初始化坐标系
|
|
@@ -116,7 +119,7 @@ class MyOl {
|
|
|
116
119
|
const eventManager = this.getEventManager();
|
|
117
120
|
// 地图加载完成事件
|
|
118
121
|
eventManager.on('rendercomplete', (eventData) => {
|
|
119
|
-
|
|
122
|
+
this.errorHandler.debug('地图初始化完成', { map: this.map });
|
|
120
123
|
}, { once: true });
|
|
121
124
|
// 地图错误事件
|
|
122
125
|
eventManager.on('error', (eventData) => {
|
|
@@ -155,7 +158,7 @@ class MyOl {
|
|
|
155
158
|
* @deprecated 请使用 createView 方法
|
|
156
159
|
*/
|
|
157
160
|
static getView(options = MyOl.DefaultOptions) {
|
|
158
|
-
|
|
161
|
+
ErrorHandler.getInstance().warn('getView 方法已废弃,请使用 createView 方法');
|
|
159
162
|
return MyOl.createView(options);
|
|
160
163
|
}
|
|
161
164
|
// ==========================================
|
|
@@ -169,7 +172,7 @@ class MyOl {
|
|
|
169
172
|
try {
|
|
170
173
|
if (!this._polygon) {
|
|
171
174
|
this._polygon = new Polygon(this.map);
|
|
172
|
-
|
|
175
|
+
this.errorHandler.debug('面要素模块已加载');
|
|
173
176
|
}
|
|
174
177
|
return this._polygon;
|
|
175
178
|
}
|
|
@@ -187,7 +190,7 @@ class MyOl {
|
|
|
187
190
|
if (!this._baseLayers) {
|
|
188
191
|
// 检查是否设置了自定义底图
|
|
189
192
|
if (Array.isArray(this.options.layers)) {
|
|
190
|
-
|
|
193
|
+
this.errorHandler.warn('已设置默认底图,MapBaseLayers 中的 switchBaseLayer 方法将失效');
|
|
191
194
|
}
|
|
192
195
|
const layerOptions = {
|
|
193
196
|
layers: this.options.layers,
|
|
@@ -198,7 +201,7 @@ class MyOl {
|
|
|
198
201
|
token: this.options.token || ''
|
|
199
202
|
};
|
|
200
203
|
this._baseLayers = new MapBaseLayers(this.map, layerOptions);
|
|
201
|
-
|
|
204
|
+
this.errorHandler.debug('基础图层模块已加载');
|
|
202
205
|
}
|
|
203
206
|
return this._baseLayers;
|
|
204
207
|
}
|
|
@@ -215,7 +218,7 @@ class MyOl {
|
|
|
215
218
|
try {
|
|
216
219
|
if (!this._point) {
|
|
217
220
|
this._point = new Point(this.map);
|
|
218
|
-
|
|
221
|
+
this.errorHandler.debug('点要素模块已加载');
|
|
219
222
|
}
|
|
220
223
|
return this._point;
|
|
221
224
|
}
|
|
@@ -232,7 +235,7 @@ class MyOl {
|
|
|
232
235
|
try {
|
|
233
236
|
if (!this._line) {
|
|
234
237
|
this._line = new Line(this.map);
|
|
235
|
-
|
|
238
|
+
this.errorHandler.debug('线要素模块已加载');
|
|
236
239
|
}
|
|
237
240
|
return this._line;
|
|
238
241
|
}
|
|
@@ -249,7 +252,7 @@ class MyOl {
|
|
|
249
252
|
try {
|
|
250
253
|
if (!this._selectHandler) {
|
|
251
254
|
this._selectHandler = new SelectHandler(this.map);
|
|
252
|
-
|
|
255
|
+
this.errorHandler.debug('要素选择模块已加载');
|
|
253
256
|
}
|
|
254
257
|
return this._selectHandler;
|
|
255
258
|
}
|
|
@@ -266,7 +269,7 @@ class MyOl {
|
|
|
266
269
|
try {
|
|
267
270
|
if (!this._mapTools) {
|
|
268
271
|
this._mapTools = new MapTools(this.map);
|
|
269
|
-
|
|
272
|
+
this.errorHandler.debug('工具模块已加载');
|
|
270
273
|
}
|
|
271
274
|
return this._mapTools;
|
|
272
275
|
}
|
|
@@ -315,7 +318,7 @@ class MyOl {
|
|
|
315
318
|
}
|
|
316
319
|
this.getPoint().locationAction(longitude, latitude, zoom, duration);
|
|
317
320
|
// 记录定位操作
|
|
318
|
-
|
|
321
|
+
this.errorHandler.debug('地图定位完成', {
|
|
319
322
|
longitude,
|
|
320
323
|
latitude,
|
|
321
324
|
zoom,
|
|
@@ -379,7 +382,7 @@ class MyOl {
|
|
|
379
382
|
this._selectHandler = undefined;
|
|
380
383
|
// 销毁地图
|
|
381
384
|
this.map.setTarget(undefined);
|
|
382
|
-
|
|
385
|
+
this.errorHandler.debug('地图实例已销毁', { map: this.map });
|
|
383
386
|
}
|
|
384
387
|
catch (error) {
|
|
385
388
|
this.errorHandler.handleError(new MyOpenLayersError(`销毁地图失败: ${error instanceof Error ? error.message : '未知错误'}`, ErrorType.MAP_ERROR));
|
package/core/Line.js
CHANGED
|
@@ -6,6 +6,7 @@ import { Feature } from "ol";
|
|
|
6
6
|
import MapTools from "./MapTools";
|
|
7
7
|
import { ValidationUtils } from "../utils/ValidationUtils";
|
|
8
8
|
import { EventManager } from "./EventManager";
|
|
9
|
+
import { ErrorHandler } from "src/utils/ErrorHandler";
|
|
9
10
|
/**
|
|
10
11
|
* 线要素管理类
|
|
11
12
|
* 用于在地图上添加和管理线要素,包括普通线要素、河流图层等
|
|
@@ -183,7 +184,7 @@ export default class Line {
|
|
|
183
184
|
}
|
|
184
185
|
}
|
|
185
186
|
catch (error) {
|
|
186
|
-
|
|
187
|
+
ErrorHandler.getInstance().warn(`Failed to load river feature at level ${level}:`, error);
|
|
187
188
|
}
|
|
188
189
|
}
|
|
189
190
|
});
|
|
@@ -278,14 +279,14 @@ export default class Line {
|
|
|
278
279
|
}
|
|
279
280
|
}
|
|
280
281
|
catch (error) {
|
|
281
|
-
|
|
282
|
+
ErrorHandler.getInstance().warn(`Failed to load river feature at level ${level}:`, error);
|
|
282
283
|
}
|
|
283
284
|
}
|
|
284
285
|
});
|
|
285
286
|
success?.(vectorSource.getFeatures());
|
|
286
287
|
})
|
|
287
288
|
.catch(error => {
|
|
288
|
-
|
|
289
|
+
ErrorHandler.getInstance().error('Error loading river data:', error);
|
|
289
290
|
failure?.();
|
|
290
291
|
});
|
|
291
292
|
}
|
package/core/MapTools.js
CHANGED
|
@@ -62,7 +62,7 @@ class MapTools {
|
|
|
62
62
|
});
|
|
63
63
|
}
|
|
64
64
|
catch (error) {
|
|
65
|
-
|
|
65
|
+
ErrorHandler.getInstance().error('Error getting layers:', error);
|
|
66
66
|
throw new Error('Failed to retrieve layers from map');
|
|
67
67
|
}
|
|
68
68
|
return targetLayer;
|
|
@@ -117,7 +117,7 @@ class MapTools {
|
|
|
117
117
|
});
|
|
118
118
|
}
|
|
119
119
|
catch (error) {
|
|
120
|
-
|
|
120
|
+
ErrorHandler.getInstance().error('Error removing layers:', error);
|
|
121
121
|
throw new Error('Failed to remove layers from map');
|
|
122
122
|
}
|
|
123
123
|
}
|
|
@@ -138,7 +138,7 @@ class MapTools {
|
|
|
138
138
|
});
|
|
139
139
|
}
|
|
140
140
|
catch (error) {
|
|
141
|
-
|
|
141
|
+
ErrorHandler.getInstance().error('Error removing layers:', error);
|
|
142
142
|
throw new Error('Failed to remove layers from map');
|
|
143
143
|
}
|
|
144
144
|
}
|
|
@@ -159,7 +159,7 @@ class MapTools {
|
|
|
159
159
|
});
|
|
160
160
|
}
|
|
161
161
|
catch (error) {
|
|
162
|
-
|
|
162
|
+
ErrorHandler.getInstance().error('Error setting layer visibility:', error);
|
|
163
163
|
throw new Error('Failed to set layer visibility');
|
|
164
164
|
}
|
|
165
165
|
}
|
|
@@ -195,7 +195,7 @@ MapTools.setLayerVisible = (map, layerName, visible) => {
|
|
|
195
195
|
});
|
|
196
196
|
}
|
|
197
197
|
catch (error) {
|
|
198
|
-
|
|
198
|
+
ErrorHandler.getInstance().error('Error setting layer visibility:', error);
|
|
199
199
|
throw new Error('Failed to set layer visibility');
|
|
200
200
|
}
|
|
201
201
|
};
|
package/core/MeasureHandler.js
CHANGED
|
@@ -7,6 +7,7 @@ import { Vector as VectorLayer } from 'ol/layer.js';
|
|
|
7
7
|
import { getArea, getLength } from 'ol/sphere.js';
|
|
8
8
|
import { unByKey } from 'ol/Observable.js';
|
|
9
9
|
import { ValidationUtils } from '../utils/ValidationUtils';
|
|
10
|
+
import { ErrorHandler } from '../utils/ErrorHandler';
|
|
10
11
|
/**
|
|
11
12
|
* 测量工具处理类
|
|
12
13
|
* 提供距离和面积测量功能
|
|
@@ -171,7 +172,7 @@ export default class MeasureHandler {
|
|
|
171
172
|
}
|
|
172
173
|
}
|
|
173
174
|
catch (error) {
|
|
174
|
-
|
|
175
|
+
ErrorHandler.getInstance().error('Error starting measurement:', error);
|
|
175
176
|
throw new Error('Failed to start measurement');
|
|
176
177
|
}
|
|
177
178
|
this._draw = new Draw({
|
package/core/Point.js
CHANGED
|
@@ -11,6 +11,7 @@ import GeoJSON from "ol/format/GeoJSON";
|
|
|
11
11
|
import VueTemplatePoint from './VueTemplatePoint';
|
|
12
12
|
import MapTools from "./MapTools";
|
|
13
13
|
import { ValidationUtils } from '../utils/ValidationUtils';
|
|
14
|
+
import { ErrorHandler } from '../utils/ErrorHandler';
|
|
14
15
|
export default class Point {
|
|
15
16
|
constructor(map) {
|
|
16
17
|
this.map = map;
|
|
@@ -286,7 +287,7 @@ export default class Point {
|
|
|
286
287
|
return true;
|
|
287
288
|
}
|
|
288
289
|
catch (error) {
|
|
289
|
-
|
|
290
|
+
ErrorHandler.getInstance().error('[地图定位]', '定位失败:', error);
|
|
290
291
|
return false;
|
|
291
292
|
}
|
|
292
293
|
}
|
|
@@ -295,7 +296,7 @@ export default class Point {
|
|
|
295
296
|
*/
|
|
296
297
|
addDomPoint(id, lgtd, lttd) {
|
|
297
298
|
if (!id) {
|
|
298
|
-
|
|
299
|
+
ErrorHandler.getInstance().error('Element ID is required');
|
|
299
300
|
return false;
|
|
300
301
|
}
|
|
301
302
|
if (!ValidationUtils.validateLngLat(lgtd, lttd)) {
|
|
@@ -303,7 +304,7 @@ export default class Point {
|
|
|
303
304
|
}
|
|
304
305
|
const el = document.getElementById(id);
|
|
305
306
|
if (!el) {
|
|
306
|
-
|
|
307
|
+
ErrorHandler.getInstance().error(`Element with id '${id}' not found`);
|
|
307
308
|
return false;
|
|
308
309
|
}
|
|
309
310
|
try {
|
|
@@ -318,7 +319,7 @@ export default class Point {
|
|
|
318
319
|
return true;
|
|
319
320
|
}
|
|
320
321
|
catch (error) {
|
|
321
|
-
|
|
322
|
+
ErrorHandler.getInstance().error('Failed to set DOM point:', error);
|
|
322
323
|
return false;
|
|
323
324
|
}
|
|
324
325
|
}
|
package/core/Polygon.js
CHANGED
|
@@ -9,6 +9,7 @@ import { fromExtent } from "ol/geom/Polygon";
|
|
|
9
9
|
import Feature from "ol/Feature";
|
|
10
10
|
import ImageStatic from "ol/source/ImageStatic";
|
|
11
11
|
import MapTools from "./MapTools";
|
|
12
|
+
import { ErrorHandler } from '../utils/ErrorHandler';
|
|
12
13
|
import { ValidationUtils } from '../utils/ValidationUtils';
|
|
13
14
|
/**
|
|
14
15
|
* Polygon 类用于处理地图上的面要素操作
|
|
@@ -276,7 +277,7 @@ export default class Polygon {
|
|
|
276
277
|
};
|
|
277
278
|
const features = layer.getSource()?.getFeatures();
|
|
278
279
|
if (!features) {
|
|
279
|
-
|
|
280
|
+
ErrorHandler.getInstance().warn(`No features found in layer '${layerName}'`);
|
|
280
281
|
return;
|
|
281
282
|
}
|
|
282
283
|
features.forEach((feature) => {
|
|
@@ -345,7 +346,7 @@ export default class Polygon {
|
|
|
345
346
|
});
|
|
346
347
|
}
|
|
347
348
|
else {
|
|
348
|
-
|
|
349
|
+
ErrorHandler.getInstance().warn('暂时不支持的类型');
|
|
349
350
|
}
|
|
350
351
|
return group;
|
|
351
352
|
}
|
|
@@ -578,7 +579,7 @@ export default class Polygon {
|
|
|
578
579
|
throw new Error(`Invalid GeoJSON data: ${error}`);
|
|
579
580
|
}
|
|
580
581
|
if (!features || features.length === 0) {
|
|
581
|
-
|
|
582
|
+
ErrorHandler.getInstance().warn('No features found in mask data');
|
|
582
583
|
}
|
|
583
584
|
const maskLayer = new VectorLayer({
|
|
584
585
|
source: new VectorSource({ features }),
|
package/core/SelectHandler.d.ts
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import Map from "ol/Map";
|
|
2
2
|
import { FeatureLike } from "ol/Feature";
|
|
3
3
|
import { Style } from "ol/style";
|
|
4
|
-
import { SelectOptions, SelectMode } from "../types";
|
|
4
|
+
import { SelectOptions, SelectMode, ProgrammaticSelectOptions } from "../types";
|
|
5
5
|
/**
|
|
6
6
|
* 要素选择处理器类
|
|
7
7
|
* 用于在地图上选择和高亮显示要素,支持单选、多选等多种选择模式
|
|
@@ -57,7 +57,7 @@ export default class SelectHandler {
|
|
|
57
57
|
constructor(map: Map);
|
|
58
58
|
/**
|
|
59
59
|
* 启用要素选择
|
|
60
|
-
* @param mode 选择模式:'click'(点击)、'hover'(悬停)、'
|
|
60
|
+
* @param mode 选择模式:'click'(点击)、'hover'(悬停)、'ctrl'(Ctrl+点击)
|
|
61
61
|
* @param options 选择配置选项
|
|
62
62
|
* @returns SelectHandler 实例(支持链式调用)
|
|
63
63
|
*/
|
|
@@ -80,20 +80,18 @@ export default class SelectHandler {
|
|
|
80
80
|
/**
|
|
81
81
|
* 通过要素ID选择要素
|
|
82
82
|
* @param featureIds 要素ID数组
|
|
83
|
-
* @param
|
|
84
|
-
* @param selectStyle 选中样式(可选,仅作用于此次选择)
|
|
83
|
+
* @param options 编程式选择配置选项
|
|
85
84
|
* @returns SelectHandler 实例(支持链式调用)
|
|
86
85
|
*/
|
|
87
|
-
selectByIds(featureIds: string[],
|
|
86
|
+
selectByIds(featureIds: string[], options?: ProgrammaticSelectOptions): this;
|
|
88
87
|
/**
|
|
89
88
|
* 通过属性选择要素
|
|
90
89
|
* @param propertyName 属性名称
|
|
91
90
|
* @param propertyValue 属性值
|
|
92
|
-
* @param
|
|
93
|
-
* @param selectStyle 选中样式(可选,仅作用于此次选择)
|
|
91
|
+
* @param options 编程式选择配置选项
|
|
94
92
|
* @returns SelectHandler 实例(支持链式调用)
|
|
95
93
|
*/
|
|
96
|
-
selectByProperty(propertyName: string, propertyValue: any,
|
|
94
|
+
selectByProperty(propertyName: string, propertyValue: any, options?: ProgrammaticSelectOptions): this;
|
|
97
95
|
/**
|
|
98
96
|
* 判断选择是否已启用
|
|
99
97
|
* @returns 是否已启用
|
|
@@ -104,6 +102,14 @@ export default class SelectHandler {
|
|
|
104
102
|
* @returns 当前选择模式
|
|
105
103
|
*/
|
|
106
104
|
getCurrentMode(): SelectMode | undefined;
|
|
105
|
+
/**
|
|
106
|
+
* 定位至要素
|
|
107
|
+
* @private
|
|
108
|
+
* @param features 要素数组
|
|
109
|
+
* @param duration 动画持续时间(毫秒),默认500
|
|
110
|
+
* @param padding 边距(像素),默认100
|
|
111
|
+
*/
|
|
112
|
+
private fitToFeatures;
|
|
107
113
|
/**
|
|
108
114
|
* 销毁选择处理器,清理所有资源
|
|
109
115
|
*/
|
package/core/SelectHandler.js
CHANGED
|
@@ -74,7 +74,7 @@ export default class SelectHandler {
|
|
|
74
74
|
}
|
|
75
75
|
/**
|
|
76
76
|
* 启用要素选择
|
|
77
|
-
* @param mode 选择模式:'click'(点击)、'hover'(悬停)、'
|
|
77
|
+
* @param mode 选择模式:'click'(点击)、'hover'(悬停)、'ctrl'(Ctrl+点击)
|
|
78
78
|
* @param options 选择配置选项
|
|
79
79
|
* @returns SelectHandler 实例(支持链式调用)
|
|
80
80
|
*/
|
|
@@ -94,7 +94,7 @@ export default class SelectHandler {
|
|
|
94
94
|
// 添加到地图
|
|
95
95
|
this.map.addInteraction(this.selectInteraction);
|
|
96
96
|
this.isEnabled = true;
|
|
97
|
-
|
|
97
|
+
this.errorHandler.debug('要素选择已启用', { mode, options: mergedOptions });
|
|
98
98
|
return this;
|
|
99
99
|
}
|
|
100
100
|
catch (error) {
|
|
@@ -114,7 +114,7 @@ export default class SelectHandler {
|
|
|
114
114
|
}
|
|
115
115
|
this.isEnabled = false;
|
|
116
116
|
this.currentMode = undefined;
|
|
117
|
-
|
|
117
|
+
this.errorHandler.debug('要素选择已禁用');
|
|
118
118
|
return this;
|
|
119
119
|
}
|
|
120
120
|
catch (error) {
|
|
@@ -146,27 +146,28 @@ export default class SelectHandler {
|
|
|
146
146
|
/**
|
|
147
147
|
* 通过要素ID选择要素
|
|
148
148
|
* @param featureIds 要素ID数组
|
|
149
|
-
* @param
|
|
150
|
-
* @param selectStyle 选中样式(可选,仅作用于此次选择)
|
|
149
|
+
* @param options 编程式选择配置选项
|
|
151
150
|
* @returns SelectHandler 实例(支持链式调用)
|
|
152
151
|
*/
|
|
153
|
-
selectByIds(featureIds,
|
|
152
|
+
selectByIds(featureIds, options) {
|
|
154
153
|
try {
|
|
155
154
|
if (!this.selectInteraction) {
|
|
156
|
-
|
|
155
|
+
this.errorHandler.warn('选择交互未启用,无法选择要素');
|
|
157
156
|
return this;
|
|
158
157
|
}
|
|
159
158
|
if (!featureIds || featureIds.length === 0) {
|
|
160
|
-
|
|
159
|
+
this.errorHandler.warn('要素ID列表为空');
|
|
161
160
|
return this;
|
|
162
161
|
}
|
|
163
162
|
// 清除当前选择
|
|
164
163
|
this.clearSelection();
|
|
164
|
+
// 临时存储选中的要素
|
|
165
|
+
const selectedFeatures = [];
|
|
165
166
|
// 获取所有图层
|
|
166
167
|
const layers = this.map.getLayers().getArray();
|
|
167
168
|
for (const layer of layers) {
|
|
168
169
|
// 过滤图层
|
|
169
|
-
if (layerName && layer.get('layerName') !== layerName) {
|
|
170
|
+
if (options?.layerName && layer.get('layerName') !== options.layerName) {
|
|
170
171
|
continue;
|
|
171
172
|
}
|
|
172
173
|
if (layer instanceof VectorLayer) {
|
|
@@ -177,24 +178,31 @@ export default class SelectHandler {
|
|
|
177
178
|
for (const featureId of featureIds) {
|
|
178
179
|
const feature = source.getFeatureById(featureId);
|
|
179
180
|
if (feature) {
|
|
180
|
-
|
|
181
|
-
if (selectStyle) {
|
|
182
|
-
if (typeof selectStyle === 'function') {
|
|
183
|
-
feature.setStyle(selectStyle(feature));
|
|
184
|
-
}
|
|
185
|
-
else {
|
|
186
|
-
feature.setStyle(selectStyle);
|
|
187
|
-
}
|
|
188
|
-
}
|
|
181
|
+
selectedFeatures.push(feature);
|
|
189
182
|
this.selectInteraction.getFeatures().push(feature);
|
|
190
183
|
}
|
|
191
184
|
}
|
|
192
185
|
}
|
|
193
186
|
}
|
|
187
|
+
// 如果传入了自定义样式,为选中的要素设置样式
|
|
188
|
+
if (options?.selectStyle && selectedFeatures.length > 0) {
|
|
189
|
+
for (const feature of selectedFeatures) {
|
|
190
|
+
if (typeof options.selectStyle === 'function') {
|
|
191
|
+
feature.setStyle(options.selectStyle(feature));
|
|
192
|
+
}
|
|
193
|
+
else {
|
|
194
|
+
feature.setStyle(options.selectStyle);
|
|
195
|
+
}
|
|
196
|
+
}
|
|
197
|
+
}
|
|
198
|
+
// 定位至选中要素
|
|
199
|
+
if (options?.fitView && selectedFeatures.length > 0) {
|
|
200
|
+
this.fitToFeatures(selectedFeatures, options.fitDuration ?? 500, options.fitPadding ?? 100);
|
|
201
|
+
}
|
|
194
202
|
return this;
|
|
195
203
|
}
|
|
196
204
|
catch (error) {
|
|
197
|
-
this.errorHandler.handleError(new MyOpenLayersError(`通过ID选择要素失败: ${error instanceof Error ? error.message : '未知错误'}`, ErrorType.COMPONENT_ERROR, { featureIds,
|
|
205
|
+
this.errorHandler.handleError(new MyOpenLayersError(`通过ID选择要素失败: ${error instanceof Error ? error.message : '未知错误'}`, ErrorType.COMPONENT_ERROR, { featureIds, options }));
|
|
198
206
|
throw error;
|
|
199
207
|
}
|
|
200
208
|
}
|
|
@@ -202,14 +210,13 @@ export default class SelectHandler {
|
|
|
202
210
|
* 通过属性选择要素
|
|
203
211
|
* @param propertyName 属性名称
|
|
204
212
|
* @param propertyValue 属性值
|
|
205
|
-
* @param
|
|
206
|
-
* @param selectStyle 选中样式(可选,仅作用于此次选择)
|
|
213
|
+
* @param options 编程式选择配置选项
|
|
207
214
|
* @returns SelectHandler 实例(支持链式调用)
|
|
208
215
|
*/
|
|
209
|
-
selectByProperty(propertyName, propertyValue,
|
|
216
|
+
selectByProperty(propertyName, propertyValue, options) {
|
|
210
217
|
try {
|
|
211
218
|
if (!this.selectInteraction) {
|
|
212
|
-
|
|
219
|
+
this.errorHandler.warn('选择交互未启用,无法选择要素');
|
|
213
220
|
return this;
|
|
214
221
|
}
|
|
215
222
|
if (!propertyName) {
|
|
@@ -217,11 +224,13 @@ export default class SelectHandler {
|
|
|
217
224
|
}
|
|
218
225
|
// 清除当前选择
|
|
219
226
|
this.clearSelection();
|
|
227
|
+
// 临时存储选中的要素
|
|
228
|
+
const selectedFeatures = [];
|
|
220
229
|
// 获取所有图层
|
|
221
230
|
const layers = this.map.getLayers().getArray();
|
|
222
231
|
for (const layer of layers) {
|
|
223
232
|
// 过滤图层
|
|
224
|
-
if (layerName && layer.get('layerName') !== layerName) {
|
|
233
|
+
if (options?.layerName && layer.get('layerName') !== options.layerName) {
|
|
225
234
|
continue;
|
|
226
235
|
}
|
|
227
236
|
if (layer instanceof VectorLayer) {
|
|
@@ -232,24 +241,31 @@ export default class SelectHandler {
|
|
|
232
241
|
const features = source.getFeatures();
|
|
233
242
|
for (const feature of features) {
|
|
234
243
|
if (feature.get(propertyName) === propertyValue) {
|
|
235
|
-
|
|
236
|
-
if (selectStyle) {
|
|
237
|
-
if (typeof selectStyle === 'function') {
|
|
238
|
-
feature.setStyle(selectStyle(feature));
|
|
239
|
-
}
|
|
240
|
-
else {
|
|
241
|
-
feature.setStyle(selectStyle);
|
|
242
|
-
}
|
|
243
|
-
}
|
|
244
|
+
selectedFeatures.push(feature);
|
|
244
245
|
this.selectInteraction.getFeatures().push(feature);
|
|
245
246
|
}
|
|
246
247
|
}
|
|
247
248
|
}
|
|
248
249
|
}
|
|
250
|
+
// 如果传入了自定义样式,为选中的要素设置样式
|
|
251
|
+
if (options?.selectStyle && selectedFeatures.length > 0) {
|
|
252
|
+
for (const feature of selectedFeatures) {
|
|
253
|
+
if (typeof options.selectStyle === 'function') {
|
|
254
|
+
feature.setStyle(options.selectStyle(feature));
|
|
255
|
+
}
|
|
256
|
+
else {
|
|
257
|
+
feature.setStyle(options.selectStyle);
|
|
258
|
+
}
|
|
259
|
+
}
|
|
260
|
+
}
|
|
261
|
+
// 定位至选中要素
|
|
262
|
+
if (options?.fitView && selectedFeatures.length > 0) {
|
|
263
|
+
this.fitToFeatures(selectedFeatures, options.fitDuration ?? 500, options.fitPadding ?? 100);
|
|
264
|
+
}
|
|
249
265
|
return this;
|
|
250
266
|
}
|
|
251
267
|
catch (error) {
|
|
252
|
-
this.errorHandler.handleError(new MyOpenLayersError(`通过属性选择要素失败: ${error instanceof Error ? error.message : '未知错误'}`, ErrorType.COMPONENT_ERROR, { propertyName, propertyValue,
|
|
268
|
+
this.errorHandler.handleError(new MyOpenLayersError(`通过属性选择要素失败: ${error instanceof Error ? error.message : '未知错误'}`, ErrorType.COMPONENT_ERROR, { propertyName, propertyValue, options }));
|
|
253
269
|
throw error;
|
|
254
270
|
}
|
|
255
271
|
}
|
|
@@ -267,13 +283,56 @@ export default class SelectHandler {
|
|
|
267
283
|
getCurrentMode() {
|
|
268
284
|
return this.currentMode;
|
|
269
285
|
}
|
|
286
|
+
/**
|
|
287
|
+
* 定位至要素
|
|
288
|
+
* @private
|
|
289
|
+
* @param features 要素数组
|
|
290
|
+
* @param duration 动画持续时间(毫秒),默认500
|
|
291
|
+
* @param padding 边距(像素),默认100
|
|
292
|
+
*/
|
|
293
|
+
fitToFeatures(features, duration = 500, padding = 100) {
|
|
294
|
+
try {
|
|
295
|
+
if (!features || features.length === 0) {
|
|
296
|
+
return;
|
|
297
|
+
}
|
|
298
|
+
// 创建一个包含所有要素的范围
|
|
299
|
+
let extent;
|
|
300
|
+
for (const feature of features) {
|
|
301
|
+
const geometry = feature.getGeometry();
|
|
302
|
+
if (geometry) {
|
|
303
|
+
const featureExtent = geometry.getExtent();
|
|
304
|
+
if (!extent) {
|
|
305
|
+
extent = featureExtent;
|
|
306
|
+
}
|
|
307
|
+
else {
|
|
308
|
+
// 扩展范围以包含当前要素
|
|
309
|
+
extent = [
|
|
310
|
+
Math.min(extent[0], featureExtent[0]),
|
|
311
|
+
Math.min(extent[1], featureExtent[1]),
|
|
312
|
+
Math.max(extent[2], featureExtent[2]),
|
|
313
|
+
Math.max(extent[3], featureExtent[3])
|
|
314
|
+
];
|
|
315
|
+
}
|
|
316
|
+
}
|
|
317
|
+
}
|
|
318
|
+
if (extent) {
|
|
319
|
+
this.map.getView().fit(extent, {
|
|
320
|
+
duration,
|
|
321
|
+
padding: [padding, padding, padding, padding]
|
|
322
|
+
});
|
|
323
|
+
}
|
|
324
|
+
}
|
|
325
|
+
catch (error) {
|
|
326
|
+
this.errorHandler.error('定位至要素失败:', error);
|
|
327
|
+
}
|
|
328
|
+
}
|
|
270
329
|
/**
|
|
271
330
|
* 销毁选择处理器,清理所有资源
|
|
272
331
|
*/
|
|
273
332
|
destroy() {
|
|
274
333
|
try {
|
|
275
334
|
this.disableSelect();
|
|
276
|
-
|
|
335
|
+
this.errorHandler.debug('选择处理器已销毁');
|
|
277
336
|
}
|
|
278
337
|
catch (error) {
|
|
279
338
|
this.errorHandler.handleError(new MyOpenLayersError(`销毁选择处理器失败: ${error instanceof Error ? error.message : '未知错误'}`, ErrorType.COMPONENT_ERROR));
|
|
@@ -329,9 +388,6 @@ export default class SelectHandler {
|
|
|
329
388
|
return pointerMove;
|
|
330
389
|
case 'ctrl':
|
|
331
390
|
return platformModifierKeyOnly;
|
|
332
|
-
case 'box':
|
|
333
|
-
// 框选需要额外的 DragBox 交互,这里暂不实现
|
|
334
|
-
return click;
|
|
335
391
|
default:
|
|
336
392
|
return click;
|
|
337
393
|
}
|
|
@@ -386,7 +442,7 @@ export default class SelectHandler {
|
|
|
386
442
|
*/
|
|
387
443
|
updateSelectStyle(selectStyle) {
|
|
388
444
|
if (!this.selectInteraction) {
|
|
389
|
-
|
|
445
|
+
this.errorHandler.warn('选择交互未启用,无法更新样式');
|
|
390
446
|
return this;
|
|
391
447
|
}
|
|
392
448
|
try {
|
|
@@ -428,7 +484,7 @@ export default class SelectHandler {
|
|
|
428
484
|
options.onSelect(callbackEvent);
|
|
429
485
|
}
|
|
430
486
|
catch (error) {
|
|
431
|
-
|
|
487
|
+
this.errorHandler.error('选择回调执行失败:', error);
|
|
432
488
|
}
|
|
433
489
|
}
|
|
434
490
|
// 触发取消选择回调
|
|
@@ -437,7 +493,7 @@ export default class SelectHandler {
|
|
|
437
493
|
options.onDeselect(callbackEvent);
|
|
438
494
|
}
|
|
439
495
|
catch (error) {
|
|
440
|
-
|
|
496
|
+
this.errorHandler.error('取消选择回调执行失败:', error);
|
|
441
497
|
}
|
|
442
498
|
}
|
|
443
499
|
});
|
package/core/VueTemplatePoint.js
CHANGED
|
@@ -20,7 +20,7 @@ async function detectAndImportVue() {
|
|
|
20
20
|
}
|
|
21
21
|
}
|
|
22
22
|
catch (e) {
|
|
23
|
-
|
|
23
|
+
ErrorHandler.getInstance().warn('Vue not found. Please ensure Vue is installed in your project.');
|
|
24
24
|
Vue = null;
|
|
25
25
|
}
|
|
26
26
|
}
|
|
@@ -42,13 +42,13 @@ function detectVueSync() {
|
|
|
42
42
|
isVue3 = !!(Vue.version?.startsWith('3') || Vue.createApp);
|
|
43
43
|
}
|
|
44
44
|
catch (e) {
|
|
45
|
-
|
|
45
|
+
ErrorHandler.getInstance().warn('Vue not found. Please ensure Vue is installed in your project.');
|
|
46
46
|
Vue = null;
|
|
47
47
|
}
|
|
48
48
|
}
|
|
49
49
|
}
|
|
50
50
|
catch (e) {
|
|
51
|
-
|
|
51
|
+
ErrorHandler.getInstance().warn('Failed to detect Vue:', e);
|
|
52
52
|
}
|
|
53
53
|
}
|
|
54
54
|
// 初始化Vue导入
|
|
@@ -457,7 +457,7 @@ class VueTemplatePointInstanceImpl {
|
|
|
457
457
|
*/
|
|
458
458
|
remove() {
|
|
459
459
|
if (this.state === VueTemplatePointState.DESTROYED) {
|
|
460
|
-
|
|
460
|
+
this.errorHandler.warn('DOM point already destroyed');
|
|
461
461
|
return;
|
|
462
462
|
}
|
|
463
463
|
try {
|
package/index.d.ts
CHANGED
|
@@ -16,4 +16,4 @@ export { ValidationUtils } from './utils/ValidationUtils';
|
|
|
16
16
|
export type { BaseOptions, StyleOptions, TextOptions } from './types';
|
|
17
17
|
export type { PointOptions, LineOptions, PolygonOptions } from './types';
|
|
18
18
|
export type { OptionsType } from './types';
|
|
19
|
-
export type { MapInitType, MapLayersOptions, HeatMapOptions, ImageLayerData, MaskLayerOptions, ColorMap, FeatureColorUpdateOptions, PointData, LineData, ClusterOptions, MeasureHandlerType, VueTemplatePointOptions, MapJSONData, FeatureData, AnnotationType, TiandituType, MapLayers, AnnotationLayerOptions, SelectOptions, SelectMode, SelectCallbackEvent } from './types';
|
|
19
|
+
export type { MapInitType, MapLayersOptions, HeatMapOptions, ImageLayerData, MaskLayerOptions, ColorMap, FeatureColorUpdateOptions, PointData, LineData, ClusterOptions, MeasureHandlerType, VueTemplatePointOptions, MapJSONData, FeatureData, AnnotationType, TiandituType, MapLayers, AnnotationLayerOptions, SelectOptions, SelectMode, SelectCallbackEvent, ProgrammaticSelectOptions } from './types';
|
package/package.json
CHANGED
package/types.d.ts
CHANGED
|
@@ -32,6 +32,8 @@ export interface MapInitType {
|
|
|
32
32
|
mapClipData?: MapJSONData;
|
|
33
33
|
token?: string;
|
|
34
34
|
annotation?: boolean;
|
|
35
|
+
enableLog?: boolean;
|
|
36
|
+
logLevel?: 'debug' | 'info' | 'warn' | 'error';
|
|
35
37
|
}
|
|
36
38
|
export type AnnotationType = 'cva_c' | 'cia_c' | 'cta_c';
|
|
37
39
|
export type TiandituType = 'vec_c' | 'img_c' | 'ter_c';
|
|
@@ -306,7 +308,7 @@ export interface VueTemplatePointInstance {
|
|
|
306
308
|
/**
|
|
307
309
|
* 选择模式类型
|
|
308
310
|
*/
|
|
309
|
-
export type SelectMode = 'click' | 'hover' | '
|
|
311
|
+
export type SelectMode = 'click' | 'hover' | 'ctrl';
|
|
310
312
|
/**
|
|
311
313
|
* 选择回调事件接口
|
|
312
314
|
*/
|
|
@@ -337,4 +339,19 @@ export interface SelectOptions {
|
|
|
337
339
|
/** 取消选中要素时的回调函数 */
|
|
338
340
|
onDeselect?: (event: SelectCallbackEvent) => void;
|
|
339
341
|
}
|
|
342
|
+
/**
|
|
343
|
+
* 编程式选择选项接口
|
|
344
|
+
*/
|
|
345
|
+
export interface ProgrammaticSelectOptions {
|
|
346
|
+
/** 图层名称,指定在哪个图层中选择要素 */
|
|
347
|
+
layerName?: string;
|
|
348
|
+
/** 自定义选中样式(仅作用于此次选择) */
|
|
349
|
+
selectStyle?: Style | Style[] | ((feature: FeatureLike) => Style | Style[]);
|
|
350
|
+
/** 是否定位至选中要素,默认 false */
|
|
351
|
+
fitView?: boolean;
|
|
352
|
+
/** 定位动画持续时间(毫秒),默认 500 */
|
|
353
|
+
fitDuration?: number;
|
|
354
|
+
/** 定位时的边距(像素),默认 100 */
|
|
355
|
+
fitPadding?: number;
|
|
356
|
+
}
|
|
340
357
|
export {};
|
package/utils/ErrorHandler.d.ts
CHANGED
|
@@ -25,6 +25,7 @@ export declare class ErrorHandler {
|
|
|
25
25
|
private static instance;
|
|
26
26
|
private errorCallbacks;
|
|
27
27
|
private logLevel;
|
|
28
|
+
private enabled;
|
|
28
29
|
private constructor();
|
|
29
30
|
/**
|
|
30
31
|
* 获取单例实例
|
|
@@ -35,6 +36,19 @@ export declare class ErrorHandler {
|
|
|
35
36
|
* @param level 日志级别
|
|
36
37
|
*/
|
|
37
38
|
setLogLevel(level: 'debug' | 'info' | 'warn' | 'error'): void;
|
|
39
|
+
/**
|
|
40
|
+
* 设置日志开关
|
|
41
|
+
* @param enabled 是否启用日志输出
|
|
42
|
+
*/
|
|
43
|
+
setEnabled(enabled: boolean): void;
|
|
44
|
+
/**
|
|
45
|
+
* 日志门槛判断
|
|
46
|
+
*/
|
|
47
|
+
private shouldLog;
|
|
48
|
+
debug(...args: any[]): void;
|
|
49
|
+
info(...args: any[]): void;
|
|
50
|
+
warn(...args: any[]): void;
|
|
51
|
+
error(...args: any[]): void;
|
|
38
52
|
/**
|
|
39
53
|
* 添加错误回调
|
|
40
54
|
* @param callback 错误回调函数
|
package/utils/ErrorHandler.js
CHANGED
|
@@ -37,6 +37,7 @@ export class ErrorHandler {
|
|
|
37
37
|
constructor() {
|
|
38
38
|
this.errorCallbacks = [];
|
|
39
39
|
this.logLevel = 'error';
|
|
40
|
+
this.enabled = false;
|
|
40
41
|
}
|
|
41
42
|
/**
|
|
42
43
|
* 获取单例实例
|
|
@@ -54,6 +55,45 @@ export class ErrorHandler {
|
|
|
54
55
|
setLogLevel(level) {
|
|
55
56
|
this.logLevel = level;
|
|
56
57
|
}
|
|
58
|
+
/**
|
|
59
|
+
* 设置日志开关
|
|
60
|
+
* @param enabled 是否启用日志输出
|
|
61
|
+
*/
|
|
62
|
+
setEnabled(enabled) {
|
|
63
|
+
this.enabled = enabled;
|
|
64
|
+
}
|
|
65
|
+
/**
|
|
66
|
+
* 日志门槛判断
|
|
67
|
+
*/
|
|
68
|
+
shouldLog(target) {
|
|
69
|
+
const levelOrder = {
|
|
70
|
+
debug: 0,
|
|
71
|
+
info: 1,
|
|
72
|
+
warn: 2,
|
|
73
|
+
error: 3
|
|
74
|
+
};
|
|
75
|
+
return this.enabled && levelOrder[target] >= levelOrder[this.logLevel];
|
|
76
|
+
}
|
|
77
|
+
debug(...args) {
|
|
78
|
+
if (this.shouldLog('debug')) {
|
|
79
|
+
console.debug(...args);
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
info(...args) {
|
|
83
|
+
if (this.shouldLog('info')) {
|
|
84
|
+
console.info(...args);
|
|
85
|
+
}
|
|
86
|
+
}
|
|
87
|
+
warn(...args) {
|
|
88
|
+
if (this.shouldLog('warn')) {
|
|
89
|
+
console.warn(...args);
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
error(...args) {
|
|
93
|
+
if (this.shouldLog('error')) {
|
|
94
|
+
console.error(...args);
|
|
95
|
+
}
|
|
96
|
+
}
|
|
57
97
|
/**
|
|
58
98
|
* 添加错误回调
|
|
59
99
|
* @param callback 错误回调函数
|
|
@@ -112,21 +152,7 @@ export class ErrorHandler {
|
|
|
112
152
|
context: error.context,
|
|
113
153
|
stack: error.stack
|
|
114
154
|
};
|
|
115
|
-
|
|
116
|
-
case 'debug':
|
|
117
|
-
console.debug(logMessage, logData);
|
|
118
|
-
break;
|
|
119
|
-
case 'info':
|
|
120
|
-
console.info(logMessage, logData);
|
|
121
|
-
break;
|
|
122
|
-
case 'warn':
|
|
123
|
-
console.warn(logMessage, logData);
|
|
124
|
-
break;
|
|
125
|
-
case 'error':
|
|
126
|
-
default:
|
|
127
|
-
console.error(logMessage, logData);
|
|
128
|
-
break;
|
|
129
|
-
}
|
|
155
|
+
this.error(logMessage, logData);
|
|
130
156
|
}
|
|
131
157
|
/**
|
|
132
158
|
* 验证参数
|
package/utils/ValidationUtils.js
CHANGED
|
@@ -2,6 +2,7 @@
|
|
|
2
2
|
* 验证工具类
|
|
3
3
|
* 统一管理所有验证方法
|
|
4
4
|
*/
|
|
5
|
+
import { ErrorHandler } from './ErrorHandler';
|
|
5
6
|
export class ValidationUtils {
|
|
6
7
|
/**
|
|
7
8
|
* 验证坐标是否有效
|
|
@@ -27,7 +28,7 @@ export class ValidationUtils {
|
|
|
27
28
|
*/
|
|
28
29
|
static validateLngLat(lgtd, lttd) {
|
|
29
30
|
if (!lgtd || !lttd || isNaN(lgtd) || isNaN(lttd)) {
|
|
30
|
-
|
|
31
|
+
ErrorHandler.getInstance().error('Invalid longitude or latitude coordinates');
|
|
31
32
|
return false;
|
|
32
33
|
}
|
|
33
34
|
return true;
|
|
@@ -39,7 +40,7 @@ export class ValidationUtils {
|
|
|
39
40
|
*/
|
|
40
41
|
static validatePointData(pointData) {
|
|
41
42
|
if (!pointData || pointData.length === 0) {
|
|
42
|
-
|
|
43
|
+
ErrorHandler.getInstance().warn('Point data is empty or undefined');
|
|
43
44
|
return false;
|
|
44
45
|
}
|
|
45
46
|
return true;
|
|
@@ -51,7 +52,7 @@ export class ValidationUtils {
|
|
|
51
52
|
*/
|
|
52
53
|
static validateCoordinates(item) {
|
|
53
54
|
if (!item.lgtd || !item.lttd) {
|
|
54
|
-
|
|
55
|
+
ErrorHandler.getInstance().warn('Invalid coordinates for point:', item);
|
|
55
56
|
return false;
|
|
56
57
|
}
|
|
57
58
|
return true;
|
|
@@ -99,11 +100,11 @@ export class ValidationUtils {
|
|
|
99
100
|
*/
|
|
100
101
|
static validateGeoJSONData(data) {
|
|
101
102
|
if (!data) {
|
|
102
|
-
|
|
103
|
+
ErrorHandler.getInstance().warn('GeoJSON data is required');
|
|
103
104
|
return false;
|
|
104
105
|
}
|
|
105
106
|
if (!data.features || !Array.isArray(data.features)) {
|
|
106
|
-
|
|
107
|
+
ErrorHandler.getInstance().warn('Invalid GeoJSON data: features array is required');
|
|
107
108
|
return false;
|
|
108
109
|
}
|
|
109
110
|
return true;
|
|
@@ -115,7 +116,7 @@ export class ValidationUtils {
|
|
|
115
116
|
*/
|
|
116
117
|
static validateOptions(options) {
|
|
117
118
|
if (!options || typeof options !== 'object') {
|
|
118
|
-
|
|
119
|
+
ErrorHandler.getInstance().warn('Options are required and must be an object');
|
|
119
120
|
return false;
|
|
120
121
|
}
|
|
121
122
|
return true;
|
|
@@ -140,7 +141,7 @@ export class ValidationUtils {
|
|
|
140
141
|
*/
|
|
141
142
|
static validateElementId(id) {
|
|
142
143
|
if (!id) {
|
|
143
|
-
|
|
144
|
+
ErrorHandler.getInstance().error('Element ID is required');
|
|
144
145
|
return false;
|
|
145
146
|
}
|
|
146
147
|
return true;
|
|
@@ -154,15 +155,15 @@ export class ValidationUtils {
|
|
|
154
155
|
*/
|
|
155
156
|
static validateVueParams(pointInfoList, template, Vue) {
|
|
156
157
|
if (!pointInfoList || !Array.isArray(pointInfoList) || pointInfoList.length === 0) {
|
|
157
|
-
|
|
158
|
+
ErrorHandler.getInstance().error('Valid point info list is required');
|
|
158
159
|
return false;
|
|
159
160
|
}
|
|
160
161
|
if (!template) {
|
|
161
|
-
|
|
162
|
+
ErrorHandler.getInstance().error('Vue template is required');
|
|
162
163
|
return false;
|
|
163
164
|
}
|
|
164
165
|
if (!Vue) {
|
|
165
|
-
|
|
166
|
+
ErrorHandler.getInstance().error('Vue instance is required');
|
|
166
167
|
return false;
|
|
167
168
|
}
|
|
168
169
|
return true;
|