Skip to content

Instantly share code, notes, and snippets.

@HarryStevens
Last active July 23, 2019 21:18
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 HarryStevens/6e007ce52b81c4f14d35c1c549668596 to your computer and use it in GitHub Desktop.
Save HarryStevens/6e007ce52b81c4f14d35c1c549668596 to your computer and use it in GitHub Desktop.
Math and Boxes
license: gpl-3.0

Use the sliders to adjust the number of boxes and the speed of rotation. Drag the "Rotation speed" slider all the way to the left to disable rotation.

Inspired by this YouTube video.

For the black and white version, see this block.

<html>
<head>
<style>
body {
margin: 0;
font-family: "Helvetica Neue", sans-serif;
}
.box {
stroke: #fff;
fill: #3a403d;
}
.label-wrapper {
top: 10px;
position: absolute;
width: 20%;
}
.label-wrapper.rotation-speed {
left: 20%;
}
.label {
width: 100%;
margin-left: 5%;
text-shadow: -3px -3px 1px rgba(255, 255, 255, 0.4), -3px -2px 1px rgba(255, 255, 255, 0.4), -3px -1px 1px rgba(255, 255, 255, 0.4), -3px 0px 1px rgba(255, 255, 255, 0.4), -3px 1px 1px rgba(255, 255, 255, 0.4), -3px 2px 1px rgba(255, 255, 255, 0.4), -3px 3px 1px rgba(255, 255, 255, 0.4), -2px -3px 1px rgba(255, 255, 255, 0.4), -2px -2px 1px rgba(255, 255, 255, 0.4), -2px -1px 1px rgba(255, 255, 255, 0.4), -2px 0px 1px rgba(255, 255, 255, 0.4), -2px 1px 1px rgba(255, 255, 255, 0.4), -2px 2px 1px rgba(255, 255, 255, 0.4), -2px 3px 1px rgba(255, 255, 255, 0.4), -1px -3px 1px rgba(255, 255, 255, 0.4), -1px -2px 1px rgba(255, 255, 255, 0.4), -1px -1px 1px rgba(255, 255, 255, 0.4), -1px 0px 1px rgba(255, 255, 255, 0.4), -1px 1px 1px rgba(255, 255, 255, 0.4), -1px 2px 1px rgba(255, 255, 255, 0.4), -1px 3px 1px rgba(255, 255, 255, 0.4), 0px -3px 1px rgba(255, 255, 255, 0.4), 0px -2px 1px rgba(255, 255, 255, 0.4), 0px -1px 1px rgba(255, 255, 255, 0.4), 0px 1px 1px rgba(255, 255, 255, 0.4), 0px 2px 1px rgba(255, 255, 255, 0.4), 0px 3px 1px rgba(255, 255, 255, 0.4), 1px -3px 1px rgba(255, 255, 255, 0.4), 1px -2px 1px rgba(255, 255, 255, 0.4), 1px -1px 1px rgba(255, 255, 255, 0.4), 1px 0px 1px rgba(255, 255, 255, 0.4), 1px 1px 1px rgba(255, 255, 255, 0.4), 1px 2px 1px rgba(255, 255, 255, 0.4), 1px 3px 1px rgba(255, 255, 255, 0.4), 2px -3px 1px rgba(255, 255, 255, 0.4), 2px -2px 1px rgba(255, 255, 255, 0.4), 2px -1px 1px rgba(255, 255, 255, 0.4), 2px 0px 1px rgba(255, 255, 255, 0.4), 2px 1px 1px rgba(255, 255, 255, 0.4), 2px 2px 1px rgba(255, 255, 255, 0.4), 2px 3px 1px rgba(255, 255, 255, 0.4), 3px -3px 1px rgba(255, 255, 255, 0.4), 3px -2px 1px rgba(255, 255, 255, 0.4), 3px -1px 1px rgba(255, 255, 255, 0.4), 3px 0px 1px rgba(255, 255, 255, 0.4), 3px 1px 1px rgba(255, 255, 255, 0.4), 3px 2px 1px rgba(255, 255, 255, 0.4), 3px 3px 1px rgba(255, 255, 255, 0.4);
}
input {
width: 90%;
margin-left: 5%;
}
</style>
</head>
<body>
<div id="canvas">
<div class="label-wrapper box-count">
<div class="label">Box count</div>
<input class="count" type="range" min="1" max="100" value="50"></input>
</div>
<div class="label-wrapper rotation-speed">
<div class="label">Rotation speed</div>
<input class="speed" type="range" min="0" max="3" value="1" step=".1"></input>
</div>
</div>
<script src="https://d3js.org/d3-array.v2.min.js"></script>
<script src="https://d3js.org/d3-selection.v1.min.js"></script>
<script src="https://d3js.org/d3-interpolate.v1.min.js"></script>
<script src="https://d3js.org/d3-timer.v1.min.js"></script>
<script src="https://d3js.org/d3-scale.v3.min.js"></script>
<script src="https://d3js.org/d3-color.v1.min.js"></script>
<script>
let width,
height,
center,
l,
m,
count = 50,
speed = 1,
rotation = 0;
const svg = d3.select("#canvas").append("svg");
const g = svg.append("g");
d3.selectAll("input").on("input", function(){
count = +d3.select("input.count").property("value");
speed = +d3.select("input.speed").property("value");
draw();
});
d3.timer(_ => {
rotation += speed;
g.attr("transform", "rotate(" + rotation + " " + center[0] + " " + center[1] + ")");
});
size();
onresize = size;
function draw(){
const s = d3.scaleLinear().domain([1, count]).range([1, 10]);
const rainbow = d3.scaleSequential(t => d3.hsl(t * 360, 1, 0.5) + "").domain([0, count]);
let sum = 0;
const boxes = g.selectAll(".box")
.data(d3.range(count + 1));
boxes.exit().remove();
boxes.enter().append("rect")
.attr("class", "box")
.merge(boxes)
.attr("x", d => center[0] - ((m * d / count) / 2))
.attr("y", d => center[1] - ((m * d / count) / 2))
.attr("width", d => m * d / count)
.attr("height", d => m * d / count)
.attr("transform", d => {
sum += d;
const theta = sum / d * Math.PI;
return theta ? `rotate(${theta + (d * (360 / count))} ${center[0]} ${center[1]})` : null;
})
.style("stroke", (d, i) => rainbow(i))
.style("fill", (d, i) => rainbow(i))
.lower();
}
function size(){
width = innerWidth;
height = innerHeight;
center = [width / 2, height / 2];
l = Math.min(width, height);
m = Math.max(width, height);
svg
.attr("width", width)
.attr("height", height);
g
.attr("width", l)
.attr("height", l);
draw();
}
</script>
</body>
</html>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment