[ Launch: Fourier ] 8523826 by dvdrtrgn
-
-
Save dvdrtrgn/8523826 to your computer and use it in GitHub Desktop.
Fourierz
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
{"description":"Fourierz","endpoint":"","display":"svg","public":true,"require":[],"fileconfigs":{"inlet.js":{"default":true,"vim":false,"emacs":false,"fontSize":12},"foo.css":{"default":true,"vim":false,"emacs":false,"fontSize":12},"_.md":{"default":true,"vim":false,"emacs":false,"fontSize":12},"config.json":{"default":true,"vim":false,"emacs":false,"fontSize":12},"form.html":{"default":true,"vim":false,"emacs":false,"fontSize":12}},"fullscreen":false,"play":true,"loop":true,"restart":true,"autoinit":false,"pause":true,"loop_type":"pingpong","bv":false,"nclones":15,"clone_opacity":0.4,"duration":3000,"ease":"linear","dt":0.01,"thumbnail":"http://i.imgur.com/SGMnsOf.png","inline-console":true} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
form { | |
background-color: pink; | |
position: absolute; | |
bottom: 10px; | |
right: 10px; | |
} | |
.hide { | |
display: none; | |
} | |
.coeff .dot { | |
fill: hsla(207, 63%, 27%, 0.2); | |
} | |
.coeff.last .dot { | |
fill: hsla(207, 63%, 27%, 1.0); | |
} | |
.coeff .circle { | |
fill: none; | |
stroke: hsl(0, 0%, 70%); | |
} | |
.coeff.first .circle { | |
fill: none; | |
stroke: hsl(0, 0%, 30%); | |
} | |
.coeff.last .circle { | |
display: none; | |
} | |
.graph { | |
fill: none; | |
stroke: steelblue; | |
stroke-width: 3px; | |
} | |
.trace { | |
fill: none; | |
stroke: steelblue; | |
} | |
.proj { | |
fill: none; | |
stroke: #000; | |
} | |
.axis { | |
stroke: hsl(0, 0%, 70%); | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<form> | |
<p> | |
<select id="type"> | |
<option value="square">Square</option> | |
<option value="triangle">Triangle</option> | |
<option value="sawtooth">Sawtooth</option> | |
<option value="fibonacci">Fibonacci</option> | |
<option value="pulse">Pulse</option> | |
</select> | |
<input id="size" type="number" value="6" min="1" max="40" step="1"> | |
</p> | |
<p><input id="freq" type="range" value="0.3" min="0.01" max="0.5" step="0.01"> <label>Speed</label></p> | |
</form> |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/*jslint es5:true, white:false, newcap:true */ | |
/*globals _, d3, pause, play, tributary, window */ | |
/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */ | |
var Pi = Math.PI; | |
var types = { | |
square: function (n) { | |
return (((n + 1) % 2) ? 0 : 1) / n; | |
}, | |
triangle: function (n) { | |
if (!Boolean(n % 2)) { | |
return 0; | |
} | |
return ((n % 4 === 1) ? 1 : - 1) / (n * n); | |
}, | |
sawtooth: function (n) { | |
return ((n % 2) ? - 1 : 1) / (n + 1); | |
}, | |
fibonacci: function (n) { | |
var fst = 0.01, | |
sec = 0.01, | |
add, i; | |
for (i = 0; i < n; i++) { | |
add = fst + sec; | |
fst = sec; | |
sec = add; | |
} | |
return add; | |
}, | |
pulse: function (n) { | |
return 0.1; | |
} | |
}; | |
function FT(A, N, Phi) { | |
Phi = Phi || 0; | |
return function (x) { | |
var n = -1, | |
y = 0; | |
while (++n < N) { | |
y += A[n] * Math.sin(2 * Pi * (n + 1) * x + Phi); | |
} | |
return y; | |
}; | |
} | |
function once(fn) { | |
var exec = false; | |
return function () { | |
if (!exec) { | |
exec = true; | |
if (fn) fn(); | |
} | |
}; | |
} | |
var | |
margin = { | |
top: 40, | |
right: 100, | |
bottom: 40, | |
left: 150 | |
}, | |
W = 960, | |
H = 500, | |
w = W - margin.left - margin.right, | |
h = H - margin.top - margin.bottom, | |
radius = 140, | |
theta = 0, | |
xmax = 1.5, | |
rate = 1 / 60, | |
tDomain = d3.range(0, 1.1, 1 / 1000), | |
// trace domain | |
gDomain = d3.range(0, xmax, xmax / 1000), | |
// graph domain | |
C = types.square, | |
// coeffiecients | |
L = 6, | |
// size | |
F = 0.3, | |
// frequence | |
yCirc = d3.scale.linear().domain([-1, 1]).range([h / 2 + radius, h / 2 - radius]), | |
xCirc = d3.scale.linear().domain([-1, 1]).range([0, 2 * radius]), | |
rAxis = d3.scale.linear().domain([0, 1]).range([0, radius]), | |
xAxis = d3.scale.linear().range([radius, W - margin.left]), | |
Fxy, fx, fy, draw, timer, data = []; | |
var graph = d3.svg.line().x(function (d) { | |
return xAxis(d); | |
}).y(function (d) { | |
return yCirc(fy(theta - d)); | |
}); | |
var proj = d3.svg.line().x(function (d) { | |
return xCirc(d.x); | |
}).y(function (d) { | |
return yCirc(d.y); | |
}); | |
var trace = d3.svg.line().x(function (d) { | |
return xCirc(fx(d)); | |
}).y(function (d) { | |
return yCirc(fy(d)); | |
}); | |
function gTransform(d) { | |
return "translate(" + xCirc(d.x) + "," + yCirc(d.y) + ")"; | |
} | |
function hTransform(d) { | |
return "translate(" + xAxis(d.f) + "," + yCirc(0) + ")"; | |
} | |
var svg = d3.select("body").append("svg").attr("width", W).attr("height", H); | |
svg.append("line").attr("class", "axis").attr("y1", margin.top + yCirc(0)).attr("x1", 0).attr("y2", margin.top + yCirc(0)).attr("x2", W); | |
svg.append("line").attr("class", "axis").attr("x1", margin.left + xCirc(0)).attr("y1", 0).attr("x2", margin.left + xCirc(0)).attr("y2", H); | |
var vis = svg.append("g").attr("transform", "translate(" + margin.left + "," + margin.top + ")"); | |
var gPath = vis.append("path").attr("class", "graph"); | |
var tPath = vis.append("path").attr("class", "trace"); | |
var pPath = vis.append("path").attr("class", "proj"); | |
function cache() { | |
var A; | |
if (typeof C === "function") { | |
A = d3.range(1, L + 1).map(C); | |
} else { | |
A = C.slice(0, L); | |
} | |
fx = FT(A, L - 1, Pi / 2); | |
fy = FT(A, L - 1, 0); | |
Fxy = A.map(function (a, i) { | |
return { | |
X: FT(A, i, Pi / 2), | |
Y: FT(A, i, 0), | |
r: Math.abs(a) | |
}; | |
}); | |
} | |
function calc() { | |
if (!Fxy) { | |
cache(); | |
} | |
Fxy.forEach(function (f, i) { | |
var d = data[i] || (data[i] = { | |
x: 0, | |
y: 0, | |
r: 0 | |
}); | |
d.x = f.X(theta); | |
d.y = f.Y(theta); | |
d.r = f.r; | |
d.f = i + 1; | |
}); | |
data.length = Fxy.length; | |
return data; | |
} | |
function coeff() { | |
var co = vis.selectAll(".coeff").data(calc()); | |
// exit | |
co.exit().remove(); | |
// enter | |
var en = co.enter().append("g").attr("class", "coeff"); | |
en.append("circle").attr("class", "circle"); | |
en.append("circle").attr("class", "dot").attr("r", 3); | |
// update | |
co.classed("last", function (d, i) { | |
return i === L - 1; | |
}); | |
co.classed("first", function (d, i) { | |
return i === 0; | |
}); | |
co.select(".circle").attr("r", function (d) { | |
return rAxis(d.r); | |
}); | |
return co; | |
} | |
function drawGraph() { | |
xAxis.domain([0, xmax]); | |
coeff().attr("transform", gTransform); | |
var last = data[data.length - 1]; | |
pPath.attr("d", proj([last, { | |
x: 0, | |
y: last.y | |
}])); | |
gPath.attr("d", graph(gDomain)); | |
tPath.attr("d", trace(tDomain)); | |
} | |
function drawHisto() { | |
xAxis.domain([1, L]); | |
coeff().attr("transform", hTransform); | |
} | |
function toggle(callback) { | |
var tran; | |
tran = (draw === drawGraph) ? hTransform : gTransform; | |
draw = (draw === drawGraph) ? drawHisto : drawGraph; | |
coeff().transition().duration(1000).attr("transform", tran).each("end", once(callback)); | |
} | |
function toggleGraph() { | |
xAxis.domain([0, xmax]); | |
toggle(function () { | |
pPath.classed("hide", false); | |
gPath.classed("hide", false); | |
tPath.classed("hide", false); | |
play(); | |
}); | |
} | |
function toggleHisto() { | |
xAxis.domain([1, L]); | |
pPath.classed("hide", true); | |
gPath.classed("hide", true); | |
tPath.classed("hide", true); | |
pause(); | |
toggle(drawHisto); | |
} | |
function play() { | |
if (timer) { | |
return; | |
} | |
(function loop() { | |
drawGraph(); | |
theta += F * rate; | |
timer = window.setTimeout(loop, rate * 1000); | |
}()); | |
} | |
function pause() { | |
if (timer) { | |
window.clearTimeout(timer); | |
timer = null; | |
} | |
} | |
function redraw() { | |
cache(); | |
draw(); | |
} | |
d3.select("svg").on("click", function () { | |
if (draw === drawHisto) { | |
toggleGraph() | |
} else { | |
toggleHisto(); | |
} | |
}); | |
d3.select("#freq").on("change", function () { | |
F = +this.value; | |
redraw(); | |
}); | |
d3.select("#size").on("change", function () { | |
L = +this.value; | |
redraw(); | |
}); | |
d3.select("#type").on("change", function () { | |
C = types[this.value]; | |
redraw(); | |
}); | |
draw = drawGraph; |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment