Created
February 20, 2013 08:01
-
-
Save ubershmekel/4993799 to your computer and use it in GitHub Desktop.
A d3js animation of sine and cosine with different base shapes.
This file contains hidden or 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
<!DOCTYPE html> | |
<html manifest="main.appcache"> | |
<meta charset="utf-8"> | |
<style> | |
.circle, .wave { | |
fill: none; | |
stroke: steelblue; | |
stroke-width: 1.5px; | |
} | |
.circle { | |
stroke: black; | |
} | |
#myshape { | |
stroke: black; | |
stroke-width: 1.5px; | |
fill: none; | |
} | |
.axis { | |
stroke: black; | |
stroke-width: 1px; | |
} | |
.edge { | |
stroke: #ccc; | |
stroke-width: 1px; | |
} | |
#xline { | |
stroke: #f00; | |
opacity: 0.5; | |
stroke-width: 2.0px; | |
} | |
#yline { | |
stroke: #00f; | |
opacity: 0.5; | |
stroke-width: 2.0px; | |
} | |
#dot { | |
fill: black; | |
} | |
#radius { | |
stroke: #0f0; | |
opacity: 0.5; | |
stroke-width: 2.0px; | |
} | |
.filler { | |
fill: white; | |
} | |
#ywave .wave { | |
stroke: #00f; | |
} | |
#xwave .wave { | |
stroke: #f00; | |
} | |
</style> | |
<body> | |
<script src="http://d3js.org/d3.v3.js"></script> | |
<div id="vis"> | |
</div> | |
<script> | |
var INTERVAL = Math.PI / 60; | |
var INTERVALS_OF_FOUR_CYCLES = Math.ceil(Math.PI * 8 / INTERVAL); | |
// Precompute sin and tan waves | |
//var d = d3.range(0, Math.PI / 2 + INTERVAL, INTERVAL), | |
//sinWave = d.map(Math.sin), | |
//tanWave = d.map(Math.tan); | |
// Remove problematic "infinite" point | |
//tanWave.pop(); | |
var w = 600, h = 400, | |
x = d3.scale.linear().domain([-2, 10]).range([0, w]), | |
y = x, | |
r = (function(a, b) { | |
return Math.sqrt(a * a + b * b); | |
})(x.invert(w), y.invert(h)); | |
var vis = d3.select("#vis").append("svg") | |
.attr("width", w).attr("height", h); | |
var jaggyCos = function(t) { | |
// we just want to define from 0 to 2*pi | |
var part = (t / Math.PI) % 2.0; | |
if (part < 1.0) { | |
return 2 * (0.5 - part); | |
} | |
if (part < 2.0) { | |
return 2 * (-1.5 + part); | |
} | |
console.log('Error, should be unreachable ' + t + ' - ' + part); | |
return part; | |
}; | |
var jaggySin = function(t) { | |
var part = (t / Math.PI) % 2.0; | |
if (part < 0.5) { | |
return 2 * part; | |
} | |
if (part < 1.5) { | |
return 2 * (1.0 - part); | |
} | |
if (part < 2.0) { | |
return 2 * (-2.0 + part); | |
} | |
console.log('Error, should be unreachable ' + t + ' - ' + part); | |
//return part; | |
}; | |
var sincify = function(t) { | |
// [0, 1] -> [0, 1] like a sin function | |
return (1 + Math.sin(-Math.PI / 2 + t * Math.PI)) / 2; | |
} | |
var squareCos = function(t) { | |
// square Y | |
var part = (t / Math.PI) % 2.0; | |
if (part < 0.25) { | |
return 1.0; | |
} | |
if (part < 0.75) { | |
var segment = (part - 0.25) * 2; | |
return 1.0 - sincify(segment) * 2; | |
} | |
if (part < 1.25) { | |
//var segment = (part - 0.75) * 2; | |
return -1.0; | |
} | |
if (part < 1.75) { | |
var segment = (part - 1.25) * 2; | |
return -1.0 + sincify(segment) * 2; | |
} | |
if (part < 2.0) { | |
return 1.0; | |
} | |
console.log('Error, should be unreachable ' + t + ' - ' + part); | |
return part; | |
} | |
var squareSin = function(t) { | |
// X | |
var part = (t / Math.PI) % 2.0; | |
if (part < 0.25) { | |
return 4 * part; | |
} | |
if (part < 0.75) { | |
return 1.0; | |
} | |
if (part < 1.25) { | |
return 1.0 + 4 * (0.75 - part); | |
} | |
if (part < 1.75) { | |
return -1.0; | |
} | |
if (part < 2.0) { | |
return -1.0 + 4 * (part - 1.75); | |
} | |
console.log('Error, should be unreachable ' + t + ' - ' + part); | |
}; | |
// Imagine that alpha is from the Y Axis towards the positive X axis | |
var xFunc = Math.sin; | |
var yFunc = Math.cos; | |
//yFunc = Math.acos; | |
//xFunc = jaggySin; | |
//yFunc = jaggyCos; | |
//xFunc = squareSin; | |
//yFunc = squareCos; | |
var polarCircle = function(t) { | |
return 1; | |
} | |
var quarterCircle = Math.PI / 2; | |
var eigthCircle = Math.PI / 4; | |
var squareDiagonal = Math.sqrt(2) / 2; | |
var polarDiamond = function(t) { | |
var part = (t % quarterCircle) - quarterCircle / 2; | |
return squareDiagonal / Math.cos(part); | |
} | |
var polarSquare = function(t) { | |
var part = ((t + eigthCircle) % quarterCircle) - eigthCircle; | |
return squareDiagonal / Math.cos(part); | |
} | |
xPolar = function(polarFunc) { | |
return function(t) { | |
return polarFunc(t) * Math.sin(t) | |
} | |
} | |
yPolar = function(polarFunc) { | |
return function(t) { | |
return polarFunc(t) * Math.cos(t) | |
} | |
} | |
var polarFunc; | |
polarActive = polarCircle; | |
polarActive = polarSquare; | |
xFunc = xPolar(polarActive); | |
yFunc = yPolar(polarActive); | |
/* | |
vis.append("g") | |
.attr("id", "xwave") | |
.attr("width", w) | |
.attr("height", h) | |
//.attr("transform", "translate("+x(1)+")") | |
.selectAll("path") | |
.data([d3.range(0, 8 * Math.PI + INTERVAL, INTERVAL).map(yFunc)]) | |
.enter().append("path") | |
.attr("class", "wave") | |
.attr("d", d3.svg.line() | |
.x(function(d, i) { return x(i * INTERVAL) }) | |
.y(function(d) { return y(d) })); | |
*/ | |
/*var yWave = vis.append("g") | |
.attr("id", "ywave") | |
.attr("width", w) | |
.attr("height", h); | |
yWave.selectAll("path") | |
.data([d3.range(0, 8 * Math.PI + INTERVAL, INTERVAL).map(xFunc)]) | |
.enter().append("path") | |
.attr("class", "wave") | |
.attr("d", d3.svg.line() | |
.x(function(d) { return x(d) }) | |
.y(function(d, i) { return y(i * INTERVAL) - y(0) }))*/ | |
var yWave = vis.append("g") | |
.attr("id", "ywave") | |
.attr("width", w) | |
.attr("height", h); | |
var yWaveData = []; | |
var yPath = yWave.selectAll("path") | |
.data([yWaveData]); | |
yPath.enter().append("path") | |
.attr("class", "wave"); | |
var xWave = vis.append("g") | |
.attr("id", "xwave") | |
.attr("width", w) | |
.attr("height", h); | |
var xWaveData = []; | |
var xPath = xWave.selectAll("path") | |
.data([xWaveData]); | |
xPath.enter().append("path") | |
.attr("class", "wave"); | |
// hides the waves under the circle shape | |
var filler = function(w, h) { | |
return vis.append("rect") | |
.attr("class", "filler") | |
.attr("width", w) | |
.attr("height", h); | |
} | |
var lineWidth = 1.5; | |
//filler(x(1) + lineWidth, y(1) + lineWidth); | |
vis.append("g") | |
.attr("id", "myshape") | |
.attr("width", w) | |
.attr("height", h) | |
.selectAll("path") | |
.data([d3.range(0, 2 * Math.PI, INTERVAL)]) | |
.enter().append("path") | |
.attr("class", "myshape") | |
.attr("d", d3.svg.line() | |
.x(function(d, i) { return x(xFunc(d)) }) | |
.y(function(d) { return y(yFunc(d)) })); | |
var line = function(e, x1, y1, x2, y2) { | |
return e.append("line") | |
.attr("class", "line") | |
.attr("x1", x1) | |
.attr("y1", y1) | |
.attr("x2", x2) | |
.attr("y2", y2); | |
} | |
var axes = function(cx, cy, cls) { | |
cx = x(cx); cy = y(cy); | |
line(vis, cx, 0, cx, h).attr("class", cls || "line") | |
line(vis, 0, cy, w, cy).attr("class", cls || "line") | |
} | |
axes(0, 0, "axis"); | |
axes(1, 1, "edge"); | |
var dotRadius = 5 | |
line(vis, 0, y(0), w, y(0)) | |
.attr("id", "xline") | |
line(vis, x(0), 0, x(0), h) | |
.attr("id", "yline") | |
var radiusLine = line(vis, x(0), y(0), x(0), y(1)) | |
.attr("id", "radius") | |
vis.append("circle") | |
.attr("class", "circle") | |
.attr("id", "dot") | |
.attr("cx", x(0)) | |
.attr("cy", y(0)) | |
.attr("r", dotRadius) | |
var offset = 0; | |
var elapsedRadians = 0; | |
var lastTime = 0; | |
var milisecPerRadian = 500; | |
d3.timer(function(elapsed) { | |
elapsedRadians = elapsed / milisecPerRadian; | |
offset = elapsedRadians % (2 * Math.PI); | |
/*lastTime = elapsed; | |
if (offset > 2 * Math.PI) { | |
offset = 0; | |
}*/ | |
vis.selectAll("#xwave") //, #tanwave") | |
.attr("transform", "translate(" + x(elapsedRadians - 1) + ",0)") | |
vis.selectAll("#ywave") | |
.attr("transform", "translate(0," + y(elapsedRadians - 1) + ")") | |
var xline = y(yFunc(offset)) - y(0); | |
var yline = x(xFunc(offset)) - x(0); | |
var nowX = x(xFunc(offset)); | |
var nowY = y(yFunc(offset)); | |
yWaveData.push({x: nowX, y: y(-elapsedRadians)}); | |
xWaveData.push({x: x(-elapsedRadians), y: nowY}); | |
if(yWaveData.length > INTERVALS_OF_FOUR_CYCLES) { | |
yWaveData.shift(); | |
xWaveData.shift(); | |
} | |
xPath.attr("d", d3.svg.line() | |
.x(function(d) { return d.x }) | |
.y(function(d) { return d.y })); | |
yPath.attr("d", d3.svg.line() | |
.x(function(d) { return d.x }) | |
.y(function(d) { return d.y })); | |
radiusLine.attr("x2", nowX); | |
radiusLine.attr("y2", nowY); | |
vis.selectAll("#dot") //, #tanline") | |
.attr("transform", "translate(" + yline + "," + xline + ")") | |
//.attr("transform", "rotate(" + (180 - offset * 180 / Math.PI) + ","+x(0)+","+y(0)+")") | |
vis.select("#xline") | |
.attr("transform", "translate(0," + xline + ")"); | |
vis.select("#yline") | |
.attr("transform", "translate(" + yline + ",0)"); | |
}); | |
</script> | |
</body> | |
</html> |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment