my-openlayer 2.5.4 → 3.0.1
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/CHANGELOG.md +68 -0
- package/MyOl.d.ts +3 -22
- package/MyOl.js +52 -112
- package/README.md +116 -29
- package/core/line/Line.d.ts +24 -5
- package/core/line/Line.js +38 -10
- package/core/map/ConfigManager.d.ts +169 -89
- package/core/map/ConfigManager.js +157 -175
- package/core/map/MapBaseLayers.d.ts +6 -0
- package/core/map/MapBaseLayers.js +9 -0
- package/core/map/MapTools.d.ts +17 -1
- package/core/map/MapTools.js +39 -5
- package/core/point/Point.d.ts +54 -14
- package/core/point/Point.js +132 -76
- package/core/point/PointOverlay.d.ts +2 -4
- package/core/point/PointOverlay.js +2 -1
- package/core/point/PointPulseLayer.js +6 -4
- package/core/polygon/Polygon.d.ts +32 -17
- package/core/polygon/Polygon.js +87 -64
- package/core/polygon/PolygonHeatmapLayer.js +15 -2
- package/core/polygon/PolygonMaskLayer.d.ts +2 -2
- package/core/polygon/PolygonMaskLayer.js +3 -1
- package/core/polygon/PolygonStyleFactory.d.ts +4 -3
- package/core/projection/ProjectionManager.d.ts +66 -0
- package/core/projection/ProjectionManager.js +144 -0
- package/core/projection/index.d.ts +2 -0
- package/core/projection/index.js +1 -0
- package/core/select/SelectHandler.d.ts +1 -1
- package/core/vue-template-point/VueTemplatePoint.d.ts +2 -4
- package/core/vue-template-point/VueTemplatePoint.js +16 -2
- package/docs/.vitepress/config.mts +1 -0
- package/docs/Line.md +4 -4
- package/docs/MIGRATION-3.0.md +221 -0
- package/docs/Point.md +24 -6
- package/docs/Polygon.md +14 -5
- package/index.d.ts +6 -3
- package/index.js +4 -1
- package/package.json +6 -3
- package/types/base.d.ts +4 -4
- package/types/common.d.ts +8 -6
- package/types/handle.d.ts +34 -0
- package/types/handle.js +1 -0
- package/types/index.d.ts +1 -0
- package/types/line.d.ts +3 -2
- package/types/map.d.ts +1 -1
- package/types/point.d.ts +11 -3
- package/utils/ErrorHandler.d.ts +12 -0
- package/utils/ErrorHandler.js +21 -0
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,73 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## [3.0.0] - 2026-05-22
|
|
4
|
+
|
|
5
|
+
### 🚀 BREAKING CHANGE: 总览
|
|
6
|
+
|
|
7
|
+
3.0 在保持向后兼容的前提下统一了 API 形态、加强了类型约束、把投影管理抽成独立类。所有 2.x 用户都应**配合 [`docs/MIGRATION-3.0.md`](./docs/MIGRATION-3.0.md) 阅读升级**。
|
|
8
|
+
|
|
9
|
+
升级核心结论:
|
|
10
|
+
|
|
11
|
+
- 真实图层类 `add*` 返回值从原始 OpenLayers layer 改为统一 `LayerHandle`
|
|
12
|
+
- 所有公开 `add*` 方法签名上 `layerName` 现在是**必填**(编译时强制)
|
|
13
|
+
- `addPointByUrl` / `addLineByUrl` / `addPolygonByUrl` 统一异步返回完整 Handle
|
|
14
|
+
|
|
15
|
+
### ✨ Features
|
|
16
|
+
|
|
17
|
+
- **handle**:新增统一 [`LayerHandle`](./src/types/handle.ts)、`AnimatedLayerHandle` 与 `ControlHandle` 接口;真实图层 add* 返回 `{ layer, remove, setVisible }`,非图层点位返回 `{ target, remove, setVisible }`。
|
|
18
|
+
- **add\***:Point / Line / Polygon 的真实图层 add 方法统一返回 `LayerHandle`;`PulsePointLayerHandle`、`FlowLineLayerHandle` 显式继承动画句柄契约。
|
|
19
|
+
- **\*ByUrl**:`Point.addPointByUrl`、`Line.addLineByUrl`、`Polygon.addPolygonByUrl` 统一先获取 JSON,再调用对应 add 方法并返回 Promise Handle。
|
|
20
|
+
- **Point \*ByUrl**:新增 `Point.addPointByUrl` / `Point.addPulsePointLayerByUrl`,从 URL 直接异步加载点位数据。
|
|
21
|
+
- **ProjectionManager**:投影注册逻辑从 `MyOl` 抽到独立 [`ProjectionManager`](./src/core/projection/ProjectionManager.ts) 类,对外暴露 `register / initialize / resolveViewProjection`。用户现在可在 MyOl 实例之外注册任意 EPSG。
|
|
22
|
+
- **ConfigManager.setDefaults**:运行时修改全局默认配置(如线宽、闪烁颜色),所有未提供该字段的后续调用都生效。配 `resetDefaults` 恢复。
|
|
23
|
+
- **错误体系**:新增 `LayerNotFoundError` / `InvalidGeoJSONError` / `ProjectionError` 三个具体子类,方便调用方 `instanceof` 判别。
|
|
24
|
+
- **类型导出**:补齐 `TwinkleItem` / `VueTemplatePointInstance` / `MeasureHandlerType` 等遗漏类型;运行时枚举 `VueTemplatePointState` 也导出。
|
|
25
|
+
|
|
26
|
+
### 🐛 Bug Fixes
|
|
27
|
+
|
|
28
|
+
- **destroy 泄漏(P0-1)**:`MyOl.destroy()` 现在会级联调用 `SelectHandler.destroy / Line.destroyAllFlowLines / Point.destroyAll / Polygon.destroyAll`,确保所有 rAF / Overlay / Vue 实例 / Select interaction 释放。
|
|
29
|
+
- **Point/Polygon 句柄注册表**:`Point` / `Polygon` 内部新增 `managedLayers` / `managedDisposables` 注册表,所有 `add*` 都会登记;`destroyAll` 一次性回收。
|
|
30
|
+
- **VueTemplatePoint 实例复用**:`Point.addVueTemplatePoint` 之前每次调用都 `new VueTemplatePoint(map)` 丢弃引用,现在改为单例复用并随 `destroyAll` 一起清理。
|
|
31
|
+
- **Polygon `[key:string]:any` 删除**:`removePolygonLayer` 不再依赖动态属性赋值。
|
|
32
|
+
|
|
33
|
+
### 🔒 Hardening
|
|
34
|
+
|
|
35
|
+
- 公开 `add*` 方法签名上 `layerName` 变成必填(用 `Options & { layerName: string }` 形式),不动 interface 本身保证 2.x 用户的 options 对象赋值不报错。
|
|
36
|
+
- `MapTools.setMapClip` 的 `baseLayer` 类型从 `any` 收紧为 `BaseLayer`;坐标数组从 `any[]` 收紧为 `number[][]` / `number[][][]`。
|
|
37
|
+
- `PulsePointIconOptions.src` 标 `@deprecated`,统一改名为 `img`(PointPulseLayer 同时识别两者)。
|
|
38
|
+
|
|
39
|
+
### 📝 Documentation
|
|
40
|
+
|
|
41
|
+
- 新增 [`docs/MIGRATION-3.0.md`](./docs/MIGRATION-3.0.md) 迁移指南。
|
|
42
|
+
- `addPolygonByUrl` / `addLineByUrl` / `Point.addVueTemplatePoint` 等破坏性返回值变化已写入迁移指南。
|
|
43
|
+
|
|
44
|
+
### 🧪 Tests
|
|
45
|
+
|
|
46
|
+
- 新增 5 个测试文件,共 40 个用例:`destroy-leak`、`config-defaults`、`async-url-api`、`layer-handle`、`config-defaults`,覆盖 P0/P1/P2 所有改动点。
|
|
47
|
+
|
|
48
|
+
---
|
|
49
|
+
|
|
50
|
+
## [2.5.5] - Unreleased(P0 补丁版)
|
|
51
|
+
|
|
52
|
+
### 🐛 Bug Fixes (P0)
|
|
53
|
+
|
|
54
|
+
- **destroy 级联清理**:`MyOl.destroy()` 现在会依次调用 `SelectHandler.destroy / Line.destroyAllFlowLines / Point.destroyAll / Polygon.destroyAll / EventManager.clear`,每一步独立 try/catch,确保所有 RAF、Overlay、Vue app、Select interaction 真正释放。
|
|
55
|
+
- **Point/Polygon 句柄注册表**:`Point.addPoint / addClusterPoint / addPulsePointLayer / addDomPoint / addVueTemplatePoint` 与 `Polygon.addPolygon / addBorderPolygon / addImageLayer / addHeatmap / addMaskLayer / setOutLayer` 创建的图层都注册到内部表,便于 `destroyAll()` 一次性回收。
|
|
56
|
+
- **VueTemplatePoint 实例复用**:`Point.addVueTemplatePoint` 之前每次都 `new VueTemplatePoint(map)` 丢弃引用导致内存泄漏,现改为单例复用。
|
|
57
|
+
- **死代码清理**:删除 `Point.ts` 注释段(旧 `addTwinkleLayerFromPolygon` 实现);删除 `Polygon` 的 `[key:string]:any` 索引签名,重写 `removePolygonLayer`。
|
|
58
|
+
|
|
59
|
+
### 🔒 Hardening (P0)
|
|
60
|
+
|
|
61
|
+
- `MapTools.setMapClip` 的 `baseLayer` 类型从 `any` 收紧到 `BaseLayer`;坐标数组从 `any[]` 收紧为 `number[][]` / `number[][][]`。
|
|
62
|
+
|
|
63
|
+
### ✨ Type Exports (P0)
|
|
64
|
+
|
|
65
|
+
- 补齐 `TwinkleItem` / `VueTemplatePointInstance` / `MeasureHandlerType` 等遗漏类型;导出运行时枚举 `VueTemplatePointState`。
|
|
66
|
+
|
|
67
|
+
### 🧪 Tests (P0)
|
|
68
|
+
|
|
69
|
+
- 新增 `tests/destroy-leak.test.ts`,4 个用例覆盖 `Line.destroyAllFlowLines` / `Point.destroyAll` / `Polygon.destroyAll` / `removePolygonLayer`。
|
|
70
|
+
|
|
3
71
|
## [2.5.4] - 2026-05-18
|
|
4
72
|
|
|
5
73
|
### 🐛 Bug Fixes
|
package/MyOl.d.ts
CHANGED
|
@@ -24,9 +24,10 @@ export default class MyOl {
|
|
|
24
24
|
private readonly configManager;
|
|
25
25
|
private readonly options;
|
|
26
26
|
static readonly DefaultOptions: MapInitType;
|
|
27
|
+
/**
|
|
28
|
+
* @deprecated 请使用 ProjectionManager.PROJECTIONS 代替
|
|
29
|
+
*/
|
|
27
30
|
private static readonly PROJECTIONS;
|
|
28
|
-
/** *********************内置投影定义*********************/
|
|
29
|
-
private static readonly PROJECTION_DEFINITIONS;
|
|
30
31
|
/**
|
|
31
32
|
* 构造函数
|
|
32
33
|
* @param id 地图容器 DOM 元素 ID
|
|
@@ -38,21 +39,6 @@ export default class MyOl {
|
|
|
38
39
|
* @private
|
|
39
40
|
*/
|
|
40
41
|
private validateConstructorParams;
|
|
41
|
-
/**
|
|
42
|
-
* 初始化坐标系
|
|
43
|
-
* @private
|
|
44
|
-
*/
|
|
45
|
-
private static initializeProjections;
|
|
46
|
-
/**
|
|
47
|
-
* 缺失时注册 proj4 投影定义,避免生产构建依赖第三方模块默认副作用。
|
|
48
|
-
* @private
|
|
49
|
-
*/
|
|
50
|
-
private static ensureProj4Definition;
|
|
51
|
-
/**
|
|
52
|
-
* 应用用户显式提供的投影元数据。
|
|
53
|
-
* @private
|
|
54
|
-
*/
|
|
55
|
-
private static applyCustomProjectionMetadata;
|
|
56
42
|
/**
|
|
57
43
|
* 创建地图控件
|
|
58
44
|
* @private
|
|
@@ -69,11 +55,6 @@ export default class MyOl {
|
|
|
69
55
|
* @returns View 地图视图实例
|
|
70
56
|
*/
|
|
71
57
|
static createView(options?: MapInitType): View;
|
|
72
|
-
/**
|
|
73
|
-
* 解析视图投影,优先复用已注册投影,避免丢失 proj4 推导的单位信息。
|
|
74
|
-
* @private
|
|
75
|
-
*/
|
|
76
|
-
private static resolveViewProjection;
|
|
77
58
|
/**
|
|
78
59
|
* 获取视图(向后兼容)
|
|
79
60
|
* @deprecated 请使用 createView 方法
|
package/MyOl.js
CHANGED
|
@@ -1,17 +1,16 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
// OpenLayers 核心导入
|
|
3
|
-
import { register as olProj4Register } from 'ol/proj/proj4';
|
|
4
|
-
import { Projection as olProjProjection, addProjection as olProjAddProjection, fromLonLat as olProjFromLonLat, get as olProjGetProjection } from 'ol/proj';
|
|
5
3
|
import View from "ol/View";
|
|
6
4
|
import Map from "ol/Map";
|
|
7
5
|
import { defaults as defaultControls } from 'ol/control';
|
|
8
|
-
import
|
|
6
|
+
import { fromLonLat as olProjFromLonLat } from 'ol/proj';
|
|
9
7
|
// 内部模块导入
|
|
10
8
|
import { Polygon } from "./core/polygon";
|
|
11
9
|
import { Point } from "./core/point";
|
|
12
10
|
import { Line } from "./core/line";
|
|
13
11
|
import { MapBaseLayers, MapTools, EventManager, ConfigManager } from "./core/map";
|
|
14
12
|
import { SelectHandler } from "./core/select";
|
|
13
|
+
import { ProjectionManager } from "./core/projection";
|
|
15
14
|
import { ErrorHandler, MyOpenLayersError, ErrorType } from './utils/ErrorHandler';
|
|
16
15
|
/**
|
|
17
16
|
* MyOl 地图核心类
|
|
@@ -37,7 +36,7 @@ class MyOl {
|
|
|
37
36
|
// 参数验证
|
|
38
37
|
this.validateConstructorParams(id, this.options);
|
|
39
38
|
// 初始化坐标系
|
|
40
|
-
|
|
39
|
+
ProjectionManager.initialize(this.options);
|
|
41
40
|
// 准备图层
|
|
42
41
|
const layers = Array.isArray(this.options.layers) ? this.options.layers : [];
|
|
43
42
|
// 创建地图实例
|
|
@@ -81,75 +80,6 @@ class MyOl {
|
|
|
81
80
|
throw new Error(typeof id === 'string' ? `找不到 ID 为 '${id}' 的 DOM 元素` : '提供的 DOM 元素无效');
|
|
82
81
|
}
|
|
83
82
|
}
|
|
84
|
-
/**
|
|
85
|
-
* 初始化坐标系
|
|
86
|
-
* @private
|
|
87
|
-
*/
|
|
88
|
-
static initializeProjections(options) {
|
|
89
|
-
/** *********************投影定义初始化*********************/
|
|
90
|
-
MyOl.ensureProj4Definition(MyOl.PROJECTIONS.WGS84, MyOl.PROJECTION_DEFINITIONS[MyOl.PROJECTIONS.WGS84]);
|
|
91
|
-
MyOl.ensureProj4Definition(MyOl.PROJECTIONS.CGCS2000, MyOl.PROJECTION_DEFINITIONS[MyOl.PROJECTIONS.CGCS2000]);
|
|
92
|
-
MyOl.ensureProj4Definition(MyOl.PROJECTIONS.CGCS2000_3_DEGREE, MyOl.PROJECTION_DEFINITIONS[MyOl.PROJECTIONS.CGCS2000_3_DEGREE]);
|
|
93
|
-
if (options.projection?.code && options.projection.def) {
|
|
94
|
-
proj4.defs(options.projection.code, options.projection.def);
|
|
95
|
-
}
|
|
96
|
-
// 注册到 OpenLayers
|
|
97
|
-
olProj4Register(proj4);
|
|
98
|
-
// 添加 CGCS2000 投影
|
|
99
|
-
const cgsc2000 = new olProjProjection({
|
|
100
|
-
code: MyOl.PROJECTIONS.CGCS2000,
|
|
101
|
-
extent: [-180, -90, 180, 90],
|
|
102
|
-
worldExtent: [-180, -90, 180, 90],
|
|
103
|
-
units: "degrees"
|
|
104
|
-
});
|
|
105
|
-
olProjAddProjection(cgsc2000);
|
|
106
|
-
if (options.projection?.code) {
|
|
107
|
-
MyOl.applyCustomProjectionMetadata(options.projection);
|
|
108
|
-
}
|
|
109
|
-
}
|
|
110
|
-
/**
|
|
111
|
-
* 缺失时注册 proj4 投影定义,避免生产构建依赖第三方模块默认副作用。
|
|
112
|
-
* @private
|
|
113
|
-
*/
|
|
114
|
-
static ensureProj4Definition(code, definition) {
|
|
115
|
-
if (!proj4.defs(code)) {
|
|
116
|
-
proj4.defs(code, definition);
|
|
117
|
-
}
|
|
118
|
-
}
|
|
119
|
-
/**
|
|
120
|
-
* 应用用户显式提供的投影元数据。
|
|
121
|
-
* @private
|
|
122
|
-
*/
|
|
123
|
-
static applyCustomProjectionMetadata(projection) {
|
|
124
|
-
const { code, extent, worldExtent, units } = projection;
|
|
125
|
-
const registeredProjection = olProjGetProjection(code);
|
|
126
|
-
/** *********************自定义投影元数据初始化*********************/
|
|
127
|
-
if (units) {
|
|
128
|
-
olProjAddProjection(new olProjProjection({
|
|
129
|
-
code,
|
|
130
|
-
extent: extent ?? registeredProjection?.getExtent(),
|
|
131
|
-
worldExtent: worldExtent ?? registeredProjection?.getWorldExtent(),
|
|
132
|
-
units
|
|
133
|
-
}));
|
|
134
|
-
return;
|
|
135
|
-
}
|
|
136
|
-
if (registeredProjection) {
|
|
137
|
-
if (extent) {
|
|
138
|
-
registeredProjection.setExtent(extent);
|
|
139
|
-
}
|
|
140
|
-
if (worldExtent) {
|
|
141
|
-
registeredProjection.setWorldExtent(worldExtent);
|
|
142
|
-
}
|
|
143
|
-
return;
|
|
144
|
-
}
|
|
145
|
-
if (extent || worldExtent) {
|
|
146
|
-
olProjAddProjection(new olProjProjection({
|
|
147
|
-
code,
|
|
148
|
-
extent,
|
|
149
|
-
worldExtent
|
|
150
|
-
}));
|
|
151
|
-
}
|
|
152
|
-
}
|
|
153
83
|
/**
|
|
154
84
|
* 创建地图控件
|
|
155
85
|
* @private
|
|
@@ -184,9 +114,9 @@ class MyOl {
|
|
|
184
114
|
static createView(options = MyOl.DefaultOptions) {
|
|
185
115
|
try {
|
|
186
116
|
/** *********************静态视图投影初始化*********************/
|
|
187
|
-
|
|
188
|
-
const code = options.projection?.code ??
|
|
189
|
-
const projection =
|
|
117
|
+
ProjectionManager.initialize(options);
|
|
118
|
+
const code = options.projection?.code ?? ProjectionManager.DEFAULT_PROJECTION;
|
|
119
|
+
const projection = ProjectionManager.resolveViewProjection(options, code);
|
|
190
120
|
const viewOptions = {
|
|
191
121
|
projection,
|
|
192
122
|
center: olProjFromLonLat(options.center, projection),
|
|
@@ -201,26 +131,6 @@ class MyOl {
|
|
|
201
131
|
throw new MyOpenLayersError(`视图创建失败: ${error instanceof Error ? error.message : '未知错误'}`, ErrorType.MAP_ERROR, { options });
|
|
202
132
|
}
|
|
203
133
|
}
|
|
204
|
-
/**
|
|
205
|
-
* 解析视图投影,优先复用已注册投影,避免丢失 proj4 推导的单位信息。
|
|
206
|
-
* @private
|
|
207
|
-
*/
|
|
208
|
-
static resolveViewProjection(options, code) {
|
|
209
|
-
const registeredProjection = olProjGetProjection(code);
|
|
210
|
-
/** *********************视图投影初始化*********************/
|
|
211
|
-
if (registeredProjection
|
|
212
|
-
&& !options.projection?.extent
|
|
213
|
-
&& !options.projection?.worldExtent
|
|
214
|
-
&& !options.projection?.units) {
|
|
215
|
-
return registeredProjection;
|
|
216
|
-
}
|
|
217
|
-
return new olProjProjection({
|
|
218
|
-
code,
|
|
219
|
-
extent: options.projection?.extent ?? registeredProjection?.getExtent() ?? [-180, -90, 180, 90],
|
|
220
|
-
worldExtent: options.projection?.worldExtent ?? registeredProjection?.getWorldExtent() ?? [-180, -90, 180, 90],
|
|
221
|
-
units: options.projection?.units ?? registeredProjection?.getUnits() ?? "degrees"
|
|
222
|
-
});
|
|
223
|
-
}
|
|
224
134
|
/**
|
|
225
135
|
* 获取视图(向后兼容)
|
|
226
136
|
* @deprecated 请使用 createView 方法
|
|
@@ -443,18 +353,56 @@ class MyOl {
|
|
|
443
353
|
*/
|
|
444
354
|
destroy() {
|
|
445
355
|
try {
|
|
446
|
-
//
|
|
356
|
+
// 1. 先停掉所有动画 / 解绑事件 / 释放 Overlay,再销毁地图本身
|
|
357
|
+
if (this._selectHandler) {
|
|
358
|
+
try {
|
|
359
|
+
this._selectHandler.destroy();
|
|
360
|
+
}
|
|
361
|
+
catch (e) {
|
|
362
|
+
this.errorHandler.warn('SelectHandler.destroy 失败:', e);
|
|
363
|
+
}
|
|
364
|
+
}
|
|
365
|
+
if (this._line) {
|
|
366
|
+
try {
|
|
367
|
+
this._line.destroyAllFlowLines();
|
|
368
|
+
}
|
|
369
|
+
catch (e) {
|
|
370
|
+
this.errorHandler.warn('Line.destroyAllFlowLines 失败:', e);
|
|
371
|
+
}
|
|
372
|
+
}
|
|
373
|
+
if (this._point) {
|
|
374
|
+
try {
|
|
375
|
+
this._point.destroyAll();
|
|
376
|
+
}
|
|
377
|
+
catch (e) {
|
|
378
|
+
this.errorHandler.warn('Point.destroyAll 失败:', e);
|
|
379
|
+
}
|
|
380
|
+
}
|
|
381
|
+
if (this._polygon) {
|
|
382
|
+
try {
|
|
383
|
+
this._polygon.destroyAll();
|
|
384
|
+
}
|
|
385
|
+
catch (e) {
|
|
386
|
+
this.errorHandler.warn('Polygon.destroyAll 失败:', e);
|
|
387
|
+
}
|
|
388
|
+
}
|
|
447
389
|
if (this._eventManager) {
|
|
448
|
-
|
|
390
|
+
try {
|
|
391
|
+
this._eventManager.clear();
|
|
392
|
+
}
|
|
393
|
+
catch (e) {
|
|
394
|
+
this.errorHandler.warn('EventManager.clear 失败:', e);
|
|
395
|
+
}
|
|
449
396
|
}
|
|
450
|
-
//
|
|
397
|
+
// 2. 释放模块引用
|
|
451
398
|
this._point = undefined;
|
|
452
399
|
this._line = undefined;
|
|
453
400
|
this._polygon = undefined;
|
|
454
401
|
this._mapTools = undefined;
|
|
455
402
|
this._baseLayers = undefined;
|
|
456
403
|
this._selectHandler = undefined;
|
|
457
|
-
|
|
404
|
+
this._eventManager = undefined;
|
|
405
|
+
// 3. 解绑 DOM 目标,OL 内部会回收 layers / interactions
|
|
458
406
|
this.map.setTarget(undefined);
|
|
459
407
|
this.errorHandler.debug('地图实例已销毁', { map: this.map });
|
|
460
408
|
}
|
|
@@ -465,16 +413,8 @@ class MyOl {
|
|
|
465
413
|
}
|
|
466
414
|
// 默认配置
|
|
467
415
|
MyOl.DefaultOptions = ConfigManager.DEFAULT_MYOL_OPTIONS;
|
|
468
|
-
|
|
469
|
-
|
|
470
|
-
|
|
471
|
-
|
|
472
|
-
CGCS2000_3_DEGREE: "EPSG:4549"
|
|
473
|
-
};
|
|
474
|
-
/** *********************内置投影定义*********************/
|
|
475
|
-
MyOl.PROJECTION_DEFINITIONS = {
|
|
476
|
-
[MyOl.PROJECTIONS.WGS84]: "+title=WGS 84 (long/lat) +proj=longlat +ellps=WGS84 +datum=WGS84 +units=degrees",
|
|
477
|
-
[MyOl.PROJECTIONS.CGCS2000]: "+proj=longlat +ellps=GRS80 +no_defs",
|
|
478
|
-
[MyOl.PROJECTIONS.CGCS2000_3_DEGREE]: "+proj=tmerc +lat_0=0 +lon_0=120 +k=1 +x_0=500000 +y_0=0 +ellps=GRS80 +units=m +no_defs"
|
|
479
|
-
};
|
|
416
|
+
/**
|
|
417
|
+
* @deprecated 请使用 ProjectionManager.PROJECTIONS 代替
|
|
418
|
+
*/
|
|
419
|
+
MyOl.PROJECTIONS = ProjectionManager.PROJECTIONS;
|
|
480
420
|
export default MyOl;
|
package/README.md
CHANGED
|
@@ -6,6 +6,26 @@ my-openlayer 是一个基于 [OpenLayers](https://openlayers.org/) 的现代地
|
|
|
6
6
|
[](https://www.typescriptlang.org/)
|
|
7
7
|
[](https://opensource.org/licenses/MIT)
|
|
8
8
|
|
|
9
|
+
**[在线 Demo](https://cuteyuchen.github.io/my-openlayer/demo/)** · [文档](https://cuteyuchen.github.io/my-openlayer/) · [迁移指南 (2.x → 3.0)](docs/MIGRATION-3.0.md)
|
|
10
|
+
|
|
11
|
+
---
|
|
12
|
+
|
|
13
|
+
## 3.0 亮点
|
|
14
|
+
|
|
15
|
+
3.0 是一次 API 形态层的范式转移,核心目标是**统一 lifecycle、降低学习成本**:
|
|
16
|
+
|
|
17
|
+
- **统一 LayerHandle** — 真实图层类 `add*` 返回 `{ layer, remove(), setVisible() }` 形态的句柄,跨 Point / Line / Polygon 复用同一套 lifecycle 模型
|
|
18
|
+
- **统一 ControlHandle** — `addDomPoint` / `addVueTemplatePoint` 返回 `{ target, remove(), setVisible() }`,并保留 `anchors` / `getPoints()` 等原有能力
|
|
19
|
+
- ***ByUrl 异步化** — `addPointByUrl` / `addLineByUrl` / `addPolygonByUrl` 统一先获取 JSON,再返回完整 Handle
|
|
20
|
+
- **destroy 级联清理** — `MyOl.destroy()` 现在依次调用 `SelectHandler.destroy` / `Line.destroyAllFlowLines` / `Point.destroyAll` / `Polygon.destroyAll`,确保 rAF / Overlay / Vue 实例 / Select interaction 全部释放
|
|
21
|
+
- **ProjectionManager** — 投影逻辑从 MyOl 内部抽取为独立类,支持 `ProjectionManager.register({ code, def })` 在 MyOl 实例之外注册任意 EPSG
|
|
22
|
+
- **ConfigManager.setDefaults** — 运行时修改全局默认配置,所有未提供该字段的后续调用都生效
|
|
23
|
+
- **具体错误类型** — `LayerNotFoundError` / `InvalidGeoJSONError` / `ProjectionError`,方便 `instanceof` 判别
|
|
24
|
+
- **layerName 必填** — 公开 `add*` 方法签名上 `layerName` 变成必填(编译时强制)
|
|
25
|
+
- **PulsePointIconOptions `src` → `img`** — 统一命名,旧 `src` 标 `@deprecated`
|
|
26
|
+
|
|
27
|
+
> 从 2.x 升级请参考 [MIGRATION-3.0.md](docs/MIGRATION-3.0.md)。3.0 会把旧 `add*` 的原始 layer 返回值改为 Handle;访问 OL 图层请使用 `handle.layer`。
|
|
28
|
+
|
|
9
29
|
---
|
|
10
30
|
|
|
11
31
|
## 项目概述
|
|
@@ -32,14 +52,14 @@ my-openlayer 是一个基于 [OpenLayers](https://openlayers.org/) 的现代地
|
|
|
32
52
|
- **🛠️ 地图工具**
|
|
33
53
|
- **测量工具 (MeasureHandler)**:距离和面积测量
|
|
34
54
|
- **要素选择 (SelectHandler)**:支持点击、悬停、多选等交互选择
|
|
35
|
-
- **地图工具 (MapTools)
|
|
55
|
+
- **地图工具 (MapTools)**:图层管理、定位、视图自适应、全图裁剪 (`clipMap`)
|
|
36
56
|
- **事件管理 (EventManager)**:统一的地图事件监听与管理
|
|
37
57
|
|
|
38
58
|
- **⚡ 高级特性**
|
|
39
|
-
- **TypeScript
|
|
40
|
-
- **错误处理 (ErrorHandler)
|
|
41
|
-
- **配置管理 (ConfigManager)
|
|
42
|
-
-
|
|
59
|
+
- **TypeScript 完全支持**:提供完整的类型定义,严格模式
|
|
60
|
+
- **错误处理 (ErrorHandler)**:统一的错误捕获与日志,含具体子类型
|
|
61
|
+
- **配置管理 (ConfigManager)**:集中管理默认配置,支持运行时 `setDefaults`
|
|
62
|
+
- **投影管理 (ProjectionManager)**:内置 `EPSG:4326` / `EPSG:4490` / `EPSG:4549`,支持 `ProjectionManager.register()` 注册任意自定义投影
|
|
43
63
|
|
|
44
64
|
## 安装
|
|
45
65
|
|
|
@@ -58,36 +78,52 @@ pnpm add my-openlayer
|
|
|
58
78
|
- **proj4**: ^2.7.5
|
|
59
79
|
- **@turf/turf**: ^7.2.0
|
|
60
80
|
|
|
81
|
+
## CC Switch 技能仓库
|
|
82
|
+
|
|
83
|
+
本仓库已按 CC Switch 技能仓库结构提供 `my-openlayer-helper`:
|
|
84
|
+
|
|
85
|
+
```txt
|
|
86
|
+
skills/my-openlayer-helper/SKILL.md
|
|
87
|
+
```
|
|
88
|
+
|
|
89
|
+
在 CC Switch 的“添加技能仓库”中填写:
|
|
90
|
+
|
|
91
|
+
```txt
|
|
92
|
+
仓库 URL:cuteyuchen/my-openlayer
|
|
93
|
+
分支:main
|
|
94
|
+
```
|
|
95
|
+
|
|
96
|
+
CC Switch 扫描后会识别到 `my-openlayer-helper`。后续更新只需要同步本仓库,使用者在 CC Switch 中刷新/更新技能即可。
|
|
97
|
+
|
|
61
98
|
## 快速上手
|
|
62
99
|
|
|
63
100
|
### 1. 初始化地图
|
|
64
101
|
|
|
65
102
|
```typescript
|
|
66
|
-
import
|
|
103
|
+
import { MyOl } from 'my-openlayer';
|
|
67
104
|
|
|
68
|
-
const
|
|
105
|
+
const map = new MyOl('map-container', {
|
|
69
106
|
center: [119.81, 29.969],
|
|
70
107
|
zoom: 10,
|
|
71
108
|
token: import.meta.env.VITE_TIANDITU_TOKEN, // 天地图 Token
|
|
72
109
|
annotation: true
|
|
73
|
-
};
|
|
74
|
-
|
|
75
|
-
const map = new MyOl('map-container', mapConfig);
|
|
110
|
+
});
|
|
76
111
|
```
|
|
77
112
|
|
|
78
113
|
### 2. 使用功能模块
|
|
79
114
|
|
|
80
115
|
```typescript
|
|
81
|
-
//
|
|
116
|
+
// 获取模块实例(懒加载)
|
|
82
117
|
const point = map.getPoint();
|
|
83
118
|
const line = map.getLine();
|
|
84
119
|
const polygon = map.getPolygon();
|
|
85
120
|
|
|
86
|
-
//
|
|
87
|
-
point.addPoint(
|
|
88
|
-
|
|
89
|
-
img: 'marker.png'
|
|
90
|
-
|
|
121
|
+
// 添加点位(3.0 add* 返回统一 LayerHandle)
|
|
122
|
+
const handle = point.addPoint(
|
|
123
|
+
[{ lgtd: 119.81, lttd: 29.969, name: '示例点' }],
|
|
124
|
+
{ layerName: 'example-point', img: 'marker.png' }
|
|
125
|
+
);
|
|
126
|
+
handle?.remove(); // 统一的生命周期管理
|
|
91
127
|
```
|
|
92
128
|
|
|
93
129
|
### 3. 添加高性能闪烁点
|
|
@@ -127,20 +163,15 @@ pulseLayer?.remove();
|
|
|
127
163
|
|
|
128
164
|
### 4. 添加流动线
|
|
129
165
|
|
|
130
|
-
`Line` 模块现在支持流光线与流动线图标动画,调用方式与 `Point.addPulsePointLayer()` 保持一致,返回可控 handle。
|
|
131
|
-
|
|
132
166
|
```typescript
|
|
133
167
|
const flow = map.getLine().addFlowLine(lineData, {
|
|
134
168
|
layerName: 'river-flow',
|
|
135
169
|
animationMode: 'icon+dash',
|
|
136
170
|
strokeColor: '#19b1ff',
|
|
137
171
|
strokeWidth: 3,
|
|
138
|
-
lineDash: [18, 12],
|
|
139
172
|
flowSymbol: {
|
|
140
173
|
src: '/symbols/boat.svg',
|
|
141
174
|
scale: 0.9,
|
|
142
|
-
color: '#19b1ff',
|
|
143
|
-
rotateWithView: true,
|
|
144
175
|
count: 2,
|
|
145
176
|
spacing: 0.2
|
|
146
177
|
}
|
|
@@ -151,28 +182,70 @@ flow?.resume();
|
|
|
151
182
|
flow?.remove();
|
|
152
183
|
```
|
|
153
184
|
|
|
185
|
+
### 5. 全图裁剪
|
|
186
|
+
|
|
187
|
+
```typescript
|
|
188
|
+
const tools = map.getTools();
|
|
189
|
+
|
|
190
|
+
// 裁剪整张地图(底图 + 注记 + 用户图层全部只在区域内可见)
|
|
191
|
+
tools.clipMap(geoJsonBoundary);
|
|
192
|
+
|
|
193
|
+
// 或只裁剪当前底图
|
|
194
|
+
const baseLayers = map.getMapBaseLayers().getCurrentBaseLayers();
|
|
195
|
+
baseLayers.forEach(layer => MapTools.setMapClip(layer, geoJsonBoundary));
|
|
196
|
+
```
|
|
197
|
+
|
|
198
|
+
### 6. 注册自定义投影
|
|
199
|
+
|
|
200
|
+
```typescript
|
|
201
|
+
import { ProjectionManager } from 'my-openlayer';
|
|
202
|
+
|
|
203
|
+
// 在 MyOl 实例之外注册任意 EPSG
|
|
204
|
+
ProjectionManager.register({
|
|
205
|
+
code: 'EPSG:4528',
|
|
206
|
+
def: '+proj=tmerc +lat_0=0 +lon_0=120 +k=1 +x_0=40500000 +y_0=0 +ellps=GRS80 +units=m +no_defs'
|
|
207
|
+
});
|
|
208
|
+
|
|
209
|
+
// 之后 MyOl 构造时直接用
|
|
210
|
+
const map = new MyOl('map', { projection: { code: 'EPSG:4528' } });
|
|
211
|
+
```
|
|
212
|
+
|
|
213
|
+
### 7. 运行时修改默认配置
|
|
214
|
+
|
|
215
|
+
```typescript
|
|
216
|
+
import { ConfigManager } from 'my-openlayer';
|
|
217
|
+
|
|
218
|
+
// 所有后续 addLine 调用的默认 strokeWidth 变为 4
|
|
219
|
+
ConfigManager.setDefaults('LINE_OPTIONS', { strokeWidth: 4 });
|
|
220
|
+
|
|
221
|
+
// 恢复内置默认
|
|
222
|
+
ConfigManager.resetDefaults('LINE_OPTIONS');
|
|
223
|
+
```
|
|
224
|
+
|
|
154
225
|
## 文档索引
|
|
155
226
|
|
|
156
|
-
|
|
227
|
+
详细文档请访问 **[在线文档](https://cuteyuchen.github.io/my-openlayer/)**,交互式 Demo 请访问 **[Demo 站点](https://cuteyuchen.github.io/my-openlayer/demo/)**。
|
|
157
228
|
|
|
158
229
|
### 核心类库
|
|
159
230
|
- **[MyOl](docs/MyOl.md)**: 地图入口类,负责初始化和模块访问。
|
|
231
|
+
- **[ProjectionManager](docs/ProjectionManager.md)**: 投影管理(3.0 新增),支持 `register()` 注册任意 EPSG。
|
|
160
232
|
- **[MapBaseLayers](docs/MapBaseLayers.md)**: 底图与注记管理。
|
|
161
|
-
- **[ConfigManager](docs/ConfigManager.md)**:
|
|
233
|
+
- **[ConfigManager](docs/ConfigManager.md)**: 配置管理,支持运行时 `setDefaults`。
|
|
162
234
|
- **[EventManager](docs/EventManager.md)**: 事件管理。
|
|
163
|
-
- **[ErrorHandler](docs/ErrorHandler.md)**:
|
|
235
|
+
- **[ErrorHandler](docs/ErrorHandler.md)**: 错误处理,含 `LayerNotFoundError` / `InvalidGeoJSONError` / `ProjectionError`。
|
|
164
236
|
|
|
165
237
|
### 要素操作
|
|
166
|
-
- **[Point](docs/Point.md)**: 点要素(含聚合、DOM
|
|
167
|
-
- **[
|
|
168
|
-
- **[
|
|
238
|
+
- **[Point](docs/Point.md)**: 点要素(含聚合、DOM 点位、高性能闪烁点、统一 Handle)。
|
|
239
|
+
- **[Point](docs/Point.md)**: 点要素(含聚合、DOM 点位、高性能闪烁点、统一 Handle)。
|
|
240
|
+
- **[Line](docs/Line.md)**: 线要素(含静态线、流动线、URL 异步加载)。
|
|
241
|
+
- **[Polygon](docs/Polygon.md)**: 面要素(含热力图、图片层、遮罩层、统一 Handle)。
|
|
169
242
|
- **[VueTemplatePoint](docs/VueTemplatePoint.md)**: Vue 组件点位。
|
|
170
243
|
- **[RiverLayerManager](docs/RiverLayerManager.md)**: 河流图层管理。
|
|
171
244
|
|
|
172
245
|
### 交互与工具
|
|
173
246
|
- **[SelectHandler](docs/SelectHandler.md)**: 要素选择交互(支持独立样式渲染、多选隔离)。
|
|
174
247
|
- **[MeasureHandler](docs/MeasureHandler.md)**: 测量工具。
|
|
175
|
-
- **[MapTools](docs/MapTools.md)**:
|
|
248
|
+
- **[MapTools](docs/MapTools.md)**: 通用地图工具(含 `clipMap` 全图裁剪)。
|
|
176
249
|
- **[ValidationUtils](docs/ValidationUtils.md)**: 验证工具。
|
|
177
250
|
|
|
178
251
|
## 详细用法示例
|
|
@@ -196,7 +269,21 @@ measure.start('LineString'); // 开始测距
|
|
|
196
269
|
measure.end(); // 结束测量
|
|
197
270
|
```
|
|
198
271
|
|
|
199
|
-
|
|
272
|
+
### 要素选择
|
|
273
|
+
|
|
274
|
+
```typescript
|
|
275
|
+
const selectHandler = map.getSelectHandler();
|
|
276
|
+
|
|
277
|
+
selectHandler.enableSelect('click', {
|
|
278
|
+
layerFilter: ['cities'],
|
|
279
|
+
onSelect: (event) => console.log('选中:', event.selected)
|
|
280
|
+
});
|
|
281
|
+
|
|
282
|
+
// 编程式选择
|
|
283
|
+
selectHandler.selectByProperty('name', '杭州', { fitView: true });
|
|
284
|
+
```
|
|
285
|
+
|
|
286
|
+
> 注意:更多示例请访问 [Demo 站点](https://cuteyuchen.github.io/my-openlayer/demo/),每个公开类都有独立的交互式演示页。
|
|
200
287
|
|
|
201
288
|
## 贡献指南
|
|
202
289
|
|
package/core/line/Line.d.ts
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import Map from "ol/Map";
|
|
2
2
|
import VectorLayer from "ol/layer/Vector";
|
|
3
3
|
import VectorSource from "ol/source/Vector";
|
|
4
|
-
import type { FlowLineLayerHandle, FlowLineOptions, LineOptions, MapJSONData } from "../../types";
|
|
4
|
+
import type { FlowLineLayerHandle, FlowLineOptions, LineOptions, MapJSONData, LayerHandle } from "../../types";
|
|
5
5
|
/**
|
|
6
6
|
* 线要素管理类
|
|
7
7
|
* 用于在地图上添加和管理静态线与流动线要素。
|
|
@@ -23,6 +23,8 @@ export default class Line {
|
|
|
23
23
|
* 创建静态线图层。
|
|
24
24
|
*/
|
|
25
25
|
private createStaticLayer;
|
|
26
|
+
/** *********************统一句柄:静态线图层*********************/
|
|
27
|
+
private toLayerHandle;
|
|
26
28
|
/**
|
|
27
29
|
* 注册流动线句柄。
|
|
28
30
|
*/
|
|
@@ -31,10 +33,27 @@ export default class Line {
|
|
|
31
33
|
* 注销流动线句柄。
|
|
32
34
|
*/
|
|
33
35
|
private unregisterFlowLineHandle;
|
|
34
|
-
|
|
35
|
-
|
|
36
|
+
/** *********************创建静态线图层*********************/
|
|
37
|
+
private createLineLayer;
|
|
38
|
+
/** *********************添加静态线图层*********************/
|
|
39
|
+
addLine(data: MapJSONData, options: LineOptions & {
|
|
40
|
+
layerName: string;
|
|
41
|
+
}): LayerHandle<VectorLayer<VectorSource>>;
|
|
42
|
+
/** *********************从 URL 添加静态线图层*********************/
|
|
43
|
+
addLineByUrl(url: string, options: LineOptions & {
|
|
44
|
+
layerName: string;
|
|
45
|
+
}): Promise<LayerHandle<VectorLayer<VectorSource>>>;
|
|
36
46
|
removeLineLayer(layerName: string): void;
|
|
37
|
-
addFlowLine(data: MapJSONData, options
|
|
38
|
-
|
|
47
|
+
addFlowLine(data: MapJSONData, options: FlowLineOptions & {
|
|
48
|
+
layerName: string;
|
|
49
|
+
}): FlowLineLayerHandle | null;
|
|
50
|
+
addFlowLineByUrl(url: string, options: FlowLineOptions & {
|
|
51
|
+
layerName: string;
|
|
52
|
+
}): Promise<FlowLineLayerHandle | null>;
|
|
39
53
|
removeFlowLineLayer(layerName: string): void;
|
|
54
|
+
/**
|
|
55
|
+
* 销毁本实例创建的所有流动线动画。供 MyOl.destroy 调用,
|
|
56
|
+
* 确保地图销毁后所有 requestAnimationFrame / postrender 监听被回收。
|
|
57
|
+
*/
|
|
58
|
+
destroyAllFlowLines(): void;
|
|
40
59
|
}
|