Skip to content

Instantly share code, notes, and snippets.

@topologicallytony
Last active January 6, 2017 03:31
Show Gist options
  • Save topologicallytony/9e32ba064d2f552bad456d3fe3ca106a to your computer and use it in GitHub Desktop.
Save topologicallytony/9e32ba064d2f552bad456d3fe3ca106a to your computer and use it in GitHub Desktop.
Achimedes Approximation to Pi
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<title>Archimedes Pi</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">
.inner {
fill: none;
stroke: steelblue;
stroke-width: 1.5px;
}
.outer {
fill: none;
stroke: steelblue;
stroke-width: 1.5px;
}
/*************************************************/
/********************Axis*************************/
/*************************************************/
.axis path,
.axis line {
fill: none;
stroke: black;
shape-rendering: crispEdges;
}
.axis text {
font-family: sans-serif;
font-size: 11px;
}
</style>
</head>
<body>
<div>
Click to add sides
</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 = 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 = 15;
//Generate Base Dataset
//Start with Triangle
var numDataPoints = 3;
//Create the scales used to map datapoints
var xScale = d3.scaleLinear()
.domain([-2,2])
.range([padding, w - padding]);
var yScale = d3.scaleLinear()
.domain([-2,2])
.range([h - padding, padding]);
//Create a canvas to display the chart on
var svg = d3.select("div#container")
.append("div")
.classed("svg-container", true)
.append("svg")
.attr("width", w)
.attr("height", h)
// .attr("viewBox", "0 0 " + w + " " + h)
.attr("id", "vis");
//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');
//Create line function to plot the data
var line = d3.line()
.x(function(d) { return xScale(d[0]);})
.y(function(d) { return yScale(d[1]);});
//Define axes
//var xAxis = d3.axisBottom()
// .scale(xScale)
// .ticks(5);
//var yAxis = d3.axisLeft()
// .scale(yScale)
// .ticks(4);
//Create axes
//svg.append("g")
// .attr("class", "axis")
// .attr("transform", "translate(0," + (h - padding) + ")")
// .call(xAxis);
//svg.append("g")
// .attr("class", "axis")
// .attr("transform", "translate(" + padding + ",0)")
// .call(yAxis);
function createPolygons(numDataPoints) {
//This will hold the end ponits of the circle in polar coordinates
var inner_data = [];
var outer_data = [];
console.log(inner_data);
for (var i = 0; i <= (numDataPoints); i++) {
//Partition [0,2Pi] into buckets
var theta = ((i*2*Math.PI)/(numDataPoints)) + ((Math.PI)/(2));
//Initialize the input as random numbers. This will iterate over time, so it doesn't matter what it holds
var inner_r = 1;
var outer_r = (1/Math.cos(Math.PI/numDataPoints));
var inner_x = inner_r * Math.cos(theta);
var inner_y = inner_r * Math.sin(theta);
var outer_x = outer_r * Math.cos(theta);
var outer_y = outer_r * Math.sin(theta);
inner_data.push([inner_x, inner_y]);
outer_data.push([outer_x, outer_y]);
}
var inner_line = layer2.selectAll(".inner")
.data(inner_data, function(d){ return numDataPoints;});
inner_line
.attr("class", "hide");
inner_line
.enter()
.append("path")
.datum(inner_data)
.attr("d", line)
.attr("class", "inner");
inner_line.exit().remove();
var outer_line = layer2.selectAll(".outer")
.data(inner_data, function(d){ return numDataPoints;});
outer_line
.attr("class", "hide");
outer_line
.enter()
.append("path")
.datum(outer_data)
.attr("d", line)
.attr("class", "outer");
outer_line.exit().remove();
var avg = layer1.selectAll(".avg")
.data([0]);
avg.text("Pi is approximately "+ ((numDataPoints * Math.sin(Math.PI / numDataPoints)) + (numDataPoints * Math.tan(Math.PI / numDataPoints)))/2);
avg.enter().append("text")
.attr("x", xScale(0))
.attr("y", yScale(0))
.text("Pi is approximately " + numDataPoints * Math.tan(Math.PI / numDataPoints))
.attr("font-size", "12px")
.attr("text-anchor", "middle")
.attr("class", "avg");
avg.exit().remove();
var min = layer1.selectAll(".min")
.data([0]);
min.text("Lower "+ numDataPoints * Math.sin(Math.PI / numDataPoints));
min.enter().append("text")
.attr("x", xScale(0))
.attr("y", yScale(-.85))
.text("Lower " + numDataPoints * Math.tan(Math.PI / numDataPoints))
.attr("font-size", "12px")
.attr("text-anchor", "middle")
.attr("class", "min");
min.exit().remove();
var max = layer1.selectAll(".max")
.data([0]);
max.text("Upper "+ numDataPoints * Math.tan(Math.PI / numDataPoints));
max.enter().append("text")
.attr("x", xScale(0))
.attr("y", yScale(1.15))
.text("Upper " + numDataPoints * Math.tan(Math.PI / numDataPoints))
.attr("font-size", "12px")
.attr("text-anchor", "middle")
.attr("class", "max");
max.exit().remove();
var numSides = layer1.selectAll(".sides")
.data([0]);
numSides.text(numDataPoints + " Sides");
numSides.enter().append("text")
.attr("x", xScale(-1.5))
.attr("y", yScale(1.5))
.text(numDataPoints + " Sides")
.attr("font-size", "12px")
// .attr("text-anchor", "middle")
.attr("class", "sides");
numSides.exit().remove();
}
var circle = layer1.selectAll("circle")
.data([0])
.enter()
.append("circle")
.attr("cx", xScale(0))
.attr("cy", yScale(0))
.attr("r", xScale(1) - xScale(0))
.attr("stroke", "steelblue")
.attr("stroke-width", "1.5px")
.attr("fill", "none");
createPolygons(3);
d3.select("body")
.on("click", function(){
numDataPoints++;
createPolygons(numDataPoints);
});
d3.select("body")
.on("touchstart", function(){
numDataPoints++;
createPolygons(numDataPoints);
});
</script>
</div>
</body>
</html>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment