diff --git a/README.md b/README.md index 047f01d7..f5bfd80c 100644 --- a/README.md +++ b/README.md @@ -1,77 +1,18 @@ -# Panolens.js +# @enra-gmbh/panolens [![NPM package][npm]][npm-url] [![License][license]][license-url] [![Bundle Size][bundle-size]][bundle-size-url] -[![Build Status][build-status]][build-status-url] -[![Dependencies][dependencies]][dependencies-url] -[![Dev Dependencies][dev-dependencies]][dev-dependencies-url] -[![Language Grade][lgtm]][lgtm-url] -[![Coverage][coverage]][coverage-url] -## Javascript 360 Panorama Viewer +This is a fork of [Panolens.js](https://github.com/pchen66/panolens.js), a Javascript 360 Panorama Viewer. Goals of this fork: -Panolens.js is an event-driven and WebGL based panorama viewer. Lightweight and flexible. It's built on top of [Three.JS](https://github.com/mrdoob/three.js). +- [x] Run with the newest version of Three.js (which uses ES6 class syntax). +- [x] Improve Typescript support (include types in published bundle). +- [ ] Have all tests in run in a browser, don't mock WebGL. -[Examples](https://pchen66.github.io/Panolens/#Example) — -[Documentation](https://pchen66.github.io/panolens.js) — -[Migration](https://github.com/pchen66/panolens.js/wiki/MigrationGuide) — -[FAQ](https://github.com/pchen66/panolens.js/wiki/Frequently-Asked-Questions) - -

- Panorama Demo -

- -## Usage - -Include `three.min.js` and `panolens.min.js` - -To find the correct supported versions, please check `dependencies` section in `package.json` or acess `PANOLENS.VERSION` or `PANOLENS.THREE_VERSION` at runtime. - -```html - - -``` -The following code generates a 360 image panorama. The first panorama added to the viewer will be the entry point. To link panoramas, use `panorama.link( other_panorama, new THREE.Vector3( X, Y, Z ) )` to connect the two. -```javascript -const panorama = new PANOLENS.ImagePanorama( 'asset/equirectangular.jpg' ); -const viewer = new PANOLENS.Viewer(); -viewer.add( panorama ); -``` - -## Dependency - -Panolens.js includes [Tween.js](https://github.com/tweenjs/tween.js/) by default, meaning `TWEEN` will be available with `window` object - -## How to contribute - -Always make your contributions for the latest `dev` branch, not `master`, so it can be tracked for the next release. - -### **Development** -``` -npm start -``` - -### **Build** -``` -npm run build-closure -``` - -[npm]: https://img.shields.io/npm/v/panolens.svg -[npm-url]:https://www.npmjs.com/package/panolens +[npm]: https://img.shields.io/npm/v/@enra-gmbh/panolens.svg +[npm-url]:https://www.npmjs.com/package/@enra-gmbh/panolens [license]: https://img.shields.io/github/license/pchen66/panolens.js.svg [license-url]: ./LICENSE -[bundle-size]: https://badgen.net/bundlephobia/minzip/panolens -[bundle-size-url]: https://bundlephobia.com/result?p=panolens -[build-status]: https://travis-ci.com/pchen66/panolens.js.svg?branch=dev -[build-status-url]: https://travis-ci.com/pchen66/panolens.js -[dependencies]: https://img.shields.io/david/pchen66/panolens.js.svg -[dependencies-url]: https://david-dm.org/pchen66/panolens.js -[dev-dependencies]: https://img.shields.io/david/dev/pchen66/panolens.js.svg -[dev-dependencies-url]: https://david-dm.org/pchen66/panolens.js?type=dev -[lgtm]: https://img.shields.io/lgtm/grade/javascript/g/pchen66/panolens.js.svg?logo=lgtm&logoWidth=18&label=code%20quality -[lgtm-url]: https://lgtm.com/projects/g/pchen66/panolens.js/context:javascript -[coverage]: https://coveralls.io/repos/github/pchen66/panolens.js/badge.svg?branch=dev -[coverage-url]: https://coveralls.io/github/pchen66/panolens.js?branch=dev -[panolens-support]: https://pics.paypal.com/00/p/NDIyZmRiMGEtMGQyMy00Y2QzLWI1YWQtZmY1OGI1MzRjNDYw/image_2.PNG -[panolens-support-url]: https://www.paypal.me/panolens \ No newline at end of file +[bundle-size]: https://badgen.net/bundlephobia/minzip/@enra-gmbh/panolens +[bundle-size-url]: https://bundlephobia.com/result?p=@enra-gmbh/panolens \ No newline at end of file diff --git a/build/Panolens.d.ts b/build/Panolens.d.ts new file mode 100644 index 00000000..ce12568a --- /dev/null +++ b/build/Panolens.d.ts @@ -0,0 +1,868 @@ +import * as THREE from 'three'; +import { Geometry } from 'three/examples/jsm/deprecated/Geometry'; +import * as TWEEN$1 from '@tweenjs/tween.js'; + +/** + * REVISION + * @module REVISION + * @example PANOLENS.REVISION + * @type {string} revision + */ +declare const REVISION: string; +/** + * VERSION + * @module VERSION + * @example PANOLENS.VERSION + * @type {string} version + */ +declare const VERSION: string; +/** + * THREEJS REVISION + * @module THREE_REVISION + * @example PANOLENS.THREE_REVISION + * @type {string} threejs revision + */ +declare const THREE_REVISION: string; +/** + * THREEJS VERSION + * @module THREE_VERSION + * @example PANOLENS.THREE_VERSION + * @type {string} threejs version + */ +declare const THREE_VERSION: string; +declare namespace CONTROLS { + const ORBIT: number; + const DEVICEORIENTATION: number; +} +declare namespace MODES$1 { + const UNKNOWN: number; + const NORMAL: number; + const CARDBOARD: number; + const STEREO: number; +} +declare namespace CONTROL_BUTTONS { + const FULLSCREEN: string; + const SETTING: string; + const VIDEO: string; +} +declare namespace OUTPUTS { + const NONE: string; + const CONSOLE: string; + const OVERLAY: string; +} + +declare namespace DataImage { + const Info: string; + const Arrow: string; + const FullscreenEnter: string; + const FullscreenLeave: string; + const VideoPlay: string; + const VideoPause: string; + const WhiteTile: string; + const Setting: string; + const ChevronRight: string; + const Check: string; + const ViewIndicator: string; +} + +interface ImageLoader { + load( + url: string, + onLoad?: (image?: HTMLElement) => any, + onProgress?: LoaderProgressHandler, + onError?: (error?: any) => any, + ): HTMLElement; +} + +interface TextureLoader { + load( + url: string, + onLoad?: (texture?: THREE.Texture) => any, + onProgress?: LoaderProgressHandler, + onError?: (error?: any) => any, + ): THREE.Texture; +} + +interface CubeTextureLoader { + load( + urls: string[], + onLoad?: (texture?: THREE.Texture) => any, + onProgress?: LoaderProgressHandler, + onError?: (error?: any) => any, + ): THREE.Texture; +} + +declare class Media$1 extends THREE.EventDispatcher { + constructor(constraints?: MediaStreamConstraints); + + constraints: MediaStreamConstraints + container: HTMLElement + scene: THREE.Scene + element: HTMLVideoElement + devices: MediaDeviceInfo[] + stream: MediaStream + ratioScalar: number + videoDeviceIndex: number + + setScene(scene: THREE.Scene): void; + + setContainer(container: HTMLElement): void; + + enumerateDevices(): Promise; + + switchNextVideoDevice(): void; + + getDevices(type?: string): Promise; + + getUserMedia(constraints?: MediaStreamConstraints): Promise; + + setVideDeviceIndex(index: number): void; + + start(targetDevice?: MediaDeviceInfo): Promise; + + stop(): void; + + setMediaStream(stream?: MediaStream): void; + + playVideo(): void; + + pauseVideo(): void; + + createVideoTexture(): THREE.VideoTexture; + + createVideoElement(): HTMLVideoElement; + + onWindowResize(event?: Event): void; +} + +declare class Reticle extends THREE.Sprite { + dpr: number + canvasWidth: number + canvasHeight: number + context: CanvasRenderingContext2D + color: THREE.Color + autoSelect: boolean + dwellTime: number + rippleDuration: number + startTimestamp: number + timerId: number + frustumCulled: boolean; + callback: undefined | (() => any) + + constructor(color?: THREE.Color, autoSelect?: boolean, dwellTime?: number); + + setColor(color: THREE.Color): void; + + createCanvasTexture(canvas: THREE.CanvasTexture): THREE.CanvasTexture; + + createCanvas(): HTMLCanvasElement; + + updateCanvasArcByProgress(progress: number): void; + + ripple(): void; + + show(): void; + + hide(): void; + + start(callback?: () => any): void; + + end(): void; + + update(): void; +} + +declare class Infospot extends THREE.Sprite { + type: string; + animated: boolean; + isHovering: boolean; + frustumCulled: boolean; + element: HTMLElement; + cursorStyle: string; + mode: number; + container: HTMLElement | object; + originalRaycast: THREE.Raycaster; + HANDLER_FOCUS: null | InfoSpotFocusHandler; + scaleUpAnimation: TWEEN.Tween; + scaleDownAnimation: TWEEN.Tween; + showAnimation: TWEEN.Tween; + hideAnimation: TWEEN.Tween; + + constructor(scale?: number, imageSrc?: string, animated?: boolean); + + postLoad(texture?: object): void; + + setContainer(data?: HTMLElement | object): void; + + getContainer(): HTMLElement; + + onClick(event?: object): void; + + onDismiss(): void; + + onHover(): void; + + onHoverStart(event?: object): void; + + onHoverEnd(): void; + + onDualEyeEffect(event?: object): void; + + translateElement(x?: number, y?: number): void; + + setElementStyle(type?: string, element?: HTMLElement, value?: string): void; + + setText(text: string): void; + + setCursorHoverStyle(style: string): void; + + addHoverText(text?: string, delta?: number): void; + + addHoverElement(el?: HTMLElement, delta?: number): void; + + removeHoverElement(): void; + + lockHoverElement(): void; + + unlockHoverElement(): void; + + enableRaycast(enabled?: boolean): void; + + show(delay?: number): void; + + hide(delay?: number): void; + + setFocusMethod(event?: { method: InfoSpotFocusHandler; }): void; + + focus(duration?: number, easing?: Easing): void; + + dispose(): void; +} + +declare class Widget extends THREE.EventDispatcher { + DEFAULT_TRANSITION: string + TOUCH_ENABLED: boolean + container: HTMLElement + barElement: HTMLElement + fullscreenElement: HTMLElement + videoElement: HTMLElement + settingElement: HTMLElement + mainMenu: HTMLElement + activeMainItem: HTMLElement + activeSubMenu: HTMLElement + mask: HTMLElement + + constructor(container?: HTMLElement) + + PREVENT_EVENT_HANDLER(event?: EventListener): void; + + addControlBar(): void; + + createDefaultMenu(): void; + + addControlButton(name?: string): void; + + createMask(): void; + + createSettingButton(): void; + + createFullscreenButton(): HTMLElement; + + createVideoControl(): HTMLElement; + + createVideoControlButton(): HTMLElement; + + createVideoControlSeekbar(): HTMLElement; + + createMenuItem(title?: string): HTMLElement; + + createMenuItemHeader(title?: string): HTMLElement; + + createMainMenu(menus?: HTMLElement[]): HTMLElement; + + createSubMenu(title?: string, items?: HTMLElement[]): void; + + createMenu(): HTMLElement; + + createCustomItem(options: WidgetCustomItemOptions): HTMLElement; + + mergeStyleOptions(element: HTMLElement, options: CSSStyleDeclaration): HTMLElement; + + dispose(): void; +} + +declare class Panorama$1 extends THREE.Mesh { + type: string; + ImageQualityLow: number; + ImageQualityFair: number; + ImageQualityMedium: number; + ImageQualityHigh: number; + ImageQualitySuperHigh: number; + animationDuration: number; + defaultInfospotSize: number; + container: HTMLElement | { container: HTMLElement; }; + loaded: boolean; + linkedSpots: Infospot[]; + isInfospotVisible: boolean; + linkingImageURL: string; + linkingImageScale: number; + active: boolean; + infospotAnimation: TWEEN$1.Tween; + + constructor(geometry?: Geometry, material?: THREE.Material); + + onClick(event?: PanoramaClickEvent): void; + + setContainer(data: HTMLElement | { container: HTMLElement; }): void; + + onLoad(): void; + + onProgress(progress?: number): void; + + onError(): void; + + getZoomLevel(): number; + + updateTexture(texture: THREE.Texture): void; + + toggleInfospotVisibility(isVisible?: boolean, delay?: number): void; + + setLinkingImage(url?: string, scale?: number): void; + + link(pano: Panorama$1, position?: THREE.Vector3, imageScale?: number, imageSource?: string): void; + + fadeIn(duration?: number): void; + + fadeOut(duration?: number): void; + + onEnter(): void; + + onLeave(): void; + + dispose(): void; +} + +declare class ImagePanorama$1 extends Panorama$1 { + src: string | HTMLElement; + radius: number; + + constructor(image: string | HTMLImageElement, geometry?: Geometry, material?: THREE.Material); + + onLoad(src?: THREE.Texture): void; + + load(src: string | HTMLImageElement): void; + + reset(): void; +} + +declare class EmptyPanorama { +} + +declare class CubePanorama$1 extends Panorama$1 { + images: string[]; + edgeLength: number; + + constructor(images: string[]); + + load(): void; + + dispose(): void; +} + +declare class BasicPanorama extends CubePanorama { +} + +interface VideoPanoramaOptions { + videoElement: HTMLVideoElement; + loop: boolean; + muted: boolean; + autoplay: boolean; + playsinline: boolean; + crossOrigin: string; +} + +declare class VideoPanorama extends Panorama { + src: string; + options: VideoPanoramaOptions; + videoElement: HTMLVideoElement; + videoProgress: number; + radius: number; + + constructor(src: string, options?: VideoPanoramaOptions); + + load(): void; + + setVideoTexture(video: HTMLVideoElement): void; + + reset(): void; + + isVideoPaused(): boolean; + + toggleVideo(): void; + + setVideoCurrentTime(event: { percentage: number; }): void; + + playVideo(): void; + + pauseVideo(): void; + + resumeVideoProgress(): void; + + resetVideo(): void; + + isVideoMuted(): boolean; + + muteVideo(): void; + + unmuteVideo(): void; + + getVideoElement(): HTMLVideoElement; +} + +declare class GoogleStreetviewPanorama extends ImagePanorama { + panoId: string; + gsvLoader: GoogleStreetviewLoader; + loadRequested: boolean; + + constructor(panoId: string, apiKey?: string); + + load(panoId: string): void; + + setupGoogleMapAPI(apiKey: string): void; + + setGSVLoader(): object; + + getGSVLoader(): object; + + loadGSVLoader(panoId: string): void; + + reset(): void; +} + +declare class LittlePlanet$1 extends ImagePanorama { + size: number; + ratio: number; + EPS: number; + frameId: number; + dragging: boolean; + userMouse: THREE.Vector2; + quatA: THREE.Quaternion; + quatB: THREE.Quaternion; + quatCur: THREE.Quaternion; + quatSlerp: THREE.Quaternion; + vectorX: THREE.Vector3; + vectorY: THREE.Vector3; + + constructor(type: string, source: string, size?: number, ratio?: number); + + createGeometry(size: number, ratio: number): THREE.PlaneBufferGeometry; + + createMaterial(size: number): THREE.ShaderMaterial; + + registerMouseEvents(): void; + + unregisterMouseEvents(): void; + + addZoomDelta(delta: number): void; +} + +declare class ImageLittlePlanet extends LittlePlanet { + constructor(source: string, size?: number, ratio?: number); + + updateTexture(texture: THREE.Texture): void; + + dispose(): void; +} + +declare class CameraPanorama extends Panorama { + media: Media; + radius: number; + + constructor(constraints: MediaStreamConstraints); + + onPanolensContainer(container: { container: HTMLElement, [key: string]: any; }): void; + + onPanolensScene(scene: { scene: THREE.Scene, [key: string]: any; }): void; + + start(): Promise; + + stop(): void; +} + +interface OrbitMouseButton { + ORBIT: THREE.MOUSE; + ZOOM: THREE.MOUSE; + PAN: THREE.MOUSE; +} + +declare class OrbitControls extends THREE.EventDispatcher { + object: THREE.Object3D; + domElement: HTMLElement; + frameId: string; + enabled: boolean; + target: THREE.Vector3; + center: THREE.Vector3; + noZoom: boolean; + zoomSpeed: number; + revertZoomScrollDirection: boolean; + minDistance: number; + maxDistance: number; + minZoom: number; + maxZoom: number; + noRotate: boolean; + rotateSpeed: number; + noPan: boolean; + keyPanSpeed: number; + autoRotate: boolean; + autoRotateSpeed: number; + minPolarAngle: number; + maxPolarAngle: number; + momentumDampingFactor: number; + momentumScalingFactor: number; + momentumKeydownFactor: number; + minFov: number; + maxFov: number; + minAzimuthAngle: number; + maxAzimuthAngle: number; + noKeys: boolean; + keys: number; + mouseButtons: OrbitMouseButton; + STATE: number; + target0: THREE.Vector3; + position0: THREE.Vector3; + zoom0: object; + changeEvent: object; + startEvent: object; + endEvent: object; + + constructor(object?: THREE.Object3D, element?: HTMLElement); + + setLastQuaternion(quaternion: THREE.Quaternion): void; + + getLastPosition(): THREE.Vector3; + + rotateLeft(angle?: number): void; + + rotateUp(angle?: number): void; + + panLeft(distance?: number): void; + + panUp(distance?: number): void; + + pan(deltaX?: number, deltaY?: number): void; + + momentum(): void; + + dollyIn(scale?: number): void; + + dollyOut(scale?: number): void; + + update(ignoreUpdate?: boolean): void; + + reset(): void; + + getPolarAngle(): number; + + getAzimuthalAngle(): number; + + getAutoRotationAngle(): number; + + getZoomScale(): number; + + onMouseDown(event?: MouseEvent): void; + + onMouseMove(event?: MouseEvent): void; + + onMouseUp(): void; + + onMouseWheel(event?: WheelEvent): void; + + onKeyUp(event?: KeyboardEvent): void; + + onKeyDown(event?: KeyboardEvent): void; + + touchstart(event?: TouchEvent): void; + + touchmove(event?: TouchEvent): void; + + touchend(event?: TouchEvent): void; + + dispose(): void; +} + +declare class DeviceOrientationControls extends THREE.EventDispatcher { + changeEvent: any; + camera: any; + domElement: any; + enabled: any; + deviceOrientation: any; + screenOrientation: any; + alpha: any; + alphaOffsetAngle: any; + + constructor(camera?: THREE.Camera, element?: HTMLElement); + + onDeviceOrientationChangeEvent(event: Event): void; + + onScreenOrientationChangeEvent(): void; + + onTouchStartEvent(event: Event): void; + + onTouchMoveEvent(event: Event): void; + + setCameraQuaternion(quaternion: THREE.Quaternion, alpha: number, beta: number, gamma: number, orient: number): void; + + connect(): void; + + disconnect(): void; + + update(ignoreUpdate: boolean): void; + + updateAlphaOffsetAngle(angle: number): void; + + dispose(): void; +} + +declare class CardboardEffect { + constructor(renderer: THREE.WebGLRenderer); + + setSize(width: number, height: number): void; + + render(scene: THREE.Scene, camera: THREE.Camera): void; +} + +declare class StereoEffect { + constructor(renderer: THREE.WebGLRenderer); + + setEyeSeparation(eyeSep: number): void; + + setSize(width: number, height: number): void; + + render(scene: THREE.Scene, camera: THREE.Camera): void; +} + +type ViewerOptions = { + container?: HTMLElement, + scene?: THREE.Scene, + camera?: THREE.Camera, + renderer?: THREE.WebGLRenderer, + controlBar?: boolean, + controlButtons?: string[], + autoHideControlBar?: boolean, + autoHideInfospot?: boolean, + horizontalView?: boolean, + clickTolerance?: number, + cameraFov?: number, + reverseDragging?: boolean, + enableReticle?: boolean, + dwellTime?: number, + autoReticleSelect?: boolean, + viewIndicator?: boolean, + indicatorSize?: number, + output?: 'event' | 'console' | 'overlay', + autoRotate?: boolean, + autoRotateSpeed?: number, + autoRotateActivationDuration?: number +}; + +declare class Viewer extends THREE.EventDispatcher { + options: ViewerOptions + container: HTMLElement + camera: THREE.PerspectiveCamera + scene: THREE.Scene + renderer: THREE.WebGLRenderer + sceneReticle: THREE.Scene + viewIndicatorSize: number + reticle: Reticle + tempEnableReticle: boolean + mode: number + panorama: Panorama$1 + widget: Widget + hoverObject: HTMLElement + infospot: Infospot + pressEntityObject: HTMLElement + pressObject: HTMLElement + raycaster: THREE.Raycaster + raycasterPoint: THREE.Vector2 + userMouse: THREE.Vector2 + updateCallbacks: (() => any)[] + requestAnimationId: number + cameraFrustum: THREE.Frustum + cameraViewProjectionMatrix: THREE.Matrix4 + autoRotateRequestId: number + outputDivElement: HTMLElement + touchSupported: boolean + HANDLER_MOUSE_DOWN: (event?: MouseEvent) => any + HANDLER_MOUSE_UP: (event?: MouseEvent) => any + HANDLER_MOUSE_MOVE: (event?: MouseEvent) => any + HANDLER_WINDOW_RESIZE: (event?: Event) => any + HANDLER_KEY_DOWN: (event?: KeyboardEvent) => any + HANDLER_KEY_UP: (event?: KeyboardEvent) => any + HANDLER_TAP: (event?: MouseEvent) => any + OUTPUT_INFOSPOT: HTMLElement + tweenLeftAnimation: TWEEN$1.Tween + tweenUpAnimation: TWEEN$1.Tween + OrbitControls: OrbitControls + DeviceOrientationControls: DeviceOrientationControls + controls: [DeviceOrientationControls, OrbitControls] + control: OrbitControls + CardboardEffect: CardboardEffect + StereoEffect: StereoEffect + effect: CardboardEffect + radius: number + currentPanoAngle: number + fovAngle: number + leftAngle: number + rightAngle: number + leftX: number + leftY: number + rightX: number + rightY: number + indicatorD: string + + constructor(options?: ViewerOptions); + + add(object?: THREE.Object3D): void; + + remove(object?: THREE.Object3D): void; + + addDefaultControlBar(array?: string[]): void; + + setPanorama(pano?: Panorama$1): void; + + eventHandler(event?: Event): void; + + dispatchEventToChildren(event?: Event): void; + + activateWidgetItem(index?: number, mode?: MODES): void; + + enableEffect(mode: MODES): void; + + disableEffect(): void; + + enableReticleControl(): void; + + disableReticleControl(): void; + + enableAutoRate(): void; + + disableAutoRate(): void; + + toggleVideoPlay(pause?: boolean): void; + + setVideoCurrentTime(percentage?: number): void; + + onVideoUpdate(percentage?: number): void; + + addUpdateCallback(fn?: () => any): void; + + removeUpdateCallback(fn?: () => any): void; + + showVideoWidget(): void; + + hideVideoWidget(): void; + + updateVideoPlayButton(paused?: boolean): void; + + addPanoramaEventListener(pano?: Panorama$1): void; + + setCameraControl(): void; + + getControl(): OrbitControls | DeviceOrientationControls; + + getScene(): THREE.Scene; + + getCamera(): THREE.Camera; + + getRenderer(): THREE.WebGLRenderer; + + getContainer(): HTMLElement; + + getControlId(): string; + + getNextControlId(): string; + + getNextControlIndex(): number; + + setCameraFov(fov: number): void; + + enableControl(index: number): void; + + disableControl(): void; + + toggleNextControl(): void; + + getScreenVector(worldVector: THREE.Vector3): void; + + checkSpriteInViewport(sprite?: THREE.Sprite): void; + + reverseDraggingDirection(): void; + + addReticle(): void; + + tweenControlCenter(vector?: THREE.Vector3, duration?: number, easing?: Easing): void; + + tweenControlCenterByObject(object?: THREE.Object3D, duration?: number, easing?: Easing): void; + + onWindowResize(windoWidth?: number, windowHeight?: number): void; + + addOutputElement(): void; + + outputPosition(): void; + + onMouseDown(event: Event): void; + + onMouseMove(event: Event): void; + + onMouseUp(event: Event): void; + + onTap(event: Event, type: string): void; + + getConvertedIntersect(intersects: THREE.Intersection[]): void; + + hideInfospot(): void; + + toggleControlBar(): void; + + onKeyDown(event: Event): void; + + onKeyUp(): void; + + update(): void; + + render(): void; + + animate(): void; + + onChange(): void; + + registerMouseAndTouchEvents(): void; + + unregisterMouseAndTouchEvents(): void; + + registerReticleEvent(): void; + + unregisterReticleEvent(): void; + + updateReticleEvent(): void; + + registerEventListeners(): void; + + unregisterEventListeners(): void; + + dispose(): void; + + destroy(): void; + + onPanoramaDispose(panorama: Panorama$1): void; + + loadAsyncRequest(url: string, callback: (event?: ProgressEvent) => any): void; + + addViewIndicator(): void; + + appendControlItem(option: object): void; + + clearAllCache(): void; +} + +export { BasicPanorama, CONTROLS, CONTROL_BUTTONS, CameraPanorama, CubePanorama$1 as CubePanorama, CubeTextureLoader, DataImage, EmptyPanorama, GoogleStreetviewPanorama, ImageLittlePlanet, ImageLoader, ImagePanorama$1 as ImagePanorama, Infospot, LittlePlanet$1 as LittlePlanet, MODES$1 as MODES, Media$1 as Media, OUTPUTS, Panorama$1 as Panorama, REVISION, Reticle, THREE_REVISION, THREE_VERSION, TextureLoader, VERSION, VideoPanorama, Viewer, Widget }; diff --git a/build/panolens.js b/build/panolens.js index a47d060c..9e952314 100644 --- a/build/panolens.js +++ b/build/panolens.js @@ -1,10 +1,30 @@ (function (global, factory) { typeof exports === 'object' && typeof module !== 'undefined' ? factory(exports, require('three')) : typeof define === 'function' && define.amd ? define(['exports', 'three'], factory) : - (global = global || self, factory(global.PANOLENS = {}, global.THREE)); -}(this, function (exports, THREE) { 'use strict'; + (global = typeof globalThis !== 'undefined' ? globalThis : global || self, factory(global.PANOLENS = {}, global.THREE)); +})(this, (function (exports, THREE) { 'use strict'; + + function _interopNamespace(e) { + if (e && e.__esModule) return e; + var n = Object.create(null); + if (e) { + Object.keys(e).forEach(function (k) { + if (k !== 'default') { + var d = Object.getOwnPropertyDescriptor(e, k); + Object.defineProperty(n, k, d.get ? d : { + enumerable: true, + get: function () { return e[k]; } + }); + } + }); + } + n["default"] = e; + return Object.freeze(n); + } + + var THREE__namespace = /*#__PURE__*/_interopNamespace(THREE); - const version="0.12.1";const dependencies={three:"^0.105.2"}; + const version="0.0.9";const dependencies={three:"^0.136"}; /** * REVISION @@ -58,6 +78,26 @@ */ const MODES = { UNKNOWN: 0, NORMAL: 1, CARDBOARD: 2, STEREO: 3 }; + /** + * CONTROL_BUTTONS + * @module CONTROL_BUTTONS + * @example PANOLENS.VIEWER.CONTROL_BUTTONS + * @property {string} FULLSCREEN + * @property {string} SETTING + * @property {string} VIDEO + */ + const CONTROL_BUTTONS = { FULLSCREEN: 'fullscreen', SETTING: 'setting', VIDEO: 'video' }; + + /** + * OUTPUTS + * @module OUTPUTS + * @example PANOLENS.VIEWER.OUTPUTS + * @property {string} NONE + * @property {string} CONSOLE + * @property {string} OVERLAY + */ + const OUTPUTS = { NONE: 'none', CONSOLE: 'console', OVERLAY: 'overlay' }; + /** * Data URI Images * @module DataImage @@ -106,7 +146,7 @@ load: function ( url, onLoad = () => {}, onProgress = () => {}, onError = () => {} ) { // Enable cache - THREE.Cache.enabled = true; + THREE__namespace.Cache.enabled = true; let cached, request, arrayBufferView, blob, urlCreator, image, reference; @@ -122,18 +162,27 @@ } // Cached - cached = THREE.Cache.get(reference ? reference : url); + cached = THREE__namespace.Cache.get(reference ? reference : url); if (cached !== undefined) { if (onLoad) { - setTimeout(function () { + if ( cached.complete && cached.src ) { + setTimeout( function () { + + onProgress( { loaded: 1, total: 1 } ); + onLoad( cached ); + + }, 0 ); + } else { + cached.addEventListener( 'load', function () { - onProgress({loaded: 1, total: 1}); - onLoad(cached); + onProgress( { loaded: 1, total: 1 } ); + onLoad( cached ); - }, 0); + }, false ); + } } @@ -146,7 +195,7 @@ image = document.createElementNS('http://www.w3.org/1999/xhtml', 'img'); // Add to cache - THREE.Cache.add(reference ? reference : url, image); + THREE__namespace.Cache.add(reference ? reference : url, image); const onImageLoaded = () => { @@ -166,13 +215,6 @@ request = new window.XMLHttpRequest(); request.open('GET', url, true); - if (process.env.npm_lifecycle_event !== 'test') { - request.onreadystatechange = function () { - if (this.readyState === 4 && this.status >= 400) { - onError(); - } - }; - } request.responseType = 'arraybuffer'; request.addEventListener( 'error', onError ); request.addEventListener( 'progress', event => { @@ -226,7 +268,7 @@ */ load: function ( url, onLoad = () => {}, onProgress, onError ) { - var texture = new THREE.Texture(); + var texture = new THREE__namespace.Texture(); ImageLoader.load( url, function ( image ) { @@ -235,7 +277,7 @@ // JPEGs can't have an alpha channel, so memory can be saved by storing them as RGB. const isJPEG = url.search( /\.(jpg|jpeg)$/ ) > 0 || url.search( /^data\:image\/jpeg/ ) === 0; - texture.format = isJPEG ? THREE.RGBFormat : THREE.RGBAFormat; + texture.format = isJPEG ? THREE__namespace.RGBFormat : THREE__namespace.RGBAFormat; texture.needsUpdate = true; onLoad( texture ); @@ -268,7 +310,7 @@ var texture, loaded, progress, all, loadings; - texture = new THREE.CubeTexture( [] ); + texture = new THREE__namespace.CubeTexture( [] ); loaded = 0; progress = {}; @@ -344,7 +386,7 @@ this.videoDeviceIndex = 0; } - Media.prototype = Object.assign( Object.create( THREE.EventDispatcher.prototype ), { + Media.prototype = Object.assign( Object.create( THREE__namespace.EventDispatcher.prototype ), { setContainer: function ( container ) { @@ -588,12 +630,12 @@ createVideoTexture: function () { const video = this.element; - const texture = new THREE.VideoTexture( video ); + const texture = new THREE__namespace.VideoTexture( video ); texture.generateMipmaps = false; - texture.minFilter = THREE.LinearFilter; - texture.magFilter = THREE.LinearFilter; - texture.format = THREE.RGBFormat; + texture.minFilter = THREE__namespace.LinearFilter; + texture.magFilter = THREE__namespace.LinearFilter; + texture.format = THREE__namespace.RGBFormat; texture.center.set( 0.5, 0.5 ); video.addEventListener( 'canplay', this.onWindowResize.bind( this ) ); @@ -676,40 +718,34 @@ * @param {boolean} [autoSelect=true] - Auto selection * @param {number} [dwellTime=1500] - Duration for dwelling sequence to complete */ - - function Reticle ( color = 0xffffff, autoSelect = true, dwellTime = 1500 ) { - - this.dpr = window.devicePixelRatio; - - const { canvas, context } = this.createCanvas(); - const material = new THREE.SpriteMaterial( { color, map: this.createCanvasTexture( canvas ) } ); - - THREE.Sprite.call( this, material ); - - this.canvasWidth = canvas.width; - this.canvasHeight = canvas.height; - this.context = context; - this.color = color instanceof THREE.Color ? color : new THREE.Color( color ); - - this.autoSelect = autoSelect; - this.dwellTime = dwellTime; - this.rippleDuration = 500; - this.position.z = -10; - this.center.set( 0.5, 0.5 ); - this.scale.set( 0.5, 0.5, 1 ); - - this.startTimestamp = null; - this.timerId = null; - this.callback = null; - - this.frustumCulled = false; - - this.updateCanvasArcByProgress( 0 ); - - } - Reticle.prototype = Object.assign( Object.create( THREE.Sprite.prototype ), { - - constructor: Reticle, + class Reticle extends THREE__namespace.Sprite { + constructor( color = 0xffffff, autoSelect = true, dwellTime = 1500 ) { + const { canvas, context } = Reticle.createCanvas(window.devicePixelRatio); + const material = new THREE__namespace.SpriteMaterial( { color, map: Reticle.createCanvasTexture( canvas ) } ); + super(material); + + this.dpr = window.devicePixelRatio; + + this.canvasWidth = canvas.width; + this.canvasHeight = canvas.height; + this.context = context; + this.color = color instanceof THREE__namespace.Color ? color : new THREE__namespace.Color( color ); + + this.autoSelect = autoSelect; + this.dwellTime = dwellTime; + this.rippleDuration = 500; + this.position.z = -10; + this.center.set( 0.5, 0.5 ); + this.scale.set( 0.5, 0.5, 1 ); + + this.startTimestamp = null; + this.timerId = null; + this.callback = null; + + this.frustumCulled = false; + + this.updateCanvasArcByProgress( 0 ); + } /** * Set material color @@ -717,12 +753,12 @@ * @memberOf Reticle * @instance */ - setColor: function ( color ) { - - this.material.color.copy( color instanceof THREE.Color ? color : new THREE.Color( color ) ); - - }, + setColor ( color ) { + this.material.color.copy( color instanceof THREE__namespace.Color ? color : new THREE__namespace.Color( color ) ); + + } + /** * Create canvas texture * @param {HTMLCanvasElement} canvas @@ -730,17 +766,17 @@ * @instance * @returns {THREE.CanvasTexture} */ - createCanvasTexture: function ( canvas ) { - - const texture = new THREE.CanvasTexture( canvas ); - texture.minFilter = THREE.LinearFilter; - texture.magFilter = THREE.LinearFilter; + static createCanvasTexture ( canvas ) { + + const texture = new THREE__namespace.CanvasTexture( canvas ); + texture.minFilter = THREE__namespace.LinearFilter; + texture.magFilter = THREE__namespace.LinearFilter; texture.generateMipmaps = false; - + return texture; - }, - + } + /** * Create canvas element * @memberOf Reticle @@ -749,33 +785,30 @@ * @returns {HTMLCanvasElement} object.canvas * @returns {CanvasRenderingContext2D} object.context */ - createCanvas: function () { - + static createCanvas (dpr) { const width = 32; const height = 32; const canvas = document.createElement( 'canvas' ); const context = canvas.getContext( '2d' ); - const dpr = this.dpr; - + canvas.width = width * dpr; canvas.height = height * dpr; context.scale( dpr, dpr ); - + context.shadowBlur = 5; context.shadowColor = 'rgba(200,200,200,0.9)'; - + return { canvas, context }; - - }, - + } + /** * Update canvas arc by progress * @param {number} progress * @memberOf Reticle * @instance */ - updateCanvasArcByProgress: function ( progress ) { - + updateCanvasArcByProgress ( progress ) { + const context = this.context; const { canvasWidth, canvasHeight, material } = this; const dpr = this.dpr; @@ -784,10 +817,10 @@ const x = canvasWidth * 0.5 / dpr; const y = canvasHeight * 0.5 / dpr; const lineWidth = 3; - + context.clearRect( 0, 0, canvasWidth, canvasHeight ); context.beginPath(); - + if ( progress === 0 ) { context.arc( x, y, canvasWidth / 16, 0, 2 * Math.PI ); context.fillStyle = color; @@ -798,13 +831,13 @@ context.lineWidth = lineWidth; context.stroke(); } - + context.closePath(); - + material.map.needsUpdate = true; - - }, - + + } + /** * Ripple effect * @memberOf Reticle @@ -812,8 +845,8 @@ * @fires Reticle#reticle-ripple-start * @fires Reticle#reticle-ripple-end */ - ripple: function () { - + ripple() { + const context = this.context; const { canvasWidth, canvasHeight, material } = this; const duration = this.rippleDuration; @@ -822,73 +855,73 @@ const dpr = this.dpr; const x = canvasWidth * 0.5 / dpr; const y = canvasHeight * 0.5 / dpr; - + const update = () => { - + const timerId = window.requestAnimationFrame( update ); const elapsed = performance.now() - timestamp; const progress = elapsed / duration; const opacity = 1.0 - progress > 0 ? 1.0 - progress : 0; const radius = progress * canvasWidth * 0.5 / dpr; - + context.clearRect( 0, 0, canvasWidth, canvasHeight ); context.beginPath(); context.arc( x, y, radius, 0, Math.PI * 2 ); context.fillStyle = `rgba(${color.r * 255}, ${color.g * 255}, ${color.b * 255}, ${opacity})`; context.fill(); context.closePath(); - + if ( progress >= 1.0 ) { - + window.cancelAnimationFrame( timerId ); this.updateCanvasArcByProgress( 0 ); - + /** * Reticle ripple end event * @type {object} * @event Reticle#reticle-ripple-end */ this.dispatchEvent( { type: 'reticle-ripple-end' } ); - + } - + material.map.needsUpdate = true; - + }; - + /** * Reticle ripple start event * @type {object} * @event Reticle#reticle-ripple-start */ this.dispatchEvent( { type: 'reticle-ripple-start' } ); - + update(); - - }, - + + } + /** * Make reticle visible * @memberOf Reticle * @instance */ - show: function () { - + show () { + this.visible = true; - - }, - + + } + /** * Make reticle invisible * @memberOf Reticle * @instance */ - hide: function () { - + hide () { + this.visible = false; - - }, - + + } + /** * Start dwelling * @param {function} callback @@ -896,87 +929,86 @@ * @instance * @fires Reticle#reticle-start */ - start: function ( callback ) { - + start ( callback ) { + if ( !this.autoSelect ) { - + return; - + } - + /** * Reticle start event * @type {object} * @event Reticle#reticle-start */ this.dispatchEvent( { type: 'reticle-start' } ); - + this.startTimestamp = performance.now(); this.callback = callback; this.update(); - - }, - + + } + /** * End dwelling * @memberOf Reticle * @instance * @fires Reticle#reticle-end */ - end: function(){ - + end(){ + if ( !this.startTimestamp ) { return; } - + window.cancelAnimationFrame( this.timerId ); - + this.updateCanvasArcByProgress( 0 ); this.callback = null; this.timerId = null; this.startTimestamp = null; - + /** * Reticle end event * @type {object} * @event Reticle#reticle-end */ this.dispatchEvent( { type: 'reticle-end' } ); - - }, - + + } + /** * Update dwelling * @memberOf Reticle * @instance * @fires Reticle#reticle-update */ - update: function () { - + update () { + this.timerId = window.requestAnimationFrame( this.update.bind( this ) ); - + const elapsed = performance.now() - this.startTimestamp; const progress = elapsed / this.dwellTime; - + this.updateCanvasArcByProgress( progress ); - + /** * Reticle update event * @type {object} * @event Reticle#reticle-update */ this.dispatchEvent( { type: 'reticle-update', progress } ); - + if ( progress >= 1.0 ) { - + window.cancelAnimationFrame( this.timerId ); if ( this.callback ) { this.callback(); } this.end(); this.ripple(); - + } - - } - - } ); + + } + } function createCommonjsModule(fn, module) { return module = { exports: {} }, fn(module, module.exports), module.exports; @@ -1142,7 +1174,7 @@ to: function (properties, duration) { - this._valuesEnd = Object.create(properties); + this._valuesEnd = properties; if (duration !== undefined) { this._duration = duration; @@ -1914,104 +1946,101 @@ * @param {string} [imageSrc=PANOLENS.DataImage.Info] - Image overlay info * @param {boolean} [animated=true] - Enable default hover animation */ - function Infospot ( scale = 300, imageSrc, animated ) { - - const duration = 500, scaleFactor = 1.3; - - imageSrc = imageSrc || DataImage.Info; - - THREE.Sprite.call( this ); - - this.type = 'infospot'; + class Infospot extends THREE__namespace.Sprite { - this.animated = animated !== undefined ? animated : true; - this.isHovering = false; + constructor( scale = 300, imageSrc, animated ) { + super(); + const duration = 500, scaleFactor = 1.3; - /* - * TODO: Three.js bug hotfix for sprite raycasting r104 - * https://github.com/mrdoob/three.js/issues/14624 - */ - this.frustumCulled = false; + imageSrc = imageSrc || DataImage.Info; - this.element = null; - this.toPanorama = null; - this.cursorStyle = null; + this.type = 'infospot'; - this.mode = MODES.NORMAL; + this.animated = animated !== undefined ? animated : true; + this.isHovering = false; - this.scale.set( scale, scale, 1 ); - this.rotation.y = Math.PI; + /* + * TODO: Three.js bug hotfix for sprite raycasting r104 + * https://github.com/mrdoob/three.js/issues/14624 + */ + this.frustumCulled = false; - this.container = null; + this.element = null; + this.toPanorama = null; + this.cursorStyle = null; - this.originalRaycast = this.raycast; + this.mode = MODES.NORMAL; - // Event Handler - this.HANDLER_FOCUS = null; + this.scale.set( scale, scale, 1 ); + this.rotation.y = Math.PI; - this.material.side = THREE.DoubleSide; - this.material.depthTest = false; - this.material.transparent = true; - this.material.opacity = 0; + this.container = null; - this.scaleUpAnimation = new Tween.Tween(); - this.scaleDownAnimation = new Tween.Tween(); + this.originalRaycast = this.raycast; + // Event Handler + this.HANDLER_FOCUS = null; - const postLoad = function ( texture ) { + this.material.side = THREE__namespace.DoubleSide; + this.material.depthTest = false; + this.material.transparent = true; + this.material.opacity = 0; - if ( !this.material ) { return; } + this.scaleUpAnimation = new Tween.Tween(); + this.scaleDownAnimation = new Tween.Tween(); - const ratio = texture.image.width / texture.image.height; - const textureScale = new THREE.Vector3(); - texture.image.width = texture.image.naturalWidth || 64; - texture.image.height = texture.image.naturalHeight || 64; + const postLoad = function ( texture ) { - this.scale.set( ratio * scale, scale, 1 ); + if ( !this.material ) { return; } - textureScale.copy( this.scale ); + const ratio = texture.image.width / texture.image.height; + const textureScale = new THREE__namespace.Vector3(); - this.scaleUpAnimation = new Tween.Tween( this.scale ) - .to( { x: textureScale.x * scaleFactor, y: textureScale.y * scaleFactor }, duration ) - .easing( Tween.Easing.Elastic.Out ); + texture.image.width = texture.image.naturalWidth || 64; + texture.image.height = texture.image.naturalHeight || 64; - this.scaleDownAnimation = new Tween.Tween( this.scale ) - .to( { x: textureScale.x, y: textureScale.y }, duration ) - .easing( Tween.Easing.Elastic.Out ); + this.scale.set( ratio * scale, scale, 1 ); - this.material.map = texture; - this.material.needsUpdate = true; + textureScale.copy( this.scale ); - }.bind( this ); + this.scaleUpAnimation = new Tween.Tween( this.scale ) + .to( { x: textureScale.x * scaleFactor, y: textureScale.y * scaleFactor }, duration ) + .easing( Tween.Easing.Elastic.Out ); - // Add show and hide animations - this.showAnimation = new Tween.Tween( this.material ) - .to( { opacity: 1 }, duration ) - .onStart( this.enableRaycast.bind( this, true ) ) - .easing( Tween.Easing.Quartic.Out ); + this.scaleDownAnimation = new Tween.Tween( this.scale ) + .to( { x: textureScale.x, y: textureScale.y }, duration ) + .easing( Tween.Easing.Elastic.Out ); - this.hideAnimation = new Tween.Tween( this.material ) - .to( { opacity: 0 }, duration ) - .onStart( this.enableRaycast.bind( this, false ) ) - .easing( Tween.Easing.Quartic.Out ); + this.material.map = texture; + this.material.needsUpdate = true; - // Attach event listeners - this.addEventListener( 'click', this.onClick ); - this.addEventListener( 'hover', this.onHover ); - this.addEventListener( 'hoverenter', this.onHoverStart ); - this.addEventListener( 'hoverleave', this.onHoverEnd ); - this.addEventListener( 'panolens-dual-eye-effect', this.onDualEyeEffect ); - this.addEventListener( 'panolens-container', this.setContainer.bind( this ) ); - this.addEventListener( 'dismiss', this.onDismiss ); - this.addEventListener( 'panolens-infospot-focus', this.setFocusMethod ); + }.bind( this ); - TextureLoader.load( imageSrc, postLoad ); + // Add show and hide animations + this.showAnimation = new Tween.Tween( this.material ) + .to( { opacity: 1 }, duration ) + .onStart( this.enableRaycast.bind( this, true ) ) + .easing( Tween.Easing.Quartic.Out ); - } - Infospot.prototype = Object.assign( Object.create( THREE.Sprite.prototype ), { + this.hideAnimation = new Tween.Tween( this.material ) + .to( { opacity: 0 }, duration ) + .onStart( this.enableRaycast.bind( this, false ) ) + .easing( Tween.Easing.Quartic.Out ); - constructor: Infospot, + // Attach event listeners + this.addEventListener( 'click', this.onClick ); + this.addEventListener( 'hover', this.onHover ); + this.addEventListener( 'hoverenter', this.onHoverStart ); + this.addEventListener( 'hoverleave', this.onHoverEnd ); + this.addEventListener( 'panolens-dual-eye-effect', this.onDualEyeEffect ); + this.addEventListener( 'panolens-container', this.setContainer.bind( this ) ); + this.addEventListener( 'dismiss', this.onDismiss ); + this.addEventListener( 'panolens-infospot-focus', this.setFocusMethod ); + + TextureLoader.load( imageSrc, postLoad ); + } + /** * Set infospot container @@ -2019,30 +2048,30 @@ * @memberOf Infospot * @instance */ - setContainer: function ( data ) { + setContainer ( data ) { let container; - + if ( data instanceof HTMLElement ) { - + container = data; - + } else if ( data && data.container ) { - + container = data.container; - + } - + // Append element if exists if ( container && this.element ) { - + container.appendChild( this.element ); - + } - + this.container = container; - - }, + + } /** * Get container @@ -2050,11 +2079,11 @@ * @instance * @return {HTMLElement} - The container of this infospot */ - getContainer: function () { + getContainer () { return this.container; - }, + } /** * This will be called by a click event @@ -2063,7 +2092,7 @@ * @memberOf Infospot * @instance */ - onClick: function ( event ) { + onClick ( event ) { if ( this.element && this.getContainer() ) { @@ -2074,7 +2103,7 @@ } - }, + } /** * Dismiss current element if any @@ -2082,7 +2111,7 @@ * @memberOf Infospot * @instance */ - onDismiss: function () { + onDismiss () { if ( this.element ) { @@ -2091,7 +2120,7 @@ } - }, + } /** * This will be called by a mouse hover event @@ -2100,7 +2129,7 @@ * @memberOf Infospot * @instance */ - onHover: function () {}, + onHover () {} /** * This will be called on a mouse hover start @@ -2109,7 +2138,7 @@ * @memberOf Infospot * @instance */ - onHoverStart: function ( event ) { + onHoverStart ( event ) { if ( !this.getContainer() ) { return; } @@ -2118,14 +2147,14 @@ this.isHovering = true; this.container.style.cursor = cursorStyle; - + if ( this.animated ) { scaleDownAnimation.stop(); scaleUpAnimation.start(); } - + if ( element && event.mouseEvent.clientX >= 0 && event.mouseEvent.clientY >= 0 ) { const { left, right, style } = element; @@ -2151,10 +2180,10 @@ element._height = element.clientHeight; } - + } - }, + } /** * This will be called on a mouse hover end @@ -2162,7 +2191,7 @@ * @memberOf Infospot * @instance */ - onHoverEnd: function () { + onHoverEnd () { if ( !this.getContainer() ) { return; } @@ -2190,7 +2219,7 @@ } - }, + } /** * On dual eye effect handler @@ -2199,8 +2228,8 @@ * @memberOf Infospot * @instance */ - onDualEyeEffect: function ( event ) { - + onDualEyeEffect ( event ) { + if ( !this.getContainer() ) { return; } let element, halfWidth, halfHeight; @@ -2245,7 +2274,7 @@ this.container.appendChild( element.left ); this.container.appendChild( element.right ); - }, + } /** * Translate the hovering element by css transform @@ -2254,7 +2283,7 @@ * @memberOf Infospot * @instance */ - translateElement: function ( x, y ) { + translateElement ( x, y ) { if ( !this.element._width || !this.element._height || !this.getContainer() ) { @@ -2274,8 +2303,8 @@ top = y - height - delta; if ( ( this.mode === MODES.CARDBOARD || this.mode === MODES.STEREO ) - && element.left && element.right - && !( x === container.clientWidth / 2 && y === container.clientHeight / 2 ) ) { + && element.left && element.right + && !( x === container.clientWidth / 2 && y === container.clientHeight / 2 ) ) { left = container.clientWidth / 4 - width + ( x - container.clientWidth / 2 ); top = container.clientHeight / 2 - height - delta + ( y - container.clientHeight / 2 ); @@ -2292,7 +2321,7 @@ } - }, + } /** * Set vendor specific css @@ -2302,7 +2331,7 @@ * @memberOf Infospot * @instance */ - setElementStyle: function ( type, element, value ) { + setElementStyle ( type, element, value ) { const style = element.style; @@ -2312,7 +2341,7 @@ } - }, + } /** * Set hovering text content @@ -2320,7 +2349,7 @@ * @memberOf Infospot * @instance */ - setText: function ( text ) { + setText ( text ) { if ( this.element ) { @@ -2328,18 +2357,18 @@ } - }, + } /** * Set cursor css style on hover * @memberOf Infospot * @instance */ - setCursorHoverStyle: function ( style ) { + setCursorHoverStyle ( style ) { this.cursorStyle = style; - }, + } /** * Add hovering text element @@ -2348,7 +2377,7 @@ * @memberOf Infospot * @instance */ - addHoverText: function ( text, delta = 40 ) { + addHoverText ( text, delta = 40 ) { if ( !this.element ) { @@ -2368,7 +2397,7 @@ this.setText( text ); - }, + } /** * Add hovering element by cloning an element @@ -2377,7 +2406,7 @@ * @memberOf Infospot * @instance */ - addHoverElement: function ( el, delta = 40 ) { + addHoverElement ( el, delta = 40 ) { if ( !this.element ) { @@ -2390,14 +2419,14 @@ } - }, + } /** * Remove hovering element * @memberOf Infospot * @instance */ - removeHoverElement: function () { + removeHoverElement () { if ( this.element ) { @@ -2420,14 +2449,14 @@ } - }, + } /** * Lock hovering element * @memberOf Infospot * @instance */ - lockHoverElement: function () { + lockHoverElement () { if ( this.element ) { @@ -2435,14 +2464,14 @@ } - }, + } /** * Unlock hovering element * @memberOf Infospot * @instance */ - unlockHoverElement: function () { + unlockHoverElement () { if ( this.element ) { @@ -2450,7 +2479,7 @@ } - }, + } /** * Enable raycasting @@ -2458,7 +2487,7 @@ * @memberOf Infospot * @instance */ - enableRaycast: function ( enabled = true ) { + enableRaycast ( enabled = true ) { if ( enabled ) { @@ -2470,7 +2499,7 @@ } - }, + } /** * Show infospot @@ -2478,7 +2507,7 @@ * @memberOf Infospot * @instance */ - show: function ( delay = 0 ) { + show ( delay = 0 ) { const { animated, hideAnimation, showAnimation, material } = this; @@ -2494,7 +2523,7 @@ } - }, + } /** * Hide infospot @@ -2502,7 +2531,7 @@ * @memberOf Infospot * @instance */ - hide: function ( delay = 0 ) { + hide ( delay = 0 ) { const { animated, hideAnimation, showAnimation, material, element } = this; @@ -2522,15 +2551,15 @@ material.opacity = 0; } - - }, + + } /** * Set focus event handler * @memberOf Infospot * @instance */ - setFocusMethod: function ( event ) { + setFocusMethod ( event ) { if ( event ) { @@ -2538,7 +2567,7 @@ } - }, + } /** * Focus camera center to this infospot @@ -2547,7 +2576,7 @@ * @memberOf Infospot * @instance */ - focus: function ( duration, easing ) { + focus ( duration, easing ) { if ( this.HANDLER_FOCUS ) { @@ -2556,14 +2585,14 @@ } - }, + } /** * Dispose * @memberOf Infospot * @instance */ - dispose: function () { + dispose () { const { geometry, material } = this; const { map } = material; @@ -2582,55 +2611,52 @@ } - } ); + + + } /** * @classdesc Widget for controls * @constructor * @param {HTMLElement} container - A domElement where default control widget will be attached to */ - function Widget ( container ) { - - if ( !container ) { - - console.warn( 'PANOLENS.Widget: No container specified' ); - - } - - THREE.EventDispatcher.call( this ); + class Widget extends THREE__namespace.EventDispatcher { - this.DEFAULT_TRANSITION = 'all 0.27s ease'; - this.TOUCH_ENABLED = !!(( 'ontouchstart' in window ) || window.DocumentTouch && document instanceof DocumentTouch); - this.PREVENT_EVENT_HANDLER = function ( event ) { - event.preventDefault(); - event.stopPropagation(); - }; + constructor( container ) { + super(); + if ( !container ) { - this.container = container; + console.warn( 'PANOLENS.Widget: No container specified' ); - this.barElement = null; - this.fullscreenElement = null; - this.videoElement = null; - this.settingElement = null; + } - this.mainMenu = null; + this.DEFAULT_TRANSITION = 'all 0.27s ease'; + this.TOUCH_ENABLED = !!(( 'ontouchstart' in window ) || window.DocumentTouch && document instanceof DocumentTouch); + this.PREVENT_EVENT_HANDLER = function ( event ) { + event.preventDefault(); + event.stopPropagation(); + }; - this.activeMainItem = null; - this.activeSubMenu = null; - this.mask = null; + this.container = container; - } + this.barElement = null; + this.fullscreenElement = null; + this.videoElement = null; + this.settingElement = null; - Widget.prototype = Object.assign( Object.create( THREE.EventDispatcher.prototype ), { + this.mainMenu = null; - constructor: Widget, + this.activeMainItem = null; + this.activeSubMenu = null; + this.mask = null; + } /** * Add control bar * @memberOf Widget * @instance */ - addControlBar: function () { + addControlBar () { if ( !this.container ) { @@ -2723,14 +2749,14 @@ this.barElement = bar; - }, + } /** * Create default menu * @memberOf Widget * @instance */ - createDefaultMenu: function () { + createDefaultMenu () { var scope = this, handler; @@ -2786,7 +2812,7 @@ ]; - }, + } /** * Add buttons on top of control bar @@ -2794,7 +2820,7 @@ * @memberOf Widget * @instance */ - addControlButton: function ( name ) { + addControlButton ( name ) { let element; @@ -2835,14 +2861,14 @@ this.barElement.appendChild( element ); - }, + } /** * Create modal mask * @memberOf Widget * @instance */ - createMask: function () { + createMask () { const element = document.createElement( 'div' ); element.style.position = 'absolute'; @@ -2867,14 +2893,14 @@ return element; - }, + } /** * Create Setting button to toggle menu * @memberOf Widget * @instance */ - createSettingButton: function () { + createSettingButton () { let scope = this, item; @@ -2886,7 +2912,7 @@ scope.mainMenu.toggle(); if ( this.activated ) { - + this.deactivate(); } else { @@ -2928,7 +2954,7 @@ if ( scope.mainMenu && scope.mainMenu.visible ) { scope.mainMenu.hide(); - + } if ( scope.activeSubMenu && scope.activeSubMenu.visible ) { @@ -2943,14 +2969,14 @@ scope.mainMenu.unslideAll(); } - + }; item.activated = false; return item; - }, + } /** * Create Fullscreen button @@ -2959,7 +2985,7 @@ * @instance * @fires Widget#panolens-viewer-handler */ - createFullscreenButton: function () { + createFullscreenButton () { let scope = this, item, isFullscreen = false, tapSkipped = true, stylesheetId; @@ -2969,9 +2995,9 @@ // Don't create button if no support if ( !document.fullscreenEnabled && - !document.webkitFullscreenEnabled && - !document.mozFullScreenEnabled && - !document.msFullscreenEnabled ) { + !document.webkitFullscreenEnabled && + !document.mozFullScreenEnabled && + !document.msFullscreenEnabled ) { return; } @@ -2988,7 +3014,7 @@ if ( container.msRequestFullscreen ) { container.msRequestFullscreen(); } if ( container.mozRequestFullScreen ) { container.mozRequestFullScreen(); } if ( container.webkitRequestFullscreen ) { container.webkitRequestFullscreen( Element.ALLOW_KEYBOARD_INPUT ); } - + isFullscreen = true; } else { @@ -3056,10 +3082,10 @@ sheet.innerHTML = ':-webkit-full-screen { width: 100% !important; height: 100% !important }'; document.body.appendChild( sheet ); } - + return item; - }, + } /** * Create video control container @@ -3067,7 +3093,7 @@ * @instance * @return {HTMLSpanElement} - The dom element icon for video control */ - createVideoControl: function () { + createVideoControl () { const item = document.createElement( 'span' ); item.style.display = 'none'; @@ -3087,7 +3113,7 @@ item.controlButton = this.createVideoControlButton(); item.seekBar = this.createVideoControlSeekbar(); - + item.appendChild( item.controlButton ); item.appendChild( item.seekBar ); @@ -3109,7 +3135,7 @@ return item; - }, + } /** * Create video control button @@ -3118,7 +3144,7 @@ * @return {HTMLSpanElement} - The dom element icon for video control * @fires Widget#panolens-viewer-handler */ - createVideoControlButton: function () { + createVideoControlButton () { const scope = this; @@ -3167,7 +3193,7 @@ return item; - }, + } /** * Create video seekbar @@ -3176,7 +3202,7 @@ * @return {HTMLSpanElement} - The dom element icon for video seekbar * @fires Widget#panolens-viewer-handler */ - createVideoControlSeekbar: function () { + createVideoControlSeekbar () { let scope = this, item, progressElement, progressElementControl, isDragging = false, mouseX, percentageNow, percentageNext; @@ -3200,9 +3226,9 @@ function onMouseDown ( event ) { event.stopPropagation(); - + isDragging = true; - + mouseX = event.clientX || ( event.changedTouches && event.changedTouches[0].clientX ); percentageNow = parseInt( progressElement.style.width ) / 100; @@ -3215,7 +3241,7 @@ if( isDragging ){ const clientX = event.clientX || ( event.changedTouches && event.changedTouches[0].clientX ); - + percentageNext = ( clientX - mouseX ) / item.clientWidth; percentageNext = percentageNow + percentageNext; @@ -3334,7 +3360,7 @@ return item; - }, + } /** * Create menu item @@ -3343,7 +3369,7 @@ * @instance * @return {HTMLElement} - An anchor tag element */ - createMenuItem: function ( title ) { + createMenuItem ( title ) { const scope = this; const item = document.createElement( 'a' ); @@ -3388,7 +3414,7 @@ }; item.addSelection = function ( name ) { - + const selection = document.createElement( 'span' ); selection.style.fontSize = '13px'; selection.style.fontWeight = '300'; @@ -3397,13 +3423,13 @@ this.selection = selection; this.setSelectionTitle( name ); this.appendChild( selection ); - + return this; }; item.addIcon = function ( url = DataImage.ChevronRight, left = false, flip = false ) { - + const element = document.createElement( 'span' ); element.style.float = left ? 'left' : 'right'; element.style.width = '17px'; @@ -3434,20 +3460,20 @@ }; item.addEventListener( 'mouseenter', function () { - + this.style.backgroundColor = '#e0e0e0'; }, false ); item.addEventListener( 'mouseleave', function () { - + this.style.backgroundColor = '#fafafa'; }, false ); return item; - }, + } /** * Create menu item header @@ -3456,7 +3482,7 @@ * @instance * @return {HTMLElement} - An anchor tag element */ - createMenuItemHeader: function ( title ) { + createMenuItemHeader ( title ) { const header = this.createMenuItem( title ); @@ -3465,7 +3491,7 @@ return header; - }, + } /** * Create main menu @@ -3474,8 +3500,8 @@ * @instance * @return {HTMLElement} - A span element */ - createMainMenu: function ( menus ) { - + createMainMenu ( menus ) { + let scope = this, menu = this.createMenu(); menu._width = 200; @@ -3528,7 +3554,7 @@ return menu; - }, + } /** * Create sub menu @@ -3538,7 +3564,7 @@ * @instance * @return {HTMLElement} - A span element */ - createSubMenu: function ( title, items ) { + createSubMenu ( title, items ) { let scope = this, menu, subMenu = this.createMenu(); @@ -3590,8 +3616,8 @@ subMenu.slideAll( true ); return subMenu; - - }, + + } /** * Create general menu @@ -3599,7 +3625,7 @@ * @instance * @return {HTMLElement} - A span element */ - createMenu: function () { + createMenu () { const scope = this; const menu = document.createElement( 'span' ); @@ -3739,7 +3765,7 @@ return menu; - }, + } /** * Create custom item element @@ -3747,7 +3773,7 @@ * @instance * @return {HTMLSpanElement} - The dom element icon */ - createCustomItem: function ( options = {} ) { + createCustomItem ( options = {} ) { const scope = this; const item = options.element || document.createElement( 'span' ); @@ -3761,19 +3787,19 @@ item.style.backgroundRepeat = 'no-repeat'; item.style.backgroundPosition = 'center'; item.style.webkitUserSelect = - item.style.MozUserSelect = - item.style.userSelect = 'none'; + item.style.MozUserSelect = + item.style.userSelect = 'none'; item.style.position = 'relative'; item.style.pointerEvents = 'auto'; // White glow on icon item.addEventListener( scope.TOUCH_ENABLED ? 'touchstart' : 'mouseenter', function() { item.style.filter = - item.style.webkitFilter = 'drop-shadow(0 0 5px rgba(255,255,255,1))'; + item.style.webkitFilter = 'drop-shadow(0 0 5px rgba(255,255,255,1))'; }, { passive: true }); item.addEventListener( scope.TOUCH_ENABLED ? 'touchend' : 'mouseleave', function() { item.style.filter = - item.style.webkitFilter = ''; + item.style.webkitFilter = ''; }, { passive: true }); this.mergeStyleOptions( item, options.style ); @@ -3791,10 +3817,10 @@ if ( onDispose ) { options.onDispose(); } }; - + return item; - }, + } /** * Merge item css style @@ -3804,7 +3830,7 @@ * @instance * @return {HTMLElement} - The same element with merged styles */ - mergeStyleOptions: function ( element, options = {} ) { + mergeStyleOptions ( element, options = {} ) { for ( let property in options ){ @@ -3818,14 +3844,14 @@ return element; - }, + } /** * Dispose widgets by detaching dom elements from container * @memberOf Widget * @instance */ - dispose: function () { + dispose () { if ( this.barElement ) { this.container.removeChild( this.barElement ); @@ -3835,8 +3861,8 @@ } } - - } ); + + } /** * @classdesc Base Panorama @@ -3844,72 +3870,59 @@ * @param {THREE.Geometry} geometry - The geometry for this panorama * @param {THREE.Material} material - The material for this panorama */ - function Panorama ( geometry, material ) { - - THREE.Mesh.call( this, geometry, material ); - - this.type = 'panorama'; + class Panorama extends THREE__namespace.Mesh { + constructor(geometry, material) { + super(geometry, material); - this.ImageQualityLow = 1; - this.ImageQualityFair = 2; - this.ImageQualityMedium = 3; - this.ImageQualityHigh = 4; - this.ImageQualitySuperHigh = 5; + this.type = 'panorama'; - this.animationDuration = 1000; + this.ImageQualityLow = 1; + this.ImageQualityFair = 2; + this.ImageQualityMedium = 3; + this.ImageQualityHigh = 4; + this.ImageQualitySuperHigh = 5; - this.defaultInfospotSize = 350; + this.animationDuration = 1000; - this.container = undefined; + this.defaultInfospotSize = 350; - this.loaded = false; + this.container = undefined; - this.linkedSpots = []; + this.loaded = false; - this.isInfospotVisible = false; - - this.linkingImageURL = undefined; - this.linkingImageScale = undefined; - - this.material.side = THREE.BackSide; - this.material.opacity = 0; + this.linkedSpots = []; - this.scale.x *= -1; - this.renderOrder = -1; + this.isInfospotVisible = false; - this.active = false; + this.linkingImageURL = undefined; + this.linkingImageScale = undefined; - this.infospotAnimation = new Tween.Tween( this ).to( {}, this.animationDuration / 2 ); + this.material.side = THREE__namespace.BackSide; + this.material.opacity = 0; - this.addEventListener( 'load', this.fadeIn.bind( this ) ); - this.addEventListener( 'panolens-container', this.setContainer.bind( this ) ); - this.addEventListener( 'click', this.onClick.bind( this ) ); + this.scale.x *= -1; + this.renderOrder = -1; - this.setupTransitions(); + this.active = false; - } + this.infospotAnimation = new Tween.Tween(this).to({}, this.animationDuration / 2); - Panorama.prototype = Object.assign( Object.create( THREE.Mesh.prototype ), { + this.addEventListener('load', this.fadeIn.bind(this)); + this.addEventListener('panolens-container', this.setContainer.bind(this)); + this.addEventListener('click', this.onClick.bind(this)); - constructor: Panorama, + this.setupTransitions(); + } - /** - * Adding an object - * To counter the scale.x = -1, it will automatically add an - * empty object with inverted scale on x - * @memberOf Panorama - * @instance - * @param {THREE.Object3D} object - The object to be added - */ - add: function ( object ) { + add(object) { let invertedObject; - if ( arguments.length > 1 ) { + if (arguments.length > 1) { - for ( var i = 0; i < arguments.length; i ++ ) { + for (var i = 0; i < arguments.length; i++) { - this.add( arguments[ i ] ); + this.add(arguments[i]); } @@ -3918,50 +3931,52 @@ } // In case of infospots - if ( object instanceof Infospot ) { + if (object instanceof Infospot) { invertedObject = object; - if ( object.dispatchEvent ) { + if (object.dispatchEvent) { const { container } = this; - if ( container ) { object.dispatchEvent( { type: 'panolens-container', container } ); } - - object.dispatchEvent( { type: 'panolens-infospot-focus', method: function ( vector, duration, easing ) { + if (container) { object.dispatchEvent({ type: 'panolens-container', container }); } - /** - * Infospot focus handler event - * @type {object} - * @event Panorama#panolens-viewer-handler - * @property {string} method - Viewer function name - * @property {*} data - The argument to be passed into the method - */ - this.dispatchEvent( { type: 'panolens-viewer-handler', method: 'tweenControlCenter', data: [ vector, duration, easing ] } ); + object.dispatchEvent({ + type: 'panolens-infospot-focus', method: function (vector, duration, easing) { + /** + * Infospot focus handler event + * @type {object} + * @event Panorama#panolens-viewer-handler + * @property {string} method - Viewer function name + * @property {*} data - The argument to be passed into the method + */ + this.dispatchEvent({ type: 'panolens-viewer-handler', method: 'tweenControlCenter', data: [vector, duration, easing] }); - }.bind( this ) } ); + + }.bind(this) + }); } } else { // Counter scale.x = -1 effect - invertedObject = new THREE.Object3D(); + invertedObject = new THREE__namespace.Object3D(); invertedObject.scale.x = -1; invertedObject.scalePlaceHolder = true; - invertedObject.add( object ); + invertedObject.add(object); } - THREE.Object3D.prototype.add.call( this, invertedObject ); + THREE__namespace.Object3D.prototype.add.call(this, invertedObject); - }, + } - load: function () { + load() { this.onLoad(); - - }, + + } /** * Click event handler @@ -3970,24 +3985,24 @@ * @instance * @fires Infospot#dismiss */ - onClick: function ( event ) { + onClick(event) { - if ( event.intersects && event.intersects.length === 0 ) { + if (event.intersects && event.intersects.length === 0) { - this.traverse( function ( object ) { + this.traverse(function (object) { /** * Dimiss event * @type {object} * @event Infospot#dismiss */ - object.dispatchEvent( { type: 'dismiss' } ); + object.dispatchEvent({ type: 'dismiss' }); - } ); + }); } - }, + } /** * Set container of this panorama @@ -3996,25 +4011,25 @@ * @instance * @fires Infospot#panolens-container */ - setContainer: function ( data ) { + setContainer(data) { let container; - if ( data instanceof HTMLElement ) { + if (data instanceof HTMLElement) { container = data; - } else if ( data && data.container ) { + } else if (data && data.container) { container = data.container; } - if ( container ) { + if (container) { - this.children.forEach( function ( child ) { + this.children.forEach(function (child) { - if ( child instanceof Infospot && child.dispatchEvent ) { + if (child instanceof Infospot && child.dispatchEvent) { /** * Set container event @@ -4022,17 +4037,17 @@ * @event Infospot#panolens-container * @property {HTMLElement} container - The container of this panorama */ - child.dispatchEvent( { type: 'panolens-container', container: container } ); + child.dispatchEvent({ type: 'panolens-container', container: container }); } - } ); + }); this.container = container; } - }, + } /** * This will be called when panorama is loaded @@ -4040,7 +4055,7 @@ * @instance * @fires Panorama#load */ - onLoad: function () { + onLoad() { this.loaded = true; @@ -4049,9 +4064,9 @@ * @type {object} * @event Panorama#load */ - this.dispatchEvent( { type: 'load' } ); + this.dispatchEvent({ type: 'load' }); - }, + } /** * This will be called when panorama is in progress @@ -4059,7 +4074,7 @@ * @instance * @fires Panorama#progress */ - onProgress: function ( progress ) { + onProgress(progress) { /** * Loading panorama progress event @@ -4067,26 +4082,25 @@ * @event Panorama#progress * @property {object} progress - The progress object containing loaded and total amount */ - this.dispatchEvent( { type: 'progress', progress: progress } ); - - }, + this.dispatchEvent({ type: 'progress', progress: progress }); + } /** * This will be called when panorama loading has error * @memberOf Panorama * @instance * @fires Panorama#error */ - onError: function () { + onError() { /** * Loading panorama error event * @type {object} * @event Panorama#error */ - this.dispatchEvent( { type: 'error' } ); + this.dispatchEvent({ type: 'error' }); - }, + } /** * Get zoom level based on window width @@ -4094,23 +4108,23 @@ * @instance * @return {number} zoom level indicating image quality */ - getZoomLevel: function () { + getZoomLevel() { let zoomLevel; - if ( window.innerWidth <= 800 ) { + if (window.innerWidth <= 800) { zoomLevel = this.ImageQualityFair; - } else if ( window.innerWidth > 800 && window.innerWidth <= 1280 ) { + } else if (window.innerWidth > 800 && window.innerWidth <= 1280) { zoomLevel = this.ImageQualityMedium; - } else if ( window.innerWidth > 1280 && window.innerWidth <= 1920 ) { + } else if (window.innerWidth > 1280 && window.innerWidth <= 1920) { zoomLevel = this.ImageQualityHigh; - } else if ( window.innerWidth > 1920 ) { + } else if (window.innerWidth > 1920) { zoomLevel = this.ImageQualitySuperHigh; @@ -4122,7 +4136,7 @@ return zoomLevel; - }, + } /** * Update texture of a panorama @@ -4130,12 +4144,12 @@ * @instance * @param {THREE.Texture} texture - Texture to be updated */ - updateTexture: function ( texture ) { + updateTexture(texture) { this.material.map = texture; this.material.needsUpdate = true; - }, + } /** * Toggle visibility of infospots in this panorama @@ -4145,45 +4159,45 @@ * @instance * @fires Panorama#infospot-animation-complete */ - toggleInfospotVisibility: function ( isVisible, delay ) { + toggleInfospotVisibility(isVisible, delay) { - delay = ( delay !== undefined ) ? delay : 0; + delay = (delay !== undefined) ? delay : 0; - const visible = ( isVisible !== undefined ) ? isVisible : ( this.isInfospotVisible ? false : true ); + const visible = (isVisible !== undefined) ? isVisible : (this.isInfospotVisible ? false : true); - this.traverse( function ( object ) { + this.traverse(function (object) { - if ( object instanceof Infospot ) { + if (object instanceof Infospot) { - if ( visible ) { + if (visible) { - object.show( delay ); + object.show(delay); } else { - object.hide( delay ); + object.hide(delay); } } - } ); + }); this.isInfospotVisible = visible; // Animation complete event - this.infospotAnimation.onComplete( function () { + this.infospotAnimation.onComplete(function () { /** * Complete toggling infospot visibility * @event Panorama#infospot-animation-complete * @type {object} */ - this.dispatchEvent( { type: 'infospot-animation-complete', visible: visible } ); + this.dispatchEvent({ type: 'infospot-animation-complete', visible: visible }); - }.bind( this ) ).delay( delay ).start(); + }.bind(this)).delay(delay).start(); - }, + } /** * Set image of this panorama's linking infospot @@ -4192,12 +4206,12 @@ * @param {string} url - Url to the image asset * @param {number} scale - Scale factor of the infospot */ - setLinkingImage: function ( url, scale ) { + setLinkingImage(url, scale) { this.linkingImageURL = url; this.linkingImageScale = scale; - }, + } /** * Link one-way panorama @@ -4208,26 +4222,26 @@ * @memberOf Panorama * @instance */ - link: function ( pano, position, imageScale, imageSrc ) { + link(pano, position, imageScale, imageSrc) { let scale, img; this.visible = true; - if ( !position ) { + if (!position) { - console.warn( 'Please specify infospot position for linking' ); + console.warn('Please specify infospot position for linking'); return; } // Infospot scale - if ( imageScale !== undefined ) { + if (imageScale !== undefined) { scale = imageScale; - } else if ( pano.linkingImageScale !== undefined ) { + } else if (pano.linkingImageScale !== undefined) { scale = pano.linkingImageScale; @@ -4239,11 +4253,11 @@ // Infospot image - if ( imageSrc ) { + if (imageSrc) { img = imageSrc; - } else if ( pano.linkingImageURL ) { + } else if (pano.linkingImageURL) { img = pano.linkingImageURL; @@ -4254,10 +4268,10 @@ } // Creates a new infospot - const spot = new Infospot( scale, img ); - spot.position.copy( position ); + const spot = new Infospot(scale, img); + spot.position.copy(position); spot.toPanorama = pano; - spot.addEventListener( 'click', function () { + spot.addEventListener('click', function () { /** * Viewer handler event @@ -4266,29 +4280,29 @@ * @property {string} method - Viewer function name * @property {*} data - The argument to be passed into the method */ - this.dispatchEvent( { type: 'panolens-viewer-handler', method: 'setPanorama', data: pano } ); + this.dispatchEvent({ type: 'panolens-viewer-handler', method: 'setPanorama', data: pano }); - }.bind( this ) ); + }.bind(this)); - this.linkedSpots.push( spot ); + this.linkedSpots.push(spot); - this.add( spot ); + this.add(spot); this.visible = false; - }, + } - reset: function () { + reset() { - this.children.length = 0; + this.children.length = 0; - }, + } - setupTransitions: function () { + setupTransitions() { - this.fadeInAnimation = new Tween.Tween( this.material ) - .easing( Tween.Easing.Quartic.Out ) - .onStart( function () { + this.fadeInAnimation = new Tween.Tween(this.material) + .easing(Tween.Easing.Quartic.Out) + .onStart(function () { this.visible = true; // this.material.visible = true; @@ -4298,13 +4312,13 @@ * @event Panorama#enter-fade-start * @type {object} */ - this.dispatchEvent( { type: 'enter-fade-start' } ); + this.dispatchEvent({ type: 'enter-fade-start' }); - }.bind( this ) ); + }.bind(this)); - this.fadeOutAnimation = new Tween.Tween( this.material ) - .easing( Tween.Easing.Quartic.Out ) - .onComplete( function () { + this.fadeOutAnimation = new Tween.Tween(this.material) + .easing(Tween.Easing.Quartic.Out) + .onComplete(function () { this.visible = false; // this.material.visible = true; @@ -4314,39 +4328,38 @@ * @event Panorama#leave-complete * @type {object} */ - this.dispatchEvent( { type: 'leave-complete' } ); + this.dispatchEvent({ type: 'leave-complete' }); - }.bind( this ) ); + }.bind(this)); - this.enterTransition = new Tween.Tween( this ) - .easing( Tween.Easing.Quartic.Out ) - .onComplete( function () { + this.enterTransition = new Tween.Tween(this) + .easing(Tween.Easing.Quartic.Out) + .onComplete(function () { /** * Enter panorama and animation complete event * @event Panorama#enter-complete * @type {object} */ - this.dispatchEvent( { type: 'enter-complete' } ); + this.dispatchEvent({ type: 'enter-complete' }); - }.bind ( this ) ) + }.bind(this)) .start(); - this.leaveTransition = new Tween.Tween( this ) - .easing( Tween.Easing.Quartic.Out ); - - }, + this.leaveTransition = new Tween.Tween(this) + .easing(Tween.Easing.Quartic.Out); - onFadeAnimationUpdate: function () { + } + onFadeAnimationUpdate() { const alpha = this.material.opacity; const { uniforms } = this.material; - if ( uniforms && uniforms.opacity ) { + if (uniforms && uniforms.opacity) { uniforms.opacity.value = alpha; } - }, + } /** * Start fading in animation @@ -4354,46 +4367,46 @@ * @instance * @fires Panorama#enter-fade-complete */ - fadeIn: function ( duration ) { + fadeIn(duration) { duration = duration >= 0 ? duration : this.animationDuration; this.fadeOutAnimation.stop(); this.fadeInAnimation - .to( { opacity: 1 }, duration ) - .onUpdate( this.onFadeAnimationUpdate.bind( this ) ) - .onComplete( function () { + .to({ opacity: 1 }, duration) + .onUpdate(this.onFadeAnimationUpdate.bind(this)) + .onComplete(function () { - this.toggleInfospotVisibility( true, duration / 2 ); + this.toggleInfospotVisibility(true, duration / 2); /** * Enter panorama fade complete event * @event Panorama#enter-fade-complete * @type {object} */ - this.dispatchEvent( { type: 'enter-fade-complete' } ); + this.dispatchEvent({ type: 'enter-fade-complete' }); - }.bind( this ) ) + }.bind(this)) .start(); - }, + } /** * Start fading out animation * @memberOf Panorama * @instance */ - fadeOut: function ( duration ) { + fadeOut(duration) { duration = duration >= 0 ? duration : this.animationDuration; this.fadeInAnimation.stop(); this.fadeOutAnimation - .to( { opacity: 0 }, duration ) - .onUpdate( this.onFadeAnimationUpdate.bind( this ) ) + .to({ opacity: 0 }, duration) + .onUpdate(this.onFadeAnimationUpdate.bind(this)) .start(); - }, + } /** * This will be called when entering a panorama @@ -4402,33 +4415,33 @@ * @fires Panorama#enter * @fires Panorama#enter-start */ - onEnter: function () { + onEnter() { const duration = this.animationDuration; this.leaveTransition.stop(); this.enterTransition - .to( {}, duration ) - .onStart( function () { + .to({}, duration) + .onStart(function () { /** * Enter panorama and animation starting event * @event Panorama#enter-start * @type {object} */ - this.dispatchEvent( { type: 'enter-start' } ); - - if ( this.loaded ) { + this.dispatchEvent({ type: 'enter-start' }); - this.fadeIn( duration ); + if (this.loaded) { + + this.fadeIn(duration); } else { this.load(); } - - }.bind( this ) ) + + }.bind(this)) .start(); /** @@ -4436,17 +4449,17 @@ * @event Panorama#enter * @type {object} */ - this.dispatchEvent( { type: 'enter' } ); + this.dispatchEvent({ type: 'enter' }); - this.children.forEach( child => { + this.children.forEach(child => { - child.dispatchEvent( { type: 'panorama-enter' } ); + child.dispatchEvent({ type: 'panorama-enter' }); - } ); + }); this.active = true; - }, + } /** * This will be called when leaving a panorama @@ -4454,26 +4467,26 @@ * @instance * @fires Panorama#leave */ - onLeave: function () { + onLeave() { const duration = this.animationDuration; this.enterTransition.stop(); this.leaveTransition - .to( {}, duration ) - .onStart( function () { + .to({}, duration) + .onStart(function () { /** * Leave panorama and animation starting event * @event Panorama#leave-start * @type {object} */ - this.dispatchEvent( { type: 'leave-start' } ); + this.dispatchEvent({ type: 'leave-start' }); - this.fadeOut( duration ); - this.toggleInfospotVisibility( false ); + this.fadeOut(duration); + this.toggleInfospotVisibility(false); - }.bind( this ) ) + }.bind(this)) .start(); /** @@ -4481,24 +4494,24 @@ * @event Panorama#leave * @type {object} */ - this.dispatchEvent( { type: 'leave' } ); + this.dispatchEvent({ type: 'leave' }); - this.children.forEach( child => { + this.children.forEach(child => { - child.dispatchEvent( { type: 'panorama-leave' } ); + child.dispatchEvent({ type: 'panorama-leave' }); - } ); + }); this.active = false; - }, + } /** * Dispose panorama * @memberOf Panorama * @instance */ - dispose: function () { + dispose() { this.infospotAnimation.stop(); this.fadeInAnimation.stop(); @@ -4513,72 +4526,58 @@ * @property {string} method - Viewer function name * @property {*} data - The argument to be passed into the method */ - this.dispatchEvent( { type: 'panolens-viewer-handler', method: 'onPanoramaDispose', data: this } ); + this.dispatchEvent({ type: 'panolens-viewer-handler', method: 'onPanoramaDispose', data: this }); // recursive disposal on 3d objects - function recursiveDispose ( object ) { + function recursiveDispose(object) { const { geometry, material } = object; - for ( var i = object.children.length - 1; i >= 0; i-- ) { + for (var i = object.children.length - 1; i >= 0; i--) { - recursiveDispose( object.children[i] ); - object.remove( object.children[i] ); + recursiveDispose(object.children[i]); + object.remove(object.children[i]); } - if ( object instanceof Infospot ) { + if (object instanceof Infospot) { object.dispose(); } - - if ( geometry ) { geometry.dispose(); object.geometry = null; } - if ( material ) { material.dispose(); object.material = null; } + + if (geometry) { geometry.dispose(); object.geometry = null; } + if (material) { material.dispose(); object.material = null; } } - recursiveDispose( this ); + recursiveDispose(this); - if ( this.parent ) { + if (this.parent) { - this.parent.remove( this ); + this.parent.remove(this); } - } - - } ); + } /** * @classdesc Equirectangular based image panorama * @constructor * @param {string} image - Image url or HTMLImageElement */ - function ImagePanorama ( image, _geometry, _material ) { - - const radius = 5000; - const geometry = _geometry || new THREE.SphereBufferGeometry( radius, 60, 40 ); - const material = _material || new THREE.MeshBasicMaterial( { opacity: 0, transparent: true } ); - - Panorama.call( this, geometry, material ); - - this.src = image; - this.radius = radius; - - } - - ImagePanorama.prototype = Object.assign( Object.create( Panorama.prototype ), { - - constructor: ImagePanorama, + class ImagePanorama extends Panorama { + constructor( image, _geometry, _material ) { + const radius = 5000; + const geometry = _geometry || new THREE__namespace.SphereBufferGeometry( radius, 60, 40 ); + const material = _material || new THREE__namespace.MeshBasicMaterial( { opacity: 0, transparent: true } ); + super(geometry, material); + + this.src = image; + this.radius = radius; + } - /** - * Load image asset - * @param {*} src - Url or image element - * @memberOf ImagePanorama - * @instance - */ - load: function ( src ) { + load ( src ) { src = src || this.src; @@ -4594,11 +4593,11 @@ } else if ( src instanceof HTMLImageElement ) { - this.onLoad( new THREE.Texture( src ) ); + this.onLoad( new THREE__namespace.Texture( src ) ); } - }, + } /** * This will be called when image is loaded @@ -4606,107 +4605,95 @@ * @memberOf ImagePanorama * @instance */ - onLoad: function ( texture ) { + onLoad( texture ) { - texture.minFilter = texture.magFilter = THREE.LinearFilter; + texture.minFilter = texture.magFilter = THREE__namespace.LinearFilter; texture.needsUpdate = true; - + this.updateTexture( texture ); window.requestAnimationFrame( Panorama.prototype.onLoad.bind( this ) ); - }, + } /** * Reset * @memberOf ImagePanorama * @instance */ - reset: function () { + reset() { Panorama.prototype.reset.call( this ); - }, + } /** * Dispose * @memberOf ImagePanorama * @instance */ - dispose: function () { + dispose() { const { material: { map } } = this; // Release cached image - THREE.Cache.remove( this.src ); + THREE__namespace.Cache.remove( this.src ); if ( map ) { map.dispose(); } Panorama.prototype.dispose.call( this ); } - - } ); + } /** * @classdesc Empty panorama * @constructor */ - function EmptyPanorama () { - - const geometry = new THREE.BufferGeometry(); - const material = new THREE.MeshBasicMaterial( { color: 0x000000, opacity: 0, transparent: true } ); - - geometry.addAttribute( 'position', new THREE.BufferAttribute( new Float32Array(), 1 ) ); - - Panorama.call( this, geometry, material ); - + class EmptyPanorama extends Panorama { + constructor() { + const geometry = new THREE__namespace.BufferGeometry(); + const material = new THREE__namespace.MeshBasicMaterial( { color: 0x000000, opacity: 0, transparent: true } ); + super(geometry, material); + geometry.setAttribute( 'position', new THREE__namespace.BufferAttribute( new Float32Array(), 1 ) ); + } } - EmptyPanorama.prototype = Object.assign( Object.create( Panorama.prototype ), { - - constructor: EmptyPanorama - - } ); - /** * @classdesc Cubemap-based panorama * @constructor * @param {array} images - Array of 6 urls to images, one for each side of the CubeTexture. The urls should be specified in the following order: pos-x, neg-x, pos-y, neg-y, pos-z, neg-z */ - function CubePanorama ( images = [] ){ + class CubePanorama extends Panorama { + constructor ( images = [] ) { - const edgeLength = 10000; - const shader = Object.assign( {}, THREE.ShaderLib[ 'cube' ] ); - const geometry = new THREE.BoxBufferGeometry( edgeLength, edgeLength, edgeLength ); - const material = new THREE.ShaderMaterial( { + const edgeLength = 10000; + const shader = Object.assign( {}, THREE__namespace.ShaderLib[ 'cube' ] ); + const geometry = new THREE__namespace.BoxBufferGeometry( edgeLength, edgeLength, edgeLength ); + const material = new THREE__namespace.ShaderMaterial( { - fragmentShader: shader.fragmentShader, - vertexShader: shader.vertexShader, - uniforms: shader.uniforms, - side: THREE.BackSide, - transparent: true - - } ); - - Panorama.call( this, geometry, material ); + fragmentShader: shader.fragmentShader, + vertexShader: shader.vertexShader, + uniforms: shader.uniforms, + side: THREE__namespace.BackSide, + transparent: true - this.images = images; - this.edgeLength = edgeLength; - this.material.uniforms.opacity.value = 0; + } ); - } + super(geometry, material); - CubePanorama.prototype = Object.assign( Object.create( Panorama.prototype ), { + this.images = images; + this.edgeLength = edgeLength; + this.material.uniforms.opacity.value = 0; - constructor: CubePanorama, + } /** * Load 6 images and bind listeners * @memberOf CubePanorama * @instance */ - load: function () { + load () { CubeTextureLoader.load( @@ -4718,7 +4705,7 @@ ); - }, + } /** * This will be called when 6 textures are ready @@ -4726,26 +4713,26 @@ * @memberOf CubePanorama * @instance */ - onLoad: function ( texture ) { + onLoad ( texture ) { this.material.uniforms[ 'tCube' ].value = texture; Panorama.prototype.onLoad.call( this ); - }, + } /** * Dispose * @memberOf CubePanorama * @instance */ - dispose: function () { + dispose () { const { value } = this.material.uniforms.tCube; - this.images.forEach( ( image ) => { THREE.Cache.remove( image ); } ); + this.images.forEach( ( image ) => { THREE__namespace.Cache.remove( image ); } ); - if ( value instanceof THREE.CubeTexture ) { + if ( value instanceof THREE__namespace.CubeTexture ) { value.dispose(); @@ -4754,33 +4741,24 @@ Panorama.prototype.dispose.call( this ); } - - } ); + } /** * @classdesc Basic panorama with 6 pre-defined grid images * @constructor */ - function BasicPanorama () { - - const images = []; + class BasicPanorama extends CubePanorama { - for ( let i = 0; i < 6; i++ ) { - - images.push( DataImage.WhiteTile ); + constructor() { + super(); + const images = []; + for ( let i = 0; i < 6; i++ ) { + images.push( DataImage.WhiteTile ); + } } - - CubePanorama.call( this, images ); - } - BasicPanorama.prototype = Object.assign( Object.create( CubePanorama.prototype ), { - - constructor: BasicPanorama - - } ); - /** * @classdesc Video Panorama * @constructor @@ -4794,50 +4772,45 @@ * @param {string} [options.crossOrigin="anonymous"] - Sets the cross-origin attribute for the video, which allows for cross-origin videos in some browsers (Firefox, Chrome). Set to either "anonymous" or "use-credentials". * @param {number} [radius=5000] - The minimum radius for this panoram */ - function VideoPanorama ( src, options = {} ) { - - const radius = 5000; - const geometry = new THREE.SphereBufferGeometry( radius, 60, 40 ); - const material = new THREE.MeshBasicMaterial( { opacity: 0, transparent: true } ); - - Panorama.call( this, geometry, material ); - - this.src = src; - - this.options = { - - videoElement: document.createElement( 'video' ), - loop: true, - muted: true, - autoplay: false, - playsinline: true, - crossOrigin: 'anonymous' - - }; - - Object.assign( this.options, options ); + class VideoPanorama extends Panorama { + + constructor( src, options = {} ) { + const radius = 5000; + const geometry = new THREE__namespace.SphereBufferGeometry( radius, 60, 40 ); + const material = new THREE__namespace.MeshBasicMaterial( { opacity: 0, transparent: true } ); + super(geometry, material); + + this.src = src; + + this.options = { + videoElement: document.createElement( 'video' ), + loop: true, + muted: true, + autoplay: false, + playsinline: true, + crossOrigin: 'anonymous' + }; - this.videoElement = this.options.videoElement; - this.videoProgress = 0; - this.radius = radius; + Object.assign( this.options, options ); - this.addEventListener( 'leave', this.pauseVideo.bind( this ) ); - this.addEventListener( 'enter-fade-start', this.resumeVideoProgress.bind( this ) ); - this.addEventListener( 'video-toggle', this.toggleVideo.bind( this ) ); - this.addEventListener( 'video-time', this.setVideoCurrentTime.bind( this ) ); + this.videoElement = this.options.videoElement; + this.videoProgress = 0; + this.radius = radius; - } - VideoPanorama.prototype = Object.assign( Object.create( Panorama.prototype ), { + this.addEventListener( 'leave', this.pauseVideo.bind( this ) ); + this.addEventListener( 'enter-fade-start', this.resumeVideoProgress.bind( this ) ); + this.addEventListener( 'video-toggle', this.toggleVideo.bind( this ) ); + this.addEventListener( 'video-time', this.setVideoCurrentTime.bind( this ) ); + } - constructor: VideoPanorama, - isMobile: function () { + isMobile () { let check = false; (function(a){if(/(android|bb\d+|meego).+mobile|avantgo|bada\/|blackberry|blazer|compal|elaine|fennec|hiptop|iemobile|ip(hone|od)|iris|kindle|lge |maemo|midp|mmp|mobile.+firefox|netfront|opera m(ob|in)i|palm( os)?|phone|p(ixi|re)\/|plucker|pocket|psp|series(4|6)0|symbian|treo|up\.(browser|link)|vodafone|wap|windows ce|xda|xiino/i.test(a)||/1207|6310|6590|3gso|4thp|50[1-6]i|770s|802s|a wa|abac|ac(er|oo|s\-)|ai(ko|rn)|al(av|ca|co)|amoi|an(ex|ny|yw)|aptu|ar(ch|go)|as(te|us)|attw|au(di|\-m|r |s )|avan|be(ck|ll|nq)|bi(lb|rd)|bl(ac|az)|br(e|v)w|bumb|bw\-(n|u)|c55\/|capi|ccwa|cdm\-|cell|chtm|cldc|cmd\-|co(mp|nd)|craw|da(it|ll|ng)|dbte|dc\-s|devi|dica|dmob|do(c|p)o|ds(12|\-d)|el(49|ai)|em(l2|ul)|er(ic|k0)|esl8|ez([4-7]0|os|wa|ze)|fetc|fly(\-|_)|g1 u|g560|gene|gf\-5|g\-mo|go(\.w|od)|gr(ad|un)|haie|hcit|hd\-(m|p|t)|hei\-|hi(pt|ta)|hp( i|ip)|hs\-c|ht(c(\-| |_|a|g|p|s|t)|tp)|hu(aw|tc)|i\-(20|go|ma)|i230|iac( |\-|\/)|ibro|idea|ig01|ikom|im1k|inno|ipaq|iris|ja(t|v)a|jbro|jemu|jigs|kddi|keji|kgt( |\/)|klon|kpt |kwc\-|kyo(c|k)|le(no|xi)|lg( g|\/(k|l|u)|50|54|\-[a-w])|libw|lynx|m1\-w|m3ga|m50\/|ma(te|ui|xo)|mc(01|21|ca)|m\-cr|me(rc|ri)|mi(o8|oa|ts)|mmef|mo(01|02|bi|de|do|t(\-| |o|v)|zz)|mt(50|p1|v )|mwbp|mywa|n10[0-2]|n20[2-3]|n30(0|2)|n50(0|2|5)|n7(0(0|1)|10)|ne((c|m)\-|on|tf|wf|wg|wt)|nok(6|i)|nzph|o2im|op(ti|wv)|oran|owg1|p800|pan(a|d|t)|pdxg|pg(13|\-([1-8]|c))|phil|pire|pl(ay|uc)|pn\-2|po(ck|rt|se)|prox|psio|pt\-g|qa\-a|qc(07|12|21|32|60|\-[2-7]|i\-)|qtek|r380|r600|raks|rim9|ro(ve|zo)|s55\/|sa(ge|ma|mm|ms|ny|va)|sc(01|h\-|oo|p\-)|sdk\/|se(c(\-|0|1)|47|mc|nd|ri)|sgh\-|shar|sie(\-|m)|sk\-0|sl(45|id)|sm(al|ar|b3|it|t5)|so(ft|ny)|sp(01|h\-|v\-|v )|sy(01|mb)|t2(18|50)|t6(00|10|18)|ta(gt|lk)|tcl\-|tdg\-|tel(i|m)|tim\-|t\-mo|to(pl|sh)|ts(70|m\-|m3|m5)|tx\-9|up(\.b|g1|si)|utst|v400|v750|veri|vi(rg|te)|vk(40|5[0-3]|\-v)|vm40|voda|vulc|vx(52|53|60|61|70|80|81|83|85|98)|w3c(\-| )|webc|whit|wi(g |nc|nw)|wmlb|wonu|x700|yas\-|your|zeto|zte\-/i.test(a.substr(0,4))) check = true;})( window.navigator.userAgent || window.navigator.vendor || window.opera ); return check; - }, + } /** * Load video panorama @@ -4845,7 +4818,7 @@ * @instance * @fires Panorama#panolens-viewer-handler */ - load: function () { + load () { const { muted, loop, autoplay, playsinline, crossOrigin } = this.options; const video = this.videoElement; @@ -4858,7 +4831,7 @@ video.playsinline = playsinline; video.crossOrigin = crossOrigin; video.muted = muted; - + if ( playsinline ) { video.setAttribute( 'playsinline', '' ); @@ -4908,7 +4881,7 @@ this.dispatchEvent( { type: 'panolens-viewer-handler', method: 'updateVideoPlayButton', data: true } ); } - + } const loaded = () => { @@ -4922,7 +4895,7 @@ }; window.requestAnimationFrame( loaded ); - + }; /** @@ -4951,7 +4924,7 @@ } video.addEventListener( 'loadeddata', onloadeddata.bind( this ) ); - + video.addEventListener( 'timeupdate', function () { this.videoProgress = video.duration >= 0 ? video.currentTime / video.duration : 0; @@ -4967,7 +4940,7 @@ }.bind( this ) ); video.addEventListener( 'ended', function () { - + if ( !loop ) { this.resetVideo(); @@ -4977,7 +4950,7 @@ }.bind( this ), false ); - }, + } /** * Set video texture @@ -4986,31 +4959,31 @@ * @param {HTMLVideoElement} video - The html5 video element * @fires Panorama#panolens-viewer-handler */ - setVideoTexture: function ( video ) { + setVideoTexture ( video ) { if ( !video ) return; - const videoTexture = new THREE.VideoTexture( video ); - videoTexture.minFilter = THREE.LinearFilter; - videoTexture.magFilter = THREE.LinearFilter; - videoTexture.format = THREE.RGBFormat; + const videoTexture = new THREE__namespace.VideoTexture( video ); + videoTexture.minFilter = THREE__namespace.LinearFilter; + videoTexture.magFilter = THREE__namespace.LinearFilter; + videoTexture.format = THREE__namespace.RGBFormat; this.updateTexture( videoTexture ); - - }, + + } /** * Reset * @memberOf VideoPanorama * @instance */ - reset: function () { + reset () { this.videoElement = undefined; Panorama.prototype.reset.call( this ); - }, + } /** * Check if video is paused @@ -5018,18 +4991,18 @@ * @instance * @return {boolean} - is video paused or not */ - isVideoPaused: function () { + isVideoPaused () { return this.videoElement.paused; - }, + } /** * Toggle video to play or pause * @memberOf VideoPanorama * @instance */ - toggleVideo: function () { + toggleVideo () { const video = this.videoElement; @@ -5037,7 +5010,7 @@ video[ video.paused ? 'play' : 'pause' ](); - }, + } /** * Set video currentTime @@ -5045,7 +5018,7 @@ * @instance * @param {object} event - Event contains percentage. Range from 0.0 to 1.0 */ - setVideoCurrentTime: function ( { percentage } ) { + setVideoCurrentTime ( { percentage } ) { const video = this.videoElement; @@ -5057,7 +5030,7 @@ } - }, + } /** * Play video @@ -5066,7 +5039,7 @@ * @fires VideoPanorama#play * @fires VideoPanorama#play-error */ - playVideo: function () { + playVideo () { const video = this.videoElement; const playVideo = this.playVideo.bind( this ); @@ -5103,7 +5076,7 @@ } - }, + } /** * Pause video @@ -5111,7 +5084,7 @@ * @instance * @fires VideoPanorama#pause */ - pauseVideo: function () { + pauseVideo () { const video = this.videoElement; @@ -5129,14 +5102,14 @@ */ this.dispatchEvent( { type: 'pause' } ); - }, + } /** * Resume video * @memberOf VideoPanorama * @instance */ - resumeVideoProgress: function () { + resumeVideoProgress () { const video = this.videoElement; @@ -5168,14 +5141,14 @@ this.setVideoCurrentTime( { percentage: this.videoProgress } ); - }, + } /** * Reset video at stating point * @memberOf VideoPanorama * @instance */ - resetVideo: function () { + resetVideo () { const video = this.videoElement; @@ -5185,7 +5158,7 @@ } - }, + } /** * Check if video is muted @@ -5193,18 +5166,18 @@ * @instance * @return {boolean} - is video muted or not */ - isVideoMuted: function () { + isVideoMuted () { return this.videoElement.muted; - }, + } /** * Mute video * @memberOf VideoPanorama * @instance */ - muteVideo: function () { + muteVideo () { const video = this.videoElement; @@ -5216,14 +5189,14 @@ this.dispatchEvent( { type: 'volumechange' } ); - }, + } /** * Unmute video * @memberOf VideoPanorama * @instance */ - unmuteVideo: function () { + unmuteVideo () { const video = this.videoElement; @@ -5235,7 +5208,7 @@ this.dispatchEvent( { type: 'volumechange' } ); - }, + } /** * Returns the video element @@ -5243,23 +5216,23 @@ * @instance * @returns {HTMLElement} */ - getVideoElement: function () { + getVideoElement () { return this.videoElement; - }, + } /** * Dispose video panorama * @memberOf VideoPanorama * @instance */ - dispose: function () { + dispose () { const { material: { map } } = this; this.pauseVideo(); - + this.removeEventListener( 'leave', this.pauseVideo.bind( this ) ); this.removeEventListener( 'enter-fade-start', this.resumeVideoProgress.bind( this ) ); this.removeEventListener( 'video-toggle', this.toggleVideo.bind( this ) ); @@ -5270,8 +5243,8 @@ Panorama.prototype.dispose.call( this ); } - - } ); + + } /** * @classdesc Google Street View Loader @@ -5525,23 +5498,18 @@ * @param {string} panoId - Panorama id from Google Streetview * @param {string} [apiKey] - Google Street View API Key */ - function GoogleStreetviewPanorama ( panoId, apiKey ) { - - ImagePanorama.call( this ); - - this.panoId = panoId; - - this.gsvLoader = null; - - this.loadRequested = false; - - this.setupGoogleMapAPI( apiKey ); - - } - - GoogleStreetviewPanorama.prototype = Object.assign( Object.create( ImagePanorama.prototype ), { + class GoogleStreetviewPanorama extends ImagePanorama { + + constructor( panoId, apiKey ) { + super(); + this.panoId = panoId; - constructor: GoogleStreetviewPanorama, + this.gsvLoader = null; + + this.loadRequested = false; + + this.setupGoogleMapAPI( apiKey ); + } /** * Load Google Street View by panorama id @@ -5549,114 +5517,113 @@ * @memberOf GoogleStreetviewPanorama * @instance */ - load: function ( panoId ) { + load ( panoId ) { this.loadRequested = true; - + panoId = ( panoId || this.panoId ) || {}; - + if ( panoId && this.gsvLoader ) { - + this.loadGSVLoader( panoId ); - + } - - }, - + + } + /** * Setup Google Map API * @param {string} apiKey * @memberOf GoogleStreetviewPanorama * @instance */ - setupGoogleMapAPI: function ( apiKey ) { - + setupGoogleMapAPI ( apiKey ) { + const script = document.createElement( 'script' ); script.src = 'https://maps.googleapis.com/maps/api/js?'; script.src += apiKey ? 'key=' + apiKey : ''; script.onreadystatechange = this.setGSVLoader.bind( this ); script.onload = this.setGSVLoader.bind( this ); - + document.querySelector( 'head' ).appendChild( script ); - - }, - + + } + /** * Set GSV Loader * @memberOf GoogleStreetviewPanorama * @instance */ - setGSVLoader: function () { - + setGSVLoader () { + this.gsvLoader = new GoogleStreetviewLoader(); - + if ( this.loadRequested ) { - + this.load(); - + } - - }, - + + } + /** * Get GSV Loader * @memberOf GoogleStreetviewPanorama * @instance * @return {GoogleStreetviewLoader} GSV Loader instance */ - getGSVLoader: function () { - + getGSVLoader () { + return this.gsvLoader; - - }, - + + } + /** * Load GSV Loader * @param {string} panoId - Gogogle Street View panorama id * @memberOf GoogleStreetviewPanorama * @instance */ - loadGSVLoader: function ( panoId ) { - + loadGSVLoader ( panoId ) { + this.loadRequested = false; - + this.gsvLoader.onProgress = this.onProgress.bind( this ); - + this.gsvLoader.onPanoramaLoad = this.onLoad.bind( this ); - + this.gsvLoader.setZoom( this.getZoomLevel() ); - + this.gsvLoader.load( panoId ); - + this.gsvLoader.loaded = true; - }, - + } + /** * This will be called when panorama is loaded * @param {HTMLCanvasElement} canvas - Canvas where the tiles have been drawn * @memberOf GoogleStreetviewPanorama * @instance */ - onLoad: function ( canvas ) { - - ImagePanorama.prototype.onLoad.call( this, new THREE.Texture( canvas ) ); - - }, - + onLoad ( canvas ) { + + ImagePanorama.prototype.onLoad.call( this, new THREE__namespace.Texture( canvas ) ); + + } + /** * Reset * @memberOf GoogleStreetviewPanorama * @instance */ - reset: function () { - + reset () { + this.gsvLoader = undefined; - + ImagePanorama.prototype.reset.call( this ); - + } - - } ); + } /** * Stereographic projection shader @@ -5680,9 +5647,9 @@ uniforms: { - 'tDiffuse': { value: new THREE.Texture() }, + 'tDiffuse': { value: new THREE__namespace.Texture() }, 'resolution': { value: 1.0 }, - 'transform': { value: new THREE.Matrix4() }, + 'transform': { value: new THREE__namespace.Matrix4() }, 'zoom': { value: 1.0 }, 'opacity': { value: 1.0 } @@ -5747,42 +5714,38 @@ * @param {number} [size=10000] - Size of plane geometry * @param {number} [ratio=0.5] - Ratio of plane geometry's height against width */ - function LittlePlanet ( type = 'image', source, size = 10000, ratio = 0.5 ) { - - if ( type === 'image' ) { - - ImagePanorama.call( this, source, this.createGeometry( size, ratio ), this.createMaterial( size ) ); - - } - - this.size = size; - this.ratio = ratio; - this.EPS = 0.000001; - this.frameId = null; - - this.dragging = false; - this.userMouse = new THREE.Vector2(); - - this.quatA = new THREE.Quaternion(); - this.quatB = new THREE.Quaternion(); - this.quatCur = new THREE.Quaternion(); - this.quatSlerp = new THREE.Quaternion(); + class LittlePlanet extends ImagePanorama { + constructor( type = 'image', source, size = 10000, ratio = 0.5 ) { + if ( type === 'image' ) { + super(source, LittlePlanet.createGeometry( size, ratio ), LittlePlanet.createMaterial( size ) ); + } + else { + super(); + } - this.vectorX = new THREE.Vector3( 1, 0, 0 ); - this.vectorY = new THREE.Vector3( 0, 1, 0 ); + this.size = size; + this.ratio = ratio; + this.EPS = 0.000001; + this.frameId = null; - this.addEventListener( 'window-resize', this.onWindowResize ); + this.dragging = false; + this.userMouse = new THREE__namespace.Vector2(); - } + this.quatA = new THREE__namespace.Quaternion(); + this.quatB = new THREE__namespace.Quaternion(); + this.quatCur = new THREE__namespace.Quaternion(); + this.quatSlerp = new THREE__namespace.Quaternion(); - LittlePlanet.prototype = Object.assign( Object.create( ImagePanorama.prototype ), { + this.vectorX = new THREE__namespace.Vector3( 1, 0, 0 ); + this.vectorY = new THREE__namespace.Vector3( 0, 1, 0 ); - constructor: LittlePlanet, + this.addEventListener( 'window-resize', this.onWindowResize ); + } - add: function ( object ) { + add ( object ) { if ( arguments.length > 1 ) { - + for ( let i = 0; i < arguments.length; i ++ ) { this.add( arguments[ i ] ); @@ -5796,39 +5759,39 @@ if ( object instanceof Infospot ) { object.material.depthTest = false; - + } ImagePanorama.prototype.add.call( this, object ); - }, + } - createGeometry: function ( size, ratio ) { + static createGeometry ( size, ratio ) { - return new THREE.PlaneBufferGeometry( size, size * ratio ); + return new THREE__namespace.PlaneBufferGeometry( size, size * ratio ); - }, + } - createMaterial: function ( size ) { + static createMaterial ( size ) { const shader = Object.assign( {}, StereographicShader ), uniforms = shader.uniforms; uniforms.zoom.value = size; uniforms.opacity.value = 0.0; - return new THREE.ShaderMaterial( { + return new THREE__namespace.ShaderMaterial( { uniforms: uniforms, vertexShader: shader.vertexShader, fragmentShader: shader.fragmentShader, - side: THREE.BackSide, + side: THREE__namespace.BackSide, transparent: true } ); - - }, - registerMouseEvents: function () { + } + + registerMouseEvents () { this.container.addEventListener( 'mousedown', this.onMouseDown.bind( this ), { passive: true } ); this.container.addEventListener( 'mousemove', this.onMouseMove.bind( this ), { passive: true } ); @@ -5839,10 +5802,10 @@ this.container.addEventListener( 'mousewheel', this.onMouseWheel.bind( this ), { passive: false } ); this.container.addEventListener( 'DOMMouseScroll', this.onMouseWheel.bind( this ), { passive: false } ); this.container.addEventListener( 'contextmenu', this.onContextMenu.bind( this ), { passive: true } ); - - }, - unregisterMouseEvents: function () { + } + + unregisterMouseEvents () { this.container.removeEventListener( 'mousedown', this.onMouseDown.bind( this ), false ); this.container.removeEventListener( 'mousemove', this.onMouseMove.bind( this ), false ); @@ -5853,10 +5816,10 @@ this.container.removeEventListener( 'mousewheel', this.onMouseWheel.bind( this ), false ); this.container.removeEventListener( 'DOMMouseScroll', this.onMouseWheel.bind( this ), false ); this.container.removeEventListener( 'contextmenu', this.onContextMenu.bind( this ), false ); - - }, - onMouseDown: function ( event ) { + } + + onMouseDown ( event ) { const inputCount = ( event.touches && event.touches.length ) || 1 ; @@ -5881,17 +5844,13 @@ break; - default: - - break; - } this.onUpdateCallback(); - }, + } - onMouseMove: function ( event ) { + onMouseMove ( event ) { const inputCount = ( event.touches && event.touches.length ) || 1 ; @@ -5902,8 +5861,8 @@ const x = ( event.clientX >= 0 ) ? event.clientX : event.touches[ 0 ].clientX; const y = ( event.clientY >= 0 ) ? event.clientY : event.touches[ 0 ].clientY; - const angleX = THREE.Math.degToRad( x - this.userMouse.x ) * 0.4; - const angleY = THREE.Math.degToRad( y - this.userMouse.y ) * 0.4; + const angleX = THREE__namespace.Math.degToRad( x - this.userMouse.x ) * 0.4; + const angleY = THREE__namespace.Math.degToRad( y - this.userMouse.y ) * 0.4; if ( this.dragging ) { this.quatA.setFromAxisAngle( this.vectorY, angleX ); @@ -5924,21 +5883,17 @@ break; - default: - - break; - } - }, + } - onMouseUp: function () { + onMouseUp () { this.dragging = false; - }, + } - onMouseWheel: function ( event ) { + onMouseWheel ( event ) { event.preventDefault(); event.stopPropagation(); @@ -5958,9 +5913,9 @@ this.addZoomDelta( delta ); this.onUpdateCallback(); - }, + } - addZoomDelta: function ( delta ) { + addZoomDelta ( delta ) { const uniforms = this.material.uniforms; const lowerBound = this.size * 0.1; @@ -5977,10 +5932,9 @@ uniforms.zoom.value = upperBound; } + } - }, - - onUpdateCallback: function () { + onUpdateCallback () { this.frameId = window.requestAnimationFrame( this.onUpdateCallback.bind( this ) ); @@ -5991,37 +5945,37 @@ this.material.uniforms.transform.value.makeRotationFromQuaternion( this.quatSlerp ); } - + if ( !this.dragging && 1.0 - this.quatSlerp.clone().dot( this.quatCur ) < this.EPS ) { - + window.cancelAnimationFrame( this.frameId ); } - }, + } - reset: function () { + reset () { this.quatCur.set( 0, 0, 0, 1 ); this.quatSlerp.set( 0, 0, 0, 1 ); this.onUpdateCallback(); - }, + } - onLoad: function ( texture ) { + onLoad ( texture ) { this.material.uniforms.resolution.value = this.container.clientWidth / this.container.clientHeight; this.registerMouseEvents(); this.onUpdateCallback(); - + this.dispatchEvent( { type: 'panolens-viewer-handler', method: 'disableControl' } ); ImagePanorama.prototype.onLoad.call( this, texture ); - - }, - onLeave: function () { + } + + onLeave () { this.unregisterMouseEvents(); @@ -6030,22 +5984,20 @@ window.cancelAnimationFrame( this.frameId ); ImagePanorama.prototype.onLeave.call( this ); - - }, - onWindowResize: function () { + } + onWindowResize () { this.material.uniforms.resolution.value = this.container.clientWidth / this.container.clientHeight; + } - }, - - onContextMenu: function () { + onContextMenu () { this.dragging = false; - }, + } - dispose: function () { + dispose () { this.unregisterMouseEvents(); @@ -6053,7 +6005,9 @@ } - }); + + + } /** * @classdesc Image Little Planet @@ -6062,15 +6016,11 @@ * @param {number} [size=10000] - Size of plane geometry * @param {number} [ratio=0.5] - Ratio of plane geometry's height against width */ - function ImageLittlePlanet ( source, size, ratio ) { - - LittlePlanet.call( this, 'image', source, size, ratio ); - - } - - ImageLittlePlanet.prototype = Object.assign( Object.create( LittlePlanet.prototype ), { + class ImageLittlePlanet extends LittlePlanet { + constructor( source, size, ratio ) { + super(source, size, ratio); + } - constructor: ImageLittlePlanet, /** * On loaded with texture @@ -6078,34 +6028,33 @@ * @memberOf ImageLittlePlanet * @instance */ - onLoad: function ( texture ) { + onLoad ( texture ) { this.updateTexture( texture ); LittlePlanet.prototype.onLoad.call( this, texture ); - - }, - + } + /** * Update texture * @param {THREE.Texture} texture * @memberOf ImageLittlePlanet * @instance */ - updateTexture: function ( texture ) { + updateTexture ( texture ) { - texture.minFilter = texture.magFilter = THREE.LinearFilter; - + texture.minFilter = texture.magFilter = THREE__namespace.LinearFilter; + this.material.uniforms[ 'tDiffuse' ].value = texture; - }, + } /** * Dispose * @memberOf ImageLittlePlanet * @instance */ - dispose: function () { + dispose () { const tDiffuse = this.material.uniforms[ 'tDiffuse' ]; @@ -6118,8 +6067,7 @@ LittlePlanet.prototype.dispose.call( this ); } - - } ); + } /** * @classdesc Camera panorama @@ -6127,27 +6075,23 @@ * @param {object} - camera constraints * @constructor */ - function CameraPanorama ( constraints ) { - - const radius = 5000; - const geometry = new THREE.SphereBufferGeometry( radius, 60, 40 ); - const material = new THREE.MeshBasicMaterial( { visible: false }); - - Panorama.call( this, geometry, material ); - - this.media = new Media( constraints ); - this.radius = radius; - - this.addEventListener( 'enter', this.start.bind( this ) ); - this.addEventListener( 'leave', this.stop.bind( this ) ); - this.addEventListener( 'panolens-container', this.onPanolensContainer.bind( this ) ); - this.addEventListener( 'panolens-scene', this.onPanolensScene.bind( this ) ); + class CameraPanorama extends Panorama { + constructor( constraints ) { + const radius = 5000; + const geometry = new THREE__namespace.SphereBufferGeometry( radius, 60, 40 ); + const material = new THREE__namespace.MeshBasicMaterial( { visible: false }); + + super(geometry, material); - } + this.media = new Media( constraints ); + this.radius = radius; - CameraPanorama.prototype = Object.assign( Object.create( Panorama.prototype ), { + this.addEventListener( 'enter', this.start.bind( this ) ); + this.addEventListener( 'leave', this.stop.bind( this ) ); + this.addEventListener( 'panolens-container', this.onPanolensContainer.bind( this ) ); + this.addEventListener( 'panolens-scene', this.onPanolensScene.bind( this ) ); - constructor: CameraPanorama, + } /** * On container event @@ -6155,11 +6099,9 @@ * @memberOf CameraPanorama * @instance */ - onPanolensContainer: function ( { container } ) { - + onPanolensContainer ( { container } ) { this.media.setContainer( container ); - - }, + } /** * On scene event @@ -6167,11 +6109,9 @@ * @memberOf CameraPanorama * @instance */ - onPanolensScene: function ( { scene } ) { - + onPanolensScene( { scene } ) { this.media.setScene( scene ); - - }, + } /** * Start camera streaming @@ -6179,24 +6119,19 @@ * @instance * @returns {Promise} */ - start: function () { - + start() { return this.media.start(); - - }, + } /** * Stop camera streaming * @memberOf CameraPanorama * @instance */ - stop: function () { - + stop() { this.media.stop(); - - }, - - } ); + } + } /** * @classdesc Orbit Controls @@ -6220,7 +6155,7 @@ * "target" sets the location of focus, where the control orbits around * and where it pans with respect to. */ - this.target = new THREE.Vector3(); + this.target = new THREE__namespace.Vector3(); // center is old, deprecated; use "target" instead this.center = this.target; @@ -6231,6 +6166,7 @@ */ this.noZoom = false; this.zoomSpeed = 1.0; + this.revertZoomScrollDirection = false; // Limits to how far you can dolly in and out ( PerspectiveCamera only ) this.minDistance = 0; @@ -6282,7 +6218,7 @@ this.keys = { LEFT: 37, UP: 38, RIGHT: 39, BOTTOM: 40 }; // Mouse buttons - this.mouseButtons = { ORBIT: THREE.MOUSE.LEFT, ZOOM: THREE.MOUSE.MIDDLE, PAN: THREE.MOUSE.RIGHT }; + this.mouseButtons = { ORBIT: THREE__namespace.MOUSE.LEFT, ZOOM: THREE__namespace.MOUSE.MIDDLE, PAN: THREE__namespace.MOUSE.RIGHT }; /* * ////////// @@ -6294,30 +6230,30 @@ var EPS = 10e-8; var MEPS = 10e-5; - var rotateStart = new THREE.Vector2(); - var rotateEnd = new THREE.Vector2(); - var rotateDelta = new THREE.Vector2(); + var rotateStart = new THREE__namespace.Vector2(); + var rotateEnd = new THREE__namespace.Vector2(); + var rotateDelta = new THREE__namespace.Vector2(); - var panStart = new THREE.Vector2(); - var panEnd = new THREE.Vector2(); - var panDelta = new THREE.Vector2(); - var panOffset = new THREE.Vector3(); + var panStart = new THREE__namespace.Vector2(); + var panEnd = new THREE__namespace.Vector2(); + var panDelta = new THREE__namespace.Vector2(); + var panOffset = new THREE__namespace.Vector3(); - var offset = new THREE.Vector3(); + var offset = new THREE__namespace.Vector3(); - var dollyStart = new THREE.Vector2(); - var dollyEnd = new THREE.Vector2(); - var dollyDelta = new THREE.Vector2(); + var dollyStart = new THREE__namespace.Vector2(); + var dollyEnd = new THREE__namespace.Vector2(); + var dollyDelta = new THREE__namespace.Vector2(); var theta = 0; var phi = 0; var phiDelta = 0; var thetaDelta = 0; var scale = 1; - var pan = new THREE.Vector3(); + var pan = new THREE__namespace.Vector3(); - var lastPosition = new THREE.Vector3(); - var lastQuaternion = new THREE.Quaternion(); + var lastPosition = new THREE__namespace.Vector3(); + var lastQuaternion = new THREE__namespace.Quaternion(); var momentumLeft = 0, momentumUp = 0; var eventPrevious; @@ -6337,8 +6273,8 @@ // so camera.up is the orbit axis - var quat = new THREE.Quaternion().setFromUnitVectors( object.up, new THREE.Vector3( 0, 1, 0 ) ); - var quatInverse = quat.clone().inverse(); + var quat = new THREE__namespace.Quaternion().setFromUnitVectors( object.up, new THREE__namespace.Vector3( 0, 1, 0 ) ); + var quatInverse = quat.clone().invert(); // events @@ -6414,7 +6350,7 @@ var element = scope.domElement === document ? scope.domElement.body : scope.domElement; - if ( scope.object instanceof THREE.PerspectiveCamera ) { + if ( scope.object instanceof THREE__namespace.PerspectiveCamera ) { // perspective var position = scope.object.position; @@ -6428,7 +6364,7 @@ scope.panLeft( 2 * deltaX * targetDistance / element.clientHeight ); scope.panUp( 2 * deltaY * targetDistance / element.clientHeight ); - } else if ( scope.object instanceof THREE.OrthographicCamera ) { + } else if ( scope.object instanceof THREE__namespace.OrthographicCamera ) { // orthographic scope.panLeft( deltaX * (scope.object.right - scope.object.left) / element.clientWidth ); @@ -6469,11 +6405,11 @@ } - if ( scope.object instanceof THREE.PerspectiveCamera ) { + if ( scope.object instanceof THREE__namespace.PerspectiveCamera ) { scale /= dollyScale; - } else if ( scope.object instanceof THREE.OrthographicCamera ) { + } else if ( scope.object instanceof THREE__namespace.OrthographicCamera ) { scope.object.zoom = Math.max( this.minZoom, Math.min( this.maxZoom, this.object.zoom * dollyScale ) ); scope.object.updateProjectionMatrix(); @@ -6495,11 +6431,11 @@ } - if ( scope.object instanceof THREE.PerspectiveCamera ) { + if ( scope.object instanceof THREE__namespace.PerspectiveCamera ) { scale *= dollyScale; - } else if ( scope.object instanceof THREE.OrthographicCamera ) { + } else if ( scope.object instanceof THREE__namespace.OrthographicCamera ) { scope.object.zoom = Math.max( this.minZoom, Math.min( this.maxZoom, this.object.zoom / dollyScale ) ); scope.object.updateProjectionMatrix(); @@ -6772,8 +6708,10 @@ delta = - event.detail; } + const zoomOut = delta > 0; + const zoomIn = delta < 0; - if ( delta > 0 ) { + if ( !scope.revertZoomScrollDirection ? zoomOut : !zoomOut ) { // scope.dollyOut(); scope.object.fov = ( scope.object.fov < scope.maxFov ) @@ -6781,7 +6719,7 @@ : scope.maxFov; scope.object.updateProjectionMatrix(); - } else if ( delta < 0 ) { + } else if ( !scope.revertZoomScrollDirection ? zoomIn : !zoomIn ) { // scope.dollyIn(); scope.object.fov = ( scope.object.fov > scope.minFov ) @@ -7051,7 +6989,7 @@ this.update(); } - OrbitControls.prototype = Object.assign( Object.create( THREE.EventDispatcher.prototype ), { + OrbitControls.prototype = Object.assign( Object.create( THREE__namespace.EventDispatcher.prototype ), { constructor: OrbitControls @@ -7114,8 +7052,8 @@ event.preventDefault(); event.stopPropagation(); - rotY += THREE.Math.degToRad( ( event.touches[ 0 ].pageX - tempX ) / 4 ); - rotX += THREE.Math.degToRad( ( tempY - event.touches[ 0 ].pageY ) / 4 ); + rotY += THREE__namespace.Math.degToRad( ( event.touches[ 0 ].pageX - tempX ) / 4 ); + rotX += THREE__namespace.Math.degToRad( ( tempY - event.touches[ 0 ].pageY ) / 4 ); scope.updateAlphaOffsetAngle( rotY ); @@ -7128,36 +7066,36 @@ var setCameraQuaternion = function( quaternion, alpha, beta, gamma, orient ) { - var zee = new THREE.Vector3( 0, 0, 1 ); + var zee = new THREE__namespace.Vector3( 0, 0, 1 ); - var euler = new THREE.Euler(); + var euler = new THREE__namespace.Euler(); - var q0 = new THREE.Quaternion(); + var q0 = new THREE__namespace.Quaternion(); - var q1 = new THREE.Quaternion( - Math.sqrt( 0.5 ), 0, 0, Math.sqrt( 0.5 ) ); // - PI/2 around the x-axis + var q1 = new THREE__namespace.Quaternion( - Math.sqrt( 0.5 ), 0, 0, Math.sqrt( 0.5 ) ); // - PI/2 around the x-axis var vectorFingerY; - var fingerQY = new THREE.Quaternion(); - var fingerQX = new THREE.Quaternion(); + var fingerQY = new THREE__namespace.Quaternion(); + var fingerQX = new THREE__namespace.Quaternion(); if ( scope.screenOrientation == 0 ) { - vectorFingerY = new THREE.Vector3( 1, 0, 0 ); + vectorFingerY = new THREE__namespace.Vector3( 1, 0, 0 ); fingerQY.setFromAxisAngle( vectorFingerY, -rotX ); } else if ( scope.screenOrientation == 180 ) { - vectorFingerY = new THREE.Vector3( 1, 0, 0 ); + vectorFingerY = new THREE__namespace.Vector3( 1, 0, 0 ); fingerQY.setFromAxisAngle( vectorFingerY, rotX ); } else if ( scope.screenOrientation == 90 ) { - vectorFingerY = new THREE.Vector3( 0, 1, 0 ); + vectorFingerY = new THREE__namespace.Vector3( 0, 1, 0 ); fingerQY.setFromAxisAngle( vectorFingerY, rotX ); } else if ( scope.screenOrientation == - 90) { - vectorFingerY = new THREE.Vector3( 0, 1, 0 ); + vectorFingerY = new THREE__namespace.Vector3( 0, 1, 0 ); fingerQY.setFromAxisAngle( vectorFingerY, -rotX ); } @@ -7207,10 +7145,10 @@ if ( scope.enabled === false ) return; - var alpha = scope.deviceOrientation.alpha ? THREE.Math.degToRad( scope.deviceOrientation.alpha ) + scope.alphaOffsetAngle : 0; // Z - var beta = scope.deviceOrientation.beta ? THREE.Math.degToRad( scope.deviceOrientation.beta ) : 0; // X' - var gamma = scope.deviceOrientation.gamma ? THREE.Math.degToRad( scope.deviceOrientation.gamma ) : 0; // Y'' - var orient = scope.screenOrientation ? THREE.Math.degToRad( scope.screenOrientation ) : 0; // O + var alpha = scope.deviceOrientation.alpha ? THREE__namespace.Math.degToRad( scope.deviceOrientation.alpha ) + scope.alphaOffsetAngle : 0; // Z + var beta = scope.deviceOrientation.beta ? THREE__namespace.Math.degToRad( scope.deviceOrientation.beta ) : 0; // X' + var gamma = scope.deviceOrientation.gamma ? THREE__namespace.Math.degToRad( scope.deviceOrientation.gamma ) : 0; // Y'' + var orient = scope.screenOrientation ? THREE__namespace.Math.degToRad( scope.screenOrientation ) : 0; // O setCameraQuaternion( scope.camera.quaternion, alpha, beta, gamma, orient ); scope.alpha = alpha; @@ -7235,7 +7173,7 @@ this.connect(); } - DeviceOrientationControls.prototype = Object.assign( Object.create( THREE.EventDispatcher.prototype), { + DeviceOrientationControls.prototype = Object.assign( Object.create( THREE__namespace.EventDispatcher.prototype), { constructor: DeviceOrientationControls @@ -7247,117 +7185,118 @@ * @external CardboardEffect * @param {THREE.WebGLRenderer} renderer */ - function CardboardEffect ( renderer ) { - - var _camera = new THREE.OrthographicCamera( - 1, 1, 1, - 1, 0, 1 ); - - var _scene = new THREE.Scene(); - - var _stereo = new THREE.StereoCamera(); - _stereo.aspect = 0.5; - - var _params = { minFilter: THREE.LinearFilter, magFilter: THREE.NearestFilter, format: THREE.RGBAFormat }; - - var _renderTarget = new THREE.WebGLRenderTarget( 512, 512, _params ); - _renderTarget.scissorTest = true; - _renderTarget.texture.generateMipmaps = false; - - /* - * Distortion Mesh ported from: - * https://github.com/borismus/webvr-boilerplate/blob/master/src/distortion/barrel-distortion-fragment.js - */ - - var distortion = new THREE.Vector2( 0.441, 0.156 ); - - var geometry = new THREE.PlaneBufferGeometry( 1, 1, 10, 20 ).removeAttribute( 'normal' ).toNonIndexed(); - - var positions = geometry.attributes.position.array; - var uvs = geometry.attributes.uv.array; - - // duplicate - geometry.attributes.position.count *= 2; - geometry.attributes.uv.count *= 2; - - var positions2 = new Float32Array( positions.length * 2 ); - positions2.set( positions ); - positions2.set( positions, positions.length ); - - var uvs2 = new Float32Array( uvs.length * 2 ); - uvs2.set( uvs ); - uvs2.set( uvs, uvs.length ); - - var vector = new THREE.Vector2(); - var length = positions.length / 3; - - for ( var i = 0, l = positions2.length / 3; i < l; i ++ ) { - - vector.x = positions2[ i * 3 + 0 ]; - vector.y = positions2[ i * 3 + 1 ]; - - var dot = vector.dot( vector ); - var scalar = 1.5 + ( distortion.x + distortion.y * dot ) * dot; - - var offset = i < length ? 0 : 1; - - positions2[ i * 3 + 0 ] = ( vector.x / scalar ) * 1.5 - 0.5 + offset; - positions2[ i * 3 + 1 ] = ( vector.y / scalar ) * 3.0; - - uvs2[ i * 2 ] = ( uvs2[ i * 2 ] + offset ) * 0.5; - + class CardboardEffect { + + constructor( renderer ) { + var _camera = new THREE__namespace.OrthographicCamera( - 1, 1, 1, - 1, 0, 1 ); + + var _scene = new THREE__namespace.Scene(); + + var _stereo = new THREE__namespace.StereoCamera(); + _stereo.aspect = 0.5; + + var _params = { minFilter: THREE__namespace.LinearFilter, magFilter: THREE__namespace.NearestFilter, format: THREE__namespace.RGBAFormat }; + + var _renderTarget = new THREE__namespace.WebGLRenderTarget( 512, 512, _params ); + _renderTarget.scissorTest = true; + _renderTarget.texture.generateMipmaps = false; + + /* + * Distortion Mesh ported from: + * https://github.com/borismus/webvr-boilerplate/blob/master/src/distortion/barrel-distortion-fragment.js + */ + + var distortion = new THREE__namespace.Vector2( 0.441, 0.156 ); + + var geometry = new THREE__namespace.PlaneBufferGeometry( 1, 1, 10, 20 ).removeAttribute( 'normal' ).toNonIndexed(); + + var positions = geometry.attributes.position.array; + var uvs = geometry.attributes.uv.array; + + // duplicate + geometry.attributes.position.count *= 2; + geometry.attributes.uv.count *= 2; + + var positions2 = new Float32Array( positions.length * 2 ); + positions2.set( positions ); + positions2.set( positions, positions.length ); + + var uvs2 = new Float32Array( uvs.length * 2 ); + uvs2.set( uvs ); + uvs2.set( uvs, uvs.length ); + + var vector = new THREE__namespace.Vector2(); + var length = positions.length / 3; + + for ( var i = 0, l = positions2.length / 3; i < l; i ++ ) { + + vector.x = positions2[ i * 3 + 0 ]; + vector.y = positions2[ i * 3 + 1 ]; + + var dot = vector.dot( vector ); + var scalar = 1.5 + ( distortion.x + distortion.y * dot ) * dot; + + var offset = i < length ? 0 : 1; + + positions2[ i * 3 + 0 ] = ( vector.x / scalar ) * 1.5 - 0.5 + offset; + positions2[ i * 3 + 1 ] = ( vector.y / scalar ) * 3.0; + + uvs2[ i * 2 ] = ( uvs2[ i * 2 ] + offset ) * 0.5; + + } + + geometry.attributes.position.array = positions2; + geometry.attributes.uv.array = uvs2; + + // + + var material = new THREE__namespace.MeshBasicMaterial( { map: _renderTarget.texture } ); + var mesh = new THREE__namespace.Mesh( geometry, material ); + _scene.add( mesh ); + + // + + this.setSize = function ( width, height ) { + + renderer.setSize( width, height ); + + var pixelRatio = renderer.getPixelRatio(); + + _renderTarget.setSize( width * pixelRatio, height * pixelRatio ); + + }; + + this.render = function ( scene, camera ) { + + scene.updateMatrixWorld(); + + if ( camera.parent === null ) camera.updateMatrixWorld(); + + _stereo.update( camera ); + + var width = _renderTarget.width / 2; + var height = _renderTarget.height; + + if ( renderer.autoClear ) renderer.clear(); + + _renderTarget.scissor.set( 0, 0, width, height ); + _renderTarget.viewport.set( 0, 0, width, height ); + renderer.setRenderTarget( _renderTarget ); + renderer.render( scene, _stereo.cameraL ); + + renderer.clearDepth(); + + _renderTarget.scissor.set( width, 0, width, height ); + _renderTarget.viewport.set( width, 0, width, height ); + renderer.setRenderTarget( _renderTarget ); + renderer.render( scene, _stereo.cameraR ); + + renderer.clearDepth(); + + renderer.setRenderTarget( null ); + renderer.render( _scene, _camera ); + }; } - - geometry.attributes.position.array = positions2; - geometry.attributes.uv.array = uvs2; - - // - - var material = new THREE.MeshBasicMaterial( { map: _renderTarget.texture } ); - var mesh = new THREE.Mesh( geometry, material ); - _scene.add( mesh ); - - // - - this.setSize = function ( width, height ) { - - renderer.setSize( width, height ); - - var pixelRatio = renderer.getPixelRatio(); - - _renderTarget.setSize( width * pixelRatio, height * pixelRatio ); - - }; - - this.render = function ( scene, camera ) { - - scene.updateMatrixWorld(); - - if ( camera.parent === null ) camera.updateMatrixWorld(); - - _stereo.update( camera ); - - var width = _renderTarget.width / 2; - var height = _renderTarget.height; - - if ( renderer.autoClear ) renderer.clear(); - - _renderTarget.scissor.set( 0, 0, width, height ); - _renderTarget.viewport.set( 0, 0, width, height ); - renderer.setRenderTarget( _renderTarget ); - renderer.render( scene, _stereo.cameraL ); - - renderer.clearDepth(); - - _renderTarget.scissor.set( width, 0, width, height ); - _renderTarget.viewport.set( width, 0, width, height ); - renderer.setRenderTarget( _renderTarget ); - renderer.render( scene, _stereo.cameraR ); - - renderer.clearDepth(); - - renderer.setRenderTarget( null ); - renderer.render( _scene, _camera ); - }; - } /** @@ -7366,50 +7305,51 @@ * @external StereoEffect * @param {THREE.WebGLRenderer} renderer */ - const StereoEffect = function ( renderer ) { - - var _stereo = new THREE.StereoCamera(); - _stereo.aspect = 0.5; - var size = new THREE.Vector2(); - - this.setEyeSeparation = function ( eyeSep ) { + class StereoEffect { + constructor ( renderer ) { + var _stereo = new THREE__namespace.StereoCamera(); + _stereo.aspect = 0.5; + var size = new THREE__namespace.Vector2(); - _stereo.eyeSep = eyeSep; + this.setEyeSeparation = function ( eyeSep ) { - }; + _stereo.eyeSep = eyeSep; - this.setSize = function ( width, height ) { + }; - renderer.setSize( width, height ); + this.setSize = function ( width, height ) { - }; + renderer.setSize( width, height ); - this.render = function ( scene, camera ) { + }; - scene.updateMatrixWorld(); + this.render = function ( scene, camera ) { - if ( camera.parent === null ) camera.updateMatrixWorld(); + scene.updateMatrixWorld(); - _stereo.update( camera ); + if ( camera.parent === null ) camera.updateMatrixWorld(); - renderer.getSize( size ); + _stereo.update( camera ); - if ( renderer.autoClear ) renderer.clear(); - renderer.setScissorTest( true ); + renderer.getSize( size ); - renderer.setScissor( 0, 0, size.width / 2, size.height ); - renderer.setViewport( 0, 0, size.width / 2, size.height ); - renderer.render( scene, _stereo.cameraL ); + if ( renderer.autoClear ) renderer.clear(); + renderer.setScissorTest( true ); - renderer.setScissor( size.width / 2, 0, size.width / 2, size.height ); - renderer.setViewport( size.width / 2, 0, size.width / 2, size.height ); - renderer.render( scene, _stereo.cameraR ); + renderer.setScissor( 0, 0, size.width / 2, size.height ); + renderer.setViewport( 0, 0, size.width / 2, size.height ); + renderer.render( scene, _stereo.cameraL ); - renderer.setScissorTest( false ); + renderer.setScissor( size.width / 2, 0, size.width / 2, size.height ); + renderer.setViewport( size.width / 2, 0, size.width / 2, size.height ); + renderer.render( scene, _stereo.cameraR ); - }; + renderer.setScissorTest( false ); - }; + }; + } + + } /** * @classdesc Viewer contains pre-defined scene, camera and renderer @@ -7437,377 +7377,374 @@ * @param {number} [options.autoRotateSpeed=2.0] - Auto rotate speed as in degree per second. Positive is counter-clockwise and negative is clockwise. * @param {number} [options.autoRotateActivationDuration=5000] - Duration before auto rotatation when no user interactivity in ms */ - function Viewer ( options ) { - - let container; - - options = options || {}; - options.controlBar = options.controlBar !== undefined ? options.controlBar : true; - options.controlButtons = options.controlButtons || [ 'fullscreen', 'setting', 'video' ]; - options.autoHideControlBar = options.autoHideControlBar !== undefined ? options.autoHideControlBar : false; - options.autoHideInfospot = options.autoHideInfospot !== undefined ? options.autoHideInfospot : true; - options.horizontalView = options.horizontalView !== undefined ? options.horizontalView : false; - options.clickTolerance = options.clickTolerance || 10; - options.cameraFov = options.cameraFov || 60; - options.reverseDragging = options.reverseDragging || false; - options.enableReticle = options.enableReticle || false; - options.dwellTime = options.dwellTime || 1500; - options.autoReticleSelect = options.autoReticleSelect !== undefined ? options.autoReticleSelect : true; - options.viewIndicator = options.viewIndicator !== undefined ? options.viewIndicator : false; - options.indicatorSize = options.indicatorSize || 30; - options.output = options.output ? options.output : 'none'; - options.autoRotate = options.autoRotate || false; - options.autoRotateSpeed = options.autoRotateSpeed || 2.0; - options.autoRotateActivationDuration = options.autoRotateActivationDuration || 5000; - - this.options = options; - - /* - * CSS Icon - * const styleLoader = new StyleLoader(); - * styleLoader.inject( 'icono' ); - */ - - // Container - if ( options.container ) { - - container = options.container; - container._width = container.clientWidth; - container._height = container.clientHeight; - - } else { - - container = document.createElement( 'div' ); - container.classList.add( 'panolens-container' ); - container.style.width = '100%'; - container.style.height = '100%'; - container._width = window.innerWidth; - container._height = window.innerHeight; - document.body.appendChild( container ); + class Viewer extends THREE__namespace.EventDispatcher { + constructor( options ) { + super(); + let container; + options = options || {}; + options.controlBar = options.controlBar !== undefined ? options.controlBar : true; + options.controlButtons = options.controlButtons || [ 'fullscreen', 'setting', 'video' ]; + options.autoHideControlBar = options.autoHideControlBar !== undefined ? options.autoHideControlBar : false; + options.autoHideInfospot = options.autoHideInfospot !== undefined ? options.autoHideInfospot : true; + options.horizontalView = options.horizontalView !== undefined ? options.horizontalView : false; + options.clickTolerance = options.clickTolerance || 10; + options.cameraFov = options.cameraFov || 60; + options.reverseDragging = options.reverseDragging || false; + options.enableReticle = options.enableReticle || false; + options.dwellTime = options.dwellTime || 1500; + options.autoReticleSelect = options.autoReticleSelect !== undefined ? options.autoReticleSelect : true; + options.viewIndicator = options.viewIndicator !== undefined ? options.viewIndicator : false; + options.indicatorSize = options.indicatorSize || 30; + options.output = options.output ? options.output : 'none'; + options.autoRotate = options.autoRotate || false; + options.autoRotateSpeed = options.autoRotateSpeed || 2.0; + options.autoRotateActivationDuration = options.autoRotateActivationDuration || 5000; + + this.options = options; + + /* + * CSS Icon + * const styleLoader = new StyleLoader(); + * styleLoader.inject( 'icono' ); + */ + + // Container + if ( options.container ) { + + container = options.container; + container._width = container.clientWidth; + container._height = container.clientHeight; + + } else { + + container = document.createElement( 'div' ); + container.classList.add( 'panolens-container' ); + container.style.width = '100%'; + container.style.height = '100%'; + container._width = window.innerWidth; + container._height = window.innerHeight; + document.body.appendChild( container ); + + } + + this.container = container; + + this.camera = options.camera || new THREE__namespace.PerspectiveCamera( this.options.cameraFov, this.container.clientWidth / this.container.clientHeight, 1, 10000 ); + this.scene = options.scene || new THREE__namespace.Scene(); + this.renderer = options.renderer || new THREE__namespace.WebGLRenderer( { alpha: true, antialias: false } ); + this.sceneReticle = new THREE__namespace.Scene(); + + this.viewIndicatorSize = this.options.indicatorSize; + + this.reticle = {}; + this.tempEnableReticle = this.options.enableReticle; + + this.mode = MODES.NORMAL; + + this.panorama = null; + this.widget = null; + + this.hoverObject = null; + this.infospot = null; + this.pressEntityObject = null; + this.pressObject = null; + + this.raycaster = new THREE__namespace.Raycaster(); + this.raycasterPoint = new THREE__namespace.Vector2(); + this.userMouse = new THREE__namespace.Vector2(); + this.updateCallbacks = []; + this.requestAnimationId = null; + + this.cameraFrustum = new THREE__namespace.Frustum(); + this.cameraViewProjectionMatrix = new THREE__namespace.Matrix4(); + + this.autoRotateRequestId = null; + + this.outputDivElement = null; + + this.touchSupported = 'ontouchstart' in window || window.DocumentTouch && document instanceof DocumentTouch; + + // Handler references + this.HANDLER_MOUSE_DOWN = this.onMouseDown.bind( this ); + this.HANDLER_MOUSE_UP = this.onMouseUp.bind( this ); + this.HANDLER_MOUSE_MOVE = this.onMouseMove.bind( this ); + this.HANDLER_WINDOW_RESIZE = this.onWindowResize.bind( this ); + this.HANDLER_KEY_DOWN = this.onKeyDown.bind( this ); + this.HANDLER_KEY_UP = this.onKeyUp.bind( this ); + this.HANDLER_TAP = this.onTap.bind( this, { + clientX: this.container.clientWidth / 2, + clientY: this.container.clientHeight / 2 + } ); + + // Flag for infospot output + this.OUTPUT_INFOSPOT = false; + + // Animations + this.tweenLeftAnimation = new Tween.Tween(); + this.tweenUpAnimation = new Tween.Tween(); + + // Renderer + this.renderer.setPixelRatio( window.devicePixelRatio ); + this.renderer.setSize( this.container.clientWidth, this.container.clientHeight ); + this.renderer.setClearColor( 0x000000, 0 ); + this.renderer.autoClear = false; + + // Append Renderer Element to container + this.renderer.domElement.classList.add( 'panolens-canvas' ); + this.renderer.domElement.style.display = 'block'; + this.container.style.backgroundColor = '#000'; + this.container.appendChild( this.renderer.domElement ); + + // Camera Controls + this.OrbitControls = new OrbitControls( this.camera, this.container ); + this.OrbitControls.id = 'orbit'; + this.OrbitControls.minDistance = 1; + this.OrbitControls.noPan = true; + this.OrbitControls.autoRotate = this.options.autoRotate; + this.OrbitControls.autoRotateSpeed = this.options.autoRotateSpeed; + + this.DeviceOrientationControls = new DeviceOrientationControls( this.camera, this.container ); + this.DeviceOrientationControls.id = 'device-orientation'; + this.DeviceOrientationControls.enabled = false; + this.camera.position.z = 1; + + // Register change event if passiveRenering + if ( this.options.passiveRendering ) { + + console.warn( 'passiveRendering is now deprecated' ); + + } + + // Controls + this.controls = [ this.OrbitControls, this.DeviceOrientationControls ]; + this.control = this.OrbitControls; + + // Cardboard effect + this.CardboardEffect = new CardboardEffect( this.renderer ); + this.CardboardEffect.setSize( this.container.clientWidth, this.container.clientHeight ); + + // Stereo effect + this.StereoEffect = new StereoEffect( this.renderer ); + this.StereoEffect.setSize( this.container.clientWidth, this.container.clientHeight ); + + this.effect = this.CardboardEffect; + + // Add default hidden reticle + this.addReticle(); + + // Lock horizontal view + if ( this.options.horizontalView ) { + this.OrbitControls.minPolarAngle = Math.PI / 2; + this.OrbitControls.maxPolarAngle = Math.PI / 2; + } + + // Add Control UI + if ( this.options.controlBar !== false ) { + this.addDefaultControlBar( this.options.controlButtons ); + } + + // Add View Indicator + if ( this.options.viewIndicator ) { + this.addViewIndicator(); + } + + // Reverse dragging direction + if ( this.options.reverseDragging ) { + this.reverseDraggingDirection(); + } + + // Register event if reticle is enabled, otherwise defaults to mouse + if ( this.options.enableReticle ) { + this.enableReticleControl(); + } else { + this.registerMouseAndTouchEvents(); + } + + // Output infospot position to an overlay container if specified + if ( this.options.output === 'overlay' ) { + this.addOutputElement(); + } + + // Register dom event listeners + this.registerEventListeners(); + + // Animate + this.animate.call( this ); } - - this.container = container; - - this.camera = options.camera || new THREE.PerspectiveCamera( this.options.cameraFov, this.container.clientWidth / this.container.clientHeight, 1, 10000 ); - this.scene = options.scene || new THREE.Scene(); - this.renderer = options.renderer || new THREE.WebGLRenderer( { alpha: true, antialias: false } ); - this.sceneReticle = new THREE.Scene(); - - this.viewIndicatorSize = this.options.indicatorSize; - - this.reticle = {}; - this.tempEnableReticle = this.options.enableReticle; - - this.mode = MODES.NORMAL; - - this.panorama = null; - this.widget = null; - - this.hoverObject = null; - this.infospot = null; - this.pressEntityObject = null; - this.pressObject = null; - - this.raycaster = new THREE.Raycaster(); - this.raycasterPoint = new THREE.Vector2(); - this.userMouse = new THREE.Vector2(); - this.updateCallbacks = []; - this.requestAnimationId = null; - - this.cameraFrustum = new THREE.Frustum(); - this.cameraViewProjectionMatrix = new THREE.Matrix4(); - - this.autoRotateRequestId = null; - - this.outputDivElement = null; - - this.touchSupported = 'ontouchstart' in window || window.DocumentTouch && document instanceof DocumentTouch; - - // Handler references - this.HANDLER_MOUSE_DOWN = this.onMouseDown.bind( this ); - this.HANDLER_MOUSE_UP = this.onMouseUp.bind( this ); - this.HANDLER_MOUSE_MOVE = this.onMouseMove.bind( this ); - this.HANDLER_WINDOW_RESIZE = this.onWindowResize.bind( this ); - this.HANDLER_KEY_DOWN = this.onKeyDown.bind( this ); - this.HANDLER_KEY_UP = this.onKeyUp.bind( this ); - this.HANDLER_TAP = this.onTap.bind( this, { - clientX: this.container.clientWidth / 2, - clientY: this.container.clientHeight / 2 - } ); - - // Flag for infospot output - this.OUTPUT_INFOSPOT = false; - - // Animations - this.tweenLeftAnimation = new Tween.Tween(); - this.tweenUpAnimation = new Tween.Tween(); - - // Renderer - this.renderer.setPixelRatio( window.devicePixelRatio ); - this.renderer.setSize( this.container.clientWidth, this.container.clientHeight ); - this.renderer.setClearColor( 0x000000, 0 ); - this.renderer.autoClear = false; - - // Append Renderer Element to container - this.renderer.domElement.classList.add( 'panolens-canvas' ); - this.renderer.domElement.style.display = 'block'; - this.container.style.backgroundColor = '#000'; - this.container.appendChild( this.renderer.domElement ); - - // Camera Controls - this.OrbitControls = new OrbitControls( this.camera, this.container ); - this.OrbitControls.id = 'orbit'; - this.OrbitControls.minDistance = 1; - this.OrbitControls.noPan = true; - this.OrbitControls.autoRotate = this.options.autoRotate; - this.OrbitControls.autoRotateSpeed = this.options.autoRotateSpeed; - - this.DeviceOrientationControls = new DeviceOrientationControls( this.camera, this.container ); - this.DeviceOrientationControls.id = 'device-orientation'; - this.DeviceOrientationControls.enabled = false; - this.camera.position.z = 1; - - // Register change event if passiveRenering - if ( this.options.passiveRendering ) { - - console.warn( 'passiveRendering is now deprecated' ); - - } - - // Controls - this.controls = [ this.OrbitControls, this.DeviceOrientationControls ]; - this.control = this.OrbitControls; - - // Cardboard effect - this.CardboardEffect = new CardboardEffect( this.renderer ); - this.CardboardEffect.setSize( this.container.clientWidth, this.container.clientHeight ); - - // Stereo effect - this.StereoEffect = new StereoEffect( this.renderer ); - this.StereoEffect.setSize( this.container.clientWidth, this.container.clientHeight ); - - this.effect = this.CardboardEffect; - - // Add default hidden reticle - this.addReticle(); - - // Lock horizontal view - if ( this.options.horizontalView ) { - this.OrbitControls.minPolarAngle = Math.PI / 2; - this.OrbitControls.maxPolarAngle = Math.PI / 2; - } - - // Add Control UI - if ( this.options.controlBar !== false ) { - this.addDefaultControlBar( this.options.controlButtons ); - } - - // Add View Indicator - if ( this.options.viewIndicator ) { - this.addViewIndicator(); - } - - // Reverse dragging direction - if ( this.options.reverseDragging ) { - this.reverseDraggingDirection(); - } - - // Register event if reticle is enabled, otherwise defaults to mouse - if ( this.options.enableReticle ) { - this.enableReticleControl(); - } else { - this.registerMouseAndTouchEvents(); - } - - // Output infospot position to an overlay container if specified - if ( this.options.output === 'overlay' ) { - this.addOutputElement(); - } - - // Register dom event listeners - this.registerEventListeners(); - - // Animate - this.animate.call( this ); - - } - Viewer.prototype = Object.assign( Object.create( THREE.EventDispatcher.prototype ), { - - constructor: Viewer, - - /** - * Add an object to the scene - * Automatically hookup with panolens-viewer-handler listener - * to communicate with viewer method - * @param {THREE.Object3D} object - The object to be added - * @memberOf Viewer - * @instance - */ - add: function ( object ) { + + /** + * Add an object to the scene + * Automatically hookup with panolens-viewer-handler listener + * to communicate with viewer method + * @param {THREE.Object3D} object - The object to be added + * @memberOf Viewer + * @instance + */ + add ( object ) { if ( arguments.length > 1 ) { - + for ( let i = 0; i < arguments.length; i ++ ) { - + this.add( arguments[ i ] ); - + } - + return this; - + } - + this.scene.add( object ); - + // All object added to scene has 'panolens-viewer-handler' event to handle viewer communication if ( object.addEventListener ) { - + object.addEventListener( 'panolens-viewer-handler', this.eventHandler.bind( this ) ); - + } - + // All object added to scene being passed with container if ( object instanceof Panorama && object.dispatchEvent ) { - + object.dispatchEvent( { type: 'panolens-container', container: this.container } ); - + } - + if ( object instanceof CameraPanorama ) { - + object.dispatchEvent( { type: 'panolens-scene', scene: this.scene } ); - + } - + // Hookup default panorama event listeners if ( object.type === 'panorama' ) { - + this.addPanoramaEventListener( object ); - + if ( !this.panorama ) { - + this.setPanorama( object ); - + } - + } - - }, - + + } + /** * Remove an object from the scene * @param {THREE.Object3D} object - Object to be removed * @memberOf Viewer * @instance */ - remove: function ( object ) { - + remove ( object ) { + if ( object.removeEventListener ) { - + object.removeEventListener( 'panolens-viewer-handler', this.eventHandler.bind( this ) ); - + } - + this.scene.remove( object ); - - }, - + + } + /** * Add default control bar * @param {array} array - The control buttons array * @memberOf Viewer * @instance */ - addDefaultControlBar: function ( array ) { - + addDefaultControlBar ( array ) { + if ( this.widget ) { - + console.warn( 'Default control bar exists' ); return; - + } - + const widget = new Widget( this.container ); widget.addEventListener( 'panolens-viewer-handler', this.eventHandler.bind( this ) ); widget.addControlBar(); array.forEach( buttonName => { - + widget.addControlButton( buttonName ); - + } ); - + this.widget = widget; - - }, - + + } + /** * Set a panorama to be the current one * @param {Panorama} pano - Panorama to be set * @memberOf Viewer * @instance */ - setPanorama: function ( pano ) { - + setPanorama ( pano ) { + const leavingPanorama = this.panorama; - + if ( pano.type === 'panorama' && leavingPanorama !== pano ) { - + // Clear exisiting infospot this.hideInfospot(); - + const afterEnterComplete = function () { - + if ( leavingPanorama ) { leavingPanorama.onLeave(); } pano.removeEventListener( 'enter-fade-start', afterEnterComplete ); - + }; - + pano.addEventListener( 'enter-fade-start', afterEnterComplete ); - + // Assign and enter panorama (this.panorama = pano).onEnter(); - + } - - }, - + + } + /** * Event handler to execute commands from child objects * @param {object} event - The dispatched event with method as function name and data as an argument * @memberOf Viewer * @instance */ - eventHandler: function ( event ) { - + eventHandler ( event ) { + if ( event.method && this[ event.method ] ) { - + this[ event.method ]( event.data ); - + } - - }, - + + } + /** * Dispatch event to all descendants * @param {object} event - Event to be passed along * @memberOf Viewer * @instance */ - dispatchEventToChildren: function ( event ) { - + dispatchEventToChildren ( event ) { + this.scene.traverse( function ( object ) { - + if ( object.dispatchEvent ) { - + object.dispatchEvent( event ); - + } - + }); - - }, - + + } + /** * Set widget content * @method activateWidgetItem @@ -7816,114 +7753,115 @@ * @memberOf Viewer * @instance */ - activateWidgetItem: function ( controlIndex, mode ) { + activateWidgetItem ( controlIndex, mode ) { + if (!this.widget) return; const mainMenu = this.widget.mainMenu; const ControlMenuItem = mainMenu.children[ 0 ]; const ModeMenuItem = mainMenu.children[ 1 ]; - + let item; - + if ( controlIndex !== undefined ) { - + switch ( controlIndex ) { - + case 0: - + item = ControlMenuItem.subMenu.children[ 1 ]; - + break; - + case 1: - + item = ControlMenuItem.subMenu.children[ 2 ]; - + break; - + default: - + item = ControlMenuItem.subMenu.children[ 1 ]; - + break; - + } - + ControlMenuItem.subMenu.setActiveItem( item ); ControlMenuItem.setSelectionTitle( item.textContent ); - + } - + if ( mode !== undefined ) { - + switch( mode ) { - + case MODES.CARDBOARD: - + item = ModeMenuItem.subMenu.children[ 2 ]; - + break; - + case MODES.STEREO: - + item = ModeMenuItem.subMenu.children[ 3 ]; - + break; - + default: - + item = ModeMenuItem.subMenu.children[ 1 ]; - + break; } - + ModeMenuItem.subMenu.setActiveItem( item ); ModeMenuItem.setSelectionTitle( item.textContent ); - + } - - }, - + + } + /** * Enable rendering effect * @param {MODES} mode - Modes for effects * @memberOf Viewer * @instance */ - enableEffect: function ( mode ) { - + enableEffect ( mode ) { + if ( this.mode === mode ) { return; } if ( mode === MODES.NORMAL ) { this.disableEffect(); return; } else { this.mode = mode; } - + const fov = this.camera.fov; - + switch( mode ) { - + case MODES.CARDBOARD: - + this.effect = this.CardboardEffect; this.enableReticleControl(); - + break; - + case MODES.STEREO: - + this.effect = this.StereoEffect; this.enableReticleControl(); - + break; - + default: - + this.effect = null; this.disableReticleControl(); - + break; - + } - + this.activateWidgetItem( undefined, this.mode ); - + /** * Dual eye effect event * @type {object} @@ -7931,13 +7869,13 @@ * @property {MODES} mode - Current display mode */ this.dispatchEventToChildren( { type: 'panolens-dual-eye-effect', mode: this.mode } ); - + // Force effect stereo camera to update by refreshing fov this.camera.fov = fov + 10e-3; this.effect.setSize( this.container.clientWidth, this.container.clientHeight ); this.render(); this.camera.fov = fov; - + /** * Dispatch mode change event * @type {object} @@ -7945,23 +7883,23 @@ * @property {MODES} mode - Current display mode */ this.dispatchEvent( { type: 'mode-change', mode: this.mode } ); - - }, - + + } + /** * Disable additional rendering effect * @memberOf Viewer * @instance */ - disableEffect: function () { - + disableEffect () { + if ( this.mode === MODES.NORMAL ) { return; } - + this.mode = MODES.NORMAL; this.disableReticleControl(); - + this.activateWidgetItem( undefined, this.mode ); - + /** * Dual eye effect event * @type {object} @@ -7969,10 +7907,10 @@ * @property {MODES} mode - Current display mode */ this.dispatchEventToChildren( { type: 'panolens-dual-eye-effect', mode: this.mode } ); - + this.renderer.setSize( this.container.clientWidth, this.container.clientHeight ); this.render(); - + /** * Dispatch mode change event * @type {object} @@ -7980,76 +7918,75 @@ * @property {MODES} mode - Current display mode */ this.dispatchEvent( { type: 'mode-change', mode: this.mode } ); - }, - + } + /** * Enable reticle control * @memberOf Viewer * @instance */ - enableReticleControl: function () { - + enableReticleControl () { + if ( this.reticle.visible ) { return; } - + this.tempEnableReticle = true; - + // Register reticle event and unregister mouse event this.unregisterMouseAndTouchEvents(); this.reticle.show(); this.registerReticleEvent(); this.updateReticleEvent(); - - }, - + + } + /** * Disable reticle control * @memberOf Viewer * @instance */ - disableReticleControl: function () { - + disableReticleControl () { + this.tempEnableReticle = false; - + // Register mouse event and unregister reticle event if ( !this.options.enableReticle ) { - + this.reticle.hide(); this.unregisterReticleEvent(); this.registerMouseAndTouchEvents(); - + } else { - + this.updateReticleEvent(); - + } - - }, - + + } + /** * Enable auto rotation * @memberOf Viewer * @instance */ - enableAutoRate: function () { - + enableAutoRate () { + this.options.autoRotate = true; this.OrbitControls.autoRotate = true; - - }, - + } + /** * Disable auto rotation * @memberOf Viewer * @instance */ - disableAutoRate: function () { - + disableAutoRate () { + clearTimeout( this.autoRotateRequestId ); this.options.autoRotate = false; this.OrbitControls.autoRotate = false; - - }, - + + } + /** * Toggle video play or stop * @param {boolean} pause @@ -8057,21 +7994,21 @@ * @instance * @fires Viewer#video-toggle */ - toggleVideoPlay: function ( pause ) { - + toggleVideoPlay ( pause ) { + if ( this.panorama instanceof VideoPanorama ) { - + /** * Toggle video event * @type {object} * @event Viewer#video-toggle */ this.panorama.dispatchEvent( { type: 'video-toggle', pause: pause } ); - + } - - }, - + + } + /** * Set currentTime in a video * @param {number} percentage - Percentage of a video. Range from 0.0 to 1.0 @@ -8079,10 +8016,10 @@ * @instance * @fires Viewer#video-time */ - setVideoCurrentTime: function ( percentage ) { - + setVideoCurrentTime ( percentage ) { + if ( this.panorama instanceof VideoPanorama ) { - + /** * Setting video time event * @type {object} @@ -8090,11 +8027,11 @@ * @property {number} percentage - Percentage of a video. Range from 0.0 to 1.0 */ this.panorama.dispatchEvent( { type: 'video-time', percentage: percentage } ); - + } - - }, - + + } + /** * This will be called when video updates if an widget is present * @param {number} percentage - Percentage of a video. Range from 0.0 to 1.0 @@ -8102,10 +8039,10 @@ * @instance * @fires Viewer#video-update */ - onVideoUpdate: function ( percentage ) { - + onVideoUpdate ( percentage ) { + const { widget } = this; - + /** * Video update event * @type {object} @@ -8113,137 +8050,136 @@ * @property {number} percentage - Percentage of a video. Range from 0.0 to 1.0 */ if( widget ) { widget.dispatchEvent( { type: 'video-update', percentage: percentage } ); } - - }, - + + } + /** * Add update callback to be called every animation frame * @param {function} callback * @memberOf Viewer * @instance */ - addUpdateCallback: function ( fn ) { - + addUpdateCallback ( fn ) { + if ( fn ) { - + this.updateCallbacks.push( fn ); - + } - - }, - + } + /** * Remove update callback * @param {function} fn - The function to be removed * @memberOf Viewer * @instance */ - removeUpdateCallback: function ( fn ) { - + removeUpdateCallback ( fn ) { + const index = this.updateCallbacks.indexOf( fn ); - + if ( fn && index >= 0 ) { - + this.updateCallbacks.splice( index, 1 ); - + } - - }, - + + } + /** * Show video widget * @memberOf Viewer * @instance */ - showVideoWidget: function () { - + showVideoWidget () { + const { widget } = this; - + /** * Show video widget event * @type {object} * @event Viewer#video-control-show */ if( widget ) { widget.dispatchEvent( { type: 'video-control-show' } ); } - - }, - + + } + /** * Hide video widget * @memberOf Viewer * @instance */ - hideVideoWidget: function () { - + hideVideoWidget () { + const { widget } = this; - + /** * Hide video widget * @type {object} * @event Viewer#video-control-hide */ if( widget ) { widget.dispatchEvent( { type: 'video-control-hide' } ); } - - }, - + + } + /** * Update video play button * @param {boolean} paused * @memberOf Viewer * @instance */ - updateVideoPlayButton: function ( paused ) { - + updateVideoPlayButton ( paused ) { + const { widget } = this; - + if ( widget && widget.videoElement && widget.videoElement.controlButton ) { - + widget.videoElement.controlButton.update( paused ); - + } - - }, - + + } + /** * Add default panorama event listeners * @param {Panorama} pano - The panorama to be added with event listener * @memberOf Viewer * @instance */ - addPanoramaEventListener: function ( pano ) { - + addPanoramaEventListener ( pano ) { + // Set camera control on every panorama pano.addEventListener( 'enter-fade-start', this.setCameraControl.bind( this ) ); - + // Show and hide widget event only when it's VideoPanorama if ( pano instanceof VideoPanorama ) { - + pano.addEventListener( 'enter-fade-start', this.showVideoWidget.bind( this ) ); pano.addEventListener( 'leave', function () { - + if ( !(this.panorama instanceof VideoPanorama) ) { - + this.hideVideoWidget.call( this ); - + } - + }.bind( this ) ); - + } - - }, - + + } + /** * Set camera control * @memberOf Viewer * @instance */ - setCameraControl: function () { - + setCameraControl () { + this.OrbitControls.target.copy( this.panorama.position ); - - }, - + + } + /** * Get current camera control * @return {object} - Current navigation control @@ -8251,239 +8187,234 @@ * @instance * @returns {THREE.OrbitControls|THREE.DeviceOrientationControls} */ - getControl: function () { - - return this.control; - - }, - + getControl () { + + return this.control; + + } + /** * Get scene * @memberOf Viewer * @instance * @return {THREE.Scene} - Current scene which the viewer is built on */ - getScene: function () { - + getScene () { + return this.scene; - - }, - + + } + /** * Get camera * @memberOf Viewer * @instance * @return {THREE.Camera} - The scene camera */ - getCamera: function () { - + getCamera () { + return this.camera; - - }, - + + } + /** * Get renderer * @memberOf Viewer * @instance * @return {THREE.WebGLRenderer} - The renderer using webgl */ - getRenderer: function () { - + getRenderer () { + return this.renderer; - - }, - + + } + /** * Get container * @memberOf Viewer * @instance * @return {HTMLElement} - The container holds rendererd canvas */ - getContainer: function () { - + getContainer () { + return this.container; - - }, - + + } + /** * Get control id * @memberOf Viewer * @instance * @return {string} - Control id. 'orbit' or 'device-orientation' */ - getControlId: function () { - + getControlId () { + return this.control.id; - - }, - + + } + /** * Get next navigation control id * @memberOf Viewer * @instance * @return {string} - Next control id */ - getNextControlId: function () { - + getNextControlId () { + return this.controls[ this.getNextControlIndex() ].id; - - }, - + + } + /** * Get next navigation control index * @memberOf Viewer * @instance * @return {number} - Next control index */ - getNextControlIndex: function () { - + getNextControlIndex () { + const controls = this.controls; const control = this.control; const nextIndex = controls.indexOf( control ) + 1; - + return ( nextIndex >= controls.length ) ? 0 : nextIndex; - - }, - + + } + /** * Set field of view of camera * @param {number} fov * @memberOf Viewer * @instance */ - setCameraFov: function ( fov ) { - + setCameraFov ( fov ) { + this.camera.fov = fov; this.camera.updateProjectionMatrix(); - - }, - + + } + /** * Enable control by index * @param {CONTROLS} index - Index of camera control * @memberOf Viewer * @instance */ - enableControl: function ( index ) { - + enableControl ( index ) { + index = ( index >= 0 && index < this.controls.length ) ? index : 0; - + this.control.enabled = false; - + this.control = this.controls[ index ]; - + this.control.enabled = true; - + switch ( index ) { - + case CONTROLS.ORBIT: - + this.camera.position.copy( this.panorama.position ); this.camera.position.z += 1; - + break; - + case CONTROLS.DEVICEORIENTATION: - + this.camera.position.copy( this.panorama.position ); - - break; - - default: - + break; } - + this.control.update(); - + this.activateWidgetItem( index, undefined ); - - }, - + + } + /** * Disable current control * @memberOf Viewer * @instance */ - disableControl: function () { - + disableControl () { + this.control.enabled = false; - - }, - + + } + /** * Toggle next control * @memberOf Viewer * @instance */ - toggleNextControl: function () { - + toggleNextControl () { + this.enableControl( this.getNextControlIndex() ); - - }, - + + } + /** * Screen Space Projection * @memberOf Viewer * @instance */ - getScreenVector: function ( worldVector ) { - + getScreenVector ( worldVector ) { + const vector = worldVector.clone(); const widthHalf = ( this.container.clientWidth ) / 2; const heightHalf = this.container.clientHeight / 2; - + vector.project( this.camera ); - + vector.x = ( vector.x * widthHalf ) + widthHalf; vector.y = - ( vector.y * heightHalf ) + heightHalf; vector.z = 0; - + return vector; - - }, - + + } + /** * Check Sprite in Viewport * @memberOf Viewer * @instance */ - checkSpriteInViewport: function ( sprite ) { - + checkSpriteInViewport ( sprite ) { + this.camera.matrixWorldInverse.getInverse( this.camera.matrixWorld ); this.cameraViewProjectionMatrix.multiplyMatrices( this.camera.projectionMatrix, this.camera.matrixWorldInverse ); this.cameraFrustum.setFromMatrix( this.cameraViewProjectionMatrix ); - + return sprite.visible && this.cameraFrustum.intersectsSprite( sprite ); - - }, - + + } + /** * Reverse dragging direction * @memberOf Viewer * @instance */ - reverseDraggingDirection: function () { + reverseDraggingDirection () { this.OrbitControls.rotateSpeed *= -1; this.OrbitControls.momentumScalingFactor *= -1; - - }, - + + } + /** * Add reticle * @memberOf Viewer * @instance */ - addReticle: function () { - + addReticle () { + this.reticle = new Reticle( 0xffffff, true, this.options.dwellTime ); this.reticle.hide(); this.camera.add( this.reticle ); this.sceneReticle.add( this.camera ); - - }, - + } + /** * Tween control looking center * @param {THREE.Vector3} vector - Vector to be looked at the center @@ -8492,56 +8423,56 @@ * @memberOf Viewer * @instance */ - tweenControlCenter: function ( vector, duration, easing ) { - + tweenControlCenter ( vector, duration, easing ) { + if ( this.control !== this.OrbitControls ) { - + return; - + } - + // Pass in arguments as array if ( vector instanceof Array ) { - + duration = vector[ 1 ]; easing = vector[ 2 ]; vector = vector[ 0 ]; - + } - + duration = duration !== undefined ? duration : 1000; easing = easing || Tween.Easing.Exponential.Out; - + let scope, ha, va, chv, cvv, hv, vv, vptc, ov, nv; - + scope = this; - - chv = this.camera.getWorldDirection( new THREE.Vector3() ); + + chv = this.camera.getWorldDirection( new THREE__namespace.Vector3() ); cvv = chv.clone(); - - vptc = this.panorama.getWorldPosition( new THREE.Vector3() ).sub( this.camera.getWorldPosition( new THREE.Vector3() ) ); - + + vptc = this.panorama.getWorldPosition( new THREE__namespace.Vector3() ).sub( this.camera.getWorldPosition( new THREE__namespace.Vector3() ) ); + hv = vector.clone(); // Scale effect hv.x *= -1; hv.add( vptc ).normalize(); vv = hv.clone(); - + chv.y = 0; hv.y = 0; - + ha = Math.atan2( hv.z, hv.x ) - Math.atan2( chv.z, chv.x ); ha = ha > Math.PI ? ha - 2 * Math.PI : ha; ha = ha < -Math.PI ? ha + 2 * Math.PI : ha; va = Math.abs( cvv.angleTo( chv ) + ( cvv.y * vv.y <= 0 ? vv.angleTo( hv ) : -vv.angleTo( hv ) ) ); va *= vv.y < cvv.y ? 1 : -1; - + ov = { left: 0, up: 0 }; nv = { left: 0, up: 0 }; - + this.tweenLeftAnimation.stop(); this.tweenUpAnimation.stop(); - + this.tweenLeftAnimation = new Tween.Tween( ov ) .to( { left: ha }, duration ) .easing( easing ) @@ -8550,7 +8481,7 @@ nv.left = ov.left; }) .start(); - + this.tweenUpAnimation = new Tween.Tween( ov ) .to( { up: va }, duration ) .easing( easing ) @@ -8559,9 +8490,9 @@ nv.up = ov.up; }) .start(); - - }, - + + } + /** * Tween control looking center by object * @param {THREE.Object3D} object - Object to be looked at the center @@ -8570,33 +8501,33 @@ * @memberOf Viewer * @instance */ - tweenControlCenterByObject: function ( object, duration, easing ) { - + tweenControlCenterByObject ( object, duration, easing ) { + let isUnderScalePlaceHolder = false; - + object.traverseAncestors( function ( ancestor ) { - + if ( ancestor.scalePlaceHolder ) { - + isUnderScalePlaceHolder = true; - + } } ); - + if ( isUnderScalePlaceHolder ) { - - const invertXVector = new THREE.Vector3( -1, 1, 1 ); - - this.tweenControlCenter( object.getWorldPosition( new THREE.Vector3() ).multiply( invertXVector ), duration, easing ); - + + const invertXVector = new THREE__namespace.Vector3( -1, 1, 1 ); + + this.tweenControlCenter( object.getWorldPosition( new THREE__namespace.Vector3() ).multiply( invertXVector ), duration, easing ); + } else { - - this.tweenControlCenter( object.getWorldPosition( new THREE.Vector3() ), duration, easing ); - + + this.tweenControlCenter( object.getWorldPosition( new THREE__namespace.Vector3() ), duration, easing ); + } - - }, - + + } + /** * This is called when window size is changed * @fires Viewer#window-resize @@ -8605,51 +8536,51 @@ * @memberOf Viewer * @instance */ - onWindowResize: function ( windowWidth, windowHeight ) { - + onWindowResize ( windowWidth, windowHeight ) { + let width, height; - + const expand = this.container.classList.contains( 'panolens-container' ) || this.container.isFullscreen; - + if ( windowWidth !== undefined && windowHeight !== undefined ) { - + width = windowWidth; height = windowHeight; this.container._width = windowWidth; this.container._height = windowHeight; - + } else { - + const isAndroid = /(android)/i.test(window.navigator.userAgent); - + const adjustWidth = isAndroid ? Math.min(document.documentElement.clientWidth, window.innerWidth || 0) : Math.max(document.documentElement.clientWidth, window.innerWidth || 0); - + const adjustHeight = isAndroid ? Math.min(document.documentElement.clientHeight, window.innerHeight || 0) : Math.max(document.documentElement.clientHeight, window.innerHeight || 0); - + width = expand ? adjustWidth : this.container.clientWidth; height = expand ? adjustHeight : this.container.clientHeight; - + this.container._width = width; this.container._height = height; - + } - + this.camera.aspect = width / height; this.camera.updateProjectionMatrix(); - + this.renderer.setSize( width, height ); - + // Update reticle if ( this.options.enableReticle || this.tempEnableReticle ) { - + this.updateReticleEvent(); - + } - + /** * Window resizing event * @type {object} @@ -8659,24 +8590,24 @@ */ this.dispatchEvent( { type: 'window-resize', width: width, height: height }); this.scene.traverse( function ( object ) { - + if ( object.dispatchEvent ) { - + object.dispatchEvent( { type: 'window-resize', width: width, height: height }); - + } - + } ); - - }, - + + } + /** * Add output element * @memberOf Viewer * @instance */ - addOutputElement: function () { - + addOutputElement () { + const element = document.createElement( 'div' ); element.style.position = 'absolute'; element.style.right = '10px'; @@ -8684,37 +8615,37 @@ element.style.color = '#fff'; this.container.appendChild( element ); this.outputDivElement = element; - - }, - + + } + /** * Output position in developer console by holding down Ctrl button * @memberOf Viewer * @instance */ - outputPosition: function () { - + outputPosition () { + const intersects = this.raycaster.intersectObject( this.panorama, true ); - + if ( intersects.length > 0 ) { - + const point = intersects[ 0 ].point.clone(); - const converter = new THREE.Vector3( -1, 1, 1 ); - const world = this.panorama.getWorldPosition( new THREE.Vector3() ); + const converter = new THREE__namespace.Vector3( -1, 1, 1 ); + const world = this.panorama.getWorldPosition( new THREE__namespace.Vector3() ); point.sub( world ).multiply( converter ); - + const position = { x: point.x.toFixed(2), y: point.y.toFixed(2), z: point.z.toFixed(2), }; - + const message = `${position.x}, ${position.y}, ${position.z}`; - + if ( point.length() === 0 ) { return; } - + switch ( this.options.output ) { - + case 'event': /** * Dispatch raycast position as event @@ -8723,121 +8654,116 @@ */ this.dispatchEvent( { type: 'position-output', position: position } ); break; - + case 'console': console.info( message ); break; - + case 'overlay': this.outputDivElement.textContent = message; break; - - default: - break; - + } - + } - - }, - + + } + /** * On mouse down * @param {MouseEvent} event * @memberOf Viewer * @instance */ - onMouseDown: function ( event ) { - + onMouseDown ( event ) { + event.preventDefault(); - + this.userMouse.x = ( event.clientX >= 0 ) ? event.clientX : event.touches[0].clientX; this.userMouse.y = ( event.clientY >= 0 ) ? event.clientY : event.touches[0].clientY; this.userMouse.type = 'mousedown'; this.onTap( event ); - - }, - + } + /** * On mouse move * @param {MouseEvent} event * @memberOf Viewer * @instance */ - onMouseMove: function ( event ) { - + onMouseMove ( event ) { + event.preventDefault(); this.userMouse.type = 'mousemove'; this.onTap( event ); - - }, - + + } + /** * On mouse up * @param {MouseEvent} event * @memberOf Viewer * @instance */ - onMouseUp: function ( event ) { - + onMouseUp ( event ) { + let onTarget = false; - + this.userMouse.type = 'mouseup'; - + const type = ( this.userMouse.x >= event.clientX - this.options.clickTolerance - && this.userMouse.x <= event.clientX + this.options.clickTolerance - && this.userMouse.y >= event.clientY - this.options.clickTolerance - && this.userMouse.y <= event.clientY + this.options.clickTolerance ) - || ( event.changedTouches - && this.userMouse.x >= event.changedTouches[0].clientX - this.options.clickTolerance - && this.userMouse.x <= event.changedTouches[0].clientX + this.options.clickTolerance - && this.userMouse.y >= event.changedTouches[0].clientY - this.options.clickTolerance - && this.userMouse.y <= event.changedTouches[0].clientY + this.options.clickTolerance ) + && this.userMouse.x <= event.clientX + this.options.clickTolerance + && this.userMouse.y >= event.clientY - this.options.clickTolerance + && this.userMouse.y <= event.clientY + this.options.clickTolerance ) + || ( event.changedTouches + && this.userMouse.x >= event.changedTouches[0].clientX - this.options.clickTolerance + && this.userMouse.x <= event.changedTouches[0].clientX + this.options.clickTolerance + && this.userMouse.y >= event.changedTouches[0].clientY - this.options.clickTolerance + && this.userMouse.y <= event.changedTouches[0].clientY + this.options.clickTolerance ) ? 'click' : undefined; - + // Event should happen on canvas if ( event && event.target && !event.target.classList.contains( 'panolens-canvas' ) ) { return; } - + event.preventDefault(); - + if ( event.changedTouches && event.changedTouches.length === 1 ) { - + onTarget = this.onTap( { clientX: event.changedTouches[0].clientX, clientY: event.changedTouches[0].clientY }, type ); - + } else { - + onTarget = this.onTap( event, type ); - + } - + this.userMouse.type = 'none'; - + if ( onTarget ) { - + return; - + } - + if ( type === 'click' ) { - + const { options: { autoHideInfospot, autoHideControlBar }, panorama, toggleControlBar } = this; - + if ( autoHideInfospot && panorama ) { - + panorama.toggleInfospotVisibility(); - + } - + if ( autoHideControlBar ) { - + toggleControlBar(); - + } - + } - - }, - + } + /** * On tap eveny frame * @param {MouseEvent} event @@ -8845,228 +8771,228 @@ * @memberOf Viewer * @instance */ - onTap: function ( event, type ) { - + onTap ( event, type ) { + const { left, top } = this.container.getBoundingClientRect(); const { clientWidth, clientHeight } = this.container; - + this.raycasterPoint.x = ( ( event.clientX - left ) / clientWidth ) * 2 - 1; this.raycasterPoint.y = - ( ( event.clientY - top ) / clientHeight ) * 2 + 1; - + this.raycaster.setFromCamera( this.raycasterPoint, this.camera ); - + // Return if no panorama if ( !this.panorama ) { - + return; - + } - + // output infospot information if ( event.type !== 'mousedown' && this.touchSupported || this.OUTPUT_INFOSPOT ) { - + this.outputPosition(); - + } - - + + const intersects = this.raycaster.intersectObjects( this.panorama.children, true ); const intersect_entity = this.getConvertedIntersect( intersects ); const intersect = ( intersects.length > 0 ) ? intersects[0].object : undefined; - + if ( this.userMouse.type === 'mouseup' ) { - + if ( intersect_entity && this.pressEntityObject === intersect_entity && this.pressEntityObject.dispatchEvent ) { - + this.pressEntityObject.dispatchEvent( { type: 'pressstop-entity', mouseEvent: event } ); - + } - + this.pressEntityObject = undefined; - + } - + if ( this.userMouse.type === 'mouseup' ) { - + if ( intersect && this.pressObject === intersect && this.pressObject.dispatchEvent ) { - + this.pressObject.dispatchEvent( { type: 'pressstop', mouseEvent: event } ); - + } - + this.pressObject = undefined; - + } - + if ( type === 'click' ) { - + this.panorama.dispatchEvent( { type: 'click', intersects: intersects, mouseEvent: event } ); - + if ( intersect_entity && intersect_entity.dispatchEvent ) { - + intersect_entity.dispatchEvent( { type: 'click-entity', mouseEvent: event } ); - + } - + if ( intersect && intersect.dispatchEvent ) { - + intersect.dispatchEvent( { type: 'click', mouseEvent: event } ); - + } - + } else { - + this.panorama.dispatchEvent( { type: 'hover', intersects: intersects, mouseEvent: event } ); - + if ( ( this.hoverObject && intersects.length > 0 && this.hoverObject !== intersect_entity ) - || ( this.hoverObject && intersects.length === 0 ) ){ - + || ( this.hoverObject && intersects.length === 0 ) ){ + if ( this.hoverObject.dispatchEvent ) { - + this.hoverObject.dispatchEvent( { type: 'hoverleave', mouseEvent: event } ); - + this.reticle.end(); - + } - + this.hoverObject = undefined; - + } - + if ( intersect_entity && intersects.length > 0 ) { - + if ( this.hoverObject !== intersect_entity ) { - + this.hoverObject = intersect_entity; - + if ( this.hoverObject.dispatchEvent ) { - + this.hoverObject.dispatchEvent( { type: 'hoverenter', mouseEvent: event } ); - + // Start reticle timer if ( this.options.autoReticleSelect && this.options.enableReticle || this.tempEnableReticle ) { this.reticle.start( this.onTap.bind( this, event, 'click' ) ); } - + } - + } - + if ( this.userMouse.type === 'mousedown' && this.pressEntityObject != intersect_entity ) { - + this.pressEntityObject = intersect_entity; - + if ( this.pressEntityObject.dispatchEvent ) { - + this.pressEntityObject.dispatchEvent( { type: 'pressstart-entity', mouseEvent: event } ); - + } - + } - + if ( this.userMouse.type === 'mousedown' && this.pressObject != intersect ) { - + this.pressObject = intersect; - + if ( this.pressObject.dispatchEvent ) { - + this.pressObject.dispatchEvent( { type: 'pressstart', mouseEvent: event } ); - + } - + } - + if ( this.userMouse.type === 'mousemove' || this.options.enableReticle ) { - + if ( intersect && intersect.dispatchEvent ) { - + intersect.dispatchEvent( { type: 'hover', mouseEvent: event } ); - + } - + if ( this.pressEntityObject && this.pressEntityObject.dispatchEvent ) { - + this.pressEntityObject.dispatchEvent( { type: 'pressmove-entity', mouseEvent: event } ); - + } - + if ( this.pressObject && this.pressObject.dispatchEvent ) { - + this.pressObject.dispatchEvent( { type: 'pressmove', mouseEvent: event } ); - + } - + } - + } - + if ( !intersect_entity && this.pressEntityObject && this.pressEntityObject.dispatchEvent ) { - + this.pressEntityObject.dispatchEvent( { type: 'pressstop-entity', mouseEvent: event } ); - + this.pressEntityObject = undefined; - + } - + if ( !intersect && this.pressObject && this.pressObject.dispatchEvent ) { - + this.pressObject.dispatchEvent( { type: 'pressstop', mouseEvent: event } ); - + this.pressObject = undefined; - + } - + } - + // Infospot handler if ( intersect && intersect instanceof Infospot ) { - + this.infospot = intersect; - + if ( type === 'click' ) { - + return true; - + } - - + + } else if ( this.infospot ) { - + this.hideInfospot(); - + } - + // Auto rotate if ( this.options.autoRotate && this.userMouse.type !== 'mousemove' ) { - + // Auto-rotate idle timer clearTimeout( this.autoRotateRequestId ); - + if ( this.control === this.OrbitControls ) { - + this.OrbitControls.autoRotate = false; this.autoRotateRequestId = window.setTimeout( this.enableAutoRate.bind( this ), this.options.autoRotateActivationDuration ); - + } - + } - - }, - + + } + /** * Get converted intersect * @param {array} intersects * @memberOf Viewer * @instance */ - getConvertedIntersect: function ( intersects ) { - + getConvertedIntersect ( intersects ) { + let intersect; - + for ( let i = 0; i < intersects.length; i++ ) { - + if ( intersects[i].distance >= 0 && intersects[i].object && !intersects[i].object.passThrough ) { - + if ( intersects[i].object.entity && intersects[i].object.entity.passThrough ) { continue; } else if ( intersects[i].object.entity && !intersects[i].object.entity.passThrough ) { @@ -9076,357 +9002,347 @@ intersect = intersects[i].object; break; } - + } - + } - + return intersect; - - }, - + + } + /** * Hide infospot * @memberOf Viewer * @instance */ - hideInfospot: function () { - + hideInfospot () { + if ( this.infospot ) { - + this.infospot.onHoverEnd(); - + this.infospot = undefined; - + } - - }, - + + } + /** * Toggle control bar * @memberOf Viewer * @instance * @fires Viewer#control-bar-toggle */ - toggleControlBar: function () { - + toggleControlBar () { + const { widget } = this; - + /** * Toggle control bar event * @type {object} * @event Viewer#control-bar-toggle */ if ( widget ) { - + widget.dispatchEvent( { type: 'control-bar-toggle' } ); - + } - - }, - + + } + /** * On key down * @param {KeyboardEvent} event * @memberOf Viewer * @instance */ - onKeyDown: function ( event ) { - + onKeyDown ( event ) { + if ( this.options.output && this.options.output !== 'none' && event.key === 'Control' ) { - + this.OUTPUT_INFOSPOT = true; - + } - - }, - + + } + /** * On key up * @param {KeyboardEvent} event * @memberOf Viewer * @instance */ - onKeyUp: function () { - + onKeyUp () { + this.OUTPUT_INFOSPOT = false; - - }, - + + } + /** * Update control and callbacks * @memberOf Viewer * @instance */ - update: function () { - + update () { + Tween.update(); - + this.updateCallbacks.forEach( function( callback ){ callback(); } ); - + this.control.update(); - + this.scene.traverse( function( child ){ if ( child instanceof Infospot - && child.element - && ( this.hoverObject === child - || child.element.style.display !== 'none' - || (child.element.left && child.element.left.style.display !== 'none') - || (child.element.right && child.element.right.style.display !== 'none') ) ) { + && child.element + && ( this.hoverObject === child + || child.element.style.display !== 'none' + || (child.element.left && child.element.left.style.display !== 'none') + || (child.element.right && child.element.right.style.display !== 'none') ) ) { if ( this.checkSpriteInViewport( child ) ) { - const { x, y } = this.getScreenVector( child.getWorldPosition( new THREE.Vector3() ) ); + const { x, y } = this.getScreenVector( child.getWorldPosition( new THREE__namespace.Vector3() ) ); child.translateElement( x, y ); } else { child.onDismiss(); } - + } }.bind( this ) ); - - }, - + + } + /** * Rendering function to be called on every animation frame * Render reticle last * @memberOf Viewer * @instance */ - render: function () { - + render () { + if ( this.mode === MODES.CARDBOARD || this.mode === MODES.STEREO ) { - + this.renderer.clear(); this.effect.render( this.scene, this.camera ); this.effect.render( this.sceneReticle, this.camera ); - - + + } else { - + this.renderer.clear(); this.renderer.render( this.scene, this.camera ); this.renderer.clearDepth(); this.renderer.render( this.sceneReticle, this.camera ); - + } - - }, - + + } + /** * Animate * @memberOf Viewer * @instance */ - animate: function () { - + animate () { + this.requestAnimationId = window.requestAnimationFrame( this.animate.bind( this ) ); - + this.onChange(); - - }, - + + } + /** * On change * @memberOf Viewer * @instance */ - onChange: function () { - + onChange () { + this.update(); this.render(); - - }, - + + } + /** * Register mouse and touch event on container * @memberOf Viewer * @instance */ - registerMouseAndTouchEvents: function () { - + registerMouseAndTouchEvents () { + const options = { passive: false }; - + this.container.addEventListener( 'mousedown' , this.HANDLER_MOUSE_DOWN, options ); this.container.addEventListener( 'mousemove' , this.HANDLER_MOUSE_MOVE, options ); this.container.addEventListener( 'mouseup' , this.HANDLER_MOUSE_UP , options ); this.container.addEventListener( 'touchstart', this.HANDLER_MOUSE_DOWN, options ); this.container.addEventListener( 'touchend' , this.HANDLER_MOUSE_UP , options ); - - }, - + + } + /** * Unregister mouse and touch event on container * @memberOf Viewer * @instance */ - unregisterMouseAndTouchEvents: function () { - + unregisterMouseAndTouchEvents () { + this.container.removeEventListener( 'mousedown' , this.HANDLER_MOUSE_DOWN, false ); this.container.removeEventListener( 'mousemove' , this.HANDLER_MOUSE_MOVE, false ); this.container.removeEventListener( 'mouseup' , this.HANDLER_MOUSE_UP , false ); this.container.removeEventListener( 'touchstart', this.HANDLER_MOUSE_DOWN, false ); this.container.removeEventListener( 'touchend' , this.HANDLER_MOUSE_UP , false ); - - }, - + + } + /** * Register reticle event * @memberOf Viewer * @instance */ - registerReticleEvent: function () { - + registerReticleEvent () { + this.addUpdateCallback( this.HANDLER_TAP ); - - }, - + + } + /** * Unregister reticle event * @memberOf Viewer * @instance */ - unregisterReticleEvent: function () { - + unregisterReticleEvent () { + this.removeUpdateCallback( this.HANDLER_TAP ); - - }, - + + } + /** * Update reticle event * @memberOf Viewer * @instance */ - updateReticleEvent: function () { - + updateReticleEvent () { + const clientX = this.container.clientWidth / 2 + this.container.offsetLeft; const clientY = this.container.clientHeight / 2; - + this.removeUpdateCallback( this.HANDLER_TAP ); this.HANDLER_TAP = this.onTap.bind( this, { clientX, clientY } ); this.addUpdateCallback( this.HANDLER_TAP ); - - }, - + } + /** * Register container and window listeners * @memberOf Viewer * @instance */ - registerEventListeners: function () { - + registerEventListeners () { + // Resize Event window.addEventListener( 'resize' , this.HANDLER_WINDOW_RESIZE, true ); - + // Keyboard Event window.addEventListener( 'keydown', this.HANDLER_KEY_DOWN, true ); window.addEventListener( 'keyup' , this.HANDLER_KEY_UP , true ); - - }, - + + } /** * Unregister container and window listeners * @memberOf Viewer * @instance */ - unregisterEventListeners: function () { - + unregisterEventListeners () { + // Resize Event window.removeEventListener( 'resize' , this.HANDLER_WINDOW_RESIZE, true ); - + // Keyboard Event window.removeEventListener( 'keydown', this.HANDLER_KEY_DOWN, true ); window.removeEventListener( 'keyup' , this.HANDLER_KEY_UP , true ); - - }, - + + } + /** * Dispose all scene objects and clear cache * @memberOf Viewer * @instance */ - dispose: function () { - + dispose () { + this.tweenLeftAnimation.stop(); this.tweenUpAnimation.stop(); - + // Unregister dom event listeners this.unregisterEventListeners(); - + // recursive disposal on 3d objects function recursiveDispose ( object ) { - + for ( let i = object.children.length - 1; i >= 0; i-- ) { - + recursiveDispose( object.children[i] ); object.remove( object.children[i] ); - + } - + if ( object instanceof Panorama || object instanceof Infospot ) { - + object.dispose(); object = null; - + } else if ( object.dispatchEvent ){ - + object.dispatchEvent( 'dispose' ); - + } - + } - + recursiveDispose( this.scene ); - + // dispose widget if ( this.widget ) { - + this.widget.dispose(); this.widget = null; - + } - + // clear cache - if ( THREE.Cache && THREE.Cache.enabled ) { - - THREE.Cache.clear(); - + if ( THREE__namespace.Cache && THREE__namespace.Cache.enabled ) { + + THREE__namespace.Cache.clear(); + } - - }, - + + } + /** * Destroy viewer by disposing and stopping requestAnimationFrame * @memberOf Viewer * @instance */ - destroy: function () { - + destroy () { this.dispose(); this.render(); window.cancelAnimationFrame( this.requestAnimationId ); - - }, - + } + /** * On panorama dispose * @memberOf Viewer * @instance */ - onPanoramaDispose: function ( panorama ) { - + onPanoramaDispose ( panorama ) { if ( panorama instanceof VideoPanorama ) { - this.hideVideoWidget(); - } - + if ( panorama === this.panorama ) { - this.panorama = null; - } - - }, - + } + /** * Load ajax call * @param {string} url - URL to be requested @@ -9434,30 +9350,28 @@ * @memberOf Viewer * @instance */ - loadAsyncRequest: function ( url, callback = () => {} ) { - + loadAsyncRequest( url, callback = () => {} ) { const request = new window.XMLHttpRequest(); request.onloadend = function ( event ) { callback( event ); }; request.open( 'GET', url, true ); request.send( null ); - - }, - + + } + /** * View indicator in upper left * @memberOf Viewer * @instance */ - addViewIndicator: function () { - + addViewIndicator () { + const scope = this; - + function loadViewIndicator ( asyncEvent ) { - if ( asyncEvent.loaded === 0 ) return; - + const viewIndicatorDiv = asyncEvent.target.responseXML.documentElement; viewIndicatorDiv.style.width = scope.viewIndicatorSize + 'px'; viewIndicatorDiv.style.height = scope.viewIndicatorSize + 'px'; @@ -9467,15 +9381,14 @@ viewIndicatorDiv.style.opacity = '0.5'; viewIndicatorDiv.style.cursor = 'pointer'; viewIndicatorDiv.id = 'panolens-view-indicator-container'; - + scope.container.appendChild( viewIndicatorDiv ); - + const indicator = viewIndicatorDiv.querySelector( '#indicator' ); const setIndicatorD = function () { - scope.radius = scope.viewIndicatorSize * 0.225; - scope.currentPanoAngle = scope.camera.rotation.y - THREE.Math.degToRad( 90 ); - scope.fovAngle = THREE.Math.degToRad( scope.camera.fov ) ; + scope.currentPanoAngle = scope.camera.rotation.y - THREE__namespace.Math.degToRad( 90 ); + scope.fovAngle = THREE__namespace.Math.degToRad( scope.camera.fov ) ; scope.leftAngle = -scope.currentPanoAngle - scope.fovAngle / 2; scope.rightAngle = -scope.currentPanoAngle + scope.fovAngle / 2; scope.leftX = scope.radius * Math.cos( scope.leftAngle ); @@ -9483,36 +9396,34 @@ scope.rightX = scope.radius * Math.cos( scope.rightAngle ); scope.rightY = scope.radius * Math.sin( scope.rightAngle ); scope.indicatorD = 'M ' + scope.leftX + ' ' + scope.leftY + ' A ' + scope.radius + ' ' + scope.radius + ' 0 0 1 ' + scope.rightX + ' ' + scope.rightY; - + if ( scope.leftX && scope.leftY && scope.rightX && scope.rightY && scope.radius ) { - indicator.setAttribute( 'd', scope.indicatorD ); - } - + }; - + scope.addUpdateCallback( setIndicatorD ); - + const indicatorOnMouseEnter = function () { - + this.style.opacity = '1'; - + }; - + const indicatorOnMouseLeave = function () { - + this.style.opacity = '0.5'; - + }; - + viewIndicatorDiv.addEventListener( 'mouseenter', indicatorOnMouseEnter ); viewIndicatorDiv.addEventListener( 'mouseleave', indicatorOnMouseLeave ); } - + this.loadAsyncRequest( DataImage.ViewIndicator, loadViewIndicator ); - - }, + + } /** * Append custom control item to existing control bar @@ -9520,38 +9431,30 @@ * @memberOf Viewer * @instance */ - appendControlItem: function ( option ) { - + appendControlItem ( option ) { const item = this.widget.createCustomItem( option ); - if ( option.group === 'video' ) { - this.widget.videoElement.appendChild( item ); - } else { - this.widget.barElement.appendChild( item ); - } - + return item; - }, - + } + /** * Clear all cached files * @memberOf Viewer * @instance */ - clearAllCache: function () { - - THREE.Cache.clear(); - + clearAllCache() { + THREE__namespace.Cache.clear(); } - } ); + } - if ( THREE.REVISION != THREE_REVISION ) { + if ( THREE__namespace.REVISION != THREE_REVISION ) { console.warn( `three.js version is not matched. Please consider use the target revision ${THREE_REVISION}` ); @@ -9566,6 +9469,7 @@ exports.BasicPanorama = BasicPanorama; exports.CONTROLS = CONTROLS; + exports.CONTROL_BUTTONS = CONTROL_BUTTONS; exports.CameraPanorama = CameraPanorama; exports.CubePanorama = CubePanorama; exports.CubeTextureLoader = CubeTextureLoader; @@ -9579,6 +9483,7 @@ exports.LittlePlanet = LittlePlanet; exports.MODES = MODES; exports.Media = Media; + exports.OUTPUTS = OUTPUTS; exports.Panorama = Panorama; exports.REVISION = REVISION; exports.Reticle = Reticle; diff --git a/build/panolens.min.js b/build/panolens.min.js index 078ef538..7cf53552 100644 --- a/build/panolens.min.js +++ b/build/panolens.min.js @@ -1,53 +1,33 @@ -(function(h,e){"object"===typeof exports&&"undefined"!==typeof module?e(exports,require("three")):"function"===typeof define&&define.amd?define(["exports","three"],e):(h=h||self,e(h.PANOLENS={},h.THREE))})(this,function(h,e){function S(a){this.constraints=Object.assign({video:{width:{ideal:1920},height:{ideal:1080},facingMode:{exact:"environment"}},audio:!1},a);this.element=this.scene=this.container=null;this.devices=[];this.stream=null;this.ratioScalar=1;this.videoDeviceIndex=0}function M(a,b,c){a= -void 0===a?16777215:a;b=void 0===b?!0:b;c=void 0===c?1500:c;this.dpr=window.devicePixelRatio;var d=this.createCanvas(),g=d.canvas;d=d.context;var k=new e.SpriteMaterial({color:a,map:this.createCanvasTexture(g)});e.Sprite.call(this,k);this.canvasWidth=g.width;this.canvasHeight=g.height;this.context=d;this.color=a instanceof e.Color?a:new e.Color(a);this.autoSelect=b;this.dwellTime=c;this.rippleDuration=500;this.position.z=-10;this.center.set(.5,.5);this.scale.set(.5,.5,1);this.callback=this.timerId= -this.startTimestamp=null;this.frustumCulled=!1;this.updateCanvasArcByProgress(0)}function z(a,b,c){a=void 0===a?300:a;b=b||u.Info;e.Sprite.call(this);this.type="infospot";this.animated=void 0!==c?c:!0;this.frustumCulled=this.isHovering=!1;this.cursorStyle=this.toPanorama=this.element=null;this.mode=t.NORMAL;this.scale.set(a,a,1);this.rotation.y=Math.PI;this.container=null;this.originalRaycast=this.raycast;this.HANDLER_FOCUS=null;this.material.side=e.DoubleSide;this.material.depthTest=!1;this.material.transparent= -!0;this.material.opacity=0;this.scaleUpAnimation=new r.Tween;this.scaleDownAnimation=new r.Tween;c=function(d){if(this.material){var b=d.image.width/d.image.height,c=new e.Vector3;d.image.width=d.image.naturalWidth||64;d.image.height=d.image.naturalHeight||64;this.scale.set(b*a,a,1);c.copy(this.scale);this.scaleUpAnimation=(new r.Tween(this.scale)).to({x:1.3*c.x,y:1.3*c.y},500).easing(r.Easing.Elastic.Out);this.scaleDownAnimation=(new r.Tween(this.scale)).to({x:c.x,y:c.y},500).easing(r.Easing.Elastic.Out); -this.material.map=d;this.material.needsUpdate=!0}}.bind(this);this.showAnimation=(new r.Tween(this.material)).to({opacity:1},500).onStart(this.enableRaycast.bind(this,!0)).easing(r.Easing.Quartic.Out);this.hideAnimation=(new r.Tween(this.material)).to({opacity:0},500).onStart(this.enableRaycast.bind(this,!1)).easing(r.Easing.Quartic.Out);this.addEventListener("click",this.onClick);this.addEventListener("hover",this.onHover);this.addEventListener("hoverenter",this.onHoverStart);this.addEventListener("hoverleave", -this.onHoverEnd);this.addEventListener("panolens-dual-eye-effect",this.onDualEyeEffect);this.addEventListener("panolens-container",this.setContainer.bind(this));this.addEventListener("dismiss",this.onDismiss);this.addEventListener("panolens-infospot-focus",this.setFocusMethod);N.load(b,c)}function I(a){a||console.warn("PANOLENS.Widget: No container specified");e.EventDispatcher.call(this);this.DEFAULT_TRANSITION="all 0.27s ease";this.TOUCH_ENABLED=!!("ontouchstart"in window||window.DocumentTouch&& -document instanceof DocumentTouch);this.PREVENT_EVENT_HANDLER=function(a){a.preventDefault();a.stopPropagation()};this.container=a;this.mask=this.activeSubMenu=this.activeMainItem=this.mainMenu=this.settingElement=this.videoElement=this.fullscreenElement=this.barElement=null}function n(a,b){e.Mesh.call(this,a,b);this.type="panorama";this.ImageQualityLow=1;this.ImageQualityFair=2;this.ImageQualityMedium=3;this.ImageQualityHigh=4;this.ImageQualitySuperHigh=5;this.animationDuration=1E3;this.defaultInfospotSize= -350;this.container=void 0;this.loaded=!1;this.linkedSpots=[];this.isInfospotVisible=!1;this.linkingImageScale=this.linkingImageURL=void 0;this.material.side=e.BackSide;this.material.opacity=0;this.scale.x*=-1;this.renderOrder=-1;this.active=!1;this.infospotAnimation=(new r.Tween(this)).to({},this.animationDuration/2);this.addEventListener("load",this.fadeIn.bind(this));this.addEventListener("panolens-container",this.setContainer.bind(this));this.addEventListener("click",this.onClick.bind(this));this.setupTransitions()} -function y(a,b,c){b=b||new e.SphereBufferGeometry(5E3,60,40);c=c||new e.MeshBasicMaterial({opacity:0,transparent:!0});n.call(this,b,c);this.src=a;this.radius=5E3}function W(){var a=new e.BufferGeometry,b=new e.MeshBasicMaterial({color:0,opacity:0,transparent:!0});a.addAttribute("position",new e.BufferAttribute(new Float32Array,1));n.call(this,a,b)}function F(a){a=void 0===a?[]:a;var b=Object.assign({},e.ShaderLib.cube),c=new e.BoxBufferGeometry(1E4,1E4,1E4);b=new e.ShaderMaterial({fragmentShader:b.fragmentShader, -vertexShader:b.vertexShader,uniforms:b.uniforms,side:e.BackSide,transparent:!0});n.call(this,c,b);this.images=a;this.edgeLength=1E4;this.material.uniforms.opacity.value=0}function O(){for(var a=[],b=0;6>b;b++)a.push(u.WhiteTile);F.call(this,a)}function B(a,b){b=void 0===b?{}:b;var c=new e.SphereBufferGeometry(5E3,60,40),d=new e.MeshBasicMaterial({opacity:0,transparent:!0});n.call(this,c,d);this.src=a;this.options={videoElement:document.createElement("video"),loop:!0,muted:!0,autoplay:!1,playsinline:!0, -crossOrigin:"anonymous"};Object.assign(this.options,b);this.videoElement=this.options.videoElement;this.videoProgress=0;this.radius=5E3;this.addEventListener("leave",this.pauseVideo.bind(this));this.addEventListener("enter-fade-start",this.resumeVideoProgress.bind(this));this.addEventListener("video-toggle",this.toggleVideo.bind(this));this.addEventListener("video-time",this.setVideoCurrentTime.bind(this))}function P(a){this._parameters=a=void 0===a?{}:a;this._panoId=this._zoom=null;this._panoClient= -new google.maps.StreetViewService;this._total=this._count=0;this._canvas=[];this._ctx=[];this._hc=this._wc=0;this.result=null;this.rotation=0;this.copyright="";this.onPanoramaLoad=this.onSizeChange=null;this.levelsW=[1,2,4,7,13,26];this.levelsH=[1,1,2,4,7,13];this.widths=[416,832,1664,3328,6656,13312];this.heights=[416,416,832,1664,3328,6656];this.maxH=this.maxW=6656;var b;try{var c=document.createElement("canvas");(b=c.getContext("experimental-webgl"))||(b=c.getContext("webgl"))}catch(d){}this.maxW= -Math.max(b.getParameter(b.MAX_TEXTURE_SIZE),this.maxW);this.maxH=Math.max(b.getParameter(b.MAX_TEXTURE_SIZE),this.maxH)}function Z(a,b){y.call(this);this.panoId=a;this.gsvLoader=null;this.loadRequested=!1;this.setupGoogleMapAPI(b)}function C(a,b,c,d){c=void 0===c?1E4:c;d=void 0===d?.5:d;"image"===(void 0===a?"image":a)&&y.call(this,b,this.createGeometry(c,d),this.createMaterial(c));this.size=c;this.ratio=d;this.EPS=1E-6;this.frameId=null;this.dragging=!1;this.userMouse=new e.Vector2;this.quatA=new e.Quaternion; -this.quatB=new e.Quaternion;this.quatCur=new e.Quaternion;this.quatSlerp=new e.Quaternion;this.vectorX=new e.Vector3(1,0,0);this.vectorY=new e.Vector3(0,1,0);this.addEventListener("window-resize",this.onWindowResize)}function aa(a,b,c){C.call(this,"image",a,b,c)}function J(a){var b=new e.SphereBufferGeometry(5E3,60,40),c=new e.MeshBasicMaterial({visible:!1});n.call(this,b,c);this.media=new S(a);this.radius=5E3;this.addEventListener("enter",this.start.bind(this));this.addEventListener("leave",this.stop.bind(this)); -this.addEventListener("panolens-container",this.onPanolensContainer.bind(this));this.addEventListener("panolens-scene",this.onPanolensScene.bind(this))}function ba(a,b){function c(a){Q=!1;K=L=0;if(!1!==f.enabled){a.preventDefault();if(a.button===f.mouseButtons.ORBIT){if(!0===f.noRotate)return;x=w.ROTATE;D.set(a.clientX,a.clientY)}else if(a.button===f.mouseButtons.ZOOM){if(!0===f.noZoom)return;x=w.DOLLY;y.set(a.clientX,a.clientY)}else if(a.button===f.mouseButtons.PAN){if(!0===f.noPan)return;x=w.PAN; -n.set(a.clientX,a.clientY)}x!==w.NONE&&(document.addEventListener("mousemove",d,!1),document.addEventListener("mouseup",g,!1),f.dispatchEvent(O));f.update()}}function d(a){if(!1!==f.enabled){a.preventDefault();var d=f.domElement===document?f.domElement.body:f.domElement;if(x===w.ROTATE){if(!0===f.noRotate)return;h.set(a.clientX,a.clientY);r.subVectors(h,D);f.rotateLeft(2*Math.PI*r.x/d.clientWidth*f.rotateSpeed);f.rotateUp(2*Math.PI*r.y/d.clientHeight*f.rotateSpeed);D.copy(h);G&&(K=a.clientX-G.clientX, -L=a.clientY-G.clientY);G=a}else if(x===w.DOLLY){if(!0===f.noZoom)return;z.set(a.clientX,a.clientY);T.subVectors(z,y);0T.y&&f.dollyOut();y.copy(z)}else if(x===w.PAN){if(!0===f.noPan)return;U.set(a.clientX,a.clientY);t.subVectors(U,n);f.pan(t.x,t.y);n.copy(U)}x!==w.NONE&&f.update()}}function g(){Q=!0;G=void 0;!1!==f.enabled&&(document.removeEventListener("mousemove",d,!1),document.removeEventListener("mouseup",g,!1),f.dispatchEvent(P),x=w.NONE)}function k(a){if(!1!==f.enabled&&!0!== -f.noZoom&&x===w.NONE){a.preventDefault();a.stopPropagation();var d=0;void 0!==a.wheelDelta?d=a.wheelDelta:void 0!==a.detail&&(d=-a.detail);0d&&(f.object.fov=f.object.fov>f.minFov?f.object.fov-1:f.minFov,f.object.updateProjectionMatrix());f.update();f.dispatchEvent(V);f.dispatchEvent(O);f.dispatchEvent(P)}}function p(a){switch(a.keyCode){case f.keys.UP:I=!1;break;case f.keys.BOTTOM:J=!1;break;case f.keys.LEFT:X= -!1;break;case f.keys.RIGHT:Y=!1}}function m(a){if(!1!==f.enabled&&!0!==f.noKeys&&!0!==f.noRotate){switch(a.keyCode){case f.keys.UP:I=!0;break;case f.keys.BOTTOM:J=!0;break;case f.keys.LEFT:X=!0;break;case f.keys.RIGHT:Y=!0}if(I||J||X||Y)Q=!0,I&&(L=-f.rotateSpeed*f.momentumKeydownFactor),J&&(L=f.rotateSpeed*f.momentumKeydownFactor),X&&(K=-f.rotateSpeed*f.momentumKeydownFactor),Y&&(K=f.rotateSpeed*f.momentumKeydownFactor)}}function l(a){Q=!1;K=L=0;if(!1!==f.enabled){switch(a.touches.length){case 1:if(!0=== -f.noRotate)return;x=w.TOUCH_ROTATE;D.set(a.touches[0].pageX,a.touches[0].pageY);break;case 2:if(!0===f.noZoom)return;x=w.TOUCH_DOLLY;var d=a.touches[0].pageX-a.touches[1].pageX;a=a.touches[0].pageY-a.touches[1].pageY;y.set(0,Math.sqrt(d*d+a*a));break;case 3:if(!0===f.noPan)return;x=w.TOUCH_PAN;n.set(a.touches[0].pageX,a.touches[0].pageY);break;default:x=w.NONE}x!==w.NONE&&f.dispatchEvent(O)}}function v(a){if(!1!==f.enabled){a.preventDefault();a.stopPropagation();var d=f.domElement===document?f.domElement.body: -f.domElement;switch(a.touches.length){case 1:if(!0===f.noRotate)break;if(x!==w.TOUCH_ROTATE)break;h.set(a.touches[0].pageX,a.touches[0].pageY);r.subVectors(h,D);f.rotateLeft(2*Math.PI*r.x/d.clientWidth*f.rotateSpeed);f.rotateUp(2*Math.PI*r.y/d.clientHeight*f.rotateSpeed);D.copy(h);G&&(K=a.touches[0].pageX-G.pageX,L=a.touches[0].pageY-G.pageY);G={pageX:a.touches[0].pageX,pageY:a.touches[0].pageY};f.update();break;case 2:if(!0===f.noZoom)break;if(x!==w.TOUCH_DOLLY)break;d=a.touches[0].pageX-a.touches[1].pageX; -a=a.touches[0].pageY-a.touches[1].pageY;z.set(0,Math.sqrt(d*d+a*a));T.subVectors(z,y);0>T.y?(f.object.fov=f.object.fovf.minFov?f.object.fov-1:f.minFov,f.object.updateProjectionMatrix());y.copy(z);f.update();f.dispatchEvent(V);break;case 3:if(!0===f.noPan)break;if(x!==w.TOUCH_PAN)break;U.set(a.touches[0].pageX,a.touches[0].pageY);t.subVectors(U,n);f.pan(t.x,t.y);n.copy(U);f.update();break;default:x= -w.NONE}}}function q(){Q=!0;G=void 0;!1!==f.enabled&&(f.dispatchEvent(P),x=w.NONE)}this.object=a;this.domElement=void 0!==b?b:document;this.frameId=null;this.enabled=!0;this.center=this.target=new e.Vector3;this.noZoom=!1;this.zoomSpeed=1;this.minDistance=0;this.maxDistance=Infinity;this.minZoom=0;this.maxZoom=Infinity;this.noRotate=!1;this.rotateSpeed=-.15;this.noPan=!0;this.keyPanSpeed=7;this.autoRotate=!1;this.autoRotateSpeed=2;this.minPolarAngle=0;this.maxPolarAngle=Math.PI;this.momentumDampingFactor= -.9;this.momentumScalingFactor=-.005;this.momentumKeydownFactor=20;this.minFov=30;this.maxFov=120;this.minAzimuthAngle=-Infinity;this.maxAzimuthAngle=Infinity;this.noKeys=!1;this.keys={LEFT:37,UP:38,RIGHT:39,BOTTOM:40};this.mouseButtons={ORBIT:e.MOUSE.LEFT,ZOOM:e.MOUSE.MIDDLE,PAN:e.MOUSE.RIGHT};var f=this,D=new e.Vector2,h=new e.Vector2,r=new e.Vector2,n=new e.Vector2,U=new e.Vector2,t=new e.Vector2,u=new e.Vector3,A=new e.Vector3,y=new e.Vector2,z=new e.Vector2,T=new e.Vector2,R=0,H=0,B=0,C=0,E=1, -F=new e.Vector3,M=new e.Vector3,N=new e.Quaternion,K=0,L=0,G,Q=!1,I,J,X,Y,w={NONE:-1,ROTATE:0,DOLLY:1,PAN:2,TOUCH_ROTATE:3,TOUCH_DOLLY:4,TOUCH_PAN:5},x=w.NONE;this.target0=this.target.clone();this.position0=this.object.position.clone();this.zoom0=this.object.zoom;var S=(new e.Quaternion).setFromUnitVectors(a.up,new e.Vector3(0,1,0)),W=S.clone().inverse(),V={type:"change"},O={type:"start"},P={type:"end"};this.setLastQuaternion=function(a){N.copy(a);f.object.quaternion.copy(a)};this.getLastPosition= -function(){return M};this.rotateLeft=function(a){void 0===a&&(a=2*Math.PI/60/60*f.autoRotateSpeed);C-=a};this.rotateUp=function(a){void 0===a&&(a=2*Math.PI/60/60*f.autoRotateSpeed);B-=a};this.panLeft=function(a){var d=this.object.matrix.elements;u.set(d[0],d[1],d[2]);u.multiplyScalar(-a);F.add(u)};this.panUp=function(a){var d=this.object.matrix.elements;u.set(d[4],d[5],d[6]);u.multiplyScalar(a);F.add(u)};this.pan=function(a,d){var b=f.domElement===document?f.domElement.body:f.domElement;if(f.object instanceof -e.PerspectiveCamera){var c=f.object.position.clone().sub(f.target).length();c*=Math.tan(f.object.fov/2*Math.PI/180);f.panLeft(2*a*c/b.clientHeight);f.panUp(2*d*c/b.clientHeight)}else f.object instanceof e.OrthographicCamera?(f.panLeft(a*(f.object.right-f.object.left)/b.clientWidth),f.panUp(d*(f.object.top-f.object.bottom)/b.clientHeight)):console.warn("WARNING: OrbitControls.js encountered an unknown camera type - pan disabled.")};this.momentum=function(){Q&&(1E-4>Math.abs(K)&&1E-4>Math.abs(L)?Q= -!1:(L*=this.momentumDampingFactor,K*=this.momentumDampingFactor,C-=this.momentumScalingFactor*K,B-=this.momentumScalingFactor*L))};this.dollyIn=function(a){void 0===a&&(a=Math.pow(.95,f.zoomSpeed));f.object instanceof e.PerspectiveCamera?E/=a:f.object instanceof e.OrthographicCamera?(f.object.zoom=Math.max(this.minZoom,Math.min(this.maxZoom,this.object.zoom*a)),f.object.updateProjectionMatrix(),f.dispatchEvent(V)):console.warn("WARNING: OrbitControls.js encountered an unknown camera type - dolly/zoom disabled.")}; -this.dollyOut=function(a){void 0===a&&(a=Math.pow(.95,f.zoomSpeed));f.object instanceof e.PerspectiveCamera?E*=a:f.object instanceof e.OrthographicCamera?(f.object.zoom=Math.max(this.minZoom,Math.min(this.maxZoom,this.object.zoom/a)),f.object.updateProjectionMatrix(),f.dispatchEvent(V)):console.warn("WARNING: OrbitControls.js encountered an unknown camera type - dolly/zoom disabled.")};this.update=function(a){var d=this.object.position;A.copy(d).sub(this.target);A.applyQuaternion(S);R=Math.atan2(A.x, -A.z);H=Math.atan2(Math.sqrt(A.x*A.x+A.z*A.z),A.y);this.autoRotate&&x===w.NONE&&this.rotateLeft(2*Math.PI/60/60*f.autoRotateSpeed);this.momentum();R+=C;H+=B;R=Math.max(this.minAzimuthAngle,Math.min(this.maxAzimuthAngle,R));H=Math.max(this.minPolarAngle,Math.min(this.maxPolarAngle,H));H=Math.max(1E-7,Math.min(Math.PI-1E-7,H));var b=A.length()*E;b=Math.max(this.minDistance,Math.min(this.maxDistance,b));this.target.add(F);A.x=b*Math.sin(H)*Math.sin(R);A.y=b*Math.cos(H);A.z=b*Math.sin(H)*Math.cos(R);A.applyQuaternion(W); -d.copy(this.target).add(A);this.object.lookAt(this.target);B=C=0;E=1;F.set(0,0,0);if(1E-7z.y&&f.dollyOut();x.copy(y)}else if(C===A.PAN){if(!0===f.noPan)return;r.set(a.clientX,a.clientY);u.subVectors(r,t);f.pan(u.x,u.y);t.copy(r)}C!==A.NONE&&f.update()}}function h(){R=!0;K=void 0;!1!==f.enabled&&(document.removeEventListener("mousemove",d,!1),document.removeEventListener("mouseup", +h,!1),f.dispatchEvent(Y),C=A.NONE)}function n(a){if(!1!==f.enabled&&!0!==f.noZoom&&C===A.NONE){a.preventDefault();a.stopPropagation();var b=0;void 0!==a.wheelDelta?b=a.wheelDelta:void 0!==a.detail&&(b=-a.detail);a=0b;if(f.revertZoomScrollDirection?!a:a)f.object.fov=f.object.fovf.minFov?f.object.fov-1:f.minFov,f.object.updateProjectionMatrix();f.update();f.dispatchEvent(U); +f.dispatchEvent(S);f.dispatchEvent(Y)}}function E(a){switch(a.keyCode){case f.keys.UP:N=!1;break;case f.keys.BOTTOM:Q=!1;break;case f.keys.LEFT:W=!1;break;case f.keys.RIGHT:X=!1}}function v(a){if(!1!==f.enabled&&!0!==f.noKeys&&!0!==f.noRotate){switch(a.keyCode){case f.keys.UP:N=!0;break;case f.keys.BOTTOM:Q=!0;break;case f.keys.LEFT:W=!0;break;case f.keys.RIGHT:X=!0}if(N||Q||W||X)R=!0,N&&(P=-f.rotateSpeed*f.momentumKeydownFactor),Q&&(P=f.rotateSpeed*f.momentumKeydownFactor),W&&(O=-f.rotateSpeed*f.momentumKeydownFactor), +X&&(O=f.rotateSpeed*f.momentumKeydownFactor)}}function m(a){R=!1;O=P=0;if(!1!==f.enabled){switch(a.touches.length){case 1:if(!0===f.noRotate)return;C=A.TOUCH_ROTATE;J.set(a.touches[0].pageX,a.touches[0].pageY);break;case 2:if(!0===f.noZoom)return;C=A.TOUCH_DOLLY;var b=a.touches[0].pageX-a.touches[1].pageX;a=a.touches[0].pageY-a.touches[1].pageY;x.set(0,Math.sqrt(b*b+a*a));break;case 3:if(!0===f.noPan)return;C=A.TOUCH_PAN;t.set(a.touches[0].pageX,a.touches[0].pageY);break;default:C=A.NONE}C!==A.NONE&& +f.dispatchEvent(S)}}function g(a){if(!1!==f.enabled){a.preventDefault();a.stopPropagation();var b=f.domElement===document?f.domElement.body:f.domElement;switch(a.touches.length){case 1:if(!0===f.noRotate)break;if(C!==A.TOUCH_ROTATE)break;l.set(a.touches[0].pageX,a.touches[0].pageY);p.subVectors(l,J);f.rotateLeft(2*Math.PI*p.x/b.clientWidth*f.rotateSpeed);f.rotateUp(2*Math.PI*p.y/b.clientHeight*f.rotateSpeed);J.copy(l);K&&(O=a.touches[0].pageX-K.pageX,P=a.touches[0].pageY-K.pageY);K={pageX:a.touches[0].pageX, +pageY:a.touches[0].pageY};f.update();break;case 2:if(!0===f.noZoom)break;if(C!==A.TOUCH_DOLLY)break;b=a.touches[0].pageX-a.touches[1].pageX;a=a.touches[0].pageY-a.touches[1].pageY;y.set(0,Math.sqrt(b*b+a*a));z.subVectors(y,x);0>z.y?(f.object.fov=f.object.fovf.minFov?f.object.fov-1:f.minFov,f.object.updateProjectionMatrix());x.copy(y);f.update();f.dispatchEvent(U);break;case 3:if(!0===f.noPan)break; +if(C!==A.TOUCH_PAN)break;r.set(a.touches[0].pageX,a.touches[0].pageY);u.subVectors(r,t);f.pan(u.x,u.y);t.copy(r);f.update();break;default:C=A.NONE}}}function k(){R=!0;K=void 0;!1!==f.enabled&&(f.dispatchEvent(Y),C=A.NONE)}this.object=a;this.domElement=void 0!==b?b:document;this.frameId=null;this.enabled=!0;this.center=this.target=new e.Vector3;this.noZoom=!1;this.zoomSpeed=1;this.revertZoomScrollDirection=!1;this.minDistance=0;this.maxDistance=Infinity;this.minZoom=0;this.maxZoom=Infinity;this.noRotate= +!1;this.rotateSpeed=-.15;this.noPan=!0;this.keyPanSpeed=7;this.autoRotate=!1;this.autoRotateSpeed=2;this.minPolarAngle=0;this.maxPolarAngle=Math.PI;this.momentumDampingFactor=.9;this.momentumScalingFactor=-.005;this.momentumKeydownFactor=20;this.minFov=30;this.maxFov=120;this.minAzimuthAngle=-Infinity;this.maxAzimuthAngle=Infinity;this.noKeys=!1;this.keys={LEFT:37,UP:38,RIGHT:39,BOTTOM:40};this.mouseButtons={ORBIT:e.MOUSE.LEFT,ZOOM:e.MOUSE.MIDDLE,PAN:e.MOUSE.RIGHT};var f=this,J=new e.Vector2,l=new e.Vector2, +p=new e.Vector2,t=new e.Vector2,r=new e.Vector2,u=new e.Vector2,w=new e.Vector3,q=new e.Vector3,x=new e.Vector2,y=new e.Vector2,z=new e.Vector2,B=0,L=0,D=0,F=0,G=1,H=new e.Vector3,I=new e.Vector3,M=new e.Quaternion,O=0,P=0,K,R=!1,N,Q,W,X,A={NONE:-1,ROTATE:0,DOLLY:1,PAN:2,TOUCH_ROTATE:3,TOUCH_DOLLY:4,TOUCH_PAN:5},C=A.NONE;this.target0=this.target.clone();this.position0=this.object.position.clone();this.zoom0=this.object.zoom;var T=(new e.Quaternion).setFromUnitVectors(a.up,new e.Vector3(0,1,0)),V= +T.clone().invert(),U={type:"change"},S={type:"start"},Y={type:"end"};this.setLastQuaternion=function(a){M.copy(a);f.object.quaternion.copy(a)};this.getLastPosition=function(){return I};this.rotateLeft=function(a){void 0===a&&(a=2*Math.PI/60/60*f.autoRotateSpeed);F-=a};this.rotateUp=function(a){void 0===a&&(a=2*Math.PI/60/60*f.autoRotateSpeed);D-=a};this.panLeft=function(a){var b=this.object.matrix.elements;w.set(b[0],b[1],b[2]);w.multiplyScalar(-a);H.add(w)};this.panUp=function(a){var b=this.object.matrix.elements; +w.set(b[4],b[5],b[6]);w.multiplyScalar(a);H.add(w)};this.pan=function(a,b){var d=f.domElement===document?f.domElement.body:f.domElement;if(f.object instanceof e.PerspectiveCamera){var c=f.object.position.clone().sub(f.target).length();c*=Math.tan(f.object.fov/2*Math.PI/180);f.panLeft(2*a*c/d.clientHeight);f.panUp(2*b*c/d.clientHeight)}else f.object instanceof e.OrthographicCamera?(f.panLeft(a*(f.object.right-f.object.left)/d.clientWidth),f.panUp(b*(f.object.top-f.object.bottom)/d.clientHeight)):console.warn("WARNING: OrbitControls.js encountered an unknown camera type - pan disabled.")}; +this.momentum=function(){R&&(1E-4>Math.abs(O)&&1E-4>Math.abs(P)?R=!1:(P*=this.momentumDampingFactor,O*=this.momentumDampingFactor,F-=this.momentumScalingFactor*O,D-=this.momentumScalingFactor*P))};this.dollyIn=function(a){void 0===a&&(a=Math.pow(.95,f.zoomSpeed));f.object instanceof e.PerspectiveCamera?G/=a:f.object instanceof e.OrthographicCamera?(f.object.zoom=Math.max(this.minZoom,Math.min(this.maxZoom,this.object.zoom*a)),f.object.updateProjectionMatrix(),f.dispatchEvent(U)):console.warn("WARNING: OrbitControls.js encountered an unknown camera type - dolly/zoom disabled.")}; +this.dollyOut=function(a){void 0===a&&(a=Math.pow(.95,f.zoomSpeed));f.object instanceof e.PerspectiveCamera?G*=a:f.object instanceof e.OrthographicCamera?(f.object.zoom=Math.max(this.minZoom,Math.min(this.maxZoom,this.object.zoom/a)),f.object.updateProjectionMatrix(),f.dispatchEvent(U)):console.warn("WARNING: OrbitControls.js encountered an unknown camera type - dolly/zoom disabled.")};this.update=function(a){var b=this.object.position;q.copy(b).sub(this.target);q.applyQuaternion(T);B=Math.atan2(q.x, +q.z);L=Math.atan2(Math.sqrt(q.x*q.x+q.z*q.z),q.y);this.autoRotate&&C===A.NONE&&this.rotateLeft(2*Math.PI/60/60*f.autoRotateSpeed);this.momentum();B+=F;L+=D;B=Math.max(this.minAzimuthAngle,Math.min(this.maxAzimuthAngle,B));L=Math.max(this.minPolarAngle,Math.min(this.maxPolarAngle,L));L=Math.max(1E-7,Math.min(Math.PI-1E-7,L));var d=q.length()*G;d=Math.max(this.minDistance,Math.min(this.maxDistance,d));this.target.add(H);q.x=d*Math.sin(L)*Math.sin(B);q.y=d*Math.cos(L);q.z=d*Math.sin(L)*Math.cos(B);q.applyQuaternion(V); +b.copy(this.target).add(q);this.object.lookAt(this.target);D=F=0;G=1;H.set(0,0,0);if(1E-7g&&(l.total=l.total/g*6);c(l)},d)});return k}};S.prototype=Object.assign(Object.create(e.EventDispatcher.prototype),{setContainer:function(a){this.container=a},setScene:function(a){this.scene=a},enumerateDevices:function(){var a=this.devices,b=new Promise(function(b){b(a)});return 0=g.length?(c(0),d--):c(d);b(g[d])})},getDevices:function(a){a=void 0===a?"video":a;var b=this.devices;return this.enumerateDevices().then(function(a){return a.map(function(a){b.includes(a)||b.push(a);return a})}).then(function(b){var d=new RegExp(a,"i");return b.filter(function(a){return d.test(a.kind)})})},getUserMedia:function(a){var b=this.setMediaStream.bind(this),c=this.playVideo.bind(this); -return window.navigator.mediaDevices.getUserMedia(a).then(b).then(c).catch(function(a){console.warn("PANOLENS.Media: "+a)})},setVideDeviceIndex:function(a){this.videoDeviceIndex=a},start:function(a){var b=this.constraints,c=this.getUserMedia.bind(this);this.element=this.createVideoElement();return this.getDevices().then(function(d){if(!d||0===d.length)throw Error("no video device found");b.video.deviceId=(a||d[0]).deviceId;return c(b)})},stop:function(){var a=this.stream;a&&a.active&&(a.getTracks()[0].stop(), -window.removeEventListener("resize",this.onWindowResize.bind(this)),this.stream=this.element=null)},setMediaStream:function(a){this.stream=a;this.element.srcObject=a;this.scene&&(this.scene.background=this.createVideoTexture());window.addEventListener("resize",this.onWindowResize.bind(this))},playVideo:function(){var a=this.element;a&&(a.play(),this.dispatchEvent({type:"play"}))},pauseVideo:function(){var a=this.element;a&&(a.pause(),this.dispatchEvent({type:"pause"}))},createVideoTexture:function(){var a= -this.element,b=new e.VideoTexture(a);b.generateMipmaps=!1;b.minFilter=e.LinearFilter;b.magFilter=e.LinearFilter;b.format=e.RGBFormat;b.center.set(.5,.5);a.addEventListener("canplay",this.onWindowResize.bind(this));return b},createVideoElement:function(){var a=this.dispatchEvent.bind(this),b=document.createElement("video");b.setAttribute("autoplay","");b.setAttribute("muted","");b.setAttribute("playsinline","");b.style.position="absolute";b.style.top="0";b.style.left="0";b.style.width="100%";b.style.height= -"100%";b.style.objectPosition="center";b.style.objectFit="cover";b.style.display=this.scene?"none":"";b.addEventListener("canplay",function(){return a({type:"canplay"})});return b},onWindowResize:function(){if(this.element&&this.element.videoWidth&&this.element.videoHeight&&this.scene){var a=this.container,b=a.clientWidth;a=a.clientHeight;var c=this.scene.background,d=this.element;d=d.videoHeight/d.videoWidth*(this.container?b/a:1)*this.ratioScalar;b>a?c.repeat.set(d,1):c.repeat.set(1,1/d)}}});M.prototype= -Object.assign(Object.create(e.Sprite.prototype),{constructor:M,setColor:function(a){this.material.color.copy(a instanceof e.Color?a:new e.Color(a))},createCanvasTexture:function(a){a=new e.CanvasTexture(a);a.minFilter=e.LinearFilter;a.magFilter=e.LinearFilter;a.generateMipmaps=!1;return a},createCanvas:function(){var a=document.createElement("canvas"),b=a.getContext("2d"),c=this.dpr;a.width=32*c;a.height=32*c;b.scale(c,c);b.shadowBlur=5;b.shadowColor="rgba(200,200,200,0.9)";return{canvas:a,context:b}}, -updateCanvasArcByProgress:function(a){var b=this.context,c=this.canvasWidth,d=this.canvasHeight,g=this.material,k=this.dpr,e=a*Math.PI*2,m=this.color.getStyle(),l=.5*c/k;k=.5*d/k;b.clearRect(0,0,c,d);b.beginPath();0===a?(b.arc(l,k,c/16,0,2*Math.PI),b.fillStyle=m,b.fill()):(b.arc(l,k,c/4-3,-Math.PI/2,-Math.PI/2+e),b.strokeStyle=m,b.lineWidth=3,b.stroke());b.closePath();g.map.needsUpdate=!0},ripple:function(){var a=this,b=this.context,c=this.canvasWidth,d=this.canvasHeight,g=this.material,k=this.rippleDuration, -e=performance.now(),m=this.color,l=this.dpr,h=.5*c/l,q=.5*d/l,f=function(){var p=window.requestAnimationFrame(f),v=(performance.now()-e)/k,n=0<1-v?1-v:0,r=v*c*.5/l;b.clearRect(0,0,c,d);b.beginPath();b.arc(h,q,r,0,2*Math.PI);b.fillStyle="rgba("+255*m.r+", "+255*m.g+", "+255*m.b+", "+n+")";b.fill();b.closePath();1<=v&&(window.cancelAnimationFrame(p),a.updateCanvasArcByProgress(0),a.dispatchEvent({type:"reticle-ripple-end"}));g.map.needsUpdate=!0};this.dispatchEvent({type:"reticle-ripple-start"});f()}, -show:function(){this.visible=!0},hide:function(){this.visible=!1},start:function(a){this.autoSelect&&(this.dispatchEvent({type:"reticle-start"}),this.startTimestamp=performance.now(),this.callback=a,this.update())},end:function(){this.startTimestamp&&(window.cancelAnimationFrame(this.timerId),this.updateCanvasArcByProgress(0),this.startTimestamp=this.timerId=this.callback=null,this.dispatchEvent({type:"reticle-end"}))},update:function(){this.timerId=window.requestAnimationFrame(this.update.bind(this)); -var a=(performance.now()-this.startTimestamp)/this.dwellTime;this.updateCanvasArcByProgress(a);this.dispatchEvent({type:"reticle-update",progress:a});1<=a&&(window.cancelAnimationFrame(this.timerId),this.callback&&this.callback(),this.end(),this.ripple())}});var r=function(a,b){return b={exports:{}},a(b,b.exports),b.exports}(function(a,b){b=function(){this._tweens={};this._tweensAddedDuringUpdate={}};b.prototype={getAll:function(){return Object.keys(this._tweens).map(function(a){return this._tweens[a]}.bind(this))}, -removeAll:function(){this._tweens={}},add:function(a){this._tweens[a.getId()]=a;this._tweensAddedDuringUpdate[a.getId()]=a},remove:function(a){delete this._tweens[a.getId()];delete this._tweensAddedDuringUpdate[a.getId()]},update:function(a,b){var d=Object.keys(this._tweens);if(0===d.length)return!1;for(a=void 0!==a?a:c.now();0(a*=2)?.5*a*a:-.5*(--a*(a-2)-1)}},Cubic:{In:function(a){return a*a*a},Out:function(a){return--a*a*a+1},InOut:function(a){return 1> -(a*=2)?.5*a*a*a:.5*((a-=2)*a*a+2)}},Quartic:{In:function(a){return a*a*a*a},Out:function(a){return 1- --a*a*a*a},InOut:function(a){return 1>(a*=2)?.5*a*a*a*a:-.5*((a-=2)*a*a*a-2)}},Quintic:{In:function(a){return a*a*a*a*a},Out:function(a){return--a*a*a*a*a+1},InOut:function(a){return 1>(a*=2)?.5*a*a*a*a*a:.5*((a-=2)*a*a*a*a+2)}},Sinusoidal:{In:function(a){return 1-Math.cos(a*Math.PI/2)},Out:function(a){return Math.sin(a*Math.PI/2)},InOut:function(a){return.5*(1-Math.cos(Math.PI*a))}},Exponential:{In:function(a){return 0=== -a?0:Math.pow(1024,a-1)},Out:function(a){return 1===a?1:1-Math.pow(2,-10*a)},InOut:function(a){return 0===a?0:1===a?1:1>(a*=2)?.5*Math.pow(1024,a-1):.5*(-Math.pow(2,-10*(a-1))+2)}},Circular:{In:function(a){return 1-Math.sqrt(1-a*a)},Out:function(a){return Math.sqrt(1- --a*a)},InOut:function(a){return 1>(a*=2)?-.5*(Math.sqrt(1-a*a)-1):.5*(Math.sqrt(1-(a-=2)*a)+1)}},Elastic:{In:function(a){return 0===a?0:1===a?1:-Math.pow(2,10*(a-1))*Math.sin(5*(a-1.1)*Math.PI)},Out:function(a){return 0===a?0:1===a? -1:Math.pow(2,-10*a)*Math.sin(5*(a-.1)*Math.PI)+1},InOut:function(a){if(0===a)return 0;if(1===a)return 1;a*=2;return 1>a?-.5*Math.pow(2,10*(a-1))*Math.sin(5*(a-1.1)*Math.PI):.5*Math.pow(2,-10*(a-1))*Math.sin(5*(a-1.1)*Math.PI)+1}},Back:{In:function(a){return a*a*(2.70158*a-1.70158)},Out:function(a){return--a*a*(2.70158*a+1.70158)+1},InOut:function(a){return 1>(a*=2)?.5*a*a*(3.5949095*a-2.5949095):.5*((a-=2)*a*(3.5949095*a+2.5949095)+2)}},Bounce:{In:function(a){return 1-c.Easing.Bounce.Out(1-a)},Out:function(a){return a< -1/2.75?7.5625*a*a:a<2/2.75?7.5625*(a-=1.5/2.75)*a+.75:a<2.5/2.75?7.5625*(a-=2.25/2.75)*a+.9375:7.5625*(a-=2.625/2.75)*a+.984375},InOut:function(a){return.5>a?.5*c.Easing.Bounce.In(2*a):.5*c.Easing.Bounce.Out(2*a-1)+.5}}};c.Interpolation={Linear:function(a,b){var d=a.length-1,g=d*b,e=Math.floor(g),l=c.Interpolation.Utils.Linear;return 0>b?l(a[0],a[1],g):1d?d:e+1],g-e)},Bezier:function(a,b){for(var d=0,g=a.length-1,e=Math.pow,l=c.Interpolation.Utils.Bernstein,h=0;h<= -g;h++)d+=e(1-b,g-h)*e(b,h)*a[h]*l(g,h);return d},CatmullRom:function(a,b){var d=a.length-1,g=d*b,e=Math.floor(g),l=c.Interpolation.Utils.CatmullRom;return a[0]===a[d]?(0>b&&(e=Math.floor(g=d*(1+b))),l(a[(e-1+d)%d],a[e],a[(e+1)%d],a[(e+2)%d],g-e)):0>b?a[0]-(l(a[0],a[0],a[1],a[1],-g)-a[0]):1l?0:l,f.setProgress(l),g.dispatchEvent({type:"panolens-viewer-handler",method:"setVideoCurrentTime",data:l}))}function c(a){a.stopPropagation();e=!1;d()}function d(){g.container.removeEventListener("mousemove",b,!1);g.container.removeEventListener("mouseup",c,!1);g.container.removeEventListener("touchmove",b,!1);g.container.removeEventListener("touchend",c,!1)}var g=this,e=!1,p,m,l;var h=document.createElement("div");h.style.width="0%";h.style.height="100%";h.style.backgroundColor="#fff";var q= -document.createElement("div");q.style.float="right";q.style.width="14px";q.style.height="14px";q.style.transform="translate(7px, -5px)";q.style.borderRadius="50%";q.style.backgroundColor="#ddd";q.addEventListener("mousedown",a,{passive:!0});q.addEventListener("touchstart",a,{passive:!0});h.appendChild(q);var f=this.createCustomItem({style:{float:"left",width:"30%",height:"4px",marginTop:"20px",backgroundColor:"rgba(188,188,188,0.8)"},onTap:function(a){a.preventDefault();a.stopPropagation();if(a.target!== -q){var b=a.changedTouches&&0=window.innerWidth?this.ImageQualityFair:800=window.innerWidth?this.ImageQualityMedium:1280=window.innerWidth?this.ImageQualityHigh:1920=d&&(b.zoom.value=d)},onUpdateCallback:function(){this.frameId=window.requestAnimationFrame(this.onUpdateCallback.bind(this));this.quatSlerp.slerp(this.quatCur,.1);this.material&& -this.material.uniforms.transform.value.makeRotationFromQuaternion(this.quatSlerp);!this.dragging&&1-this.quatSlerp.clone().dot(this.quatCur)=a.length?0:b},setCameraFov:function(a){this.camera.fov=a;this.camera.updateProjectionMatrix()}, -enableControl:function(a){a=0<=a&&aMath.PI?m-2*Math.PI:m;m=m<-Math.PI?m+2*Math.PI:m;k=Math.abs(h.angleTo(k)+(0>=h.y*l.y?l.angleTo(a):-l.angleTo(a)));k*=l.y=a.clientX-this.options.clickTolerance&&this.userMouse.x<=a.clientX+ -this.options.clickTolerance&&this.userMouse.y>=a.clientY-this.options.clickTolerance&&this.userMouse.y<=a.clientY+this.options.clickTolerance||a.changedTouches&&this.userMouse.x>=a.changedTouches[0].clientX-this.options.clickTolerance&&this.userMouse.x<=a.changedTouches[0].clientX+this.options.clickTolerance&&this.userMouse.y>=a.changedTouches[0].clientY-this.options.clickTolerance&&this.userMouse.y<=a.changedTouches[0].clientY+this.options.clickTolerance?"click":void 0;if(!a||!a.target||a.target.classList.contains("panolens-canvas"))if(a.preventDefault(), -a=a.changedTouches&&1===a.changedTouches.length?this.onTap({clientX:a.changedTouches[0].clientX,clientY:a.changedTouches[0].clientY},b):this.onTap(a,b),this.userMouse.type="none",!a&&"click"===b){b=this.options;a=b.autoHideControlBar;var c=this.panorama,d=this.toggleControlBar;b.autoHideInfospot&&c&&c.toggleInfospotVisibility();a&&d()}},onTap:function(a,b){var c=this.container.getBoundingClientRect(),d=c.top,e=this.container,h=e.clientHeight;this.raycasterPoint.x=(a.clientX-c.left)/e.clientWidth* -2-1;this.raycasterPoint.y=2*-((a.clientY-d)/h)+1;this.raycaster.setFromCamera(this.raycasterPoint,this.camera);if(this.panorama){("mousedown"!==a.type&&this.touchSupported||this.OUTPUT_INFOSPOT)&&this.outputPosition();c=this.raycaster.intersectObjects(this.panorama.children,!0);d=this.getConvertedIntersect(c);e=0h&&(m.total=m.total/h*6);c(m)},d)});return n}};D.prototype=Object.assign(Object.create(e.EventDispatcher.prototype),{setContainer:function(a){this.container=a},setScene:function(a){this.scene=a},enumerateDevices:function(){var a=this.devices,b=new Promise(function(b){b(a)});return 0=h.length?(c(0),d--):c(d);b(h[d])})},getDevices:function(a){a=void 0===a?"video":a;var b=this.devices;return this.enumerateDevices().then(function(a){return a.map(function(a){b.includes(a)||b.push(a);return a})}).then(function(b){var d=new RegExp(a,"i"); +return b.filter(function(a){return d.test(a.kind)})})},getUserMedia:function(a){var b=this.setMediaStream.bind(this),c=this.playVideo.bind(this);return window.navigator.mediaDevices.getUserMedia(a).then(b).then(c).catch(function(a){console.warn("PANOLENS.Media: "+a)})},setVideDeviceIndex:function(a){this.videoDeviceIndex=a},start:function(a){var b=this.constraints,c=this.getUserMedia.bind(this);this.element=this.createVideoElement();return this.getDevices().then(function(d){if(!d||0===d.length)throw Error("no video device found"); +b.video.deviceId=(a||d[0]).deviceId;return c(b)})},stop:function(){var a=this.stream;a&&a.active&&(a.getTracks()[0].stop(),window.removeEventListener("resize",this.onWindowResize.bind(this)),this.stream=this.element=null)},setMediaStream:function(a){this.stream=a;this.element.srcObject=a;this.scene&&(this.scene.background=this.createVideoTexture());window.addEventListener("resize",this.onWindowResize.bind(this))},playVideo:function(){var a=this.element;a&&(a.play(),this.dispatchEvent({type:"play"}))}, +pauseVideo:function(){var a=this.element;a&&(a.pause(),this.dispatchEvent({type:"pause"}))},createVideoTexture:function(){var a=this.element,b=new e.VideoTexture(a);b.generateMipmaps=!1;b.minFilter=e.LinearFilter;b.magFilter=e.LinearFilter;b.format=e.RGBFormat;b.center.set(.5,.5);a.addEventListener("canplay",this.onWindowResize.bind(this));return b},createVideoElement:function(){var a=this.dispatchEvent.bind(this),b=document.createElement("video");b.setAttribute("autoplay","");b.setAttribute("muted", +"");b.setAttribute("playsinline","");b.style.position="absolute";b.style.top="0";b.style.left="0";b.style.width="100%";b.style.height="100%";b.style.objectPosition="center";b.style.objectFit="cover";b.style.display=this.scene?"none":"";b.addEventListener("canplay",function(){return a({type:"canplay"})});return b},onWindowResize:function(){if(this.element&&this.element.videoWidth&&this.element.videoHeight&&this.scene){var a=this.container,b=a.clientWidth;a=a.clientHeight;var c=this.scene.background, +d=this.element;d=d.videoHeight/d.videoWidth*(this.container?b/a:1)*this.ratioScalar;b>a?c.repeat.set(d,1):c.repeat.set(1,1/d)}}});var B=function(a,b,c){a=void 0===a?16777215:a;b=void 0===b?!0:b;c=void 0===c?1500:c;var d=B.createCanvas(window.devicePixelRatio),h=d.canvas;d=d.context;var n=new e.SpriteMaterial({color:a,map:B.createCanvasTexture(h)});n=e.Sprite.call(this,n)||this;n.dpr=window.devicePixelRatio;n.canvasWidth=h.width;n.canvasHeight=h.height;n.context=d;n.color=a instanceof e.Color?a:new e.Color(a); +n.autoSelect=b;n.dwellTime=c;n.rippleDuration=500;n.position.z=-10;n.center.set(.5,.5);n.scale.set(.5,.5,1);n.startTimestamp=null;n.timerId=null;n.callback=null;n.frustumCulled=!1;n.updateCanvasArcByProgress(0);return n};$jscomp.inherits(B,e.Sprite);B.prototype.setColor=function(a){this.material.color.copy(a instanceof e.Color?a:new e.Color(a))};B.createCanvasTexture=function(a){a=new e.CanvasTexture(a);a.minFilter=e.LinearFilter;a.magFilter=e.LinearFilter;a.generateMipmaps=!1;return a};B.createCanvas= +function(a){var b=document.createElement("canvas"),c=b.getContext("2d");b.width=32*a;b.height=32*a;c.scale(a,a);c.shadowBlur=5;c.shadowColor="rgba(200,200,200,0.9)";return{canvas:b,context:c}};B.prototype.updateCanvasArcByProgress=function(a){var b=this.context,c=this.canvasWidth,d=this.canvasHeight,h=this.material,n=this.dpr,e=a*Math.PI*2,v=this.color.getStyle(),m=.5*c/n;n=.5*d/n;b.clearRect(0,0,c,d);b.beginPath();0===a?(b.arc(m,n,c/16,0,2*Math.PI),b.fillStyle=v,b.fill()):(b.arc(m,n,c/4-3,-Math.PI/ +2,-Math.PI/2+e),b.strokeStyle=v,b.lineWidth=3,b.stroke());b.closePath();h.map.needsUpdate=!0};B.prototype.ripple=function(){var a=this,b=this.context,c=this.canvasWidth,d=this.canvasHeight,h=this.material,n=this.rippleDuration,e=performance.now(),v=this.color,m=this.dpr,g=.5*c/m,k=.5*d/m,f=function(){var E=window.requestAnimationFrame(f),l=(performance.now()-e)/n,p=0<1-l?1-l:0,q=l*c*.5/m;b.clearRect(0,0,c,d);b.beginPath();b.arc(g,k,q,0,2*Math.PI);b.fillStyle="rgba("+255*v.r+", "+255*v.g+", "+255* +v.b+", "+p+")";b.fill();b.closePath();1<=l&&(window.cancelAnimationFrame(E),a.updateCanvasArcByProgress(0),a.dispatchEvent({type:"reticle-ripple-end"}));h.map.needsUpdate=!0};this.dispatchEvent({type:"reticle-ripple-start"});f()};B.prototype.show=function(){this.visible=!0};B.prototype.hide=function(){this.visible=!1};B.prototype.start=function(a){this.autoSelect&&(this.dispatchEvent({type:"reticle-start"}),this.startTimestamp=performance.now(),this.callback=a,this.update())};B.prototype.end=function(){this.startTimestamp&& +(window.cancelAnimationFrame(this.timerId),this.updateCanvasArcByProgress(0),this.startTimestamp=this.timerId=this.callback=null,this.dispatchEvent({type:"reticle-end"}))};B.prototype.update=function(){this.timerId=window.requestAnimationFrame(this.update.bind(this));var a=(performance.now()-this.startTimestamp)/this.dwellTime;this.updateCanvasArcByProgress(a);this.dispatchEvent({type:"reticle-update",progress:a});1<=a&&(window.cancelAnimationFrame(this.timerId),this.callback&&this.callback(),this.end(), +this.ripple())};var t=function(a,b){return b={exports:{}},a(b,b.exports),b.exports}(function(a,b){b=function(){this._tweens={};this._tweensAddedDuringUpdate={}};b.prototype={getAll:function(){return Object.keys(this._tweens).map(function(a){return this._tweens[a]}.bind(this))},removeAll:function(){this._tweens={}},add:function(a){this._tweens[a.getId()]=a;this._tweensAddedDuringUpdate[a.getId()]=a},remove:function(a){delete this._tweens[a.getId()];delete this._tweensAddedDuringUpdate[a.getId()]}, +update:function(a,b){var d=Object.keys(this._tweens);if(0===d.length)return!1;for(a=void 0!==a?a:c.now();0(a*=2)?.5*a*a:-.5*(--a*(a-2)-1)}},Cubic:{In:function(a){return a*a*a},Out:function(a){return--a*a*a+1},InOut:function(a){return 1>(a*=2)?.5*a*a*a:.5*((a-=2)*a*a+2)}},Quartic:{In:function(a){return a*a*a*a},Out:function(a){return 1- --a*a*a*a},InOut:function(a){return 1>(a*=2)?.5*a*a*a*a:-.5*((a-=2)*a*a*a-2)}},Quintic:{In:function(a){return a*a*a*a*a},Out:function(a){return--a* +a*a*a*a+1},InOut:function(a){return 1>(a*=2)?.5*a*a*a*a*a:.5*((a-=2)*a*a*a*a+2)}},Sinusoidal:{In:function(a){return 1-Math.cos(a*Math.PI/2)},Out:function(a){return Math.sin(a*Math.PI/2)},InOut:function(a){return.5*(1-Math.cos(Math.PI*a))}},Exponential:{In:function(a){return 0===a?0:Math.pow(1024,a-1)},Out:function(a){return 1===a?1:1-Math.pow(2,-10*a)},InOut:function(a){return 0===a?0:1===a?1:1>(a*=2)?.5*Math.pow(1024,a-1):.5*(-Math.pow(2,-10*(a-1))+2)}},Circular:{In:function(a){return 1-Math.sqrt(1- +a*a)},Out:function(a){return Math.sqrt(1- --a*a)},InOut:function(a){return 1>(a*=2)?-.5*(Math.sqrt(1-a*a)-1):.5*(Math.sqrt(1-(a-=2)*a)+1)}},Elastic:{In:function(a){return 0===a?0:1===a?1:-Math.pow(2,10*(a-1))*Math.sin(5*(a-1.1)*Math.PI)},Out:function(a){return 0===a?0:1===a?1:Math.pow(2,-10*a)*Math.sin(5*(a-.1)*Math.PI)+1},InOut:function(a){if(0===a)return 0;if(1===a)return 1;a*=2;return 1>a?-.5*Math.pow(2,10*(a-1))*Math.sin(5*(a-1.1)*Math.PI):.5*Math.pow(2,-10*(a-1))*Math.sin(5*(a-1.1)*Math.PI)+ +1}},Back:{In:function(a){return a*a*(2.70158*a-1.70158)},Out:function(a){return--a*a*(2.70158*a+1.70158)+1},InOut:function(a){return 1>(a*=2)?.5*a*a*(3.5949095*a-2.5949095):.5*((a-=2)*a*(3.5949095*a+2.5949095)+2)}},Bounce:{In:function(a){return 1-c.Easing.Bounce.Out(1-a)},Out:function(a){return a<1/2.75?7.5625*a*a:a<2/2.75?7.5625*(a-=1.5/2.75)*a+.75:a<2.5/2.75?7.5625*(a-=2.25/2.75)*a+.9375:7.5625*(a-=2.625/2.75)*a+.984375},InOut:function(a){return.5>a?.5*c.Easing.Bounce.In(2*a):.5*c.Easing.Bounce.Out(2* +a-1)+.5}}};c.Interpolation={Linear:function(a,b){var d=a.length-1,h=d*b,e=Math.floor(h),m=c.Interpolation.Utils.Linear;return 0>b?m(a[0],a[1],h):1d?d:e+1],h-e)},Bezier:function(a,b){for(var d=0,h=a.length-1,e=Math.pow,m=c.Interpolation.Utils.Bernstein,g=0;g<=h;g++)d+=e(1-b,h-g)*e(b,g)*a[g]*m(h,g);return d},CatmullRom:function(a,b){var d=a.length-1,h=d*b,e=Math.floor(h),m=c.Interpolation.Utils.CatmullRom;return a[0]===a[d]?(0>b&&(e=Math.floor(h=d*(1+b))),m(a[(e-1+ +d)%d],a[e],a[(e+1)%d],a[(e+2)%d],h-e)):0>b?a[0]-(m(a[0],a[0],a[1],a[1],-h)-a[0]):1m?0:m,f.setProgress(m),h.dispatchEvent({type:"panolens-viewer-handler",method:"setVideoCurrentTime",data:m}))}function c(a){a.stopPropagation();e=!1;d()}function d(){h.container.removeEventListener("mousemove",b,!1);h.container.removeEventListener("mouseup",c,!1);h.container.removeEventListener("touchmove",b,!1);h.container.removeEventListener("touchend", +c,!1)}var h=this,e=!1,g,k,m;var l=document.createElement("div");l.style.width="0%";l.style.height="100%";l.style.backgroundColor="#fff";var p=document.createElement("div");p.style.float="right";p.style.width="14px";p.style.height="14px";p.style.transform="translate(7px, -5px)";p.style.borderRadius="50%";p.style.backgroundColor="#ddd";p.addEventListener("mousedown",a,{passive:!0});p.addEventListener("touchstart",a,{passive:!0});l.appendChild(p);var f=this.createCustomItem({style:{float:"left",width:"30%", +height:"4px",marginTop:"20px",backgroundColor:"rgba(188,188,188,0.8)"},onTap:function(a){a.preventDefault();a.stopPropagation();if(a.target!==p){var b=a.changedTouches&&0=window.innerWidth?this.ImageQualityFair:800=window.innerWidth?this.ImageQualityMedium:1280=window.innerWidth?this.ImageQualityHigh:1920c;c++)b.push(y.WhiteTile);return a};$jscomp.inherits(ba,G);var w=function(a,b){b=void 0===b?{}:b;var c=new e.SphereBufferGeometry(5E3,60,40);var d=new e.MeshBasicMaterial({opacity:0,transparent:!0});c=l.call(this,c,d)||this;c.src=a;c.options={videoElement:document.createElement("video"),loop:!0,muted:!0,autoplay:!1,playsinline:!0,crossOrigin:"anonymous"};Object.assign(c.options, +b);c.videoElement=c.options.videoElement;c.videoProgress=0;c.radius=5E3;c.addEventListener("leave",c.pauseVideo.bind(c));c.addEventListener("enter-fade-start",c.resumeVideoProgress.bind(c));c.addEventListener("video-toggle",c.toggleVideo.bind(c));c.addEventListener("video-time",c.setVideoCurrentTime.bind(c));return c};$jscomp.inherits(w,l);w.prototype.isMobile=function(){var a=!1,b=window.navigator.userAgent||window.navigator.vendor||window.opera;if(/(android|bb\d+|meego).+mobile|avantgo|bada\/|blackberry|blazer|compal|elaine|fennec|hiptop|iemobile|ip(hone|od)|iris|kindle|lge |maemo|midp|mmp|mobile.+firefox|netfront|opera m(ob|in)i|palm( os)?|phone|p(ixi|re)\/|plucker|pocket|psp|series(4|6)0|symbian|treo|up\.(browser|link)|vodafone|wap|windows ce|xda|xiino/i.test(b)|| +/1207|6310|6590|3gso|4thp|50[1-6]i|770s|802s|a wa|abac|ac(er|oo|s\-)|ai(ko|rn)|al(av|ca|co)|amoi|an(ex|ny|yw)|aptu|ar(ch|go)|as(te|us)|attw|au(di|\-m|r |s )|avan|be(ck|ll|nq)|bi(lb|rd)|bl(ac|az)|br(e|v)w|bumb|bw\-(n|u)|c55\/|capi|ccwa|cdm\-|cell|chtm|cldc|cmd\-|co(mp|nd)|craw|da(it|ll|ng)|dbte|dc\-s|devi|dica|dmob|do(c|p)o|ds(12|\-d)|el(49|ai)|em(l2|ul)|er(ic|k0)|esl8|ez([4-7]0|os|wa|ze)|fetc|fly(\-|_)|g1 u|g560|gene|gf\-5|g\-mo|go(\.w|od)|gr(ad|un)|haie|hcit|hd\-(m|p|t)|hei\-|hi(pt|ta)|hp( i|ip)|hs\-c|ht(c(\-| |_|a|g|p|s|t)|tp)|hu(aw|tc)|i\-(20|go|ma)|i230|iac( |\-|\/)|ibro|idea|ig01|ikom|im1k|inno|ipaq|iris|ja(t|v)a|jbro|jemu|jigs|kddi|keji|kgt( |\/)|klon|kpt |kwc\-|kyo(c|k)|le(no|xi)|lg( g|\/(k|l|u)|50|54|\-[a-w])|libw|lynx|m1\-w|m3ga|m50\/|ma(te|ui|xo)|mc(01|21|ca)|m\-cr|me(rc|ri)|mi(o8|oa|ts)|mmef|mo(01|02|bi|de|do|t(\-| |o|v)|zz)|mt(50|p1|v )|mwbp|mywa|n10[0-2]|n20[2-3]|n30(0|2)|n50(0|2|5)|n7(0(0|1)|10)|ne((c|m)\-|on|tf|wf|wg|wt)|nok(6|i)|nzph|o2im|op(ti|wv)|oran|owg1|p800|pan(a|d|t)|pdxg|pg(13|\-([1-8]|c))|phil|pire|pl(ay|uc)|pn\-2|po(ck|rt|se)|prox|psio|pt\-g|qa\-a|qc(07|12|21|32|60|\-[2-7]|i\-)|qtek|r380|r600|raks|rim9|ro(ve|zo)|s55\/|sa(ge|ma|mm|ms|ny|va)|sc(01|h\-|oo|p\-)|sdk\/|se(c(\-|0|1)|47|mc|nd|ri)|sgh\-|shar|sie(\-|m)|sk\-0|sl(45|id)|sm(al|ar|b3|it|t5)|so(ft|ny)|sp(01|h\-|v\-|v )|sy(01|mb)|t2(18|50)|t6(00|10|18)|ta(gt|lk)|tcl\-|tdg\-|tel(i|m)|tim\-|t\-mo|to(pl|sh)|ts(70|m\-|m3|m5)|tx\-9|up(\.b|g1|si)|utst|v400|v750|veri|vi(rg|te)|vk(40|5[0-3]|\-v)|vm40|voda|vulc|vx(52|53|60|61|70|80|81|83|85|98)|w3c(\-| )|webc|whit|wi(g |nc|nw)|wmlb|wonu|x700|yas\-|your|zeto|zte\-/i.test(b.substr(0, +4)))a=!0;return a};w.prototype.load=function(){var a=this.options,b=a.muted,c=a.loop,d=a.autoplay,e=a.playsinline;a=a.crossOrigin;var n=this.videoElement,g=this.material,k=this.onProgress.bind(this),m=this.onLoad.bind(this);n.loop=c;n.autoplay=d;n.playsinline=e;n.crossOrigin=a;n.muted=b;e&&(n.setAttribute("playsinline",""),n.setAttribute("webkit-playsinline",""));e=function(){this.setVideoTexture(n);d&&this.dispatchEvent({type:"panolens-viewer-handler",method:"updateVideoPlayButton",data:!1});this.isMobile()&& +(n.pause(),d&&b?this.dispatchEvent({type:"panolens-viewer-handler",method:"updateVideoPlayButton",data:!1}):this.dispatchEvent({type:"panolens-viewer-handler",method:"updateVideoPlayButton",data:!0}));window.requestAnimationFrame(function(){g.map.needsUpdate=!0;k({loaded:1,total:1});m()})};2=d&&(b.zoom.value=d)};r.prototype.onUpdateCallback=function(){this.frameId=window.requestAnimationFrame(this.onUpdateCallback.bind(this)); +this.quatSlerp.slerp(this.quatCur,.1);this.material&&this.material.uniforms.transform.value.makeRotationFromQuaternion(this.quatSlerp);!this.dragging&&1-this.quatSlerp.clone().dot(this.quatCur)=a.length?0:b};g.prototype.setCameraFov=function(a){this.camera.fov=a;this.camera.updateProjectionMatrix()};g.prototype.enableControl=function(a){a=0<=a&&aMath.PI?l-2*Math.PI:l;l=l<-Math.PI?l+2*Math.PI:l;g=Math.abs(k.angleTo(g)+(0>=k.y*m.y?m.angleTo(a):-m.angleTo(a)));g*=m.y=a.clientX-this.options.clickTolerance&&this.userMouse.x<=a.clientX+this.options.clickTolerance&& +this.userMouse.y>=a.clientY-this.options.clickTolerance&&this.userMouse.y<=a.clientY+this.options.clickTolerance||a.changedTouches&&this.userMouse.x>=a.changedTouches[0].clientX-this.options.clickTolerance&&this.userMouse.x<=a.changedTouches[0].clientX+this.options.clickTolerance&&this.userMouse.y>=a.changedTouches[0].clientY-this.options.clickTolerance&&this.userMouse.y<=a.changedTouches[0].clientY+this.options.clickTolerance?"click":void 0;if(!a||!a.target||a.target.classList.contains("panolens-canvas"))if(a.preventDefault(), +a=a.changedTouches&&1===a.changedTouches.length?this.onTap({clientX:a.changedTouches[0].clientX,clientY:a.changedTouches[0].clientY},b):this.onTap(a,b),this.userMouse.type="none",!a&&"click"===b){b=this.options;a=b.autoHideControlBar;var c=this.panorama,d=this.toggleControlBar;b.autoHideInfospot&&c&&c.toggleInfospotVisibility();a&&d()}};g.prototype.onTap=function(a,b){var c=this.container.getBoundingClientRect(),d=c.top,e=this.container,g=e.clientHeight;this.raycasterPoint.x=(a.clientX-c.left)/e.clientWidth* +2-1;this.raycasterPoint.y=2*-((a.clientY-d)/g)+1;this.raycaster.setFromCamera(this.raycasterPoint,this.camera);if(this.panorama){("mousedown"!==a.type&&this.touchSupported||this.OUTPUT_INFOSPOT)&&this.outputPosition();c=this.raycaster.intersectObjects(this.panorama.children,!0);d=this.getConvertedIntersect(c);e=0 {}, onProgress = () => {}, onError = () => {} ) { // Enable cache - Cache.enabled = true; + THREE.Cache.enabled = true; let cached, request, arrayBufferView, blob, urlCreator, image, reference; @@ -118,18 +138,27 @@ const ImageLoader = { } // Cached - cached = Cache.get(reference ? reference : url); + cached = THREE.Cache.get(reference ? reference : url); if (cached !== undefined) { if (onLoad) { - setTimeout(function () { + if ( cached.complete && cached.src ) { + setTimeout( function () { + + onProgress( { loaded: 1, total: 1 } ); + onLoad( cached ); + + }, 0 ); + } else { + cached.addEventListener( 'load', function () { - onProgress({loaded: 1, total: 1}); - onLoad(cached); + onProgress( { loaded: 1, total: 1 } ); + onLoad( cached ); - }, 0); + }, false ); + } } @@ -142,7 +171,7 @@ const ImageLoader = { image = document.createElementNS('http://www.w3.org/1999/xhtml', 'img'); // Add to cache - Cache.add(reference ? reference : url, image); + THREE.Cache.add(reference ? reference : url, image); const onImageLoaded = () => { @@ -162,13 +191,6 @@ const ImageLoader = { request = new window.XMLHttpRequest(); request.open('GET', url, true); - if (process.env.npm_lifecycle_event !== 'test') { - request.onreadystatechange = function () { - if (this.readyState === 4 && this.status >= 400) { - onError(); - } - }; - } request.responseType = 'arraybuffer'; request.addEventListener( 'error', onError ); request.addEventListener( 'progress', event => { @@ -222,7 +244,7 @@ const TextureLoader = { */ load: function ( url, onLoad = () => {}, onProgress, onError ) { - var texture = new Texture(); + var texture = new THREE.Texture(); ImageLoader.load( url, function ( image ) { @@ -231,7 +253,7 @@ const TextureLoader = { // JPEGs can't have an alpha channel, so memory can be saved by storing them as RGB. const isJPEG = url.search( /\.(jpg|jpeg)$/ ) > 0 || url.search( /^data\:image\/jpeg/ ) === 0; - texture.format = isJPEG ? RGBFormat : RGBAFormat; + texture.format = isJPEG ? THREE.RGBFormat : THREE.RGBAFormat; texture.needsUpdate = true; onLoad( texture ); @@ -264,7 +286,7 @@ const CubeTextureLoader = { var texture, loaded, progress, all, loadings; - texture = new CubeTexture( [] ); + texture = new THREE.CubeTexture( [] ); loaded = 0; progress = {}; @@ -340,7 +362,7 @@ function Media ( constraints ) { this.videoDeviceIndex = 0; } -Media.prototype = Object.assign( Object.create( EventDispatcher.prototype ), { +Media.prototype = Object.assign( Object.create( THREE.EventDispatcher.prototype ), { setContainer: function ( container ) { @@ -584,12 +606,12 @@ Media.prototype = Object.assign( Object.create( EventDispatcher.prototype ), { createVideoTexture: function () { const video = this.element; - const texture = new VideoTexture( video ); + const texture = new THREE.VideoTexture( video ); texture.generateMipmaps = false; - texture.minFilter = LinearFilter; - texture.magFilter = LinearFilter; - texture.format = RGBFormat; + texture.minFilter = THREE.LinearFilter; + texture.magFilter = THREE.LinearFilter; + texture.format = THREE.RGBFormat; texture.center.set( 0.5, 0.5 ); video.addEventListener( 'canplay', this.onWindowResize.bind( this ) ); @@ -672,40 +694,34 @@ Media.prototype = Object.assign( Object.create( EventDispatcher.prototype ), { * @param {boolean} [autoSelect=true] - Auto selection * @param {number} [dwellTime=1500] - Duration for dwelling sequence to complete */ - -function Reticle ( color = 0xffffff, autoSelect = true, dwellTime = 1500 ) { - - this.dpr = window.devicePixelRatio; - - const { canvas, context } = this.createCanvas(); - const material = new SpriteMaterial( { color, map: this.createCanvasTexture( canvas ) } ); - - Sprite.call( this, material ); - - this.canvasWidth = canvas.width; - this.canvasHeight = canvas.height; - this.context = context; - this.color = color instanceof Color ? color : new Color( color ); - - this.autoSelect = autoSelect; - this.dwellTime = dwellTime; - this.rippleDuration = 500; - this.position.z = -10; - this.center.set( 0.5, 0.5 ); - this.scale.set( 0.5, 0.5, 1 ); - - this.startTimestamp = null; - this.timerId = null; - this.callback = null; - - this.frustumCulled = false; - - this.updateCanvasArcByProgress( 0 ); - -} -Reticle.prototype = Object.assign( Object.create( Sprite.prototype ), { - - constructor: Reticle, +class Reticle extends THREE.Sprite { + constructor( color = 0xffffff, autoSelect = true, dwellTime = 1500 ) { + const { canvas, context } = Reticle.createCanvas(window.devicePixelRatio); + const material = new THREE.SpriteMaterial( { color, map: Reticle.createCanvasTexture( canvas ) } ); + super(material); + + this.dpr = window.devicePixelRatio; + + this.canvasWidth = canvas.width; + this.canvasHeight = canvas.height; + this.context = context; + this.color = color instanceof THREE.Color ? color : new THREE.Color( color ); + + this.autoSelect = autoSelect; + this.dwellTime = dwellTime; + this.rippleDuration = 500; + this.position.z = -10; + this.center.set( 0.5, 0.5 ); + this.scale.set( 0.5, 0.5, 1 ); + + this.startTimestamp = null; + this.timerId = null; + this.callback = null; + + this.frustumCulled = false; + + this.updateCanvasArcByProgress( 0 ); + } /** * Set material color @@ -713,12 +729,12 @@ Reticle.prototype = Object.assign( Object.create( Sprite.prototype ), { * @memberOf Reticle * @instance */ - setColor: function ( color ) { - - this.material.color.copy( color instanceof Color ? color : new Color( color ) ); - - }, + setColor ( color ) { + this.material.color.copy( color instanceof THREE.Color ? color : new THREE.Color( color ) ); + + } + /** * Create canvas texture * @param {HTMLCanvasElement} canvas @@ -726,17 +742,17 @@ Reticle.prototype = Object.assign( Object.create( Sprite.prototype ), { * @instance * @returns {THREE.CanvasTexture} */ - createCanvasTexture: function ( canvas ) { - - const texture = new CanvasTexture( canvas ); - texture.minFilter = LinearFilter; - texture.magFilter = LinearFilter; + static createCanvasTexture ( canvas ) { + + const texture = new THREE.CanvasTexture( canvas ); + texture.minFilter = THREE.LinearFilter; + texture.magFilter = THREE.LinearFilter; texture.generateMipmaps = false; - + return texture; - }, - + } + /** * Create canvas element * @memberOf Reticle @@ -745,33 +761,30 @@ Reticle.prototype = Object.assign( Object.create( Sprite.prototype ), { * @returns {HTMLCanvasElement} object.canvas * @returns {CanvasRenderingContext2D} object.context */ - createCanvas: function () { - + static createCanvas (dpr) { const width = 32; const height = 32; const canvas = document.createElement( 'canvas' ); const context = canvas.getContext( '2d' ); - const dpr = this.dpr; - + canvas.width = width * dpr; canvas.height = height * dpr; context.scale( dpr, dpr ); - + context.shadowBlur = 5; context.shadowColor = 'rgba(200,200,200,0.9)'; - + return { canvas, context }; - - }, - + } + /** * Update canvas arc by progress * @param {number} progress * @memberOf Reticle * @instance */ - updateCanvasArcByProgress: function ( progress ) { - + updateCanvasArcByProgress ( progress ) { + const context = this.context; const { canvasWidth, canvasHeight, material } = this; const dpr = this.dpr; @@ -780,10 +793,10 @@ Reticle.prototype = Object.assign( Object.create( Sprite.prototype ), { const x = canvasWidth * 0.5 / dpr; const y = canvasHeight * 0.5 / dpr; const lineWidth = 3; - + context.clearRect( 0, 0, canvasWidth, canvasHeight ); context.beginPath(); - + if ( progress === 0 ) { context.arc( x, y, canvasWidth / 16, 0, 2 * Math.PI ); context.fillStyle = color; @@ -794,13 +807,13 @@ Reticle.prototype = Object.assign( Object.create( Sprite.prototype ), { context.lineWidth = lineWidth; context.stroke(); } - + context.closePath(); - + material.map.needsUpdate = true; - - }, - + + } + /** * Ripple effect * @memberOf Reticle @@ -808,8 +821,8 @@ Reticle.prototype = Object.assign( Object.create( Sprite.prototype ), { * @fires Reticle#reticle-ripple-start * @fires Reticle#reticle-ripple-end */ - ripple: function () { - + ripple() { + const context = this.context; const { canvasWidth, canvasHeight, material } = this; const duration = this.rippleDuration; @@ -818,73 +831,73 @@ Reticle.prototype = Object.assign( Object.create( Sprite.prototype ), { const dpr = this.dpr; const x = canvasWidth * 0.5 / dpr; const y = canvasHeight * 0.5 / dpr; - + const update = () => { - + const timerId = window.requestAnimationFrame( update ); const elapsed = performance.now() - timestamp; const progress = elapsed / duration; const opacity = 1.0 - progress > 0 ? 1.0 - progress : 0; const radius = progress * canvasWidth * 0.5 / dpr; - + context.clearRect( 0, 0, canvasWidth, canvasHeight ); context.beginPath(); context.arc( x, y, radius, 0, Math.PI * 2 ); context.fillStyle = `rgba(${color.r * 255}, ${color.g * 255}, ${color.b * 255}, ${opacity})`; context.fill(); context.closePath(); - + if ( progress >= 1.0 ) { - + window.cancelAnimationFrame( timerId ); this.updateCanvasArcByProgress( 0 ); - + /** * Reticle ripple end event * @type {object} * @event Reticle#reticle-ripple-end */ this.dispatchEvent( { type: 'reticle-ripple-end' } ); - + } - + material.map.needsUpdate = true; - + }; - + /** * Reticle ripple start event * @type {object} * @event Reticle#reticle-ripple-start */ this.dispatchEvent( { type: 'reticle-ripple-start' } ); - + update(); - - }, - + + } + /** * Make reticle visible * @memberOf Reticle * @instance */ - show: function () { - + show () { + this.visible = true; - - }, - + + } + /** * Make reticle invisible * @memberOf Reticle * @instance */ - hide: function () { - + hide () { + this.visible = false; - - }, - + + } + /** * Start dwelling * @param {function} callback @@ -892,87 +905,86 @@ Reticle.prototype = Object.assign( Object.create( Sprite.prototype ), { * @instance * @fires Reticle#reticle-start */ - start: function ( callback ) { - + start ( callback ) { + if ( !this.autoSelect ) { - + return; - + } - + /** * Reticle start event * @type {object} * @event Reticle#reticle-start */ this.dispatchEvent( { type: 'reticle-start' } ); - + this.startTimestamp = performance.now(); this.callback = callback; this.update(); - - }, - + + } + /** * End dwelling * @memberOf Reticle * @instance * @fires Reticle#reticle-end */ - end: function(){ - + end(){ + if ( !this.startTimestamp ) { return; } - + window.cancelAnimationFrame( this.timerId ); - + this.updateCanvasArcByProgress( 0 ); this.callback = null; this.timerId = null; this.startTimestamp = null; - + /** * Reticle end event * @type {object} * @event Reticle#reticle-end */ this.dispatchEvent( { type: 'reticle-end' } ); - - }, - + + } + /** * Update dwelling * @memberOf Reticle * @instance * @fires Reticle#reticle-update */ - update: function () { - + update () { + this.timerId = window.requestAnimationFrame( this.update.bind( this ) ); - + const elapsed = performance.now() - this.startTimestamp; const progress = elapsed / this.dwellTime; - + this.updateCanvasArcByProgress( progress ); - + /** * Reticle update event * @type {object} * @event Reticle#reticle-update */ this.dispatchEvent( { type: 'reticle-update', progress } ); - + if ( progress >= 1.0 ) { - + window.cancelAnimationFrame( this.timerId ); if ( this.callback ) { this.callback(); } this.end(); this.ripple(); - + } - - } - -} ); + + } +} function createCommonjsModule(fn, module) { return module = { exports: {} }, fn(module, module.exports), module.exports; @@ -1138,7 +1150,7 @@ TWEEN.Tween.prototype = { to: function (properties, duration) { - this._valuesEnd = Object.create(properties); + this._valuesEnd = properties; if (duration !== undefined) { this._duration = duration; @@ -1910,104 +1922,101 @@ TWEEN.Interpolation = { * @param {string} [imageSrc=PANOLENS.DataImage.Info] - Image overlay info * @param {boolean} [animated=true] - Enable default hover animation */ -function Infospot ( scale = 300, imageSrc, animated ) { - - const duration = 500, scaleFactor = 1.3; - - imageSrc = imageSrc || DataImage.Info; - - Sprite.call( this ); - - this.type = 'infospot'; +class Infospot extends THREE.Sprite { - this.animated = animated !== undefined ? animated : true; - this.isHovering = false; + constructor( scale = 300, imageSrc, animated ) { + super(); + const duration = 500, scaleFactor = 1.3; - /* - * TODO: Three.js bug hotfix for sprite raycasting r104 - * https://github.com/mrdoob/three.js/issues/14624 - */ - this.frustumCulled = false; + imageSrc = imageSrc || DataImage.Info; - this.element = null; - this.toPanorama = null; - this.cursorStyle = null; + this.type = 'infospot'; - this.mode = MODES.NORMAL; + this.animated = animated !== undefined ? animated : true; + this.isHovering = false; - this.scale.set( scale, scale, 1 ); - this.rotation.y = Math.PI; + /* + * TODO: Three.js bug hotfix for sprite raycasting r104 + * https://github.com/mrdoob/three.js/issues/14624 + */ + this.frustumCulled = false; - this.container = null; + this.element = null; + this.toPanorama = null; + this.cursorStyle = null; - this.originalRaycast = this.raycast; + this.mode = MODES.NORMAL; - // Event Handler - this.HANDLER_FOCUS = null; + this.scale.set( scale, scale, 1 ); + this.rotation.y = Math.PI; - this.material.side = DoubleSide; - this.material.depthTest = false; - this.material.transparent = true; - this.material.opacity = 0; + this.container = null; - this.scaleUpAnimation = new Tween.Tween(); - this.scaleDownAnimation = new Tween.Tween(); + this.originalRaycast = this.raycast; + // Event Handler + this.HANDLER_FOCUS = null; - const postLoad = function ( texture ) { + this.material.side = THREE.DoubleSide; + this.material.depthTest = false; + this.material.transparent = true; + this.material.opacity = 0; - if ( !this.material ) { return; } + this.scaleUpAnimation = new Tween.Tween(); + this.scaleDownAnimation = new Tween.Tween(); - const ratio = texture.image.width / texture.image.height; - const textureScale = new Vector3(); - texture.image.width = texture.image.naturalWidth || 64; - texture.image.height = texture.image.naturalHeight || 64; + const postLoad = function ( texture ) { - this.scale.set( ratio * scale, scale, 1 ); + if ( !this.material ) { return; } - textureScale.copy( this.scale ); + const ratio = texture.image.width / texture.image.height; + const textureScale = new THREE.Vector3(); - this.scaleUpAnimation = new Tween.Tween( this.scale ) - .to( { x: textureScale.x * scaleFactor, y: textureScale.y * scaleFactor }, duration ) - .easing( Tween.Easing.Elastic.Out ); + texture.image.width = texture.image.naturalWidth || 64; + texture.image.height = texture.image.naturalHeight || 64; - this.scaleDownAnimation = new Tween.Tween( this.scale ) - .to( { x: textureScale.x, y: textureScale.y }, duration ) - .easing( Tween.Easing.Elastic.Out ); + this.scale.set( ratio * scale, scale, 1 ); - this.material.map = texture; - this.material.needsUpdate = true; + textureScale.copy( this.scale ); - }.bind( this ); + this.scaleUpAnimation = new Tween.Tween( this.scale ) + .to( { x: textureScale.x * scaleFactor, y: textureScale.y * scaleFactor }, duration ) + .easing( Tween.Easing.Elastic.Out ); - // Add show and hide animations - this.showAnimation = new Tween.Tween( this.material ) - .to( { opacity: 1 }, duration ) - .onStart( this.enableRaycast.bind( this, true ) ) - .easing( Tween.Easing.Quartic.Out ); + this.scaleDownAnimation = new Tween.Tween( this.scale ) + .to( { x: textureScale.x, y: textureScale.y }, duration ) + .easing( Tween.Easing.Elastic.Out ); - this.hideAnimation = new Tween.Tween( this.material ) - .to( { opacity: 0 }, duration ) - .onStart( this.enableRaycast.bind( this, false ) ) - .easing( Tween.Easing.Quartic.Out ); + this.material.map = texture; + this.material.needsUpdate = true; - // Attach event listeners - this.addEventListener( 'click', this.onClick ); - this.addEventListener( 'hover', this.onHover ); - this.addEventListener( 'hoverenter', this.onHoverStart ); - this.addEventListener( 'hoverleave', this.onHoverEnd ); - this.addEventListener( 'panolens-dual-eye-effect', this.onDualEyeEffect ); - this.addEventListener( 'panolens-container', this.setContainer.bind( this ) ); - this.addEventListener( 'dismiss', this.onDismiss ); - this.addEventListener( 'panolens-infospot-focus', this.setFocusMethod ); + }.bind( this ); - TextureLoader.load( imageSrc, postLoad ); + // Add show and hide animations + this.showAnimation = new Tween.Tween( this.material ) + .to( { opacity: 1 }, duration ) + .onStart( this.enableRaycast.bind( this, true ) ) + .easing( Tween.Easing.Quartic.Out ); -} -Infospot.prototype = Object.assign( Object.create( Sprite.prototype ), { + this.hideAnimation = new Tween.Tween( this.material ) + .to( { opacity: 0 }, duration ) + .onStart( this.enableRaycast.bind( this, false ) ) + .easing( Tween.Easing.Quartic.Out ); - constructor: Infospot, + // Attach event listeners + this.addEventListener( 'click', this.onClick ); + this.addEventListener( 'hover', this.onHover ); + this.addEventListener( 'hoverenter', this.onHoverStart ); + this.addEventListener( 'hoverleave', this.onHoverEnd ); + this.addEventListener( 'panolens-dual-eye-effect', this.onDualEyeEffect ); + this.addEventListener( 'panolens-container', this.setContainer.bind( this ) ); + this.addEventListener( 'dismiss', this.onDismiss ); + this.addEventListener( 'panolens-infospot-focus', this.setFocusMethod ); + + TextureLoader.load( imageSrc, postLoad ); + } + /** * Set infospot container @@ -2015,30 +2024,30 @@ Infospot.prototype = Object.assign( Object.create( Sprite.prototype ), { * @memberOf Infospot * @instance */ - setContainer: function ( data ) { + setContainer ( data ) { let container; - + if ( data instanceof HTMLElement ) { - + container = data; - + } else if ( data && data.container ) { - + container = data.container; - + } - + // Append element if exists if ( container && this.element ) { - + container.appendChild( this.element ); - + } - + this.container = container; - - }, + + } /** * Get container @@ -2046,11 +2055,11 @@ Infospot.prototype = Object.assign( Object.create( Sprite.prototype ), { * @instance * @return {HTMLElement} - The container of this infospot */ - getContainer: function () { + getContainer () { return this.container; - }, + } /** * This will be called by a click event @@ -2059,7 +2068,7 @@ Infospot.prototype = Object.assign( Object.create( Sprite.prototype ), { * @memberOf Infospot * @instance */ - onClick: function ( event ) { + onClick ( event ) { if ( this.element && this.getContainer() ) { @@ -2070,7 +2079,7 @@ Infospot.prototype = Object.assign( Object.create( Sprite.prototype ), { } - }, + } /** * Dismiss current element if any @@ -2078,7 +2087,7 @@ Infospot.prototype = Object.assign( Object.create( Sprite.prototype ), { * @memberOf Infospot * @instance */ - onDismiss: function () { + onDismiss () { if ( this.element ) { @@ -2087,7 +2096,7 @@ Infospot.prototype = Object.assign( Object.create( Sprite.prototype ), { } - }, + } /** * This will be called by a mouse hover event @@ -2096,7 +2105,7 @@ Infospot.prototype = Object.assign( Object.create( Sprite.prototype ), { * @memberOf Infospot * @instance */ - onHover: function () {}, + onHover () {} /** * This will be called on a mouse hover start @@ -2105,7 +2114,7 @@ Infospot.prototype = Object.assign( Object.create( Sprite.prototype ), { * @memberOf Infospot * @instance */ - onHoverStart: function ( event ) { + onHoverStart ( event ) { if ( !this.getContainer() ) { return; } @@ -2114,14 +2123,14 @@ Infospot.prototype = Object.assign( Object.create( Sprite.prototype ), { this.isHovering = true; this.container.style.cursor = cursorStyle; - + if ( this.animated ) { scaleDownAnimation.stop(); scaleUpAnimation.start(); } - + if ( element && event.mouseEvent.clientX >= 0 && event.mouseEvent.clientY >= 0 ) { const { left, right, style } = element; @@ -2147,10 +2156,10 @@ Infospot.prototype = Object.assign( Object.create( Sprite.prototype ), { element._height = element.clientHeight; } - + } - }, + } /** * This will be called on a mouse hover end @@ -2158,7 +2167,7 @@ Infospot.prototype = Object.assign( Object.create( Sprite.prototype ), { * @memberOf Infospot * @instance */ - onHoverEnd: function () { + onHoverEnd () { if ( !this.getContainer() ) { return; } @@ -2186,7 +2195,7 @@ Infospot.prototype = Object.assign( Object.create( Sprite.prototype ), { } - }, + } /** * On dual eye effect handler @@ -2195,8 +2204,8 @@ Infospot.prototype = Object.assign( Object.create( Sprite.prototype ), { * @memberOf Infospot * @instance */ - onDualEyeEffect: function ( event ) { - + onDualEyeEffect ( event ) { + if ( !this.getContainer() ) { return; } let element, halfWidth, halfHeight; @@ -2241,7 +2250,7 @@ Infospot.prototype = Object.assign( Object.create( Sprite.prototype ), { this.container.appendChild( element.left ); this.container.appendChild( element.right ); - }, + } /** * Translate the hovering element by css transform @@ -2250,7 +2259,7 @@ Infospot.prototype = Object.assign( Object.create( Sprite.prototype ), { * @memberOf Infospot * @instance */ - translateElement: function ( x, y ) { + translateElement ( x, y ) { if ( !this.element._width || !this.element._height || !this.getContainer() ) { @@ -2270,8 +2279,8 @@ Infospot.prototype = Object.assign( Object.create( Sprite.prototype ), { top = y - height - delta; if ( ( this.mode === MODES.CARDBOARD || this.mode === MODES.STEREO ) - && element.left && element.right - && !( x === container.clientWidth / 2 && y === container.clientHeight / 2 ) ) { + && element.left && element.right + && !( x === container.clientWidth / 2 && y === container.clientHeight / 2 ) ) { left = container.clientWidth / 4 - width + ( x - container.clientWidth / 2 ); top = container.clientHeight / 2 - height - delta + ( y - container.clientHeight / 2 ); @@ -2288,7 +2297,7 @@ Infospot.prototype = Object.assign( Object.create( Sprite.prototype ), { } - }, + } /** * Set vendor specific css @@ -2298,7 +2307,7 @@ Infospot.prototype = Object.assign( Object.create( Sprite.prototype ), { * @memberOf Infospot * @instance */ - setElementStyle: function ( type, element, value ) { + setElementStyle ( type, element, value ) { const style = element.style; @@ -2308,7 +2317,7 @@ Infospot.prototype = Object.assign( Object.create( Sprite.prototype ), { } - }, + } /** * Set hovering text content @@ -2316,7 +2325,7 @@ Infospot.prototype = Object.assign( Object.create( Sprite.prototype ), { * @memberOf Infospot * @instance */ - setText: function ( text ) { + setText ( text ) { if ( this.element ) { @@ -2324,18 +2333,18 @@ Infospot.prototype = Object.assign( Object.create( Sprite.prototype ), { } - }, + } /** * Set cursor css style on hover * @memberOf Infospot * @instance */ - setCursorHoverStyle: function ( style ) { + setCursorHoverStyle ( style ) { this.cursorStyle = style; - }, + } /** * Add hovering text element @@ -2344,7 +2353,7 @@ Infospot.prototype = Object.assign( Object.create( Sprite.prototype ), { * @memberOf Infospot * @instance */ - addHoverText: function ( text, delta = 40 ) { + addHoverText ( text, delta = 40 ) { if ( !this.element ) { @@ -2364,7 +2373,7 @@ Infospot.prototype = Object.assign( Object.create( Sprite.prototype ), { this.setText( text ); - }, + } /** * Add hovering element by cloning an element @@ -2373,7 +2382,7 @@ Infospot.prototype = Object.assign( Object.create( Sprite.prototype ), { * @memberOf Infospot * @instance */ - addHoverElement: function ( el, delta = 40 ) { + addHoverElement ( el, delta = 40 ) { if ( !this.element ) { @@ -2386,14 +2395,14 @@ Infospot.prototype = Object.assign( Object.create( Sprite.prototype ), { } - }, + } /** * Remove hovering element * @memberOf Infospot * @instance */ - removeHoverElement: function () { + removeHoverElement () { if ( this.element ) { @@ -2416,14 +2425,14 @@ Infospot.prototype = Object.assign( Object.create( Sprite.prototype ), { } - }, + } /** * Lock hovering element * @memberOf Infospot * @instance */ - lockHoverElement: function () { + lockHoverElement () { if ( this.element ) { @@ -2431,14 +2440,14 @@ Infospot.prototype = Object.assign( Object.create( Sprite.prototype ), { } - }, + } /** * Unlock hovering element * @memberOf Infospot * @instance */ - unlockHoverElement: function () { + unlockHoverElement () { if ( this.element ) { @@ -2446,7 +2455,7 @@ Infospot.prototype = Object.assign( Object.create( Sprite.prototype ), { } - }, + } /** * Enable raycasting @@ -2454,7 +2463,7 @@ Infospot.prototype = Object.assign( Object.create( Sprite.prototype ), { * @memberOf Infospot * @instance */ - enableRaycast: function ( enabled = true ) { + enableRaycast ( enabled = true ) { if ( enabled ) { @@ -2466,7 +2475,7 @@ Infospot.prototype = Object.assign( Object.create( Sprite.prototype ), { } - }, + } /** * Show infospot @@ -2474,7 +2483,7 @@ Infospot.prototype = Object.assign( Object.create( Sprite.prototype ), { * @memberOf Infospot * @instance */ - show: function ( delay = 0 ) { + show ( delay = 0 ) { const { animated, hideAnimation, showAnimation, material } = this; @@ -2490,7 +2499,7 @@ Infospot.prototype = Object.assign( Object.create( Sprite.prototype ), { } - }, + } /** * Hide infospot @@ -2498,7 +2507,7 @@ Infospot.prototype = Object.assign( Object.create( Sprite.prototype ), { * @memberOf Infospot * @instance */ - hide: function ( delay = 0 ) { + hide ( delay = 0 ) { const { animated, hideAnimation, showAnimation, material, element } = this; @@ -2518,15 +2527,15 @@ Infospot.prototype = Object.assign( Object.create( Sprite.prototype ), { material.opacity = 0; } - - }, + + } /** * Set focus event handler * @memberOf Infospot * @instance */ - setFocusMethod: function ( event ) { + setFocusMethod ( event ) { if ( event ) { @@ -2534,7 +2543,7 @@ Infospot.prototype = Object.assign( Object.create( Sprite.prototype ), { } - }, + } /** * Focus camera center to this infospot @@ -2543,7 +2552,7 @@ Infospot.prototype = Object.assign( Object.create( Sprite.prototype ), { * @memberOf Infospot * @instance */ - focus: function ( duration, easing ) { + focus ( duration, easing ) { if ( this.HANDLER_FOCUS ) { @@ -2552,14 +2561,14 @@ Infospot.prototype = Object.assign( Object.create( Sprite.prototype ), { } - }, + } /** * Dispose * @memberOf Infospot * @instance */ - dispose: function () { + dispose () { const { geometry, material } = this; const { map } = material; @@ -2578,55 +2587,52 @@ Infospot.prototype = Object.assign( Object.create( Sprite.prototype ), { } -} ); + + +} /** * @classdesc Widget for controls * @constructor * @param {HTMLElement} container - A domElement where default control widget will be attached to */ -function Widget ( container ) { - - if ( !container ) { - - console.warn( 'PANOLENS.Widget: No container specified' ); - - } - - EventDispatcher.call( this ); +class Widget extends THREE.EventDispatcher { - this.DEFAULT_TRANSITION = 'all 0.27s ease'; - this.TOUCH_ENABLED = !!(( 'ontouchstart' in window ) || window.DocumentTouch && document instanceof DocumentTouch); - this.PREVENT_EVENT_HANDLER = function ( event ) { - event.preventDefault(); - event.stopPropagation(); - }; + constructor( container ) { + super(); + if ( !container ) { - this.container = container; + console.warn( 'PANOLENS.Widget: No container specified' ); - this.barElement = null; - this.fullscreenElement = null; - this.videoElement = null; - this.settingElement = null; + } - this.mainMenu = null; + this.DEFAULT_TRANSITION = 'all 0.27s ease'; + this.TOUCH_ENABLED = !!(( 'ontouchstart' in window ) || window.DocumentTouch && document instanceof DocumentTouch); + this.PREVENT_EVENT_HANDLER = function ( event ) { + event.preventDefault(); + event.stopPropagation(); + }; - this.activeMainItem = null; - this.activeSubMenu = null; - this.mask = null; + this.container = container; -} + this.barElement = null; + this.fullscreenElement = null; + this.videoElement = null; + this.settingElement = null; -Widget.prototype = Object.assign( Object.create( EventDispatcher.prototype ), { + this.mainMenu = null; - constructor: Widget, + this.activeMainItem = null; + this.activeSubMenu = null; + this.mask = null; + } /** * Add control bar * @memberOf Widget * @instance */ - addControlBar: function () { + addControlBar () { if ( !this.container ) { @@ -2719,14 +2725,14 @@ Widget.prototype = Object.assign( Object.create( EventDispatcher.prototype ), { this.barElement = bar; - }, + } /** * Create default menu * @memberOf Widget * @instance */ - createDefaultMenu: function () { + createDefaultMenu () { var scope = this, handler; @@ -2782,7 +2788,7 @@ Widget.prototype = Object.assign( Object.create( EventDispatcher.prototype ), { ]; - }, + } /** * Add buttons on top of control bar @@ -2790,7 +2796,7 @@ Widget.prototype = Object.assign( Object.create( EventDispatcher.prototype ), { * @memberOf Widget * @instance */ - addControlButton: function ( name ) { + addControlButton ( name ) { let element; @@ -2831,14 +2837,14 @@ Widget.prototype = Object.assign( Object.create( EventDispatcher.prototype ), { this.barElement.appendChild( element ); - }, + } /** * Create modal mask * @memberOf Widget * @instance */ - createMask: function () { + createMask () { const element = document.createElement( 'div' ); element.style.position = 'absolute'; @@ -2863,14 +2869,14 @@ Widget.prototype = Object.assign( Object.create( EventDispatcher.prototype ), { return element; - }, + } /** * Create Setting button to toggle menu * @memberOf Widget * @instance */ - createSettingButton: function () { + createSettingButton () { let scope = this, item; @@ -2882,7 +2888,7 @@ Widget.prototype = Object.assign( Object.create( EventDispatcher.prototype ), { scope.mainMenu.toggle(); if ( this.activated ) { - + this.deactivate(); } else { @@ -2924,7 +2930,7 @@ Widget.prototype = Object.assign( Object.create( EventDispatcher.prototype ), { if ( scope.mainMenu && scope.mainMenu.visible ) { scope.mainMenu.hide(); - + } if ( scope.activeSubMenu && scope.activeSubMenu.visible ) { @@ -2939,14 +2945,14 @@ Widget.prototype = Object.assign( Object.create( EventDispatcher.prototype ), { scope.mainMenu.unslideAll(); } - + }; item.activated = false; return item; - }, + } /** * Create Fullscreen button @@ -2955,7 +2961,7 @@ Widget.prototype = Object.assign( Object.create( EventDispatcher.prototype ), { * @instance * @fires Widget#panolens-viewer-handler */ - createFullscreenButton: function () { + createFullscreenButton () { let scope = this, item, isFullscreen = false, tapSkipped = true, stylesheetId; @@ -2965,9 +2971,9 @@ Widget.prototype = Object.assign( Object.create( EventDispatcher.prototype ), { // Don't create button if no support if ( !document.fullscreenEnabled && - !document.webkitFullscreenEnabled && - !document.mozFullScreenEnabled && - !document.msFullscreenEnabled ) { + !document.webkitFullscreenEnabled && + !document.mozFullScreenEnabled && + !document.msFullscreenEnabled ) { return; } @@ -2984,7 +2990,7 @@ Widget.prototype = Object.assign( Object.create( EventDispatcher.prototype ), { if ( container.msRequestFullscreen ) { container.msRequestFullscreen(); } if ( container.mozRequestFullScreen ) { container.mozRequestFullScreen(); } if ( container.webkitRequestFullscreen ) { container.webkitRequestFullscreen( Element.ALLOW_KEYBOARD_INPUT ); } - + isFullscreen = true; } else { @@ -3052,10 +3058,10 @@ Widget.prototype = Object.assign( Object.create( EventDispatcher.prototype ), { sheet.innerHTML = ':-webkit-full-screen { width: 100% !important; height: 100% !important }'; document.body.appendChild( sheet ); } - + return item; - }, + } /** * Create video control container @@ -3063,7 +3069,7 @@ Widget.prototype = Object.assign( Object.create( EventDispatcher.prototype ), { * @instance * @return {HTMLSpanElement} - The dom element icon for video control */ - createVideoControl: function () { + createVideoControl () { const item = document.createElement( 'span' ); item.style.display = 'none'; @@ -3083,7 +3089,7 @@ Widget.prototype = Object.assign( Object.create( EventDispatcher.prototype ), { item.controlButton = this.createVideoControlButton(); item.seekBar = this.createVideoControlSeekbar(); - + item.appendChild( item.controlButton ); item.appendChild( item.seekBar ); @@ -3105,7 +3111,7 @@ Widget.prototype = Object.assign( Object.create( EventDispatcher.prototype ), { return item; - }, + } /** * Create video control button @@ -3114,7 +3120,7 @@ Widget.prototype = Object.assign( Object.create( EventDispatcher.prototype ), { * @return {HTMLSpanElement} - The dom element icon for video control * @fires Widget#panolens-viewer-handler */ - createVideoControlButton: function () { + createVideoControlButton () { const scope = this; @@ -3163,7 +3169,7 @@ Widget.prototype = Object.assign( Object.create( EventDispatcher.prototype ), { return item; - }, + } /** * Create video seekbar @@ -3172,7 +3178,7 @@ Widget.prototype = Object.assign( Object.create( EventDispatcher.prototype ), { * @return {HTMLSpanElement} - The dom element icon for video seekbar * @fires Widget#panolens-viewer-handler */ - createVideoControlSeekbar: function () { + createVideoControlSeekbar () { let scope = this, item, progressElement, progressElementControl, isDragging = false, mouseX, percentageNow, percentageNext; @@ -3196,9 +3202,9 @@ Widget.prototype = Object.assign( Object.create( EventDispatcher.prototype ), { function onMouseDown ( event ) { event.stopPropagation(); - + isDragging = true; - + mouseX = event.clientX || ( event.changedTouches && event.changedTouches[0].clientX ); percentageNow = parseInt( progressElement.style.width ) / 100; @@ -3211,7 +3217,7 @@ Widget.prototype = Object.assign( Object.create( EventDispatcher.prototype ), { if( isDragging ){ const clientX = event.clientX || ( event.changedTouches && event.changedTouches[0].clientX ); - + percentageNext = ( clientX - mouseX ) / item.clientWidth; percentageNext = percentageNow + percentageNext; @@ -3330,7 +3336,7 @@ Widget.prototype = Object.assign( Object.create( EventDispatcher.prototype ), { return item; - }, + } /** * Create menu item @@ -3339,7 +3345,7 @@ Widget.prototype = Object.assign( Object.create( EventDispatcher.prototype ), { * @instance * @return {HTMLElement} - An anchor tag element */ - createMenuItem: function ( title ) { + createMenuItem ( title ) { const scope = this; const item = document.createElement( 'a' ); @@ -3384,7 +3390,7 @@ Widget.prototype = Object.assign( Object.create( EventDispatcher.prototype ), { }; item.addSelection = function ( name ) { - + const selection = document.createElement( 'span' ); selection.style.fontSize = '13px'; selection.style.fontWeight = '300'; @@ -3393,13 +3399,13 @@ Widget.prototype = Object.assign( Object.create( EventDispatcher.prototype ), { this.selection = selection; this.setSelectionTitle( name ); this.appendChild( selection ); - + return this; }; item.addIcon = function ( url = DataImage.ChevronRight, left = false, flip = false ) { - + const element = document.createElement( 'span' ); element.style.float = left ? 'left' : 'right'; element.style.width = '17px'; @@ -3430,20 +3436,20 @@ Widget.prototype = Object.assign( Object.create( EventDispatcher.prototype ), { }; item.addEventListener( 'mouseenter', function () { - + this.style.backgroundColor = '#e0e0e0'; }, false ); item.addEventListener( 'mouseleave', function () { - + this.style.backgroundColor = '#fafafa'; }, false ); return item; - }, + } /** * Create menu item header @@ -3452,7 +3458,7 @@ Widget.prototype = Object.assign( Object.create( EventDispatcher.prototype ), { * @instance * @return {HTMLElement} - An anchor tag element */ - createMenuItemHeader: function ( title ) { + createMenuItemHeader ( title ) { const header = this.createMenuItem( title ); @@ -3461,7 +3467,7 @@ Widget.prototype = Object.assign( Object.create( EventDispatcher.prototype ), { return header; - }, + } /** * Create main menu @@ -3470,8 +3476,8 @@ Widget.prototype = Object.assign( Object.create( EventDispatcher.prototype ), { * @instance * @return {HTMLElement} - A span element */ - createMainMenu: function ( menus ) { - + createMainMenu ( menus ) { + let scope = this, menu = this.createMenu(); menu._width = 200; @@ -3524,7 +3530,7 @@ Widget.prototype = Object.assign( Object.create( EventDispatcher.prototype ), { return menu; - }, + } /** * Create sub menu @@ -3534,7 +3540,7 @@ Widget.prototype = Object.assign( Object.create( EventDispatcher.prototype ), { * @instance * @return {HTMLElement} - A span element */ - createSubMenu: function ( title, items ) { + createSubMenu ( title, items ) { let scope = this, menu, subMenu = this.createMenu(); @@ -3586,8 +3592,8 @@ Widget.prototype = Object.assign( Object.create( EventDispatcher.prototype ), { subMenu.slideAll( true ); return subMenu; - - }, + + } /** * Create general menu @@ -3595,7 +3601,7 @@ Widget.prototype = Object.assign( Object.create( EventDispatcher.prototype ), { * @instance * @return {HTMLElement} - A span element */ - createMenu: function () { + createMenu () { const scope = this; const menu = document.createElement( 'span' ); @@ -3735,7 +3741,7 @@ Widget.prototype = Object.assign( Object.create( EventDispatcher.prototype ), { return menu; - }, + } /** * Create custom item element @@ -3743,7 +3749,7 @@ Widget.prototype = Object.assign( Object.create( EventDispatcher.prototype ), { * @instance * @return {HTMLSpanElement} - The dom element icon */ - createCustomItem: function ( options = {} ) { + createCustomItem ( options = {} ) { const scope = this; const item = options.element || document.createElement( 'span' ); @@ -3757,19 +3763,19 @@ Widget.prototype = Object.assign( Object.create( EventDispatcher.prototype ), { item.style.backgroundRepeat = 'no-repeat'; item.style.backgroundPosition = 'center'; item.style.webkitUserSelect = - item.style.MozUserSelect = - item.style.userSelect = 'none'; + item.style.MozUserSelect = + item.style.userSelect = 'none'; item.style.position = 'relative'; item.style.pointerEvents = 'auto'; // White glow on icon item.addEventListener( scope.TOUCH_ENABLED ? 'touchstart' : 'mouseenter', function() { item.style.filter = - item.style.webkitFilter = 'drop-shadow(0 0 5px rgba(255,255,255,1))'; + item.style.webkitFilter = 'drop-shadow(0 0 5px rgba(255,255,255,1))'; }, { passive: true }); item.addEventListener( scope.TOUCH_ENABLED ? 'touchend' : 'mouseleave', function() { item.style.filter = - item.style.webkitFilter = ''; + item.style.webkitFilter = ''; }, { passive: true }); this.mergeStyleOptions( item, options.style ); @@ -3787,10 +3793,10 @@ Widget.prototype = Object.assign( Object.create( EventDispatcher.prototype ), { if ( onDispose ) { options.onDispose(); } }; - + return item; - }, + } /** * Merge item css style @@ -3800,7 +3806,7 @@ Widget.prototype = Object.assign( Object.create( EventDispatcher.prototype ), { * @instance * @return {HTMLElement} - The same element with merged styles */ - mergeStyleOptions: function ( element, options = {} ) { + mergeStyleOptions ( element, options = {} ) { for ( let property in options ){ @@ -3814,14 +3820,14 @@ Widget.prototype = Object.assign( Object.create( EventDispatcher.prototype ), { return element; - }, + } /** * Dispose widgets by detaching dom elements from container * @memberOf Widget * @instance */ - dispose: function () { + dispose () { if ( this.barElement ) { this.container.removeChild( this.barElement ); @@ -3831,8 +3837,8 @@ Widget.prototype = Object.assign( Object.create( EventDispatcher.prototype ), { } } - -} ); + +} /** * @classdesc Base Panorama @@ -3840,72 +3846,59 @@ Widget.prototype = Object.assign( Object.create( EventDispatcher.prototype ), { * @param {THREE.Geometry} geometry - The geometry for this panorama * @param {THREE.Material} material - The material for this panorama */ -function Panorama ( geometry, material ) { - - Mesh.call( this, geometry, material ); - - this.type = 'panorama'; +class Panorama extends THREE.Mesh { + constructor(geometry, material) { + super(geometry, material); - this.ImageQualityLow = 1; - this.ImageQualityFair = 2; - this.ImageQualityMedium = 3; - this.ImageQualityHigh = 4; - this.ImageQualitySuperHigh = 5; + this.type = 'panorama'; - this.animationDuration = 1000; + this.ImageQualityLow = 1; + this.ImageQualityFair = 2; + this.ImageQualityMedium = 3; + this.ImageQualityHigh = 4; + this.ImageQualitySuperHigh = 5; - this.defaultInfospotSize = 350; + this.animationDuration = 1000; - this.container = undefined; + this.defaultInfospotSize = 350; - this.loaded = false; + this.container = undefined; - this.linkedSpots = []; + this.loaded = false; - this.isInfospotVisible = false; - - this.linkingImageURL = undefined; - this.linkingImageScale = undefined; - - this.material.side = BackSide; - this.material.opacity = 0; + this.linkedSpots = []; - this.scale.x *= -1; - this.renderOrder = -1; + this.isInfospotVisible = false; - this.active = false; + this.linkingImageURL = undefined; + this.linkingImageScale = undefined; - this.infospotAnimation = new Tween.Tween( this ).to( {}, this.animationDuration / 2 ); + this.material.side = THREE.BackSide; + this.material.opacity = 0; - this.addEventListener( 'load', this.fadeIn.bind( this ) ); - this.addEventListener( 'panolens-container', this.setContainer.bind( this ) ); - this.addEventListener( 'click', this.onClick.bind( this ) ); + this.scale.x *= -1; + this.renderOrder = -1; - this.setupTransitions(); + this.active = false; -} + this.infospotAnimation = new Tween.Tween(this).to({}, this.animationDuration / 2); -Panorama.prototype = Object.assign( Object.create( Mesh.prototype ), { + this.addEventListener('load', this.fadeIn.bind(this)); + this.addEventListener('panolens-container', this.setContainer.bind(this)); + this.addEventListener('click', this.onClick.bind(this)); - constructor: Panorama, + this.setupTransitions(); + } - /** - * Adding an object - * To counter the scale.x = -1, it will automatically add an - * empty object with inverted scale on x - * @memberOf Panorama - * @instance - * @param {THREE.Object3D} object - The object to be added - */ - add: function ( object ) { + add(object) { let invertedObject; - if ( arguments.length > 1 ) { + if (arguments.length > 1) { - for ( var i = 0; i < arguments.length; i ++ ) { + for (var i = 0; i < arguments.length; i++) { - this.add( arguments[ i ] ); + this.add(arguments[i]); } @@ -3914,50 +3907,52 @@ Panorama.prototype = Object.assign( Object.create( Mesh.prototype ), { } // In case of infospots - if ( object instanceof Infospot ) { + if (object instanceof Infospot) { invertedObject = object; - if ( object.dispatchEvent ) { + if (object.dispatchEvent) { const { container } = this; - if ( container ) { object.dispatchEvent( { type: 'panolens-container', container } ); } - - object.dispatchEvent( { type: 'panolens-infospot-focus', method: function ( vector, duration, easing ) { + if (container) { object.dispatchEvent({ type: 'panolens-container', container }); } - /** - * Infospot focus handler event - * @type {object} - * @event Panorama#panolens-viewer-handler - * @property {string} method - Viewer function name - * @property {*} data - The argument to be passed into the method - */ - this.dispatchEvent( { type: 'panolens-viewer-handler', method: 'tweenControlCenter', data: [ vector, duration, easing ] } ); + object.dispatchEvent({ + type: 'panolens-infospot-focus', method: function (vector, duration, easing) { + /** + * Infospot focus handler event + * @type {object} + * @event Panorama#panolens-viewer-handler + * @property {string} method - Viewer function name + * @property {*} data - The argument to be passed into the method + */ + this.dispatchEvent({ type: 'panolens-viewer-handler', method: 'tweenControlCenter', data: [vector, duration, easing] }); - }.bind( this ) } ); + + }.bind(this) + }); } } else { // Counter scale.x = -1 effect - invertedObject = new Object3D(); + invertedObject = new THREE.Object3D(); invertedObject.scale.x = -1; invertedObject.scalePlaceHolder = true; - invertedObject.add( object ); + invertedObject.add(object); } - Object3D.prototype.add.call( this, invertedObject ); + THREE.Object3D.prototype.add.call(this, invertedObject); - }, + } - load: function () { + load() { this.onLoad(); - - }, + + } /** * Click event handler @@ -3966,24 +3961,24 @@ Panorama.prototype = Object.assign( Object.create( Mesh.prototype ), { * @instance * @fires Infospot#dismiss */ - onClick: function ( event ) { + onClick(event) { - if ( event.intersects && event.intersects.length === 0 ) { + if (event.intersects && event.intersects.length === 0) { - this.traverse( function ( object ) { + this.traverse(function (object) { /** * Dimiss event * @type {object} * @event Infospot#dismiss */ - object.dispatchEvent( { type: 'dismiss' } ); + object.dispatchEvent({ type: 'dismiss' }); - } ); + }); } - }, + } /** * Set container of this panorama @@ -3992,25 +3987,25 @@ Panorama.prototype = Object.assign( Object.create( Mesh.prototype ), { * @instance * @fires Infospot#panolens-container */ - setContainer: function ( data ) { + setContainer(data) { let container; - if ( data instanceof HTMLElement ) { + if (data instanceof HTMLElement) { container = data; - } else if ( data && data.container ) { + } else if (data && data.container) { container = data.container; } - if ( container ) { + if (container) { - this.children.forEach( function ( child ) { + this.children.forEach(function (child) { - if ( child instanceof Infospot && child.dispatchEvent ) { + if (child instanceof Infospot && child.dispatchEvent) { /** * Set container event @@ -4018,17 +4013,17 @@ Panorama.prototype = Object.assign( Object.create( Mesh.prototype ), { * @event Infospot#panolens-container * @property {HTMLElement} container - The container of this panorama */ - child.dispatchEvent( { type: 'panolens-container', container: container } ); + child.dispatchEvent({ type: 'panolens-container', container: container }); } - } ); + }); this.container = container; } - }, + } /** * This will be called when panorama is loaded @@ -4036,7 +4031,7 @@ Panorama.prototype = Object.assign( Object.create( Mesh.prototype ), { * @instance * @fires Panorama#load */ - onLoad: function () { + onLoad() { this.loaded = true; @@ -4045,9 +4040,9 @@ Panorama.prototype = Object.assign( Object.create( Mesh.prototype ), { * @type {object} * @event Panorama#load */ - this.dispatchEvent( { type: 'load' } ); + this.dispatchEvent({ type: 'load' }); - }, + } /** * This will be called when panorama is in progress @@ -4055,7 +4050,7 @@ Panorama.prototype = Object.assign( Object.create( Mesh.prototype ), { * @instance * @fires Panorama#progress */ - onProgress: function ( progress ) { + onProgress(progress) { /** * Loading panorama progress event @@ -4063,26 +4058,25 @@ Panorama.prototype = Object.assign( Object.create( Mesh.prototype ), { * @event Panorama#progress * @property {object} progress - The progress object containing loaded and total amount */ - this.dispatchEvent( { type: 'progress', progress: progress } ); - - }, + this.dispatchEvent({ type: 'progress', progress: progress }); + } /** * This will be called when panorama loading has error * @memberOf Panorama * @instance * @fires Panorama#error */ - onError: function () { + onError() { /** * Loading panorama error event * @type {object} * @event Panorama#error */ - this.dispatchEvent( { type: 'error' } ); + this.dispatchEvent({ type: 'error' }); - }, + } /** * Get zoom level based on window width @@ -4090,23 +4084,23 @@ Panorama.prototype = Object.assign( Object.create( Mesh.prototype ), { * @instance * @return {number} zoom level indicating image quality */ - getZoomLevel: function () { + getZoomLevel() { let zoomLevel; - if ( window.innerWidth <= 800 ) { + if (window.innerWidth <= 800) { zoomLevel = this.ImageQualityFair; - } else if ( window.innerWidth > 800 && window.innerWidth <= 1280 ) { + } else if (window.innerWidth > 800 && window.innerWidth <= 1280) { zoomLevel = this.ImageQualityMedium; - } else if ( window.innerWidth > 1280 && window.innerWidth <= 1920 ) { + } else if (window.innerWidth > 1280 && window.innerWidth <= 1920) { zoomLevel = this.ImageQualityHigh; - } else if ( window.innerWidth > 1920 ) { + } else if (window.innerWidth > 1920) { zoomLevel = this.ImageQualitySuperHigh; @@ -4118,7 +4112,7 @@ Panorama.prototype = Object.assign( Object.create( Mesh.prototype ), { return zoomLevel; - }, + } /** * Update texture of a panorama @@ -4126,12 +4120,12 @@ Panorama.prototype = Object.assign( Object.create( Mesh.prototype ), { * @instance * @param {THREE.Texture} texture - Texture to be updated */ - updateTexture: function ( texture ) { + updateTexture(texture) { this.material.map = texture; this.material.needsUpdate = true; - }, + } /** * Toggle visibility of infospots in this panorama @@ -4141,45 +4135,45 @@ Panorama.prototype = Object.assign( Object.create( Mesh.prototype ), { * @instance * @fires Panorama#infospot-animation-complete */ - toggleInfospotVisibility: function ( isVisible, delay ) { + toggleInfospotVisibility(isVisible, delay) { - delay = ( delay !== undefined ) ? delay : 0; + delay = (delay !== undefined) ? delay : 0; - const visible = ( isVisible !== undefined ) ? isVisible : ( this.isInfospotVisible ? false : true ); + const visible = (isVisible !== undefined) ? isVisible : (this.isInfospotVisible ? false : true); - this.traverse( function ( object ) { + this.traverse(function (object) { - if ( object instanceof Infospot ) { + if (object instanceof Infospot) { - if ( visible ) { + if (visible) { - object.show( delay ); + object.show(delay); } else { - object.hide( delay ); + object.hide(delay); } } - } ); + }); this.isInfospotVisible = visible; // Animation complete event - this.infospotAnimation.onComplete( function () { + this.infospotAnimation.onComplete(function () { /** * Complete toggling infospot visibility * @event Panorama#infospot-animation-complete * @type {object} */ - this.dispatchEvent( { type: 'infospot-animation-complete', visible: visible } ); + this.dispatchEvent({ type: 'infospot-animation-complete', visible: visible }); - }.bind( this ) ).delay( delay ).start(); + }.bind(this)).delay(delay).start(); - }, + } /** * Set image of this panorama's linking infospot @@ -4188,12 +4182,12 @@ Panorama.prototype = Object.assign( Object.create( Mesh.prototype ), { * @param {string} url - Url to the image asset * @param {number} scale - Scale factor of the infospot */ - setLinkingImage: function ( url, scale ) { + setLinkingImage(url, scale) { this.linkingImageURL = url; this.linkingImageScale = scale; - }, + } /** * Link one-way panorama @@ -4204,26 +4198,26 @@ Panorama.prototype = Object.assign( Object.create( Mesh.prototype ), { * @memberOf Panorama * @instance */ - link: function ( pano, position, imageScale, imageSrc ) { + link(pano, position, imageScale, imageSrc) { let scale, img; this.visible = true; - if ( !position ) { + if (!position) { - console.warn( 'Please specify infospot position for linking' ); + console.warn('Please specify infospot position for linking'); return; } // Infospot scale - if ( imageScale !== undefined ) { + if (imageScale !== undefined) { scale = imageScale; - } else if ( pano.linkingImageScale !== undefined ) { + } else if (pano.linkingImageScale !== undefined) { scale = pano.linkingImageScale; @@ -4235,11 +4229,11 @@ Panorama.prototype = Object.assign( Object.create( Mesh.prototype ), { // Infospot image - if ( imageSrc ) { + if (imageSrc) { img = imageSrc; - } else if ( pano.linkingImageURL ) { + } else if (pano.linkingImageURL) { img = pano.linkingImageURL; @@ -4250,10 +4244,10 @@ Panorama.prototype = Object.assign( Object.create( Mesh.prototype ), { } // Creates a new infospot - const spot = new Infospot( scale, img ); - spot.position.copy( position ); + const spot = new Infospot(scale, img); + spot.position.copy(position); spot.toPanorama = pano; - spot.addEventListener( 'click', function () { + spot.addEventListener('click', function () { /** * Viewer handler event @@ -4262,29 +4256,29 @@ Panorama.prototype = Object.assign( Object.create( Mesh.prototype ), { * @property {string} method - Viewer function name * @property {*} data - The argument to be passed into the method */ - this.dispatchEvent( { type: 'panolens-viewer-handler', method: 'setPanorama', data: pano } ); + this.dispatchEvent({ type: 'panolens-viewer-handler', method: 'setPanorama', data: pano }); - }.bind( this ) ); + }.bind(this)); - this.linkedSpots.push( spot ); + this.linkedSpots.push(spot); - this.add( spot ); + this.add(spot); this.visible = false; - }, + } - reset: function () { + reset() { - this.children.length = 0; + this.children.length = 0; - }, + } - setupTransitions: function () { + setupTransitions() { - this.fadeInAnimation = new Tween.Tween( this.material ) - .easing( Tween.Easing.Quartic.Out ) - .onStart( function () { + this.fadeInAnimation = new Tween.Tween(this.material) + .easing(Tween.Easing.Quartic.Out) + .onStart(function () { this.visible = true; // this.material.visible = true; @@ -4294,13 +4288,13 @@ Panorama.prototype = Object.assign( Object.create( Mesh.prototype ), { * @event Panorama#enter-fade-start * @type {object} */ - this.dispatchEvent( { type: 'enter-fade-start' } ); + this.dispatchEvent({ type: 'enter-fade-start' }); - }.bind( this ) ); + }.bind(this)); - this.fadeOutAnimation = new Tween.Tween( this.material ) - .easing( Tween.Easing.Quartic.Out ) - .onComplete( function () { + this.fadeOutAnimation = new Tween.Tween(this.material) + .easing(Tween.Easing.Quartic.Out) + .onComplete(function () { this.visible = false; // this.material.visible = true; @@ -4310,39 +4304,38 @@ Panorama.prototype = Object.assign( Object.create( Mesh.prototype ), { * @event Panorama#leave-complete * @type {object} */ - this.dispatchEvent( { type: 'leave-complete' } ); + this.dispatchEvent({ type: 'leave-complete' }); - }.bind( this ) ); + }.bind(this)); - this.enterTransition = new Tween.Tween( this ) - .easing( Tween.Easing.Quartic.Out ) - .onComplete( function () { + this.enterTransition = new Tween.Tween(this) + .easing(Tween.Easing.Quartic.Out) + .onComplete(function () { /** * Enter panorama and animation complete event * @event Panorama#enter-complete * @type {object} */ - this.dispatchEvent( { type: 'enter-complete' } ); + this.dispatchEvent({ type: 'enter-complete' }); - }.bind ( this ) ) + }.bind(this)) .start(); - this.leaveTransition = new Tween.Tween( this ) - .easing( Tween.Easing.Quartic.Out ); - - }, + this.leaveTransition = new Tween.Tween(this) + .easing(Tween.Easing.Quartic.Out); - onFadeAnimationUpdate: function () { + } + onFadeAnimationUpdate() { const alpha = this.material.opacity; const { uniforms } = this.material; - if ( uniforms && uniforms.opacity ) { + if (uniforms && uniforms.opacity) { uniforms.opacity.value = alpha; } - }, + } /** * Start fading in animation @@ -4350,46 +4343,46 @@ Panorama.prototype = Object.assign( Object.create( Mesh.prototype ), { * @instance * @fires Panorama#enter-fade-complete */ - fadeIn: function ( duration ) { + fadeIn(duration) { duration = duration >= 0 ? duration : this.animationDuration; this.fadeOutAnimation.stop(); this.fadeInAnimation - .to( { opacity: 1 }, duration ) - .onUpdate( this.onFadeAnimationUpdate.bind( this ) ) - .onComplete( function () { + .to({ opacity: 1 }, duration) + .onUpdate(this.onFadeAnimationUpdate.bind(this)) + .onComplete(function () { - this.toggleInfospotVisibility( true, duration / 2 ); + this.toggleInfospotVisibility(true, duration / 2); /** * Enter panorama fade complete event * @event Panorama#enter-fade-complete * @type {object} */ - this.dispatchEvent( { type: 'enter-fade-complete' } ); + this.dispatchEvent({ type: 'enter-fade-complete' }); - }.bind( this ) ) + }.bind(this)) .start(); - }, + } /** * Start fading out animation * @memberOf Panorama * @instance */ - fadeOut: function ( duration ) { + fadeOut(duration) { duration = duration >= 0 ? duration : this.animationDuration; this.fadeInAnimation.stop(); this.fadeOutAnimation - .to( { opacity: 0 }, duration ) - .onUpdate( this.onFadeAnimationUpdate.bind( this ) ) + .to({ opacity: 0 }, duration) + .onUpdate(this.onFadeAnimationUpdate.bind(this)) .start(); - }, + } /** * This will be called when entering a panorama @@ -4398,33 +4391,33 @@ Panorama.prototype = Object.assign( Object.create( Mesh.prototype ), { * @fires Panorama#enter * @fires Panorama#enter-start */ - onEnter: function () { + onEnter() { const duration = this.animationDuration; this.leaveTransition.stop(); this.enterTransition - .to( {}, duration ) - .onStart( function () { + .to({}, duration) + .onStart(function () { /** * Enter panorama and animation starting event * @event Panorama#enter-start * @type {object} */ - this.dispatchEvent( { type: 'enter-start' } ); - - if ( this.loaded ) { + this.dispatchEvent({ type: 'enter-start' }); - this.fadeIn( duration ); + if (this.loaded) { + + this.fadeIn(duration); } else { this.load(); } - - }.bind( this ) ) + + }.bind(this)) .start(); /** @@ -4432,17 +4425,17 @@ Panorama.prototype = Object.assign( Object.create( Mesh.prototype ), { * @event Panorama#enter * @type {object} */ - this.dispatchEvent( { type: 'enter' } ); + this.dispatchEvent({ type: 'enter' }); - this.children.forEach( child => { + this.children.forEach(child => { - child.dispatchEvent( { type: 'panorama-enter' } ); + child.dispatchEvent({ type: 'panorama-enter' }); - } ); + }); this.active = true; - }, + } /** * This will be called when leaving a panorama @@ -4450,26 +4443,26 @@ Panorama.prototype = Object.assign( Object.create( Mesh.prototype ), { * @instance * @fires Panorama#leave */ - onLeave: function () { + onLeave() { const duration = this.animationDuration; this.enterTransition.stop(); this.leaveTransition - .to( {}, duration ) - .onStart( function () { + .to({}, duration) + .onStart(function () { /** * Leave panorama and animation starting event * @event Panorama#leave-start * @type {object} */ - this.dispatchEvent( { type: 'leave-start' } ); + this.dispatchEvent({ type: 'leave-start' }); - this.fadeOut( duration ); - this.toggleInfospotVisibility( false ); + this.fadeOut(duration); + this.toggleInfospotVisibility(false); - }.bind( this ) ) + }.bind(this)) .start(); /** @@ -4477,24 +4470,24 @@ Panorama.prototype = Object.assign( Object.create( Mesh.prototype ), { * @event Panorama#leave * @type {object} */ - this.dispatchEvent( { type: 'leave' } ); + this.dispatchEvent({ type: 'leave' }); - this.children.forEach( child => { + this.children.forEach(child => { - child.dispatchEvent( { type: 'panorama-leave' } ); + child.dispatchEvent({ type: 'panorama-leave' }); - } ); + }); this.active = false; - }, + } /** * Dispose panorama * @memberOf Panorama * @instance */ - dispose: function () { + dispose() { this.infospotAnimation.stop(); this.fadeInAnimation.stop(); @@ -4509,72 +4502,58 @@ Panorama.prototype = Object.assign( Object.create( Mesh.prototype ), { * @property {string} method - Viewer function name * @property {*} data - The argument to be passed into the method */ - this.dispatchEvent( { type: 'panolens-viewer-handler', method: 'onPanoramaDispose', data: this } ); + this.dispatchEvent({ type: 'panolens-viewer-handler', method: 'onPanoramaDispose', data: this }); // recursive disposal on 3d objects - function recursiveDispose ( object ) { + function recursiveDispose(object) { const { geometry, material } = object; - for ( var i = object.children.length - 1; i >= 0; i-- ) { + for (var i = object.children.length - 1; i >= 0; i--) { - recursiveDispose( object.children[i] ); - object.remove( object.children[i] ); + recursiveDispose(object.children[i]); + object.remove(object.children[i]); } - if ( object instanceof Infospot ) { + if (object instanceof Infospot) { object.dispose(); } - - if ( geometry ) { geometry.dispose(); object.geometry = null; } - if ( material ) { material.dispose(); object.material = null; } + + if (geometry) { geometry.dispose(); object.geometry = null; } + if (material) { material.dispose(); object.material = null; } } - recursiveDispose( this ); + recursiveDispose(this); - if ( this.parent ) { + if (this.parent) { - this.parent.remove( this ); + this.parent.remove(this); } - } - -} ); +} /** * @classdesc Equirectangular based image panorama * @constructor * @param {string} image - Image url or HTMLImageElement */ -function ImagePanorama ( image, _geometry, _material ) { - - const radius = 5000; - const geometry = _geometry || new SphereBufferGeometry( radius, 60, 40 ); - const material = _material || new MeshBasicMaterial( { opacity: 0, transparent: true } ); - - Panorama.call( this, geometry, material ); - - this.src = image; - this.radius = radius; - -} - -ImagePanorama.prototype = Object.assign( Object.create( Panorama.prototype ), { - - constructor: ImagePanorama, +class ImagePanorama extends Panorama { + constructor( image, _geometry, _material ) { + const radius = 5000; + const geometry = _geometry || new THREE.SphereBufferGeometry( radius, 60, 40 ); + const material = _material || new THREE.MeshBasicMaterial( { opacity: 0, transparent: true } ); + super(geometry, material); + + this.src = image; + this.radius = radius; + } - /** - * Load image asset - * @param {*} src - Url or image element - * @memberOf ImagePanorama - * @instance - */ - load: function ( src ) { + load ( src ) { src = src || this.src; @@ -4590,11 +4569,11 @@ ImagePanorama.prototype = Object.assign( Object.create( Panorama.prototype ), { } else if ( src instanceof HTMLImageElement ) { - this.onLoad( new Texture( src ) ); + this.onLoad( new THREE.Texture( src ) ); } - }, + } /** * This will be called when image is loaded @@ -4602,107 +4581,95 @@ ImagePanorama.prototype = Object.assign( Object.create( Panorama.prototype ), { * @memberOf ImagePanorama * @instance */ - onLoad: function ( texture ) { + onLoad( texture ) { - texture.minFilter = texture.magFilter = LinearFilter; + texture.minFilter = texture.magFilter = THREE.LinearFilter; texture.needsUpdate = true; - + this.updateTexture( texture ); window.requestAnimationFrame( Panorama.prototype.onLoad.bind( this ) ); - }, + } /** * Reset * @memberOf ImagePanorama * @instance */ - reset: function () { + reset() { Panorama.prototype.reset.call( this ); - }, + } /** * Dispose * @memberOf ImagePanorama * @instance */ - dispose: function () { + dispose() { const { material: { map } } = this; // Release cached image - Cache.remove( this.src ); + THREE.Cache.remove( this.src ); if ( map ) { map.dispose(); } Panorama.prototype.dispose.call( this ); } - -} ); +} /** * @classdesc Empty panorama * @constructor */ -function EmptyPanorama () { - - const geometry = new BufferGeometry(); - const material = new MeshBasicMaterial( { color: 0x000000, opacity: 0, transparent: true } ); - - geometry.addAttribute( 'position', new BufferAttribute( new Float32Array(), 1 ) ); - - Panorama.call( this, geometry, material ); - +class EmptyPanorama extends Panorama { + constructor() { + const geometry = new THREE.BufferGeometry(); + const material = new THREE.MeshBasicMaterial( { color: 0x000000, opacity: 0, transparent: true } ); + super(geometry, material); + geometry.setAttribute( 'position', new THREE.BufferAttribute( new Float32Array(), 1 ) ); + } } -EmptyPanorama.prototype = Object.assign( Object.create( Panorama.prototype ), { - - constructor: EmptyPanorama - -} ); - /** * @classdesc Cubemap-based panorama * @constructor * @param {array} images - Array of 6 urls to images, one for each side of the CubeTexture. The urls should be specified in the following order: pos-x, neg-x, pos-y, neg-y, pos-z, neg-z */ -function CubePanorama ( images = [] ){ +class CubePanorama extends Panorama { + constructor ( images = [] ) { - const edgeLength = 10000; - const shader = Object.assign( {}, ShaderLib[ 'cube' ] ); - const geometry = new BoxBufferGeometry( edgeLength, edgeLength, edgeLength ); - const material = new ShaderMaterial( { + const edgeLength = 10000; + const shader = Object.assign( {}, THREE.ShaderLib[ 'cube' ] ); + const geometry = new THREE.BoxBufferGeometry( edgeLength, edgeLength, edgeLength ); + const material = new THREE.ShaderMaterial( { - fragmentShader: shader.fragmentShader, - vertexShader: shader.vertexShader, - uniforms: shader.uniforms, - side: BackSide, - transparent: true - - } ); - - Panorama.call( this, geometry, material ); + fragmentShader: shader.fragmentShader, + vertexShader: shader.vertexShader, + uniforms: shader.uniforms, + side: THREE.BackSide, + transparent: true - this.images = images; - this.edgeLength = edgeLength; - this.material.uniforms.opacity.value = 0; + } ); -} + super(geometry, material); -CubePanorama.prototype = Object.assign( Object.create( Panorama.prototype ), { + this.images = images; + this.edgeLength = edgeLength; + this.material.uniforms.opacity.value = 0; - constructor: CubePanorama, + } /** * Load 6 images and bind listeners * @memberOf CubePanorama * @instance */ - load: function () { + load () { CubeTextureLoader.load( @@ -4714,7 +4681,7 @@ CubePanorama.prototype = Object.assign( Object.create( Panorama.prototype ), { ); - }, + } /** * This will be called when 6 textures are ready @@ -4722,26 +4689,26 @@ CubePanorama.prototype = Object.assign( Object.create( Panorama.prototype ), { * @memberOf CubePanorama * @instance */ - onLoad: function ( texture ) { + onLoad ( texture ) { this.material.uniforms[ 'tCube' ].value = texture; Panorama.prototype.onLoad.call( this ); - }, + } /** * Dispose * @memberOf CubePanorama * @instance */ - dispose: function () { + dispose () { const { value } = this.material.uniforms.tCube; - this.images.forEach( ( image ) => { Cache.remove( image ); } ); + this.images.forEach( ( image ) => { THREE.Cache.remove( image ); } ); - if ( value instanceof CubeTexture ) { + if ( value instanceof THREE.CubeTexture ) { value.dispose(); @@ -4750,33 +4717,24 @@ CubePanorama.prototype = Object.assign( Object.create( Panorama.prototype ), { Panorama.prototype.dispose.call( this ); } - -} ); +} /** * @classdesc Basic panorama with 6 pre-defined grid images * @constructor */ -function BasicPanorama () { - - const images = []; +class BasicPanorama extends CubePanorama { - for ( let i = 0; i < 6; i++ ) { - - images.push( DataImage.WhiteTile ); + constructor() { + super(); + const images = []; + for ( let i = 0; i < 6; i++ ) { + images.push( DataImage.WhiteTile ); + } } - - CubePanorama.call( this, images ); - } -BasicPanorama.prototype = Object.assign( Object.create( CubePanorama.prototype ), { - - constructor: BasicPanorama - -} ); - /** * @classdesc Video Panorama * @constructor @@ -4790,50 +4748,45 @@ BasicPanorama.prototype = Object.assign( Object.create( CubePanorama.prototype ) * @param {string} [options.crossOrigin="anonymous"] - Sets the cross-origin attribute for the video, which allows for cross-origin videos in some browsers (Firefox, Chrome). Set to either "anonymous" or "use-credentials". * @param {number} [radius=5000] - The minimum radius for this panoram */ -function VideoPanorama ( src, options = {} ) { - - const radius = 5000; - const geometry = new SphereBufferGeometry( radius, 60, 40 ); - const material = new MeshBasicMaterial( { opacity: 0, transparent: true } ); - - Panorama.call( this, geometry, material ); - - this.src = src; - - this.options = { - - videoElement: document.createElement( 'video' ), - loop: true, - muted: true, - autoplay: false, - playsinline: true, - crossOrigin: 'anonymous' - - }; - - Object.assign( this.options, options ); +class VideoPanorama extends Panorama { + + constructor( src, options = {} ) { + const radius = 5000; + const geometry = new THREE.SphereBufferGeometry( radius, 60, 40 ); + const material = new THREE.MeshBasicMaterial( { opacity: 0, transparent: true } ); + super(geometry, material); + + this.src = src; + + this.options = { + videoElement: document.createElement( 'video' ), + loop: true, + muted: true, + autoplay: false, + playsinline: true, + crossOrigin: 'anonymous' + }; - this.videoElement = this.options.videoElement; - this.videoProgress = 0; - this.radius = radius; + Object.assign( this.options, options ); - this.addEventListener( 'leave', this.pauseVideo.bind( this ) ); - this.addEventListener( 'enter-fade-start', this.resumeVideoProgress.bind( this ) ); - this.addEventListener( 'video-toggle', this.toggleVideo.bind( this ) ); - this.addEventListener( 'video-time', this.setVideoCurrentTime.bind( this ) ); + this.videoElement = this.options.videoElement; + this.videoProgress = 0; + this.radius = radius; -} -VideoPanorama.prototype = Object.assign( Object.create( Panorama.prototype ), { + this.addEventListener( 'leave', this.pauseVideo.bind( this ) ); + this.addEventListener( 'enter-fade-start', this.resumeVideoProgress.bind( this ) ); + this.addEventListener( 'video-toggle', this.toggleVideo.bind( this ) ); + this.addEventListener( 'video-time', this.setVideoCurrentTime.bind( this ) ); + } - constructor: VideoPanorama, - isMobile: function () { + isMobile () { let check = false; (function(a){if(/(android|bb\d+|meego).+mobile|avantgo|bada\/|blackberry|blazer|compal|elaine|fennec|hiptop|iemobile|ip(hone|od)|iris|kindle|lge |maemo|midp|mmp|mobile.+firefox|netfront|opera m(ob|in)i|palm( os)?|phone|p(ixi|re)\/|plucker|pocket|psp|series(4|6)0|symbian|treo|up\.(browser|link)|vodafone|wap|windows ce|xda|xiino/i.test(a)||/1207|6310|6590|3gso|4thp|50[1-6]i|770s|802s|a wa|abac|ac(er|oo|s\-)|ai(ko|rn)|al(av|ca|co)|amoi|an(ex|ny|yw)|aptu|ar(ch|go)|as(te|us)|attw|au(di|\-m|r |s )|avan|be(ck|ll|nq)|bi(lb|rd)|bl(ac|az)|br(e|v)w|bumb|bw\-(n|u)|c55\/|capi|ccwa|cdm\-|cell|chtm|cldc|cmd\-|co(mp|nd)|craw|da(it|ll|ng)|dbte|dc\-s|devi|dica|dmob|do(c|p)o|ds(12|\-d)|el(49|ai)|em(l2|ul)|er(ic|k0)|esl8|ez([4-7]0|os|wa|ze)|fetc|fly(\-|_)|g1 u|g560|gene|gf\-5|g\-mo|go(\.w|od)|gr(ad|un)|haie|hcit|hd\-(m|p|t)|hei\-|hi(pt|ta)|hp( i|ip)|hs\-c|ht(c(\-| |_|a|g|p|s|t)|tp)|hu(aw|tc)|i\-(20|go|ma)|i230|iac( |\-|\/)|ibro|idea|ig01|ikom|im1k|inno|ipaq|iris|ja(t|v)a|jbro|jemu|jigs|kddi|keji|kgt( |\/)|klon|kpt |kwc\-|kyo(c|k)|le(no|xi)|lg( g|\/(k|l|u)|50|54|\-[a-w])|libw|lynx|m1\-w|m3ga|m50\/|ma(te|ui|xo)|mc(01|21|ca)|m\-cr|me(rc|ri)|mi(o8|oa|ts)|mmef|mo(01|02|bi|de|do|t(\-| |o|v)|zz)|mt(50|p1|v )|mwbp|mywa|n10[0-2]|n20[2-3]|n30(0|2)|n50(0|2|5)|n7(0(0|1)|10)|ne((c|m)\-|on|tf|wf|wg|wt)|nok(6|i)|nzph|o2im|op(ti|wv)|oran|owg1|p800|pan(a|d|t)|pdxg|pg(13|\-([1-8]|c))|phil|pire|pl(ay|uc)|pn\-2|po(ck|rt|se)|prox|psio|pt\-g|qa\-a|qc(07|12|21|32|60|\-[2-7]|i\-)|qtek|r380|r600|raks|rim9|ro(ve|zo)|s55\/|sa(ge|ma|mm|ms|ny|va)|sc(01|h\-|oo|p\-)|sdk\/|se(c(\-|0|1)|47|mc|nd|ri)|sgh\-|shar|sie(\-|m)|sk\-0|sl(45|id)|sm(al|ar|b3|it|t5)|so(ft|ny)|sp(01|h\-|v\-|v )|sy(01|mb)|t2(18|50)|t6(00|10|18)|ta(gt|lk)|tcl\-|tdg\-|tel(i|m)|tim\-|t\-mo|to(pl|sh)|ts(70|m\-|m3|m5)|tx\-9|up(\.b|g1|si)|utst|v400|v750|veri|vi(rg|te)|vk(40|5[0-3]|\-v)|vm40|voda|vulc|vx(52|53|60|61|70|80|81|83|85|98)|w3c(\-| )|webc|whit|wi(g |nc|nw)|wmlb|wonu|x700|yas\-|your|zeto|zte\-/i.test(a.substr(0,4))) check = true;})( window.navigator.userAgent || window.navigator.vendor || window.opera ); return check; - }, + } /** * Load video panorama @@ -4841,7 +4794,7 @@ VideoPanorama.prototype = Object.assign( Object.create( Panorama.prototype ), { * @instance * @fires Panorama#panolens-viewer-handler */ - load: function () { + load () { const { muted, loop, autoplay, playsinline, crossOrigin } = this.options; const video = this.videoElement; @@ -4854,7 +4807,7 @@ VideoPanorama.prototype = Object.assign( Object.create( Panorama.prototype ), { video.playsinline = playsinline; video.crossOrigin = crossOrigin; video.muted = muted; - + if ( playsinline ) { video.setAttribute( 'playsinline', '' ); @@ -4904,7 +4857,7 @@ VideoPanorama.prototype = Object.assign( Object.create( Panorama.prototype ), { this.dispatchEvent( { type: 'panolens-viewer-handler', method: 'updateVideoPlayButton', data: true } ); } - + } const loaded = () => { @@ -4918,7 +4871,7 @@ VideoPanorama.prototype = Object.assign( Object.create( Panorama.prototype ), { }; window.requestAnimationFrame( loaded ); - + }; /** @@ -4947,7 +4900,7 @@ VideoPanorama.prototype = Object.assign( Object.create( Panorama.prototype ), { } video.addEventListener( 'loadeddata', onloadeddata.bind( this ) ); - + video.addEventListener( 'timeupdate', function () { this.videoProgress = video.duration >= 0 ? video.currentTime / video.duration : 0; @@ -4963,7 +4916,7 @@ VideoPanorama.prototype = Object.assign( Object.create( Panorama.prototype ), { }.bind( this ) ); video.addEventListener( 'ended', function () { - + if ( !loop ) { this.resetVideo(); @@ -4973,7 +4926,7 @@ VideoPanorama.prototype = Object.assign( Object.create( Panorama.prototype ), { }.bind( this ), false ); - }, + } /** * Set video texture @@ -4982,31 +4935,31 @@ VideoPanorama.prototype = Object.assign( Object.create( Panorama.prototype ), { * @param {HTMLVideoElement} video - The html5 video element * @fires Panorama#panolens-viewer-handler */ - setVideoTexture: function ( video ) { + setVideoTexture ( video ) { if ( !video ) return; - const videoTexture = new VideoTexture( video ); - videoTexture.minFilter = LinearFilter; - videoTexture.magFilter = LinearFilter; - videoTexture.format = RGBFormat; + const videoTexture = new THREE.VideoTexture( video ); + videoTexture.minFilter = THREE.LinearFilter; + videoTexture.magFilter = THREE.LinearFilter; + videoTexture.format = THREE.RGBFormat; this.updateTexture( videoTexture ); - - }, + + } /** * Reset * @memberOf VideoPanorama * @instance */ - reset: function () { + reset () { this.videoElement = undefined; Panorama.prototype.reset.call( this ); - }, + } /** * Check if video is paused @@ -5014,18 +4967,18 @@ VideoPanorama.prototype = Object.assign( Object.create( Panorama.prototype ), { * @instance * @return {boolean} - is video paused or not */ - isVideoPaused: function () { + isVideoPaused () { return this.videoElement.paused; - }, + } /** * Toggle video to play or pause * @memberOf VideoPanorama * @instance */ - toggleVideo: function () { + toggleVideo () { const video = this.videoElement; @@ -5033,7 +4986,7 @@ VideoPanorama.prototype = Object.assign( Object.create( Panorama.prototype ), { video[ video.paused ? 'play' : 'pause' ](); - }, + } /** * Set video currentTime @@ -5041,7 +4994,7 @@ VideoPanorama.prototype = Object.assign( Object.create( Panorama.prototype ), { * @instance * @param {object} event - Event contains percentage. Range from 0.0 to 1.0 */ - setVideoCurrentTime: function ( { percentage } ) { + setVideoCurrentTime ( { percentage } ) { const video = this.videoElement; @@ -5053,7 +5006,7 @@ VideoPanorama.prototype = Object.assign( Object.create( Panorama.prototype ), { } - }, + } /** * Play video @@ -5062,7 +5015,7 @@ VideoPanorama.prototype = Object.assign( Object.create( Panorama.prototype ), { * @fires VideoPanorama#play * @fires VideoPanorama#play-error */ - playVideo: function () { + playVideo () { const video = this.videoElement; const playVideo = this.playVideo.bind( this ); @@ -5099,7 +5052,7 @@ VideoPanorama.prototype = Object.assign( Object.create( Panorama.prototype ), { } - }, + } /** * Pause video @@ -5107,7 +5060,7 @@ VideoPanorama.prototype = Object.assign( Object.create( Panorama.prototype ), { * @instance * @fires VideoPanorama#pause */ - pauseVideo: function () { + pauseVideo () { const video = this.videoElement; @@ -5125,14 +5078,14 @@ VideoPanorama.prototype = Object.assign( Object.create( Panorama.prototype ), { */ this.dispatchEvent( { type: 'pause' } ); - }, + } /** * Resume video * @memberOf VideoPanorama * @instance */ - resumeVideoProgress: function () { + resumeVideoProgress () { const video = this.videoElement; @@ -5164,14 +5117,14 @@ VideoPanorama.prototype = Object.assign( Object.create( Panorama.prototype ), { this.setVideoCurrentTime( { percentage: this.videoProgress } ); - }, + } /** * Reset video at stating point * @memberOf VideoPanorama * @instance */ - resetVideo: function () { + resetVideo () { const video = this.videoElement; @@ -5181,7 +5134,7 @@ VideoPanorama.prototype = Object.assign( Object.create( Panorama.prototype ), { } - }, + } /** * Check if video is muted @@ -5189,18 +5142,18 @@ VideoPanorama.prototype = Object.assign( Object.create( Panorama.prototype ), { * @instance * @return {boolean} - is video muted or not */ - isVideoMuted: function () { + isVideoMuted () { return this.videoElement.muted; - }, + } /** * Mute video * @memberOf VideoPanorama * @instance */ - muteVideo: function () { + muteVideo () { const video = this.videoElement; @@ -5212,14 +5165,14 @@ VideoPanorama.prototype = Object.assign( Object.create( Panorama.prototype ), { this.dispatchEvent( { type: 'volumechange' } ); - }, + } /** * Unmute video * @memberOf VideoPanorama * @instance */ - unmuteVideo: function () { + unmuteVideo () { const video = this.videoElement; @@ -5231,7 +5184,7 @@ VideoPanorama.prototype = Object.assign( Object.create( Panorama.prototype ), { this.dispatchEvent( { type: 'volumechange' } ); - }, + } /** * Returns the video element @@ -5239,23 +5192,23 @@ VideoPanorama.prototype = Object.assign( Object.create( Panorama.prototype ), { * @instance * @returns {HTMLElement} */ - getVideoElement: function () { + getVideoElement () { return this.videoElement; - }, + } /** * Dispose video panorama * @memberOf VideoPanorama * @instance */ - dispose: function () { + dispose () { const { material: { map } } = this; this.pauseVideo(); - + this.removeEventListener( 'leave', this.pauseVideo.bind( this ) ); this.removeEventListener( 'enter-fade-start', this.resumeVideoProgress.bind( this ) ); this.removeEventListener( 'video-toggle', this.toggleVideo.bind( this ) ); @@ -5266,8 +5219,8 @@ VideoPanorama.prototype = Object.assign( Object.create( Panorama.prototype ), { Panorama.prototype.dispose.call( this ); } - -} ); + +} /** * @classdesc Google Street View Loader @@ -5521,23 +5474,18 @@ Object.assign( GoogleStreetviewLoader.prototype, { * @param {string} panoId - Panorama id from Google Streetview * @param {string} [apiKey] - Google Street View API Key */ -function GoogleStreetviewPanorama ( panoId, apiKey ) { - - ImagePanorama.call( this ); - - this.panoId = panoId; - - this.gsvLoader = null; - - this.loadRequested = false; - - this.setupGoogleMapAPI( apiKey ); - -} - -GoogleStreetviewPanorama.prototype = Object.assign( Object.create( ImagePanorama.prototype ), { +class GoogleStreetviewPanorama extends ImagePanorama { + + constructor( panoId, apiKey ) { + super(); + this.panoId = panoId; - constructor: GoogleStreetviewPanorama, + this.gsvLoader = null; + + this.loadRequested = false; + + this.setupGoogleMapAPI( apiKey ); + } /** * Load Google Street View by panorama id @@ -5545,114 +5493,113 @@ GoogleStreetviewPanorama.prototype = Object.assign( Object.create( ImagePanorama * @memberOf GoogleStreetviewPanorama * @instance */ - load: function ( panoId ) { + load ( panoId ) { this.loadRequested = true; - + panoId = ( panoId || this.panoId ) || {}; - + if ( panoId && this.gsvLoader ) { - + this.loadGSVLoader( panoId ); - + } - - }, - + + } + /** * Setup Google Map API * @param {string} apiKey * @memberOf GoogleStreetviewPanorama * @instance */ - setupGoogleMapAPI: function ( apiKey ) { - + setupGoogleMapAPI ( apiKey ) { + const script = document.createElement( 'script' ); script.src = 'https://maps.googleapis.com/maps/api/js?'; script.src += apiKey ? 'key=' + apiKey : ''; script.onreadystatechange = this.setGSVLoader.bind( this ); script.onload = this.setGSVLoader.bind( this ); - + document.querySelector( 'head' ).appendChild( script ); - - }, - + + } + /** * Set GSV Loader * @memberOf GoogleStreetviewPanorama * @instance */ - setGSVLoader: function () { - + setGSVLoader () { + this.gsvLoader = new GoogleStreetviewLoader(); - + if ( this.loadRequested ) { - + this.load(); - + } - - }, - + + } + /** * Get GSV Loader * @memberOf GoogleStreetviewPanorama * @instance * @return {GoogleStreetviewLoader} GSV Loader instance */ - getGSVLoader: function () { - + getGSVLoader () { + return this.gsvLoader; - - }, - + + } + /** * Load GSV Loader * @param {string} panoId - Gogogle Street View panorama id * @memberOf GoogleStreetviewPanorama * @instance */ - loadGSVLoader: function ( panoId ) { - + loadGSVLoader ( panoId ) { + this.loadRequested = false; - + this.gsvLoader.onProgress = this.onProgress.bind( this ); - + this.gsvLoader.onPanoramaLoad = this.onLoad.bind( this ); - + this.gsvLoader.setZoom( this.getZoomLevel() ); - + this.gsvLoader.load( panoId ); - + this.gsvLoader.loaded = true; - }, - + } + /** * This will be called when panorama is loaded * @param {HTMLCanvasElement} canvas - Canvas where the tiles have been drawn * @memberOf GoogleStreetviewPanorama * @instance */ - onLoad: function ( canvas ) { - - ImagePanorama.prototype.onLoad.call( this, new Texture( canvas ) ); - - }, - + onLoad ( canvas ) { + + ImagePanorama.prototype.onLoad.call( this, new THREE.Texture( canvas ) ); + + } + /** * Reset * @memberOf GoogleStreetviewPanorama * @instance */ - reset: function () { - + reset () { + this.gsvLoader = undefined; - + ImagePanorama.prototype.reset.call( this ); - + } - -} ); +} /** * Stereographic projection shader @@ -5676,9 +5623,9 @@ const StereographicShader = { uniforms: { - 'tDiffuse': { value: new Texture() }, + 'tDiffuse': { value: new THREE.Texture() }, 'resolution': { value: 1.0 }, - 'transform': { value: new Matrix4() }, + 'transform': { value: new THREE.Matrix4() }, 'zoom': { value: 1.0 }, 'opacity': { value: 1.0 } @@ -5743,42 +5690,38 @@ const StereographicShader = { * @param {number} [size=10000] - Size of plane geometry * @param {number} [ratio=0.5] - Ratio of plane geometry's height against width */ -function LittlePlanet ( type = 'image', source, size = 10000, ratio = 0.5 ) { - - if ( type === 'image' ) { - - ImagePanorama.call( this, source, this.createGeometry( size, ratio ), this.createMaterial( size ) ); - - } - - this.size = size; - this.ratio = ratio; - this.EPS = 0.000001; - this.frameId = null; - - this.dragging = false; - this.userMouse = new Vector2(); - - this.quatA = new Quaternion(); - this.quatB = new Quaternion(); - this.quatCur = new Quaternion(); - this.quatSlerp = new Quaternion(); +class LittlePlanet extends ImagePanorama { + constructor( type = 'image', source, size = 10000, ratio = 0.5 ) { + if ( type === 'image' ) { + super(source, LittlePlanet.createGeometry( size, ratio ), LittlePlanet.createMaterial( size ) ); + } + else { + super(); + } - this.vectorX = new Vector3( 1, 0, 0 ); - this.vectorY = new Vector3( 0, 1, 0 ); + this.size = size; + this.ratio = ratio; + this.EPS = 0.000001; + this.frameId = null; - this.addEventListener( 'window-resize', this.onWindowResize ); + this.dragging = false; + this.userMouse = new THREE.Vector2(); -} + this.quatA = new THREE.Quaternion(); + this.quatB = new THREE.Quaternion(); + this.quatCur = new THREE.Quaternion(); + this.quatSlerp = new THREE.Quaternion(); -LittlePlanet.prototype = Object.assign( Object.create( ImagePanorama.prototype ), { + this.vectorX = new THREE.Vector3( 1, 0, 0 ); + this.vectorY = new THREE.Vector3( 0, 1, 0 ); - constructor: LittlePlanet, + this.addEventListener( 'window-resize', this.onWindowResize ); + } - add: function ( object ) { + add ( object ) { if ( arguments.length > 1 ) { - + for ( let i = 0; i < arguments.length; i ++ ) { this.add( arguments[ i ] ); @@ -5792,39 +5735,39 @@ LittlePlanet.prototype = Object.assign( Object.create( ImagePanorama.prototype ) if ( object instanceof Infospot ) { object.material.depthTest = false; - + } ImagePanorama.prototype.add.call( this, object ); - }, + } - createGeometry: function ( size, ratio ) { + static createGeometry ( size, ratio ) { - return new PlaneBufferGeometry( size, size * ratio ); + return new THREE.PlaneBufferGeometry( size, size * ratio ); - }, + } - createMaterial: function ( size ) { + static createMaterial ( size ) { const shader = Object.assign( {}, StereographicShader ), uniforms = shader.uniforms; uniforms.zoom.value = size; uniforms.opacity.value = 0.0; - return new ShaderMaterial( { + return new THREE.ShaderMaterial( { uniforms: uniforms, vertexShader: shader.vertexShader, fragmentShader: shader.fragmentShader, - side: BackSide, + side: THREE.BackSide, transparent: true } ); - - }, - registerMouseEvents: function () { + } + + registerMouseEvents () { this.container.addEventListener( 'mousedown', this.onMouseDown.bind( this ), { passive: true } ); this.container.addEventListener( 'mousemove', this.onMouseMove.bind( this ), { passive: true } ); @@ -5835,10 +5778,10 @@ LittlePlanet.prototype = Object.assign( Object.create( ImagePanorama.prototype ) this.container.addEventListener( 'mousewheel', this.onMouseWheel.bind( this ), { passive: false } ); this.container.addEventListener( 'DOMMouseScroll', this.onMouseWheel.bind( this ), { passive: false } ); this.container.addEventListener( 'contextmenu', this.onContextMenu.bind( this ), { passive: true } ); - - }, - unregisterMouseEvents: function () { + } + + unregisterMouseEvents () { this.container.removeEventListener( 'mousedown', this.onMouseDown.bind( this ), false ); this.container.removeEventListener( 'mousemove', this.onMouseMove.bind( this ), false ); @@ -5849,10 +5792,10 @@ LittlePlanet.prototype = Object.assign( Object.create( ImagePanorama.prototype ) this.container.removeEventListener( 'mousewheel', this.onMouseWheel.bind( this ), false ); this.container.removeEventListener( 'DOMMouseScroll', this.onMouseWheel.bind( this ), false ); this.container.removeEventListener( 'contextmenu', this.onContextMenu.bind( this ), false ); - - }, - onMouseDown: function ( event ) { + } + + onMouseDown ( event ) { const inputCount = ( event.touches && event.touches.length ) || 1 ; @@ -5877,17 +5820,13 @@ LittlePlanet.prototype = Object.assign( Object.create( ImagePanorama.prototype ) break; - default: - - break; - } this.onUpdateCallback(); - }, + } - onMouseMove: function ( event ) { + onMouseMove ( event ) { const inputCount = ( event.touches && event.touches.length ) || 1 ; @@ -5898,8 +5837,8 @@ LittlePlanet.prototype = Object.assign( Object.create( ImagePanorama.prototype ) const x = ( event.clientX >= 0 ) ? event.clientX : event.touches[ 0 ].clientX; const y = ( event.clientY >= 0 ) ? event.clientY : event.touches[ 0 ].clientY; - const angleX = Math$1.degToRad( x - this.userMouse.x ) * 0.4; - const angleY = Math$1.degToRad( y - this.userMouse.y ) * 0.4; + const angleX = THREE.Math.degToRad( x - this.userMouse.x ) * 0.4; + const angleY = THREE.Math.degToRad( y - this.userMouse.y ) * 0.4; if ( this.dragging ) { this.quatA.setFromAxisAngle( this.vectorY, angleX ); @@ -5920,21 +5859,17 @@ LittlePlanet.prototype = Object.assign( Object.create( ImagePanorama.prototype ) break; - default: - - break; - } - }, + } - onMouseUp: function () { + onMouseUp () { this.dragging = false; - }, + } - onMouseWheel: function ( event ) { + onMouseWheel ( event ) { event.preventDefault(); event.stopPropagation(); @@ -5954,9 +5889,9 @@ LittlePlanet.prototype = Object.assign( Object.create( ImagePanorama.prototype ) this.addZoomDelta( delta ); this.onUpdateCallback(); - }, + } - addZoomDelta: function ( delta ) { + addZoomDelta ( delta ) { const uniforms = this.material.uniforms; const lowerBound = this.size * 0.1; @@ -5973,10 +5908,9 @@ LittlePlanet.prototype = Object.assign( Object.create( ImagePanorama.prototype ) uniforms.zoom.value = upperBound; } + } - }, - - onUpdateCallback: function () { + onUpdateCallback () { this.frameId = window.requestAnimationFrame( this.onUpdateCallback.bind( this ) ); @@ -5987,37 +5921,37 @@ LittlePlanet.prototype = Object.assign( Object.create( ImagePanorama.prototype ) this.material.uniforms.transform.value.makeRotationFromQuaternion( this.quatSlerp ); } - + if ( !this.dragging && 1.0 - this.quatSlerp.clone().dot( this.quatCur ) < this.EPS ) { - + window.cancelAnimationFrame( this.frameId ); } - }, + } - reset: function () { + reset () { this.quatCur.set( 0, 0, 0, 1 ); this.quatSlerp.set( 0, 0, 0, 1 ); this.onUpdateCallback(); - }, + } - onLoad: function ( texture ) { + onLoad ( texture ) { this.material.uniforms.resolution.value = this.container.clientWidth / this.container.clientHeight; this.registerMouseEvents(); this.onUpdateCallback(); - + this.dispatchEvent( { type: 'panolens-viewer-handler', method: 'disableControl' } ); ImagePanorama.prototype.onLoad.call( this, texture ); - - }, - onLeave: function () { + } + + onLeave () { this.unregisterMouseEvents(); @@ -6026,22 +5960,20 @@ LittlePlanet.prototype = Object.assign( Object.create( ImagePanorama.prototype ) window.cancelAnimationFrame( this.frameId ); ImagePanorama.prototype.onLeave.call( this ); - - }, - onWindowResize: function () { + } + onWindowResize () { this.material.uniforms.resolution.value = this.container.clientWidth / this.container.clientHeight; + } - }, - - onContextMenu: function () { + onContextMenu () { this.dragging = false; - }, + } - dispose: function () { + dispose () { this.unregisterMouseEvents(); @@ -6049,7 +5981,9 @@ LittlePlanet.prototype = Object.assign( Object.create( ImagePanorama.prototype ) } -}); + + +} /** * @classdesc Image Little Planet @@ -6058,15 +5992,11 @@ LittlePlanet.prototype = Object.assign( Object.create( ImagePanorama.prototype ) * @param {number} [size=10000] - Size of plane geometry * @param {number} [ratio=0.5] - Ratio of plane geometry's height against width */ -function ImageLittlePlanet ( source, size, ratio ) { - - LittlePlanet.call( this, 'image', source, size, ratio ); - -} - -ImageLittlePlanet.prototype = Object.assign( Object.create( LittlePlanet.prototype ), { +class ImageLittlePlanet extends LittlePlanet { + constructor( source, size, ratio ) { + super(source, size, ratio); + } - constructor: ImageLittlePlanet, /** * On loaded with texture @@ -6074,34 +6004,33 @@ ImageLittlePlanet.prototype = Object.assign( Object.create( LittlePlanet.prototy * @memberOf ImageLittlePlanet * @instance */ - onLoad: function ( texture ) { + onLoad ( texture ) { this.updateTexture( texture ); LittlePlanet.prototype.onLoad.call( this, texture ); - - }, - + } + /** * Update texture * @param {THREE.Texture} texture * @memberOf ImageLittlePlanet * @instance */ - updateTexture: function ( texture ) { + updateTexture ( texture ) { - texture.minFilter = texture.magFilter = LinearFilter; - + texture.minFilter = texture.magFilter = THREE.LinearFilter; + this.material.uniforms[ 'tDiffuse' ].value = texture; - }, + } /** * Dispose * @memberOf ImageLittlePlanet * @instance */ - dispose: function () { + dispose () { const tDiffuse = this.material.uniforms[ 'tDiffuse' ]; @@ -6114,8 +6043,7 @@ ImageLittlePlanet.prototype = Object.assign( Object.create( LittlePlanet.prototy LittlePlanet.prototype.dispose.call( this ); } - -} ); +} /** * @classdesc Camera panorama @@ -6123,27 +6051,23 @@ ImageLittlePlanet.prototype = Object.assign( Object.create( LittlePlanet.prototy * @param {object} - camera constraints * @constructor */ -function CameraPanorama ( constraints ) { - - const radius = 5000; - const geometry = new SphereBufferGeometry( radius, 60, 40 ); - const material = new MeshBasicMaterial( { visible: false }); - - Panorama.call( this, geometry, material ); - - this.media = new Media( constraints ); - this.radius = radius; - - this.addEventListener( 'enter', this.start.bind( this ) ); - this.addEventListener( 'leave', this.stop.bind( this ) ); - this.addEventListener( 'panolens-container', this.onPanolensContainer.bind( this ) ); - this.addEventListener( 'panolens-scene', this.onPanolensScene.bind( this ) ); +class CameraPanorama extends Panorama { + constructor( constraints ) { + const radius = 5000; + const geometry = new THREE.SphereBufferGeometry( radius, 60, 40 ); + const material = new THREE.MeshBasicMaterial( { visible: false }); + + super(geometry, material); -} + this.media = new Media( constraints ); + this.radius = radius; -CameraPanorama.prototype = Object.assign( Object.create( Panorama.prototype ), { + this.addEventListener( 'enter', this.start.bind( this ) ); + this.addEventListener( 'leave', this.stop.bind( this ) ); + this.addEventListener( 'panolens-container', this.onPanolensContainer.bind( this ) ); + this.addEventListener( 'panolens-scene', this.onPanolensScene.bind( this ) ); - constructor: CameraPanorama, + } /** * On container event @@ -6151,11 +6075,9 @@ CameraPanorama.prototype = Object.assign( Object.create( Panorama.prototype ), { * @memberOf CameraPanorama * @instance */ - onPanolensContainer: function ( { container } ) { - + onPanolensContainer ( { container } ) { this.media.setContainer( container ); - - }, + } /** * On scene event @@ -6163,11 +6085,9 @@ CameraPanorama.prototype = Object.assign( Object.create( Panorama.prototype ), { * @memberOf CameraPanorama * @instance */ - onPanolensScene: function ( { scene } ) { - + onPanolensScene( { scene } ) { this.media.setScene( scene ); - - }, + } /** * Start camera streaming @@ -6175,24 +6095,19 @@ CameraPanorama.prototype = Object.assign( Object.create( Panorama.prototype ), { * @instance * @returns {Promise} */ - start: function () { - + start() { return this.media.start(); - - }, + } /** * Stop camera streaming * @memberOf CameraPanorama * @instance */ - stop: function () { - + stop() { this.media.stop(); - - }, - -} ); + } +} /** * @classdesc Orbit Controls @@ -6216,7 +6131,7 @@ function OrbitControls ( object, domElement ) { * "target" sets the location of focus, where the control orbits around * and where it pans with respect to. */ - this.target = new Vector3(); + this.target = new THREE.Vector3(); // center is old, deprecated; use "target" instead this.center = this.target; @@ -6227,6 +6142,7 @@ function OrbitControls ( object, domElement ) { */ this.noZoom = false; this.zoomSpeed = 1.0; + this.revertZoomScrollDirection = false; // Limits to how far you can dolly in and out ( PerspectiveCamera only ) this.minDistance = 0; @@ -6278,7 +6194,7 @@ function OrbitControls ( object, domElement ) { this.keys = { LEFT: 37, UP: 38, RIGHT: 39, BOTTOM: 40 }; // Mouse buttons - this.mouseButtons = { ORBIT: MOUSE.LEFT, ZOOM: MOUSE.MIDDLE, PAN: MOUSE.RIGHT }; + this.mouseButtons = { ORBIT: THREE.MOUSE.LEFT, ZOOM: THREE.MOUSE.MIDDLE, PAN: THREE.MOUSE.RIGHT }; /* * ////////// @@ -6290,30 +6206,30 @@ function OrbitControls ( object, domElement ) { var EPS = 10e-8; var MEPS = 10e-5; - var rotateStart = new Vector2(); - var rotateEnd = new Vector2(); - var rotateDelta = new Vector2(); + var rotateStart = new THREE.Vector2(); + var rotateEnd = new THREE.Vector2(); + var rotateDelta = new THREE.Vector2(); - var panStart = new Vector2(); - var panEnd = new Vector2(); - var panDelta = new Vector2(); - var panOffset = new Vector3(); + var panStart = new THREE.Vector2(); + var panEnd = new THREE.Vector2(); + var panDelta = new THREE.Vector2(); + var panOffset = new THREE.Vector3(); - var offset = new Vector3(); + var offset = new THREE.Vector3(); - var dollyStart = new Vector2(); - var dollyEnd = new Vector2(); - var dollyDelta = new Vector2(); + var dollyStart = new THREE.Vector2(); + var dollyEnd = new THREE.Vector2(); + var dollyDelta = new THREE.Vector2(); var theta = 0; var phi = 0; var phiDelta = 0; var thetaDelta = 0; var scale = 1; - var pan = new Vector3(); + var pan = new THREE.Vector3(); - var lastPosition = new Vector3(); - var lastQuaternion = new Quaternion(); + var lastPosition = new THREE.Vector3(); + var lastQuaternion = new THREE.Quaternion(); var momentumLeft = 0, momentumUp = 0; var eventPrevious; @@ -6333,8 +6249,8 @@ function OrbitControls ( object, domElement ) { // so camera.up is the orbit axis - var quat = new Quaternion().setFromUnitVectors( object.up, new Vector3( 0, 1, 0 ) ); - var quatInverse = quat.clone().inverse(); + var quat = new THREE.Quaternion().setFromUnitVectors( object.up, new THREE.Vector3( 0, 1, 0 ) ); + var quatInverse = quat.clone().invert(); // events @@ -6410,7 +6326,7 @@ function OrbitControls ( object, domElement ) { var element = scope.domElement === document ? scope.domElement.body : scope.domElement; - if ( scope.object instanceof PerspectiveCamera ) { + if ( scope.object instanceof THREE.PerspectiveCamera ) { // perspective var position = scope.object.position; @@ -6424,7 +6340,7 @@ function OrbitControls ( object, domElement ) { scope.panLeft( 2 * deltaX * targetDistance / element.clientHeight ); scope.panUp( 2 * deltaY * targetDistance / element.clientHeight ); - } else if ( scope.object instanceof OrthographicCamera ) { + } else if ( scope.object instanceof THREE.OrthographicCamera ) { // orthographic scope.panLeft( deltaX * (scope.object.right - scope.object.left) / element.clientWidth ); @@ -6465,11 +6381,11 @@ function OrbitControls ( object, domElement ) { } - if ( scope.object instanceof PerspectiveCamera ) { + if ( scope.object instanceof THREE.PerspectiveCamera ) { scale /= dollyScale; - } else if ( scope.object instanceof OrthographicCamera ) { + } else if ( scope.object instanceof THREE.OrthographicCamera ) { scope.object.zoom = Math.max( this.minZoom, Math.min( this.maxZoom, this.object.zoom * dollyScale ) ); scope.object.updateProjectionMatrix(); @@ -6491,11 +6407,11 @@ function OrbitControls ( object, domElement ) { } - if ( scope.object instanceof PerspectiveCamera ) { + if ( scope.object instanceof THREE.PerspectiveCamera ) { scale *= dollyScale; - } else if ( scope.object instanceof OrthographicCamera ) { + } else if ( scope.object instanceof THREE.OrthographicCamera ) { scope.object.zoom = Math.max( this.minZoom, Math.min( this.maxZoom, this.object.zoom / dollyScale ) ); scope.object.updateProjectionMatrix(); @@ -6768,8 +6684,10 @@ function OrbitControls ( object, domElement ) { delta = - event.detail; } + const zoomOut = delta > 0; + const zoomIn = delta < 0; - if ( delta > 0 ) { + if ( !scope.revertZoomScrollDirection ? zoomOut : !zoomOut ) { // scope.dollyOut(); scope.object.fov = ( scope.object.fov < scope.maxFov ) @@ -6777,7 +6695,7 @@ function OrbitControls ( object, domElement ) { : scope.maxFov; scope.object.updateProjectionMatrix(); - } else if ( delta < 0 ) { + } else if ( !scope.revertZoomScrollDirection ? zoomIn : !zoomIn ) { // scope.dollyIn(); scope.object.fov = ( scope.object.fov > scope.minFov ) @@ -7047,7 +6965,7 @@ function OrbitControls ( object, domElement ) { this.update(); } -OrbitControls.prototype = Object.assign( Object.create( EventDispatcher.prototype ), { +OrbitControls.prototype = Object.assign( Object.create( THREE.EventDispatcher.prototype ), { constructor: OrbitControls @@ -7110,8 +7028,8 @@ function DeviceOrientationControls ( camera, domElement ) { event.preventDefault(); event.stopPropagation(); - rotY += Math$1.degToRad( ( event.touches[ 0 ].pageX - tempX ) / 4 ); - rotX += Math$1.degToRad( ( tempY - event.touches[ 0 ].pageY ) / 4 ); + rotY += THREE.Math.degToRad( ( event.touches[ 0 ].pageX - tempX ) / 4 ); + rotX += THREE.Math.degToRad( ( tempY - event.touches[ 0 ].pageY ) / 4 ); scope.updateAlphaOffsetAngle( rotY ); @@ -7124,36 +7042,36 @@ function DeviceOrientationControls ( camera, domElement ) { var setCameraQuaternion = function( quaternion, alpha, beta, gamma, orient ) { - var zee = new Vector3( 0, 0, 1 ); + var zee = new THREE.Vector3( 0, 0, 1 ); - var euler = new Euler(); + var euler = new THREE.Euler(); - var q0 = new Quaternion(); + var q0 = new THREE.Quaternion(); - var q1 = new Quaternion( - Math.sqrt( 0.5 ), 0, 0, Math.sqrt( 0.5 ) ); // - PI/2 around the x-axis + var q1 = new THREE.Quaternion( - Math.sqrt( 0.5 ), 0, 0, Math.sqrt( 0.5 ) ); // - PI/2 around the x-axis var vectorFingerY; - var fingerQY = new Quaternion(); - var fingerQX = new Quaternion(); + var fingerQY = new THREE.Quaternion(); + var fingerQX = new THREE.Quaternion(); if ( scope.screenOrientation == 0 ) { - vectorFingerY = new Vector3( 1, 0, 0 ); + vectorFingerY = new THREE.Vector3( 1, 0, 0 ); fingerQY.setFromAxisAngle( vectorFingerY, -rotX ); } else if ( scope.screenOrientation == 180 ) { - vectorFingerY = new Vector3( 1, 0, 0 ); + vectorFingerY = new THREE.Vector3( 1, 0, 0 ); fingerQY.setFromAxisAngle( vectorFingerY, rotX ); } else if ( scope.screenOrientation == 90 ) { - vectorFingerY = new Vector3( 0, 1, 0 ); + vectorFingerY = new THREE.Vector3( 0, 1, 0 ); fingerQY.setFromAxisAngle( vectorFingerY, rotX ); } else if ( scope.screenOrientation == - 90) { - vectorFingerY = new Vector3( 0, 1, 0 ); + vectorFingerY = new THREE.Vector3( 0, 1, 0 ); fingerQY.setFromAxisAngle( vectorFingerY, -rotX ); } @@ -7203,10 +7121,10 @@ function DeviceOrientationControls ( camera, domElement ) { if ( scope.enabled === false ) return; - var alpha = scope.deviceOrientation.alpha ? Math$1.degToRad( scope.deviceOrientation.alpha ) + scope.alphaOffsetAngle : 0; // Z - var beta = scope.deviceOrientation.beta ? Math$1.degToRad( scope.deviceOrientation.beta ) : 0; // X' - var gamma = scope.deviceOrientation.gamma ? Math$1.degToRad( scope.deviceOrientation.gamma ) : 0; // Y'' - var orient = scope.screenOrientation ? Math$1.degToRad( scope.screenOrientation ) : 0; // O + var alpha = scope.deviceOrientation.alpha ? THREE.Math.degToRad( scope.deviceOrientation.alpha ) + scope.alphaOffsetAngle : 0; // Z + var beta = scope.deviceOrientation.beta ? THREE.Math.degToRad( scope.deviceOrientation.beta ) : 0; // X' + var gamma = scope.deviceOrientation.gamma ? THREE.Math.degToRad( scope.deviceOrientation.gamma ) : 0; // Y'' + var orient = scope.screenOrientation ? THREE.Math.degToRad( scope.screenOrientation ) : 0; // O setCameraQuaternion( scope.camera.quaternion, alpha, beta, gamma, orient ); scope.alpha = alpha; @@ -7231,7 +7149,7 @@ function DeviceOrientationControls ( camera, domElement ) { this.connect(); } -DeviceOrientationControls.prototype = Object.assign( Object.create( EventDispatcher.prototype), { +DeviceOrientationControls.prototype = Object.assign( Object.create( THREE.EventDispatcher.prototype), { constructor: DeviceOrientationControls @@ -7243,117 +7161,118 @@ DeviceOrientationControls.prototype = Object.assign( Object.create( EventDispatc * @external CardboardEffect * @param {THREE.WebGLRenderer} renderer */ -function CardboardEffect ( renderer ) { - - var _camera = new OrthographicCamera( - 1, 1, 1, - 1, 0, 1 ); - - var _scene = new Scene(); - - var _stereo = new StereoCamera(); - _stereo.aspect = 0.5; - - var _params = { minFilter: LinearFilter, magFilter: NearestFilter, format: RGBAFormat }; - - var _renderTarget = new WebGLRenderTarget( 512, 512, _params ); - _renderTarget.scissorTest = true; - _renderTarget.texture.generateMipmaps = false; - - /* - * Distortion Mesh ported from: - * https://github.com/borismus/webvr-boilerplate/blob/master/src/distortion/barrel-distortion-fragment.js - */ - - var distortion = new Vector2( 0.441, 0.156 ); - - var geometry = new PlaneBufferGeometry( 1, 1, 10, 20 ).removeAttribute( 'normal' ).toNonIndexed(); - - var positions = geometry.attributes.position.array; - var uvs = geometry.attributes.uv.array; - - // duplicate - geometry.attributes.position.count *= 2; - geometry.attributes.uv.count *= 2; - - var positions2 = new Float32Array( positions.length * 2 ); - positions2.set( positions ); - positions2.set( positions, positions.length ); - - var uvs2 = new Float32Array( uvs.length * 2 ); - uvs2.set( uvs ); - uvs2.set( uvs, uvs.length ); - - var vector = new Vector2(); - var length = positions.length / 3; - - for ( var i = 0, l = positions2.length / 3; i < l; i ++ ) { - - vector.x = positions2[ i * 3 + 0 ]; - vector.y = positions2[ i * 3 + 1 ]; - - var dot = vector.dot( vector ); - var scalar = 1.5 + ( distortion.x + distortion.y * dot ) * dot; - - var offset = i < length ? 0 : 1; - - positions2[ i * 3 + 0 ] = ( vector.x / scalar ) * 1.5 - 0.5 + offset; - positions2[ i * 3 + 1 ] = ( vector.y / scalar ) * 3.0; - - uvs2[ i * 2 ] = ( uvs2[ i * 2 ] + offset ) * 0.5; - +class CardboardEffect { + + constructor( renderer ) { + var _camera = new THREE.OrthographicCamera( - 1, 1, 1, - 1, 0, 1 ); + + var _scene = new THREE.Scene(); + + var _stereo = new THREE.StereoCamera(); + _stereo.aspect = 0.5; + + var _params = { minFilter: THREE.LinearFilter, magFilter: THREE.NearestFilter, format: THREE.RGBAFormat }; + + var _renderTarget = new THREE.WebGLRenderTarget( 512, 512, _params ); + _renderTarget.scissorTest = true; + _renderTarget.texture.generateMipmaps = false; + + /* + * Distortion Mesh ported from: + * https://github.com/borismus/webvr-boilerplate/blob/master/src/distortion/barrel-distortion-fragment.js + */ + + var distortion = new THREE.Vector2( 0.441, 0.156 ); + + var geometry = new THREE.PlaneBufferGeometry( 1, 1, 10, 20 ).removeAttribute( 'normal' ).toNonIndexed(); + + var positions = geometry.attributes.position.array; + var uvs = geometry.attributes.uv.array; + + // duplicate + geometry.attributes.position.count *= 2; + geometry.attributes.uv.count *= 2; + + var positions2 = new Float32Array( positions.length * 2 ); + positions2.set( positions ); + positions2.set( positions, positions.length ); + + var uvs2 = new Float32Array( uvs.length * 2 ); + uvs2.set( uvs ); + uvs2.set( uvs, uvs.length ); + + var vector = new THREE.Vector2(); + var length = positions.length / 3; + + for ( var i = 0, l = positions2.length / 3; i < l; i ++ ) { + + vector.x = positions2[ i * 3 + 0 ]; + vector.y = positions2[ i * 3 + 1 ]; + + var dot = vector.dot( vector ); + var scalar = 1.5 + ( distortion.x + distortion.y * dot ) * dot; + + var offset = i < length ? 0 : 1; + + positions2[ i * 3 + 0 ] = ( vector.x / scalar ) * 1.5 - 0.5 + offset; + positions2[ i * 3 + 1 ] = ( vector.y / scalar ) * 3.0; + + uvs2[ i * 2 ] = ( uvs2[ i * 2 ] + offset ) * 0.5; + + } + + geometry.attributes.position.array = positions2; + geometry.attributes.uv.array = uvs2; + + // + + var material = new THREE.MeshBasicMaterial( { map: _renderTarget.texture } ); + var mesh = new THREE.Mesh( geometry, material ); + _scene.add( mesh ); + + // + + this.setSize = function ( width, height ) { + + renderer.setSize( width, height ); + + var pixelRatio = renderer.getPixelRatio(); + + _renderTarget.setSize( width * pixelRatio, height * pixelRatio ); + + }; + + this.render = function ( scene, camera ) { + + scene.updateMatrixWorld(); + + if ( camera.parent === null ) camera.updateMatrixWorld(); + + _stereo.update( camera ); + + var width = _renderTarget.width / 2; + var height = _renderTarget.height; + + if ( renderer.autoClear ) renderer.clear(); + + _renderTarget.scissor.set( 0, 0, width, height ); + _renderTarget.viewport.set( 0, 0, width, height ); + renderer.setRenderTarget( _renderTarget ); + renderer.render( scene, _stereo.cameraL ); + + renderer.clearDepth(); + + _renderTarget.scissor.set( width, 0, width, height ); + _renderTarget.viewport.set( width, 0, width, height ); + renderer.setRenderTarget( _renderTarget ); + renderer.render( scene, _stereo.cameraR ); + + renderer.clearDepth(); + + renderer.setRenderTarget( null ); + renderer.render( _scene, _camera ); + }; } - - geometry.attributes.position.array = positions2; - geometry.attributes.uv.array = uvs2; - - // - - var material = new MeshBasicMaterial( { map: _renderTarget.texture } ); - var mesh = new Mesh( geometry, material ); - _scene.add( mesh ); - - // - - this.setSize = function ( width, height ) { - - renderer.setSize( width, height ); - - var pixelRatio = renderer.getPixelRatio(); - - _renderTarget.setSize( width * pixelRatio, height * pixelRatio ); - - }; - - this.render = function ( scene, camera ) { - - scene.updateMatrixWorld(); - - if ( camera.parent === null ) camera.updateMatrixWorld(); - - _stereo.update( camera ); - - var width = _renderTarget.width / 2; - var height = _renderTarget.height; - - if ( renderer.autoClear ) renderer.clear(); - - _renderTarget.scissor.set( 0, 0, width, height ); - _renderTarget.viewport.set( 0, 0, width, height ); - renderer.setRenderTarget( _renderTarget ); - renderer.render( scene, _stereo.cameraL ); - - renderer.clearDepth(); - - _renderTarget.scissor.set( width, 0, width, height ); - _renderTarget.viewport.set( width, 0, width, height ); - renderer.setRenderTarget( _renderTarget ); - renderer.render( scene, _stereo.cameraR ); - - renderer.clearDepth(); - - renderer.setRenderTarget( null ); - renderer.render( _scene, _camera ); - }; - } /** @@ -7362,50 +7281,51 @@ function CardboardEffect ( renderer ) { * @external StereoEffect * @param {THREE.WebGLRenderer} renderer */ -const StereoEffect = function ( renderer ) { - - var _stereo = new StereoCamera(); - _stereo.aspect = 0.5; - var size = new Vector2(); - - this.setEyeSeparation = function ( eyeSep ) { +class StereoEffect { + constructor ( renderer ) { + var _stereo = new THREE.StereoCamera(); + _stereo.aspect = 0.5; + var size = new THREE.Vector2(); - _stereo.eyeSep = eyeSep; + this.setEyeSeparation = function ( eyeSep ) { - }; + _stereo.eyeSep = eyeSep; - this.setSize = function ( width, height ) { + }; - renderer.setSize( width, height ); + this.setSize = function ( width, height ) { - }; + renderer.setSize( width, height ); - this.render = function ( scene, camera ) { + }; - scene.updateMatrixWorld(); + this.render = function ( scene, camera ) { - if ( camera.parent === null ) camera.updateMatrixWorld(); + scene.updateMatrixWorld(); - _stereo.update( camera ); + if ( camera.parent === null ) camera.updateMatrixWorld(); - renderer.getSize( size ); + _stereo.update( camera ); - if ( renderer.autoClear ) renderer.clear(); - renderer.setScissorTest( true ); + renderer.getSize( size ); - renderer.setScissor( 0, 0, size.width / 2, size.height ); - renderer.setViewport( 0, 0, size.width / 2, size.height ); - renderer.render( scene, _stereo.cameraL ); + if ( renderer.autoClear ) renderer.clear(); + renderer.setScissorTest( true ); - renderer.setScissor( size.width / 2, 0, size.width / 2, size.height ); - renderer.setViewport( size.width / 2, 0, size.width / 2, size.height ); - renderer.render( scene, _stereo.cameraR ); + renderer.setScissor( 0, 0, size.width / 2, size.height ); + renderer.setViewport( 0, 0, size.width / 2, size.height ); + renderer.render( scene, _stereo.cameraL ); - renderer.setScissorTest( false ); + renderer.setScissor( size.width / 2, 0, size.width / 2, size.height ); + renderer.setViewport( size.width / 2, 0, size.width / 2, size.height ); + renderer.render( scene, _stereo.cameraR ); - }; + renderer.setScissorTest( false ); -}; + }; + } + +} /** * @classdesc Viewer contains pre-defined scene, camera and renderer @@ -7433,377 +7353,374 @@ const StereoEffect = function ( renderer ) { * @param {number} [options.autoRotateSpeed=2.0] - Auto rotate speed as in degree per second. Positive is counter-clockwise and negative is clockwise. * @param {number} [options.autoRotateActivationDuration=5000] - Duration before auto rotatation when no user interactivity in ms */ -function Viewer ( options ) { - - let container; - - options = options || {}; - options.controlBar = options.controlBar !== undefined ? options.controlBar : true; - options.controlButtons = options.controlButtons || [ 'fullscreen', 'setting', 'video' ]; - options.autoHideControlBar = options.autoHideControlBar !== undefined ? options.autoHideControlBar : false; - options.autoHideInfospot = options.autoHideInfospot !== undefined ? options.autoHideInfospot : true; - options.horizontalView = options.horizontalView !== undefined ? options.horizontalView : false; - options.clickTolerance = options.clickTolerance || 10; - options.cameraFov = options.cameraFov || 60; - options.reverseDragging = options.reverseDragging || false; - options.enableReticle = options.enableReticle || false; - options.dwellTime = options.dwellTime || 1500; - options.autoReticleSelect = options.autoReticleSelect !== undefined ? options.autoReticleSelect : true; - options.viewIndicator = options.viewIndicator !== undefined ? options.viewIndicator : false; - options.indicatorSize = options.indicatorSize || 30; - options.output = options.output ? options.output : 'none'; - options.autoRotate = options.autoRotate || false; - options.autoRotateSpeed = options.autoRotateSpeed || 2.0; - options.autoRotateActivationDuration = options.autoRotateActivationDuration || 5000; - - this.options = options; - - /* - * CSS Icon - * const styleLoader = new StyleLoader(); - * styleLoader.inject( 'icono' ); - */ - - // Container - if ( options.container ) { - - container = options.container; - container._width = container.clientWidth; - container._height = container.clientHeight; - - } else { - - container = document.createElement( 'div' ); - container.classList.add( 'panolens-container' ); - container.style.width = '100%'; - container.style.height = '100%'; - container._width = window.innerWidth; - container._height = window.innerHeight; - document.body.appendChild( container ); +class Viewer extends THREE.EventDispatcher { + constructor( options ) { + super(); + let container; + options = options || {}; + options.controlBar = options.controlBar !== undefined ? options.controlBar : true; + options.controlButtons = options.controlButtons || [ 'fullscreen', 'setting', 'video' ]; + options.autoHideControlBar = options.autoHideControlBar !== undefined ? options.autoHideControlBar : false; + options.autoHideInfospot = options.autoHideInfospot !== undefined ? options.autoHideInfospot : true; + options.horizontalView = options.horizontalView !== undefined ? options.horizontalView : false; + options.clickTolerance = options.clickTolerance || 10; + options.cameraFov = options.cameraFov || 60; + options.reverseDragging = options.reverseDragging || false; + options.enableReticle = options.enableReticle || false; + options.dwellTime = options.dwellTime || 1500; + options.autoReticleSelect = options.autoReticleSelect !== undefined ? options.autoReticleSelect : true; + options.viewIndicator = options.viewIndicator !== undefined ? options.viewIndicator : false; + options.indicatorSize = options.indicatorSize || 30; + options.output = options.output ? options.output : 'none'; + options.autoRotate = options.autoRotate || false; + options.autoRotateSpeed = options.autoRotateSpeed || 2.0; + options.autoRotateActivationDuration = options.autoRotateActivationDuration || 5000; + + this.options = options; + + /* + * CSS Icon + * const styleLoader = new StyleLoader(); + * styleLoader.inject( 'icono' ); + */ + + // Container + if ( options.container ) { + + container = options.container; + container._width = container.clientWidth; + container._height = container.clientHeight; + + } else { + + container = document.createElement( 'div' ); + container.classList.add( 'panolens-container' ); + container.style.width = '100%'; + container.style.height = '100%'; + container._width = window.innerWidth; + container._height = window.innerHeight; + document.body.appendChild( container ); + + } + + this.container = container; + + this.camera = options.camera || new THREE.PerspectiveCamera( this.options.cameraFov, this.container.clientWidth / this.container.clientHeight, 1, 10000 ); + this.scene = options.scene || new THREE.Scene(); + this.renderer = options.renderer || new THREE.WebGLRenderer( { alpha: true, antialias: false } ); + this.sceneReticle = new THREE.Scene(); + + this.viewIndicatorSize = this.options.indicatorSize; + + this.reticle = {}; + this.tempEnableReticle = this.options.enableReticle; + + this.mode = MODES.NORMAL; + + this.panorama = null; + this.widget = null; + + this.hoverObject = null; + this.infospot = null; + this.pressEntityObject = null; + this.pressObject = null; + + this.raycaster = new THREE.Raycaster(); + this.raycasterPoint = new THREE.Vector2(); + this.userMouse = new THREE.Vector2(); + this.updateCallbacks = []; + this.requestAnimationId = null; + + this.cameraFrustum = new THREE.Frustum(); + this.cameraViewProjectionMatrix = new THREE.Matrix4(); + + this.autoRotateRequestId = null; + + this.outputDivElement = null; + + this.touchSupported = 'ontouchstart' in window || window.DocumentTouch && document instanceof DocumentTouch; + + // Handler references + this.HANDLER_MOUSE_DOWN = this.onMouseDown.bind( this ); + this.HANDLER_MOUSE_UP = this.onMouseUp.bind( this ); + this.HANDLER_MOUSE_MOVE = this.onMouseMove.bind( this ); + this.HANDLER_WINDOW_RESIZE = this.onWindowResize.bind( this ); + this.HANDLER_KEY_DOWN = this.onKeyDown.bind( this ); + this.HANDLER_KEY_UP = this.onKeyUp.bind( this ); + this.HANDLER_TAP = this.onTap.bind( this, { + clientX: this.container.clientWidth / 2, + clientY: this.container.clientHeight / 2 + } ); + + // Flag for infospot output + this.OUTPUT_INFOSPOT = false; + + // Animations + this.tweenLeftAnimation = new Tween.Tween(); + this.tweenUpAnimation = new Tween.Tween(); + + // Renderer + this.renderer.setPixelRatio( window.devicePixelRatio ); + this.renderer.setSize( this.container.clientWidth, this.container.clientHeight ); + this.renderer.setClearColor( 0x000000, 0 ); + this.renderer.autoClear = false; + + // Append Renderer Element to container + this.renderer.domElement.classList.add( 'panolens-canvas' ); + this.renderer.domElement.style.display = 'block'; + this.container.style.backgroundColor = '#000'; + this.container.appendChild( this.renderer.domElement ); + + // Camera Controls + this.OrbitControls = new OrbitControls( this.camera, this.container ); + this.OrbitControls.id = 'orbit'; + this.OrbitControls.minDistance = 1; + this.OrbitControls.noPan = true; + this.OrbitControls.autoRotate = this.options.autoRotate; + this.OrbitControls.autoRotateSpeed = this.options.autoRotateSpeed; + + this.DeviceOrientationControls = new DeviceOrientationControls( this.camera, this.container ); + this.DeviceOrientationControls.id = 'device-orientation'; + this.DeviceOrientationControls.enabled = false; + this.camera.position.z = 1; + + // Register change event if passiveRenering + if ( this.options.passiveRendering ) { + + console.warn( 'passiveRendering is now deprecated' ); + + } + + // Controls + this.controls = [ this.OrbitControls, this.DeviceOrientationControls ]; + this.control = this.OrbitControls; + + // Cardboard effect + this.CardboardEffect = new CardboardEffect( this.renderer ); + this.CardboardEffect.setSize( this.container.clientWidth, this.container.clientHeight ); + + // Stereo effect + this.StereoEffect = new StereoEffect( this.renderer ); + this.StereoEffect.setSize( this.container.clientWidth, this.container.clientHeight ); + + this.effect = this.CardboardEffect; + + // Add default hidden reticle + this.addReticle(); + + // Lock horizontal view + if ( this.options.horizontalView ) { + this.OrbitControls.minPolarAngle = Math.PI / 2; + this.OrbitControls.maxPolarAngle = Math.PI / 2; + } + + // Add Control UI + if ( this.options.controlBar !== false ) { + this.addDefaultControlBar( this.options.controlButtons ); + } + + // Add View Indicator + if ( this.options.viewIndicator ) { + this.addViewIndicator(); + } + + // Reverse dragging direction + if ( this.options.reverseDragging ) { + this.reverseDraggingDirection(); + } + + // Register event if reticle is enabled, otherwise defaults to mouse + if ( this.options.enableReticle ) { + this.enableReticleControl(); + } else { + this.registerMouseAndTouchEvents(); + } + + // Output infospot position to an overlay container if specified + if ( this.options.output === 'overlay' ) { + this.addOutputElement(); + } + + // Register dom event listeners + this.registerEventListeners(); + + // Animate + this.animate.call( this ); } - - this.container = container; - - this.camera = options.camera || new PerspectiveCamera( this.options.cameraFov, this.container.clientWidth / this.container.clientHeight, 1, 10000 ); - this.scene = options.scene || new Scene(); - this.renderer = options.renderer || new WebGLRenderer( { alpha: true, antialias: false } ); - this.sceneReticle = new Scene(); - - this.viewIndicatorSize = this.options.indicatorSize; - - this.reticle = {}; - this.tempEnableReticle = this.options.enableReticle; - - this.mode = MODES.NORMAL; - - this.panorama = null; - this.widget = null; - - this.hoverObject = null; - this.infospot = null; - this.pressEntityObject = null; - this.pressObject = null; - - this.raycaster = new Raycaster(); - this.raycasterPoint = new Vector2(); - this.userMouse = new Vector2(); - this.updateCallbacks = []; - this.requestAnimationId = null; - - this.cameraFrustum = new Frustum(); - this.cameraViewProjectionMatrix = new Matrix4(); - - this.autoRotateRequestId = null; - - this.outputDivElement = null; - - this.touchSupported = 'ontouchstart' in window || window.DocumentTouch && document instanceof DocumentTouch; - - // Handler references - this.HANDLER_MOUSE_DOWN = this.onMouseDown.bind( this ); - this.HANDLER_MOUSE_UP = this.onMouseUp.bind( this ); - this.HANDLER_MOUSE_MOVE = this.onMouseMove.bind( this ); - this.HANDLER_WINDOW_RESIZE = this.onWindowResize.bind( this ); - this.HANDLER_KEY_DOWN = this.onKeyDown.bind( this ); - this.HANDLER_KEY_UP = this.onKeyUp.bind( this ); - this.HANDLER_TAP = this.onTap.bind( this, { - clientX: this.container.clientWidth / 2, - clientY: this.container.clientHeight / 2 - } ); - - // Flag for infospot output - this.OUTPUT_INFOSPOT = false; - - // Animations - this.tweenLeftAnimation = new Tween.Tween(); - this.tweenUpAnimation = new Tween.Tween(); - - // Renderer - this.renderer.setPixelRatio( window.devicePixelRatio ); - this.renderer.setSize( this.container.clientWidth, this.container.clientHeight ); - this.renderer.setClearColor( 0x000000, 0 ); - this.renderer.autoClear = false; - - // Append Renderer Element to container - this.renderer.domElement.classList.add( 'panolens-canvas' ); - this.renderer.domElement.style.display = 'block'; - this.container.style.backgroundColor = '#000'; - this.container.appendChild( this.renderer.domElement ); - - // Camera Controls - this.OrbitControls = new OrbitControls( this.camera, this.container ); - this.OrbitControls.id = 'orbit'; - this.OrbitControls.minDistance = 1; - this.OrbitControls.noPan = true; - this.OrbitControls.autoRotate = this.options.autoRotate; - this.OrbitControls.autoRotateSpeed = this.options.autoRotateSpeed; - - this.DeviceOrientationControls = new DeviceOrientationControls( this.camera, this.container ); - this.DeviceOrientationControls.id = 'device-orientation'; - this.DeviceOrientationControls.enabled = false; - this.camera.position.z = 1; - - // Register change event if passiveRenering - if ( this.options.passiveRendering ) { - - console.warn( 'passiveRendering is now deprecated' ); - - } - - // Controls - this.controls = [ this.OrbitControls, this.DeviceOrientationControls ]; - this.control = this.OrbitControls; - - // Cardboard effect - this.CardboardEffect = new CardboardEffect( this.renderer ); - this.CardboardEffect.setSize( this.container.clientWidth, this.container.clientHeight ); - - // Stereo effect - this.StereoEffect = new StereoEffect( this.renderer ); - this.StereoEffect.setSize( this.container.clientWidth, this.container.clientHeight ); - - this.effect = this.CardboardEffect; - - // Add default hidden reticle - this.addReticle(); - - // Lock horizontal view - if ( this.options.horizontalView ) { - this.OrbitControls.minPolarAngle = Math.PI / 2; - this.OrbitControls.maxPolarAngle = Math.PI / 2; - } - - // Add Control UI - if ( this.options.controlBar !== false ) { - this.addDefaultControlBar( this.options.controlButtons ); - } - - // Add View Indicator - if ( this.options.viewIndicator ) { - this.addViewIndicator(); - } - - // Reverse dragging direction - if ( this.options.reverseDragging ) { - this.reverseDraggingDirection(); - } - - // Register event if reticle is enabled, otherwise defaults to mouse - if ( this.options.enableReticle ) { - this.enableReticleControl(); - } else { - this.registerMouseAndTouchEvents(); - } - - // Output infospot position to an overlay container if specified - if ( this.options.output === 'overlay' ) { - this.addOutputElement(); - } - - // Register dom event listeners - this.registerEventListeners(); - - // Animate - this.animate.call( this ); - -} -Viewer.prototype = Object.assign( Object.create( EventDispatcher.prototype ), { - - constructor: Viewer, - - /** - * Add an object to the scene - * Automatically hookup with panolens-viewer-handler listener - * to communicate with viewer method - * @param {THREE.Object3D} object - The object to be added - * @memberOf Viewer - * @instance - */ - add: function ( object ) { + + /** + * Add an object to the scene + * Automatically hookup with panolens-viewer-handler listener + * to communicate with viewer method + * @param {THREE.Object3D} object - The object to be added + * @memberOf Viewer + * @instance + */ + add ( object ) { if ( arguments.length > 1 ) { - + for ( let i = 0; i < arguments.length; i ++ ) { - + this.add( arguments[ i ] ); - + } - + return this; - + } - + this.scene.add( object ); - + // All object added to scene has 'panolens-viewer-handler' event to handle viewer communication if ( object.addEventListener ) { - + object.addEventListener( 'panolens-viewer-handler', this.eventHandler.bind( this ) ); - + } - + // All object added to scene being passed with container if ( object instanceof Panorama && object.dispatchEvent ) { - + object.dispatchEvent( { type: 'panolens-container', container: this.container } ); - + } - + if ( object instanceof CameraPanorama ) { - + object.dispatchEvent( { type: 'panolens-scene', scene: this.scene } ); - + } - + // Hookup default panorama event listeners if ( object.type === 'panorama' ) { - + this.addPanoramaEventListener( object ); - + if ( !this.panorama ) { - + this.setPanorama( object ); - + } - + } - - }, - + + } + /** * Remove an object from the scene * @param {THREE.Object3D} object - Object to be removed * @memberOf Viewer * @instance */ - remove: function ( object ) { - + remove ( object ) { + if ( object.removeEventListener ) { - + object.removeEventListener( 'panolens-viewer-handler', this.eventHandler.bind( this ) ); - + } - + this.scene.remove( object ); - - }, - + + } + /** * Add default control bar * @param {array} array - The control buttons array * @memberOf Viewer * @instance */ - addDefaultControlBar: function ( array ) { - + addDefaultControlBar ( array ) { + if ( this.widget ) { - + console.warn( 'Default control bar exists' ); return; - + } - + const widget = new Widget( this.container ); widget.addEventListener( 'panolens-viewer-handler', this.eventHandler.bind( this ) ); widget.addControlBar(); array.forEach( buttonName => { - + widget.addControlButton( buttonName ); - + } ); - + this.widget = widget; - - }, - + + } + /** * Set a panorama to be the current one * @param {Panorama} pano - Panorama to be set * @memberOf Viewer * @instance */ - setPanorama: function ( pano ) { - + setPanorama ( pano ) { + const leavingPanorama = this.panorama; - + if ( pano.type === 'panorama' && leavingPanorama !== pano ) { - + // Clear exisiting infospot this.hideInfospot(); - + const afterEnterComplete = function () { - + if ( leavingPanorama ) { leavingPanorama.onLeave(); } pano.removeEventListener( 'enter-fade-start', afterEnterComplete ); - + }; - + pano.addEventListener( 'enter-fade-start', afterEnterComplete ); - + // Assign and enter panorama (this.panorama = pano).onEnter(); - + } - - }, - + + } + /** * Event handler to execute commands from child objects * @param {object} event - The dispatched event with method as function name and data as an argument * @memberOf Viewer * @instance */ - eventHandler: function ( event ) { - + eventHandler ( event ) { + if ( event.method && this[ event.method ] ) { - + this[ event.method ]( event.data ); - + } - - }, - + + } + /** * Dispatch event to all descendants * @param {object} event - Event to be passed along * @memberOf Viewer * @instance */ - dispatchEventToChildren: function ( event ) { - + dispatchEventToChildren ( event ) { + this.scene.traverse( function ( object ) { - + if ( object.dispatchEvent ) { - + object.dispatchEvent( event ); - + } - + }); - - }, - + + } + /** * Set widget content * @method activateWidgetItem @@ -7812,114 +7729,115 @@ Viewer.prototype = Object.assign( Object.create( EventDispatcher.prototype ), { * @memberOf Viewer * @instance */ - activateWidgetItem: function ( controlIndex, mode ) { + activateWidgetItem ( controlIndex, mode ) { + if (!this.widget) return; const mainMenu = this.widget.mainMenu; const ControlMenuItem = mainMenu.children[ 0 ]; const ModeMenuItem = mainMenu.children[ 1 ]; - + let item; - + if ( controlIndex !== undefined ) { - + switch ( controlIndex ) { - + case 0: - + item = ControlMenuItem.subMenu.children[ 1 ]; - + break; - + case 1: - + item = ControlMenuItem.subMenu.children[ 2 ]; - + break; - + default: - + item = ControlMenuItem.subMenu.children[ 1 ]; - + break; - + } - + ControlMenuItem.subMenu.setActiveItem( item ); ControlMenuItem.setSelectionTitle( item.textContent ); - + } - + if ( mode !== undefined ) { - + switch( mode ) { - + case MODES.CARDBOARD: - + item = ModeMenuItem.subMenu.children[ 2 ]; - + break; - + case MODES.STEREO: - + item = ModeMenuItem.subMenu.children[ 3 ]; - + break; - + default: - + item = ModeMenuItem.subMenu.children[ 1 ]; - + break; } - + ModeMenuItem.subMenu.setActiveItem( item ); ModeMenuItem.setSelectionTitle( item.textContent ); - + } - - }, - + + } + /** * Enable rendering effect * @param {MODES} mode - Modes for effects * @memberOf Viewer * @instance */ - enableEffect: function ( mode ) { - + enableEffect ( mode ) { + if ( this.mode === mode ) { return; } if ( mode === MODES.NORMAL ) { this.disableEffect(); return; } else { this.mode = mode; } - + const fov = this.camera.fov; - + switch( mode ) { - + case MODES.CARDBOARD: - + this.effect = this.CardboardEffect; this.enableReticleControl(); - + break; - + case MODES.STEREO: - + this.effect = this.StereoEffect; this.enableReticleControl(); - + break; - + default: - + this.effect = null; this.disableReticleControl(); - + break; - + } - + this.activateWidgetItem( undefined, this.mode ); - + /** * Dual eye effect event * @type {object} @@ -7927,13 +7845,13 @@ Viewer.prototype = Object.assign( Object.create( EventDispatcher.prototype ), { * @property {MODES} mode - Current display mode */ this.dispatchEventToChildren( { type: 'panolens-dual-eye-effect', mode: this.mode } ); - + // Force effect stereo camera to update by refreshing fov this.camera.fov = fov + 10e-3; this.effect.setSize( this.container.clientWidth, this.container.clientHeight ); this.render(); this.camera.fov = fov; - + /** * Dispatch mode change event * @type {object} @@ -7941,23 +7859,23 @@ Viewer.prototype = Object.assign( Object.create( EventDispatcher.prototype ), { * @property {MODES} mode - Current display mode */ this.dispatchEvent( { type: 'mode-change', mode: this.mode } ); - - }, - + + } + /** * Disable additional rendering effect * @memberOf Viewer * @instance */ - disableEffect: function () { - + disableEffect () { + if ( this.mode === MODES.NORMAL ) { return; } - + this.mode = MODES.NORMAL; this.disableReticleControl(); - + this.activateWidgetItem( undefined, this.mode ); - + /** * Dual eye effect event * @type {object} @@ -7965,10 +7883,10 @@ Viewer.prototype = Object.assign( Object.create( EventDispatcher.prototype ), { * @property {MODES} mode - Current display mode */ this.dispatchEventToChildren( { type: 'panolens-dual-eye-effect', mode: this.mode } ); - + this.renderer.setSize( this.container.clientWidth, this.container.clientHeight ); this.render(); - + /** * Dispatch mode change event * @type {object} @@ -7976,76 +7894,75 @@ Viewer.prototype = Object.assign( Object.create( EventDispatcher.prototype ), { * @property {MODES} mode - Current display mode */ this.dispatchEvent( { type: 'mode-change', mode: this.mode } ); - }, - + } + /** * Enable reticle control * @memberOf Viewer * @instance */ - enableReticleControl: function () { - + enableReticleControl () { + if ( this.reticle.visible ) { return; } - + this.tempEnableReticle = true; - + // Register reticle event and unregister mouse event this.unregisterMouseAndTouchEvents(); this.reticle.show(); this.registerReticleEvent(); this.updateReticleEvent(); - - }, - + + } + /** * Disable reticle control * @memberOf Viewer * @instance */ - disableReticleControl: function () { - + disableReticleControl () { + this.tempEnableReticle = false; - + // Register mouse event and unregister reticle event if ( !this.options.enableReticle ) { - + this.reticle.hide(); this.unregisterReticleEvent(); this.registerMouseAndTouchEvents(); - + } else { - + this.updateReticleEvent(); - + } - - }, - + + } + /** * Enable auto rotation * @memberOf Viewer * @instance */ - enableAutoRate: function () { - + enableAutoRate () { + this.options.autoRotate = true; this.OrbitControls.autoRotate = true; - - }, - + } + /** * Disable auto rotation * @memberOf Viewer * @instance */ - disableAutoRate: function () { - + disableAutoRate () { + clearTimeout( this.autoRotateRequestId ); this.options.autoRotate = false; this.OrbitControls.autoRotate = false; - - }, - + + } + /** * Toggle video play or stop * @param {boolean} pause @@ -8053,21 +7970,21 @@ Viewer.prototype = Object.assign( Object.create( EventDispatcher.prototype ), { * @instance * @fires Viewer#video-toggle */ - toggleVideoPlay: function ( pause ) { - + toggleVideoPlay ( pause ) { + if ( this.panorama instanceof VideoPanorama ) { - + /** * Toggle video event * @type {object} * @event Viewer#video-toggle */ this.panorama.dispatchEvent( { type: 'video-toggle', pause: pause } ); - + } - - }, - + + } + /** * Set currentTime in a video * @param {number} percentage - Percentage of a video. Range from 0.0 to 1.0 @@ -8075,10 +7992,10 @@ Viewer.prototype = Object.assign( Object.create( EventDispatcher.prototype ), { * @instance * @fires Viewer#video-time */ - setVideoCurrentTime: function ( percentage ) { - + setVideoCurrentTime ( percentage ) { + if ( this.panorama instanceof VideoPanorama ) { - + /** * Setting video time event * @type {object} @@ -8086,11 +8003,11 @@ Viewer.prototype = Object.assign( Object.create( EventDispatcher.prototype ), { * @property {number} percentage - Percentage of a video. Range from 0.0 to 1.0 */ this.panorama.dispatchEvent( { type: 'video-time', percentage: percentage } ); - + } - - }, - + + } + /** * This will be called when video updates if an widget is present * @param {number} percentage - Percentage of a video. Range from 0.0 to 1.0 @@ -8098,10 +8015,10 @@ Viewer.prototype = Object.assign( Object.create( EventDispatcher.prototype ), { * @instance * @fires Viewer#video-update */ - onVideoUpdate: function ( percentage ) { - + onVideoUpdate ( percentage ) { + const { widget } = this; - + /** * Video update event * @type {object} @@ -8109,137 +8026,136 @@ Viewer.prototype = Object.assign( Object.create( EventDispatcher.prototype ), { * @property {number} percentage - Percentage of a video. Range from 0.0 to 1.0 */ if( widget ) { widget.dispatchEvent( { type: 'video-update', percentage: percentage } ); } - - }, - + + } + /** * Add update callback to be called every animation frame * @param {function} callback * @memberOf Viewer * @instance */ - addUpdateCallback: function ( fn ) { - + addUpdateCallback ( fn ) { + if ( fn ) { - + this.updateCallbacks.push( fn ); - + } - - }, - + } + /** * Remove update callback * @param {function} fn - The function to be removed * @memberOf Viewer * @instance */ - removeUpdateCallback: function ( fn ) { - + removeUpdateCallback ( fn ) { + const index = this.updateCallbacks.indexOf( fn ); - + if ( fn && index >= 0 ) { - + this.updateCallbacks.splice( index, 1 ); - + } - - }, - + + } + /** * Show video widget * @memberOf Viewer * @instance */ - showVideoWidget: function () { - + showVideoWidget () { + const { widget } = this; - + /** * Show video widget event * @type {object} * @event Viewer#video-control-show */ if( widget ) { widget.dispatchEvent( { type: 'video-control-show' } ); } - - }, - + + } + /** * Hide video widget * @memberOf Viewer * @instance */ - hideVideoWidget: function () { - + hideVideoWidget () { + const { widget } = this; - + /** * Hide video widget * @type {object} * @event Viewer#video-control-hide */ if( widget ) { widget.dispatchEvent( { type: 'video-control-hide' } ); } - - }, - + + } + /** * Update video play button * @param {boolean} paused * @memberOf Viewer * @instance */ - updateVideoPlayButton: function ( paused ) { - + updateVideoPlayButton ( paused ) { + const { widget } = this; - + if ( widget && widget.videoElement && widget.videoElement.controlButton ) { - + widget.videoElement.controlButton.update( paused ); - + } - - }, - + + } + /** * Add default panorama event listeners * @param {Panorama} pano - The panorama to be added with event listener * @memberOf Viewer * @instance */ - addPanoramaEventListener: function ( pano ) { - + addPanoramaEventListener ( pano ) { + // Set camera control on every panorama pano.addEventListener( 'enter-fade-start', this.setCameraControl.bind( this ) ); - + // Show and hide widget event only when it's VideoPanorama if ( pano instanceof VideoPanorama ) { - + pano.addEventListener( 'enter-fade-start', this.showVideoWidget.bind( this ) ); pano.addEventListener( 'leave', function () { - + if ( !(this.panorama instanceof VideoPanorama) ) { - + this.hideVideoWidget.call( this ); - + } - + }.bind( this ) ); - + } - - }, - + + } + /** * Set camera control * @memberOf Viewer * @instance */ - setCameraControl: function () { - + setCameraControl () { + this.OrbitControls.target.copy( this.panorama.position ); - - }, - + + } + /** * Get current camera control * @return {object} - Current navigation control @@ -8247,239 +8163,234 @@ Viewer.prototype = Object.assign( Object.create( EventDispatcher.prototype ), { * @instance * @returns {THREE.OrbitControls|THREE.DeviceOrientationControls} */ - getControl: function () { - - return this.control; - - }, - + getControl () { + + return this.control; + + } + /** * Get scene * @memberOf Viewer * @instance * @return {THREE.Scene} - Current scene which the viewer is built on */ - getScene: function () { - + getScene () { + return this.scene; - - }, - + + } + /** * Get camera * @memberOf Viewer * @instance * @return {THREE.Camera} - The scene camera */ - getCamera: function () { - + getCamera () { + return this.camera; - - }, - + + } + /** * Get renderer * @memberOf Viewer * @instance * @return {THREE.WebGLRenderer} - The renderer using webgl */ - getRenderer: function () { - + getRenderer () { + return this.renderer; - - }, - + + } + /** * Get container * @memberOf Viewer * @instance * @return {HTMLElement} - The container holds rendererd canvas */ - getContainer: function () { - + getContainer () { + return this.container; - - }, - + + } + /** * Get control id * @memberOf Viewer * @instance * @return {string} - Control id. 'orbit' or 'device-orientation' */ - getControlId: function () { - + getControlId () { + return this.control.id; - - }, - + + } + /** * Get next navigation control id * @memberOf Viewer * @instance * @return {string} - Next control id */ - getNextControlId: function () { - + getNextControlId () { + return this.controls[ this.getNextControlIndex() ].id; - - }, - + + } + /** * Get next navigation control index * @memberOf Viewer * @instance * @return {number} - Next control index */ - getNextControlIndex: function () { - + getNextControlIndex () { + const controls = this.controls; const control = this.control; const nextIndex = controls.indexOf( control ) + 1; - + return ( nextIndex >= controls.length ) ? 0 : nextIndex; - - }, - + + } + /** * Set field of view of camera * @param {number} fov * @memberOf Viewer * @instance */ - setCameraFov: function ( fov ) { - + setCameraFov ( fov ) { + this.camera.fov = fov; this.camera.updateProjectionMatrix(); - - }, - + + } + /** * Enable control by index * @param {CONTROLS} index - Index of camera control * @memberOf Viewer * @instance */ - enableControl: function ( index ) { - + enableControl ( index ) { + index = ( index >= 0 && index < this.controls.length ) ? index : 0; - + this.control.enabled = false; - + this.control = this.controls[ index ]; - + this.control.enabled = true; - + switch ( index ) { - + case CONTROLS.ORBIT: - + this.camera.position.copy( this.panorama.position ); this.camera.position.z += 1; - + break; - + case CONTROLS.DEVICEORIENTATION: - + this.camera.position.copy( this.panorama.position ); - - break; - - default: - + break; } - + this.control.update(); - + this.activateWidgetItem( index, undefined ); - - }, - + + } + /** * Disable current control * @memberOf Viewer * @instance */ - disableControl: function () { - + disableControl () { + this.control.enabled = false; - - }, - + + } + /** * Toggle next control * @memberOf Viewer * @instance */ - toggleNextControl: function () { - + toggleNextControl () { + this.enableControl( this.getNextControlIndex() ); - - }, - + + } + /** * Screen Space Projection * @memberOf Viewer * @instance */ - getScreenVector: function ( worldVector ) { - + getScreenVector ( worldVector ) { + const vector = worldVector.clone(); const widthHalf = ( this.container.clientWidth ) / 2; const heightHalf = this.container.clientHeight / 2; - + vector.project( this.camera ); - + vector.x = ( vector.x * widthHalf ) + widthHalf; vector.y = - ( vector.y * heightHalf ) + heightHalf; vector.z = 0; - + return vector; - - }, - + + } + /** * Check Sprite in Viewport * @memberOf Viewer * @instance */ - checkSpriteInViewport: function ( sprite ) { - + checkSpriteInViewport ( sprite ) { + this.camera.matrixWorldInverse.getInverse( this.camera.matrixWorld ); this.cameraViewProjectionMatrix.multiplyMatrices( this.camera.projectionMatrix, this.camera.matrixWorldInverse ); this.cameraFrustum.setFromMatrix( this.cameraViewProjectionMatrix ); - + return sprite.visible && this.cameraFrustum.intersectsSprite( sprite ); - - }, - + + } + /** * Reverse dragging direction * @memberOf Viewer * @instance */ - reverseDraggingDirection: function () { + reverseDraggingDirection () { this.OrbitControls.rotateSpeed *= -1; this.OrbitControls.momentumScalingFactor *= -1; - - }, - + + } + /** * Add reticle * @memberOf Viewer * @instance */ - addReticle: function () { - + addReticle () { + this.reticle = new Reticle( 0xffffff, true, this.options.dwellTime ); this.reticle.hide(); this.camera.add( this.reticle ); this.sceneReticle.add( this.camera ); - - }, - + } + /** * Tween control looking center * @param {THREE.Vector3} vector - Vector to be looked at the center @@ -8488,56 +8399,56 @@ Viewer.prototype = Object.assign( Object.create( EventDispatcher.prototype ), { * @memberOf Viewer * @instance */ - tweenControlCenter: function ( vector, duration, easing ) { - + tweenControlCenter ( vector, duration, easing ) { + if ( this.control !== this.OrbitControls ) { - + return; - + } - + // Pass in arguments as array if ( vector instanceof Array ) { - + duration = vector[ 1 ]; easing = vector[ 2 ]; vector = vector[ 0 ]; - + } - + duration = duration !== undefined ? duration : 1000; easing = easing || Tween.Easing.Exponential.Out; - + let scope, ha, va, chv, cvv, hv, vv, vptc, ov, nv; - + scope = this; - - chv = this.camera.getWorldDirection( new Vector3() ); + + chv = this.camera.getWorldDirection( new THREE.Vector3() ); cvv = chv.clone(); - - vptc = this.panorama.getWorldPosition( new Vector3() ).sub( this.camera.getWorldPosition( new Vector3() ) ); - + + vptc = this.panorama.getWorldPosition( new THREE.Vector3() ).sub( this.camera.getWorldPosition( new THREE.Vector3() ) ); + hv = vector.clone(); // Scale effect hv.x *= -1; hv.add( vptc ).normalize(); vv = hv.clone(); - + chv.y = 0; hv.y = 0; - + ha = Math.atan2( hv.z, hv.x ) - Math.atan2( chv.z, chv.x ); ha = ha > Math.PI ? ha - 2 * Math.PI : ha; ha = ha < -Math.PI ? ha + 2 * Math.PI : ha; va = Math.abs( cvv.angleTo( chv ) + ( cvv.y * vv.y <= 0 ? vv.angleTo( hv ) : -vv.angleTo( hv ) ) ); va *= vv.y < cvv.y ? 1 : -1; - + ov = { left: 0, up: 0 }; nv = { left: 0, up: 0 }; - + this.tweenLeftAnimation.stop(); this.tweenUpAnimation.stop(); - + this.tweenLeftAnimation = new Tween.Tween( ov ) .to( { left: ha }, duration ) .easing( easing ) @@ -8546,7 +8457,7 @@ Viewer.prototype = Object.assign( Object.create( EventDispatcher.prototype ), { nv.left = ov.left; }) .start(); - + this.tweenUpAnimation = new Tween.Tween( ov ) .to( { up: va }, duration ) .easing( easing ) @@ -8555,9 +8466,9 @@ Viewer.prototype = Object.assign( Object.create( EventDispatcher.prototype ), { nv.up = ov.up; }) .start(); - - }, - + + } + /** * Tween control looking center by object * @param {THREE.Object3D} object - Object to be looked at the center @@ -8566,33 +8477,33 @@ Viewer.prototype = Object.assign( Object.create( EventDispatcher.prototype ), { * @memberOf Viewer * @instance */ - tweenControlCenterByObject: function ( object, duration, easing ) { - + tweenControlCenterByObject ( object, duration, easing ) { + let isUnderScalePlaceHolder = false; - + object.traverseAncestors( function ( ancestor ) { - + if ( ancestor.scalePlaceHolder ) { - + isUnderScalePlaceHolder = true; - + } } ); - + if ( isUnderScalePlaceHolder ) { - - const invertXVector = new Vector3( -1, 1, 1 ); - - this.tweenControlCenter( object.getWorldPosition( new Vector3() ).multiply( invertXVector ), duration, easing ); - + + const invertXVector = new THREE.Vector3( -1, 1, 1 ); + + this.tweenControlCenter( object.getWorldPosition( new THREE.Vector3() ).multiply( invertXVector ), duration, easing ); + } else { - - this.tweenControlCenter( object.getWorldPosition( new Vector3() ), duration, easing ); - + + this.tweenControlCenter( object.getWorldPosition( new THREE.Vector3() ), duration, easing ); + } - - }, - + + } + /** * This is called when window size is changed * @fires Viewer#window-resize @@ -8601,51 +8512,51 @@ Viewer.prototype = Object.assign( Object.create( EventDispatcher.prototype ), { * @memberOf Viewer * @instance */ - onWindowResize: function ( windowWidth, windowHeight ) { - + onWindowResize ( windowWidth, windowHeight ) { + let width, height; - + const expand = this.container.classList.contains( 'panolens-container' ) || this.container.isFullscreen; - + if ( windowWidth !== undefined && windowHeight !== undefined ) { - + width = windowWidth; height = windowHeight; this.container._width = windowWidth; this.container._height = windowHeight; - + } else { - + const isAndroid = /(android)/i.test(window.navigator.userAgent); - + const adjustWidth = isAndroid ? Math.min(document.documentElement.clientWidth, window.innerWidth || 0) : Math.max(document.documentElement.clientWidth, window.innerWidth || 0); - + const adjustHeight = isAndroid ? Math.min(document.documentElement.clientHeight, window.innerHeight || 0) : Math.max(document.documentElement.clientHeight, window.innerHeight || 0); - + width = expand ? adjustWidth : this.container.clientWidth; height = expand ? adjustHeight : this.container.clientHeight; - + this.container._width = width; this.container._height = height; - + } - + this.camera.aspect = width / height; this.camera.updateProjectionMatrix(); - + this.renderer.setSize( width, height ); - + // Update reticle if ( this.options.enableReticle || this.tempEnableReticle ) { - + this.updateReticleEvent(); - + } - + /** * Window resizing event * @type {object} @@ -8655,24 +8566,24 @@ Viewer.prototype = Object.assign( Object.create( EventDispatcher.prototype ), { */ this.dispatchEvent( { type: 'window-resize', width: width, height: height }); this.scene.traverse( function ( object ) { - + if ( object.dispatchEvent ) { - + object.dispatchEvent( { type: 'window-resize', width: width, height: height }); - + } - + } ); - - }, - + + } + /** * Add output element * @memberOf Viewer * @instance */ - addOutputElement: function () { - + addOutputElement () { + const element = document.createElement( 'div' ); element.style.position = 'absolute'; element.style.right = '10px'; @@ -8680,37 +8591,37 @@ Viewer.prototype = Object.assign( Object.create( EventDispatcher.prototype ), { element.style.color = '#fff'; this.container.appendChild( element ); this.outputDivElement = element; - - }, - + + } + /** * Output position in developer console by holding down Ctrl button * @memberOf Viewer * @instance */ - outputPosition: function () { - + outputPosition () { + const intersects = this.raycaster.intersectObject( this.panorama, true ); - + if ( intersects.length > 0 ) { - + const point = intersects[ 0 ].point.clone(); - const converter = new Vector3( -1, 1, 1 ); - const world = this.panorama.getWorldPosition( new Vector3() ); + const converter = new THREE.Vector3( -1, 1, 1 ); + const world = this.panorama.getWorldPosition( new THREE.Vector3() ); point.sub( world ).multiply( converter ); - + const position = { x: point.x.toFixed(2), y: point.y.toFixed(2), z: point.z.toFixed(2), }; - + const message = `${position.x}, ${position.y}, ${position.z}`; - + if ( point.length() === 0 ) { return; } - + switch ( this.options.output ) { - + case 'event': /** * Dispatch raycast position as event @@ -8719,121 +8630,116 @@ Viewer.prototype = Object.assign( Object.create( EventDispatcher.prototype ), { */ this.dispatchEvent( { type: 'position-output', position: position } ); break; - + case 'console': console.info( message ); break; - + case 'overlay': this.outputDivElement.textContent = message; break; - - default: - break; - + } - + } - - }, - + + } + /** * On mouse down * @param {MouseEvent} event * @memberOf Viewer * @instance */ - onMouseDown: function ( event ) { - + onMouseDown ( event ) { + event.preventDefault(); - + this.userMouse.x = ( event.clientX >= 0 ) ? event.clientX : event.touches[0].clientX; this.userMouse.y = ( event.clientY >= 0 ) ? event.clientY : event.touches[0].clientY; this.userMouse.type = 'mousedown'; this.onTap( event ); - - }, - + } + /** * On mouse move * @param {MouseEvent} event * @memberOf Viewer * @instance */ - onMouseMove: function ( event ) { - + onMouseMove ( event ) { + event.preventDefault(); this.userMouse.type = 'mousemove'; this.onTap( event ); - - }, - + + } + /** * On mouse up * @param {MouseEvent} event * @memberOf Viewer * @instance */ - onMouseUp: function ( event ) { - + onMouseUp ( event ) { + let onTarget = false; - + this.userMouse.type = 'mouseup'; - + const type = ( this.userMouse.x >= event.clientX - this.options.clickTolerance - && this.userMouse.x <= event.clientX + this.options.clickTolerance - && this.userMouse.y >= event.clientY - this.options.clickTolerance - && this.userMouse.y <= event.clientY + this.options.clickTolerance ) - || ( event.changedTouches - && this.userMouse.x >= event.changedTouches[0].clientX - this.options.clickTolerance - && this.userMouse.x <= event.changedTouches[0].clientX + this.options.clickTolerance - && this.userMouse.y >= event.changedTouches[0].clientY - this.options.clickTolerance - && this.userMouse.y <= event.changedTouches[0].clientY + this.options.clickTolerance ) + && this.userMouse.x <= event.clientX + this.options.clickTolerance + && this.userMouse.y >= event.clientY - this.options.clickTolerance + && this.userMouse.y <= event.clientY + this.options.clickTolerance ) + || ( event.changedTouches + && this.userMouse.x >= event.changedTouches[0].clientX - this.options.clickTolerance + && this.userMouse.x <= event.changedTouches[0].clientX + this.options.clickTolerance + && this.userMouse.y >= event.changedTouches[0].clientY - this.options.clickTolerance + && this.userMouse.y <= event.changedTouches[0].clientY + this.options.clickTolerance ) ? 'click' : undefined; - + // Event should happen on canvas if ( event && event.target && !event.target.classList.contains( 'panolens-canvas' ) ) { return; } - + event.preventDefault(); - + if ( event.changedTouches && event.changedTouches.length === 1 ) { - + onTarget = this.onTap( { clientX: event.changedTouches[0].clientX, clientY: event.changedTouches[0].clientY }, type ); - + } else { - + onTarget = this.onTap( event, type ); - + } - + this.userMouse.type = 'none'; - + if ( onTarget ) { - + return; - + } - + if ( type === 'click' ) { - + const { options: { autoHideInfospot, autoHideControlBar }, panorama, toggleControlBar } = this; - + if ( autoHideInfospot && panorama ) { - + panorama.toggleInfospotVisibility(); - + } - + if ( autoHideControlBar ) { - + toggleControlBar(); - + } - + } - - }, - + } + /** * On tap eveny frame * @param {MouseEvent} event @@ -8841,228 +8747,228 @@ Viewer.prototype = Object.assign( Object.create( EventDispatcher.prototype ), { * @memberOf Viewer * @instance */ - onTap: function ( event, type ) { - + onTap ( event, type ) { + const { left, top } = this.container.getBoundingClientRect(); const { clientWidth, clientHeight } = this.container; - + this.raycasterPoint.x = ( ( event.clientX - left ) / clientWidth ) * 2 - 1; this.raycasterPoint.y = - ( ( event.clientY - top ) / clientHeight ) * 2 + 1; - + this.raycaster.setFromCamera( this.raycasterPoint, this.camera ); - + // Return if no panorama if ( !this.panorama ) { - + return; - + } - + // output infospot information if ( event.type !== 'mousedown' && this.touchSupported || this.OUTPUT_INFOSPOT ) { - + this.outputPosition(); - + } - - + + const intersects = this.raycaster.intersectObjects( this.panorama.children, true ); const intersect_entity = this.getConvertedIntersect( intersects ); const intersect = ( intersects.length > 0 ) ? intersects[0].object : undefined; - + if ( this.userMouse.type === 'mouseup' ) { - + if ( intersect_entity && this.pressEntityObject === intersect_entity && this.pressEntityObject.dispatchEvent ) { - + this.pressEntityObject.dispatchEvent( { type: 'pressstop-entity', mouseEvent: event } ); - + } - + this.pressEntityObject = undefined; - + } - + if ( this.userMouse.type === 'mouseup' ) { - + if ( intersect && this.pressObject === intersect && this.pressObject.dispatchEvent ) { - + this.pressObject.dispatchEvent( { type: 'pressstop', mouseEvent: event } ); - + } - + this.pressObject = undefined; - + } - + if ( type === 'click' ) { - + this.panorama.dispatchEvent( { type: 'click', intersects: intersects, mouseEvent: event } ); - + if ( intersect_entity && intersect_entity.dispatchEvent ) { - + intersect_entity.dispatchEvent( { type: 'click-entity', mouseEvent: event } ); - + } - + if ( intersect && intersect.dispatchEvent ) { - + intersect.dispatchEvent( { type: 'click', mouseEvent: event } ); - + } - + } else { - + this.panorama.dispatchEvent( { type: 'hover', intersects: intersects, mouseEvent: event } ); - + if ( ( this.hoverObject && intersects.length > 0 && this.hoverObject !== intersect_entity ) - || ( this.hoverObject && intersects.length === 0 ) ){ - + || ( this.hoverObject && intersects.length === 0 ) ){ + if ( this.hoverObject.dispatchEvent ) { - + this.hoverObject.dispatchEvent( { type: 'hoverleave', mouseEvent: event } ); - + this.reticle.end(); - + } - + this.hoverObject = undefined; - + } - + if ( intersect_entity && intersects.length > 0 ) { - + if ( this.hoverObject !== intersect_entity ) { - + this.hoverObject = intersect_entity; - + if ( this.hoverObject.dispatchEvent ) { - + this.hoverObject.dispatchEvent( { type: 'hoverenter', mouseEvent: event } ); - + // Start reticle timer if ( this.options.autoReticleSelect && this.options.enableReticle || this.tempEnableReticle ) { this.reticle.start( this.onTap.bind( this, event, 'click' ) ); } - + } - + } - + if ( this.userMouse.type === 'mousedown' && this.pressEntityObject != intersect_entity ) { - + this.pressEntityObject = intersect_entity; - + if ( this.pressEntityObject.dispatchEvent ) { - + this.pressEntityObject.dispatchEvent( { type: 'pressstart-entity', mouseEvent: event } ); - + } - + } - + if ( this.userMouse.type === 'mousedown' && this.pressObject != intersect ) { - + this.pressObject = intersect; - + if ( this.pressObject.dispatchEvent ) { - + this.pressObject.dispatchEvent( { type: 'pressstart', mouseEvent: event } ); - + } - + } - + if ( this.userMouse.type === 'mousemove' || this.options.enableReticle ) { - + if ( intersect && intersect.dispatchEvent ) { - + intersect.dispatchEvent( { type: 'hover', mouseEvent: event } ); - + } - + if ( this.pressEntityObject && this.pressEntityObject.dispatchEvent ) { - + this.pressEntityObject.dispatchEvent( { type: 'pressmove-entity', mouseEvent: event } ); - + } - + if ( this.pressObject && this.pressObject.dispatchEvent ) { - + this.pressObject.dispatchEvent( { type: 'pressmove', mouseEvent: event } ); - + } - + } - + } - + if ( !intersect_entity && this.pressEntityObject && this.pressEntityObject.dispatchEvent ) { - + this.pressEntityObject.dispatchEvent( { type: 'pressstop-entity', mouseEvent: event } ); - + this.pressEntityObject = undefined; - + } - + if ( !intersect && this.pressObject && this.pressObject.dispatchEvent ) { - + this.pressObject.dispatchEvent( { type: 'pressstop', mouseEvent: event } ); - + this.pressObject = undefined; - + } - + } - + // Infospot handler if ( intersect && intersect instanceof Infospot ) { - + this.infospot = intersect; - + if ( type === 'click' ) { - + return true; - + } - - + + } else if ( this.infospot ) { - + this.hideInfospot(); - + } - + // Auto rotate if ( this.options.autoRotate && this.userMouse.type !== 'mousemove' ) { - + // Auto-rotate idle timer clearTimeout( this.autoRotateRequestId ); - + if ( this.control === this.OrbitControls ) { - + this.OrbitControls.autoRotate = false; this.autoRotateRequestId = window.setTimeout( this.enableAutoRate.bind( this ), this.options.autoRotateActivationDuration ); - + } - + } - - }, - + + } + /** * Get converted intersect * @param {array} intersects * @memberOf Viewer * @instance */ - getConvertedIntersect: function ( intersects ) { - + getConvertedIntersect ( intersects ) { + let intersect; - + for ( let i = 0; i < intersects.length; i++ ) { - + if ( intersects[i].distance >= 0 && intersects[i].object && !intersects[i].object.passThrough ) { - + if ( intersects[i].object.entity && intersects[i].object.entity.passThrough ) { continue; } else if ( intersects[i].object.entity && !intersects[i].object.entity.passThrough ) { @@ -9072,357 +8978,347 @@ Viewer.prototype = Object.assign( Object.create( EventDispatcher.prototype ), { intersect = intersects[i].object; break; } - + } - + } - + return intersect; - - }, - + + } + /** * Hide infospot * @memberOf Viewer * @instance */ - hideInfospot: function () { - + hideInfospot () { + if ( this.infospot ) { - + this.infospot.onHoverEnd(); - + this.infospot = undefined; - + } - - }, - + + } + /** * Toggle control bar * @memberOf Viewer * @instance * @fires Viewer#control-bar-toggle */ - toggleControlBar: function () { - + toggleControlBar () { + const { widget } = this; - + /** * Toggle control bar event * @type {object} * @event Viewer#control-bar-toggle */ if ( widget ) { - + widget.dispatchEvent( { type: 'control-bar-toggle' } ); - + } - - }, - + + } + /** * On key down * @param {KeyboardEvent} event * @memberOf Viewer * @instance */ - onKeyDown: function ( event ) { - + onKeyDown ( event ) { + if ( this.options.output && this.options.output !== 'none' && event.key === 'Control' ) { - + this.OUTPUT_INFOSPOT = true; - + } - - }, - + + } + /** * On key up * @param {KeyboardEvent} event * @memberOf Viewer * @instance */ - onKeyUp: function () { - + onKeyUp () { + this.OUTPUT_INFOSPOT = false; - - }, - + + } + /** * Update control and callbacks * @memberOf Viewer * @instance */ - update: function () { - + update () { + Tween.update(); - + this.updateCallbacks.forEach( function( callback ){ callback(); } ); - + this.control.update(); - + this.scene.traverse( function( child ){ if ( child instanceof Infospot - && child.element - && ( this.hoverObject === child - || child.element.style.display !== 'none' - || (child.element.left && child.element.left.style.display !== 'none') - || (child.element.right && child.element.right.style.display !== 'none') ) ) { + && child.element + && ( this.hoverObject === child + || child.element.style.display !== 'none' + || (child.element.left && child.element.left.style.display !== 'none') + || (child.element.right && child.element.right.style.display !== 'none') ) ) { if ( this.checkSpriteInViewport( child ) ) { - const { x, y } = this.getScreenVector( child.getWorldPosition( new Vector3() ) ); + const { x, y } = this.getScreenVector( child.getWorldPosition( new THREE.Vector3() ) ); child.translateElement( x, y ); } else { child.onDismiss(); } - + } }.bind( this ) ); - - }, - + + } + /** * Rendering function to be called on every animation frame * Render reticle last * @memberOf Viewer * @instance */ - render: function () { - + render () { + if ( this.mode === MODES.CARDBOARD || this.mode === MODES.STEREO ) { - + this.renderer.clear(); this.effect.render( this.scene, this.camera ); this.effect.render( this.sceneReticle, this.camera ); - - + + } else { - + this.renderer.clear(); this.renderer.render( this.scene, this.camera ); this.renderer.clearDepth(); this.renderer.render( this.sceneReticle, this.camera ); - + } - - }, - + + } + /** * Animate * @memberOf Viewer * @instance */ - animate: function () { - + animate () { + this.requestAnimationId = window.requestAnimationFrame( this.animate.bind( this ) ); - + this.onChange(); - - }, - + + } + /** * On change * @memberOf Viewer * @instance */ - onChange: function () { - + onChange () { + this.update(); this.render(); - - }, - + + } + /** * Register mouse and touch event on container * @memberOf Viewer * @instance */ - registerMouseAndTouchEvents: function () { - + registerMouseAndTouchEvents () { + const options = { passive: false }; - + this.container.addEventListener( 'mousedown' , this.HANDLER_MOUSE_DOWN, options ); this.container.addEventListener( 'mousemove' , this.HANDLER_MOUSE_MOVE, options ); this.container.addEventListener( 'mouseup' , this.HANDLER_MOUSE_UP , options ); this.container.addEventListener( 'touchstart', this.HANDLER_MOUSE_DOWN, options ); this.container.addEventListener( 'touchend' , this.HANDLER_MOUSE_UP , options ); - - }, - + + } + /** * Unregister mouse and touch event on container * @memberOf Viewer * @instance */ - unregisterMouseAndTouchEvents: function () { - + unregisterMouseAndTouchEvents () { + this.container.removeEventListener( 'mousedown' , this.HANDLER_MOUSE_DOWN, false ); this.container.removeEventListener( 'mousemove' , this.HANDLER_MOUSE_MOVE, false ); this.container.removeEventListener( 'mouseup' , this.HANDLER_MOUSE_UP , false ); this.container.removeEventListener( 'touchstart', this.HANDLER_MOUSE_DOWN, false ); this.container.removeEventListener( 'touchend' , this.HANDLER_MOUSE_UP , false ); - - }, - + + } + /** * Register reticle event * @memberOf Viewer * @instance */ - registerReticleEvent: function () { - + registerReticleEvent () { + this.addUpdateCallback( this.HANDLER_TAP ); - - }, - + + } + /** * Unregister reticle event * @memberOf Viewer * @instance */ - unregisterReticleEvent: function () { - + unregisterReticleEvent () { + this.removeUpdateCallback( this.HANDLER_TAP ); - - }, - + + } + /** * Update reticle event * @memberOf Viewer * @instance */ - updateReticleEvent: function () { - + updateReticleEvent () { + const clientX = this.container.clientWidth / 2 + this.container.offsetLeft; const clientY = this.container.clientHeight / 2; - + this.removeUpdateCallback( this.HANDLER_TAP ); this.HANDLER_TAP = this.onTap.bind( this, { clientX, clientY } ); this.addUpdateCallback( this.HANDLER_TAP ); - - }, - + } + /** * Register container and window listeners * @memberOf Viewer * @instance */ - registerEventListeners: function () { - + registerEventListeners () { + // Resize Event window.addEventListener( 'resize' , this.HANDLER_WINDOW_RESIZE, true ); - + // Keyboard Event window.addEventListener( 'keydown', this.HANDLER_KEY_DOWN, true ); window.addEventListener( 'keyup' , this.HANDLER_KEY_UP , true ); - - }, - + + } /** * Unregister container and window listeners * @memberOf Viewer * @instance */ - unregisterEventListeners: function () { - + unregisterEventListeners () { + // Resize Event window.removeEventListener( 'resize' , this.HANDLER_WINDOW_RESIZE, true ); - + // Keyboard Event window.removeEventListener( 'keydown', this.HANDLER_KEY_DOWN, true ); window.removeEventListener( 'keyup' , this.HANDLER_KEY_UP , true ); - - }, - + + } + /** * Dispose all scene objects and clear cache * @memberOf Viewer * @instance */ - dispose: function () { - + dispose () { + this.tweenLeftAnimation.stop(); this.tweenUpAnimation.stop(); - + // Unregister dom event listeners this.unregisterEventListeners(); - + // recursive disposal on 3d objects function recursiveDispose ( object ) { - + for ( let i = object.children.length - 1; i >= 0; i-- ) { - + recursiveDispose( object.children[i] ); object.remove( object.children[i] ); - + } - + if ( object instanceof Panorama || object instanceof Infospot ) { - + object.dispose(); object = null; - + } else if ( object.dispatchEvent ){ - + object.dispatchEvent( 'dispose' ); - + } - + } - + recursiveDispose( this.scene ); - + // dispose widget if ( this.widget ) { - + this.widget.dispose(); this.widget = null; - + } - + // clear cache - if ( Cache && Cache.enabled ) { - - Cache.clear(); - + if ( THREE.Cache && THREE.Cache.enabled ) { + + THREE.Cache.clear(); + } - - }, - + + } + /** * Destroy viewer by disposing and stopping requestAnimationFrame * @memberOf Viewer * @instance */ - destroy: function () { - + destroy () { this.dispose(); this.render(); window.cancelAnimationFrame( this.requestAnimationId ); - - }, - + } + /** * On panorama dispose * @memberOf Viewer * @instance */ - onPanoramaDispose: function ( panorama ) { - + onPanoramaDispose ( panorama ) { if ( panorama instanceof VideoPanorama ) { - this.hideVideoWidget(); - } - + if ( panorama === this.panorama ) { - this.panorama = null; - } - - }, - + } + /** * Load ajax call * @param {string} url - URL to be requested @@ -9430,30 +9326,28 @@ Viewer.prototype = Object.assign( Object.create( EventDispatcher.prototype ), { * @memberOf Viewer * @instance */ - loadAsyncRequest: function ( url, callback = () => {} ) { - + loadAsyncRequest( url, callback = () => {} ) { const request = new window.XMLHttpRequest(); request.onloadend = function ( event ) { callback( event ); }; request.open( 'GET', url, true ); request.send( null ); - - }, - + + } + /** * View indicator in upper left * @memberOf Viewer * @instance */ - addViewIndicator: function () { - + addViewIndicator () { + const scope = this; - + function loadViewIndicator ( asyncEvent ) { - if ( asyncEvent.loaded === 0 ) return; - + const viewIndicatorDiv = asyncEvent.target.responseXML.documentElement; viewIndicatorDiv.style.width = scope.viewIndicatorSize + 'px'; viewIndicatorDiv.style.height = scope.viewIndicatorSize + 'px'; @@ -9463,15 +9357,14 @@ Viewer.prototype = Object.assign( Object.create( EventDispatcher.prototype ), { viewIndicatorDiv.style.opacity = '0.5'; viewIndicatorDiv.style.cursor = 'pointer'; viewIndicatorDiv.id = 'panolens-view-indicator-container'; - + scope.container.appendChild( viewIndicatorDiv ); - + const indicator = viewIndicatorDiv.querySelector( '#indicator' ); const setIndicatorD = function () { - scope.radius = scope.viewIndicatorSize * 0.225; - scope.currentPanoAngle = scope.camera.rotation.y - Math$1.degToRad( 90 ); - scope.fovAngle = Math$1.degToRad( scope.camera.fov ) ; + scope.currentPanoAngle = scope.camera.rotation.y - THREE.Math.degToRad( 90 ); + scope.fovAngle = THREE.Math.degToRad( scope.camera.fov ) ; scope.leftAngle = -scope.currentPanoAngle - scope.fovAngle / 2; scope.rightAngle = -scope.currentPanoAngle + scope.fovAngle / 2; scope.leftX = scope.radius * Math.cos( scope.leftAngle ); @@ -9479,36 +9372,34 @@ Viewer.prototype = Object.assign( Object.create( EventDispatcher.prototype ), { scope.rightX = scope.radius * Math.cos( scope.rightAngle ); scope.rightY = scope.radius * Math.sin( scope.rightAngle ); scope.indicatorD = 'M ' + scope.leftX + ' ' + scope.leftY + ' A ' + scope.radius + ' ' + scope.radius + ' 0 0 1 ' + scope.rightX + ' ' + scope.rightY; - + if ( scope.leftX && scope.leftY && scope.rightX && scope.rightY && scope.radius ) { - indicator.setAttribute( 'd', scope.indicatorD ); - } - + }; - + scope.addUpdateCallback( setIndicatorD ); - + const indicatorOnMouseEnter = function () { - + this.style.opacity = '1'; - + }; - + const indicatorOnMouseLeave = function () { - + this.style.opacity = '0.5'; - + }; - + viewIndicatorDiv.addEventListener( 'mouseenter', indicatorOnMouseEnter ); viewIndicatorDiv.addEventListener( 'mouseleave', indicatorOnMouseLeave ); } - + this.loadAsyncRequest( DataImage.ViewIndicator, loadViewIndicator ); - - }, + + } /** * Append custom control item to existing control bar @@ -9516,38 +9407,30 @@ Viewer.prototype = Object.assign( Object.create( EventDispatcher.prototype ), { * @memberOf Viewer * @instance */ - appendControlItem: function ( option ) { - + appendControlItem ( option ) { const item = this.widget.createCustomItem( option ); - if ( option.group === 'video' ) { - this.widget.videoElement.appendChild( item ); - } else { - this.widget.barElement.appendChild( item ); - } - + return item; - }, - + } + /** * Clear all cached files * @memberOf Viewer * @instance */ - clearAllCache: function () { - - Cache.clear(); - + clearAllCache() { + THREE.Cache.clear(); } -} ); +} -if ( REVISION$1 != THREE_REVISION ) { +if ( THREE.REVISION != THREE_REVISION ) { console.warn( `three.js version is not matched. Please consider use the target revision ${THREE_REVISION}` ); @@ -9560,4 +9443,4 @@ if ( REVISION$1 != THREE_REVISION ) { */ window.TWEEN = Tween; -export { BasicPanorama, CONTROLS, CameraPanorama, CubePanorama, CubeTextureLoader, DataImage, EmptyPanorama, GoogleStreetviewPanorama, ImageLittlePlanet, ImageLoader, ImagePanorama, Infospot, LittlePlanet, MODES, Media, Panorama, REVISION, Reticle, THREE_REVISION, THREE_VERSION, TextureLoader, VERSION, VideoPanorama, Viewer, Widget }; +export { BasicPanorama, CONTROLS, CONTROL_BUTTONS, CameraPanorama, CubePanorama, CubeTextureLoader, DataImage, EmptyPanorama, GoogleStreetviewPanorama, ImageLittlePlanet, ImageLoader, ImagePanorama, Infospot, LittlePlanet, MODES, Media, OUTPUTS, Panorama, REVISION, Reticle, THREE_REVISION, THREE_VERSION, TextureLoader, VERSION, VideoPanorama, Viewer, Widget }; diff --git a/docs/BasicPanorama.html b/docs/BasicPanorama.html index af8c551f..c8df5813 100644 --- a/docs/BasicPanorama.html +++ b/docs/BasicPanorama.html @@ -41,7 +41,7 @@ -

Home

Github

Classes

Modules

Externals

Events

Namespaces

+

Home

Github

Classes

Modules

Externals

Events

Namespaces

@@ -62,7 +62,7 @@

BasicPanorama

-

Basic panorama with 6 pre-defined grid images

+

Basic panorama with 6 pre-defined grid images

@@ -192,7 +192,7 @@

new Basi
- Documentation generated by JSDoc 3.6.2 on Wed Jun 12 2019 12:14:50 GMT-0700 (Pacific Daylight Time) using the docdash theme. + Documentation generated by JSDoc 3.6.10 on Wed Apr 27 2022 13:47:09 GMT+0200 (Central European Summer Time) using the docdash theme.
diff --git a/docs/CameraPanorama.html b/docs/CameraPanorama.html index 6ce28346..a45b07ce 100644 --- a/docs/CameraPanorama.html +++ b/docs/CameraPanorama.html @@ -41,7 +41,7 @@ -

Home

Github

Classes

Modules

Externals

Events

Namespaces

+

Home

Github

Classes

Modules

Externals

Events

Namespaces

@@ -62,7 +62,7 @@

CameraPanorama

-

Camera panorama

+

Camera panorama

@@ -128,7 +128,7 @@

new Cam -
+

See MediaStreamConstraints for constraints

@@ -246,7 +246,7 @@

on
Source:
@@ -285,7 +285,7 @@

on -
+

On container event

@@ -382,7 +382,7 @@

onPano
Source:
@@ -421,7 +421,7 @@

onPano -
+

On scene event

@@ -518,7 +518,7 @@

startSource:
@@ -557,7 +557,7 @@

start +

Start camera streaming

@@ -623,7 +623,7 @@

stopSource:
@@ -662,7 +662,7 @@

stop +

Stop camera streaming

@@ -713,7 +713,7 @@

stop
- Documentation generated by JSDoc 3.6.2 on Wed Jun 12 2019 12:14:50 GMT-0700 (Pacific Daylight Time) using the docdash theme. + Documentation generated by JSDoc 3.6.10 on Wed Apr 27 2022 13:47:09 GMT+0200 (Central European Summer Time) using the docdash theme.
diff --git a/docs/Constants.js.html b/docs/Constants.js.html index 24b89728..6b670694 100644 --- a/docs/Constants.js.html +++ b/docs/Constants.js.html @@ -41,7 +41,7 @@ -

Home

Github

Classes

Modules

Externals

Events

Namespaces

+

Home

Github

Classes

Modules

Externals

Events

Namespaces

@@ -108,7 +108,29 @@

Constants.js

* @property {number} CARDBOARD 2 * @property {number} STEREO 3 */ -export const MODES = { UNKNOWN: 0, NORMAL: 1, CARDBOARD: 2, STEREO: 3 }; +export const MODES = { UNKNOWN: 0, NORMAL: 1, CARDBOARD: 2, STEREO: 3 }; + +/** + * CONTROL_BUTTONS + * @module CONTROL_BUTTONS + * @example PANOLENS.VIEWER.CONTROL_BUTTONS + * @property {string} FULLSCREEN + * @property {string} SETTING + * @property {string} VIDEO + */ +export const CONTROL_BUTTONS = { FULLSCREEN: 'fullscreen', SETTING: 'setting', VIDEO: 'video' }; + +/** + * OUTPUTS + * @module OUTPUTS + * @example PANOLENS.VIEWER.OUTPUTS + * @property {string} NONE + * @property {string} CONSOLE + * @property {string} OVERLAY + */ +export const OUTPUTS = { NONE: 'none', CONSOLE: 'console', OVERLAY: 'overlay' }; + + @@ -122,7 +144,7 @@

Constants.js


- Documentation generated by JSDoc 3.6.2 on Wed Jun 12 2019 12:14:50 GMT-0700 (Pacific Daylight Time) using the docdash theme. + Documentation generated by JSDoc 3.6.10 on Wed Apr 27 2022 13:47:09 GMT+0200 (Central European Summer Time) using the docdash theme.
diff --git a/docs/CubePanorama.html b/docs/CubePanorama.html index 1a013e3a..544969e9 100644 --- a/docs/CubePanorama.html +++ b/docs/CubePanorama.html @@ -41,7 +41,7 @@ -

Home

Github

Classes

Modules

Externals

Events

Namespaces

+

Home

Github

Classes

Modules

Externals

Events

Namespaces

@@ -62,7 +62,7 @@

CubePanorama

-

Cubemap-based panorama

+

Cubemap-based panorama

@@ -242,7 +242,7 @@

disposeSource:
@@ -281,7 +281,7 @@

dispose +

Dispose

@@ -329,7 +329,7 @@

loadSource:
@@ -368,7 +368,7 @@

load +

Load 6 images and bind listeners

@@ -416,7 +416,7 @@

onLoadSource:
@@ -455,7 +455,7 @@

onLoad +

This will be called when 6 textures are ready

@@ -555,7 +555,7 @@
Parameters:

- Documentation generated by JSDoc 3.6.2 on Wed Jun 12 2019 12:14:50 GMT-0700 (Pacific Daylight Time) using the docdash theme. + Documentation generated by JSDoc 3.6.10 on Wed Apr 27 2022 13:47:09 GMT+0200 (Central European Summer Time) using the docdash theme.
diff --git a/docs/DataImage.js.html b/docs/DataImage.js.html index bab1a7e8..34cfc130 100644 --- a/docs/DataImage.js.html +++ b/docs/DataImage.js.html @@ -41,7 +41,7 @@ -

Home

Github

Classes

Modules

Externals

Events

Namespaces

+

Home

Github

Classes

Modules

Externals

Events

Namespaces

@@ -100,7 +100,7 @@

DataImage.js


- Documentation generated by JSDoc 3.6.2 on Wed Jun 12 2019 12:14:50 GMT-0700 (Pacific Daylight Time) using the docdash theme. + Documentation generated by JSDoc 3.6.10 on Wed Apr 27 2022 13:47:09 GMT+0200 (Central European Summer Time) using the docdash theme.
diff --git a/docs/EmptyPanorama.html b/docs/EmptyPanorama.html index c593a408..2b4f55fb 100644 --- a/docs/EmptyPanorama.html +++ b/docs/EmptyPanorama.html @@ -41,7 +41,7 @@ -

Home

Github

Classes

Modules

Externals

Events

Namespaces

+

Home

Github

Classes

Modules

Externals

Events

Namespaces

@@ -62,7 +62,7 @@

EmptyPanorama

-

Empty panorama

+

Empty panorama

@@ -192,7 +192,7 @@

new Empt
- Documentation generated by JSDoc 3.6.2 on Wed Jun 12 2019 12:14:50 GMT-0700 (Pacific Daylight Time) using the docdash theme. + Documentation generated by JSDoc 3.6.10 on Wed Apr 27 2022 13:47:09 GMT+0200 (Central European Summer Time) using the docdash theme.
diff --git a/docs/GoogleStreetviewLoader.html b/docs/GoogleStreetviewLoader.html index b802d126..c1bc8c12 100644 --- a/docs/GoogleStreetviewLoader.html +++ b/docs/GoogleStreetviewLoader.html @@ -41,7 +41,7 @@ -

Home

Github

Classes

Modules

Externals

Events

Namespaces

+

Home

Github

Classes

Modules

Externals

Events

Namespaces

@@ -62,7 +62,7 @@

GoogleStreetviewLoader

-

Google Street View Loader

+

Google Street View Loader

@@ -281,7 +281,7 @@

ada -
+

Adapt texture to zoom

@@ -368,7 +368,7 @@

compos -
+

Compose from tile

@@ -550,7 +550,7 @@

compos -
+

Compose panorama

@@ -637,7 +637,7 @@

load +

Load

@@ -773,7 +773,7 @@

loadPano +

Load panorama

@@ -909,7 +909,7 @@

progress +

Progress

@@ -996,7 +996,7 @@

setProgres -
+

Set progress

@@ -1155,7 +1155,7 @@

setZoom +

Set zoom level

@@ -1255,7 +1255,7 @@
Parameters:

- Documentation generated by JSDoc 3.6.2 on Wed Jun 12 2019 12:14:50 GMT-0700 (Pacific Daylight Time) using the docdash theme. + Documentation generated by JSDoc 3.6.10 on Wed Apr 27 2022 13:47:09 GMT+0200 (Central European Summer Time) using the docdash theme.
diff --git a/docs/GoogleStreetviewPanorama.html b/docs/GoogleStreetviewPanorama.html index e6baa7cd..2980517b 100644 --- a/docs/GoogleStreetviewPanorama.html +++ b/docs/GoogleStreetviewPanorama.html @@ -41,7 +41,7 @@ -

Home

Github

Classes

Modules

Externals

Events

Namespaces

+

Home

Github

Classes

Modules

Externals

Events

Namespaces

@@ -62,7 +62,7 @@

GoogleStreetviewPanorama

-

Google streetview panorama

+

Google streetview panorama

@@ -128,7 +128,7 @@

+ @@ -289,7 +289,7 @@

getGSVLoa
Source:
@@ -328,7 +328,7 @@

getGSVLoa -
+

Get GSV Loader

@@ -398,7 +398,7 @@

loadSource:
@@ -437,7 +437,7 @@

load +

Load Google Street View by panorama id

@@ -534,7 +534,7 @@

loadGSVL
Source:
@@ -573,7 +573,7 @@

loadGSVL -
+

Load GSV Loader

@@ -670,7 +670,7 @@

onLoadSource:
@@ -709,7 +709,7 @@

onLoad +

This will be called when panorama is loaded

@@ -806,7 +806,7 @@

resetSource:
@@ -845,7 +845,7 @@

reset +

Reset

@@ -893,7 +893,7 @@

setGSVLoa
Source:
@@ -932,7 +932,7 @@

setGSVLoa -
+

Set GSV Loader

@@ -980,7 +980,7 @@

setu
Source:
@@ -1019,7 +1019,7 @@

setu -
+

Setup Google Map API

@@ -1119,7 +1119,7 @@
Parameters:

- Documentation generated by JSDoc 3.6.2 on Wed Jun 12 2019 12:14:50 GMT-0700 (Pacific Daylight Time) using the docdash theme. + Documentation generated by JSDoc 3.6.10 on Wed Apr 27 2022 13:47:09 GMT+0200 (Central European Summer Time) using the docdash theme.
diff --git a/docs/ImageLittlePlanet.html b/docs/ImageLittlePlanet.html index 59153fbf..5aaa0247 100644 --- a/docs/ImageLittlePlanet.html +++ b/docs/ImageLittlePlanet.html @@ -41,7 +41,7 @@ -

Home

Github

Classes

Modules

Externals

Events

Namespaces

+

Home

Github

Classes

Modules

Externals

Events

Namespaces

@@ -62,7 +62,7 @@

ImageLittlePlanet

-

Image Little Planet

+

Image Little Planet

@@ -336,7 +336,7 @@

disposeSource:
@@ -375,7 +375,7 @@

dispose +

Dispose

@@ -423,7 +423,7 @@

onLoadSource:
@@ -462,7 +462,7 @@

onLoad +

On loaded with texture

@@ -559,7 +559,7 @@

updateTe
Source:
@@ -598,7 +598,7 @@

updateTe -
+

Update texture

@@ -698,7 +698,7 @@
Parameters:

- Documentation generated by JSDoc 3.6.2 on Wed Jun 12 2019 12:14:50 GMT-0700 (Pacific Daylight Time) using the docdash theme. + Documentation generated by JSDoc 3.6.10 on Wed Apr 27 2022 13:47:09 GMT+0200 (Central European Summer Time) using the docdash theme.
diff --git a/docs/ImagePanorama.html b/docs/ImagePanorama.html index 49f40518..c9f3c3dc 100644 --- a/docs/ImagePanorama.html +++ b/docs/ImagePanorama.html @@ -41,7 +41,7 @@ -

Home

Github

Classes

Modules

Externals

Events

Namespaces

+

Home

Github

Classes

Modules

Externals

Events

Namespaces

@@ -62,7 +62,7 @@

ImagePanorama

-

Equirectangular based image panorama

+

Equirectangular based image panorama

@@ -242,7 +242,7 @@

disposeSource:
@@ -281,7 +281,7 @@

dispose +

Dispose

@@ -304,142 +304,6 @@

disposeload(src)

- - - - - - -
- - -
Source:
-
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
- - - - - -
-

Load image asset

-
- - - - - - - - - - - -
Parameters:
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
NameTypeDescription
src - - -* - - - -

Url or image element

- - - - - - - - - - - @@ -465,7 +329,7 @@

onLoadSource:
@@ -504,7 +368,7 @@

onLoad +

This will be called when image is loaded

@@ -601,7 +465,7 @@

resetSource:
@@ -640,7 +504,7 @@

reset +

Reset

@@ -691,7 +555,7 @@

reset
- Documentation generated by JSDoc 3.6.2 on Wed Jun 12 2019 12:14:50 GMT-0700 (Pacific Daylight Time) using the docdash theme. + Documentation generated by JSDoc 3.6.10 on Wed Apr 27 2022 13:47:09 GMT+0200 (Central European Summer Time) using the docdash theme.
diff --git a/docs/Infospot.html b/docs/Infospot.html index 336e627a..c52d6776 100644 --- a/docs/Infospot.html +++ b/docs/Infospot.html @@ -41,7 +41,7 @@ -

Home

Github

Classes

Modules

Externals

Events

Namespaces

+

Home

Github

Classes

Modules

Externals

Events

Namespaces

@@ -62,7 +62,7 @@

Infospot

-

Information spot attached to panorama

+

Information spot attached to panorama

@@ -340,7 +340,7 @@

addHov
Source:
@@ -379,7 +379,7 @@

addHov -
+

Add hovering element by cloning an element

@@ -531,7 +531,7 @@

addHoverT
Source:
@@ -570,7 +570,7 @@

addHoverT -
+

Add hovering text element

@@ -722,7 +722,7 @@

disposeSource:
@@ -761,7 +761,7 @@

dispose +

Dispose

@@ -809,7 +809,7 @@

enableRa
Source:
@@ -848,7 +848,7 @@

enableRa -
+

Enable raycasting

@@ -965,7 +965,7 @@

focusSource:
@@ -1004,7 +1004,7 @@

focus +

Focus camera center to this infospot

@@ -1160,7 +1160,7 @@

getContai
Source:
@@ -1199,7 +1199,7 @@

getContai -
+

Get container

@@ -1271,7 +1271,7 @@

hideSource:
@@ -1310,7 +1310,7 @@

hide +

Hide infospot

@@ -1427,7 +1427,7 @@

lockH
Source:
@@ -1466,7 +1466,7 @@

lockH -
+

Lock hovering element

@@ -1514,7 +1514,7 @@

onClickSource:
@@ -1553,7 +1553,7 @@

onClick +

This will be called by a click event Translate and lock the hovering element if any

@@ -1651,7 +1651,7 @@

onDismissSource:
@@ -1690,7 +1690,7 @@

onDismiss +

Dismiss current element if any

@@ -1787,7 +1787,7 @@

onDual
Source:
@@ -1826,7 +1826,7 @@

onDual -
+

On dual eye effect handler Creates duplicate left and right element

@@ -1924,7 +1924,7 @@

onHoverSource:
@@ -1963,7 +1963,7 @@

onHover +

This will be called by a mouse hover event Translate the hovering element if any

@@ -2061,7 +2061,7 @@

onHoverEnd<
Source:
@@ -2100,7 +2100,7 @@

onHoverEnd< -
+

This will be called on a mouse hover end Sets cursor style to 'default', hide the element and scale down the infospot

@@ -2149,7 +2149,7 @@

onHoverSt
Source:
@@ -2188,7 +2188,7 @@

onHoverSt -
+

This will be called on a mouse hover start Sets cursor style to 'pointer', display the element and scale up the infospot

@@ -2286,7 +2286,7 @@

rem
Source:
@@ -2325,7 +2325,7 @@

rem -
+

Remove hovering element

@@ -2373,7 +2373,7 @@

setContai
Source:
@@ -2412,7 +2412,7 @@

setContai -
+

Set infospot container

@@ -2512,7 +2512,7 @@

se
Source:
@@ -2551,7 +2551,7 @@

se -
+

Set cursor css style on hover

@@ -2599,7 +2599,7 @@

setEle
Source:
@@ -2638,7 +2638,7 @@

setEle -
+

Set vendor specific css

@@ -2781,7 +2781,7 @@

setFocu
Source:
@@ -2820,7 +2820,7 @@

setFocu -
+

Set focus event handler

@@ -2868,7 +2868,7 @@

setTextSource:
@@ -2907,7 +2907,7 @@

setText +

Set hovering text content

@@ -3004,7 +3004,7 @@

showSource:
@@ -3043,7 +3043,7 @@

show +

Show infospot

@@ -3160,7 +3160,7 @@

trans
Source:
@@ -3199,7 +3199,7 @@

trans -
+

Translate the hovering element by css transform

@@ -3319,7 +3319,7 @@

unl
Source:
@@ -3358,7 +3358,7 @@

unl -
+

Unlock hovering element

@@ -3414,7 +3414,7 @@

dismiss

Source:
@@ -3453,7 +3453,7 @@

dismiss

-
+

Dimiss event

@@ -3511,7 +3511,7 @@

panolens-container

Source:
@@ -3602,7 +3602,7 @@
Properties:
-
+

Set container event

@@ -3660,7 +3660,7 @@

panolens-dual-eye-effectSource:
@@ -3751,7 +3751,7 @@

Properties:
-
+

Dual eye effect event

@@ -3809,7 +3809,7 @@

panolens-dual-eye-effectSource:
@@ -3900,7 +3900,7 @@

Properties:
-
+

Dual eye effect event

@@ -3957,7 +3957,7 @@
Type:

- Documentation generated by JSDoc 3.6.2 on Wed Jun 12 2019 12:14:50 GMT-0700 (Pacific Daylight Time) using the docdash theme. + Documentation generated by JSDoc 3.6.10 on Wed Apr 27 2022 13:47:09 GMT+0200 (Central European Summer Time) using the docdash theme.
diff --git a/docs/LittlePlanet.html b/docs/LittlePlanet.html index b77eb401..060f0b70 100644 --- a/docs/LittlePlanet.html +++ b/docs/LittlePlanet.html @@ -41,7 +41,7 @@ -

Home

Github

Classes

Modules

Externals

Events

Namespaces

+

Home

Github

Classes

Modules

Externals

Events

Namespaces

@@ -62,7 +62,7 @@

LittlePlanet

-

Little Planet

+

Little Planet

@@ -192,8 +192,6 @@
Parameters:
- image - @@ -372,7 +370,7 @@
Parameters:

- Documentation generated by JSDoc 3.6.2 on Wed Jun 12 2019 12:14:50 GMT-0700 (Pacific Daylight Time) using the docdash theme. + Documentation generated by JSDoc 3.6.10 on Wed Apr 27 2022 13:47:09 GMT+0200 (Central European Summer Time) using the docdash theme.
diff --git a/docs/Media.html b/docs/Media.html index 8110cbbc..ac68d0d8 100644 --- a/docs/Media.html +++ b/docs/Media.html @@ -41,7 +41,7 @@ -

Home

Github

Classes

Modules

Externals

Events

Namespaces

+

Home

Github

Classes

Modules

Externals

Events

Namespaces

@@ -62,7 +62,7 @@

Media

-

User Media

+

User Media

@@ -301,7 +301,7 @@

cre -
+

Create video element

@@ -411,7 +411,7 @@

cre -
+

Create video texture

@@ -516,7 +516,7 @@

enume -
+

Enumerate devices

@@ -621,7 +621,7 @@

getDevices< -
+

Get devices

@@ -757,7 +757,7 @@

getUserMe -
+

Get user media

@@ -893,7 +893,7 @@

onWindo -
+

On window resize event

@@ -1029,7 +1029,7 @@

pauseVideo< -
+

Pause video element

@@ -1116,7 +1116,7 @@

playVideo +

Play video element

@@ -1203,7 +1203,7 @@

setMedi -
+

Set media stream

@@ -1339,7 +1339,7 @@

set -
+

Set video device index

@@ -1475,7 +1475,7 @@

start +

Start streaming

@@ -1623,7 +1623,7 @@

stop +

Stop streaming

@@ -1710,7 +1710,7 @@

-
+

Switch to next available video device

@@ -1805,7 +1805,7 @@

canplay

-
+

Video can play event

@@ -1862,7 +1862,7 @@
Type:

- Documentation generated by JSDoc 3.6.2 on Wed Jun 12 2019 12:14:50 GMT-0700 (Pacific Daylight Time) using the docdash theme. + Documentation generated by JSDoc 3.6.10 on Wed Apr 27 2022 13:47:09 GMT+0200 (Central European Summer Time) using the docdash theme.
diff --git a/docs/PANOLENS.html b/docs/PANOLENS.html index 43b014e7..e19392e6 100644 --- a/docs/PANOLENS.html +++ b/docs/PANOLENS.html @@ -41,7 +41,7 @@ -

Home

Github

Classes

Modules

Externals

Events

Namespaces

+

Home

Github

Classes

Modules

Externals

Events

Namespaces

@@ -122,7 +122,7 @@

-

Panolens.js

+

Panolens.js

@@ -163,7 +163,7 @@


- Documentation generated by JSDoc 3.6.2 on Wed Jun 12 2019 12:14:50 GMT-0700 (Pacific Daylight Time) using the docdash theme. + Documentation generated by JSDoc 3.6.10 on Wed Apr 27 2022 13:47:09 GMT+0200 (Central European Summer Time) using the docdash theme.
diff --git a/docs/Panolens.js.html b/docs/Panolens.js.html index da5ba978..5611fc08 100644 --- a/docs/Panolens.js.html +++ b/docs/Panolens.js.html @@ -41,7 +41,7 @@ -

Home

Github

Classes

Modules

Externals

Events

Namespaces

+

Home

Github

Classes

Modules

Externals

Events

Namespaces

@@ -99,7 +99,7 @@

Panolens.js


- Documentation generated by JSDoc 3.6.2 on Wed Jun 12 2019 12:14:50 GMT-0700 (Pacific Daylight Time) using the docdash theme. + Documentation generated by JSDoc 3.6.10 on Wed Apr 27 2022 13:47:09 GMT+0200 (Central European Summer Time) using the docdash theme.
diff --git a/docs/Panorama.html b/docs/Panorama.html index e7879dad..a5a9eb4d 100644 --- a/docs/Panorama.html +++ b/docs/Panorama.html @@ -41,7 +41,7 @@ -

Home

Github

Classes

Modules

Externals

Events

Namespaces

+

Home

Github

Classes

Modules

Externals

Events

Namespaces

@@ -62,7 +62,7 @@

Panorama

-

Base Panorama

+

Base Panorama

@@ -249,144 +249,6 @@
Parameters:

Methods

- - - - -

add(object)

- - - - - - -
- - -
Source:
-
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
- - - - - -
-

Adding an object -To counter the scale.x = -1, it will automatically add an -empty object with inverted scale on x

-
- - - - - - - - - - - -
Parameters:
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
NameTypeDescription
object - - -THREE.Object3D - - - -

The object to be added

- - - - - - - - - - - - - - - - - - - - @@ -403,7 +265,7 @@

disposeSource:
@@ -442,7 +304,7 @@

dispose +

Dispose panorama

@@ -490,7 +352,7 @@

fadeInSource:
@@ -529,7 +391,7 @@

fadeIn +

Start fading in animation

@@ -582,7 +444,7 @@

fadeOutSource:
@@ -621,7 +483,7 @@

fadeOut +

Start fading out animation

@@ -669,7 +531,7 @@

getZoomLe
Source:
@@ -708,7 +570,7 @@

getZoomLe -
+

Get zoom level based on window width

@@ -778,7 +640,7 @@