JavaScript
语言:
JaveScriptBabelCoffeeScript
确定
// Configuration
const SIM_ITERATIONS = 14;
class Vector2 {
constructor(x = 0, y = 0) {
this.x = x;
this.y = y;
}
clone() {
return new Vector2(this.x, this.y);
}
add(v) {
this.x += v.x;
this.y += v.y;
return this;
}
subtract(v) {
this.x -= v.x;
this.y -= v.y;
return this;
}
multiply(v) {
this.x *= v.x;
this.y *= v.y;
return this;
}
multiplyScalar(s) {
this.x *= s;
this.y *= s;
return this;
}
static fromScalar(s) {
return new Vector2(s, s);
}
}
class Rectangle {
constructor(position, size) {
this.position = position;
this.size = size;
}
getSurfaceSize() {
return this.size.x * this.size.y;
}
cut(position) {
const orientation = Math.random() < .5 ? 'x': 'y';
const positionInv = 1 - position;
const positionA = this.position.clone();
const sizeA = this.size.clone();
sizeA[orientation] *= position;
const positionB = this.position.clone();
const sizeB = this.size.clone();
positionB[orientation] += sizeA[orientation];
sizeB[orientation] -= sizeA[orientation];
return [
new Rectangle(positionA, sizeA),
new Rectangle(positionB, sizeB),
];
}
render(context, scale = Vector2.fromScalar(1)) {
const position = this.position.clone()
.multiply(scale);
const size = this.size.clone()
.multiply(scale);
context.fillRect(
position.x,
position.y,
size.x,
size.y
);
}
}
class Simulation {
constructor(interationsMAx) {
this.canvas = document.createElement('canvas');
this.context = this.canvas.getContext('2d');
this.scale = Vector2.fromScalar(1);
this.rectangles = [];
this.loop = this.animate.bind(this);
this.loopInterval = null;
this.iterationsMax = interationsMAx;
this.reset();
}
setSize(width, height) {
this.canvas.height = height;
this.canvas.width = width;
this.scale.x = width;
this.scale.y = height;
}
reset() {
if (this.loopInterval) {
this.loopInterval = cancelAnimationFrame(this.loopInterval);
this.loopInterval = null;
}
this.iteration = 0;
this.rectangles = [
new Rectangle(
Vector2.fromScalar(0),
Vector2.fromScalar(1)
)
];
this.animate();
}
animate() {
if (++this.iteration <= this.iterationsMax) {
this.loopInterval = requestAnimationFrame(this.loop);
}
this.update();
this.render();
}
update() {
const newRectangles = [];
const cutMin = .1;
const cutMax = .9;
this.rectangles.forEach((rectangle, index) => {
const cut = cutMin + (cutMax - cutMin) * Math.random();
const segments = rectangle.cut(cut);
newRectangles.push(...segments);
});
this.rectangles = newRectangles;
}
getColor(rectangle) {
const shadeMin = .25;
const shadeMax = .75;
const hue = rectangle.position.x;
const shade = shadeMin + (shadeMax - shadeMin) * (1 - rectangle.position.y);
return `hsl(${hue * 360}, 80%, ${shade * 100}%)`;
}
render() {
this.context.fillStyle = 'rgba(255, 255, 255, .5)';
this.context.fillRect(0, 0, this.canvas.width, this.canvas.height);
this.rectangles.forEach((rectangle, index) => {
this.context.fillStyle = this.getColor(rectangle);
rectangle.render(this.context, this.scale);
});
}
}
const sim = new Simulation(SIM_ITERATIONS);
sim.setSize(window.innerWidth, window.innerHeight);
document.body.appendChild(sim.canvas);
window.addEventListener('click', () => sim.reset());
window.addEventListener('resize', () => {
sim.setSize(window.innerWidth, window.innerHeight);
sim.render();
});