codepens/baubudsgenerative-bauhaus-i.../dist/script.js

237 lines
4.9 KiB
JavaScript

import { SVG } from "https://cdn.skypack.dev/@svgdotjs/svg.js";
function random(min, max, clamp = false) {
const value = Math.random() * (max - min) + min;
return clamp ? Math.round(value) : value;
}
class BauBudEyes {}
class BauBudPatternGenerator {
constructor(svg) {
this.svg = svg;
this.types = ["dots", "rects"];
}
generate(fill) {
this.type = this.types[random(0, this.types.length, true)];
return this.svg.pattern(4, 4, (add) => {
if (this.type === "rects") {
add.rect(2, 2).cx(0).cy(0).fill(fill);
} else {
add.circle(1).cx(2).cy(2).fill(fill);
}
});
}
}
class BauBudBody {
constructor(svg, x, y, width, height) {
this.svg = svg.group();
this.x = x;
this.y = y;
this.width = width;
this.height = height;
this.types = [
this.circle,
this.rect,
this.equilateralTriangle,
this.rightAngleTriangle,
this.semiCircle
];
this.patternGenerator = new BauBudPatternGenerator(this.svg);
}
circle() {
this.type = "circle";
return this.svg
.circle(Math.max(this.width, this.height))
.cx(this.x)
.cy(this.height);
}
rect() {
this.type = "rect";
return this.svg.rect(this.width, this.height).cx(this.x).cy(this.y);
}
equilateralTriangle() {
this.type = "equilateralTriangle";
return this.svg
.path(
`
M ${this.x} ${this.y - this.height / 2}
L ${this.x + this.width / 2} ${this.y + this.height / 2}
L ${this.x - this.width / 2} ${this.y + this.height / 2}
Z
`
)
.rotate(this.randomRotation(180));
}
rightAngleTriangle() {
this.type = "rightAngleTriangle";
return this.svg
.path(
`
M ${this.x - this.width / 2} ${this.y - this.height / 2}
L ${this.x + this.width / 2} ${this.y + this.height / 2}
L ${this.x - this.width / 2} ${this.y + this.height / 2}
Z
`
)
.rotate(this.randomRotation(90));
}
semiCircle() {
this.type = "semiCircle";
const rad = Math.max(this.width, this.height) / 2;
return this.svg
.path(
`
M ${this.x - rad} ${this.y + rad / 2}
A ${rad} ${rad} 0 0 1 ${this.x + this.width / 2} ${this.y + rad / 2}
Z
`
)
.rotate(this.randomRotation(180));
}
randomRotation(step = 90) {
const n = 360 / step;
return random(0, n, true) * step;
}
generate() {
this.svg.clear();
this.fill = ["red", "yellow", "blue"][random(0, 2, true)];
const pattern = this.patternGenerator.generate("#000");
this.base = this.types[random(0, this.types.length - 1, true)]
.call(this)
.fill("none")
.stroke("none");
let translateVal = random(5, 15);
if (random(0, 1) > 0.5) translateVal *= -1;
this.fill = this.base
.clone()
.addTo(this.svg)
.fill(this.fill)
.translate(translateVal, -translateVal);
this.pattern = this.base
.clone()
.addTo(this.svg)
.fill(pattern)
.translate(-translateVal * 2, translateVal * 2)
.scale(random(0.625, 0.825));
this.outline = this.base
.clone()
.addTo(this.svg)
.stroke("black")
.fill("transparent");
}
}
class BauBud {
constructor(target) {
this.svg = SVG().viewbox(0, 0, 200, 200).addTo(target);
this.body = new BauBudBody(this.svg, 100, 100, 100, 100);
this.eyes = new BauBudEyes(this.svg, 100, 100);
}
generate() {
this.body.generate();
const eyeWidth = random(5, 20);
const innerWidth = 8;
this.svg
.ellipse(16)
.stroke("#000")
.fill("#fff")
.cx(100 - eyeWidth)
.cy(100);
this.svg
.ellipse(16)
.stroke("#000")
.fill("#fff")
.cx(100 + eyeWidth)
.cy(100);
const choice = random(0, 5, true);
let leftEyeInnerX = 100 - eyeWidth;
let rightEyeInnerX = 100 + eyeWidth;
let eyeY = 100;
switch (choice) {
case 1:
leftEyeInnerX -= 4;
rightEyeInnerX -= 4;
break;
case 2:
leftEyeInnerX += 4;
rightEyeInnerX += 4;
break;
case 3:
eyeY += 4;
break;
case 4:
eyeY -= 4;
break;
default:
leftEyeInnerX = leftEyeInnerX;
rightEyeInnerX = rightEyeInnerX;
}
this.svg
.ellipse(innerWidth)
.stroke("#000")
.fill("#000")
.cx(leftEyeInnerX)
.cy(eyeY);
this.svg
.ellipse(innerWidth)
.stroke("#000")
.fill("#000")
.cx(rightEyeInnerX)
.cy(eyeY);
}
}
for (let i = 0; i < 100; i++) {
const bauBud = new BauBud(document.querySelector(".buds"));
bauBud.generate();
}
const buds = document.querySelector(".buds");
setInterval(() => {
const y = window.pageYOffset;
const windowHeight = window.innerHeight;
if (y + 200 + windowHeight >= buds.scrollHeight) {
for (let i = 0; i < 100; i++) {
const bauBud = new BauBud(buds);
bauBud.generate();
}
}
}, 100);