my-openlayer 1.0.4 → 1.0.6

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.d.ts CHANGED
@@ -8,7 +8,7 @@ import MapTools from "./core/MapTools";
8
8
  import { ErrorHandler } from './utils/ErrorHandler';
9
9
  import { EventManager } from './core/EventManager';
10
10
  import { ConfigManager } from './core/ConfigManager';
11
- import { MapInitType, EventType } from './types';
11
+ import { MapInitType } from './types';
12
12
  /**
13
13
  * MyOl 地图核心类
14
14
  * 提供完整的地图操作功能,包括点、线、面要素管理,底图切换,工具操作等
@@ -21,7 +21,7 @@ export default class MyOl {
21
21
  private _point?;
22
22
  private _line?;
23
23
  private readonly errorHandler;
24
- private readonly eventManager;
24
+ private _eventManager?;
25
25
  private readonly configManager;
26
26
  private readonly options;
27
27
  static readonly DefaultOptions: MapInitType;
@@ -101,13 +101,6 @@ export default class MyOl {
101
101
  * @param duration 动画持续时间(毫秒)
102
102
  */
103
103
  locationAction(longitude: number, latitude: number, zoom?: number, duration?: number): void;
104
- /**
105
- * 监听地图事件
106
- * @param eventType 事件类型
107
- * @param callback 回调函数
108
- * @param clickType 点击类型(可选)
109
- */
110
- mapOnEvent(eventType: EventType, callback: (feature?: any, e?: any) => void, clickType?: 'point' | 'line' | 'polygon'): void;
111
104
  /**
112
105
  * 获取错误处理器实例
113
106
  * @returns ErrorHandler 错误处理器
package/MyOl.js CHANGED
@@ -46,9 +46,10 @@ class MyOl {
46
46
  layers: layers,
47
47
  controls: this.createControls()
48
48
  });
49
- // 初始化事件管理器(需要地图实例)
50
- this.eventManager = new EventManager(this.map);
51
- // 初始化事件监听
49
+ if (layers.length === 0 || this.options.annotation) {
50
+ this.getMapBaseLayers();
51
+ }
52
+ // 初始化基础事件监听(地图错误等)
52
53
  this.initializeEventListeners();
53
54
  }
54
55
  catch (error) {
@@ -108,13 +109,14 @@ class MyOl {
108
109
  * @private
109
110
  */
110
111
  initializeEventListeners() {
112
+ const eventManager = this.getEventManager();
111
113
  // 地图加载完成事件
112
- this.map.once('rendercomplete', () => {
114
+ eventManager.on('rendercomplete', (eventData) => {
113
115
  console.debug('地图初始化完成', { map: this.map });
114
- });
116
+ }, { once: true });
115
117
  // 地图错误事件
116
- this.map.on('error', (error) => {
117
- this.errorHandler.handleError(new MyOpenLayersError('地图渲染错误', ErrorType.MAP_ERROR, { error }));
118
+ eventManager.on('error', (eventData) => {
119
+ this.errorHandler.handleError(new MyOpenLayersError('地图渲染错误', ErrorType.MAP_ERROR, { error: eventData.error }));
118
120
  });
119
121
  }
120
122
  /**
@@ -304,29 +306,6 @@ class MyOl {
304
306
  throw error;
305
307
  }
306
308
  }
307
- /**
308
- * 监听地图事件
309
- * @param eventType 事件类型
310
- * @param callback 回调函数
311
- * @param clickType 点击类型(可选)
312
- */
313
- mapOnEvent(eventType, callback, clickType) {
314
- try {
315
- if (typeof callback !== 'function') {
316
- throw new Error('回调函数必须是函数类型');
317
- }
318
- MapTools.mapOnEvent(this.map, eventType, callback, clickType);
319
- // 记录事件监听
320
- console.debug('地图事件监听已添加', {
321
- eventType,
322
- clickType
323
- });
324
- }
325
- catch (error) {
326
- this.errorHandler.handleError(new MyOpenLayersError(`添加地图事件监听失败: ${error instanceof Error ? error.message : '未知错误'}`, ErrorType.MAP_ERROR, { eventType, clickType }));
327
- throw error;
328
- }
329
- }
330
309
  // ==========================================
331
310
  // 管理器访问方法
332
311
  // ==========================================
@@ -342,7 +321,10 @@ class MyOl {
342
321
  * @returns EventManager 事件管理器
343
322
  */
344
323
  getEventManager() {
345
- return this.eventManager;
324
+ if (!this._eventManager) {
325
+ this._eventManager = new EventManager(this.map);
326
+ }
327
+ return this._eventManager;
346
328
  }
347
329
  /**
348
330
  * 获取配置管理器实例
@@ -363,8 +345,10 @@ class MyOl {
363
345
  */
364
346
  destroy() {
365
347
  try {
366
- // 清理事件监听
367
- this.eventManager.clear();
348
+ // 清理事件监听(仅在已初始化时)
349
+ if (this._eventManager) {
350
+ this._eventManager.clear();
351
+ }
368
352
  // 销毁功能模块
369
353
  this._point = undefined;
370
354
  this._line = undefined;
@@ -54,13 +54,6 @@ export default class DomPoint {
54
54
  * @private
55
55
  */
56
56
  private createVueApp;
57
- /**
58
- * 判断是否为Vue 3
59
- * @param Vue Vue构造函数
60
- * @returns 是否为Vue 3
61
- * @private
62
- */
63
- private isVue3;
64
57
  /**
65
58
  * 创建覆盖层
66
59
  * @returns 覆盖层实例
@@ -88,11 +81,11 @@ export default class DomPoint {
88
81
  isVisible(): boolean;
89
82
  /**
90
83
  * 更新位置
91
- * @param longitude 新经度
92
- * @param latitude 新纬度
84
+ * @param lgtd 新经度
85
+ * @param lttd 新纬度
93
86
  * @throws 当操作失败时抛出错误
94
87
  */
95
- updatePosition(longitude: number, latitude: number): void;
88
+ updatePosition(lgtd: number, lttd: number): void;
96
89
  /**
97
90
  * 获取当前位置
98
91
  * @returns 当前坐标位置
package/core/DomPoint.js CHANGED
@@ -2,6 +2,60 @@ import Overlay from 'ol/Overlay';
2
2
  import { DomPointState } from '../types';
3
3
  import { ErrorHandler, ErrorType } from '../utils/ErrorHandler';
4
4
  import { ValidationUtils } from '../utils/ValidationUtils';
5
+ // 动态导入Vue
6
+ let Vue = null;
7
+ let isVue3 = false;
8
+ // 检测Vue版本并导入
9
+ async function detectAndImportVue() {
10
+ try {
11
+ // 尝试动态导入Vue
12
+ const vueModule = await import('vue');
13
+ Vue = vueModule.default || vueModule;
14
+ // 检测Vue版本
15
+ if (Vue && (Vue.version?.startsWith('3') || Vue.createApp)) {
16
+ isVue3 = true;
17
+ }
18
+ else {
19
+ isVue3 = false;
20
+ }
21
+ }
22
+ catch (e) {
23
+ console.warn('Vue not found. Please ensure Vue is installed in your project.');
24
+ Vue = null;
25
+ }
26
+ }
27
+ // 同步版本的Vue检测(用于兼容性)
28
+ function detectVueSync() {
29
+ try {
30
+ // 尝试从全局对象获取Vue
31
+ if (typeof window !== 'undefined' && window.Vue) {
32
+ Vue = window.Vue;
33
+ isVue3 = !!(Vue.version?.startsWith('3') || Vue.createApp);
34
+ return;
35
+ }
36
+ // 如果在Node.js环境中,尝试require
37
+ if (typeof window === 'undefined') {
38
+ try {
39
+ // 使用eval来避免TypeScript编译时的require检查
40
+ const requireFunc = eval('require');
41
+ Vue = requireFunc('vue');
42
+ isVue3 = !!(Vue.version?.startsWith('3') || Vue.createApp);
43
+ }
44
+ catch (e) {
45
+ console.warn('Vue not found. Please ensure Vue is installed in your project.');
46
+ Vue = null;
47
+ }
48
+ }
49
+ }
50
+ catch (e) {
51
+ console.warn('Failed to detect Vue:', e);
52
+ }
53
+ }
54
+ // 初始化Vue导入
55
+ detectVueSync();
56
+ if (!Vue) {
57
+ detectAndImportVue();
58
+ }
5
59
  /**
6
60
  * DOM点位管理类
7
61
  * 用于在地图上添加和管理DOM元素覆盖物
@@ -23,10 +77,7 @@ export default class DomPoint {
23
77
  this.map = map;
24
78
  this.options = this.mergeDefaultOptions(options);
25
79
  this.id = this.generateUniqueId();
26
- this.position = [
27
- this.options.longitude ?? this.options.lgtd,
28
- this.options.latitude ?? this.options.lttd
29
- ];
80
+ this.position = [this.options.lgtd, this.options.lttd];
30
81
  // 创建DOM元素
31
82
  this.dom = this.createDomElement();
32
83
  // 创建Vue应用实例
@@ -53,13 +104,12 @@ export default class DomPoint {
53
104
  validateConstructorParams(map, options) {
54
105
  ValidationUtils.validateRequired(map, 'Map instance is required');
55
106
  ValidationUtils.validateRequired(options, 'Options are required');
56
- const { Vue, Template, longitude, latitude } = options;
57
- ValidationUtils.validateRequired(Vue, 'Vue is required in options');
107
+ const { Template, lgtd, lttd } = options;
58
108
  ValidationUtils.validateRequired(Template, 'Template is required in options');
59
- if (typeof longitude !== 'number' || typeof latitude !== 'number') {
60
- throw new Error('Longitude and latitude must be numbers');
109
+ if (typeof lgtd !== 'number' || typeof lttd !== 'number') {
110
+ throw new Error('Longitude and lttd must be numbers');
61
111
  }
62
- ValidationUtils.validateCoordinate(longitude, latitude);
112
+ ValidationUtils.validateCoordinate(lgtd, lttd);
63
113
  }
64
114
  /**
65
115
  * 合并默认配置选项
@@ -105,9 +155,12 @@ export default class DomPoint {
105
155
  * @private
106
156
  */
107
157
  createVueApp() {
108
- const { Vue, Template, props } = this.options;
158
+ const { Template, props } = this.options;
159
+ if (!Vue) {
160
+ throw new Error('Vue is not available. Please ensure Vue is installed in your project.');
161
+ }
109
162
  try {
110
- if (this.isVue3(Vue)) {
163
+ if (isVue3) {
111
164
  // Vue 3
112
165
  this.app = Vue.createApp({
113
166
  ...Template,
@@ -127,15 +180,6 @@ export default class DomPoint {
127
180
  throw new Error(`Failed to create Vue app: ${error}`);
128
181
  }
129
182
  }
130
- /**
131
- * 判断是否为Vue 3
132
- * @param Vue Vue构造函数
133
- * @returns 是否为Vue 3
134
- * @private
135
- */
136
- isVue3(Vue) {
137
- return !!(Vue.version && Vue.version.startsWith('3')) || !!Vue.createApp;
138
- }
139
183
  /**
140
184
  * 创建覆盖层
141
185
  * @returns 覆盖层实例
@@ -188,21 +232,21 @@ export default class DomPoint {
188
232
  }
189
233
  /**
190
234
  * 更新位置
191
- * @param longitude 新经度
192
- * @param latitude 新纬度
235
+ * @param lgtd 新经度
236
+ * @param lttd 新纬度
193
237
  * @throws 当操作失败时抛出错误
194
238
  */
195
- updatePosition(longitude, latitude) {
239
+ updatePosition(lgtd, lttd) {
196
240
  if (this.state === DomPointState.DESTROYED) {
197
241
  throw new Error('Cannot update position on destroyed DOM point');
198
242
  }
199
- ValidationUtils.validateCoordinate(longitude, latitude);
243
+ ValidationUtils.validateCoordinate(lgtd, lttd);
200
244
  try {
201
- this.position = [longitude, latitude];
245
+ this.position = [lgtd, lttd];
202
246
  this.anchor.setPosition(this.position);
203
247
  }
204
248
  catch (error) {
205
- this.handleError('Failed to update position', error, { longitude, latitude });
249
+ this.handleError('Failed to update position', error, { lgtd, lttd });
206
250
  throw error;
207
251
  }
208
252
  }
@@ -293,17 +337,17 @@ export default class DomPoint {
293
337
  destroyVueApp() {
294
338
  if (this.app) {
295
339
  try {
296
- if ('unmount' in this.app) {
297
- // Vue 3
340
+ if (isVue3) {
341
+ // Vue 3: 使用 unmount
298
342
  this.app.unmount();
299
343
  }
300
- else if ('$destroy' in this.app) {
301
- // Vue 2
344
+ else {
345
+ // Vue 2: 使用 $destroy
302
346
  this.app.$destroy();
303
347
  }
304
348
  }
305
349
  catch (error) {
306
- console.warn('Error destroying Vue app:', error);
350
+ this.handleError('Failed to destroy Vue app', error);
307
351
  }
308
352
  finally {
309
353
  this.app = null;
@@ -4,7 +4,7 @@ import { FeatureLike } from 'ol/Feature';
4
4
  /**
5
5
  * 事件类型定义
6
6
  */
7
- export type MapEventType = 'click' | 'dblclick' | 'hover' | 'moveend' | 'zoomend' | 'pointermove';
7
+ export type MapEventType = 'click' | 'dblclick' | 'hover' | 'moveend' | 'zoomend' | 'pointermove' | 'rendercomplete' | 'error';
8
8
  /**
9
9
  * 事件回调函数类型
10
10
  */
@@ -30,6 +30,7 @@ export declare class EventManager {
30
30
  private readonly map;
31
31
  private listeners;
32
32
  private eventCounters;
33
+ private mapEventListeners;
33
34
  /**
34
35
  * 构造函数
35
36
  * @param map OpenLayers地图实例
@@ -80,10 +81,10 @@ export declare class EventManager {
80
81
  */
81
82
  private attachMapEvent;
82
83
  /**
83
- * 分离地图事件(如果不再需要)
84
+ * 移除地图事件监听器
84
85
  * @param type 事件类型
85
86
  */
86
- private detachMapEventIfNeeded;
87
+ private detachMapEvent;
87
88
  /**
88
89
  * 处理点击事件
89
90
  * @param event 地图浏览器事件
@@ -107,6 +108,15 @@ export declare class EventManager {
107
108
  * 处理缩放结束事件
108
109
  */
109
110
  private handleZoomEndEvent;
111
+ /**
112
+ * 处理渲染完成事件
113
+ */
114
+ private handleRenderCompleteEvent;
115
+ /**
116
+ * 处理错误事件
117
+ * @param error 错误对象
118
+ */
119
+ private handleErrorEvent;
110
120
  /**
111
121
  * 创建事件数据
112
122
  * @param type 事件类型
@@ -11,6 +11,7 @@ export class EventManager {
11
11
  constructor(map) {
12
12
  this.listeners = new Map();
13
13
  this.eventCounters = new Map();
14
+ this.mapEventListeners = new Map();
14
15
  ErrorHandler.validateMap(map);
15
16
  this.map = map;
16
17
  this.initializeEventCounters();
@@ -19,7 +20,7 @@ export class EventManager {
19
20
  * 初始化事件计数器
20
21
  */
21
22
  initializeEventCounters() {
22
- const eventTypes = ['click', 'dblclick', 'hover', 'moveend', 'zoomend', 'pointermove'];
23
+ const eventTypes = ['click', 'dblclick', 'hover', 'moveend', 'zoomend', 'pointermove', 'rendercomplete', 'error'];
23
24
  eventTypes.forEach(type => {
24
25
  this.eventCounters.set(type, 0);
25
26
  });
@@ -54,7 +55,11 @@ export class EventManager {
54
55
  return false;
55
56
  }
56
57
  this.listeners.delete(id);
57
- this.detachMapEventIfNeeded(listener.type);
58
+ // 如果该类型没有其他监听器了,移除地图事件监听器
59
+ const remainingListeners = this.getListenerCount(listener.type);
60
+ if (remainingListeners === 0) {
61
+ this.detachMapEvent(listener.type);
62
+ }
58
63
  return true;
59
64
  }
60
65
  /**
@@ -71,15 +76,19 @@ export class EventManager {
71
76
  idsToRemove.forEach(id => {
72
77
  this.listeners.delete(id);
73
78
  });
74
- this.detachMapEventIfNeeded(type);
79
+ // 移除对应的地图事件监听器
80
+ if (idsToRemove.length > 0) {
81
+ this.detachMapEvent(type);
82
+ }
75
83
  }
76
84
  /**
77
85
  * 清除所有事件监听器
78
86
  */
79
87
  clear() {
80
88
  this.listeners.clear();
81
- this.eventCounters.forEach((_, type) => {
82
- this.detachMapEventIfNeeded(type);
89
+ // 移除所有地图事件监听器
90
+ this.mapEventListeners.forEach((_, type) => {
91
+ this.detachMapEvent(type);
83
92
  });
84
93
  }
85
94
  /**
@@ -113,37 +122,64 @@ export class EventManager {
113
122
  if (existingListeners > 1) {
114
123
  return; // 已经附加过该类型的事件
115
124
  }
125
+ // 如果已经有地图事件监听器,先移除
126
+ if (this.mapEventListeners.has(type)) {
127
+ this.detachMapEvent(type);
128
+ }
129
+ let eventHandler;
130
+ let target = this.map;
131
+ let eventName;
116
132
  switch (type) {
117
133
  case 'click':
118
- this.map.on('click', this.handleClickEvent.bind(this));
134
+ eventHandler = this.handleClickEvent.bind(this);
135
+ eventName = 'click';
119
136
  break;
120
137
  case 'dblclick':
121
- this.map.on('dblclick', this.handleDblClickEvent.bind(this));
138
+ eventHandler = this.handleDblClickEvent.bind(this);
139
+ eventName = 'dblclick';
122
140
  break;
123
141
  case 'hover':
124
142
  case 'pointermove':
125
- this.map.on('pointermove', this.handlePointerMoveEvent.bind(this));
143
+ eventHandler = this.handlePointerMoveEvent.bind(this);
144
+ eventName = 'pointermove';
126
145
  break;
127
146
  case 'moveend':
128
- this.map.on('moveend', this.handleMoveEndEvent.bind(this));
147
+ eventHandler = this.handleMoveEndEvent.bind(this);
148
+ eventName = 'moveend';
129
149
  break;
130
150
  case 'zoomend':
131
- this.map.getView().on('change:resolution', this.handleZoomEndEvent.bind(this));
151
+ eventHandler = this.handleZoomEndEvent.bind(this);
152
+ target = this.map.getView();
153
+ eventName = 'change:resolution';
154
+ break;
155
+ case 'rendercomplete':
156
+ eventHandler = this.handleRenderCompleteEvent.bind(this);
157
+ eventName = 'rendercomplete';
158
+ this.map.once(eventName, eventHandler);
159
+ this.mapEventListeners.set(type, { handler: eventHandler, target, eventName, isOnce: true });
160
+ return;
161
+ case 'error':
162
+ eventHandler = this.handleErrorEvent.bind(this);
163
+ eventName = 'error';
132
164
  break;
165
+ default:
166
+ return;
133
167
  }
168
+ target.on(eventName, eventHandler);
169
+ this.mapEventListeners.set(type, { handler: eventHandler, target, eventName, isOnce: false });
134
170
  }
135
171
  /**
136
- * 分离地图事件(如果不再需要)
172
+ * 移除地图事件监听器
137
173
  * @param type 事件类型
138
174
  */
139
- detachMapEventIfNeeded(type) {
140
- const remainingListeners = this.getListenerCount(type);
141
- if (remainingListeners > 0) {
142
- return; // 还有其他监听器需要该事件
175
+ detachMapEvent(type) {
176
+ const mapListener = this.mapEventListeners.get(type);
177
+ if (!mapListener) {
178
+ return;
143
179
  }
144
- // 注意:OpenLayers 不提供直接移除特定事件监听器的方法
145
- // 这里只是示例,实际实现可能需要保存事件监听器的引用
146
- console.warn(`Event type '${type}' detachment not fully implemented`);
180
+ const { handler, target, eventName } = mapListener;
181
+ target.un(eventName, handler);
182
+ this.mapEventListeners.delete(type);
147
183
  }
148
184
  /**
149
185
  * 处理点击事件
@@ -192,6 +228,29 @@ export class EventManager {
192
228
  };
193
229
  this.triggerListeners('zoomend', eventData);
194
230
  }
231
+ /**
232
+ * 处理渲染完成事件
233
+ */
234
+ handleRenderCompleteEvent() {
235
+ const eventData = {
236
+ type: 'rendercomplete',
237
+ zoom: this.map.getView().getZoom(),
238
+ coordinate: this.map.getView().getCenter()
239
+ };
240
+ this.triggerListeners('rendercomplete', eventData);
241
+ }
242
+ /**
243
+ * 处理错误事件
244
+ * @param error 错误对象
245
+ */
246
+ handleErrorEvent(error) {
247
+ const eventData = {
248
+ type: 'error',
249
+ originalEvent: error,
250
+ error: error
251
+ };
252
+ this.triggerListeners('error', eventData);
253
+ }
195
254
  /**
196
255
  * 创建事件数据
197
256
  * @param type 事件类型
package/core/Line.d.ts CHANGED
@@ -38,6 +38,8 @@ interface RiverLayerOptions extends LineOptions {
38
38
  export default class Line {
39
39
  /** OpenLayers 地图实例 */
40
40
  private readonly map;
41
+ /** 事件管理器实例 */
42
+ private readonly eventManager;
41
43
  /** 河流图层列表 */
42
44
  private riverLayerList;
43
45
  /** 河流图层显示状态 */
package/core/Line.js CHANGED
@@ -5,6 +5,7 @@ import { Stroke, Style } from "ol/style";
5
5
  import { Feature } from "ol";
6
6
  import MapTools from "./MapTools";
7
7
  import { ValidationUtils } from "../utils/ValidationUtils";
8
+ import { EventManager } from "./EventManager";
8
9
  /**
9
10
  * 线要素管理类
10
11
  * 用于在地图上添加和管理线要素,包括普通线要素、河流图层等
@@ -39,6 +40,7 @@ export default class Line {
39
40
  };
40
41
  ValidationUtils.validateMapInstance(map);
41
42
  this.map = map;
43
+ this.eventManager = new EventManager(map);
42
44
  }
43
45
  /**
44
46
  * 添加线要素
@@ -156,7 +158,7 @@ export default class Line {
156
158
  this.map.addLayer(riverLayer);
157
159
  }
158
160
  // 设置缩放事件监听
159
- MapTools.mapOnEvent(this.map, 'moveend', () => {
161
+ this.eventManager.on('moveend', () => {
160
162
  this.showRiverLayerByZoom();
161
163
  });
162
164
  // 初始显示
@@ -48,6 +48,8 @@ export default class MapBaseLayers {
48
48
  private layers;
49
49
  private readonly errorHandler;
50
50
  private currentBaseLayerType;
51
+ private currentAnnotationLayer;
52
+ private currentAnnotationType;
51
53
  /**
52
54
  * 构造函数
53
55
  * @param map OpenLayers地图实例
@@ -79,12 +81,40 @@ export default class MapBaseLayers {
79
81
  */
80
82
  private initTiandituLayers;
81
83
  /**
82
- * 添加注记图层
84
+ * 加载默认注记图层(cia_c)
83
85
  * @param token 天地图token
84
86
  * @param baseZIndex 基础层级
85
87
  * @private
86
88
  */
87
- private addAnnotationLayers;
89
+ private loadDefaultAnnotationLayer;
90
+ /**
91
+ * 切换注记类别
92
+ * @param annotationType 注记类型 ('cva_c' | 'cia_c' | 'cta_c')
93
+ */
94
+ switchAnnotationLayer(annotationType: 'cva_c' | 'cia_c' | 'cta_c'): void;
95
+ /**
96
+ * 设置注记图层(私有方法,用于消除代码重复)
97
+ * @param annotationType 注记类型
98
+ * @param token 天地图token
99
+ * @param baseZIndex 基础层级
100
+ * @private
101
+ */
102
+ private setAnnotationLayer;
103
+ /**
104
+ * 获取当前注记类型
105
+ * @returns 当前注记类型
106
+ */
107
+ getCurrentAnnotationType(): string | null;
108
+ /**
109
+ * 显示/隐藏注记图层
110
+ * @param visible 是否可见
111
+ */
112
+ setAnnotationVisible(visible: boolean): void;
113
+ /**
114
+ * 检查注记图层是否可见
115
+ * @returns 是否可见
116
+ */
117
+ isAnnotationVisible(): boolean;
88
118
  /**
89
119
  * 切换底图图层
90
120
  * @param type 图层类型