my-openlayer 2.0.0 → 2.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/MyOl.d.ts +128 -128
- package/MyOl.js +382 -381
- package/README.md +0 -21
- package/core/ConfigManager.d.ts +88 -88
- package/core/ConfigManager.js +112 -112
- package/core/EventManager.d.ts +141 -141
- package/core/EventManager.js +316 -316
- package/core/Line.d.ts +130 -109
- package/core/Line.js +354 -288
- package/core/MapBaseLayers.d.ts +234 -234
- package/core/MapBaseLayers.js +573 -573
- package/core/MapTools.d.ts +68 -68
- package/core/MapTools.js +202 -201
- package/core/MeasureHandler.d.ts +65 -65
- package/core/MeasureHandler.js +312 -312
- package/core/Point.d.ts +94 -94
- package/core/Point.js +348 -348
- package/core/Polygon.d.ts +157 -139
- package/core/Polygon.js +558 -529
- package/core/VueTemplatePoint.d.ts +51 -51
- package/core/VueTemplatePoint.js +529 -529
- package/index.d.ts +18 -18
- package/index.js +17 -17
- package/package.json +1 -1
- package/types.d.ts +305 -302
- package/types.js +11 -11
- package/utils/ErrorHandler.d.ts +102 -102
- package/utils/ErrorHandler.js +191 -191
- package/utils/ValidationUtils.d.ts +163 -163
- package/utils/ValidationUtils.js +312 -312
package/core/Point.js
CHANGED
|
@@ -1,348 +1,348 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
import Overlay from 'ol/Overlay';
|
|
3
|
-
import Feature from "ol/Feature";
|
|
4
|
-
import { Point as olPoint } from "ol/geom";
|
|
5
|
-
import { Text, Style, Fill, Stroke, Icon } from "ol/style";
|
|
6
|
-
import VectorLayer from "ol/layer/Vector";
|
|
7
|
-
import VectorSource from "ol/source/Vector";
|
|
8
|
-
import { Cluster } from 'ol/source';
|
|
9
|
-
import * as turf from '@turf/turf';
|
|
10
|
-
import GeoJSON from "ol/format/GeoJSON";
|
|
11
|
-
import VueTemplatePoint from './VueTemplatePoint';
|
|
12
|
-
import MapTools from "./MapTools";
|
|
13
|
-
import { ValidationUtils } from '../utils/ValidationUtils';
|
|
14
|
-
export default class Point {
|
|
15
|
-
constructor(map) {
|
|
16
|
-
this.map = map;
|
|
17
|
-
}
|
|
18
|
-
/**
|
|
19
|
-
* 创建文本样式
|
|
20
|
-
* @private
|
|
21
|
-
* @param options 选项
|
|
22
|
-
* @param text 文本内容
|
|
23
|
-
* @returns 文本样式
|
|
24
|
-
*/
|
|
25
|
-
createTextStyle(options, text) {
|
|
26
|
-
return new Text({
|
|
27
|
-
text: text,
|
|
28
|
-
font: options.textFont || '12px Calibri,sans-serif',
|
|
29
|
-
fill: new Fill({
|
|
30
|
-
color: options.textFillColor || '#FFF'
|
|
31
|
-
}),
|
|
32
|
-
stroke: new Stroke({
|
|
33
|
-
color: options.textStrokeColor || '#000',
|
|
34
|
-
width: options.textStrokeWidth || 3
|
|
35
|
-
}),
|
|
36
|
-
offsetY: options.textOffsetY || 20,
|
|
37
|
-
});
|
|
38
|
-
}
|
|
39
|
-
/**
|
|
40
|
-
* 创建图标样式
|
|
41
|
-
* @private
|
|
42
|
-
* @param options 选项
|
|
43
|
-
* @returns 图标样式
|
|
44
|
-
*/
|
|
45
|
-
createIconStyle(options) {
|
|
46
|
-
const iconOptions = {
|
|
47
|
-
src: options.img,
|
|
48
|
-
scale: options.scale ?? 1,
|
|
49
|
-
};
|
|
50
|
-
if (options.iconColor) {
|
|
51
|
-
iconOptions.color = options.iconColor;
|
|
52
|
-
}
|
|
53
|
-
return new Icon(iconOptions);
|
|
54
|
-
}
|
|
55
|
-
/**
|
|
56
|
-
* 创建点样式
|
|
57
|
-
* @private
|
|
58
|
-
* @param options 选项
|
|
59
|
-
* @param item 数据项
|
|
60
|
-
* @returns 样式对象
|
|
61
|
-
*/
|
|
62
|
-
createPointStyle(options, item) {
|
|
63
|
-
const style = {};
|
|
64
|
-
if (options.textKey && item) {
|
|
65
|
-
style.text = this.createTextStyle(options, item[options.textKey]);
|
|
66
|
-
}
|
|
67
|
-
if (options.img) {
|
|
68
|
-
style.image = this.createIconStyle(options);
|
|
69
|
-
}
|
|
70
|
-
return new Style(style);
|
|
71
|
-
}
|
|
72
|
-
/**
|
|
73
|
-
* 创建集群样式
|
|
74
|
-
* @private
|
|
75
|
-
* @param options 选项
|
|
76
|
-
* @param name 名称
|
|
77
|
-
* @returns 样式对象
|
|
78
|
-
*/
|
|
79
|
-
createClusterStyle(options, name) {
|
|
80
|
-
const style = {};
|
|
81
|
-
if (options.textKey) {
|
|
82
|
-
style.text = this.createTextStyle(options, name);
|
|
83
|
-
}
|
|
84
|
-
if (options.img) {
|
|
85
|
-
style.image = this.createIconStyle(options);
|
|
86
|
-
}
|
|
87
|
-
return new Style(style);
|
|
88
|
-
}
|
|
89
|
-
/**
|
|
90
|
-
* 配置图层属性
|
|
91
|
-
* @private
|
|
92
|
-
* @param layer 图层
|
|
93
|
-
* @param options 选项
|
|
94
|
-
*/
|
|
95
|
-
configureLayer(layer, options) {
|
|
96
|
-
layer.setVisible(options.visible === undefined ? true : options.visible);
|
|
97
|
-
this.map.addLayer(layer);
|
|
98
|
-
}
|
|
99
|
-
/**
|
|
100
|
-
*
|
|
101
|
-
* @param pointData
|
|
102
|
-
* @param type
|
|
103
|
-
* @param options {
|
|
104
|
-
* textKey: String 数据中的文本的key
|
|
105
|
-
* img: String 图标
|
|
106
|
-
* }
|
|
107
|
-
*/
|
|
108
|
-
addPoint(pointData, options) {
|
|
109
|
-
if (!ValidationUtils.validatePointData(pointData)) {
|
|
110
|
-
return null;
|
|
111
|
-
}
|
|
112
|
-
const pointFeatureList = [];
|
|
113
|
-
pointData.forEach((item) => {
|
|
114
|
-
if (!ValidationUtils.validateCoordinates(item)) {
|
|
115
|
-
return;
|
|
116
|
-
}
|
|
117
|
-
const pointFeature = new Feature({
|
|
118
|
-
rawData: item,
|
|
119
|
-
type: options.layerName,
|
|
120
|
-
geometry: new olPoint([item.lgtd, item.lttd])
|
|
121
|
-
});
|
|
122
|
-
pointFeature.setStyle(this.createPointStyle(options, item));
|
|
123
|
-
pointFeatureList.push(pointFeature);
|
|
124
|
-
});
|
|
125
|
-
const PointVectorLayer = new VectorLayer({
|
|
126
|
-
layerName: options.layerName,
|
|
127
|
-
source: new VectorSource({
|
|
128
|
-
features: pointFeatureList
|
|
129
|
-
}),
|
|
130
|
-
zIndex: options.zIndex || 21,
|
|
131
|
-
});
|
|
132
|
-
this.configureLayer(PointVectorLayer, options);
|
|
133
|
-
return PointVectorLayer;
|
|
134
|
-
}
|
|
135
|
-
addClusterPoint(pointData, options) {
|
|
136
|
-
if (!ValidationUtils.validatePointData(pointData)) {
|
|
137
|
-
return null;
|
|
138
|
-
}
|
|
139
|
-
const pointFeatureList = [];
|
|
140
|
-
pointData.forEach(item => {
|
|
141
|
-
if (!ValidationUtils.validateCoordinates(item)) {
|
|
142
|
-
return;
|
|
143
|
-
}
|
|
144
|
-
const pointFeature = new Feature({
|
|
145
|
-
geometry: new olPoint([item.lgtd, item.lttd]),
|
|
146
|
-
name: options.textKey ? item[options.textKey] : '',
|
|
147
|
-
});
|
|
148
|
-
pointFeatureList.push(pointFeature);
|
|
149
|
-
});
|
|
150
|
-
const source = new VectorSource({
|
|
151
|
-
features: pointFeatureList,
|
|
152
|
-
});
|
|
153
|
-
const clusterSource = new Cluster({
|
|
154
|
-
distance: options.distance || 40,
|
|
155
|
-
minDistance: options.minDistance || 0,
|
|
156
|
-
source: source,
|
|
157
|
-
});
|
|
158
|
-
const clusterLayer = new VectorLayer({
|
|
159
|
-
layerName: options.layerName,
|
|
160
|
-
source: clusterSource,
|
|
161
|
-
style: (feature) => {
|
|
162
|
-
const name = feature.get('features')[0].get(options.textKey);
|
|
163
|
-
return this.createClusterStyle(options, name);
|
|
164
|
-
},
|
|
165
|
-
zIndex: options.zIndex || 21,
|
|
166
|
-
});
|
|
167
|
-
this.configureLayer(clusterLayer, options);
|
|
168
|
-
return clusterLayer;
|
|
169
|
-
}
|
|
170
|
-
// 在流域中心添加闪烁点位
|
|
171
|
-
addTwinkleLayerFromPolygon(twinkleList, className, key, json) {
|
|
172
|
-
new MapTools(this.map).removeLayer('twinklePoint');
|
|
173
|
-
// 计算多边形的中心点坐标
|
|
174
|
-
const calculatePolygonCenter = (polygonCoordinates) => {
|
|
175
|
-
const polygon = turf.polygon(polygonCoordinates[0]);
|
|
176
|
-
const centroid = turf.centroid(polygon);
|
|
177
|
-
return centroid.geometry.coordinates;
|
|
178
|
-
};
|
|
179
|
-
const features = json.features;
|
|
180
|
-
const vectorSource = new VectorSource({
|
|
181
|
-
format: new GeoJSON(),
|
|
182
|
-
});
|
|
183
|
-
twinkleList.forEach(item => {
|
|
184
|
-
const feature = features.find((ele) => {
|
|
185
|
-
return ele.properties.BASIN === item.idx;
|
|
186
|
-
});
|
|
187
|
-
if (!feature)
|
|
188
|
-
return;
|
|
189
|
-
feature.properties.level = item.lev;
|
|
190
|
-
const geojson = new GeoJSON();
|
|
191
|
-
const olFeature = geojson.readFeature(feature);
|
|
192
|
-
if (Array.isArray(olFeature)) {
|
|
193
|
-
vectorSource.addFeatures(olFeature);
|
|
194
|
-
}
|
|
195
|
-
else {
|
|
196
|
-
vectorSource.addFeature(olFeature);
|
|
197
|
-
}
|
|
198
|
-
if (feature) {
|
|
199
|
-
const polygonCenter = calculatePolygonCenter(feature.geometry.coordinates);
|
|
200
|
-
item.lgtd = polygonCenter[0];
|
|
201
|
-
item.lttd = polygonCenter[1];
|
|
202
|
-
}
|
|
203
|
-
});
|
|
204
|
-
const basinLayer = new VectorLayer({
|
|
205
|
-
name: 'twinklePoint',
|
|
206
|
-
layerName: 'twinklePoint',
|
|
207
|
-
source: vectorSource,
|
|
208
|
-
style: function (feature) {
|
|
209
|
-
return new Style({
|
|
210
|
-
stroke: new Stroke({
|
|
211
|
-
color: 'rgb(139,188,245)',
|
|
212
|
-
width: 3
|
|
213
|
-
}),
|
|
214
|
-
fill: new Fill({ color: 'rgba(255, 255, 255, 0)' }),
|
|
215
|
-
text: new Text({
|
|
216
|
-
text: feature.values_['BASIN'] || "",
|
|
217
|
-
font: '14px Calibri,sans-serif',
|
|
218
|
-
fill: new Fill({ color: '#FFF' }),
|
|
219
|
-
stroke: new Stroke({
|
|
220
|
-
color: '#409EFF', width: 2
|
|
221
|
-
}),
|
|
222
|
-
})
|
|
223
|
-
});
|
|
224
|
-
},
|
|
225
|
-
zIndex: 21
|
|
226
|
-
});
|
|
227
|
-
this.map.addLayer(basinLayer);
|
|
228
|
-
this.addTwinkleLayer(twinkleList, className, key, (twinkleItem) => {
|
|
229
|
-
});
|
|
230
|
-
}
|
|
231
|
-
/**
|
|
232
|
-
* 添加闪烁点
|
|
233
|
-
* @param twinkleList 闪烁点数据 - 二维数组 [[],[]]
|
|
234
|
-
* @param className 闪烁点样式,需要和id保持一致
|
|
235
|
-
* @param key 闪烁点索引
|
|
236
|
-
* @param callback
|
|
237
|
-
*/
|
|
238
|
-
addTwinkleLayer(twinkleList, className = 'marker_warning', key, callback) {
|
|
239
|
-
// 查找class是warn-points的dom,并删除
|
|
240
|
-
const arr = document.getElementsByClassName(className);
|
|
241
|
-
const l = arr.length;
|
|
242
|
-
for (let i = l - 1; i >= 0; i--) {
|
|
243
|
-
if (arr[i] !== null) {
|
|
244
|
-
arr[i].parentNode?.removeChild(arr[i]);
|
|
245
|
-
}
|
|
246
|
-
}
|
|
247
|
-
const el = document.getElementById(className);
|
|
248
|
-
for (let i = 0; i < twinkleList.length; i++) {
|
|
249
|
-
const twinkleItem = twinkleList[i];
|
|
250
|
-
// 定义图标Dom
|
|
251
|
-
const el2 = document.createElement('div');
|
|
252
|
-
el2.id = className + i;
|
|
253
|
-
el2.className = className + twinkleItem[key];
|
|
254
|
-
el2.onclick = () => {
|
|
255
|
-
callback && callback(twinkleItem);
|
|
256
|
-
// bus.emit('twinkleClick', twinkleItem)
|
|
257
|
-
};
|
|
258
|
-
// 插入图标
|
|
259
|
-
if (el)
|
|
260
|
-
el.insertAdjacentElement('afterend', el2);
|
|
261
|
-
// 创建一个覆盖物
|
|
262
|
-
const anchor = new Overlay({
|
|
263
|
-
element: document.getElementById(className + i) || undefined,
|
|
264
|
-
positioning: 'center-center',
|
|
265
|
-
className: className
|
|
266
|
-
});
|
|
267
|
-
// 关键的一点,需要设置附加到地图上的位置
|
|
268
|
-
anchor.setPosition([twinkleItem.lgtd, twinkleItem.lttd]);
|
|
269
|
-
// 然后添加到map上
|
|
270
|
-
this.map.addOverlay(anchor);
|
|
271
|
-
}
|
|
272
|
-
}
|
|
273
|
-
/**
|
|
274
|
-
* 地图定位
|
|
275
|
-
* @param lgtd 经度
|
|
276
|
-
* @param lttd 纬度
|
|
277
|
-
* @param zoom 缩放级别
|
|
278
|
-
* @param duration 动画时长
|
|
279
|
-
*/
|
|
280
|
-
locationAction(lgtd, lttd, zoom = 20, duration = 3000) {
|
|
281
|
-
if (!ValidationUtils.validateLngLat(lgtd, lttd)) {
|
|
282
|
-
return false;
|
|
283
|
-
}
|
|
284
|
-
try {
|
|
285
|
-
this.map.getView().animate({ center: [lgtd, lttd], zoom, duration });
|
|
286
|
-
return true;
|
|
287
|
-
}
|
|
288
|
-
catch (error) {
|
|
289
|
-
console.error('[地图定位]', '定位失败:', error);
|
|
290
|
-
return false;
|
|
291
|
-
}
|
|
292
|
-
}
|
|
293
|
-
/**
|
|
294
|
-
* 设置dom元素为点位
|
|
295
|
-
*/
|
|
296
|
-
addDomPoint(id, lgtd, lttd) {
|
|
297
|
-
if (!id) {
|
|
298
|
-
console.error('Element ID is required');
|
|
299
|
-
return false;
|
|
300
|
-
}
|
|
301
|
-
if (!ValidationUtils.validateLngLat(lgtd, lttd)) {
|
|
302
|
-
return false;
|
|
303
|
-
}
|
|
304
|
-
const el = document.getElementById(id);
|
|
305
|
-
if (!el) {
|
|
306
|
-
console.error(`Element with id '${id}' not found`);
|
|
307
|
-
return false;
|
|
308
|
-
}
|
|
309
|
-
try {
|
|
310
|
-
const anchor = new Overlay({
|
|
311
|
-
id: id,
|
|
312
|
-
element: el,
|
|
313
|
-
positioning: 'center-center',
|
|
314
|
-
stopEvent: false
|
|
315
|
-
});
|
|
316
|
-
anchor.setPosition([lgtd, lttd]);
|
|
317
|
-
this.map.addOverlay(anchor);
|
|
318
|
-
return true;
|
|
319
|
-
}
|
|
320
|
-
catch (error) {
|
|
321
|
-
console.error('Failed to set DOM point:', error);
|
|
322
|
-
return false;
|
|
323
|
-
}
|
|
324
|
-
}
|
|
325
|
-
/**
|
|
326
|
-
* 添加vue组件为点位
|
|
327
|
-
* @param pointDataList 点位信息列表
|
|
328
|
-
* @param template vue组件模板
|
|
329
|
-
* @param Vue Vue实例
|
|
330
|
-
* @returns 返回控制对象,包含显示、隐藏、移除方法
|
|
331
|
-
* @throws 当参数无效时抛出错误
|
|
332
|
-
*/
|
|
333
|
-
addVueTemplatePoint(pointDataList, template, options) {
|
|
334
|
-
if (!pointDataList || !Array.isArray(pointDataList) || pointDataList.length === 0) {
|
|
335
|
-
throw new Error('Valid point info list is required');
|
|
336
|
-
}
|
|
337
|
-
if (!template) {
|
|
338
|
-
throw new Error('Vue template is required');
|
|
339
|
-
}
|
|
340
|
-
try {
|
|
341
|
-
const vueTemplatePoint = new VueTemplatePoint(this.map);
|
|
342
|
-
return vueTemplatePoint.addVueTemplatePoint(pointDataList, template, options);
|
|
343
|
-
}
|
|
344
|
-
catch (error) {
|
|
345
|
-
throw new Error(`Failed to create Vue template points: ${error}`);
|
|
346
|
-
}
|
|
347
|
-
}
|
|
348
|
-
}
|
|
1
|
+
"use strict";
|
|
2
|
+
import Overlay from 'ol/Overlay';
|
|
3
|
+
import Feature from "ol/Feature";
|
|
4
|
+
import { Point as olPoint } from "ol/geom";
|
|
5
|
+
import { Text, Style, Fill, Stroke, Icon } from "ol/style";
|
|
6
|
+
import VectorLayer from "ol/layer/Vector";
|
|
7
|
+
import VectorSource from "ol/source/Vector";
|
|
8
|
+
import { Cluster } from 'ol/source';
|
|
9
|
+
import * as turf from '@turf/turf';
|
|
10
|
+
import GeoJSON from "ol/format/GeoJSON";
|
|
11
|
+
import VueTemplatePoint from './VueTemplatePoint';
|
|
12
|
+
import MapTools from "./MapTools";
|
|
13
|
+
import { ValidationUtils } from '../utils/ValidationUtils';
|
|
14
|
+
export default class Point {
|
|
15
|
+
constructor(map) {
|
|
16
|
+
this.map = map;
|
|
17
|
+
}
|
|
18
|
+
/**
|
|
19
|
+
* 创建文本样式
|
|
20
|
+
* @private
|
|
21
|
+
* @param options 选项
|
|
22
|
+
* @param text 文本内容
|
|
23
|
+
* @returns 文本样式
|
|
24
|
+
*/
|
|
25
|
+
createTextStyle(options, text) {
|
|
26
|
+
return new Text({
|
|
27
|
+
text: text,
|
|
28
|
+
font: options.textFont || '12px Calibri,sans-serif',
|
|
29
|
+
fill: new Fill({
|
|
30
|
+
color: options.textFillColor || '#FFF'
|
|
31
|
+
}),
|
|
32
|
+
stroke: new Stroke({
|
|
33
|
+
color: options.textStrokeColor || '#000',
|
|
34
|
+
width: options.textStrokeWidth || 3
|
|
35
|
+
}),
|
|
36
|
+
offsetY: options.textOffsetY || 20,
|
|
37
|
+
});
|
|
38
|
+
}
|
|
39
|
+
/**
|
|
40
|
+
* 创建图标样式
|
|
41
|
+
* @private
|
|
42
|
+
* @param options 选项
|
|
43
|
+
* @returns 图标样式
|
|
44
|
+
*/
|
|
45
|
+
createIconStyle(options) {
|
|
46
|
+
const iconOptions = {
|
|
47
|
+
src: options.img,
|
|
48
|
+
scale: options.scale ?? 1,
|
|
49
|
+
};
|
|
50
|
+
if (options.iconColor) {
|
|
51
|
+
iconOptions.color = options.iconColor;
|
|
52
|
+
}
|
|
53
|
+
return new Icon(iconOptions);
|
|
54
|
+
}
|
|
55
|
+
/**
|
|
56
|
+
* 创建点样式
|
|
57
|
+
* @private
|
|
58
|
+
* @param options 选项
|
|
59
|
+
* @param item 数据项
|
|
60
|
+
* @returns 样式对象
|
|
61
|
+
*/
|
|
62
|
+
createPointStyle(options, item) {
|
|
63
|
+
const style = {};
|
|
64
|
+
if (options.textKey && item) {
|
|
65
|
+
style.text = this.createTextStyle(options, item[options.textKey]);
|
|
66
|
+
}
|
|
67
|
+
if (options.img) {
|
|
68
|
+
style.image = this.createIconStyle(options);
|
|
69
|
+
}
|
|
70
|
+
return new Style(style);
|
|
71
|
+
}
|
|
72
|
+
/**
|
|
73
|
+
* 创建集群样式
|
|
74
|
+
* @private
|
|
75
|
+
* @param options 选项
|
|
76
|
+
* @param name 名称
|
|
77
|
+
* @returns 样式对象
|
|
78
|
+
*/
|
|
79
|
+
createClusterStyle(options, name) {
|
|
80
|
+
const style = {};
|
|
81
|
+
if (options.textKey) {
|
|
82
|
+
style.text = this.createTextStyle(options, name);
|
|
83
|
+
}
|
|
84
|
+
if (options.img) {
|
|
85
|
+
style.image = this.createIconStyle(options);
|
|
86
|
+
}
|
|
87
|
+
return new Style(style);
|
|
88
|
+
}
|
|
89
|
+
/**
|
|
90
|
+
* 配置图层属性
|
|
91
|
+
* @private
|
|
92
|
+
* @param layer 图层
|
|
93
|
+
* @param options 选项
|
|
94
|
+
*/
|
|
95
|
+
configureLayer(layer, options) {
|
|
96
|
+
layer.setVisible(options.visible === undefined ? true : options.visible);
|
|
97
|
+
this.map.addLayer(layer);
|
|
98
|
+
}
|
|
99
|
+
/**
|
|
100
|
+
*
|
|
101
|
+
* @param pointData
|
|
102
|
+
* @param type
|
|
103
|
+
* @param options {
|
|
104
|
+
* textKey: String 数据中的文本的key
|
|
105
|
+
* img: String 图标
|
|
106
|
+
* }
|
|
107
|
+
*/
|
|
108
|
+
addPoint(pointData, options) {
|
|
109
|
+
if (!ValidationUtils.validatePointData(pointData)) {
|
|
110
|
+
return null;
|
|
111
|
+
}
|
|
112
|
+
const pointFeatureList = [];
|
|
113
|
+
pointData.forEach((item) => {
|
|
114
|
+
if (!ValidationUtils.validateCoordinates(item)) {
|
|
115
|
+
return;
|
|
116
|
+
}
|
|
117
|
+
const pointFeature = new Feature({
|
|
118
|
+
rawData: item,
|
|
119
|
+
type: options.layerName,
|
|
120
|
+
geometry: new olPoint([item.lgtd, item.lttd])
|
|
121
|
+
});
|
|
122
|
+
pointFeature.setStyle(this.createPointStyle(options, item));
|
|
123
|
+
pointFeatureList.push(pointFeature);
|
|
124
|
+
});
|
|
125
|
+
const PointVectorLayer = new VectorLayer({
|
|
126
|
+
layerName: options.layerName,
|
|
127
|
+
source: new VectorSource({
|
|
128
|
+
features: pointFeatureList
|
|
129
|
+
}),
|
|
130
|
+
zIndex: options.zIndex || 21,
|
|
131
|
+
});
|
|
132
|
+
this.configureLayer(PointVectorLayer, options);
|
|
133
|
+
return PointVectorLayer;
|
|
134
|
+
}
|
|
135
|
+
addClusterPoint(pointData, options) {
|
|
136
|
+
if (!ValidationUtils.validatePointData(pointData)) {
|
|
137
|
+
return null;
|
|
138
|
+
}
|
|
139
|
+
const pointFeatureList = [];
|
|
140
|
+
pointData.forEach(item => {
|
|
141
|
+
if (!ValidationUtils.validateCoordinates(item)) {
|
|
142
|
+
return;
|
|
143
|
+
}
|
|
144
|
+
const pointFeature = new Feature({
|
|
145
|
+
geometry: new olPoint([item.lgtd, item.lttd]),
|
|
146
|
+
name: options.textKey ? item[options.textKey] : '',
|
|
147
|
+
});
|
|
148
|
+
pointFeatureList.push(pointFeature);
|
|
149
|
+
});
|
|
150
|
+
const source = new VectorSource({
|
|
151
|
+
features: pointFeatureList,
|
|
152
|
+
});
|
|
153
|
+
const clusterSource = new Cluster({
|
|
154
|
+
distance: options.distance || 40, // The distance for clustering in pixels
|
|
155
|
+
minDistance: options.minDistance || 0,
|
|
156
|
+
source: source,
|
|
157
|
+
});
|
|
158
|
+
const clusterLayer = new VectorLayer({
|
|
159
|
+
layerName: options.layerName,
|
|
160
|
+
source: clusterSource,
|
|
161
|
+
style: (feature) => {
|
|
162
|
+
const name = feature.get('features')[0].get(options.textKey);
|
|
163
|
+
return this.createClusterStyle(options, name);
|
|
164
|
+
},
|
|
165
|
+
zIndex: options.zIndex || 21,
|
|
166
|
+
});
|
|
167
|
+
this.configureLayer(clusterLayer, options);
|
|
168
|
+
return clusterLayer;
|
|
169
|
+
}
|
|
170
|
+
// 在流域中心添加闪烁点位
|
|
171
|
+
addTwinkleLayerFromPolygon(twinkleList, className, key, json) {
|
|
172
|
+
new MapTools(this.map).removeLayer('twinklePoint');
|
|
173
|
+
// 计算多边形的中心点坐标
|
|
174
|
+
const calculatePolygonCenter = (polygonCoordinates) => {
|
|
175
|
+
const polygon = turf.polygon(polygonCoordinates[0]);
|
|
176
|
+
const centroid = turf.centroid(polygon);
|
|
177
|
+
return centroid.geometry.coordinates;
|
|
178
|
+
};
|
|
179
|
+
const features = json.features;
|
|
180
|
+
const vectorSource = new VectorSource({
|
|
181
|
+
format: new GeoJSON(),
|
|
182
|
+
});
|
|
183
|
+
twinkleList.forEach(item => {
|
|
184
|
+
const feature = features.find((ele) => {
|
|
185
|
+
return ele.properties.BASIN === item.idx;
|
|
186
|
+
});
|
|
187
|
+
if (!feature)
|
|
188
|
+
return;
|
|
189
|
+
feature.properties.level = item.lev;
|
|
190
|
+
const geojson = new GeoJSON();
|
|
191
|
+
const olFeature = geojson.readFeature(feature);
|
|
192
|
+
if (Array.isArray(olFeature)) {
|
|
193
|
+
vectorSource.addFeatures(olFeature);
|
|
194
|
+
}
|
|
195
|
+
else {
|
|
196
|
+
vectorSource.addFeature(olFeature);
|
|
197
|
+
}
|
|
198
|
+
if (feature) {
|
|
199
|
+
const polygonCenter = calculatePolygonCenter(feature.geometry.coordinates);
|
|
200
|
+
item.lgtd = polygonCenter[0];
|
|
201
|
+
item.lttd = polygonCenter[1];
|
|
202
|
+
}
|
|
203
|
+
});
|
|
204
|
+
const basinLayer = new VectorLayer({
|
|
205
|
+
name: 'twinklePoint',
|
|
206
|
+
layerName: 'twinklePoint',
|
|
207
|
+
source: vectorSource,
|
|
208
|
+
style: function (feature) {
|
|
209
|
+
return new Style({
|
|
210
|
+
stroke: new Stroke({
|
|
211
|
+
color: 'rgb(139,188,245)',
|
|
212
|
+
width: 3
|
|
213
|
+
}),
|
|
214
|
+
fill: new Fill({ color: 'rgba(255, 255, 255, 0)' }),
|
|
215
|
+
text: new Text({
|
|
216
|
+
text: feature.values_['BASIN'] || "",
|
|
217
|
+
font: '14px Calibri,sans-serif',
|
|
218
|
+
fill: new Fill({ color: '#FFF' }),
|
|
219
|
+
stroke: new Stroke({
|
|
220
|
+
color: '#409EFF', width: 2
|
|
221
|
+
}),
|
|
222
|
+
})
|
|
223
|
+
});
|
|
224
|
+
},
|
|
225
|
+
zIndex: 21
|
|
226
|
+
});
|
|
227
|
+
this.map.addLayer(basinLayer);
|
|
228
|
+
this.addTwinkleLayer(twinkleList, className, key, (twinkleItem) => {
|
|
229
|
+
});
|
|
230
|
+
}
|
|
231
|
+
/**
|
|
232
|
+
* 添加闪烁点
|
|
233
|
+
* @param twinkleList 闪烁点数据 - 二维数组 [[],[]]
|
|
234
|
+
* @param className 闪烁点样式,需要和id保持一致
|
|
235
|
+
* @param key 闪烁点索引
|
|
236
|
+
* @param callback
|
|
237
|
+
*/
|
|
238
|
+
addTwinkleLayer(twinkleList, className = 'marker_warning', key, callback) {
|
|
239
|
+
// 查找class是warn-points的dom,并删除
|
|
240
|
+
const arr = document.getElementsByClassName(className);
|
|
241
|
+
const l = arr.length;
|
|
242
|
+
for (let i = l - 1; i >= 0; i--) {
|
|
243
|
+
if (arr[i] !== null) {
|
|
244
|
+
arr[i].parentNode?.removeChild(arr[i]);
|
|
245
|
+
}
|
|
246
|
+
}
|
|
247
|
+
const el = document.getElementById(className);
|
|
248
|
+
for (let i = 0; i < twinkleList.length; i++) {
|
|
249
|
+
const twinkleItem = twinkleList[i];
|
|
250
|
+
// 定义图标Dom
|
|
251
|
+
const el2 = document.createElement('div');
|
|
252
|
+
el2.id = className + i;
|
|
253
|
+
el2.className = className + twinkleItem[key];
|
|
254
|
+
el2.onclick = () => {
|
|
255
|
+
callback && callback(twinkleItem);
|
|
256
|
+
// bus.emit('twinkleClick', twinkleItem)
|
|
257
|
+
};
|
|
258
|
+
// 插入图标
|
|
259
|
+
if (el)
|
|
260
|
+
el.insertAdjacentElement('afterend', el2);
|
|
261
|
+
// 创建一个覆盖物
|
|
262
|
+
const anchor = new Overlay({
|
|
263
|
+
element: document.getElementById(className + i) || undefined,
|
|
264
|
+
positioning: 'center-center',
|
|
265
|
+
className: className
|
|
266
|
+
});
|
|
267
|
+
// 关键的一点,需要设置附加到地图上的位置
|
|
268
|
+
anchor.setPosition([twinkleItem.lgtd, twinkleItem.lttd]);
|
|
269
|
+
// 然后添加到map上
|
|
270
|
+
this.map.addOverlay(anchor);
|
|
271
|
+
}
|
|
272
|
+
}
|
|
273
|
+
/**
|
|
274
|
+
* 地图定位
|
|
275
|
+
* @param lgtd 经度
|
|
276
|
+
* @param lttd 纬度
|
|
277
|
+
* @param zoom 缩放级别
|
|
278
|
+
* @param duration 动画时长
|
|
279
|
+
*/
|
|
280
|
+
locationAction(lgtd, lttd, zoom = 20, duration = 3000) {
|
|
281
|
+
if (!ValidationUtils.validateLngLat(lgtd, lttd)) {
|
|
282
|
+
return false;
|
|
283
|
+
}
|
|
284
|
+
try {
|
|
285
|
+
this.map.getView().animate({ center: [lgtd, lttd], zoom, duration });
|
|
286
|
+
return true;
|
|
287
|
+
}
|
|
288
|
+
catch (error) {
|
|
289
|
+
console.error('[地图定位]', '定位失败:', error);
|
|
290
|
+
return false;
|
|
291
|
+
}
|
|
292
|
+
}
|
|
293
|
+
/**
|
|
294
|
+
* 设置dom元素为点位
|
|
295
|
+
*/
|
|
296
|
+
addDomPoint(id, lgtd, lttd) {
|
|
297
|
+
if (!id) {
|
|
298
|
+
console.error('Element ID is required');
|
|
299
|
+
return false;
|
|
300
|
+
}
|
|
301
|
+
if (!ValidationUtils.validateLngLat(lgtd, lttd)) {
|
|
302
|
+
return false;
|
|
303
|
+
}
|
|
304
|
+
const el = document.getElementById(id);
|
|
305
|
+
if (!el) {
|
|
306
|
+
console.error(`Element with id '${id}' not found`);
|
|
307
|
+
return false;
|
|
308
|
+
}
|
|
309
|
+
try {
|
|
310
|
+
const anchor = new Overlay({
|
|
311
|
+
id: id,
|
|
312
|
+
element: el,
|
|
313
|
+
positioning: 'center-center',
|
|
314
|
+
stopEvent: false
|
|
315
|
+
});
|
|
316
|
+
anchor.setPosition([lgtd, lttd]);
|
|
317
|
+
this.map.addOverlay(anchor);
|
|
318
|
+
return true;
|
|
319
|
+
}
|
|
320
|
+
catch (error) {
|
|
321
|
+
console.error('Failed to set DOM point:', error);
|
|
322
|
+
return false;
|
|
323
|
+
}
|
|
324
|
+
}
|
|
325
|
+
/**
|
|
326
|
+
* 添加vue组件为点位
|
|
327
|
+
* @param pointDataList 点位信息列表
|
|
328
|
+
* @param template vue组件模板
|
|
329
|
+
* @param Vue Vue实例
|
|
330
|
+
* @returns 返回控制对象,包含显示、隐藏、移除方法
|
|
331
|
+
* @throws 当参数无效时抛出错误
|
|
332
|
+
*/
|
|
333
|
+
addVueTemplatePoint(pointDataList, template, options) {
|
|
334
|
+
if (!pointDataList || !Array.isArray(pointDataList) || pointDataList.length === 0) {
|
|
335
|
+
throw new Error('Valid point info list is required');
|
|
336
|
+
}
|
|
337
|
+
if (!template) {
|
|
338
|
+
throw new Error('Vue template is required');
|
|
339
|
+
}
|
|
340
|
+
try {
|
|
341
|
+
const vueTemplatePoint = new VueTemplatePoint(this.map);
|
|
342
|
+
return vueTemplatePoint.addVueTemplatePoint(pointDataList, template, options);
|
|
343
|
+
}
|
|
344
|
+
catch (error) {
|
|
345
|
+
throw new Error(`Failed to create Vue template points: ${error}`);
|
|
346
|
+
}
|
|
347
|
+
}
|
|
348
|
+
}
|