1
|
|
2
|
|
3
|
|
4
|
|
5
|
|
6
|
|
7
|
|
8
|
|
9
|
function HeatmapOverlay(map, cfg){
|
10
|
this.setMap(map);
|
11
|
this.initialize(cfg || {});
|
12
|
};
|
13
|
|
14
|
HeatmapOverlay.prototype = new google.maps.OverlayView();
|
15
|
|
16
|
|
17
|
HeatmapOverlay.CSS_TRANSFORM = (function() {
|
18
|
var div = document.createElement('div');
|
19
|
var props = [
|
20
|
'transform',
|
21
|
'WebkitTransform',
|
22
|
'MozTransform',
|
23
|
'OTransform',
|
24
|
'msTransform'
|
25
|
];
|
26
|
|
27
|
for (var i = 0; i < props.length; i++) {
|
28
|
var prop = props[i];
|
29
|
if (div.style[prop] !== undefined) {
|
30
|
return prop;
|
31
|
}
|
32
|
}
|
33
|
|
34
|
return props[0];
|
35
|
})();
|
36
|
|
37
|
HeatmapOverlay.prototype.initialize = function(cfg) {
|
38
|
this.cfg = cfg;
|
39
|
|
40
|
var map = this.map = this.getMap();
|
41
|
var container = this.container = document.createElement('div');
|
42
|
var mapDiv = map.getDiv();
|
43
|
var width = this.width = mapDiv.clientWidth;
|
44
|
var height = this.height = mapDiv.clientHeight;
|
45
|
|
46
|
container.style.cssText = 'width:' + width +'px;height:' + height+'px;';
|
47
|
|
48
|
this.data = [];
|
49
|
this.max = 1;
|
50
|
this.min = 0;
|
51
|
|
52
|
cfg.container = container;
|
53
|
};
|
54
|
|
55
|
HeatmapOverlay.prototype.onAdd = function(){
|
56
|
|
57
|
this.getPanes().overlayLayer.appendChild(this.container);
|
58
|
|
59
|
this.changeHandler = google.maps.event.addListener(
|
60
|
this.map,
|
61
|
'bounds_changed',
|
62
|
this.draw
|
63
|
);
|
64
|
|
65
|
if (!this.heatmap) {
|
66
|
this.heatmap = h337.create(this.cfg);
|
67
|
}
|
68
|
this.draw();
|
69
|
};
|
70
|
|
71
|
HeatmapOverlay.prototype.onRemove = function() {
|
72
|
if (!this.map) { return; }
|
73
|
|
74
|
this.map = null;
|
75
|
|
76
|
this.container.parentElement.removeChild(this.container);
|
77
|
|
78
|
if (this.changeHandler) {
|
79
|
google.maps.event.removeListener(this.changeHandler);
|
80
|
this.changeHandler = null;
|
81
|
}
|
82
|
|
83
|
};
|
84
|
|
85
|
HeatmapOverlay.prototype.draw = function() {
|
86
|
if (!this.map) { return; }
|
87
|
|
88
|
var bounds = this.map.getBounds();
|
89
|
|
90
|
var topLeft = new google.maps.LatLng(
|
91
|
bounds.getNorthEast().lat(),
|
92
|
bounds.getSouthWest().lng()
|
93
|
);
|
94
|
|
95
|
var projection = this.getProjection();
|
96
|
var point = projection.fromLatLngToDivPixel(topLeft);
|
97
|
|
98
|
this.container.style[HeatmapOverlay.CSS_TRANSFORM] = 'translate(' +
|
99
|
Math.round(point.x) + 'px,' +
|
100
|
Math.round(point.y) + 'px)';
|
101
|
|
102
|
this.update();
|
103
|
};
|
104
|
|
105
|
HeatmapOverlay.prototype.resize = function() {
|
106
|
|
107
|
if (!this.map){ return; }
|
108
|
|
109
|
var div = this.map.getDiv(),
|
110
|
width = div.clientWidth,
|
111
|
height = div.clientHeight;
|
112
|
|
113
|
if (width == this.width && height == this.height){ return; }
|
114
|
|
115
|
this.width = width;
|
116
|
this.height = height;
|
117
|
|
118
|
|
119
|
this.heatmap._renderer.setDimensions(width, height);
|
120
|
|
121
|
this.update();
|
122
|
};
|
123
|
|
124
|
HeatmapOverlay.prototype.update = function() {
|
125
|
var projection = this.map.getProjection(),
|
126
|
zoom, scale, bounds, topLeft;
|
127
|
|
128
|
if (!projection){ return; }
|
129
|
|
130
|
bounds = this.map.getBounds();
|
131
|
|
132
|
topLeft = new google.maps.LatLng(
|
133
|
bounds.getNorthEast().lat(),
|
134
|
bounds.getSouthWest().lng()
|
135
|
);
|
136
|
|
137
|
zoom = this.map.getZoom();
|
138
|
scale = Math.pow(2, zoom);
|
139
|
|
140
|
this.resize();
|
141
|
|
142
|
if (this.data.length == 0) {
|
143
|
return;
|
144
|
}
|
145
|
|
146
|
var generatedData = { max: this.max, min: this.min };
|
147
|
var latLngPoints = [];
|
148
|
|
149
|
var len = this.data.length;
|
150
|
var layerProjection = this.getProjection();
|
151
|
var layerOffset = layerProjection.fromLatLngToDivPixel(topLeft);
|
152
|
var radiusMultiplier = this.cfg.scaleRadius ? scale : 1;
|
153
|
var localMax = 0;
|
154
|
var localMin = 0;
|
155
|
var valueField = this.cfg.valueField;
|
156
|
|
157
|
|
158
|
while (len--) {
|
159
|
var entry = this.data[len];
|
160
|
var value = entry[valueField];
|
161
|
var latlng = entry.latlng;
|
162
|
|
163
|
|
164
|
|
165
|
if (!bounds.contains(latlng)) {
|
166
|
continue;
|
167
|
}
|
168
|
|
169
|
localMax = Math.max(value, localMax);
|
170
|
localMin = Math.min(value, localMin);
|
171
|
|
172
|
var point = this.pixelTransform(layerProjection.fromLatLngToDivPixel(latlng));
|
173
|
var latlngPoint = { x: Math.round(point.x - layerOffset.x), y: Math.round(point.y - layerOffset.y) };
|
174
|
latlngPoint[valueField] = value;
|
175
|
|
176
|
var radius;
|
177
|
|
178
|
if (entry.radius) {
|
179
|
radius = entry.radius * radiusMultiplier;
|
180
|
} else {
|
181
|
radius = (this.cfg.radius || 2) * radiusMultiplier;
|
182
|
}
|
183
|
latlngPoint.radius = radius;
|
184
|
latLngPoints.push(latlngPoint);
|
185
|
}
|
186
|
if (this.cfg.useLocalExtrema) {
|
187
|
generatedData.max = localMax;
|
188
|
generatedData.min = localMin;
|
189
|
}
|
190
|
|
191
|
generatedData.data = latLngPoints;
|
192
|
|
193
|
this.heatmap.setData(generatedData);
|
194
|
|
195
|
};
|
196
|
|
197
|
HeatmapOverlay.prototype.pixelTransform = function(point) {
|
198
|
if (point.x < 0) {
|
199
|
point.x += this.width;
|
200
|
}
|
201
|
if (point.x > this.width) {
|
202
|
point.x -= this.width;
|
203
|
}
|
204
|
if (point.y < 0) {
|
205
|
point.y += this.height;
|
206
|
}
|
207
|
if (point.y > this.height) {
|
208
|
point.y -= this.height;
|
209
|
}
|
210
|
return point;
|
211
|
};
|
212
|
|
213
|
HeatmapOverlay.prototype.setData = function(data) {
|
214
|
this.max = data.max;
|
215
|
this.min = data.min;
|
216
|
|
217
|
var latField = this.cfg.latField || 'lat';
|
218
|
var lngField = this.cfg.lngField || 'lng';
|
219
|
var valueField = this.cfg.valueField || 'value';
|
220
|
|
221
|
|
222
|
var data = data.data;
|
223
|
var len = data.length;
|
224
|
var d = [];
|
225
|
|
226
|
while (len--) {
|
227
|
var entry = data[len];
|
228
|
var latlng = new google.maps.LatLng(entry[latField], entry[lngField]);
|
229
|
var dataObj = { latlng: latlng };
|
230
|
dataObj[valueField] = entry[valueField];
|
231
|
if (entry.radius) {
|
232
|
dataObj.radius = entry.radius;
|
233
|
}
|
234
|
d.push(dataObj);
|
235
|
}
|
236
|
this.data = d;
|
237
|
this.update();
|
238
|
};
|
239
|
|
240
|
HeatmapOverlay.prototype.addData = function(pointOrArray) {
|
241
|
if (pointOrArray.length > 0) {
|
242
|
var len = pointOrArray.length;
|
243
|
while(len--) {
|
244
|
this.addData(pointOrArray[len]);
|
245
|
}
|
246
|
} else {
|
247
|
var latField = this.cfg.latField || 'lat';
|
248
|
var lngField = this.cfg.lngField || 'lng';
|
249
|
var valueField = this.cfg.valueField || 'value';
|
250
|
var entry = pointOrArray;
|
251
|
var latlng = new google.maps.LatLng(entry[latField], entry[lngField]);
|
252
|
var dataObj = { latlng: latlng };
|
253
|
|
254
|
dataObj[valueField] = entry[valueField];
|
255
|
if (entry.radius) {
|
256
|
dataObj.radius = entry.radius;
|
257
|
}
|
258
|
this.max = Math.max(this.max, dataObj[valueField]);
|
259
|
this.min = Math.min(this.min, dataObj[valueField]);
|
260
|
this.data.push(dataObj);
|
261
|
this.update();
|
262
|
}
|
263
|
};
|
264
|
|