@pmndrs/uikit
Version:
Build performant 3D user interfaces with Three.js and yoga.
52 lines (51 loc) • 1.95 kB
JavaScript
import { Image } from './image.js';
import { VideoTexture } from 'three';
import { effect, signal } from '@preact/signals-core';
import { setupVideoElementInvalidation, updateVideoElement, } from '../components/index.js';
export class Video extends Image {
element;
texture;
aspectRatio;
updateAspectRatio;
unsubscribeInvalidate;
constructor(props, defaultProperties) {
const element = props.src instanceof HTMLVideoElement ? props.src : document.createElement('video');
if (!(props.src instanceof HTMLVideoElement)) {
updateVideoElement(element, props);
}
const texture = new VideoTexture(element);
texture.needsUpdate = true;
const aspectRatio = signal(1);
super({ aspectRatio, ...props, src: texture }, defaultProperties);
this.unsubscribeInvalidate = effect(() => {
const root = this.parentContextSignal.value?.value?.root;
if (root == null) {
return;
}
return setupVideoElementInvalidation(element, root.requestRender);
});
this.element = element;
this.texture = texture;
this.aspectRatio = aspectRatio;
this.updateAspectRatio = () => (aspectRatio.value = this.element.videoWidth / this.element.videoHeight);
this.updateAspectRatio();
this.element.addEventListener('resize', this.updateAspectRatio);
}
setProperties(props) {
if (!(props.src instanceof HTMLVideoElement)) {
updateVideoElement(this.element, props);
}
super.setProperties({
aspectRatio: this.aspectRatio,
...props,
src: this.texture,
});
}
destroy() {
super.destroy();
this.unsubscribeInvalidate();
this.texture.dispose();
this.element.remove();
this.element.removeEventListener('resize', this.updateAspectRatio);
}
}