content/blog/graphs/enhancements.js (view raw)
1// Enhancing prototypes
2CanvasRenderingContext2D.prototype.clear = function() {
3 // http://stackoverflow.com/a/9722502/4759433
4 this.clearRect(0, 0, this.canvas.width, this.canvas.height);
5 this.beginPath(); // Clear strokes
6};
7
8var TWOPI = 2 * Math.PI;
9CanvasRenderingContext2D.prototype.circle = function(x, y, r) {
10 this.beginPath();
11 this.arc(x, y, r, 0, TWOPI);
12 this.fill();
13 this.beginPath();
14};
15
16var SIXTHPI = Math.PI / 6.0;
17CanvasRenderingContext2D.prototype.arrow = function(
18 x0, y0, x1, y1, headLen=10) {
19 // http://stackoverflow.com/a/6333775
20 var angle = Math.atan2(y1 - y0, x1 - x0);
21 this.moveTo(x0, y0);
22
23 this.lineTo(x1, y1);
24 this.lineTo(x1 - headLen * Math.cos(angle - SIXTHPI),
25 y1 - headLen * Math.sin(angle - SIXTHPI));
26
27 this.moveTo(x1, y1);
28 this.lineTo(x1 - headLen * Math.cos(angle + SIXTHPI),
29 y1 - headLen * Math.sin(angle + SIXTHPI));
30
31 this.stroke();
32}
33
34String.prototype.format = function() {
35 // http://stackoverflow.com/a/4673436/4759433
36 var args = arguments;
37 return this.replace(/{(\d+)}/g, function(match, number) {
38 return typeof args[number] != 'undefined' ? args[number] : match;
39 });
40};
41
42String.prototype.lpad = function(pad) {
43 return String(pad + this).slice(-pad.length);
44};
45
46Array.matrix = function(numrows, numcols, initial) {
47 // http://stackoverflow.com/a/30056867/4759433
48 var arr = [];
49 for (var i = 0; i != numrows; ++i) {
50 var columns = [];
51 for (var j = 0; j != numcols; ++j)
52 columns[j] = initial;
53 arr[i] = columns;
54 }
55 return arr;
56}
57
58function matrixCpy(src, dst) {
59 // Ensure it has at least one item
60 if (src.length != 0 && dst.length != 0) {
61 var ii = Math.min(src.length, dst.length);
62 var jj = Math.min(src[0].length, dst[0].length);
63
64 for (var i = 0; i != ii; ++i)
65 for (var j = 0; j != jj; ++j)
66 dst[i][j] = src[i][j];
67 }
68}
69
70function matrixAdd(src, dst) {
71 // Ensure it has at least one item
72 if (src.length != 0 && dst.length != 0) {
73 var ii = Math.min(src.length, dst.length);
74 var jj = Math.min(src[0].length, dst[0].length);
75
76 for (var i = 0; i != ii; ++i)
77 for (var j = 0; j != jj; ++j)
78 dst[i][j] += src[i][j];
79 }
80}
81
82function matrixMul(a, b) {
83 var ii = a.length;
84 var jj = b[0].length;
85 var c = Array.matrix(ii, jj, 0);
86
87 var kk = a[0].length;
88 if (kk == b.length) // Ensure nxp times pxm
89 for (var i = 0; i != ii; ++i)
90 for (var j = 0; j != jj; ++j)
91 for (var k = 0; k != kk; ++k)
92 c[i][j] += a[i][k] * b[k][j];
93
94 return c;
95}
96
97// Pops the i'th row and j'th column off the matrix
98function matrixPop(matrix, i, j) {
99 if (!matrix || !matrix[0])
100 return Array.matrix(0, 0, 0);
101
102 var ii = matrix.length;
103 var jj = matrix[0].length;
104 if (i < 0 || i >= ii || j < 0 || j >= jj)
105 return matrix;
106
107 var srci, srcj, dsti, dstj;
108 var result = Array.matrix(ii-1, jj-1, 0);
109
110 dsti = 0;
111 for (srci = 0; srci < ii; ++srci) {
112 dstj = 0;
113 if (srci != i) {
114 for (srcj = 0; srcj < jj; ++srcj) {
115 if (srcj != j) {
116 result[dsti][dstj] = matrix[srci][srcj];
117 ++dstj;
118 }
119 }
120 ++dsti;
121 }
122 }
123
124 return result;
125}
126
127function matrixStr(a) {
128 if (!a || !a[0])
129 return '[]';
130
131 var ii = a.length;
132 var jj = a[0].length;
133 var jjm1 = jj - 1;
134
135 var max = a[0][0];
136 for (var i = 0; i != ii; ++i)
137 for (var j = 0; j != jj; ++j)
138 if (a[i][j] > max)
139 max = a[i][j];
140
141 var result = '';
142 max = '' + max;
143 var pad = '';
144 for (var i = 0; i != max; ++i)
145 pad += ' ';
146
147 for (var i = 0; i != ii; ++i) {
148 result += '[';
149 for (var j = 0; j != jjm1; ++j) {
150 result += ('' + a[i][j]).lpad(pad);
151 result += ',';
152 }
153 result += ('' + a[i][jjm1]).lpad(pad);
154 result += ']\n';
155 }
156
157 return result;
158}
159
160// highlight = [belowRow, belowCol, color]
161function matrixRepr(matrix, table, highlight=null) {
162 if (!matrix || !matrix[0]) {
163 table.innerHTML = '';
164 return;
165 }
166
167 if (!highlight)
168 highlight = [-1, -1, '#000'];
169
170 var result = '';
171 var ii = matrix.length;
172 var jj = matrix[0].length;
173
174 result += '<tr><td></td>';
175 for (var j = 0; j != jj; ++j)
176 result += '<td><b>' + (j+1) + '</b></td>';
177 result += '</tr>';
178
179 for (var i = 0; i != ii; ++i) {
180 result += '<tr><td><b>' + (i+1) + '</b></td>';
181 for (var j = 0; j != jj; ++j) {
182 // We want to higlight 0..col on row and 0..row on col
183 if ((i <= highlight[0] && j == highlight[1]) ||
184 (i == highlight[0] && j <= highlight[1])) {
185 result += '<td style="background-color:' + highlight[2] +
186 ';">' + matrix[i][j] + '</td>';
187 } else {
188 result += '<td>' + matrix[i][j] + '</td>';
189 }
190 }
191 result += '</tr>';
192 }
193
194 table.innerHTML = result;
195}
196
197function lerp(start, end, t) {
198 return start + t * (end - start);
199}
200
201function lerpArray(start, end, t) {
202 var result = [];
203 var ii = Math.min(start.length, end.length);
204 for (var i = 0; i != ii; ++i)
205 result.push(start[i] + t * (end[i] - start[i]));
206 return result;
207}