Skip to content

Instantly share code, notes, and snippets.

@fjenner
Last active October 25, 2016 22:31
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save fjenner/a3ec8710dec15d5029bd589c1682e7bd to your computer and use it in GitHub Desktop.
Save fjenner/a3ec8710dec15d5029bd589c1682e7bd to your computer and use it in GitHub Desktop.
Sinusoids
<!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>
// 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);
}
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