/* * Author: 2015 Minori Yamashita [email protected] */ var origin = {x: 160, y:340}; var canvas = document.getElementById("space"); //http://stackoverflow.com/questions/9960908/permutations-in-javascript function permutate (arr) { return arr.reduce(function permute(res, item, key, arr) { return res.concat(arr.length > 1 && arr.slice(0, key) .concat(arr.slice(key + 1)) .reduce(permute, []) .map(function(perm) { return [item].concat(perm); }) || [[item]]); }, []); } Array.prototype.fill = Array.prototype.fill || function (v) { var self = this; this.forEach(function (x, i) { self[i] = v; }); return this; } _.mixin({ second: function (arr) { return arr[1]; } }); var edgeColors = { x: "#D04255", y: "#64C99B", z: "#208DC3", p: "#F0BA32", q: "#DB7BB1", r: "#CFE283" }; function vec () { return _.toArray(arguments); } function revY (x) { return origin.y - x; } function circle (r, theta) { return { x: r * Math.cos(theta), y: r * Math.sin(theta) } } function render (ctx, dimentions, xAxisAngle, yAxisAngle, transform) { var axisAngles = renderAxis(ctx, dimentions, { x: xAxisAngle, y: yAxisAngle }, 200); var allOne = _.range(dimentions.length).fill(1); vec = transform ? $V(transform).toDiagonalMatrix().multiply($V(allOne)).elements : allOne; permutate(_.zip(dimentions, vec)).forEach(function (route, i) { requestAnimationFrame(function () { plotVertex(ctx, route.map(_.first), axisAngles, route.map(_.second)); }); }); } function renderAxis (ctx, dimentions, axisAngles, length) { var fixedAxisAngles = axisAngles || { x: - Math.PI/4, y: Math.PI/2 }; var restAngle = fixedAxisAngles.y - fixedAxisAngles.x; var anglePerAxis = restAngle / (dimentions.length-1); ctx.lineWidth = 0.2; dimentions.forEach(function (axisName, i) { if (_.isNumber(fixedAxisAngles[axisName])) var dest = circle(length, fixedAxisAngles[axisName]); else { var angle = fixedAxisAngles.x + anglePerAxis * (i-1) + 0.1; fixedAxisAngles[axisName] = angle; var dest = circle(length, angle); } ctx.beginPath(); ctx.moveTo(origin.x, origin.y); ctx.lineTo(dest.x + origin.x, revY(dest.y)); ctx.stroke(); ctx.closePath(); }); return fixedAxisAngles; } function plotVertex (ctx, dimentions, axisAngles, vertex) { ctx.lineWidth = 2; var localOrigin = origin; vertex.forEach(function (p, i) { var axisName = dimentions[i]; var dest = circle(p*100, axisAngles[axisName]); var dest = { x: dest.x + localOrigin.x, y: localOrigin.y - dest.y }; ctx.strokeStyle = edgeColors[axisName] || "#D04255"; ctx.beginPath(); ctx.moveTo(localOrigin.x, localOrigin.y); ctx.lineTo(dest.x, dest.y); ctx.stroke(); ctx.closePath(); localOrigin = dest; }); } var canvas = document.getElementById("space"); function test (xAxisAngle, d, transform) { var ctx = canvas.getContext("2d"); ctx.clearRect(0,0,500,600); render(ctx, ["x", "y", "z", "p", "q", "r", "s", "t", "u", "v", "w", "a", "b", "c", "d", "e", "f", "g", "h", "i", "j", "k", "l", "m", "n", "o"].slice(0,d), xAxisAngle || 0, Math.PI/2, transform); } var state = { theta: -Math.PI*1.5, delta: 0.02, dimention: 5, //CHANGE ME! transform: null //scale }; function frame () { if (state.dimention < 7) requestAnimationFrame(frame); test(Math.PI/2 * Math.sin(state.theta) - Math.PI/2, state.dimention, state.transform); state.theta += state.delta; } requestAnimationFrame(frame);
<canvas id="space" width="500" height="600"></canvas>