Files
animate/docs/js/shapes/CircleExpand.js
Sam 14ec23237f V1.1
Giant refactor. added layers. ui overhaul. added save/load and we now got presets
2025-12-28 03:21:25 +13:00

100 lines
3.1 KiB
JavaScript

/**
* CircleExpand - Expanding concentric circles/hearts animation
*/
class CircleExpand extends BaseShape {
static config = [
{ type: 'range', min: 1, max: 70, defaultValue: 21, property: 'nCircles' },
{ type: 'range', min: 50, max: 150, defaultValue: 150, property: 'gap' },
{ type: 'range', min: 0, max: 1, defaultValue: 1, property: 'linear' },
{ type: 'range', min: 0, max: 1, defaultValue: 1, property: 'heart' },
{ type: 'color', defaultValue: '#fc03cf', property: 'colour1' },
{ type: 'color', defaultValue: '#00fffb', property: 'colour2' },
];
constructor(nCircles, gap, linear, heart, colour1, colour2) {
super();
this.nCircles = nCircles;
this.gap = gap;
this.linear = linear;
this.heart = heart;
this.colour1 = colour1;
this.colour2 = colour2;
}
lerpColor(a, b, amount) {
const ah = +a.replace('#', '0x');
const ar = ah >> 16, ag = ah >> 8 & 0xff, ab = ah & 0xff;
const bh = +b.replace('#', '0x');
const br = bh >> 16, bg = bh >> 8 & 0xff, bb = bh & 0xff;
const rr = ar + amount * (br - ar);
const rg = ag + amount * (bg - ag);
const rb = ab + amount * (bb - ab);
return '#' + ((1 << 24) + (rr << 16) + (rg << 8) + rb | 0).toString(16).slice(1);
}
arraySort(x, y) {
if (x.r > y.r) return 1;
if (x.r < y.r) return -1;
return 0;
}
drawHeart(w, colour) {
ctx.strokeStyle = "black";
ctx.fillStyle = colour;
ctx.lineWidth = 1;
const x = centerX - w / 2;
const y = centerY - w / 2;
ctx.beginPath();
ctx.moveTo(x, y + w / 4);
ctx.quadraticCurveTo(x, y, x + w / 4, y);
ctx.quadraticCurveTo(x + w / 2, y, x + w / 2, y + w / 5);
ctx.quadraticCurveTo(x + w / 2, y, x + w * 3 / 4, y);
ctx.quadraticCurveTo(x + w, y, x + w, y + w / 4);
ctx.quadraticCurveTo(x + w, y + w / 2, x + w * 3 / 4, y + w * 3 / 4);
ctx.lineTo(x + w / 2, y + w);
ctx.lineTo(x + w / 4, y + w * 3 / 4);
ctx.quadraticCurveTo(x, y + w / 2, x, y + w / 4);
ctx.stroke();
ctx.fill();
}
draw(elapsed) {
const rotation = elapsed * 0.9;
ctx.strokeWeight = 1;
ctx.lineWidth = 1;
const arrOfWidths = [];
let intRot;
if (this.linear) {
intRot = Math.floor(rotation * 30) / 100;
} else {
intRot = Math.sin(rad(Math.floor(rotation * 30) / 4)) + rotation / 4;
}
for (let i = 0; i < this.nCircles; i++) {
const width = this.gap * ((intRot + i) % this.nCircles);
const colour = (Math.sin(rad(i * (360 / this.nCircles) - 90)) + 1) / 2;
arrOfWidths.push({ r: width, c: colour });
}
const newArr = arrOfWidths.sort(this.arraySort);
for (let i = this.nCircles - 1; i >= 0; i--) {
const newColour = this.lerpColor(this.colour1, this.colour2, newArr[i].c);
if (this.heart) {
this.drawHeart(newArr[i].r, newColour);
} else {
ctx.beginPath();
ctx.arc(centerX, centerY, newArr[i].r, 0, 2 * Math.PI);
ctx.fillStyle = newColour;
ctx.fill();
ctx.strokeStyle = "black";
ctx.stroke();
}
}
}
}
shapeRegistry.register('CircleExpand', CircleExpand);