Skip to content

Instantly share code, notes, and snippets.

@HarryStevens
Last active Jul 8, 2019
Embed
What would you like to do?
Math and Boxes II
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 rainbow 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>
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]);
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-width", d => s(d))
.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