Last active
December 28, 2017 20:39
-
-
Save travisdoesmath/e23895cd3d155f6526146f647952b97f to your computer and use it in GitHub Desktop.
Animated Golden Ratio Squares
This file contains hidden or 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> | |
<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