-
Notifications
You must be signed in to change notification settings - Fork 61
/
index.js
152 lines (120 loc) · 2.74 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
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
/**
* Module dependencies.
*/
var matrix = require('array-matrix');
/**
* Expose `chart()`.
*/
module.exports = chart;
/**
* Return ascii chart of `data`.
*
* - `width` total chart width [130]
* - `height` total chart height [30]
* - `padding` edge padding [3]
* - `pointChar` character used to plot a point [█]
* - `negativePointChar` character used to plot a negative point [░]
* - `axisChar` character used to draw axis [.]
*
* @param {Array} data
* @param {Object} [opts]
* @return {String}
* @api public
*/
function chart(data, opts) {
opts = opts || {};
// options
var w = opts.width || 130;
var h = opts.height || 30;
var pc = opts.pointChar || '█';
var nc = opts.negativePointChar || '░';
var ac = opts.axisChar || '.';
// padding
var pad = typeof opts.padding === 'number' ? opts.padding : 3;
w -= pad * 2;
h -= pad * 2;
// setup
var out = matrix(w, h);
var m = max(data) || 0;
var label = Math.abs(m).toString();
var labelw = label.length;
var labelp = 1;
// chart sizes void of padding etc
var ch = h;
var cw = w - labelw - labelp;
// fill
for (var y = 0; y < h; y++) {
for (var x = 0; x < w; x++) {
out[y][x] = ' ';
}
}
// y-axis labels
for (var i = 0; i < labelw; i++) {
out[0][i] = label[i];
}
out[h - 1][labelw - labelp] = '0';
// y-axis
for (var y = 0; y < h; y++) {
out[y][labelw + labelp] = ac;
}
// x-axis
var x = labelw + labelp;
while (x < w) {
out[h - 1][x++] = ac;
out[h - 1][x++] = ' ';
}
// strip excess from head
// so that data may "roll"
var space = Math.floor(w / 2) - 1;
var excess = Math.max(0, data.length - space);
if (excess) data = data.slice(excess);
// plot data
var x = labelw + labelp + 2;
for (var i = 0; i < data.length; i++) {
var d = data[i];
var p = d / m;
var y = Math.round((h - 2) * p);
var c = y < 0 ? nc : pc;
if (y < 0) y = -y;
while (y--) {
out[Math.abs(y - h) - 2][x] = c;
}
x += 2;
}
// Return string
var str = string(out, h);
return pad ? padding(str, pad) : str;
}
/**
* Apply padding.
*/
function padding(str, n) {
var linew = str.split('\n')[0].length;
var line = Array(linew).join(' ') + '\n';
// y
str = Array(n).join(line) + str;
str = str + Array(n).join(line);
// x
str = str.replace(/^/gm, Array(n).join(' '));
return str;
}
/**
* Convert matrix to a string.
*/
function string(out) {
var buf = [];
for (var i = 0; i < out.length; i++) {
buf.push(out[i].join(''));
}
return buf.join('\n');
}
/**
* Return max in array.
*/
function max(data) {
var n = Math.abs(data[0]);
for (var i = 1; i < data.length; i++) {
n = Math.abs(data[i]) > n ? Math.abs(data[i]) : n;
}
return n;
}