my-openlayer 2.5.5 → 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 +10 -108
- package/README.md +116 -29
- package/core/line/Line.d.ts +19 -5
- package/core/line/Line.js +25 -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 +16 -0
- package/core/map/MapTools.js +35 -1
- package/core/point/Point.d.ts +40 -14
- package/core/point/Point.js +70 -4
- 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 +19 -16
- package/core/polygon/Polygon.js +41 -63
- 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 +4 -2
- package/index.js +2 -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
|
@@ -183,6 +183,15 @@ export default class MapBaseLayers {
|
|
|
183
183
|
getCurrentBaseLayerType() {
|
|
184
184
|
return this.currentBaseLayerType;
|
|
185
185
|
}
|
|
186
|
+
/**
|
|
187
|
+
* 获取当前可见底图对应的 BaseLayer 数组(多 layer 的底图类型会返回多个)。
|
|
188
|
+
* 用于 MapTools.setMapClip 等需要直接操作底图实例的场景。
|
|
189
|
+
*/
|
|
190
|
+
getCurrentBaseLayers() {
|
|
191
|
+
if (!this.currentBaseLayerType)
|
|
192
|
+
return [];
|
|
193
|
+
return (this.layers[this.currentBaseLayerType] ?? []);
|
|
194
|
+
}
|
|
186
195
|
/**
|
|
187
196
|
* 获取默认底图类型
|
|
188
197
|
* @private
|
package/core/map/MapTools.d.ts
CHANGED
|
@@ -34,6 +34,21 @@ export default class MapTools {
|
|
|
34
34
|
* 注意:此方法会修改 baseLayer 的 prerender 和 postrender 事件
|
|
35
35
|
*/
|
|
36
36
|
static setMapClip(baseLayer: BaseLayer, data: MapJSONData): BaseLayer;
|
|
37
|
+
/**
|
|
38
|
+
* 用 GeoJSON 区域裁剪地图上**所有**图层(底图 + 注记 + 用户 vector 层)。
|
|
39
|
+
*
|
|
40
|
+
* 每个图层都会绑定 prerender/postrender 进行 canvas clip。这是 setMapClip
|
|
41
|
+
* 的批量版本,用于"整张地图只在某区域内可见"的需求(例如行政区聚焦)。
|
|
42
|
+
*
|
|
43
|
+
* 实例方法 mapTools.clipMap(data) 会自动用当前 map。
|
|
44
|
+
*/
|
|
45
|
+
clipMap(data: MapJSONData): void;
|
|
46
|
+
/**
|
|
47
|
+
* 用 GeoJSON 区域裁剪地图上所有图层(静态版本)。
|
|
48
|
+
* @param map 地图实例
|
|
49
|
+
* @param data 裁剪边界 GeoJSON
|
|
50
|
+
*/
|
|
51
|
+
static clipMap(map: Map, data: MapJSONData): void;
|
|
37
52
|
/**
|
|
38
53
|
* 移除图层
|
|
39
54
|
* @param layerName 图层名称
|
|
@@ -68,6 +83,7 @@ export default class MapTools {
|
|
|
68
83
|
* @param lttd 纬度
|
|
69
84
|
* @param zoom 缩放级别
|
|
70
85
|
* @param duration 动画时长
|
|
86
|
+
* @param projection
|
|
71
87
|
* @returns 定位是否成功
|
|
72
88
|
*/
|
|
73
89
|
locationAction(lgtd: number, lttd: number, zoom?: number, duration?: number, projection?: {
|
package/core/map/MapTools.js
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
import VectorSource from "ol/source/Vector";
|
|
3
3
|
import GeoJSON from "ol/format/GeoJSON";
|
|
4
|
+
import ImageStatic from "ol/source/ImageStatic";
|
|
4
5
|
import { ErrorHandler, ErrorType } from "../../utils/ErrorHandler";
|
|
5
6
|
import ValidationUtils from "../../utils/ValidationUtils";
|
|
6
7
|
import ProjectionUtils from "../../utils/ProjectionUtils";
|
|
@@ -133,6 +134,38 @@ class MapTools {
|
|
|
133
134
|
});
|
|
134
135
|
return baseLayer;
|
|
135
136
|
}
|
|
137
|
+
/**
|
|
138
|
+
* 用 GeoJSON 区域裁剪地图上**所有**图层(底图 + 注记 + 用户 vector 层)。
|
|
139
|
+
*
|
|
140
|
+
* 每个图层都会绑定 prerender/postrender 进行 canvas clip。这是 setMapClip
|
|
141
|
+
* 的批量版本,用于"整张地图只在某区域内可见"的需求(例如行政区聚焦)。
|
|
142
|
+
*
|
|
143
|
+
* 实例方法 mapTools.clipMap(data) 会自动用当前 map。
|
|
144
|
+
*/
|
|
145
|
+
clipMap(data) {
|
|
146
|
+
if (!this.map) {
|
|
147
|
+
throw new Error('Map instance is not available');
|
|
148
|
+
}
|
|
149
|
+
MapTools.clipMap(this.map, data);
|
|
150
|
+
}
|
|
151
|
+
/**
|
|
152
|
+
* 用 GeoJSON 区域裁剪地图上所有图层(静态版本)。
|
|
153
|
+
* @param map 地图实例
|
|
154
|
+
* @param data 裁剪边界 GeoJSON
|
|
155
|
+
*/
|
|
156
|
+
static clipMap(map, data) {
|
|
157
|
+
if (!map) {
|
|
158
|
+
throw new Error('Map instance is required');
|
|
159
|
+
}
|
|
160
|
+
map.getLayers().getArray().forEach(layer => {
|
|
161
|
+
try {
|
|
162
|
+
MapTools.setMapClip(layer, data);
|
|
163
|
+
}
|
|
164
|
+
catch (error) {
|
|
165
|
+
ErrorHandler.getInstance().warn('clipMap: 单层裁剪失败,跳过', { layer, error });
|
|
166
|
+
}
|
|
167
|
+
});
|
|
168
|
+
}
|
|
136
169
|
/**
|
|
137
170
|
* 移除图层
|
|
138
171
|
* @param layerName 图层名称
|
|
@@ -183,6 +216,7 @@ class MapTools {
|
|
|
183
216
|
* @param lttd 纬度
|
|
184
217
|
* @param zoom 缩放级别
|
|
185
218
|
* @param duration 动画时长
|
|
219
|
+
* @param projection
|
|
186
220
|
* @returns 定位是否成功
|
|
187
221
|
*/
|
|
188
222
|
locationAction(lgtd, lttd, zoom = 20, duration = 3000, projection) {
|
|
@@ -286,7 +320,7 @@ class MapTools {
|
|
|
286
320
|
layers.forEach((layer) => {
|
|
287
321
|
try {
|
|
288
322
|
const source = layer?.getSource?.();
|
|
289
|
-
const extent = source?.getExtent?.();
|
|
323
|
+
const extent = source?.getExtent?.() ?? (source instanceof ImageStatic ? source.getImageExtent() : undefined);
|
|
290
324
|
if (extent && !isEmpty(extent)) {
|
|
291
325
|
extend(overallExtent, extent);
|
|
292
326
|
hasValidExtent = true;
|
package/core/point/Point.d.ts
CHANGED
|
@@ -1,7 +1,8 @@
|
|
|
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
|
|
4
|
+
import Overlay from 'ol/Overlay';
|
|
5
|
+
import { PointOptions, ClusterOptions, PointData, VueTemplatePointInstance, TwinkleItem, PulsePointOptions, PulsePointLayerHandle, LayerHandle, ControlHandle } from '../../types';
|
|
5
6
|
export default class Point {
|
|
6
7
|
private map;
|
|
7
8
|
/** 由本实例创建的纯图层(addPoint / addClusterPoint)。destroyAll 时统一移除。 */
|
|
@@ -66,40 +67,65 @@ export default class Point {
|
|
|
66
67
|
* img: String 图标
|
|
67
68
|
* }
|
|
68
69
|
*/
|
|
69
|
-
|
|
70
|
-
|
|
70
|
+
/** *********************创建普通点图层*********************/
|
|
71
|
+
private createPointLayer;
|
|
72
|
+
/** *********************创建聚合点图层*********************/
|
|
73
|
+
private createClusterPointLayer;
|
|
74
|
+
/** *********************添加普通点*********************/
|
|
75
|
+
addPoint(pointData: PointData[], options: PointOptions & {
|
|
76
|
+
layerName: string;
|
|
77
|
+
}): LayerHandle<VectorLayer<VectorSource>> | null;
|
|
78
|
+
/** *********************添加聚合点*********************/
|
|
79
|
+
addClusterPoint(pointData: PointData[], options: ClusterOptions & {
|
|
80
|
+
layerName: string;
|
|
81
|
+
}): LayerHandle<VectorLayer<VectorSource>> | null;
|
|
82
|
+
/** @internal 把 VectorLayer 包成 LayerHandle 的内部工具。 */
|
|
83
|
+
private toLayerHandle;
|
|
71
84
|
/**
|
|
72
85
|
* 添加高性能闪烁点图层。
|
|
73
86
|
*
|
|
74
87
|
* 与 addDomPoint 不同,该方法使用 VectorLayer 批量渲染点位,并通过单个
|
|
75
88
|
* requestAnimationFrame 驱动闪烁圈,适合村庄预警等大量点位场景。
|
|
76
89
|
*/
|
|
77
|
-
addPulsePointLayer(pointData: PointData[], options: PulsePointOptions
|
|
90
|
+
addPulsePointLayer(pointData: PointData[], options: PulsePointOptions & {
|
|
91
|
+
layerName: string;
|
|
92
|
+
}): PulsePointLayerHandle | null;
|
|
93
|
+
/**
|
|
94
|
+
* P1-2:从 URL 加载点位数据并添加为静态点图层。
|
|
95
|
+
*
|
|
96
|
+
* 期望 URL 返回 `PointData[]` 形态的 JSON 数组(含 lgtd / lttd)或 FeatureCollection。
|
|
97
|
+
* features 加载/解析完成后 Promise resolve 为 LayerHandle。
|
|
98
|
+
*/
|
|
99
|
+
addPointByUrl(url: string, options: PointOptions & {
|
|
100
|
+
layerName: string;
|
|
101
|
+
}): Promise<LayerHandle<VectorLayer<VectorSource>> | null>;
|
|
102
|
+
/**
|
|
103
|
+
* P1-2:从 URL 加载点位数据并添加为高性能闪烁点图层。
|
|
104
|
+
*/
|
|
105
|
+
addPulsePointLayerByUrl(url: string, options: PulsePointOptions & {
|
|
106
|
+
layerName: string;
|
|
107
|
+
}): Promise<PulsePointLayerHandle | null>;
|
|
78
108
|
/**
|
|
79
109
|
* 添加闪烁点
|
|
80
110
|
* @param twinkleList 闪烁点数据
|
|
81
111
|
* @param callback
|
|
82
112
|
*/
|
|
83
|
-
addDomPoint(twinkleList: TwinkleItem[], callback?: Function): {
|
|
84
|
-
anchors:
|
|
85
|
-
remove: () => void;
|
|
86
|
-
setVisible: (visible: boolean) => void;
|
|
113
|
+
addDomPoint(twinkleList: TwinkleItem[], callback?: Function): ControlHandle<Overlay[]> & {
|
|
114
|
+
anchors: Overlay[];
|
|
87
115
|
};
|
|
88
116
|
/**
|
|
89
117
|
* 添加vue组件为点位
|
|
90
118
|
* @param pointDataList 点位信息列表
|
|
91
119
|
* @param template vue组件模板
|
|
92
|
-
* @param
|
|
120
|
+
* @param options
|
|
93
121
|
* @returns 返回控制对象,包含显示、隐藏、移除方法
|
|
94
122
|
* @throws 当参数无效时抛出错误
|
|
95
123
|
*/
|
|
96
|
-
addVueTemplatePoint(pointDataList: PointData[], template:
|
|
124
|
+
addVueTemplatePoint(pointDataList: PointData[], template: object, options?: {
|
|
97
125
|
positioning?: 'bottom-left' | 'bottom-center' | 'bottom-right' | 'center-left' | 'center-center' | 'center-right' | 'top-left' | 'top-center' | 'top-right';
|
|
98
126
|
stopEvent?: boolean;
|
|
99
|
-
}): {
|
|
100
|
-
|
|
101
|
-
setOneVisibleByProp: (propName: string, propValue: any, visible: boolean) => void;
|
|
102
|
-
remove: () => void;
|
|
127
|
+
}): ControlHandle<VueTemplatePointInstance[]> & {
|
|
128
|
+
setOneVisibleByProp: (propName: string, propValue: unknown, visible: boolean) => void;
|
|
103
129
|
getPoints: () => VueTemplatePointInstance[];
|
|
104
130
|
};
|
|
105
131
|
/**
|
package/core/point/Point.js
CHANGED
|
@@ -102,7 +102,7 @@ export default class Point {
|
|
|
102
102
|
createPointStyle(options, item) {
|
|
103
103
|
const style = {};
|
|
104
104
|
if (options.textKey && item) {
|
|
105
|
-
style.text = this.createTextStyle(options, item[options.textKey]);
|
|
105
|
+
style.text = this.createTextStyle(options, String(item[options.textKey] ?? ''));
|
|
106
106
|
}
|
|
107
107
|
if (options.img) {
|
|
108
108
|
style.image = this.createIconStyle(options);
|
|
@@ -145,7 +145,8 @@ export default class Point {
|
|
|
145
145
|
* img: String 图标
|
|
146
146
|
* }
|
|
147
147
|
*/
|
|
148
|
-
|
|
148
|
+
/** *********************创建普通点图层*********************/
|
|
149
|
+
createPointLayer(pointData, options) {
|
|
149
150
|
if (!ValidationUtils.validatePointData(pointData)) {
|
|
150
151
|
return null;
|
|
151
152
|
}
|
|
@@ -187,7 +188,8 @@ export default class Point {
|
|
|
187
188
|
this.trackLayer(PointVectorLayer);
|
|
188
189
|
return PointVectorLayer;
|
|
189
190
|
}
|
|
190
|
-
|
|
191
|
+
/** *********************创建聚合点图层*********************/
|
|
192
|
+
createClusterPointLayer(pointData, options) {
|
|
191
193
|
if (!ValidationUtils.validatePointData(pointData)) {
|
|
192
194
|
return null;
|
|
193
195
|
}
|
|
@@ -197,6 +199,33 @@ export default class Point {
|
|
|
197
199
|
}
|
|
198
200
|
return layer;
|
|
199
201
|
}
|
|
202
|
+
/** *********************添加普通点*********************/
|
|
203
|
+
addPoint(pointData, options) {
|
|
204
|
+
const layer = this.createPointLayer(pointData, options);
|
|
205
|
+
if (!layer)
|
|
206
|
+
return null;
|
|
207
|
+
return this.toLayerHandle(layer);
|
|
208
|
+
}
|
|
209
|
+
/** *********************添加聚合点*********************/
|
|
210
|
+
addClusterPoint(pointData, options) {
|
|
211
|
+
const layer = this.createClusterPointLayer(pointData, options);
|
|
212
|
+
if (!layer)
|
|
213
|
+
return null;
|
|
214
|
+
return this.toLayerHandle(layer);
|
|
215
|
+
}
|
|
216
|
+
/** @internal 把 VectorLayer 包成 LayerHandle 的内部工具。 */
|
|
217
|
+
toLayerHandle(layer) {
|
|
218
|
+
const map = this.map;
|
|
219
|
+
const managedLayers = this.managedLayers;
|
|
220
|
+
return {
|
|
221
|
+
layer,
|
|
222
|
+
setVisible(visible) { layer.setVisible(visible); },
|
|
223
|
+
remove() {
|
|
224
|
+
managedLayers.delete(layer);
|
|
225
|
+
map.removeLayer(layer);
|
|
226
|
+
}
|
|
227
|
+
};
|
|
228
|
+
}
|
|
200
229
|
/**
|
|
201
230
|
* 添加高性能闪烁点图层。
|
|
202
231
|
*
|
|
@@ -211,6 +240,43 @@ export default class Point {
|
|
|
211
240
|
this.trackDisposable(handle);
|
|
212
241
|
return handle;
|
|
213
242
|
}
|
|
243
|
+
/**
|
|
244
|
+
* P1-2:从 URL 加载点位数据并添加为静态点图层。
|
|
245
|
+
*
|
|
246
|
+
* 期望 URL 返回 `PointData[]` 形态的 JSON 数组(含 lgtd / lttd)或 FeatureCollection。
|
|
247
|
+
* features 加载/解析完成后 Promise resolve 为 LayerHandle。
|
|
248
|
+
*/
|
|
249
|
+
async addPointByUrl(url, options) {
|
|
250
|
+
ValidationUtils.validateNonEmptyString(url, 'Point url is required');
|
|
251
|
+
const response = await fetch(url);
|
|
252
|
+
if (!response.ok) {
|
|
253
|
+
throw new Error(`Failed to fetch point data: ${response.status}`);
|
|
254
|
+
}
|
|
255
|
+
const json = await response.json();
|
|
256
|
+
const pointData = Array.isArray(json) ? json : (json?.features ?? []).map((f) => ({
|
|
257
|
+
...f.properties,
|
|
258
|
+
lgtd: f.geometry?.coordinates?.[0],
|
|
259
|
+
lttd: f.geometry?.coordinates?.[1]
|
|
260
|
+
}));
|
|
261
|
+
return this.addPoint(pointData, options);
|
|
262
|
+
}
|
|
263
|
+
/**
|
|
264
|
+
* P1-2:从 URL 加载点位数据并添加为高性能闪烁点图层。
|
|
265
|
+
*/
|
|
266
|
+
async addPulsePointLayerByUrl(url, options) {
|
|
267
|
+
ValidationUtils.validateNonEmptyString(url, 'Pulse point url is required');
|
|
268
|
+
const response = await fetch(url);
|
|
269
|
+
if (!response.ok) {
|
|
270
|
+
throw new Error(`Failed to fetch pulse point data: ${response.status}`);
|
|
271
|
+
}
|
|
272
|
+
const json = await response.json();
|
|
273
|
+
const pointData = Array.isArray(json) ? json : (json?.features ?? []).map((f) => ({
|
|
274
|
+
...f.properties,
|
|
275
|
+
lgtd: f.geometry?.coordinates?.[0],
|
|
276
|
+
lttd: f.geometry?.coordinates?.[1]
|
|
277
|
+
}));
|
|
278
|
+
return this.addPulsePointLayer(pointData, options);
|
|
279
|
+
}
|
|
214
280
|
/**
|
|
215
281
|
* 添加闪烁点
|
|
216
282
|
* @param twinkleList 闪烁点数据
|
|
@@ -225,7 +291,7 @@ export default class Point {
|
|
|
225
291
|
* 添加vue组件为点位
|
|
226
292
|
* @param pointDataList 点位信息列表
|
|
227
293
|
* @param template vue组件模板
|
|
228
|
-
* @param
|
|
294
|
+
* @param options
|
|
229
295
|
* @returns 返回控制对象,包含显示、隐藏、移除方法
|
|
230
296
|
* @throws 当参数无效时抛出错误
|
|
231
297
|
*/
|
|
@@ -1,13 +1,11 @@
|
|
|
1
1
|
import Overlay from 'ol/Overlay';
|
|
2
2
|
import Map from 'ol/Map';
|
|
3
|
-
import type { TwinkleItem } from '../../types';
|
|
3
|
+
import type { ControlHandle, TwinkleItem } from '../../types';
|
|
4
4
|
/**
|
|
5
5
|
* DOM 点位覆盖物构建器。
|
|
6
6
|
*/
|
|
7
7
|
export default class PointOverlay {
|
|
8
|
-
static create(map: Map, twinkleList: TwinkleItem[], callback?: Function): {
|
|
8
|
+
static create(map: Map, twinkleList: TwinkleItem[], callback?: Function): ControlHandle<Overlay[]> & {
|
|
9
9
|
anchors: Overlay[];
|
|
10
|
-
remove: () => void;
|
|
11
|
-
setVisible: (visible: boolean) => void;
|
|
12
10
|
};
|
|
13
11
|
}
|
|
@@ -36,13 +36,14 @@ export default class PointOverlay {
|
|
|
36
36
|
anchors.push(anchor);
|
|
37
37
|
});
|
|
38
38
|
return {
|
|
39
|
+
target: anchors,
|
|
39
40
|
anchors,
|
|
40
41
|
remove: () => {
|
|
41
42
|
anchors.forEach(anchor => {
|
|
42
43
|
anchor.getElement()?.remove();
|
|
43
44
|
map.removeOverlay(anchor);
|
|
44
45
|
});
|
|
45
|
-
anchors
|
|
46
|
+
anchors.splice(0, anchors.length);
|
|
46
47
|
},
|
|
47
48
|
setVisible: (visible) => {
|
|
48
49
|
anchors.forEach(anchor => {
|
|
@@ -84,7 +84,7 @@ export default class PointPulseLayer {
|
|
|
84
84
|
});
|
|
85
85
|
const createStyles = (feature) => {
|
|
86
86
|
const rawData = feature.get('rawData');
|
|
87
|
-
const level = rawData?.[levelKey] ?? 'default';
|
|
87
|
+
const level = String(rawData?.[levelKey] ?? 'default');
|
|
88
88
|
const progress = frameIndex / Math.max(1, pulseOptions.frameCount - 1);
|
|
89
89
|
const [minRadius, maxRadius] = pulseOptions.radius;
|
|
90
90
|
const radius = minRadius + (maxRadius - minRadius) * progress;
|
|
@@ -110,9 +110,11 @@ export default class PointPulseLayer {
|
|
|
110
110
|
}
|
|
111
111
|
styles.push(pulseStyle);
|
|
112
112
|
}
|
|
113
|
-
const text = options.textVisible && options.textKey && rawData ? rawData[options.textKey] ?? '' : '';
|
|
113
|
+
const text = options.textVisible && options.textKey && rawData ? String(rawData[options.textKey] ?? '') : '';
|
|
114
|
+
// P1-4: icon.img 是新名,icon.src 保留兼容(@deprecated)
|
|
115
|
+
const iconImg = options.icon?.img ?? options.icon?.src;
|
|
114
116
|
const staticCacheKey = [
|
|
115
|
-
options.img ??
|
|
117
|
+
options.img ?? iconImg ?? '',
|
|
116
118
|
options.scale ?? options.icon?.scale ?? ConfigManager.DEFAULT_POINT_ICON_SCALE,
|
|
117
119
|
options.iconColor ?? options.icon?.color ?? '',
|
|
118
120
|
text
|
|
@@ -123,7 +125,7 @@ export default class PointPulseLayer {
|
|
|
123
125
|
return styles;
|
|
124
126
|
}
|
|
125
127
|
const pointStyleOptions = {};
|
|
126
|
-
const iconSrc = options.img ??
|
|
128
|
+
const iconSrc = options.img ?? iconImg;
|
|
127
129
|
if (iconSrc) {
|
|
128
130
|
pointStyleOptions.image = new Icon({
|
|
129
131
|
src: iconSrc,
|
|
@@ -3,7 +3,7 @@ import VectorLayer from "ol/layer/Vector";
|
|
|
3
3
|
import VectorSource from "ol/source/Vector";
|
|
4
4
|
import { Image as ImageLayer } from "ol/layer";
|
|
5
5
|
import Feature from "ol/Feature";
|
|
6
|
-
import { PolygonOptions, MapJSONData, PointData, HeatMapOptions, ImageLayerData, MaskLayerOptions, FeatureColorUpdateOptions } from '../../types';
|
|
6
|
+
import { PolygonOptions, MapJSONData, PointData, HeatMapOptions, ImageLayerData, MaskLayerOptions, FeatureColorUpdateOptions, LayerHandle } from '../../types';
|
|
7
7
|
/**
|
|
8
8
|
* Polygon 类用于处理地图上的面要素操作
|
|
9
9
|
* 包括添加多边形、边框、图片图层、热力图等功能
|
|
@@ -24,6 +24,8 @@ export default class Polygon {
|
|
|
24
24
|
* @internal
|
|
25
25
|
*/
|
|
26
26
|
private trackLayer;
|
|
27
|
+
/** *********************统一句柄:OL 图层*********************/
|
|
28
|
+
private toLayerHandle;
|
|
27
29
|
/**
|
|
28
30
|
* 销毁本实例创建的所有图层。供 MyOl.destroy 调用。
|
|
29
31
|
*/
|
|
@@ -35,7 +37,7 @@ export default class Polygon {
|
|
|
35
37
|
* @returns 创建的图层实例
|
|
36
38
|
* @throws 当数据格式无效时抛出错误
|
|
37
39
|
*/
|
|
38
|
-
addBorderPolygon(data: MapJSONData, options?: PolygonOptions): VectorLayer<VectorSource
|
|
40
|
+
addBorderPolygon(data: MapJSONData, options?: PolygonOptions): LayerHandle<VectorLayer<VectorSource>>;
|
|
39
41
|
/**
|
|
40
42
|
* 从URL添加地图边框图层
|
|
41
43
|
* @param url 数据URL
|
|
@@ -43,7 +45,7 @@ export default class Polygon {
|
|
|
43
45
|
* @returns 创建的图层实例
|
|
44
46
|
* @throws 当数据格式无效时抛出错误
|
|
45
47
|
*/
|
|
46
|
-
addBorderPolygonByUrl(url: string, options?: PolygonOptions): VectorLayer<VectorSource
|
|
48
|
+
addBorderPolygonByUrl(url: string, options?: PolygonOptions): Promise<LayerHandle<VectorLayer<VectorSource>>>;
|
|
47
49
|
/**
|
|
48
50
|
* 添加多边形图层
|
|
49
51
|
* @param dataJSON GeoJSON 数据
|
|
@@ -51,15 +53,16 @@ export default class Polygon {
|
|
|
51
53
|
* @returns 创建的矢量图层
|
|
52
54
|
* @throws 当数据格式无效时抛出错误
|
|
53
55
|
*/
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
56
|
+
/** *********************创建多边形图层*********************/
|
|
57
|
+
private createPolygonLayer;
|
|
58
|
+
/** *********************添加多边形图层*********************/
|
|
59
|
+
addPolygon(dataJSON: MapJSONData, options: PolygonOptions & {
|
|
60
|
+
layerName: string;
|
|
61
|
+
}): LayerHandle<VectorLayer<VectorSource>>;
|
|
62
|
+
/** *********************从 URL 添加多边形图层*********************/
|
|
63
|
+
addPolygonByUrl(url: string, options: PolygonOptions & {
|
|
64
|
+
layerName: string;
|
|
65
|
+
}): Promise<LayerHandle<VectorLayer<VectorSource>>>;
|
|
63
66
|
/**
|
|
64
67
|
* 适应图层视图
|
|
65
68
|
* @param layer 图层对象
|
|
@@ -85,7 +88,7 @@ export default class Polygon {
|
|
|
85
88
|
*/
|
|
86
89
|
setOutLayer(data: MapJSONData, options?: {
|
|
87
90
|
layerName?: string;
|
|
88
|
-
extent?:
|
|
91
|
+
extent?: number[];
|
|
89
92
|
fillColor?: string;
|
|
90
93
|
strokeWidth?: number;
|
|
91
94
|
strokeColor?: string;
|
|
@@ -98,13 +101,13 @@ export default class Polygon {
|
|
|
98
101
|
* @returns 创建的图片图层
|
|
99
102
|
* @throws 当数据格式无效时抛出错误
|
|
100
103
|
*/
|
|
101
|
-
addImageLayer(imageData: ImageLayerData, options?: PolygonOptions): ImageLayer<any
|
|
104
|
+
addImageLayer(imageData: ImageLayerData, options?: PolygonOptions): LayerHandle<ImageLayer<any>>;
|
|
102
105
|
/**
|
|
103
106
|
* 添加热力图图层
|
|
104
107
|
* @param pointData 点数据数组
|
|
105
108
|
* @param options 热力图配置
|
|
106
109
|
*/
|
|
107
|
-
addHeatmap(pointData: PointData[], options?: HeatMapOptions): import("ol/layer").Heatmap<Feature<import("ol/geom").Geometry>, VectorSource<Feature<import("ol/geom").Geometry
|
|
110
|
+
addHeatmap(pointData: PointData[], options?: HeatMapOptions): LayerHandle<import("ol/layer").Heatmap<Feature<import("ol/geom").Geometry>, VectorSource<Feature<import("ol/geom").Geometry>>>>;
|
|
108
111
|
/**
|
|
109
112
|
* 添加遮罩图层
|
|
110
113
|
* @param data GeoJSON格式的遮罩数据
|
|
@@ -112,6 +115,6 @@ export default class Polygon {
|
|
|
112
115
|
* @returns 创建的遮罩图层
|
|
113
116
|
* @throws 当数据格式无效时抛出错误
|
|
114
117
|
*/
|
|
115
|
-
addMaskLayer(data:
|
|
118
|
+
addMaskLayer(data: MapJSONData, options?: MaskLayerOptions): LayerHandle<VectorLayer<VectorSource>>;
|
|
116
119
|
removePolygonLayer(layerName: string): void;
|
|
117
120
|
}
|
package/core/polygon/Polygon.js
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
import VectorLayer from "ol/layer/Vector";
|
|
3
3
|
import VectorSource from "ol/source/Vector";
|
|
4
4
|
import GeoJSON from "ol/format/GeoJSON";
|
|
5
|
-
import { ErrorHandler } from '../../utils/ErrorHandler';
|
|
5
|
+
import { ErrorHandler, InvalidGeoJSONError, LayerNotFoundError } from '../../utils/ErrorHandler';
|
|
6
6
|
import ProjectionUtils from '../../utils/ProjectionUtils';
|
|
7
7
|
import ValidationUtils from '../../utils/ValidationUtils';
|
|
8
8
|
import { ConfigManager, MapTools } from "../map";
|
|
@@ -37,6 +37,19 @@ export default class Polygon {
|
|
|
37
37
|
this.managedLayers.add(layer);
|
|
38
38
|
return layer;
|
|
39
39
|
}
|
|
40
|
+
/** *********************统一句柄:OL 图层*********************/
|
|
41
|
+
toLayerHandle(layer) {
|
|
42
|
+
const map = this.map;
|
|
43
|
+
const managedLayers = this.managedLayers;
|
|
44
|
+
return {
|
|
45
|
+
layer,
|
|
46
|
+
setVisible(visible) { layer.setVisible(visible); },
|
|
47
|
+
remove() {
|
|
48
|
+
managedLayers.delete(layer);
|
|
49
|
+
map.removeLayer(layer);
|
|
50
|
+
}
|
|
51
|
+
};
|
|
52
|
+
}
|
|
40
53
|
/**
|
|
41
54
|
* 销毁本实例创建的所有图层。供 MyOl.destroy 调用。
|
|
42
55
|
*/
|
|
@@ -62,13 +75,14 @@ export default class Polygon {
|
|
|
62
75
|
ValidationUtils.validateGeoJSONData(data);
|
|
63
76
|
const mergedOptions = {
|
|
64
77
|
fillColor: 'rgba(255, 255, 255, 0)',
|
|
65
|
-
...options
|
|
78
|
+
...options,
|
|
79
|
+
layerName: options?.layerName ?? 'border'
|
|
66
80
|
};
|
|
67
|
-
const
|
|
81
|
+
const handle = this.addPolygon(data, mergedOptions);
|
|
68
82
|
if (mergedOptions.mask) {
|
|
69
83
|
this.setOutLayer(data);
|
|
70
84
|
}
|
|
71
|
-
return
|
|
85
|
+
return handle;
|
|
72
86
|
}
|
|
73
87
|
/**
|
|
74
88
|
* 从URL添加地图边框图层
|
|
@@ -77,14 +91,13 @@ export default class Polygon {
|
|
|
77
91
|
* @returns 创建的图层实例
|
|
78
92
|
* @throws 当数据格式无效时抛出错误
|
|
79
93
|
*/
|
|
80
|
-
addBorderPolygonByUrl(url, options) {
|
|
94
|
+
async addBorderPolygonByUrl(url, options) {
|
|
81
95
|
const mergedOptions = {
|
|
82
|
-
layerName: 'border',
|
|
83
96
|
fillColor: 'rgba(255, 255, 255, 0)',
|
|
84
|
-
...options
|
|
97
|
+
...options,
|
|
98
|
+
layerName: options?.layerName ?? 'border'
|
|
85
99
|
};
|
|
86
|
-
|
|
87
|
-
return layer;
|
|
100
|
+
return this.addPolygonByUrl(url, mergedOptions);
|
|
88
101
|
}
|
|
89
102
|
/**
|
|
90
103
|
* 添加多边形图层
|
|
@@ -93,7 +106,8 @@ export default class Polygon {
|
|
|
93
106
|
* @returns 创建的矢量图层
|
|
94
107
|
* @throws 当数据格式无效时抛出错误
|
|
95
108
|
*/
|
|
96
|
-
|
|
109
|
+
/** *********************创建多边形图层*********************/
|
|
110
|
+
createPolygonLayer(dataJSON, options) {
|
|
97
111
|
ValidationUtils.validateGeoJSONData(dataJSON);
|
|
98
112
|
const mergedOptions = {
|
|
99
113
|
...ConfigManager.DEFAULT_POLYGON_OPTIONS,
|
|
@@ -118,7 +132,7 @@ export default class Polygon {
|
|
|
118
132
|
features = format.readFeatures(dataJSON, ProjectionUtils.getGeoJSONReadOptions(mergedOptions));
|
|
119
133
|
}
|
|
120
134
|
catch (error) {
|
|
121
|
-
throw new
|
|
135
|
+
throw new InvalidGeoJSONError(error instanceof Error ? error.message : String(error), { layerName: mergedOptions.layerName });
|
|
122
136
|
}
|
|
123
137
|
const layer = new VectorLayer({
|
|
124
138
|
properties: {
|
|
@@ -138,55 +152,19 @@ export default class Polygon {
|
|
|
138
152
|
}
|
|
139
153
|
return layer;
|
|
140
154
|
}
|
|
141
|
-
/**
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
...options
|
|
152
|
-
};
|
|
153
|
-
// 如果指定了图层名称,先移除同名图层
|
|
154
|
-
if (mergedOptions.layerName) {
|
|
155
|
-
new MapTools(this.map).removeLayer(mergedOptions.layerName);
|
|
156
|
-
}
|
|
157
|
-
const format = new GeoJSON(ProjectionUtils.getGeoJSONReadOptions(mergedOptions));
|
|
158
|
-
// 优化:在解析 Feature 时直接注入 layerName,利用解析过程的遍历,避免解析后的二次循环
|
|
159
|
-
if (mergedOptions.layerName) {
|
|
160
|
-
const originalReadFeatureFromObject = format.readFeatureFromObject;
|
|
161
|
-
format.readFeatureFromObject = function (object, options) {
|
|
162
|
-
const feature = originalReadFeatureFromObject.call(this, object, options);
|
|
163
|
-
feature.set('layerName', mergedOptions.layerName, true); // true 表示静默设置,不触发事件
|
|
164
|
-
return feature;
|
|
165
|
-
};
|
|
166
|
-
}
|
|
167
|
-
const source = new VectorSource({
|
|
168
|
-
url,
|
|
169
|
-
format
|
|
170
|
-
});
|
|
171
|
-
const layer = new VectorLayer({
|
|
172
|
-
properties: {
|
|
173
|
-
name: mergedOptions.layerName,
|
|
174
|
-
layerName: mergedOptions.layerName
|
|
175
|
-
},
|
|
176
|
-
source,
|
|
177
|
-
style: PolygonStyleFactory.createStyle(mergedOptions),
|
|
178
|
-
zIndex: mergedOptions.zIndex
|
|
179
|
-
});
|
|
180
|
-
layer.setVisible(mergedOptions.visible);
|
|
181
|
-
this.map.addLayer(layer);
|
|
182
|
-
this.trackLayer(layer);
|
|
183
|
-
// 如果需要适应视图
|
|
184
|
-
if (mergedOptions.fitView) {
|
|
185
|
-
source.once('featuresloadend', () => {
|
|
186
|
-
this.fitViewToLayer(layer);
|
|
187
|
-
});
|
|
155
|
+
/** *********************添加多边形图层*********************/
|
|
156
|
+
addPolygon(dataJSON, options) {
|
|
157
|
+
return this.toLayerHandle(this.createPolygonLayer(dataJSON, options));
|
|
158
|
+
}
|
|
159
|
+
/** *********************从 URL 添加多边形图层*********************/
|
|
160
|
+
async addPolygonByUrl(url, options) {
|
|
161
|
+
ValidationUtils.validateNonEmptyString(url, 'Polygon url is required');
|
|
162
|
+
const response = await fetch(url);
|
|
163
|
+
if (!response.ok) {
|
|
164
|
+
throw new Error(`Failed to fetch polygon GeoJSON: ${response.status}`);
|
|
188
165
|
}
|
|
189
|
-
|
|
166
|
+
const json = await response.json();
|
|
167
|
+
return this.addPolygon(json, options);
|
|
190
168
|
}
|
|
191
169
|
/**
|
|
192
170
|
* 适应图层视图
|
|
@@ -209,7 +187,7 @@ export default class Polygon {
|
|
|
209
187
|
ValidationUtils.validateLayerName(layerName);
|
|
210
188
|
const layers = MapTools.getLayerByLayerName(this.map, layerName);
|
|
211
189
|
if (layers.length === 0) {
|
|
212
|
-
throw new
|
|
190
|
+
throw new LayerNotFoundError(layerName, { method: 'updateFeatureColor' });
|
|
213
191
|
}
|
|
214
192
|
const layer = layers[0];
|
|
215
193
|
if (!(layer instanceof VectorLayer)) {
|
|
@@ -255,7 +233,7 @@ export default class Polygon {
|
|
|
255
233
|
addImageLayer(imageData, options) {
|
|
256
234
|
const layer = PolygonImageLayer.addImageLayer(this.map, imageData, options);
|
|
257
235
|
this.trackLayer(layer);
|
|
258
|
-
return layer;
|
|
236
|
+
return this.toLayerHandle(layer);
|
|
259
237
|
}
|
|
260
238
|
/**
|
|
261
239
|
* 添加热力图图层
|
|
@@ -267,7 +245,7 @@ export default class Polygon {
|
|
|
267
245
|
if (layer) {
|
|
268
246
|
this.trackLayer(layer);
|
|
269
247
|
}
|
|
270
|
-
return layer;
|
|
248
|
+
return this.toLayerHandle(layer);
|
|
271
249
|
}
|
|
272
250
|
/**
|
|
273
251
|
* 添加遮罩图层
|
|
@@ -279,7 +257,7 @@ export default class Polygon {
|
|
|
279
257
|
addMaskLayer(data, options) {
|
|
280
258
|
const layer = PolygonMaskLayer.addMaskLayer(this.map, data, options);
|
|
281
259
|
this.trackLayer(layer);
|
|
282
|
-
return layer;
|
|
260
|
+
return this.toLayerHandle(layer);
|
|
283
261
|
}
|
|
284
262
|
removePolygonLayer(layerName) {
|
|
285
263
|
new MapTools(this.map).removeLayer(layerName);
|