125 lines
3.9 KiB
TypeScript
125 lines
3.9 KiB
TypeScript
import { createElement } from '../../helper/create-element';
|
|
import { getHeight } from '../../helper/get-height';
|
|
import { mix } from '../../helper/mix';
|
|
import { Random } from '../../helper/random';
|
|
import { sum } from '../../helper/sum';
|
|
import { PageElement } from '../page-element';
|
|
import { generate } from './background.html';
|
|
|
|
export class PageBackground extends PageElement {
|
|
private static readonly perspective = 5;
|
|
private static readonly zMin = 6;
|
|
private static readonly zMax = 50;
|
|
|
|
private random: Random = new Random();
|
|
private blobs: Array<HTMLElement> = [];
|
|
|
|
public constructor(
|
|
private readonly topOffsetElementCount: number,
|
|
private readonly bottomOffsetElementCount: number
|
|
) {
|
|
super(createElement(generate()));
|
|
|
|
for (let i = 0; i < window.innerWidth / 10; i++) {
|
|
const blob = document.createElement('div');
|
|
blob.classList.add('blob');
|
|
blob.style.width = '140px';
|
|
const z = this.random.inInterval(PageBackground.zMin, PageBackground.zMax);
|
|
blob.style.zIndex = (-z).toFixed(0);
|
|
blob.style.opacity = (
|
|
1 -
|
|
(z - PageBackground.zMin) / (PageBackground.zMax - PageBackground.zMin)
|
|
).toString();
|
|
blob.style.height = `${this.random.inInterval(360, 740)}px`;
|
|
this.blobs.push(blob);
|
|
this.htmlRoot.appendChild(blob);
|
|
}
|
|
}
|
|
|
|
private windowHeight = 0;
|
|
private windowWidth = 0;
|
|
private contentHeight = 0;
|
|
private drawIfNecessary() {
|
|
const siblings = this.getSiblings();
|
|
const currentContentHeight = sum(siblings.map(getHeight));
|
|
|
|
if (
|
|
window.innerWidth !== this.windowWidth ||
|
|
currentContentHeight !== this.contentHeight
|
|
) {
|
|
this.windowWidth = window.innerWidth;
|
|
this.windowHeight = window.innerHeight;
|
|
this.contentHeight = currentContentHeight;
|
|
|
|
this.randomizeBlobs(
|
|
sum(siblings.slice(0, this.topOffsetElementCount).map(getHeight)),
|
|
sum(siblings.slice(-this.bottomOffsetElementCount).map(getHeight))
|
|
);
|
|
}
|
|
|
|
requestAnimationFrame(this.drawIfNecessary.bind(this));
|
|
}
|
|
|
|
private parent?: HTMLElement;
|
|
protected setParent(parent: PageElement) {
|
|
this.parent = parent.htmlRoot;
|
|
requestAnimationFrame(this.drawIfNecessary.bind(this));
|
|
super.setParent(parent);
|
|
}
|
|
|
|
private getSiblings(): Array<HTMLElement> {
|
|
return Array.prototype.slice
|
|
.call(this.parent!.childNodes)
|
|
.filter((n: HTMLElement) => n !== this.htmlRoot);
|
|
}
|
|
|
|
private randomizeBlobs(topOffset: number, bottomOffset: number) {
|
|
this.random.seed = 50;
|
|
this.blobs.forEach((b) => {
|
|
const z = -Number.parseInt(b.style.zIndex);
|
|
const [x, y] = this.randomXY(z, topOffset, bottomOffset, parseInt(b.style.height));
|
|
b.style.transform = `translate3D(${x}px, ${y}px, ${-z}px) rotate(-20deg)`;
|
|
});
|
|
}
|
|
|
|
private randomXY(
|
|
z: number,
|
|
topOffset: number,
|
|
bottomOffset: number,
|
|
height: number
|
|
): [number, number] {
|
|
const farTop = -(
|
|
((this.windowHeight / 2 - topOffset) / PageBackground.perspective) *
|
|
(PageBackground.zMax + PageBackground.perspective) -
|
|
this.windowHeight / 2
|
|
);
|
|
|
|
const farBottom = Math.min(
|
|
((this.windowHeight / 2 - bottomOffset) / PageBackground.perspective) *
|
|
(PageBackground.zMax + PageBackground.perspective) -
|
|
this.windowHeight / 2 +
|
|
this.contentHeight,
|
|
this.contentHeight - height
|
|
);
|
|
|
|
const endXSpan =
|
|
((this.windowWidth / PageBackground.perspective) *
|
|
(PageBackground.zMax + PageBackground.perspective)) /
|
|
2;
|
|
|
|
return [
|
|
this.random.inInterval(
|
|
mix(0, -(endXSpan - this.windowWidth / 2), z / PageBackground.zMax),
|
|
mix(
|
|
this.windowWidth,
|
|
this.windowWidth + endXSpan - this.windowWidth / 2,
|
|
z / PageBackground.zMax
|
|
)
|
|
),
|
|
this.random.inInterval(
|
|
mix(topOffset, farTop, z / PageBackground.zMax),
|
|
mix(this.contentHeight - bottomOffset, farBottom, z / PageBackground.zMax)
|
|
),
|
|
];
|
|
}
|
|
}
|