-
Notifications
You must be signed in to change notification settings - Fork 2
/
index.js
119 lines (100 loc) · 3.28 KB
/
index.js
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
var xtend = require('xtend'),
getControlPoints = require('get-control-points'),
linearScale = require('simple-linear-scale'),
util = require('./util');
module.exports = canvasLineChart;
/**
* Draw a line chart on canvas.
* @param {Canvas} c canvas element
* @param {number} height
* @param {number} width
* @param {Array<Array<number>>} data, as [zoom, val] doubles
* @param {number} base mathematical base, a number between 0 and 1
* @param {Object} options optional customizations
* @param {number} [options.options.scaleFactor=1] dpi ratio
* @param {number} [options.min=0] minimum x value
* @param {number} [options.max=22] maximum y value
* @param {number} [options.tickSize=1] space between each tick mark
* @param {number} options.marker a marker as a zoom value
* @param {boolean} options.step whether to represent the chart as stair-steps
* rather than an interpolated line.
*/
function canvasLineChart(c, width, height, data, base, options) {
options = xtend({
scaleFactor: 1,
tickSize: 1,
min: 0,
max: 22
}, options);
function s(x) { return x * options.scaleFactor; }
width = s(width);
height = s(height);
var margin = s(12);
var fontSize = s(10);
var values = data.map(function(d) { return d[1]; });
var xScaleRaw = linearScale(
[options.min, options.max],
[margin, width - margin]);
var xScale = function(v) {
return ~~xScaleRaw(v);
};
var chartHeight = height - s(margin);
var yScale = linearScale([util.min(values), util.max(values)],
[chartHeight, margin]);
c.width = width;
c.height = height;
c.style.width = width / options.scaleFactor + 'px';
c.style.height = height / options.scaleFactor + 'px';
var ctx = c.getContext('2d');
ctx.fillStyle = 'transparent';
ctx.fillRect(0, 0, width, height);
// draw [steps] axis ticks
ctx.fillStyle = 'rgba(0,0,0,0.1)';
for (var i = options.min; i <= options.max; i += options.tickSize) {
ctx.fillRect(xScale(i), 0, s(2), chartHeight + margin);
}
if (typeof options.marker === 'number') {
ctx.fillStyle = '#ddd';
ctx.fillRect(xScale(options.marker), 0, s(2), chartHeight + margin);
}
// draw the data line
ctx.strokeStyle = '#222';
ctx.lineWidth = s(2);
data.forEach(function(d, i) {
if (i === 0) ctx.lineTo(xScale(d[0]), yScale(d[1]));
else if (options.step) {
ctx.lineTo(xScale(d[0]), yScale(data[i - 1][1]));
ctx.lineTo(xScale(d[0]), yScale(d[1]));
} else {
var cp = getControlPoints(data[i - 1], d, base);
ctx.bezierCurveTo(xScale(cp[0][0]), yScale(cp[0][1]),
xScale(cp[1][0]), yScale(cp[1][1]),
xScale(d[0]), yScale(d[1]));
}
});
ctx.stroke();
ctx.fillStyle = '#fff';
ctx.strokeStyle = '#222';
data.forEach(function(data) {
// Draw circle
ctx.beginPath();
ctx.lineWidth = s(2);
var r = s(3);
if (data[2] && data[2].focus) {
ctx.lineWidth = s(3);
r = s(5);
}
if (!data[2] || !data[2].end) {
ctx.arc(xScale(data[0]), yScale(data[1]), r, 0, s(2 * Math.PI), false);
}
ctx.fill();
ctx.stroke();
// Draw text
ctx.fillStyle = '#ddd';
ctx.font = fontSize + 'px Menlo, monospace';
ctx.textAlign = 'center';
if (!data[2] || !data[2].end) {
ctx.fillText(data[0], xScale(data[0]), chartHeight + margin);
}
});
}