// the canvas and its graphic context
var cs = document.getElementById('theCanvas');
var ctx = cs.getContext('2d');
// line style
var colors = [ 'gray', 'navy', 'purple', 'brown',
'red', 'orange', 'yellowgreen', 'skyblue' ];
var widths = [5, 4, 3, 2, 2, 1, 1, 0.5 ];
var tm = [
[ [ 0, 1/2, 0], [ 1/2, 0, 0], [0, 0, 1] ],
[ [1/2, 0, 0], [ 0, 1/2, 1/2], [0, 0, 1] ],
[ [1/2, 0, 1/2], [ 0, 1/2, 1/2], [0, 0, 1] ],
[ [ 0, -1/2, 1], [-1/2, 0, 1/2], [0, 0, 1] ]
];
var E = [ [ 1, 0, 0], [0, 1, 0], [0, 0, 1] ];
function affine_transform(m, p) {
return [ m[0][0] * p[0] + m[0][1] * p[1] + m[0][2],
m[1][0] * p[0] + m[1][1] * p[1] + m[1][2] ];
}
function mat_mul(m0, m1) {
return [ [m0[0][0]*m1[0][0]+m0[0][1]*m1[1][0]+m0[0][2]*m1[2][0],
m0[0][0]*m1[0][1]+m0[0][1]*m1[1][1]+m0[0][2]*m1[2][1],
m0[0][0]*m1[0][2]+m0[0][1]*m1[1][2]+m0[0][2]*m1[2][2]],
[m0[1][0]*m1[0][0]+m0[1][1]*m1[1][0]+m0[1][2]*m1[2][0],
m0[1][0]*m1[0][1]+m0[1][1]*m1[1][1]+m0[1][2]*m1[2][1],
m0[1][0]*m1[0][2]+m0[1][1]*m1[1][2]+m0[1][2]*m1[2][2]],
[m0[2][0]*m1[0][0]+m0[2][1]*m1[1][0]+m0[2][2]*m1[2][0],
m0[2][0]*m1[0][1]+m0[2][1]*m1[1][1]+m0[2][2]*m1[2][1],
m0[2][0]*m1[0][2]+m0[2][1]*m1[1][2]+m0[2][2]*m1[2][2]] ];
}
function hilbert(n, m) {
if (n > 0) {
tm.forEach(mm => { hilbert(n-1, mat_mul(m, mm)); });
} else {
[ [0.25, 0.25], [0.25, 0.75], [0.75, 0.75], [0.75, 0.25] ]
.map(p => affine_transform(m, p))
.map(p => [p[0]*cs.width, p[1]*cs.height])
.forEach(p => { ctx.lineTo(p[0],p[1]); });
}
}
function drawHilbert(i) {
ctx.beginPath();
ctx.lineWidth = widths[i];
ctx.strokeStyle = colors[i];
hilbert(i, E);
ctx.stroke();
}
for(i=0; i<colors.length; i++) { drawHilbert(i); }