Skip to content

Commit 066f7b6

Browse files
committed
Add alpha version of SVG area heatmap plugin
1 parent 3ca8327 commit 066f7b6

1 file changed

Lines changed: 195 additions & 0 deletions

File tree

plugins/svg-area-heatmap.js

Lines changed: 195 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,195 @@
1+
/*
2+
* SVG Area Heatmap Plugin
3+
*
4+
* Copyright (c) 2014, Patrick Wied (http://www.patrick-wied.at)
5+
* Dual-licensed under the MIT (http://www.opensource.org/licenses/mit-license.php)
6+
* and the Beerware (http://en.wikipedia.org/wiki/Beerware) license.
7+
*/
8+
(function() {
9+
'use strict';
10+
11+
var SvgAreaHeatmap = (function SvgAreaHeatmapClosure() {
12+
13+
var _getColorPalette = function(config) {
14+
var gradientConfig = config.gradient || config.defaultGradient;
15+
var paletteCanvas = document.createElement('canvas');
16+
var paletteCtx = paletteCanvas.getContext('2d');
17+
18+
paletteCanvas.width = 256;
19+
paletteCanvas.height = 1;
20+
21+
var gradient = paletteCtx.createLinearGradient(0, 0, 256, 1);
22+
for (var key in gradientConfig) {
23+
gradient.addColorStop(key, gradientConfig[key]);
24+
}
25+
26+
paletteCtx.fillStyle = gradient;
27+
paletteCtx.fillRect(0, 0, 256, 1);
28+
29+
return paletteCtx.getImageData(0, 0, 256, 1).data;
30+
};
31+
32+
33+
function SvgAreaHeatmapStore(config) {
34+
this._coordinator = {};
35+
this._data = {};
36+
this._max = 1;
37+
this._min = 0;
38+
};
39+
40+
SvgAreaHeatmapStore.prototype = {
41+
setCoordinator: function(coordinator) {
42+
this._coordinator = coordinator;
43+
},
44+
setData: function(data) {
45+
this._max = data.max || this._max;
46+
this._min = data.min || this._min;
47+
this._data = {};
48+
49+
var d = data.data;
50+
var dataLen = d.length;
51+
52+
while (dataLen--) {
53+
this._organiseData(d[dataLen]);
54+
}
55+
56+
this._coordinator.emit('renderall', this._getInternalData());
57+
},
58+
addData: function(data) {
59+
var organisedEntry = this._organiseData(data);
60+
if (organisedEntry) {
61+
this._coordinator.emit('renderpartial', {
62+
min: this._min,
63+
max: this._max,
64+
data: [organisedEntry]
65+
});
66+
}
67+
},
68+
updateData: function(data) {
69+
70+
},
71+
removeData: function(data) {
72+
73+
},
74+
getData: function() {
75+
76+
},
77+
setDataMax: function(max) {
78+
this._max = max;
79+
//this._onExtremaChange();
80+
this._coordinator.emit('renderall', this._getInternalData());
81+
return this;
82+
},
83+
setDataMin: function(min) {
84+
this._min = min;
85+
//this._onExtremaChange();
86+
this._coordinator.emit('renderall', this._getInternalData());
87+
return this;
88+
},
89+
_organiseData: function(point) {
90+
if (this._data[point.id]) {
91+
this._data[point.id] += point.value;
92+
93+
} else {
94+
this._data[point.id] = point.value;
95+
}
96+
97+
if (this._data[point.id] > this._max) {
98+
this.setDataMax(this._data[point.id]);
99+
}
100+
if (this._data[point.id] < this._min) {
101+
this.setDataMin(this._data[point.id]);
102+
}
103+
return point;
104+
},
105+
_getInternalData: function() {
106+
return {
107+
max: this._max,
108+
min: this._min,
109+
data: this._data,
110+
};
111+
}
112+
};
113+
114+
115+
function SvgAreaHeatmapRenderer(config) {
116+
// initialization
117+
var container = config.container;
118+
var svgUrl = config.svgUrl;
119+
this.renderQueue = [];
120+
121+
122+
var svgObj = document.createElement('object');
123+
svgObj.type = 'image/svg+xml';
124+
svgObj.id = 'svgHeatmap';
125+
svgObj.data = svgUrl;
126+
127+
var that = this;
128+
129+
svgObj.onload = function() {
130+
that.svgDoc = this.getSVGDocument();
131+
that.$ = function(selector) {
132+
return that.svgDoc.querySelector(selector);
133+
};
134+
135+
that._processQueue();
136+
}
137+
138+
container.appendChild(svgObj);
139+
140+
this._palette = _getColorPalette(config);
141+
142+
};
143+
144+
SvgAreaHeatmapRenderer.prototype = {
145+
renderPartial: function(data) {
146+
var point = data.data[0];
147+
this.max = data.max;
148+
this.min = data.min;
149+
this._colorize(point.id, point.value);
150+
},
151+
renderAll: function(data) {
152+
var points = data.data;
153+
this.max = data.max;
154+
this.min = data.min;
155+
for (var key in points) {
156+
this._colorize(key, points[key]);
157+
}
158+
},
159+
_colorize: function(key, value) {
160+
161+
if (!this.svgDoc) {
162+
this.renderQueue.push([key, value]);
163+
} else {
164+
var node = this.$('#' + key);
165+
var color;
166+
var max = this.max;
167+
var min = this.min;
168+
var colorIndex = (((value/(Math.abs(max-min)) * 255) >> 0) * 4);
169+
170+
var r = this._palette[colorIndex];
171+
var g = this._palette[colorIndex + 1];
172+
var b = this._palette[colorIndex + 2];
173+
174+
node.style.fill = ['rgb(', r, ',', g, ',', b,')'].join('');
175+
}
176+
},
177+
_processQueue: function() {
178+
var renderElement = this.renderQueue.pop();
179+
if (!renderElement) {
180+
return;
181+
}
182+
this._colorize.apply(this, renderElement);
183+
this._processQueue();
184+
}
185+
};
186+
187+
return {
188+
store: SvgAreaHeatmapStore,
189+
renderer: SvgAreaHeatmapRenderer
190+
}
191+
}());
192+
193+
h337.register('SvgAreaHeatmap', SvgAreaHeatmap);
194+
195+
}());

0 commit comments

Comments
 (0)