This animation is based on a pattern available in 'Islamic Geometric Design' by Eric Broug.
xxxxxxxxxx
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Sixfold Pattern 3</title>
<style>
line {
stroke: #000;
stroke-width: 1px;
}
circle, rect {
fill-opacity: 0;
stroke: #000;
stroke-width: 1px;
stroke-opacity: 1;
}
.construction {
stroke-dasharray: 2,5;
}
.final {
stroke-width: 3px;
}
</style>
</head>
<body>
<script src="https://d3js.org/d3.v4.min.js"></script>
<script src="utils.js" type="text/javascript"></script>
<script>
const height = 500;
const width = 960;
const r = 200;
const duration = 1500;
let svg = d3.select('body').append('svg')
.attr('height', height)
.attr('width', width)
.attr('overflow', 'hidden');
let g = svg.append('g')
.attr('transform', 'translate(' + (width/2) + ',' + (height/2) +')');
let start = Date.now();
let count = 0;
d3.timer(animate);
function animate () {
let t = (Date.now() - start)/(duration+200);
if (t > count) {
switch(count) {
case 0:
step0();
break;
case 1:
step1();
break;
case 2:
step2();
break;
case 3:
step3();
break;
case 4:
step4();
break;
case 5:
step5();
break;
case 6:
step6();
break;
case 7:
step7();
break;
case 8:
step8();
break;
case 11:
g.selectAll('*').remove();
count = -1;
start = Date.now();
break;
}
count += 1;
}
}
function step0 () {
g.append('circle')
.attr('id', 'step1Circle')
.classed('construction', true)
.transition()
.duration(duration)
.attr('r', r);
}
function step1 () {
const lineNum = 12;
const lineOffset = 15;
for (let i = 0; i < lineNum; i++) {
g.append('line')
.attr('id', 'step1Line' + i)
.classed('construction', true)
.transition()
.duration(duration)
.attr('x2', (r+lineOffset) * Math.sin((2*Math.PI/lineNum)*i))
.attr('y2', (r+lineOffset) * Math.cos((2*Math.PI/lineNum)*i));
}
}
function step2 () {
const lineNum = 6;
for (let i = 0; i < lineNum; i++) {
let intersect = findCircleIntersection(d3.select('#step1Line' + ((i*2) + 1) % (lineNum*2)), d3.select('#step1Circle'));
let intersect2 = findCircleIntersection(d3.select('#step1Line' + ((i+1)*2 + 1) % (lineNum*2)), d3.select('#step1Circle'));
let points = {'x1': intersect.x, 'y1': intersect.y, 'x2': intersect2.x, 'y2': intersect2.y};
addLine(points, 2, i);
}
}
function step3 () {
const lineNum = 6;
for (let i = 0; i < lineNum; i++) {
let intersect = findLineIntersection(d3.select('#step2Line' + i), d3.select('#step1Line' + (i*2 + 1) % (lineNum*2)));
let intersect2 = findLineIntersection(d3.select('#step2Line' + (i+2) % lineNum), d3.select('#step1Line' + ((i+2)*2 + 1) % (lineNum*2)));
let points = {'x1': intersect.x, 'y1': intersect.y, 'x2': intersect2.x, 'y2': intersect2.y};
addLine(points, 3, i);
}
}
function step4 () {
let intersect = findLineIntersection(d3.select('#step2Line0'), d3.select('#step1Line2'));
let length = Math.round(Math.sqrt(Math.pow(intersect.x, 2) + Math.pow(intersect.y, 2))*1000)/1000;
g.append('circle')
.attr('id', 'step4Circle')
.classed('construction', true)
.transition()
.duration(duration)
.attr('r', length);
}
function step5 () {
const lineNum = 6;
for (let i = 0; i < lineNum; i++) {
let intersect = findLineIntersection(d3.select('#step3Line' + i), d3.select('#step1Line' + ((i+1)*2) % (lineNum*2)));
let intersect2 = findLineIntersection(d3.select('#step3Line' + i), d3.select('#step1Line' + ((i+2)*2) % (lineNum*2)));
let points = {'x1': intersect.x, 'y1': intersect.y, 'x2': intersect2.x, 'y2': intersect2.y};
addLine(points, 5, i);
d3.select('#step5Line' + i)
.classed('construction', false)
.classed('final', true);
}
}
function step6 () {
const lineNum = 6;
for (let i = 0; i < lineNum; i++) {
let intersect = findLineIntersection(d3.select('#step2Line' + i), d3.select('#step1Line' + ((i+1)*2) % (lineNum*2)));
let intersect2 = findLineIntersection(d3.select('#step2Line' + (i+1) % lineNum), d3.select('#step1Line' + ((i+2)*2) % (lineNum*2)));
let points = {'x1': intersect.x, 'y1': intersect.y, 'x2': intersect2.x, 'y2': intersect2.y};
addLine(points, 6, i);
d3.select('#step6Line' + i)
.classed('construction', false)
.classed('final', true);
}
}
function step7 () {
const lineNum = 6;
for (let i = 0; i < lineNum; i++) {
let intersect = findLineIntersection(d3.select('#step6Line' + i), d3.select('#step3Line' + (i+1) % lineNum));
let intersect2 = findLineIntersection(d3.select('#step6Line' + (i+3) % lineNum), d3.select('#step3Line' + (i+2) % lineNum));
let points = {'x1': intersect.x, 'y1': intersect.y, 'x2': intersect2.x, 'y2': intersect2.y};
addLine(points, 7, i);
}
}
function step8 () {
const lineNum = 6;
for (let i = 0; i < lineNum; i++) {
let intersect = findLineIntersection(d3.select('#step7Line' + i), d3.select('#step6Line' + i));
let intersect2 = findLineIntersection(d3.select('#step7Line' + i), d3.select('#step1Line' + ((i+2)*2 + 1) % (lineNum*2)));
let points = {'x1': intersect.x, 'y1': intersect.y, 'x2': intersect2.x, 'y2': intersect2.y};
addLine(points, 8, i);
d3.select('#step8Line' + i)
.classed('construction', false)
.classed('final', true);
}
for (let j = 0; j < lineNum; j++) {
let intersect = findLineIntersection(d3.select('#step7Line' + j), d3.select('#step6Line' + (j+3) % lineNum));
let intersect2 = findLineIntersection(d3.select('#step7Line' + j), d3.select('#step1Line' + ((j+3)*2 + 1) % (lineNum*2)));
let points = {'x1': intersect.x, 'y1': intersect.y, 'x2': intersect2.x, 'y2': intersect2.y};
addLine(points, 8, j+lineNum);
d3.select('#step8Line' + (j+lineNum))
.classed('construction', false)
.classed('final', true);
}
}
</script>
</body>
</html>
https://d3js.org/d3.v4.min.js