|
<!DOCTYPE html> |
|
<html lang="en"> |
|
<head> |
|
<meta charset="utf-8"> |
|
<title>Cantor Set</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> |
|
<div> |
|
Click to iterate |
|
</div> |
|
<div id="container"> |
|
<script type="text/javascript"> |
|
|
|
//Width and height of the visualization. Smaller numbers will zoom in, larger numbers zoom out |
|
var w = 800; |
|
var h = 400; |
|
//padding creates a buffer of white space around the chart to make it a little easier to look at |
|
var padding = 15; |
|
|
|
//Generate Base Dataset |
|
//Start with line from x = 0 t |
|
//Create the scales used to map the set |
|
var xScale = d3.scaleLinear() |
|
.domain([0,1]) |
|
.range([padding, w - padding]); |
|
|
|
//Create a canvas to display the chart on |
|
var svg = d3.select("body").append("svg") |
|
.attr("width", w) |
|
.attr("height", h); |
|
|
|
//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'); |
|
|
|
//This function will iterate the cantor set and is called on mouse click |
|
function step() { |
|
//temp_dataset holds the most recently displayed iteration of the cantor set |
|
temp_dataset = curr_dataset; |
|
//curr_dataset will get loaded with the next iteration of the cantor set |
|
curr_dataset = []; |
|
//What iteration we are on (determined by the number of line segments, which will always be 2x the previous iteration) |
|
var y = Math.log2(temp_dataset.length) + 1; |
|
var len = temp_dataset.length; |
|
//For each line segment, we remove the middle third and load the 2 new line segments into curr_dataset and dataset |
|
for (var i = 0; i < len; i++) { |
|
//get the endpoints of the current line segment |
|
var low = temp_dataset[i][0]; |
|
var high = temp_dataset[i][1]; |
|
//get the endpoints of the new segment |
|
var firstThird_x2 = (((high - low) / 3) + low); |
|
var secondThird_x1 = (((high - low) * (2 / 3)) + low); |
|
//store the new endpoints |
|
curr_dataset.push([low, firstThird_x2, y]); |
|
curr_dataset.push([secondThird_x1, high, y]); |
|
dataset.push([low, firstThird_x2, y]); |
|
dataset.push([secondThird_x1, high, y]); |
|
} |
|
|
|
//rescale the y-axis to accomidate the next iteration which will be plotted on the minimum of the y-axis |
|
var yScale = d3.scaleLinear() |
|
.domain([0,Math.log2(curr_dataset.length)]) |
|
.range([padding, h - padding]); |
|
|
|
//For each line segment, draw the lines |
|
//dataset holds all line segments, not just the current iteration |
|
for (var i = 0; i < dataset.length; i++) { |
|
var line = layer2.append("line") |
|
.attr("x1", xScale(dataset[i][0])) |
|
.attr("x2",xScale(dataset[i][1])) |
|
.attr("y1",yScale(dataset[i][2])) |
|
.attr("y2",yScale(dataset[i][2])) |
|
.attr("stroke", "steelblue") |
|
.attr("stroke-width", "1.5px") |
|
.attr("fill", "none"); |
|
} |
|
|
|
//Display the iteration number |
|
var numIterations = layer1.selectAll(".iter") |
|
.data([0]); |
|
numIterations |
|
.text(y); |
|
numIterations.enter().append("text") |
|
.attr("x", xScale(0)) |
|
.attr("y", yScale(0)) |
|
.text(y) |
|
.attr("font-size", "12px") |
|
.attr("class", "iter"); |
|
numIterations.exit().remove(); |
|
} |
|
|
|
//initialize the datasets |
|
var temp_dataset = []; |
|
//dataset will hold all the line segments, not just the current iteration |
|
//initialize with a line from 0 to 1 |
|
var dataset = [[0,1,0]]; |
|
var curr_dataset = dataset; |
|
var yScale = d3.scaleLinear() |
|
.domain([0,Math.log2(curr_dataset.length)]) |
|
.range([padding, h - padding]); |
|
|
|
//Draw the initial line from 0 to 1 |
|
var line = layer2.append("line") |
|
.attr("x1", xScale(dataset[0][0])) |
|
.attr("x2",xScale(dataset[0][1])) |
|
.attr("y1",yScale(dataset[0][2])) |
|
.attr("y2",yScale(dataset[0][2])) |
|
.attr("stroke", "steelblue") |
|
.attr("stroke-width", "1.5px") |
|
.attr("fill", "none"); |
|
|
|
//Handle click event by clearing all the lines and running step() |
|
d3.select("body") |
|
.on("click", function(){ |
|
svg.selectAll("line").remove(); |
|
step(); |
|
}); |
|
|
|
d3.select("body") |
|
.on("touchstart", function(){ |
|
svg.selectAll("line").remove(); |
|
step(); |
|
}); |
|
</script> |
|
</div> |
|
</body> |
|
</html> |