Skip to content

Instantly share code, notes, and snippets.

@topologicallytony
Created August 18, 2017 18:07
Show Gist options
  • Save topologicallytony/b6bda7bae8144d7059dd870e7aaf097e to your computer and use it in GitHub Desktop.
Save topologicallytony/b6bda7bae8144d7059dd870e7aaf097e to your computer and use it in GitHub Desktop.
Wave 10
<!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