Fork of: http://bl.ocks.org/mbostock/5649592
To show: http://glowingpython.blogspot.com/2013/05/a-colorful-trifoil-knot.html
TODO: Figure out how to encode height along path as color or above and below at line crossings.
Fork of: http://bl.ocks.org/mbostock/5649592
To show: http://glowingpython.blogspot.com/2013/05/a-colorful-trifoil-knot.html
TODO: Figure out how to encode height along path as color or above and below at line crossings.
| <!DOCTYPE html> | |
| <meta charset="utf-8"> | |
| <body> | |
| <style> | |
| path { | |
| fill: none; | |
| stroke: #000; | |
| stroke-width: 3px; | |
| } | |
| circle { | |
| fill: steelblue; | |
| stroke: #fff; | |
| stroke-width: 3px; | |
| } | |
| </style> | |
| <script src="http://d3js.org/d3.v3.min.js"></script> | |
| <script src="http://cdnjs.cloudflare.com/ajax/libs/dat-gui/0.5/dat.gui.min.js"></script> | |
| <script> | |
| var range = function (start, end, step) { | |
| var result = []; | |
| for (var i = start; i < end; i += step) { | |
| result.push(i); | |
| } | |
| return result; | |
| } | |
| var options = { | |
| size: 500, // canvas width and height | |
| interpolation: "basis-closed", | |
| samples: 8, // points along parameterized function | |
| showSamples: false | |
| }; | |
| var draw = function () { | |
| var sin = Math.sin; | |
| var cos = Math.cos; | |
| var pi = Math.PI; | |
| var size = options.size; | |
| var samples = options.samples; | |
| var phis = range(0, pi * 2, (pi * 2) / samples); | |
| var points = phis.map(function (phi) { | |
| return [sin(phi) + 2*sin(2*phi), cos(phi) - 2*cos(2*phi)]; | |
| }); | |
| points = points.map(function (point) { | |
| return point | |
| .map(function (coord) { return coord * (size / 8) }) // scale | |
| .map(function (coord) { return coord + (size / 2) }); // center | |
| }); | |
| var line = d3.svg.line() | |
| .interpolate(options.interpolation); | |
| // out with the old | |
| d3.select("body svg").remove(); | |
| var svg = d3.select("body") | |
| .append("svg") | |
| .datum(points) | |
| .attr("width", size) | |
| .attr("height", size); | |
| svg.append("path") | |
| .style("stroke", "#ddd") | |
| .attr("d", line); | |
| svg.append("path") | |
| .attr("d", line) | |
| .call(transition); | |
| if (options.showSamples) { | |
| svg.selectAll('.point') | |
| .data(points) | |
| .enter() | |
| .append("circle") | |
| .attr("r", 4) | |
| .attr("transform", function(d) { return "translate(" + d + ")"; }); | |
| } | |
| function transition(path) { | |
| path.transition() | |
| .duration(7500) | |
| .attrTween("stroke-dasharray", tweenDash) | |
| .each("end", function() { d3.select(this).call(transition); }); | |
| } | |
| function tweenDash() { | |
| var l = this.getTotalLength(), | |
| i = d3.interpolateString("0," + l, l + "," + l); | |
| return function(t) { return i(t); }; | |
| } | |
| } | |
| var gui = new dat.GUI(); | |
| gui.add(options, 'size', 0, 2000) | |
| .step(10) | |
| .onChange(draw); | |
| gui.add(options, 'samples', 0, 16) | |
| .step(1) | |
| .onChange(draw); | |
| var interpolatorNames = [ | |
| "linear", | |
| "step-before", | |
| "step-after", | |
| "basis", | |
| "basis-open", | |
| "basis-closed", | |
| "cardinal", | |
| "cardinal-open", | |
| "cardinal-closed", | |
| "monotone" | |
| ] | |
| gui.add(options, 'interpolation') | |
| .options(interpolatorNames) | |
| .onChange(draw); | |
| gui.add(options, 'showSamples') | |
| .onChange(draw); | |
| draw(); | |
| </script> |