forked from SuperMap/iClient-JavaScript
-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathHeatMapLayer.js
More file actions
730 lines (655 loc) · 29.2 KB
/
HeatMapLayer.js
File metadata and controls
730 lines (655 loc) · 29.2 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
/* Copyright© 2000 - 2018 SuperMap Software Co.Ltd. All rights reserved.
* This program are made available under the terms of the Apache License, Version 2.0
* which accompanies this distribution and is available at http://www.apache.org/licenses/LICENSE-2.0.html.*/
import mapboxgl from 'mapbox-gl';
import '../core/Base';
import {
GeoJSON as GeoJSONFormat,
ServerFeature,
GeometryVector,
LonLat,
GeometryPoint as Point,
GeoText,
CommonUtil
} from '@supermap/iclient-common';
/**
* @class mapboxgl.supermap.HeatMapLayer
* @classdesc 热力图层类。
* @category Visualization HeatMap
* @param {string} name - 图层名称。
* @param {Object} options - 构造参数。
* @param {mapboxgl.Map} options.map - mapboxgl map 对象。
* @param {string} options.featureWeight - 对应 feature 属性中的热点权重字段名称,权重值类型为 float。
* @param {string} [options.id] - 专题图层ID。默认使用 CommonUtil.createUniqueID("HeatMapLayer_") 创建专题图层 ID。
* @param {number} [options.radius=50] - 热点渲染的最大半径(热点像素半径),单位为 px,当 useGeoUnit参数 为 true 时,单位使用当前图层地理坐标单位。热点显示的时候以精确点为中心点开始往四周辐射衰减,其衰减半径和权重值成比列。
* @param {boolean} [options.loadWhileAnimating=true] - 是否实时重绘。(当绘制大数据量要素的情况下会出现卡顿,建议把该参数设为false)。
* @param {number} [options.opacity=1] - 图层透明度。
* @param {Array.<string>} [options.colors=['blue','cyan','lime','yellow','red']] - 颜色线性渐变数组,颜色值必须为canvas所支。
* @param {boolean} [options.useGeoUnit=false] - 使用地理单位,即默认热点半径默认使用像素单位。 当设置为 true 时,热点半径和图层地理坐标保持一致。
* @extends {mapboxgl.Evented}
* @fires mapboxgl.supermap.HeatMapLayer#featuresadded
* @fires mapboxgl.supermap.HeatMapLayer#changelayer
* @fires mapboxgl.supermap.HeatMapLayer#featuresremoved
*
*/
export class HeatMapLayer extends mapboxgl.Evented {
constructor(name, options) {
super();
var _options = options ? options : {};
/**
* @member {string} mapboxgl.supermap.HeatMapLayer.prototype.name
* @description 图层名字。
*/
this.name = name;
/**
* @member {string} mapboxgl.supermap.HeatMapLayer.prototype.id
* @description 热力图图层 id。
*/
this.id = _options.id ? _options.id : CommonUtil.createUniqueID("HeatMapLayer_");
/**
* @member {mapboxgl.Map} mapboxgl.supermap.HeatMapLayer.prototype.map
* @description 热力图图层 map。
*/
this.map = _options.map ? _options.map : null;
/**
* @member {boolean} [mapboxgl.supermap.HeatMapLayer.prototype.loadWhileAnimating=true]
* @description 是否实时重绘。(当绘制大数据量要素的情况下会出现卡顿,建议把该参数设为false)。
*/
this.loadWhileAnimating = _options.loadWhileAnimating === undefined ? true : _options.loadWhileAnimating;
/**
* @member {boolean} [mapboxgl.supermap.HeatMapLayer.prototype.visibility=true]
* @description 图层显示状态属性。
*/
this.visibility = true;
/**
* @member {number} [mapboxgl.supermap.HeatMapLayer.prototype.opacity=1]
* @description 图层透明度,取值范围[0,1]。
*/
this.opacity = _options.opacity ? _options.opacity : 1;
/**
* @member {Array.<string>} [mapboxgl.supermap.HeatMapLayer.prototype.colors=['blue','cyan','lime','yellow','red']]
* @description 颜色线性渐变数组,颜色值必须为 canvas 所支。
*/
this.colors = _options.colors ? _options.colors : ['blue', 'cyan', 'lime', 'yellow', 'red'];
/**
* @member {boolean} [mapboxgl.supermap.HeatMapLayer.prototype.useGeoUnit=false]
* @description 使用地理单位,即默认热点半径默认使用像素单位。 当设置为 true 时,热点半径和图层地理坐标保持一致。
*/
this.useGeoUnit = _options.useGeoUnit ? _options.useGeoUnit : false;
/**
* @member {number} [mapboxgl.supermap.HeatMapLayer.prototype.radius=50]
* @description 热点渲染的最大半径(热点像素半径),
* 热点显示的时候以精确点为中心点开始往四周辐射衰减,
* 其衰减半径和权重值成比列。
*/
this.radius = _options.radius ? _options.radius : 50;
/**
* @member {string} mapboxgl.supermap.HeatMapLayer.prototype.featureWeight
* @description 对应 feature 属性中的热点权重字段名称,权重值类型为 float。
* @example
* //feature.attributes中表示权重的字段为 height,则在 HeatMapLayer 的 featureWeight 参数赋值为 "height"。
* feature1.attributes.height = 7.0;
* feature2.attributes.height = 6.0;
* var heatMapLayer = new mapboxgl.supermap.HeatMapLayer("heatmaplayer",{"featureWeight":"height"});
* heatMapLayer.addFeatures([feature1,feature2]);
*/
this.featureWeight = _options.featureWeight ? _options.featureWeight : null;
/**
* @member {Array.<SuperMap.Feature.Vector>} mapboxgl.supermap.HeatMapLayer.prototype.features
* @description 热点信息数组,记录存储图层上添加的所有热点信息。
*/
this.features = [];
/**
* @member {number} mapboxgl.supermap.HeatMapLayer.prototype.maxWeight
* @description 设置权重最大值。如果不设置此属性,将按照当前屏幕范围内热点所拥有的权重最大值绘制热点图。
*/
this.maxWeight = null;
/**
* @member {number} mapboxgl.supermap.HeatMapLayer.prototype.minWeight
* @description 设置权重最小值。如果不设置此属性,将按照当前屏幕范围内热点所拥有的权重最小值绘制热点图。
*/
this.minWeight = null;
/**
* @member mapboxgl.supermap.HeatMapLayer.prototype.EVENT_TYPES
* @description 监听一个自定义事件可用如下方式:
* 热点图自定义事件信息,事件调用时的属性与具体事件类型相对应。
*
* All event objects have at least the following properties:
* {Object} object - A reference to layer.events.object.
* {DOMElement} element - A reference to layer.events.element.
*
* 支持的事件如下 (另外包含 <SuperMap.Layer 中定义的其他事件>):
* featuresadded - 热点添加完成时触发。传递参数为添加的热点信息数组和操作成功与否信息。
* 参数类型:{features: features, succeed: succeed}
* featuresremoved - 热点被删除时触发。传递参数为删除的热点信息数组和操作成功与否信息。
* 参数类型:{features: features, succeed: succeed}
* featuresdrawcompleted - 热点图渲染完成时触发,没有额外属性。
*/
this.EVENT_TYPES = ["featuresadded", "featuresremoved", "featuresdrawcompleted"];
/**
* @member {boolean} [mapboxgl.supermap.HeatMapLayer.prototype.supported=false]
* @description 当前浏览器是否支持 canvas 绘制,
* 决定了热点图是否可用,内部判断使用。
*/
this.supported = false;
/**
* @member {Object} mapboxgl.supermap.HeatMapLayer.prototype.rootCanvas
* @description 热点图主绘制面板。
*/
this.rootCanvas = null;
/**
* @member {Object} mapboxgl.supermap.HeatMapLayer.prototype.canvasContext
* @description 热点图主绘制对象。
*/
this.canvasContext = null;
/**
* @member {number} mapboxgl.supermap.HeatMapLayer.prototype.maxWidth
* @description 当前绘制面板宽度。和当前 map 窗口宽度一致。
*/
this.maxWidth = null;
/**
* @member {number} mapboxgl.supermap.HeatMapLayer.prototype.maxHeight
* @description 当前绘制面板宽度。和当前 map 窗口高度一致。
*/
this.maxHeight = null;
}
/**
* @function mapboxgl.supermap.HeatMapLayer.prototype.onAdd
* @description 向底图添加该图层
*/
onAdd(map) {
this.map = map;
if (this.features.length === 0) {
return;
}
//创建热力图绘制容器
this._createCanvasContainer();
//绑定图层事件与Map同步
this.map.on('resize', this._resizeEvent.bind(this));
this.map.on('zoomstart', this._zoomStartEvent.bind(this));
this.map.on('zoomend', this._zoomEndEvent.bind(this));
this.map.on('rotatestart', this._rotateStartEvent.bind(this));
this.map.on('rotate', this._rotateEvent.bind(this));
this.map.on('rotateend', this._rotateEndEvent.bind(this));
this.map.on('dragend', this._dragEndEvent.bind(this));
this.map.on('movestart', this._moveStartEvent.bind(this));
this.map.on('move', this._moveEvent.bind(this));
this.map.on('moveend', this._moveEndEvent.bind(this));
this.map.on('remove', this.removeFromMap.bind(this));
this.refresh();
}
/**
* @function mapboxgl.supermap.HeatMapLayer.prototype.removeFromMap
* @description 从底图删除该图层。
*/
removeFromMap() {
this.removeAllFeatures();
this.map.getCanvasContainer().removeChild(this.rootCanvas);
}
/**
* @function mapboxgl.supermap.HeatMapLayer.prototype._createCanvasContainer
* @description 创建热力图绘制容器。
* @private
*/
_createCanvasContainer() {
this.supported = true;
//构建绘图面板
this.mapContainer = this.map.getCanvasContainer();
//热点图要求使用canvas绘制,判断是否支持
this.rootCanvas = document.createElement("canvas");
this.rootCanvas.id = this.id;
var mapCanvas = this.map.getCanvas();
this.rootCanvas.width = this.maxWidth = parseInt(mapCanvas.width);
this.rootCanvas.height = this.maxHeight = parseInt(mapCanvas.height);
CommonUtil.modifyDOMElement(this.rootCanvas, null, null, null,
"absolute", null, null, this.opacity);
this.canvasContext = this.rootCanvas.getContext('2d');
this.mapContainer.appendChild(this.rootCanvas);
}
/**
* @function mapboxgl.supermap.HeatMapLayer.prototype.addFeatures
* @description 添加热点信息。
* @param {GeoJSONObject} features - 待添加的要素数组。
*
* @example
* var geojson = {
* "type": "FeatureCollection",
* "features": [
* {
* "type": "feature",
* "geometry": {
* "type": "Point", //只支持point类型
* "coordinates": [0, 0]
* },
* "properties": {
* "height": Math.random()*9,
* "geoRadius": useGeoRadius?radius:null
* }
* }
* ]
* };
* var heatMapLayer = new mapboxgl.supermap.HeatMapLayer("heatmaplayer",{"featureWeight":"height"}); pLayer = new mapboxgl.supermap.HeatMapLayer("heatmaplayer",{"featureWeight":"height"});
* heatMapLayer.addFeatures(geojson);
* map.addLayer(heatMapLayer);
*/
addFeatures(features) {
this.features = this.toiClientFeature(features);
/**
* @event mapboxgl.supermap.HeatMapLayer#featuresadded
* @description 要素添加完成之后触发。
* @property {GeoJSONObject} features - 被添加的要素。
* @property {boolean} succeed - 要素是否成功添加。
*/
this.fire(this.EVENT_TYPES[0], {features: features, succeed: true});
//支持更新features,刷新底图
this.refresh();
}
/**
* @function mapboxgl.supermap.HeatMapLayer.prototype.refresh
* @description 强制刷新当前热点显示,在图层热点数组发生变化后调用,更新显示。
*/
refresh() {
if (this.features.length === 0) {
return;
}
if (this.map) {
var extent = this.map.getBounds();
this.updateHeatPoints(extent);
}
}
/**
* @function mapboxgl.supermap.HeatMapLayer.prototype.setOpacity
* @description 设置图层的不透明度,取值[0-1]之间。
* @param {number} [opacity] - 透明度。
*/
setOpacity(opacity) {
if (opacity !== this.opacity) {
this.opacity = opacity;
CommonUtil.modifyDOMElement(this.rootCanvas, null, null, null,
null, null, null, opacity);
if (this.map !== null) {
/**
* @event mapboxgl.supermap.HeatMapLayer#changelayer
* @description 图层属性改变之后触发。
* @property {Object} layer - 图层。
* @property {string} property - 被改变的图层属性。
*/
this.fire('changelayer', {layer: this, property: "opacity"});
}
}
}
/**
* @function mapboxgl.supermap.HeatMapLayer.prototype.updateHeatPoints
* @description 刷新热点图显示。
* @param {mapboxgl.LngLatBounds} bounds - 当前显示范围。
*/
updateHeatPoints(bounds) {
if (this.features && this.features.length > 0) {
this.convertFastToPixelPoints(bounds);
} else {
this.canvasContext.clearRect(0, 0, this.maxWidth, this.maxWidth);
}
}
/**
* @function mapboxgl.supermap.HeatMapLayer.prototype.convertFastToPixelPoints
* @description 过滤位于当前显示范围内的热点,并转换其为当前分辨率下的像素坐标。
* @param {mapboxgl.LngLatBounds} bounds - 当前显示范围。
* @private
*/
convertFastToPixelPoints(bounds) {
var data = [], x, y, k, resolution, maxTemp, minTemp, maxWeightTemp;
//获取当前像素下的地理范围
var dw = bounds.getEast() - bounds.getWest();
var dh = bounds.getNorth() - bounds.getSouth();
var mapCanvas = this.map.getCanvas();
if (dw / mapCanvas.width > dh / mapCanvas.height) {
resolution = dw / mapCanvas.width;
} else {
resolution = dh / mapCanvas.height;
}
//热点半径
this.useRadius = this.useGeoUnit ? parseInt(this.radius / resolution) : this.radius;
for (var i = 0; i < this.features.length; i++) {
var feature = this.features[i];
var point = feature.geometry;
//可通过bounds过滤需绘制的features以优化性能,但mapboxgl旋转获取得bounds不适
var pixelPoint = this.getPixelXY(new LonLat(point.x, point.y));
if (this.featureWeight) {
pixelPoint.weight = feature.attributes[this.featureWeight];//point.value;
if (!this.maxWeight) {
//找出最大最小权重值
maxTemp = maxTemp ? maxTemp : pixelPoint.weight;
minTemp = minTemp ? minTemp : pixelPoint.weight;
maxTemp = Math.max(maxTemp, pixelPoint.weight);
minTemp = Math.min(minTemp, pixelPoint.weight);
}
} else {
pixelPoint.weight = 1;
}
x = Math.floor(pixelPoint.x);
y = Math.floor(pixelPoint.y);
k = pixelPoint.weight;
data.push([x, y, k]);
}
//无最大权重设置
if (!this.maxWeight) {
if (maxTemp && minTemp) {
maxWeightTemp = (maxTemp + minTemp) / 2;
} else {
maxWeightTemp = 1;
}
this.draw(data, maxWeightTemp);
} else {
this.draw(data, this.maxWeight);
}
}
/**
* @function mapboxgl.supermap.HeatMapLayer.prototype.draw
* @description 绘制热点图。
* @param {Array} data - convertToPixelPoints方法计算出的点。
* @private
*/
draw(data, maxWeight) {
if (this.maxHeight > 0 && this.maxWidth > 0) {
//清空
var ctx = this.canvasContext;
this.canvasContext.clearRect(0, 0, this.maxWidth, this.maxHeight);
this.drawCircle(this.useRadius);
this.createGradient();
for (var i = 0; i < data.length; i++) {
var p = data[i];
this.canvasContext.globalAlpha = Math.max(p[2] / maxWeight, 0.05);
this.canvasContext.drawImage(this.circle, p[0] - this.useRadius, p[1] - this.useRadius);
}
var colored = ctx.getImageData(0, 0, this.maxWidth, this.maxHeight);
this.colorize(colored.data, this.grad);
ctx.putImageData(colored, 0, 0);
} else {
return false;
}
}
/**
* @function mapboxgl.supermap.HeatMapLayer.prototype.colorize
* @description 根据渐变色重置热点图rgb值。
* @param {Array} pixels - 像素 RGBA 值。
* @param {Array} gradient - 渐变 canvas.getImageData.data。
* @private
*/
colorize(pixels, gradient) {
for (var i = 0, j; i < pixels.length; i += 4) {
j = pixels[i + 3] * 4;
if (j) {
pixels[i] = gradient[j];
pixels[i + 1] = gradient[j + 1];
pixels[i + 2] = gradient[j + 2];
}
}
}
/**
* @function mapboxgl.supermap.HeatMapLayer.drawCircle
* @description 绘制热点半径圆。
* @param {number} r - 热点半径。
* @private
*/
drawCircle(r) {
var blur = r / 2;
var circle = this.circle = document.createElement('canvas'),
ctx = circle.getContext("2d");
circle.height = 2 * r;
circle.width = 2 * r;
ctx.shadowOffsetX = ctx.shadowOffsetY = 2 * r;
ctx.shadowBlur = blur;
ctx.shadowColor = "#000000";
ctx.beginPath();
ctx.arc(-r, -r, r / 2, 0, Math.PI * 2, true);
ctx.closePath();
ctx.fill();
}
/**
* @function mapboxgl.supermap.HeatMapLayer.createGradient
* @description 根据 this.colors 设置渐变并 getImageData。
* @private
*/
createGradient() {
var colors = this.colors;
var canvas = document.createElement('canvas'),
ctx = canvas.getContext("2d"),
gradient = ctx.createLinearGradient(0, 0, 0, 256);
canvas.height = 256;
canvas.width = 1;
var index = 1;
for (var i = 0, len = colors.length; i < len; i++) {
gradient.addColorStop(index / len, colors[i]);
index++;
}
ctx.fillStyle = gradient;
ctx.fillRect(0, 0, 1, 256);
this.grad = ctx.getImageData(0, 0, 1, 256).data;
}
/**
* @function mapboxgl.supermap.HeatMapLayer.prototype.getPixelXY
* @description 转换地理坐标为相对于当前窗口左上角的像素坐标。
* @param {number} x - 热点的像素 x 坐标。
* @param {number} y - 热点的像素 y 坐标。
*/
getPixelXY(coordinate) {
var pixelP, map = this.map;
if (coordinate instanceof Point || coordinate instanceof GeoText) {
let tempPoint = map.project(new mapboxgl.LngLat(coordinate.x, coordinate.y));
pixelP = {x: parseInt(tempPoint.x), y: parseInt(tempPoint.y)};
}
if (coordinate instanceof LonLat) {
let tempPoint = map.project(new mapboxgl.LngLat(coordinate.lon, coordinate.lat));
pixelP = {x: parseInt(tempPoint.x), y: parseInt(tempPoint.y)};
}
return pixelP;
}
/**
* @function mapboxgl.supermap.HeatMapLayer.prototype.toiClientFeature
* @description 转为 iClient 要素。
* @param {GeoJSONObject} features - 待添加的要素数组。
*/
toiClientFeature(features) {
if (!CommonUtil.isArray(features)) {
features = [features];
}
let featuresTemp = [];
for (let i = 0; i < features.length; i++) {
if (features[i] instanceof GeometryVector) {
// 若是 GeometryVector 直接返回
featuresTemp.push(features[i]);
} else if (["FeatureCollection", "Feature", "Geometry"].indexOf(features[i].type) != -1) {
//GeoJSON 规范数据类型
let format = new GeoJSONFormat();
featuresTemp = featuresTemp.concat(format.read(features[i]));
} else if (features[i].geometry && features[i].geometry.parts) {
//iServer服务器返回数据格式
featuresTemp.push(ServerFeature.fromJson(features[i]).toFeature());
} else {
throw new Error(`Features[${i}]'s type does not match, please check.`);
}
}
return featuresTemp;
}
/**
* @function mapboxgl.supermap.HeatMapLayer.prototype.removeFeatures
* @description 移除指定的热点信息。
* @param {Array.<SuperMap.Feature.Vector>} features - 热点信息数组。
*/
removeFeatures(features) {
if (!features || features.length === 0 || !this.features || this.features.length === 0) {
return;
}
if (features === this.features) {
return this.removeAllFeatures();
}
if (!(CommonUtil.isArray(features))) {
features = [features];
}
var heatPoint, index, heatPointsFailedRemoved = [];
for (var i = 0, len = features.length; i < len; i++) {
heatPoint = features[i];
index = CommonUtil.indexOf(this.features, heatPoint);
//找不到视为删除失败
if (index === -1) {
heatPointsFailedRemoved.push(heatPoint);
continue;
}
//删除热点
this.features.splice(index, 1);
}
var succeed = heatPointsFailedRemoved.length == 0 ? true : false;
//派发删除features成功的事件
/**
* @event mapboxgl.supermap.HeatMapLayer#featuresremoved
* @description 要素删除之后触发。
* @property {Array.<SuperMap.Feature.Vector>} features - 需要被删除的要素。
* @property {boolean} succeed - 要素删除成功与否。
*/
this.fire(this.EVENT_TYPES[1], {features: heatPointsFailedRemoved, succeed: succeed});
this.refresh();
}
/**
* @function mapboxgl.supermap.HeatMapLayer.prototype.removeAllFeatures
* @description 移除全部的热点信息。
*/
removeAllFeatures() {
this.features = [];
this.refresh();
}
/**
* @function mapboxgl.supermap.HeatMapLayer.prototype.moveTo
* @description 将图层移动到某个图层之前。
* @param {string} layerID - 待插入的图层ID。
* @param {boolean} [before=true] - 是否将本图层插入到图层 id 为 layerID 的图层之前(如果为 false 则将本图层插入到图层 id 为 layerID 的图层之后)。
*/
moveTo(layerID, before) {
var layer = document.getElementById(this.rootCanvas.id);
before = before !== undefined ? before : true;
if (before) {
var beforeLayer = document.getElementById(layerID);
if (layer && beforeLayer) {
beforeLayer.parentNode.insertBefore(layer, beforeLayer);
}
return;
}
var nextLayer = document.getElementById(layerID);
if (layer) {
if (nextLayer.nextSibling) {
nextLayer.parentNode.insertBefore(layer, nextLayer.nextSibling);
return;
}
nextLayer.parentNode.appendChild(layer);
}
}
/**
* @function mapboxgl.supermap.HeatMapLayer.prototype.setVisibility
* @description 设置图层可见性,设置图层的隐藏,显示,重绘的相应的可见标记。
* @param {boolean} [visibility] - 是否显示图层(当前地图的resolution在最大最小resolution之间)。
*/
setVisibility(visibility) {
if (this.rootCanvas && visibility !== this.visibility) {
this.visibility = visibility;
this.rootCanvas.style.display = visibility ? "block" : "none";
}
}
//事件绑定
_resizeEvent() {
this.mapContainer.style.perspective = this.map.transform.cameraToCenterDistance + 'px';
var canvas = this.map.getCanvas();
this.rootCanvas.style.width = canvas.style.width;
this.rootCanvas.style.height = canvas.style.height;
this.rootCanvas.width = this.maxWidth = parseInt(canvas.width);
this.rootCanvas.height = this.maxHeight = parseInt(canvas.height);
this.refresh();
}
_zoomStartEvent() {
if (this.loadWhileAnimating || !this.visibility) {
return;
}
this.zooming = true;
this._hide();
}
_zoomEndEvent() {
if (this.loadWhileAnimating || !this.visibility) {
return;
}
this.zooming = false;
this._show();
}
_rotateStartEvent() {
if (this.loadWhileAnimating || !this.visibility) {
return;
}
this.rotating = true;
}
_rotateEvent() {
if (this.loadWhileAnimating || !this.visibility) {
return;
}
if (this.map.getPitch() !== 0) {
this._hide();
}
this.mapContainer.style.perspective = this.map.transform.cameraToCenterDistance + 'px';
var tPitch = this.map.getPitch() - this.startPitch;
var tBearing = -this.map.getBearing() + this.startBearing;
this.rootCanvas.style.transform = 'rotateX(' + tPitch + 'deg)' + ' rotateZ(' + tBearing + 'deg)'
}
_rotateEndEvent() {
if (this.loadWhileAnimating || !this.visibility) {
return;
}
this.rotating = false;
this._show();
}
_dragEndEvent() {
if (this.loadWhileAnimating || !this.visibility) {
return;
}
this._hide();
}
_moveEndEvent() {
if (this.loadWhileAnimating || !this.visibility) {
return;
}
this.rootCanvas.style.transform = '';
this.refresh();
this._show();
}
_moveStartEvent() {
if (this.loadWhileAnimating || !this.visibility) {
return;
}
this.startPitch = this.map.getPitch();
this.startBearing = this.map.getBearing();
var startMovePoint = this.map.project(new mapboxgl.LngLat(0, 0));
this.startMoveX = startMovePoint.x;
this.startMoveY = startMovePoint.y;
}
_moveEvent() {
if (this.loadWhileAnimating || !this.visibility) {
this.refresh();
return;
}
if (this.rotating || this.zooming) {
return;
}
if (this.map.getPitch() !== 0) {
this._hide();
}
this.mapContainer.style.perspective = this.map.transform.cameraToCenterDistance + 'px';
var tPitch = this.map.getPitch() - this.startPitch;
var tBearing = -this.map.getBearing() + this.startBearing;
var endMovePoint = this.map.project(new mapboxgl.LngLat(0, 0));
var tMoveX = endMovePoint.x - this.startMoveX;
var tMoveY = endMovePoint.y - this.startMoveY;
this.rootCanvas.style.transform = 'rotateX(' + tPitch + 'deg)' + ' rotateZ(' + tBearing + 'deg)' + ' translate3d(' + tMoveX + 'px, ' + tMoveY + 'px, 0px)';
}
_hide() {
this.rootCanvas.style.display = 'none';
}
_show() {
this.rootCanvas.style.display = 'block';
}
}
mapboxgl.supermap.HeatMapLayer = HeatMapLayer;