Last active
October 25, 2016 22:31
-
-
Save fjenner/a3ec8710dec15d5029bd589c1682e7bd to your computer and use it in GitHub Desktop.
Sinusoids
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
<!DOCTYPE html> | |
<html lang="en"> | |
<head> | |
<meta charset="utf-8"> | |
<title>Sinusoid Animation</title> | |
<link type="text/css" rel="stylesheet" href="style.css" /> | |
<script src="https://d3js.org/d3.v3.js"></script> | |
</head> | |
<body> | |
<script src="sinusoids.js"></script> | |
</body> | |
</html> |
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
// Sizes and positions | |
var WIDTH = 500; | |
var HEIGHT = 500; | |
var ORIGIN_X = 0.3 * Math.min(WIDTH, HEIGHT); | |
var ORIGIN_Y = 0.3 * Math.min(WIDTH, HEIGHT); | |
var RADIUS = 0.2 * Math.min(WIDTH, HEIGHT); | |
var SIN_ORIGIN_X = 1.2 * (ORIGIN_X + RADIUS); | |
var COS_ORIGIN_Y = 1.2 * (ORIGIN_Y + RADIUS); | |
var SIN_AXIS_X_LEN = WIDTH - SIN_ORIGIN_X; | |
var COS_AXIS_Y_LEN = HEIGHT - COS_ORIGIN_Y; | |
// Timing and samples | |
var FREQ_HZ = 0.5; | |
var MS_PER_SECOND = 1000.0; | |
var PERIOD = 1.0 / FREQ_HZ | |
var PLOT_TIME = 1.5 * PERIOD; | |
var NUM_POINTS = 100; | |
// Create the SVG canvas | |
var svg = d3.select("body") | |
.append("svg") | |
.attr("width", WIDTH) | |
.attr("height", HEIGHT); | |
// Draw unit circle | |
svg.append("circle") | |
.attr("cx", ORIGIN_X) | |
.attr("cy", ORIGIN_Y) | |
.attr("r", RADIUS) | |
.attr("fill", "none") | |
.attr("stroke", "violet"); | |
// Line from the origin to the unit circle | |
var vector = svg.append("line") | |
.attr("x1", ORIGIN_X) | |
.attr("y1", ORIGIN_Y) | |
.attr("class", "plot_line guide_line composite_line"); | |
// Dot representing the current position around the unit circle | |
var currentPoint = svg.append("circle") | |
.attr("r", 5) | |
.attr("class", "composite_line composite_fill"); | |
// Dot representing the current sin position (y-coordinate) | |
var currentPointSin = svg.append("circle") | |
.attr("cx", SIN_ORIGIN_X) | |
.attr("r", 5) | |
.attr("class", "sin_line sin_fill"); | |
// Dot represnting the current cos position (x-coordinate) | |
var currentPointCos = svg.append("circle") | |
.attr("cy", COS_ORIGIN_Y) | |
.attr("r", 5) | |
.attr("class", "cos_line cos_fill"); | |
// Horizontal guide line indicating the current sin position | |
var sinLine = svg.append("line") | |
.attr("x1", 0) | |
.attr("x2", WIDTH) | |
.attr("class", "plot_line sin_line guide_line"); | |
// Vertical guide line indicating the current cos position | |
var cosLine = svg.append("line") | |
.attr("y1", 0) | |
.attr("y2", HEIGHT) | |
.attr("class", "plot_line cos_line guide_line"); | |
// Scales to map the sin and cos ranges to pixels | |
var cosScaleX = d3.scale.linear() | |
.domain([-1, 1]) | |
.range([-RADIUS, RADIUS]); | |
var sinScaleY = d3.scale.linear() | |
.domain([-1, 1]) | |
.range([RADIUS, -RADIUS]); | |
// Create the fixed axes | |
var cosAxisX = d3.svg.axis().scale(cosScaleX).orient("top").ticks(4); | |
var sinAxisY = d3.svg.axis().scale(sinScaleY).orient("left").ticks(4); | |
// Add the axes to the SVG | |
var circleAxisXG = svg.append("g") | |
.attr("class", "d3_axis") | |
.attr("transform", "translate(" + ORIGIN_X + "," + COS_ORIGIN_Y + ")") | |
.call(cosAxisX); | |
var circleAxisYG = svg.append("g") | |
.attr("class", "d3_axis") | |
.attr("transform", "translate(" + SIN_ORIGIN_X + "," + ORIGIN_Y + ")") | |
.call(sinAxisY); | |
// Scales to map time values to pixels | |
var sinScaleX = d3.scale.linear().range([SIN_AXIS_X_LEN, 0]); | |
var cosScaleY = d3.scale.linear().range([COS_AXIS_Y_LEN, 0]); | |
// Create axes | |
var sinAxisX = d3.svg.axis().scale(sinScaleX).orient("bottom"); | |
var cosAxisY = d3.svg.axis().scale(cosScaleY).orient("left"); | |
// Create helpers for constructing SVG paths | |
var sinPathInterpolator = d3.svg.line().interpolate("linear"); | |
var sinPath = svg.append("path") | |
.attr("class", "plot_line sin_line"); | |
var cosPathInterpolator = d3.svg.line().interpolate("linear"); | |
var cosPath = svg.append("path") | |
.attr("class", "plot_line cos_line"); | |
// Add the initial axes to the SVG | |
var sinAxisXG = svg.append("g") | |
.attr("class", "d3_axis") | |
.attr("transform", "translate(" + SIN_ORIGIN_X + ", " + ORIGIN_Y + ")") | |
.call(sinAxisX); | |
var cosAxisYG = svg.append("g") | |
.attr("class", "d3_axis") | |
.attr("transform", "translate(" + ORIGIN_X + ", " + COS_ORIGIN_Y + ")") | |
.call(cosAxisY); | |
// Establish a callback function for animation | |
var timer = d3.timer(callback); | |
function callback(elapsed_ms) { | |
// Calculate the current position on the unit circle | |
var elapsed = elapsed_ms / MS_PER_SECOND; | |
var theta = 2 * Math.PI * FREQ_HZ * elapsed; | |
var circleX = ORIGIN_X + (RADIUS * Math.cos(theta)); | |
var circleY = ORIGIN_Y - (RADIUS * Math.sin(theta)); | |
// Update the vector | |
vector.attr("x2", circleX); | |
vector.attr("y2", circleY); | |
// Update the three "points" | |
currentPointSin.attr("cy", circleY); | |
currentPointCos.attr("cx", circleX); | |
currentPoint | |
.attr("cx", circleX) | |
.attr("cy", circleY); | |
// Update the horizontal guide line for the sin position | |
sinLine | |
.attr("y1", circleY) | |
.attr("y2", circleY); | |
// Update the vertical guide line for the cos position | |
cosLine | |
.attr("x1", circleX) | |
.attr("x2", circleX); | |
sinPoints = []; | |
cosPoints = []; | |
// Calculate the historical sin and cos plot points | |
for (var i = 0; i < NUM_POINTS; i++) { | |
time = elapsed - (i * parseFloat(PLOT_TIME) / NUM_POINTS); | |
theta = 2 * Math.PI * FREQ_HZ * time; | |
sinPoints.push([ | |
SIN_ORIGIN_X + (SIN_AXIS_X_LEN * i / NUM_POINTS), | |
ORIGIN_Y - (RADIUS * Math.sin(theta)) | |
]); | |
cosPoints.push([ | |
ORIGIN_X + (RADIUS * Math.cos(theta)), | |
COS_ORIGIN_Y + (COS_AXIS_Y_LEN * i / NUM_POINTS) | |
]); | |
} | |
// Update the sin and cos plots | |
sinPath.attr("d", sinPathInterpolator(sinPoints)); | |
cosPath.attr("d", cosPathInterpolator(cosPoints)); | |
// Update the axes | |
var timeDomain = [elapsed - PLOT_TIME, elapsed]; | |
sinScaleX.domain(timeDomain); | |
cosScaleY.domain(timeDomain); | |
sinAxisXG.call(sinAxisX); | |
cosAxisYG.call(cosAxisY); | |
} |
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
svg .plot_line { | |
stroke-width: 1px; | |
fill: none; | |
} | |
svg .guide_line { | |
stroke-opacity: 0.5; | |
} | |
svg .sin_fill { | |
fill: blue; | |
} | |
svg .sin_line { | |
stroke: blue; | |
} | |
svg .cos_fill { | |
fill: red; | |
} | |
svg .cos_line { | |
stroke: red; | |
} | |
svg .composite_fill { | |
fill: violet; | |
} | |
svg .composite_line { | |
stroke: violet; | |
} | |
svg .d3_axis path, | |
svg .d3_axis line { | |
fill: none; | |
stroke: black; | |
shape-rendering: crispEdges; | |
} | |
svg .d3_axis text { | |
font-family: sans-serif; | |
font-size: 10px; | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment