forked from EXT/VR180-Web-Player
added image support
This commit is contained in:
@@ -5,11 +5,19 @@ export type MediaCapabilities = {
|
||||
timeline: boolean;
|
||||
};
|
||||
|
||||
type MediaLoadCallbacks = {
|
||||
onError: (event: Event) => void;
|
||||
onReady: () => void;
|
||||
};
|
||||
|
||||
export type MediaKind = 'image' | 'video';
|
||||
|
||||
export interface MediaAdapter<TElement extends HTMLElement = HTMLElement, TTextureSource = TElement> {
|
||||
readonly capabilities: MediaCapabilities;
|
||||
readonly element: TElement;
|
||||
readonly kind: string;
|
||||
readonly kind: MediaKind;
|
||||
readonly textureSource: TTextureSource;
|
||||
bindLoadState(callbacks: MediaLoadCallbacks): void;
|
||||
getTitle(): string;
|
||||
hideElement(): void;
|
||||
load(): void;
|
||||
@@ -17,7 +25,7 @@ export interface MediaAdapter<TElement extends HTMLElement = HTMLElement, TTextu
|
||||
showElement(): void;
|
||||
}
|
||||
|
||||
export type SupportedMediaAdapter = VideoMediaAdapter;
|
||||
export type SupportedMediaAdapter = ImageMediaAdapter | VideoMediaAdapter;
|
||||
|
||||
const VIDEO_CAPABILITIES: MediaCapabilities = {
|
||||
audio: true,
|
||||
@@ -26,9 +34,16 @@ const VIDEO_CAPABILITIES: MediaCapabilities = {
|
||||
timeline: true
|
||||
};
|
||||
|
||||
const IMAGE_CAPABILITIES: MediaCapabilities = {
|
||||
audio: false,
|
||||
dynamicTexture: false,
|
||||
playback: false,
|
||||
timeline: false
|
||||
};
|
||||
|
||||
export class VideoMediaAdapter implements MediaAdapter<HTMLVideoElement, HTMLVideoElement> {
|
||||
readonly capabilities = VIDEO_CAPABILITIES;
|
||||
readonly kind = 'video';
|
||||
readonly kind = 'video' as const;
|
||||
|
||||
constructor(readonly element: HTMLVideoElement) {}
|
||||
|
||||
@@ -42,6 +57,16 @@ export class VideoMediaAdapter implements MediaAdapter<HTMLVideoElement, HTMLVid
|
||||
'Video Title';
|
||||
}
|
||||
|
||||
bindLoadState({ onError, onReady }: MediaLoadCallbacks): void {
|
||||
if (this.element.readyState >= this.element.HAVE_METADATA) {
|
||||
queueMicrotask(onReady);
|
||||
}
|
||||
|
||||
this.element.addEventListener('loadedmetadata', onReady);
|
||||
this.element.addEventListener('canplaythrough', onReady);
|
||||
this.element.addEventListener('error', onError);
|
||||
}
|
||||
|
||||
hideElement(): void {
|
||||
this.element.style.display = 'none';
|
||||
}
|
||||
@@ -59,12 +84,75 @@ export class VideoMediaAdapter implements MediaAdapter<HTMLVideoElement, HTMLVid
|
||||
}
|
||||
}
|
||||
|
||||
export class ImageMediaAdapter implements MediaAdapter<HTMLImageElement, HTMLImageElement> {
|
||||
readonly capabilities = IMAGE_CAPABILITIES;
|
||||
readonly kind = 'image' as const;
|
||||
|
||||
constructor(readonly element: HTMLImageElement) {}
|
||||
|
||||
get textureSource(): HTMLImageElement {
|
||||
return this.element;
|
||||
}
|
||||
|
||||
getTitle(): string {
|
||||
return this.element.getAttribute('title') ||
|
||||
this.element.getAttribute('alt') ||
|
||||
getFilenameTitle(this.element.currentSrc || this.element.src) ||
|
||||
'Image Title';
|
||||
}
|
||||
|
||||
bindLoadState({ onError, onReady }: MediaLoadCallbacks): void {
|
||||
if (this.element.complete && this.element.naturalWidth > 0) {
|
||||
queueMicrotask(onReady);
|
||||
}
|
||||
|
||||
this.element.addEventListener('load', onReady);
|
||||
this.element.addEventListener('error', onError);
|
||||
}
|
||||
|
||||
hideElement(): void {
|
||||
this.element.style.display = 'none';
|
||||
}
|
||||
|
||||
load(): void {
|
||||
// Images begin loading from markup. Kept for parity with video media.
|
||||
}
|
||||
|
||||
shouldUpdateTexture(): boolean {
|
||||
return false;
|
||||
}
|
||||
|
||||
showElement(): void {
|
||||
this.element.style.display = '';
|
||||
}
|
||||
}
|
||||
|
||||
export function createMediaAdapter(playerContainer: HTMLElement): SupportedMediaAdapter | null {
|
||||
const videoElement = playerContainer.querySelector<HTMLVideoElement>('video');
|
||||
if (!videoElement) {
|
||||
const mediaElements = Array.from(
|
||||
playerContainer.querySelectorAll<HTMLVideoElement | HTMLImageElement>('video,img')
|
||||
);
|
||||
|
||||
if (mediaElements.length !== 1) {
|
||||
return null;
|
||||
}
|
||||
|
||||
videoElement.classList.add('vrwp-video');
|
||||
return new VideoMediaAdapter(videoElement);
|
||||
const mediaElement = mediaElements[0];
|
||||
const tagName = mediaElement.tagName.toLowerCase();
|
||||
mediaElement.classList.add('vrwp-media');
|
||||
|
||||
if (tagName === 'video') {
|
||||
mediaElement.classList.add('vrwp-video');
|
||||
return new VideoMediaAdapter(mediaElement as HTMLVideoElement);
|
||||
}
|
||||
|
||||
if (tagName === 'img') {
|
||||
mediaElement.classList.add('vrwp-image');
|
||||
return new ImageMediaAdapter(mediaElement as HTMLImageElement);
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
function getFilenameTitle(source: string): string {
|
||||
return source.split('/').pop()?.split('.')[0].replace(/-/g, ' ') || '';
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user