Skip to content

Instantly share code, notes, and snippets.

@agware
Last active August 16, 2019 04:55
Show Gist options
  • Save agware/ef95a6796905bfbe85953187837c3a10 to your computer and use it in GitHub Desktop.
Save agware/ef95a6796905bfbe85953187837c3a10 to your computer and use it in GitHub Desktop.
Star
license: gpl-3.0

Credit

This animation is based on a pattern 'Sixfold Pattern 1' available in 'Islamic Geometric Design' by Eric Broug.

<!DOCTYPE html>
<head>
<meta charset="utf-8">
<style>
line, circle {
stroke: #000;
stroke-width: 1px;
}
circle {
fill-opacity: 0;
stroke-opacity: 1;
}
.construction {
stroke-dasharray: 2,5;
}
.final {
stroke-width: 3px;
}
</style>
</head>
<body>
<div id="container"></div>
<script src="https://d3js.org/d3.v5.min.js"></script>
<script>
const margin = {top: 50, right: 50, bottom: 50, left: 50}
const height = Math.max(500, window.innerHeight - margin.top - margin.bottom);
const width = Math.max(height, window.innerWidth - margin.left - margin.right);
let svg = d3.select('#container').append('svg')
.attr('width', width + margin.left + margin.right)
.attr('height', height + margin.top + margin.bottom);
let g = svg.append('g')
.attr('transform', 'translate(' + (width/2 + margin.right) + ',' + (height/2 + margin.top) + ')');
const r = {outer: height/2, padding: height/10};
let circleData = [];
let lineData = [];
// Step 0 - draw the circle
circleData.push({step: 0, category: 'construction', r: r.outer - r.padding});
// Step 1 - split the circle into 12 parts
let lineNum = 12;
for(let i = 0; i < lineNum; i++) {
lineData.push({step: 1, category: 'construction', x1: 0, y1: 0, x2: r.outer*Math.sin(2*i*Math.PI/lineNum),
y2: r.outer*Math.cos(2*i*Math.PI/lineNum)});
}
// Step 2 - draw a hexagon (i.e. draw lines between the intersection of even numbered lines from step 1 and the circle)
lineNum = 6;
for(let i = 0; i < lineNum; i++) {
lineData.push({step: 2, category: 'construction', ...addPoints(r.outer-r.padding, i, lineNum, 0)});
}
// Step 3 - draw two triangles in the circle
lineNum = 3;
let offset = Math.PI/3;
for(let i = 0; i < lineNum; i++) {
lineData.push({step: 3, category: 'final', ...addPoints(r.outer-r.padding, i, lineNum, 0)});
lineData.push({step: 3, category: 'final', ...addPoints(r.outer-r.padding, i, lineNum, offset)});
}
function addPoints(r, i, lineNum, offset) {
return {x1: r*Math.sin(2*i*Math.PI/lineNum + offset),
y1: r*Math.cos(2*i*Math.PI/lineNum + offset),
x2: r*Math.sin(2*(i+1)*Math.PI/lineNum + offset),
y2: r*Math.cos(2*(i+1)*Math.PI/lineNum + offset)}
}
// Generate the actual animations
let duration = 1000;
g.selectAll('circle')
.data(circleData).enter()
.append('circle')
.attr('class', d => d.category)
.transition().duration(duration).delay(d => d.step*duration)
.attr('r', d => d.r);
g.selectAll('line')
.data(lineData).enter()
.append('line')
.attr('class', d => d.category)
.attr('x1', d => d.x1)
.attr('y1', d => d.y1)
.attr('x2', d => d.x1)
.attr('y2', d => d.y1)
.transition().duration(duration).delay(d => d.step*duration)
.attr('x2', d => d.x2)
.attr('y2', d => d.y2);
</script>
</body>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment