Skip to content

Instantly share code, notes, and snippets.

@tophtucker
Last active September 15, 2018 21:42
Show Gist options
  • Star 2 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save tophtucker/45e8112e70ea9192c8d666dba6fe79fc to your computer and use it in GitHub Desktop.
Save tophtucker/45e8112e70ea9192c8d666dba6fe79fc to your computer and use it in GitHub Desktop.
Diagonal
height: 960

Someone just wanted to make a grid of squares animate in diagonally. This takes a series of numbers and maps them to rows and columns using triangular numbers. (It might’ve been more straightforward to just invert the Cantor pairing function.)

I added little fractions text, so it doubles as a visual proof of the countability of the rationals! And then I made two, so it doubles as a visual proof of the fact that the sum of consecutive triangular numbers is a square number!

Refresh for a different pair of consecutive triangle numbers.

See also:

<!DOCTYPE html>
<meta charset="utf-8">
<style>
* {
box-sizing: border-box;
}
body {
margin: 0;
position: relative;
font-family: sans-serif;
}
div {
background: black;
border: 1px solid white;
position: absolute;
color: rgba(255,255,255,.5);
font-size: 16px;
text-align: center;
overflow: hidden;
}
</style>
<body></body>
<script src="//d3js.org/d3.v4.0.0-alpha.35.min.js" charset="utf-8"></script>
<script>
var pageWidth = 960;
var gridSize = 960/Math.ceil(Math.random()*24);
var triangularNumber = (960/gridSize)-1;
var delay = 50;
// Render warm upper larger triangle
renderTriangle(
d3.select('body').append('section'),
triangularNumber + 1,
d3.scaleWarm().domain([0, getTriangularNumber(triangularNumber+1)*2]),
function(d) { return d; }
);
// Render cool lower smaller triangle
renderTriangle(
d3.select('body').append('section'),
triangularNumber,
d3.scaleCool().domain([getTriangularNumber(triangularNumber)*2, 0]),
function(d) { return triangularNumber - d; }
);
function renderTriangle(selection, triangularNumber, color, offsetter) {
// offsetter just lets us choose whether to count from upper left or bottom right
if(offsetter === undefined) offsetter = function(d) { return d; };
if(color === undefined) color = d3.scaleRainbow();
selection.selectAll('div')
.data(d3.range(getTriangularNumber(triangularNumber)).map(getUpperTriangleCoordinates))
.enter()
.append('div')
.style('width', gridSize+'px')
.style('height', gridSize+'px')
.style('background-color', function(d,i) { return color(i); })
.style('font-size', gridSize/4+'px')
.style('line-height', gridSize+'px')
.style('left', function(d,n) { return gridSize * offsetter(d.column) + 'px'; })
.style('top', function(d,n) { return gridSize * offsetter(d.row) + 'px'; })
.style('opacity', 0)
.text(function(d,n) { return (d.row + 1) + '/' + (d.column + 1); })
.transition()
.delay(function(d,n) { return n * delay; })
.style('opacity', 1);
}
// https://en.wikipedia.org/wiki/Triangular_number
function getTriangularNumber(n) {
return n * (n + 1) / 2;
}
function getTriangularNumberInverse(n) {
return (1/2) * (-1 + Math.sqrt(8 * n + 1));
}
/*
0 2 5
1 4
3
*/
function getUpperTriangleCoordinates(n) {
var i = Math.floor(getTriangularNumberInverse(n));
return {
n: n,
row: i - (n - getTriangularNumber(i)),
column: n - getTriangularNumber(i)
}
}
// Below, an unused alternative!
/*
0
1 2
3 4 5
*/
function getLowerTriangleCoordinates(n) {
var i = Math.floor(getTriangularNumberInverse(n));
return {
n: n,
row: i,
column: n - getTriangularNumber(i)
}
}
</script>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment