Skip to content

Instantly share code, notes, and snippets.

@travisdoesmath
Last active December 28, 2017 20:39
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 travisdoesmath/e23895cd3d155f6526146f647952b97f to your computer and use it in GitHub Desktop.
Save travisdoesmath/e23895cd3d155f6526146f647952b97f to your computer and use it in GitHub Desktop.
Animated Golden Ratio Squares
<!DOCTYPE html>
<meta charset="utf-8">
<style>
body {
background: black;
}
.square {
fill: none;
fill-opacity: 0.75;
/*stroke-opacity: 0.1;*/
/*stroke-width: 1.5px;*/
}
.mainSquare {
fill: none;
}
</style>
<svg width="960" height="500"></svg>
<script src="https://d3js.org/d3.v4.min.js"></script>
<script>
var n_splits = 3;
var width = 960,
height = 500,
color = d3.scaleSequential(d3.interpolateRainbow).domain([0, 2**(n_splits+3)]);
var splitTransformation = function(T) {
var detM = 2 * Math.sqrt(T.A)*Math.cos(T.theta/2)+T.A+1
var new_t_x = (T.t_x * (Math.sqrt(T.A) * Math.cos(T.theta/2) + 1) + T.t_y * Math.sqrt(T.A) * Math.sin(T.theta/2))/detM;
var new_t_y = (T.t_y * (Math.sqrt(T.A) * Math.cos(T.theta/2) + 1) - T.t_x * Math.sqrt(T.A) * Math.sin(T.theta/2))/detM;
var T_split = {
'A':Math.sqrt(T.A),
'theta':T.theta/2,
't_x':new_t_x,
't_y':new_t_y
};
return T_split;
}
var composeTransformations = function(T_1, T_2) {
return {
'A': T_1.A * T_2.A,
'theta': T_1.theta + T_2.theta,
't_x': T_2.A * T_1.t_x * Math.cos(T_2.theta) - T_2.A * T_1.t_y * Math.sin(T_2.theta) + T_2.t_x,
't_y': T_2.A * T_1.t_x * Math.sin(T_2.theta) + T_2.A * T_1.t_y * Math.cos(T_2.theta) + T_2.t_y
}
}
var scale = d3.scaleLinear().domain([0,1]).range([0,130])
var svg = d3.select("svg")
.attr("width", width)
.attr("height", height)
.append("g")
.attr("transform", "translate(50,50)");
var draw = function(angle) {
T = {
'A':Math.sqrt(5)/2 - 0.5,
'theta': angle,
't_x':1,
't_y':1
}
var T_split = T;
for (var i = 0; i < n_splits; i++) {
T_split = splitTransformation(T_split);
}
transformations = [{'A':1, 'theta':0, 't_x': 0, 't_y': 0}];
for (var i = 0; i < 2**(n_splits+3); i++) {
var T_next = composeTransformations(transformations[transformations.length - 1], T_split);
transformations.push(T_next);
}
var squares = svg.selectAll(".square").data(transformations)
squares
.enter()
.append("rect")
.attr("class", "square")
.attr("width", scale(1))
.attr("height", scale(1))
.attr("stroke", function(d, i) { return color(i); })
.attr("stroke-width", function(d, i) { return 2/d.A + "px"; })
//.attr("fill", function(d, i) { return color(i); })
.attr("transform", function(t) {
var a = t.A * Math.cos(t.theta),
b = t.A * Math.sin(t.theta),
c = - t.A * Math.sin(t.theta),
d = t.A * Math.cos(t.theta),
e = scale(t.t_x),
f = scale(t.t_y);
return "matrix(" + a + "," + b + "," + c + "," + d + "," + e + "," + f + ")"; })
squares
.attr("transform", function(t) {
var a = t.A * Math.cos(t.theta),
b = t.A * Math.sin(t.theta),
c = - t.A * Math.sin(t.theta),
d = t.A * Math.cos(t.theta),
e = scale(t.t_x),
f = scale(t.t_y);
return "matrix(" + a + "," + b + "," + c + "," + d + "," + e + "," + f + ")"; })
var goldenTransformations = [{'A':1, 'theta':0, 't_x': 0, 't_y': 0}];
for (var i = 0; i < 2**(n_splits+3); i++) {
var T_next = composeTransformations(goldenTransformations[goldenTransformations.length - 1], T);
goldenTransformations.push(T_next);
}
var goldenSquares = svg.selectAll(".mainSquare").data(goldenTransformations, function(d) { return d.A; });
goldenSquares
.enter()
.append("rect")
.attr("class", "mainSquare")
.attr("width", scale(1))
.attr("height", scale(1))
.attr("stroke", "white")
.attr("stroke-width", function(d, i) { return 2/d.A + "px"; })
.attr("transform", function(t) {
var a = t.A * Math.cos(t.theta),
b = t.A * Math.sin(t.theta),
c = - t.A * Math.sin(t.theta),
d = t.A * Math.cos(t.theta),
e = scale(t.t_x),
f = scale(t.t_y);
return "matrix(" + a + "," + b + "," + c + "," + d + "," + e + "," + f + ")"; })
goldenSquares
.attr("transform", function(t) {
var a = t.A * Math.cos(t.theta),
b = t.A * Math.sin(t.theta),
c = - t.A * Math.sin(t.theta),
d = t.A * Math.cos(t.theta),
e = scale(t.t_x),
f = scale(t.t_y);
return "matrix(" + a + "," + b + "," + c + "," + d + "," + e + "," + f + ")"; })
}
step = 0;
var animate = function() {
step = (step + 1/100) % 2;
draw(-Math.PI / 2 + d3.easeQuadInOut(Math.min(step, 2 - step)) * Math.PI);
}
d3.timer(animate);
</script>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment