class Composer {
constructor({height, perspective, scene, ...opts}) {
this.root = document.createElement('div');
this.width = opts.width || width;
this.height = height || (window.isExported ? window.innerHeight - 1 : screen.height - 300);
this.root.style.overflow = 'hidden';
this.root.style.position = 'relative';
this.root.style.width = this.width + 'px';
this.root.style.height = this.height + 'px';
this.root.style.userSelect = 'none';
this.root.style.webkitUserDrag = 'none';
this.perspective = perspective ?? 500;
this.root.style.perspective = `${this.perspective}px`;
this.root.style.perspectiveOrigin = 'center center';
this.root.style.transformStyle = 'preserve-3d';
this.sceneRoot = document.createElement('div');
this.sceneRoot.style.transformStyle = 'preserve-3d';
this.sceneRoot.style.transformOrigin = 'center';
this.sceneRoot.style.backfaceVisibility = 'visible';
this.root.appendChild(this.sceneRoot);
this.objects = [];
this.controls = new Controls({
domObject: this.root,
step: 50,
coords: opts.coords,
angleX: opts.angleX,
angleY: opts.angleY,
distanceToCoords: opts.distanceToCoords,
onUpdate: () => {
this.update();
},
});
this.controls.mount();
invalidation.then(() => {
this.controls.unmount();
});
this.add(scene);
this.update();
}
setAnimation(duration) {
this.sceneRoot.style.transition = `transform ${duration}s ease-in-out`;
}
update() {
const [cx, cy, cz] = this.controls.getPosition();
const [rx, ry, rz] = [this.width / 2, 0, -this.perspective];
this.sceneRoot.style.transform = [
`translate3d(${this.width / 2}px, ${this.height / 2}px, 0px)`,
`translate3d(${-rx}px, ${-ry}px, ${-rz}px)`,
`rotateX(${this.controls.angleY}deg)`,
`rotateY(${-this.controls.angleX}deg)`,
`translate3d(${rx}px, ${ry}px, ${rz}px)`,
`translate3d(${cx}px, ${cy}px, ${cz + this.perspective}px)`,
].join(' ');
this.objects.forEach(obj => {
if (obj.update) obj.update();
obj.root.style.transform = [
`translate3d(${-obj.position[0]}px, ${-obj.position[1]}px, ${-obj.position[2]}px)`,
obj.transform || '',
].join(' ');
});
}
add(obj) {
if (Array.isArray(obj)) {
obj.forEach(o => this.add(o));
return;
}
this.sceneRoot.appendChild(obj.root);
obj.root.style.position = 'absolute';
obj.composer = this;
obj.controls = this.controls;
this.objects.push(obj);
}
}