const { interpolate } = flubber;
const polygonStroke = document.querySelector('#reuleaux-polygon');
const polygonFill = document.querySelector('#reuleaux-fill');
const polygons = [3, 5, 7, 9]
.map(count => [
regularPolygon([200, 200], 180, count),
reuleauxPolygon([200, 200], 180, count),
])
.reduce((acc, v) => acc.concat(v), []);
const colors = ['#fff', '#fff', '#ED705C', '#ED705C', '#337EED', '#337EED', '#ffb700', '#ffb700'];
let idx = 1;
const next = () => {
idx = idx < polygons.length - 1 ? idx + 1 : 0;
}
const randomColor = (not) => {
const p = colors[Math.floor(Math.random() * colors.length)];
return p === not ? randomColor(not) : p;
};
let fromColor = '#fff';
let toColor = randomColor(fromColor);
let interpolator = flubber.interpolate(polygons[0], polygons[idx]);
const time = { t: 0 };
const animate = () =>
anime({
targets: [polygonFill, time],
t: [0, 1],
fill: colors[idx],
duration: 900,
easing: 'easeOutQuint',
delay: 600,
update: anim => {
const d = interpolator(time.t);
polygonStroke.setAttribute('d', d);
polygonFill.setAttribute('d', d);
},
complete: (anim) => {
next();
interpolator = flubber
.interpolate(
polygons[idx === 0 ? polygons.length - 1 : idx - 1],
polygons[idx],
);
fromColor = toColor;
toColor = randomColor(fromColor);
animate();
}
});
animate();
/**
* Polygon Math
*/
function pts(sideCount, radius) {
const angle = 360 / sideCount;
const vertexIndices = range(sideCount);
const offsetDeg = 90 - (180 - angle) / 2;
const offset = degreesToRadians(offsetDeg);
return vertexIndices.map(index => {
return {
theta: offset + degreesToRadians(angle * index),
r: radius,
};
});
}
function range(count) {
return Array.from(Array(count).keys());
}
function degreesToRadians(angleInDegrees) {
return Math.PI * angleInDegrees / 180;
}
function polygon([cx, cy], radius, sideCount) {
return pts(sideCount, radius).map(({ r, theta }) => [
cx + r * Math.cos(theta),
cy + r * Math.sin(theta),
]);
}
function dist([x1, y1], [x2, y2]) {
return ((x1 - x2) ** 2 + (y1 - y2) ** 2) ** 0.5;
}
function reuleauxPolygon([cx, cy], radius, sideCount) {
const pts = polygon([cx, cy], radius, sideCount);
const l = dist(pts[0], pts[2]);
const [o, ...rest] = pts;
return [
'M',
o[0],
o[1],
...rest.map(p => `A ${l} ${l} 0 0 1 ${p[0]} ${p[1]}`),
`A ${l} ${l} 0 0 1 ${o[0]} ${o[1]}`,
'Z',
].join(' ');
}
function regularPolygon([cx, cy], sideCount, radius) {
const [o, ...rest] = polygon([cx, cy], sideCount, radius);
return [
'M',
o[0],
o[1],
...rest.map(p => `L ${p[0]} ${p[1]}`),
'Z',
].join(' ');
}
View Compiled