src/viewer/Container.ts (138 lines of code) (raw):

import { DOMRenderer } from "../render/DOMRenderer"; import { GLRenderer } from "../render/GLRenderer"; import { RenderService } from "../render/RenderService"; import { StateService } from "../state/StateService"; import { DOM } from "../util/DOM"; import { ViewerOptions } from "./options/ViewerOptions"; import { KeyboardService } from "./KeyboardService"; import { MouseService } from "./MouseService"; import { SpriteService } from "./SpriteService"; import { TouchService } from "./TouchService"; import { ConfigurationService } from "./ConfigurationService"; export class Container { public id: string; public renderService: RenderService; public glRenderer: GLRenderer; public domRenderer: DOMRenderer; public keyboardService: KeyboardService; public mouseService: MouseService; public touchService: TouchService; public spriteService: SpriteService; public readonly configurationService: ConfigurationService; private _canvasContainer: HTMLDivElement; private _canvas: HTMLCanvasElement; private _container: HTMLElement; private _domContainer: HTMLDivElement; private _dom: DOM; private readonly _trackResize: boolean; constructor( options: ViewerOptions, stateService: StateService, dom?: DOM) { this._dom = dom ?? new DOM(); if (typeof options.container === "string") { this._container = this._dom.document .getElementById(options.container); if (!this._container) { throw new Error( `Container "${options.container}" not found.`); } } else if (options.container instanceof HTMLElement) { this._container = options.container; } else { throw new Error( `Invalid type: "container" must be ` + `a String or HTMLElement.`); } this._trackResize = options.trackResize === false ? false : true; this.id = this._container.id ?? "mapillary-fallback-container-id"; this._container.classList .add("mapillary-viewer"); this._canvasContainer = this._dom .createElement( "div", "mapillary-interactive", this._container); this._canvas = this._dom .createElement( "canvas", "mapillary-canvas"); this._canvas.style.position = "absolute"; this._canvas.setAttribute("tabindex", "0"); // Add DOM container after canvas container to // render DOM elements on top of the interactive // canvas. this._domContainer = this._dom .createElement( "div", "mapillary-dom", this._container); this.configurationService = new ConfigurationService(options); this.renderService = new RenderService( this._container, stateService.currentState$, options.renderMode); this.glRenderer = new GLRenderer( this._canvas, this._canvasContainer, this.renderService); this.domRenderer = new DOMRenderer( this._domContainer, this.renderService, stateService.currentState$); this.keyboardService = new KeyboardService(this._canvasContainer); this.mouseService = new MouseService( this._container, this._canvasContainer, this._domContainer, document); this.touchService = new TouchService( this._canvasContainer, this._domContainer); this.spriteService = new SpriteService(options.sprite); window.addEventListener('resize', this._onWindowResize, false); } public get canvas(): HTMLCanvasElement { return !!this._canvas.parentNode ? this._canvas : null; } public get canvasContainer(): HTMLDivElement { return this._canvasContainer; } public get container(): HTMLElement { return this._container; } public get domContainer(): HTMLDivElement { return this._domContainer; } public remove(): void { window.removeEventListener('resize', this._onWindowResize, false); this.spriteService.dispose(); this.touchService.dispose(); this.mouseService.dispose(); this.glRenderer.remove(); this.domRenderer.remove(); this.renderService.dispose(); this._removeNode(this._canvasContainer); this._removeNode(this._domContainer); this._container.classList .remove("mapillary-viewer"); } private _onWindowResize = () => { if (this._trackResize) { this.renderService.resize$.next(); } }; private _removeNode(node: Node): void { if (node.parentNode) { node.parentNode.removeChild(node); } } }