Created
August 18, 2017 18:07
-
-
Save topologicallytony/b6bda7bae8144d7059dd870e7aaf097e to your computer and use it in GitHub Desktop.
Wave 10
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>Wave 10</title> | |
<!-- D3.js --> | |
<script src="https://d3js.org/d3.v4.min.js"></script> | |
<!-- Latest compiled and minified CSS --> | |
<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.2/css/bootstrap.min.css"> | |
<style type="text/css"> | |
</style> | |
</head> | |
<body> | |
click and drag to change visual | |
<div id=svgContainer></div> | |
<script type="text/javascript"> | |
//This visualization demonstrates the importance of proper sampling | |
//The visual starts off with a sine wave sampled by a fixed number of points | |
//The amplitude of the sine wave slowly increases | |
//This is visually interesting because of all the patterns that emerge, and the visual will eventually restart (even though the function it is sampled off of is completely different!) | |
//Width and height of the visualization. Smaller numbers will zoom in, larger numbers zoom out | |
var w = 500; | |
var h = 500; | |
//padding creates a buffer of white space around the chart to make it a little easier to look at | |
var padding = 20; | |
//This will hold the sampled function's data | |
var dataset = []; | |
var x = []; | |
var y = []; | |
var curr_t = 0; | |
//how finely will the function be sampled | |
var numDataPoints = 720; | |
//initialize amplitude of the function | |
var freq = 0; | |
var freq2 = 0; | |
//size of the circles, more data points should have smaller radii | |
var radius = 3; | |
//define y axis (domain of function) | |
//Note: if domain is 2pi then animation will reset after [numDataPoints] iterations | |
var y_min = -1 * Math.PI; | |
var y_max = 1 * Math.PI; | |
//define x axis domain (range of function) | |
//var x_min = 2; | |
//var x_max = -2; | |
var x_min = 2*Math.exp(y_max); | |
var x_max = -2 * Math.exp(y_max); | |
//Generate a random sample of the space | |
for (var i = 1; i <= numDataPoints; i++) { | |
//Partition interval | |
var curr_t = ((i * (y_max - y_min)) / (numDataPoints)) + y_min; | |
//determine function's value at current point | |
//var curr_x = Math.exp(curr_y / 2) * Math.sin(amp*curr_y); | |
//var curr_x = Math.exp(Math.abs(curr_y) - 5) * Math.sin(amp*curr_y); | |
var curr_x = Math.cos(curr_t); | |
var curr_y = Math.sin(curr_t); | |
dataset.push([curr_x, curr_y, curr_t]); | |
} | |
//Create x & y scales to convert points to proper svg canvas positions | |
var xScale = d3.scaleLinear() | |
.domain([-4, 4]) | |
.range([padding, w + padding]); | |
var yScale = d3.scaleLinear() | |
.domain([-4, 4]) | |
.range([h + padding, padding]); | |
//Define the format for the number | |
var format = d3.format(",.2f"); | |
//Create a canvas to display the chart on | |
var svg = d3.select("body") | |
.append("svg") | |
.attr("width", w) | |
.attr("height", h); | |
//Make the background of the canvas white | |
svg.append("rect") | |
.attr("width", "100%") | |
.attr("height", "100%") | |
.attr("fill", "#fff"); | |
//Create group elements to layer the svg | |
//This is an easy way to make sure things you want on top are on top, and things you want behind stay behind | |
var layer1 = svg.append('g'); | |
var layer2 = svg.append('g'); | |
//'draw' the function using points sampled at a regular interval | |
function drawPts() { | |
var pts = layer2 | |
.selectAll(".points") | |
.data(dataset); | |
pts | |
.enter() | |
.append("circle") | |
.attr("class", "points") | |
.attr("cy", function(d){ | |
return yScale((Math.cos(d[2] * freq) * Math.pow(Math.cos((freq2 * d[2]) / 2), 2) + 1.5) * Math.sin(d[2])); | |
}) | |
.attr("cx", function(d){ | |
return xScale((Math.cos(d[2] * freq) * Math.pow(Math.cos((freq2 * d[2]) / 2), 2) + 1.5) * Math.cos(d[2])); | |
}) | |
.attr("r", radius) | |
.attr("fill","steelblue"); | |
pts | |
.attr("cy", function(d){ | |
return yScale((Math.cos(d[2] * freq) * Math.pow(Math.cos((freq2 * d[2]) / 2), 8) + 1.5) * Math.sin(d[2])); | |
}) | |
.attr("cx", function(d){ | |
return xScale((Math.cos(d[2] * freq) * Math.pow(Math.cos((freq2 * d[2]) / 2), 8) + 1.5) * Math.cos(d[2])); | |
}); | |
} | |
//display a counter to show the frequency of cosine function | |
function counter(){ | |
var freq1_ctr = layer2.selectAll(".freq1") | |
.data([0]); | |
freq1_ctr | |
.text("Freq1: " + format(freq)); | |
freq1_ctr.enter().append("text") | |
.attr("x", 2 * padding) | |
.attr("y", 2 * padding) | |
.text("Freq1: " + freq) | |
.attr("font-size", "12px") | |
.attr("class", "freq1") | |
freq1_ctr.exit().remove(); | |
var freq2_ctr = layer2.selectAll(".freq2") | |
.data([0]); | |
freq2_ctr | |
.text("Freq2: " + format(freq2)); | |
freq2_ctr.enter().append("text") | |
.attr("x", 2 * padding) | |
.attr("y", 3 * padding) | |
.text("Freq2: " + freq2) | |
.attr("font-size", "12px") | |
.attr("class", "freq2") | |
freq2_ctr.exit().remove(); | |
} | |
//initialize the animation | |
drawPts(); | |
counter(); | |
var g = d3.select("body").select("svg") | |
.call(d3.drag() | |
.on("drag", dragged)); | |
function dragged(){ | |
freq += (numDataPoints / 20) * d3.event.dx / w; | |
freq2 += -10 * d3.event.dy / h; | |
drawPts(); | |
counter(); | |
} | |
</script> | |
</body> | |
</html> |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment