@supermapgis/iclient-ol 11.2.0

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.
Files changed (91) hide show
  1. package/README.md +56 -0
  2. package/control/ChangeTileVersion.js +438 -0
  3. package/control/Logo.js +97 -0
  4. package/control/ScaleLine.js +164 -0
  5. package/control/index.js +6 -0
  6. package/core/MapExtend.js +49 -0
  7. package/core/StyleUtils.js +1253 -0
  8. package/core/Util.js +500 -0
  9. package/core/index.js +6 -0
  10. package/css/ChangeTileVersion.css +347 -0
  11. package/css/index.js +5 -0
  12. package/dist/iclient-openlayers-es6.js +124963 -0
  13. package/dist/iclient-openlayers-es6.min.js +8 -0
  14. package/dist/iclient-openlayers.css +668 -0
  15. package/dist/iclient-openlayers.js +142946 -0
  16. package/dist/iclient-openlayers.min.css +8 -0
  17. package/dist/iclient-openlayers.min.js +8 -0
  18. package/index.js +9 -0
  19. package/mapping/BaiduMap.js +121 -0
  20. package/mapping/ImageSuperMapRest.js +252 -0
  21. package/mapping/ImageTileSuperMapRest.js +99 -0
  22. package/mapping/InitMap.js +150 -0
  23. package/mapping/SuperMapCloud.js +56 -0
  24. package/mapping/Tianditu.js +152 -0
  25. package/mapping/TileSuperMapRest.js +374 -0
  26. package/mapping/WebMap.js +5485 -0
  27. package/mapping/index.js +11 -0
  28. package/mapping/webmap/Util.js +176 -0
  29. package/mapping/webmap/config/MunicipalCenter.json +1 -0
  30. package/mapping/webmap/config/ProvinceCenter.json +1 -0
  31. package/mapping/webmap/config/SampleDataInfo.json +55 -0
  32. package/namespace.js +150 -0
  33. package/overlay/DataFlow.js +114 -0
  34. package/overlay/FGB.js +100 -0
  35. package/overlay/Graph.js +439 -0
  36. package/overlay/GraphMap.js +140 -0
  37. package/overlay/Graphic.js +588 -0
  38. package/overlay/HeatMap.js +450 -0
  39. package/overlay/Label.js +966 -0
  40. package/overlay/Mapv.js +149 -0
  41. package/overlay/Range.js +129 -0
  42. package/overlay/RankSymbol.js +94 -0
  43. package/overlay/Turf.js +299 -0
  44. package/overlay/Unique.js +124 -0
  45. package/overlay/VectorTileSuperMapRest.js +501 -0
  46. package/overlay/graphic/CanvasRenderer.js +177 -0
  47. package/overlay/graphic/CloverShape.js +133 -0
  48. package/overlay/graphic/Graphic.js +174 -0
  49. package/overlay/graphic/HitCloverShape.js +64 -0
  50. package/overlay/graphic/WebGLRenderer.js +356 -0
  51. package/overlay/graphic/index.js +9 -0
  52. package/overlay/index.js +21 -0
  53. package/overlay/mapv/MapvCanvasLayer.js +104 -0
  54. package/overlay/mapv/MapvLayer.js +413 -0
  55. package/overlay/mapv/index.js +5 -0
  56. package/overlay/theme/GeoFeature.js +275 -0
  57. package/overlay/theme/Theme.js +587 -0
  58. package/overlay/theme/ThemeFeature.js +46 -0
  59. package/overlay/theme/index.js +6 -0
  60. package/overlay/vectortile/DeafultCanvasStyle.js +125 -0
  61. package/overlay/vectortile/MapboxStyles.js +377 -0
  62. package/overlay/vectortile/StyleMap.js +252 -0
  63. package/overlay/vectortile/VectorTileStyles.js +554 -0
  64. package/overlay/vectortile/index.js +7 -0
  65. package/overlay/vectortile/olExtends.js +382 -0
  66. package/package.json +30 -0
  67. package/services/AddressMatchService.js +60 -0
  68. package/services/ChartService.js +97 -0
  69. package/services/DataFlowService.js +119 -0
  70. package/services/DatasetService.js +104 -0
  71. package/services/DatasourceService.js +76 -0
  72. package/services/FeatureService.js +260 -0
  73. package/services/FieldService.js +53 -0
  74. package/services/GeoprocessingService.js +157 -0
  75. package/services/GridCellInfosService.js +53 -0
  76. package/services/ImageCollectionService.js +93 -0
  77. package/services/ImageService.js +70 -0
  78. package/services/KnowledgeGraphService.js +96 -0
  79. package/services/LayerInfoService.js +85 -0
  80. package/services/MapService.js +85 -0
  81. package/services/MeasureService.js +77 -0
  82. package/services/NetworkAnalyst3DService.js +93 -0
  83. package/services/NetworkAnalystService.js +268 -0
  84. package/services/ProcessingService.js +507 -0
  85. package/services/QueryService.js +116 -0
  86. package/services/ServiceBase.js +26 -0
  87. package/services/SpatialAnalystService.js +466 -0
  88. package/services/ThemeService.js +50 -0
  89. package/services/TrafficTransferAnalystService.js +93 -0
  90. package/services/WebPrintingJobService.js +112 -0
  91. package/services/index.js +27 -0
@@ -0,0 +1,966 @@
1
+ /* Copyright© 2000 - 2024 SuperMap Software Co.Ltd. All rights reserved.
2
+ * This program are made available under the terms of the Apache License, Version 2.0
3
+ * which accompanies this distribution and is available at http://www.apache.org/licenses/LICENSE-2.0.html.*/
4
+ import { Util as CommonUtil} from '@supermapgis/iclient-common/commontypes/Util';
5
+ import { GeoText } from '@supermapgis/iclient-common/commontypes/geometry/GeoText';
6
+ import { Bounds } from '@supermapgis/iclient-common/commontypes/Bounds';
7
+ import { ShapeFactory } from '@supermapgis/iclient-common/overlay/feature/ShapeFactory';
8
+ import { ThemeVector } from '@supermapgis/iclient-common/overlay/ThemeVector';
9
+ import { Vector as FeatureVector } from '@supermapgis/iclient-common/commontypes/Vector';
10
+ import {
11
+ GeoFeature
12
+ } from './theme/GeoFeature';
13
+ import Point from 'ol/geom/Point';
14
+
15
+ /**
16
+ * @class Label
17
+ * @browsernamespace ol.source
18
+ * @category Visualization Theme
19
+ * @classdesc 标签专题图图层源。标签专题图是用文本形式在图层上直接显示属性表中的数据,实质上是对图层的标注。
20
+ * 不仅帮助用户更好地区分地物要素,同时也显示了要素的某些重要属性,如行政区划、河流、机关、旅游景点的名称、等高线的高程等。
21
+ * 在 SuperMap 中,通过制作标签专题图,用户可以轻松实现地图标注。
22
+ * @modulecategory Overlay
23
+ * @param {string} name - 名称。
24
+ * @param {Object} opt_options - 参数。
25
+ * @param {ol.Map} opt_options.map - 当前 OpenLayers 地图对象。
26
+ * @param {string} [opt_options.id] - 专题图层 ID。默认使用 CommonUtil.createUniqueID("themeLayer_") 创建专题图层 ID。
27
+ * @param {number} [opt_options.opacity=1] - 图层不透明度。
28
+ * @param {string|Object} [opt_options.attributions] - 版权描述信息。
29
+ * @param {string} [opt_options.logo] - Logo(OpenLayers 5.0.0 及更高版本不再支持此参数)。
30
+ * @param {ol.proj.Projection} [opt_options.projection] - 投影信息。
31
+ * @param {number} [opt_options.ratio=1.5] - 视图比,1 表示画布是地图视口的大小,2 表示地图视口的宽度和高度的两倍,依此类推。必须是 1 或更高。
32
+ * @param {Array.<number>} [opt_options.resolutions] - 分辨率数组。
33
+ * @param {ol.source.State} [opt_options.state] - 资源状态。
34
+ * @param {string} [opt_options.themeField] - 指定创建专题图字段。
35
+ * @param {Object} [opt_options.style] - 专题图样式。
36
+ * @param {Object} [opt_options.styleGroups] - 各专题类型样式组。
37
+ * @param {boolean} [opt_options.isHoverAble = false] - 是否开启 hover 事件。
38
+ * @param {Object} [opt_options.highlightStyle] - 开启 hover 事件后,触发的样式风格。
39
+ * @extends {GeoFeature}
40
+ * @usage
41
+ */
42
+ export class Label extends GeoFeature {
43
+
44
+ constructor(name, opt_options) {
45
+ super(name, opt_options);
46
+ this.isOverLay = opt_options.isOverLay != null ? opt_options.isOverLay : true;
47
+ this.isAvoid = opt_options.isAvoid != null ? opt_options.isAvoid : true;
48
+
49
+ this.style = opt_options.style;
50
+ this.themeField = opt_options.themeField;
51
+ this.styleGroups = opt_options.styleGroups;
52
+
53
+ this.defaultStyle = {
54
+ //默认文本样式
55
+ fontColor: "#000000",
56
+ fontOpacity: 1,
57
+ fontSize: "12px",
58
+ fontStyle: "normal",
59
+ fontWeight: "normal",
60
+ labelAlign: "cm",
61
+ labelXOffset: 0,
62
+ labelYOffset: 0,
63
+ labelRotation: 0,
64
+
65
+ //默认背景框样式
66
+ fill: false,
67
+ fillColor: "#ee9900",
68
+ fillOpacity: 0.4,
69
+ stroke: false,
70
+ strokeColor: "#ee9900",
71
+ strokeOpacity: 1,
72
+ strokeWidth: 1,
73
+ strokeLinecap: "round",
74
+ strokeDashstyle: "solid",
75
+
76
+ //对用户隐藏但必须保持此值的属性
77
+ //cursor: "pointer",
78
+ labelSelect: true,
79
+
80
+ //用 _isGeoTextStrategyStyle 标记此style,携带此类style的要素特指GeoText策略中的标签要素
81
+ _isGeoTextStrategyStyle: true
82
+ };
83
+
84
+ //获取标签像素 bounds 的方式。0 - 表示通过文本类容和文本风格计算获取像素范围,现在支持中文、英文; 1 - 表示通过绘制的文本标签获取像素范围,支持各个语种的文字范围获取,但性能消耗较大(尤其是采用 SVG 渲染)。默认值为 0。
85
+ this.getPxBoundsMode = 0;
86
+
87
+ this.labelFeatures = [];
88
+ }
89
+
90
+ /**
91
+ * @function Label.prototype.destroy
92
+ * @description 释放资源,将引用资源的属性置空。
93
+ */
94
+ destroy() {
95
+ this.style = null;
96
+ this.themeField = null;
97
+ this.styleGroups = null;
98
+ super.destroy();
99
+ }
100
+
101
+ /**
102
+ * @private
103
+ * @function Label.prototype.createThematicFeature
104
+ * @description 创建专题要素。
105
+ * @param {FeatureVector} feature - 矢量要素。
106
+ * @returns {FeatureThemeVector} 专题图矢量要素。
107
+ */
108
+ createThematicFeature(feature) {
109
+ //赋 style
110
+ var style = this.getStyleByData(feature);
111
+ //创建专题要素时的可选参数
112
+ var options = {};
113
+ options.nodesClipPixel = this.nodesClipPixel;
114
+ options.isHoverAble = this.isHoverAble;
115
+ options.isMultiHover = this.isMultiHover;
116
+ options.isClickAble = this.isClickAble;
117
+ options.highlightStyle = ShapeFactory.transformStyle(this.highlightStyle);
118
+ //将数据转为专题要素(Vector)
119
+ var thematicFeature = new ThemeVector(feature, this, ShapeFactory.transformStyle(style), options);
120
+ //直接添加图形到渲染器
121
+ for (var m = 0; m < thematicFeature.shapes.length; m++) {
122
+ this.renderer.addShape(thematicFeature.shapes[m]);
123
+ }
124
+ return thematicFeature;
125
+ }
126
+
127
+
128
+ /**
129
+ * @function Label.prototype.redrawThematicFeatures
130
+ * @description 重绘所有专题要素。
131
+ * 此方法包含绘制专题要素的所有步骤,包含用户数据到专题要素的转换,抽稀,缓存等步骤。
132
+ * 地图漫游时调用此方法进行图层刷新。
133
+ * @param {Array.<number>} bounds - 重绘范围。
134
+ */
135
+ redrawThematicFeatures(bounds) {
136
+ if (this.features.length > 0 && this.labelFeatures.length === 0) {
137
+ var feats = this.setLabelsStyle(this.features);
138
+ for (var i = 0, len = feats.length; i < len; i++) {
139
+ this.labelFeatures.push(feats[i]);
140
+ }
141
+ }
142
+ this.features = this.getDrawnLabels(this.labelFeatures);
143
+ super.redrawThematicFeatures.call(this, bounds);
144
+ }
145
+ /**
146
+ * @function Label.prototype.removeFeatures
147
+ * @description 从专题图中删除要素。这个函数删除所有传递进来的矢量要素。
148
+ * @param {(Array.<FeatureVector>|FeatureVector|Function)} features - 待删除的要素对象或用于过滤的回调函数。
149
+ */
150
+ removeFeatures(features) { // eslint-disable-line no-unused-vars
151
+ this.labelFeatures = [];
152
+ super.removeFeatures.call(this, features);
153
+ }
154
+
155
+ /**
156
+ * @function Label.prototype.removeAllFeatures
157
+ * @description 清除当前图层所有的矢量要素。
158
+ */
159
+ removeAllFeatures() {
160
+ this.labelFeatures = [];
161
+ super.removeAllFeatures.call(this, arguments);
162
+ }
163
+ /**
164
+ * @function Label.prototype.getDrawnLabels
165
+ * @description 获取经(压盖)处理后将要绘制在图层上的标签要素。
166
+ * @param {Array.<FeatureVector>} labelFeatures - 所有标签要素的数组。
167
+ * @returns {Array.<FeatureVector>} 最终要绘制的标签要素数组。
168
+ */
169
+ getDrawnLabels(labelFeatures) {
170
+ var feas = [], //最终要绘制的标签要素集
171
+ fea, //最终要绘制的标签要素
172
+ fi, //临时标签要素,用户的第i个标签
173
+ labelsB = [], //不产生压盖的标签要素范围集
174
+ styTmp, //用于临时存储要素style的变量
175
+ feaSty, //标签要素最终的style
176
+ // styleTemp用于屏蔽文本style中带有偏移性质style属性,偏移已经在计算bounds的过程中参与了运算,
177
+ // 所以在最终按照bounds来绘制标签时,需屏蔽style中带有偏移性质属性,否则文本的偏移量将扩大一倍。
178
+ styleTemp = {
179
+ labelAlign: "cm",
180
+ labelXOffset: 0,
181
+ labelYOffset: 0
182
+ };
183
+
184
+ var map = this.map;
185
+ var mapSize = map.getSize();
186
+ mapSize = {
187
+ x: mapSize[0],
188
+ y: mapSize[1]
189
+ };
190
+ var zoom = map.getView().getZoom();
191
+ //对用户的每个标签要素进行处理与判断
192
+ for (var i = 0, len = labelFeatures.length; i < len; i++) {
193
+ fi = labelFeatures[i];
194
+ //检查fi的style在避让中是否被改变,如果改变,重新设置要素的style
195
+ if (fi.isStyleChange) {
196
+ fi = this.setStyle(fi);
197
+ }
198
+
199
+ //标签最终的中心点像素位置 (偏移后)
200
+ var loc = this.getLabelPxLocation(fi);
201
+
202
+ //过滤掉地图范围外的标签 (偏移后)
203
+ if ((loc.x >= 0 && loc.x <= mapSize.x) && (loc.y >= 0 && loc.y <= mapSize.y)) {
204
+ //根据当前地图缩放级别过滤标签
205
+ if (fi.style.minZoomLevel > -1) {
206
+ if (zoom <= fi.style.minZoomLevel) {
207
+ continue;
208
+ }
209
+ }
210
+ if (fi.style.maxZoomLevel > -1) {
211
+ if (zoom > fi.style.maxZoomLevel) {
212
+ continue;
213
+ }
214
+ }
215
+
216
+ //计算标签bounds
217
+ var boundsQuad = null;
218
+ if (fi.isStyleChange) {
219
+ fi.isStyleChange = null;
220
+ boundsQuad = this.calculateLabelBounds(fi, loc);
221
+ } else {
222
+ if (fi.geometry.bsInfo.w && fi.geometry.bsInfo.h) {
223
+ //使用calculateLabelBounds2可以提高bounds的计算效率,尤其是在getPxBoundsMode = 1时
224
+ boundsQuad = this.calculateLabelBounds2(fi, loc);
225
+ } else {
226
+ boundsQuad = this.calculateLabelBounds(fi, loc);
227
+ }
228
+ }
229
+
230
+ //避让处理 -start
231
+ var mapViewBounds = new Bounds(0, mapSize.y, mapSize.x, 0), //地图像素范围
232
+ quadlen = boundsQuad.length;
233
+
234
+ if (this.isAvoid) {
235
+ var avoidInfo = this.getAvoidInfo(mapViewBounds, boundsQuad); //避让信息
236
+
237
+ if (avoidInfo) {
238
+ //横向(x方向)上的避让
239
+ if (avoidInfo.aspectW === "left") {
240
+ fi.style.labelXOffset += avoidInfo.offsetX;
241
+
242
+ for (let j = 0; j < quadlen; j++) {
243
+ boundsQuad[j].x += avoidInfo.offsetX;
244
+ }
245
+ } else if (avoidInfo.aspectW === "right") {
246
+ fi.style.labelXOffset += (-avoidInfo.offsetX);
247
+
248
+ for (let j = 0; j < quadlen; j++) {
249
+ boundsQuad[j].x += (-avoidInfo.offsetX);
250
+ }
251
+ }
252
+
253
+ //纵向(y方向)上的避让
254
+ if (avoidInfo.aspectH === "top") {
255
+ fi.style.labelYOffset += avoidInfo.offsetY;
256
+
257
+ for (let j = 0; j < quadlen; j++) {
258
+ boundsQuad[j].y += avoidInfo.offsetY;
259
+ }
260
+ } else if (avoidInfo.aspectH === "bottom") {
261
+ fi.style.labelYOffset += (-avoidInfo.offsetY);
262
+
263
+ for (let j = 0; j < quadlen; j++) {
264
+ boundsQuad[j].y += (-avoidInfo.offsetY);
265
+ }
266
+ }
267
+
268
+ //如果style发生变化,记录下来
269
+ fi.isStyleChange = true;
270
+ }
271
+ }
272
+ //避让处理 -end
273
+
274
+ //压盖处理 -start
275
+ if (this.isOverLay) {
276
+ //是否压盖
277
+ var isOL = false;
278
+ if (i != 0) {
279
+ for (let j = 0; j < labelsB.length; j++) {
280
+ //压盖判断
281
+ if (this.isQuadrilateralOverLap(boundsQuad, labelsB[j])) {
282
+ isOL = true;
283
+ break;
284
+ }
285
+ }
286
+ }
287
+
288
+ if (isOL) {
289
+ continue;
290
+ } else {
291
+ labelsB.push(boundsQuad);
292
+ }
293
+ }
294
+ //压盖处理 -end
295
+
296
+ //将标签像素范围转为地理范围
297
+ var geoBs = [];
298
+ for (let j = 0; j < quadlen - 1; j++) {
299
+ geoBs.push(map.getCoordinateFromPixel([boundsQuad[j].x, boundsQuad[j].y]));
300
+ }
301
+
302
+ //屏蔽有偏移性质的style属性,偏移量在算bounds时已经加入计算
303
+ var bounds = new Bounds(geoBs[3][0], geoBs[3][1], geoBs[1][0], [geoBs[1][1]]);
304
+ var center = bounds.getCenterLonLat();
305
+ var label = new GeoText(center.lon, center.lat, fi.attributes[this.themeField]);
306
+ label.calculateBounds();
307
+ styTmp = CommonUtil.cloneObject(fi.style);
308
+ feaSty = CommonUtil.cloneObject(CommonUtil.copyAttributes(styTmp, styleTemp));
309
+ fea = new FeatureVector(label, fi.attributes, feaSty);
310
+ //赋予id
311
+ fea.id = fi.id;
312
+ fea.fid = fi.fid;
313
+ feas.push(fea);
314
+ }
315
+ }
316
+
317
+ //返回最终要绘制的标签要素
318
+ return feas;
319
+ }
320
+
321
+ /**
322
+ * @function Label.prototype.getStyleByData
323
+ * @description 根据用户数据(feature)设置专题要素的风格。
324
+ * @param {FeatureVector} feat - 矢量要素对象。
325
+ * @returns {Array.<ThemeStyle>} 专题要素的风格。
326
+ */
327
+ getStyleByData(feat) {
328
+ var feature = feat;
329
+ feature.style = CommonUtil.copyAttributes(feature.style, this.defaultStyle);
330
+ //将style赋给标签
331
+ if (this.style && this.style.fontSize && parseFloat(this.style.fontSize) < 12) {
332
+ this.style.fontSize = "12px";
333
+ }
334
+ feature.style = CommonUtil.copyAttributes(feature.style, this.style);
335
+
336
+ if (this.themeField && this.styleGroups && feature.attributes) {
337
+ var Sf = this.themeField;
338
+ var attributes = feature.attributes;
339
+ var groups = this.styleGroups;
340
+ var isSfInAttrs = false; //指定的 groupField 是否是geotext的属性字段之一
341
+ var attr = null; //属性值
342
+
343
+ for (var property in attributes) {
344
+ if (Sf === property) {
345
+ isSfInAttrs = true;
346
+ attr = attributes[property];
347
+ break;
348
+ }
349
+ }
350
+
351
+ //判断属性值是否属于styleGroups的某一个范围,以便对标签分组
352
+ if (isSfInAttrs) {
353
+ for (var i = 0, len = groups.length; i < len; i++) {
354
+ if ((attr >= groups[i].start) && (attr < groups[i].end)) {
355
+ var sty1 = groups[i].style;
356
+ if (sty1 && sty1.fontSize && parseFloat(sty1.fontSize) < 12) {
357
+ sty1.fontSize = "12px";
358
+ }
359
+ feature.style = CommonUtil.copyAttributes(feature.style, sty1);
360
+ }
361
+ }
362
+ }
363
+ feature.style.label = feature.attributes[this.themeField]
364
+ }
365
+
366
+
367
+ return feature.style;
368
+ }
369
+
370
+ /**
371
+ * @function Label.prototype.setLabelsStyle
372
+ * @description 设置标签要素的风格。
373
+ * @param {Array.<FeatureVector>} labelFeatures - 需要设置风格的标签要素数组。
374
+ * @returns {Array.<FeatureVector>} 赋予风格后的标签要素数组。
375
+ */
376
+ setLabelsStyle(labelFeatures) {
377
+ var fea, labelFeas = [];
378
+ for (var i = 0, len = labelFeatures.length; i < len; i++) {
379
+ var feature = labelFeatures[i];
380
+ if (feature.geometry.CLASS_NAME === "SuperMap.Geometry.GeoText") {
381
+ //设置标签的Style
382
+ if (feature.geometry.bsInfo.w || feature.geometry.bsInfo.h) {
383
+ feature.geometry.bsInfo.w = null;
384
+ feature.geometry.bsInfo.h = null;
385
+ feature.geometry.labelWTmp = null;
386
+ }
387
+ fea = this.setStyle(feature);
388
+ //为标签要素指定图层
389
+ fea.layer = this.layer;
390
+ labelFeas.push(fea);
391
+ } else {
392
+ return labelFeatures;
393
+ }
394
+ }
395
+ return labelFeas;
396
+ }
397
+
398
+ /**
399
+ * @function Label.prototype.setStyle
400
+ * @description 设置标签要素的风格。
401
+ * @param {FeatureVector} feat - 需要赋予风格的要素。
402
+ */
403
+ setStyle(feat) {
404
+ var feature = feat;
405
+ feature.style = CommonUtil.copyAttributes(feature.style, this.defaultStyle);
406
+ //将style赋给标签
407
+ if (this.style && this.style.fontSize && parseFloat(this.style.fontSize) < 12) {
408
+ this.style.fontSize = "12px";
409
+ }
410
+ feature.style = CommonUtil.copyAttributes(feature.style, this.style);
411
+
412
+ if (this.groupField && this.styleGroups && feature.attributes) {
413
+ var Sf = this.groupField;
414
+ var attributes = feature.attributes;
415
+ var groups = this.styleGroups;
416
+ var isSfInAttrs = false; //指定的 groupField 是否是geotext的属性字段之一
417
+ var attr = null; //属性值
418
+
419
+ for (var property in attributes) {
420
+ if (Sf === property) {
421
+ isSfInAttrs = true;
422
+ attr = attributes[property];
423
+ break;
424
+ }
425
+ }
426
+
427
+ //判断属性值是否属于styleGroups的某一个范围,以便对标签分组
428
+ if (isSfInAttrs) {
429
+ for (var i = 0, len = groups.length; i < len; i++) {
430
+ if ((attr >= groups[i].start) && (attr < groups[i].end)) {
431
+ var sty1 = groups[i].style;
432
+ if (sty1 && sty1.fontSize && parseFloat(sty1.fontSize) < 12) {
433
+ sty1.fontSize = "12px";
434
+ }
435
+ feature.style = CommonUtil.copyAttributes(feature.style, sty1);
436
+ }
437
+ }
438
+ }
439
+ }
440
+
441
+ //将文本内容赋到标签要素的style上
442
+ feature.style.label = feature.geometry.text;
443
+
444
+ return feature;
445
+ }
446
+
447
+ /**
448
+ * @function Label.prototype.getLabelPxLocation
449
+ * @description 获取标签要素的像素坐标。
450
+ * @param {FeatureVector} feature - 标签要素。
451
+ * @returns {Object} 标签位置,例如:{"x":1,"y":1}。
452
+ */
453
+ getLabelPxLocation(feature) {
454
+ var geoText = feature.geometry;
455
+ var styleTmp = feature.style;
456
+
457
+ //将标签的地理位置转为像素位置
458
+ var locationTmp = geoText.getCentroid();
459
+ var locTmp = this.map.getPixelFromCoordinate([locationTmp.x, locationTmp.y]);
460
+ var loc = new Point([locTmp[0], locTmp[1]]);
461
+
462
+ //偏移处理
463
+ if (styleTmp.labelXOffset || styleTmp.labelYOffset) {
464
+ var xOffset = isNaN(styleTmp.labelXOffset) ? 0 : styleTmp.labelXOffset;
465
+ var yOffset = isNaN(styleTmp.labelYOffset) ? 0 : styleTmp.labelYOffset;
466
+ loc.translate(xOffset, -yOffset);
467
+ }
468
+ return {
469
+ x: loc.getCoordinates()[0],
470
+ y: loc.getCoordinates()[1]
471
+ };
472
+ }
473
+
474
+
475
+ /**
476
+ * @function Label.prototype.calculateLabelBounds
477
+ * @description 获得标签要素的最终范围。
478
+ * @param {FeatureVector} feature - 需要计算范围的标签要素数。
479
+ * @param {Object} loc - 标签位置,例如:{"x":1,"y":1}。
480
+ * @returns {Array.<Object>} 四边形节点数组。例如:[{"x":1,"y":1},{"x":3,"y":1},{"x":6,"y":4},{"x":2,"y":10},{"x":1,"y":1}]。
481
+ */
482
+ calculateLabelBounds(feature, loc) {
483
+ var geoText = feature.geometry;
484
+
485
+ //标签范围(未旋转前)
486
+ var labB = null;
487
+ var labelInfo = null;
488
+ //获取bounds的方式
489
+ if (this.getPxBoundsMode == 0) {
490
+ labB = geoText.getLabelPxBoundsByText(loc, feature.style);
491
+ } else if (this.getPxBoundsMode === 1) {
492
+ //canvas
493
+ labelInfo = this.getLabelInfo(feature.geometry.getCentroid(), feature.style);
494
+ labB = geoText.getLabelPxBoundsByLabel(loc, labelInfo.w, labelInfo.h, feature.style);
495
+ } else {
496
+ return null;
497
+ }
498
+
499
+ //旋转Bounds
500
+ var boundsQuad = [];
501
+ if ((feature.style.labelRotation % 180) == 0) {
502
+ boundsQuad = [{
503
+ "x": labB.left,
504
+ "y": labB.top
505
+ },
506
+ {
507
+ "x": labB.right,
508
+ "y": labB.top
509
+ },
510
+ {
511
+ "x": labB.right,
512
+ "y": labB.bottom
513
+ },
514
+ {
515
+ "x": labB.left,
516
+ "y": labB.bottom
517
+ },
518
+ {
519
+ "x": labB.left,
520
+ "y": labB.top
521
+ }
522
+ ];
523
+ } else {
524
+ boundsQuad = this.rotationBounds(labB, loc, feature.style.labelRotation);
525
+ }
526
+
527
+ //重置GeoText的bounds
528
+ geoText.bounds = new Bounds(boundsQuad[1].x, boundsQuad[3].y, boundsQuad[2].x, boundsQuad[4].y);
529
+ return boundsQuad;
530
+ }
531
+
532
+ /**
533
+ * @function Label.prototype.calculateLabelBounds2
534
+ * @description 获得标签要素的最终范围的另一种算法(通过记录下的标签宽高),提高计算范围的效率。
535
+ * @param {FeatureVector} feature - 需要计算范围的标签要素数。
536
+ * @param {Object} loc - 标签位置,例如:{"x":1,"y":1}。
537
+ * @returns {Array.<Object>} 四边形节点数组。例如:[{"x":1,"y":1},{"x":3,"y":1},{"x":6,"y":4},{"x":2,"y":10},{"x":1,"y":1}]。
538
+ */
539
+ calculateLabelBounds2(feature, loc) {
540
+ var labB, left, bottom, top, right;
541
+ var labelSize = feature.geometry.bsInfo;
542
+ var style = feature.style;
543
+ var locationPx = CommonUtil.cloneObject(loc);
544
+
545
+ //处理文字对齐
546
+ if (style.labelAlign && style.labelAlign !== "cm") {
547
+ switch (style.labelAlign) {
548
+ case "lt":
549
+ locationPx.x += labelSize.w / 2;
550
+ locationPx.y += labelSize.h / 2;
551
+ break;
552
+ case "lm":
553
+ locationPx.x += labelSize.w / 2;
554
+ break;
555
+ case "lb":
556
+ locationPx.x += labelSize.w / 2;
557
+ locationPx.y -= labelSize.h / 2;
558
+ break;
559
+ case "ct":
560
+ locationPx.y += labelSize.h / 2;
561
+ break;
562
+ case "cb":
563
+ locationPx.y -= labelSize.h / 2;
564
+ break;
565
+ case "rt":
566
+ locationPx.x -= labelSize.w / 2;
567
+ locationPx.y += labelSize.h / 2;
568
+ break;
569
+ case "rm":
570
+ locationPx.x -= labelSize.w / 2;
571
+ break;
572
+ case "rb":
573
+ locationPx.x -= labelSize.w / 2;
574
+ locationPx.y -= labelSize.h / 2;
575
+ break;
576
+ default:
577
+ break;
578
+ }
579
+ }
580
+
581
+ left = locationPx.x - labelSize.w / 2;
582
+ bottom = locationPx.y + labelSize.h / 2;
583
+ //处理斜体字
584
+ if (style.fontStyle && style.fontStyle === "italic") {
585
+ right = locationPx.x + labelSize.w / 2 + parseInt(parseFloat(style.fontSize) / 2);
586
+ } else {
587
+ right = locationPx.x + labelSize.w / 2;
588
+ }
589
+ top = locationPx.y - labelSize.h / 2;
590
+
591
+ labB = new Bounds(left, bottom, right, top);
592
+
593
+ //旋转Bounds
594
+ var boundsQuad = [];
595
+ if ((style.labelRotation % 180) == 0) {
596
+ boundsQuad = [{
597
+ "x": labB.left,
598
+ "y": labB.top
599
+ },
600
+ {
601
+ "x": labB.right,
602
+ "y": labB.top
603
+ },
604
+ {
605
+ "x": labB.right,
606
+ "y": labB.bottom
607
+ },
608
+ {
609
+ "x": labB.left,
610
+ "y": labB.bottom
611
+ },
612
+ {
613
+ "x": labB.left,
614
+ "y": labB.top
615
+ }
616
+ ];
617
+ } else {
618
+ boundsQuad = this.rotationBounds(labB, loc, style.labelRotation);
619
+ }
620
+
621
+ //重置GeoText的bounds
622
+ feature.geometry.bounds = new Bounds(boundsQuad[1].x, boundsQuad[3].y, boundsQuad[2].x, boundsQuad[4].y);
623
+ return boundsQuad;
624
+ }
625
+
626
+ /**
627
+ * @function Label.prototype.getLabelInfo
628
+ * @description 根据当前位置获取绘制后的标签信息,包括标签的宽,高和行数等。
629
+ * @returns {Object} 绘制后的标签信息。
630
+ */
631
+ getLabelInfo(location, style) {
632
+ var LABEL_ALIGN = {
633
+ "l": "left",
634
+ "r": "right",
635
+ "t": "top",
636
+ "b": "bottom"
637
+ },
638
+ LABEL_FACTOR = {
639
+ "l": 0,
640
+ "r": -1,
641
+ "t": 0,
642
+ "b": -1
643
+ };
644
+
645
+ style = CommonUtil.extend({
646
+ fontColor: "#000000",
647
+ labelAlign: "cm"
648
+ }, style);
649
+ var pt = this.getLocalXY(location);
650
+ var labelWidth = 0;
651
+
652
+ if (style.labelXOffset || style.labelYOffset) {
653
+ var xOffset = isNaN(style.labelXOffset) ? 0 : style.labelXOffset;
654
+ var yOffset = isNaN(style.labelYOffset) ? 0 : style.labelYOffset;
655
+ pt[0] += xOffset;
656
+ pt[1] -= yOffset;
657
+ }
658
+
659
+ var canvas = document.createElement('canvas');
660
+ canvas.globalAlpha = 0;
661
+ canvas.lineWidth = 1;
662
+
663
+ var ctx = canvas.getContext("2d");
664
+
665
+ ctx.fillStyle = style.fontColor;
666
+ ctx.globalAlpha = style.fontOpacity || 1.0;
667
+ var fontStyle = [style.fontStyle ? style.fontStyle : "normal",
668
+ "normal",
669
+ style.fontWeight ? style.fontWeight : "normal",
670
+ style.fontSize ? style.fontSize : "1em",
671
+ style.fontFamily ? style.fontFamily : "sans-serif"
672
+ ].join(" ");
673
+ var labelRows = style.label.split('\n');
674
+ var numRows = labelRows.length;
675
+ var vfactor, lineHeight, labelWidthTmp;
676
+ if (ctx.fillText) {
677
+ // HTML5
678
+ ctx.font = fontStyle;
679
+ ctx.textAlign = LABEL_ALIGN[style.labelAlign[0]] ||
680
+ "center";
681
+ ctx.textBaseline = LABEL_ALIGN[style.labelAlign[1]] ||
682
+ "middle";
683
+ vfactor = LABEL_FACTOR[style.labelAlign[1]];
684
+ if (vfactor == null) {
685
+ vfactor = -.5;
686
+ }
687
+ lineHeight = ctx.measureText('Mg').height ||
688
+ ctx.measureText('xx').width;
689
+ pt[1] += lineHeight * vfactor * (numRows - 1);
690
+ for (let i = 0; i < numRows; i++) {
691
+ labelWidthTmp = ctx.measureText(labelRows[i]).width;
692
+ if (labelWidth < labelWidthTmp) {
693
+ labelWidth = labelWidthTmp;
694
+ }
695
+ }
696
+ } else if (ctx.mozDrawText) {
697
+ // Mozilla pre-Gecko1.9.1 (<FF3.1)
698
+ ctx.mozTextStyle = fontStyle;
699
+ vfactor = LABEL_FACTOR[style.labelAlign[1]];
700
+ if (vfactor == null) {
701
+ vfactor = -.5;
702
+ }
703
+ lineHeight = ctx.mozMeasureText('xx');
704
+ pt[1] += lineHeight * (1 + (vfactor * numRows));
705
+ for (let i = 0; i < numRows; i++) {
706
+ labelWidthTmp = ctx.measureText(labelRows[i]).width;
707
+ if (labelWidth < labelWidthTmp) {
708
+ labelWidth = labelWidthTmp;
709
+ }
710
+ }
711
+ }
712
+ var labelInfo = {}; //标签信息
713
+ if (labelWidth) {
714
+ labelInfo.w = labelWidth; //标签的宽
715
+ } else {
716
+ return null;
717
+ }
718
+
719
+ labelInfo.h = style.fontSize; //一行标签的高
720
+ labelInfo.rows = labelRows.length; //标签的行数
721
+
722
+ return labelInfo;
723
+ }
724
+
725
+ /**
726
+ * @function Label.prototype.rotationBounds
727
+ * @description 旋转 bounds。
728
+ * @param {Bounds} bounds - 要旋转的 bounds。
729
+ * @param {Object} rotationCenterPoi - 旋转中心点对象,此对象含有属性 x(横坐标),属性 y(纵坐标)。
730
+ * @param {number} angle - 旋转角度(顺时针)。
731
+ * @returns {Array.<Object>} bounds 旋转后形成的多边形节点数组。是一个四边形,形如:[{"x":1,"y":1},{"x":3,"y":1},{"x":6,"y":4},{"x":2,"y":10},{"x":1,"y":1}]。
732
+ */
733
+ rotationBounds(bounds, rotationCenterPoi, angle) {
734
+ var ltPoi = new Point([bounds.left, bounds.top]);
735
+ var rtPoi = new Point([bounds.right, bounds.top]);
736
+ var rbPoi = new Point([bounds.right, bounds.bottom]);
737
+ var lbPoi = new Point([bounds.left, bounds.bottom]);
738
+
739
+ var ver = [];
740
+ ver.push(this.getRotatedLocation(ltPoi.getCoordinates()[0], ltPoi.getCoordinates()[1], rotationCenterPoi.x, rotationCenterPoi.y, angle));
741
+ ver.push(this.getRotatedLocation(rtPoi.getCoordinates()[0], rtPoi.getCoordinates()[1], rotationCenterPoi.x, rotationCenterPoi.y, angle));
742
+ ver.push(this.getRotatedLocation(rbPoi.getCoordinates()[0], rbPoi.getCoordinates()[1], rotationCenterPoi.x, rotationCenterPoi.y, angle));
743
+ ver.push(this.getRotatedLocation(lbPoi.getCoordinates()[0], lbPoi.getCoordinates()[1], rotationCenterPoi.x, rotationCenterPoi.y, angle));
744
+
745
+ //bounds旋转后形成的多边形节点数组
746
+ var quad = [];
747
+
748
+ for (var i = 0; i < ver.length; i++) {
749
+ quad.push({
750
+ "x": ver[i].x,
751
+ "y": ver[i].y
752
+ });
753
+ }
754
+ quad.push({
755
+ "x": ver[0].x,
756
+ "y": ver[0].y
757
+ });
758
+ return quad;
759
+ }
760
+
761
+ /**
762
+ * @function Label.prototype.getRotatedLocation
763
+ * @description 获取一个点绕旋转中心顺时针旋转后的位置。(此方法用于屏幕坐标)。
764
+ * @param {number} x - 旋转点横坐标。
765
+ * @param {number} y - 旋转点纵坐标。
766
+ * @param {number} rx - 旋转中心点横坐标。
767
+ * @param {number} ry - 旋转中心点纵坐标。
768
+ * @param {number} angle - 旋转角度。
769
+ * @returns {Object} 旋转后的坐标位置对象,该对象含有属性 x(横坐标),属性 y(纵坐标)。
770
+ */
771
+ getRotatedLocation(x, y, rx, ry, angle) {
772
+ var loc = {},
773
+ x0, y0;
774
+
775
+ y = -y;
776
+ ry = -ry;
777
+ angle = -angle; //顺时针旋转
778
+ x0 = (x - rx) * Math.cos((angle / 180) * Math.PI) - (y - ry) * Math.sin((angle / 180) * Math.PI) + rx;
779
+ y0 = (x - rx) * Math.sin((angle / 180) * Math.PI) + (y - ry) * Math.cos((angle / 180) * Math.PI) + ry;
780
+
781
+ loc.x = x0;
782
+ loc.y = -y0;
783
+
784
+ return loc;
785
+ }
786
+
787
+ /**
788
+ * @function Label.prototype.getAvoidInfo
789
+ * @description 获取避让的信息。
790
+ * @param {Bounds} bounds - 地图像素范围。
791
+ * @param {Array.<Object>} quadrilateral - 四边形节点数组。例如:[{"x":1,"y":1},{"x":3,"y":1},{"x":6,"y":4},{"x":2,"y":10},{"x":1,"y":1}]。
792
+ * @returns {Object} 避让的信息。
793
+ */
794
+ getAvoidInfo(bounds, quadrilateral) {
795
+ if (quadrilateral.length !== 5) {
796
+ return null;
797
+ } //不是四边形
798
+
799
+ //将bound序列化为点数组形式
800
+ var bounddQuad = [{
801
+ "x": bounds.left,
802
+ "y": bounds.top
803
+ },
804
+ {
805
+ "x": bounds.right,
806
+ "y": bounds.top
807
+ },
808
+ {
809
+ "x": bounds.right,
810
+ "y": bounds.bottom
811
+ },
812
+ {
813
+ "x": bounds.left,
814
+ "y": bounds.bottom
815
+ },
816
+ {
817
+ "x": bounds.left,
818
+ "y": bounds.top
819
+ }
820
+ ];
821
+
822
+ var isIntersection = false,
823
+ bqLen = bounddQuad.length,
824
+ quadLen = quadrilateral.length;
825
+
826
+ var offsetX = 0,
827
+ offsetY = 0,
828
+ aspectH = "",
829
+ aspectW = "";
830
+ for (var i = 0; i < bqLen - 1; i++) {
831
+ for (var j = 0; j < quadLen - 1; j++) {
832
+ var isLineIn = CommonUtil.lineIntersection(bounddQuad[i], bounddQuad[i + 1], quadrilateral[j], quadrilateral[j + 1]);
833
+ if (isLineIn.CLASS_NAME === "SuperMap.Geometry.Point") {
834
+ //设置避让信息
835
+ setInfo(quadrilateral[j]);
836
+ setInfo(quadrilateral[j + 1]);
837
+ isIntersection = true;
838
+ }
839
+ }
840
+ }
841
+
842
+ if (isIntersection) {
843
+ //组织避让操作所需的信息
844
+ return {
845
+ "aspectW": aspectW,
846
+ "aspectH": aspectH,
847
+ "offsetX": offsetX,
848
+ "offsetY": offsetY
849
+ };
850
+ } else {
851
+ return null;
852
+ }
853
+
854
+
855
+ //内部函数:设置避让信息
856
+ //参数:vec-{Object} quadrilateral四边形单个节点。如:{"x":1,"y":1}。
857
+ function setInfo(vec) {
858
+ //四边形不在bounds内的节点
859
+ if (!bounds.contains(vec.x, vec.y)) {
860
+ //bounds的Top边
861
+ if (vec.y < bounds.top) {
862
+ let oY = Math.abs(bounds.top - vec.y);
863
+ if (oY > offsetY) {
864
+ offsetY = oY;
865
+ aspectH = "top";
866
+ }
867
+ }
868
+
869
+ //bounds的Bottom边
870
+ if (vec.y > bounds.bottom) {
871
+ let oY = Math.abs(vec.y - bounds.bottom);
872
+ if (oY > offsetY) {
873
+ offsetY = oY;
874
+ aspectH = "bottom";
875
+ }
876
+ }
877
+
878
+ //bounds的left边
879
+ if (vec.x < bounds.left) {
880
+ let oX = Math.abs(bounds.left - vec.x);
881
+ if (oX > offsetX) {
882
+ offsetX = oX;
883
+ aspectW = "left";
884
+ }
885
+ }
886
+
887
+ //bounds的right边
888
+ if (vec.x > bounds.right) {
889
+ let oX = Math.abs(vec.x - bounds.right);
890
+ if (oX > offsetX) {
891
+ offsetX = oX;
892
+ aspectW = "right";
893
+ }
894
+ }
895
+ }
896
+ }
897
+
898
+ }
899
+
900
+
901
+ /**
902
+ * @function Label.prototype.isQuadrilateralOverLap
903
+ * @description 判断两个四边形是否有压盖。
904
+ * @param {Array.<Object>} quadrilateral - 四边形节点数组。例如:[{"x":1,"y":1},{"x":3,"y":1},{"x":6,"y":4},{"x":2,"y":10},{"x":1,"y":1}]。
905
+ * @param {Array.<Object>} quadrilateral2 - 第二个四边形节点数组。
906
+ * @returns {boolean} 是否压盖,true 表示压盖。
907
+ */
908
+ isQuadrilateralOverLap(quadrilateral, quadrilateral2) {
909
+ var quadLen = quadrilateral.length,
910
+ quad2Len = quadrilateral2.length;
911
+ if (quadLen !== 5 || quad2Len !== 5) {
912
+ return null;
913
+ } //不是四边形
914
+
915
+ var OverLap = false;
916
+ //如果两四边形互不包含对方的节点,则两个四边形不相交
917
+ for (let i = 0; i < quadLen; i++) {
918
+ if (this.isPointInPoly(quadrilateral[i], quadrilateral2)) {
919
+ OverLap = true;
920
+ break;
921
+ }
922
+ }
923
+ for (let i = 0; i < quad2Len; i++) {
924
+ if (this.isPointInPoly(quadrilateral2[i], quadrilateral)) {
925
+ OverLap = true;
926
+ break;
927
+ }
928
+ }
929
+ //加上两矩形十字相交的情况
930
+ for (let i = 0; i < quadLen - 1; i++) {
931
+ if (OverLap) {
932
+ break;
933
+ }
934
+ for (var j = 0; j < quad2Len - 1; j++) {
935
+ var isLineIn = CommonUtil.lineIntersection(quadrilateral[i], quadrilateral[i + 1], quadrilateral2[j], quadrilateral2[j + 1]);
936
+ if (isLineIn.CLASS_NAME === "SuperMap.Geometry.Point") {
937
+ OverLap = true;
938
+ break;
939
+ }
940
+ }
941
+ }
942
+
943
+ return OverLap;
944
+ }
945
+
946
+ /**
947
+ * @function Label.prototype.isPointInPoly
948
+ * @description 判断一个点是否在多边形里面(射线法)。
949
+ * @param {Object} pt - 需要判定的点对象,该对象含有属性 x(横坐标),属性 y(纵坐标)。
950
+ * @param {Array.<Object>} poly - 多边形节点数组。例如一个四边形:[{"x":1,"y":1},{"x":3,"y":1},{"x":6,"y":4},{"x":2,"y":10},{"x":1,"y":1}]。
951
+ * @returns {boolean} 点是否在多边形内。
952
+ */
953
+ isPointInPoly(pt, poly) {
954
+ for (var isIn = false, i = -1, l = poly.length, j = l - 1; ++i < l; j = i) {
955
+ ((poly[i].y <= pt.y && pt.y < poly[j].y) || (poly[j].y <= pt.y && pt.y < poly[i].y)) &&
956
+ (pt.x < (poly[j].x - poly[i].x) * (pt.y - poly[i].y) / (poly[j].y - poly[i].y) + poly[i].x) &&
957
+ (isIn = !isIn);
958
+ }
959
+ return isIn;
960
+ }
961
+
962
+
963
+ canvasFunctionInternal_(extent, resolution, pixelRatio, size, projection) { // eslint-disable-line no-unused-vars
964
+ return super.canvasFunctionInternal_.apply(this, arguments);
965
+ }
966
+ }