98 lines
3 KiB
JavaScript
98 lines
3 KiB
JavaScript
Heatmap.prototype.draw = function() {
|
|
this.drawHeatmap();
|
|
for (var i = 0; i < this.drawTraces.length; ++i)
|
|
if (this.drawTraces[i])
|
|
this.drawTrace(i, 1);
|
|
};
|
|
|
|
Heatmap.prototype.drawHeatmap = function() {
|
|
this.context.clearRect(0, 0, this.w, this.h);
|
|
|
|
this.context.save();
|
|
this.context.scale(this.w / this.revisions.length, this.h / this.resolution);
|
|
|
|
var counts = [];
|
|
for (var time = 0; time < this.revisions.length; ++time) {
|
|
var revision = this.revisions[time];
|
|
for (var bucket in this.data[revision]) {
|
|
counts.push(this.data[revision][bucket].length);
|
|
}
|
|
}
|
|
counts.sort(function(a, b) {return a - b});
|
|
var cutoff = percentile(counts, 0.9);
|
|
if (cutoff < 2)
|
|
cutoff = 2;
|
|
|
|
for (var time = 0; time < this.revisions.length; ++time) {
|
|
var revision = this.revisions[time];
|
|
for (var bucket in this.data[revision]) {
|
|
var count = this.data[revision][bucket].length;
|
|
|
|
// Calculate average color across all traces in bucket.
|
|
var r = 0, g = 0, b = 0;
|
|
for (var i = 0; i < this.data[revision][bucket].length; ++i) {
|
|
var trace = this.data[revision][bucket][i];
|
|
r += nthColor(trace)[0];
|
|
g += nthColor(trace)[1];
|
|
b += nthColor(trace)[2];
|
|
}
|
|
r /= count, g /= count, b /= count;
|
|
var brightness = mapRange(count / cutoff, 0, 1, 2, 0.5);
|
|
|
|
// Draw!
|
|
this.context.fillStyle = calculateColor(r, g, b, 1, brightness);
|
|
this.context.fillRect(time, bucket, 1, 1);
|
|
}
|
|
}
|
|
|
|
this.context.restore();
|
|
};
|
|
|
|
Heatmap.prototype.drawTrace = function(trace, opacity) {
|
|
this.drawTraceLine(trace, 4, calculateColor(255, 255, 255, opacity, 1));
|
|
var color = calculateColor(nthColor(trace)[0], nthColor(trace)[1], nthColor(trace)[2], opacity, 1);
|
|
this.drawTraceLine(trace, 2, color);
|
|
};
|
|
|
|
Heatmap.prototype.drawTraceLine = function(trace, width, color) {
|
|
var revisionWidth = this.w / this.revisions.length;
|
|
|
|
this.context.save();
|
|
this.context.lineJoin = 'round';
|
|
this.context.lineWidth = width;
|
|
this.context.strokeStyle = color;
|
|
this.context.translate(revisionWidth / 2, 0);
|
|
this.context.beginPath();
|
|
|
|
var started = false;
|
|
for (var time = 0; time < this.revisions.length; ++time) {
|
|
var values = this.traces[this.revisions[time]][trace];
|
|
var sum = 0;
|
|
for (var value of values)
|
|
sum += value;
|
|
var value = sum / values.length;
|
|
|
|
var bucket = mapRange(value, this.min, this.max, 0, this.h);
|
|
if (started) {
|
|
this.context.lineTo(revisionWidth * time, bucket);
|
|
} else {
|
|
this.context.moveTo(revisionWidth * time, bucket);
|
|
started = true;
|
|
}
|
|
}
|
|
|
|
this.context.stroke();
|
|
this.context.restore();
|
|
}
|
|
|
|
Heatmap.prototype.scaleCanvas = function() {
|
|
this.canvas.width = this.canvas.clientWidth * window.devicePixelRatio;
|
|
this.canvas.height = this.canvas.clientHeight * window.devicePixelRatio;
|
|
this.context.scale(window.devicePixelRatio, window.devicePixelRatio);
|
|
|
|
this.w = this.canvas.clientWidth, this.h = this.canvas.clientHeight;
|
|
|
|
// Flip canvas.
|
|
this.context.scale(1, -1);
|
|
this.context.translate(0, -this.h);
|
|
};
|