|
var c = document.getElementById('c'); |
|
var ctx = c.getContext('2d'); |
|
ctx.lineWidth = 2; |
|
ctx.strokeStyle = '#556'; |
|
|
|
var width = window.innerWidth * 2; |
|
var height = window.innerHeight * 2; |
|
c.width = width; |
|
c.height = height; |
|
c.style.width = (width / 2) + 'px'; |
|
c.style.height = (height / 2) + 'px'; |
|
ctx.translate(width/2, width/2); |
|
|
|
function render(levels) { |
|
c.width = width; |
|
ctx.translate(width/2, width/2); |
|
var nodes = []; |
|
|
|
for (var i = 0; i < levels; i++) { |
|
for (var j = 0; j < Math.pow(2, i); j++) { |
|
nodes.push([i, j, levels]); |
|
} |
|
} |
|
|
|
nodes.forEach(backTrack); |
|
|
|
nodes.forEach(function (node) { |
|
var xy = nodePosition(node); |
|
ctx.beginPath(); |
|
ctx.arc(xy[0], xy[1], 5, 0, 2 * Math.PI); |
|
ctx.fill(); |
|
}); |
|
} |
|
|
|
var levels = 3; |
|
window.setInterval(function() { |
|
if (++levels > 9) levels = 1; |
|
render(levels); |
|
}, 400); |
|
|
|
c.addEventListener('click', function() { |
|
levels = levels + 1 > 8 ? 0 : levels + 1; |
|
render(levels); |
|
}); |
|
|
|
function nodePosition(pts) { |
|
var radius = pts[0] * ((width / 2) / (pts[2])); |
|
var nParts = Math.pow(2, pts[0]); |
|
var angle = (((pts[1]) / (nParts - 1)) * Math.PI * 1) - Math.PI; |
|
if (isNaN(angle)) angle = 0; |
|
return [ |
|
radius * Math.cos(angle), |
|
radius * Math.sin(angle) |
|
]; |
|
} |
|
|
|
function backTrack(pts) { |
|
if (pts[0] === 0) return; |
|
var here = nodePosition(pts); |
|
var father = [ |
|
pts[0] - 1, |
|
Math.floor(pts[1] / 2), |
|
pts[2] |
|
]; |
|
var there = nodePosition(father); |
|
ctx.beginPath(); |
|
ctx.moveTo(here[0], here[1]); |
|
ctx.lineTo(there[0], there[1]); |
|
ctx.stroke(); |
|
} |