\");\n const data = binary.substring(a, b);\n if (a !== -1 && b !== -1 && data.includes(\"GPano:\")) {\n return {\n fullWidth: getXMPValue(data, \"FullPanoWidthPixels\"),\n fullHeight: getXMPValue(data, \"FullPanoHeightPixels\"),\n croppedWidth: getXMPValue(data, \"CroppedAreaImageWidthPixels\"),\n croppedHeight: getXMPValue(data, \"CroppedAreaImageHeightPixels\"),\n croppedX: getXMPValue(data, \"CroppedAreaLeftPixels\"),\n croppedY: getXMPValue(data, \"CroppedAreaTopPixels\"),\n poseHeading: getXMPValue(data, \"PoseHeadingDegrees\"),\n posePitch: getXMPValue(data, \"PosePitchDegrees\"),\n poseRoll: getXMPValue(data, \"PoseRollDegrees\")\n };\n }\n return null;\n }\n /**\n * Reads a Blob as a string\n */\n loadBlobAsString(blob) {\n return new Promise((resolve, reject) => {\n const reader = new FileReader();\n reader.onload = () => resolve(reader.result);\n reader.onerror = reject;\n reader.readAsText(blob);\n });\n }\n /**\n * Creates the final texture from image and panorama data\n */\n createEquirectangularTexture(img, panoData) {\n if (this.config.blur || panoData.fullWidth > SYSTEM.maxTextureWidth || panoData.croppedWidth !== panoData.fullWidth || panoData.croppedHeight !== panoData.fullHeight) {\n const ratio = Math.min(1, SYSTEM.maxCanvasWidth / panoData.fullWidth);\n const resizedPanoData = {\n fullWidth: panoData.fullWidth * ratio,\n fullHeight: panoData.fullHeight * ratio,\n croppedWidth: panoData.croppedWidth * ratio,\n croppedHeight: panoData.croppedHeight * ratio,\n croppedX: panoData.croppedX * ratio,\n croppedY: panoData.croppedY * ratio\n };\n const buffer = document.createElement(\"canvas\");\n buffer.width = resizedPanoData.fullWidth;\n buffer.height = resizedPanoData.fullHeight;\n const ctx = buffer.getContext(\"2d\");\n if (this.config.backgroundColor) {\n ctx.fillStyle = this.config.backgroundColor;\n ctx.fillRect(0, 0, buffer.width, buffer.height);\n }\n if (this.config.blur) {\n ctx.filter = `blur(${buffer.width / 2048}px)`;\n }\n ctx.drawImage(\n img,\n resizedPanoData.croppedX,\n resizedPanoData.croppedY,\n resizedPanoData.croppedWidth,\n resizedPanoData.croppedHeight\n );\n const t = createTexture(buffer);\n if (this.config.interpolateBackground && (panoData.croppedWidth !== panoData.fullWidth || panoData.croppedHeight !== panoData.fullHeight)) {\n this.interpolationWorker.postMessage({\n image: ctx.getImageData(\n resizedPanoData.croppedX,\n resizedPanoData.croppedY,\n resizedPanoData.croppedWidth,\n resizedPanoData.croppedHeight\n ),\n panoData: resizedPanoData\n });\n this.interpolationWorker.onmessage = (e) => {\n ctx.putImageData(e.data, 0, 0);\n t.needsUpdate = true;\n this.viewer.needsUpdate();\n };\n }\n return t;\n }\n return createTexture(img);\n }\n createMesh(scale = 1) {\n const geometry = new SphereGeometry(\n SPHERE_RADIUS * scale,\n this.SPHERE_SEGMENTS,\n this.SPHERE_HORIZONTAL_SEGMENTS,\n -Math.PI / 2\n ).scale(-1, 1, 1);\n const material = AbstractAdapter.createOverlayMaterial();\n return new Mesh2(geometry, material);\n }\n setTexture(mesh, textureData) {\n this.__setUniform(mesh, AbstractAdapter.OVERLAY_UNIFORMS.panorama, textureData.texture);\n }\n setOverlay(mesh, textureData, opacity) {\n this.__setUniform(mesh, AbstractAdapter.OVERLAY_UNIFORMS.overlayOpacity, opacity);\n if (!textureData) {\n this.__setUniform(mesh, AbstractAdapter.OVERLAY_UNIFORMS.overlay, null);\n } else {\n this.__setUniform(mesh, AbstractAdapter.OVERLAY_UNIFORMS.overlay, textureData.texture);\n }\n }\n setTextureOpacity(mesh, opacity) {\n this.__setUniform(mesh, AbstractAdapter.OVERLAY_UNIFORMS.globalOpacity, opacity);\n mesh.material.transparent = opacity < 1;\n }\n disposeTexture(textureData) {\n textureData.texture?.dispose();\n }\n __setUniform(mesh, uniform, value) {\n mesh.material.uniforms[uniform].value = value;\n }\n __defaultPanoData(img) {\n const fullWidth = Math.max(img.width, img.height * 2);\n const fullHeight = Math.round(fullWidth / 2);\n const croppedX = Math.round((fullWidth - img.width) / 2);\n const croppedY = Math.round((fullHeight - img.height) / 2);\n return {\n fullWidth,\n fullHeight,\n croppedWidth: img.width,\n croppedHeight: img.height,\n croppedX,\n croppedY\n };\n }\n};\nEquirectangularAdapter.id = \"equirectangular\";\nEquirectangularAdapter.supportsDownload = true;\nEquirectangularAdapter.supportsOverlay = true;\n\n// src/components/AbstractComponent.ts\nvar AbstractComponent = class _AbstractComponent {\n constructor(parent, config) {\n this.parent = parent;\n /**\n * All child components\n * @internal\n */\n this.children = [];\n /**\n * Container element\n */\n this.container = document.createElement(\"div\");\n /**\n * Internal properties\n * @internal\n */\n this.state = {\n visible: true\n };\n this.viewer = parent instanceof _AbstractComponent ? parent.viewer : parent;\n this.container.className = config.className || \"\";\n this.parent.children.push(this);\n this.parent.container.appendChild(this.container);\n }\n /**\n * Destroys the component\n */\n destroy() {\n this.parent.container.removeChild(this.container);\n const childIdx = this.parent.children.indexOf(this);\n if (childIdx !== -1) {\n this.parent.children.splice(childIdx, 1);\n }\n this.children.slice().forEach((child) => child.destroy());\n this.children.length = 0;\n }\n /**\n * Displays or hides the component\n */\n toggle(visible = !this.isVisible()) {\n if (!visible) {\n this.hide();\n } else {\n this.show();\n }\n }\n /**\n * Hides the component\n */\n // @ts-ignore unused parameter\n // eslint-disable-next-line @typescript-eslint/no-unused-vars\n hide(options) {\n this.container.style.display = \"none\";\n this.state.visible = false;\n }\n /**\n * Displays the component\n */\n // @ts-ignore unused parameter\n // eslint-disable-next-line @typescript-eslint/no-unused-vars\n show(options) {\n this.container.style.display = \"\";\n this.state.visible = true;\n }\n /**\n * Checks if the component is visible\n */\n isVisible() {\n return this.state.visible;\n }\n};\n\n// src/buttons/AbstractButton.ts\nvar getConfig2 = getConfigParser({\n id: null,\n className: null,\n title: null,\n hoverScale: false,\n collapsable: false,\n tabbable: true,\n icon: null,\n iconActive: null\n});\nvar AbstractButton = class extends AbstractComponent {\n constructor(navbar, config) {\n super(navbar, {\n className: `psv-button ${config.hoverScale ? \"psv-button--hover-scale\" : \"\"} ${config.className || \"\"}`\n });\n /**\n * Internal properties\n */\n this.state = {\n visible: true,\n enabled: true,\n supported: true,\n collapsed: false,\n active: false,\n width: 0\n };\n this.config = getConfig2(config);\n this.config.id = this.constructor.id;\n if (config.icon) {\n this.__setIcon(config.icon);\n }\n this.state.width = this.container.offsetWidth;\n if (this.config.title) {\n this.container.title = this.config.title;\n } else if (this.id && this.id in this.viewer.config.lang) {\n this.container.title = this.viewer.config.lang[this.id];\n }\n if (config.tabbable) {\n this.container.tabIndex = 0;\n }\n this.container.addEventListener(\"click\", (e) => {\n if (this.state.enabled) {\n this.onClick();\n }\n e.stopPropagation();\n });\n this.container.addEventListener(\"keydown\", (e) => {\n if (e.key === KEY_CODES.Enter && this.state.enabled) {\n this.onClick();\n e.stopPropagation();\n }\n });\n }\n get id() {\n return this.config.id;\n }\n get title() {\n return this.container.title;\n }\n get content() {\n return this.container.innerHTML;\n }\n get width() {\n return this.state.width;\n }\n get collapsable() {\n return this.config.collapsable;\n }\n show(refresh = true) {\n if (!this.isVisible()) {\n this.state.visible = true;\n if (!this.state.collapsed) {\n this.container.style.display = \"\";\n }\n if (refresh) {\n this.viewer.navbar.autoSize();\n }\n }\n }\n hide(refresh = true) {\n if (this.isVisible()) {\n this.state.visible = false;\n this.container.style.display = \"none\";\n if (refresh) {\n this.viewer.navbar.autoSize();\n }\n }\n }\n /**\n * Hides/shows the button depending of the result of {@link isSupported}\n * @internal\n */\n checkSupported() {\n resolveBoolean(this.isSupported(), (supported, init) => {\n if (!this.state) {\n return;\n }\n this.state.supported = supported;\n if (!init) {\n this.toggle(supported);\n } else if (!supported) {\n this.hide();\n }\n });\n }\n /**\n * Perform action when the navbar size/content changes\n * @internal\n */\n autoSize() {\n }\n /**\n * Checks if the button can be displayed\n */\n isSupported() {\n return true;\n }\n /**\n * Changes the active state of the button\n */\n toggleActive(active = !this.state.active) {\n if (active !== this.state.active) {\n this.state.active = active;\n toggleClass(this.container, \"psv-button--active\", this.state.active);\n if (this.config.iconActive) {\n this.__setIcon(this.state.active ? this.config.iconActive : this.config.icon);\n }\n }\n }\n /**\n * Disables the button\n */\n disable() {\n this.container.classList.add(\"psv-button--disabled\");\n this.state.enabled = false;\n }\n /**\n * Enables the button\n */\n enable() {\n this.container.classList.remove(\"psv-button--disabled\");\n this.state.enabled = true;\n }\n /**\n * Collapses the button in the navbar menu\n */\n collapse() {\n this.state.collapsed = true;\n this.container.style.display = \"none\";\n }\n /**\n * Uncollapses the button from the navbar menu\n */\n uncollapse() {\n this.state.collapsed = false;\n if (this.state.visible) {\n this.container.style.display = \"\";\n }\n }\n __setIcon(icon) {\n this.container.innerHTML = icon;\n addClasses(this.container.querySelector(\"svg\"), \"psv-button-svg\");\n }\n};\n\n// src/buttons/CustomButton.ts\nvar CustomButton = class extends AbstractButton {\n constructor(navbar, config) {\n super(navbar, {\n className: `psv-custom-button ${config.className || \"\"}`,\n hoverScale: false,\n collapsable: config.collapsable !== false,\n tabbable: config.tabbable !== false,\n title: config.title\n });\n this.customOnClick = config.onClick;\n if (config.id) {\n this.config.id = config.id;\n } else {\n this.config.id = \"psvButton-\" + Math.random().toString(36).substring(2);\n }\n if (config.content) {\n this.container.innerHTML = config.content;\n }\n this.state.width = this.container.offsetWidth;\n if (config.disabled) {\n this.disable();\n }\n if (config.visible === false) {\n this.hide();\n }\n }\n onClick() {\n this.customOnClick?.(this.viewer);\n }\n};\n\n// src/buttons/DescriptionButton.ts\nvar DescriptionButton = class extends AbstractButton {\n constructor(navbar) {\n super(navbar, {\n className: \"psv-description-button\",\n hoverScale: true,\n collapsable: false,\n tabbable: true,\n icon: ICONS.info\n });\n this.mode = 0 /* NONE */;\n this.viewer.addEventListener(HideNotificationEvent.type, this);\n this.viewer.addEventListener(ShowNotificationEvent.type, this);\n this.viewer.addEventListener(HidePanelEvent.type, this);\n this.viewer.addEventListener(ShowPanelEvent.type, this);\n this.viewer.addEventListener(ConfigChangedEvent.type, this);\n }\n destroy() {\n this.viewer.removeEventListener(HideNotificationEvent.type, this);\n this.viewer.removeEventListener(ShowNotificationEvent.type, this);\n this.viewer.removeEventListener(HidePanelEvent.type, this);\n this.viewer.removeEventListener(ShowPanelEvent.type, this);\n this.viewer.removeEventListener(ConfigChangedEvent.type, this);\n super.destroy();\n }\n handleEvent(e) {\n if (e instanceof ConfigChangedEvent) {\n e.containsOptions(\"description\") && this.autoSize(true);\n return;\n }\n if (!this.mode) {\n return;\n }\n let closed = false;\n if (e instanceof HideNotificationEvent) {\n closed = this.mode === 1 /* NOTIF */;\n } else if (e instanceof ShowNotificationEvent) {\n closed = this.mode === 1 /* NOTIF */ && e.notificationId !== IDS.DESCRIPTION;\n } else if (e instanceof HidePanelEvent) {\n closed = this.mode === 2 /* PANEL */;\n } else if (e instanceof ShowPanelEvent) {\n closed = this.mode === 2 /* PANEL */ && e.panelId !== IDS.DESCRIPTION;\n }\n if (closed) {\n this.toggleActive(false);\n this.mode = 0 /* NONE */;\n }\n }\n onClick() {\n if (this.mode) {\n this.__close();\n } else {\n this.__open();\n }\n }\n hide(refresh) {\n super.hide(refresh);\n if (this.mode) {\n this.__close();\n }\n }\n /**\n * This button can only be refreshed from NavbarCaption\n * @internal\n */\n autoSize(refresh = false) {\n if (refresh) {\n const caption = this.viewer.navbar.getButton(\"caption\", false);\n const captionHidden = caption && !caption.isVisible();\n const hasDescription = !!this.viewer.config.description;\n if (captionHidden || hasDescription) {\n this.show(false);\n } else {\n this.hide(false);\n }\n }\n }\n __close() {\n switch (this.mode) {\n case 1 /* NOTIF */:\n this.viewer.notification.hide(IDS.DESCRIPTION);\n break;\n case 2 /* PANEL */:\n this.viewer.panel.hide(IDS.DESCRIPTION);\n break;\n default:\n }\n }\n __open() {\n this.toggleActive(true);\n if (this.viewer.config.description) {\n this.mode = 2 /* PANEL */;\n this.viewer.panel.show({\n id: IDS.DESCRIPTION,\n content: (this.viewer.config.caption ? `${this.viewer.config.caption}
` : \"\") + this.viewer.config.description\n });\n } else {\n this.mode = 1 /* NOTIF */;\n this.viewer.notification.show({\n id: IDS.DESCRIPTION,\n content: this.viewer.config.caption\n });\n }\n }\n};\nDescriptionButton.id = \"description\";\n\n// src/buttons/DownloadButton.ts\nvar DownloadButton = class extends AbstractButton {\n constructor(navbar) {\n super(navbar, {\n className: \"psv-download-button\",\n hoverScale: true,\n collapsable: true,\n tabbable: true,\n icon: ICONS.download\n });\n this.viewer.addEventListener(ConfigChangedEvent.type, this);\n }\n destroy() {\n this.viewer.removeEventListener(ConfigChangedEvent.type, this);\n super.destroy();\n }\n handleEvent(e) {\n if (e instanceof ConfigChangedEvent) {\n e.containsOptions(\"downloadUrl\") && this.checkSupported();\n }\n }\n onClick() {\n const link = document.createElement(\"a\");\n link.href = this.viewer.config.downloadUrl || this.viewer.config.panorama;\n if (link.href.startsWith(\"data:\") && !this.viewer.config.downloadName) {\n link.download = \"panorama.\" + link.href.substring(0, link.href.indexOf(\";\")).split(\"/\").pop();\n } else {\n link.download = this.viewer.config.downloadName || link.href.split(\"/\").pop();\n }\n link.target = \"_blank\";\n this.viewer.container.appendChild(link);\n link.click();\n setTimeout(() => {\n this.viewer.container.removeChild(link);\n }, 100);\n }\n checkSupported() {\n const supported = this.viewer.adapter.constructor.supportsDownload || this.viewer.config.downloadUrl;\n if (supported) {\n this.show();\n } else {\n this.hide();\n }\n }\n};\nDownloadButton.id = \"download\";\n\n// src/buttons/FullscreenButton.ts\nvar FullscreenButton = class extends AbstractButton {\n constructor(navbar) {\n super(navbar, {\n className: \"psv-fullscreen-button\",\n hoverScale: true,\n collapsable: false,\n tabbable: true,\n icon: ICONS.fullscreenIn,\n iconActive: ICONS.fullscreenOut\n });\n this.viewer.addEventListener(FullscreenEvent.type, this);\n }\n destroy() {\n this.viewer.removeEventListener(FullscreenEvent.type, this);\n super.destroy();\n }\n handleEvent(e) {\n if (e instanceof FullscreenEvent) {\n this.toggleActive(e.fullscreenEnabled);\n }\n }\n onClick() {\n this.viewer.toggleFullscreen();\n }\n};\nFullscreenButton.id = \"fullscreen\";\n\n// src/buttons/MenuButton.ts\nvar BUTTON_DATA = \"psvButton\";\nvar MENU_TEMPLATE = (buttons, title) => `\n\n`;\nvar MenuButton = class extends AbstractButton {\n constructor(navbar) {\n super(navbar, {\n className: \"psv-menu-button\",\n hoverScale: true,\n collapsable: false,\n tabbable: true,\n icon: ICONS.menu\n });\n this.viewer.addEventListener(ShowPanelEvent.type, this);\n this.viewer.addEventListener(HidePanelEvent.type, this);\n super.hide();\n }\n destroy() {\n this.viewer.removeEventListener(ShowPanelEvent.type, this);\n this.viewer.removeEventListener(HidePanelEvent.type, this);\n super.destroy();\n }\n handleEvent(e) {\n if (e instanceof ShowPanelEvent) {\n this.toggleActive(e.panelId === IDS.MENU);\n } else if (e instanceof HidePanelEvent) {\n this.toggleActive(false);\n }\n }\n onClick() {\n if (this.state.active) {\n this.__hideMenu();\n } else {\n this.__showMenu();\n }\n }\n hide(refresh) {\n super.hide(refresh);\n this.__hideMenu();\n }\n show(refresh) {\n super.show(refresh);\n if (this.state.active) {\n this.__showMenu();\n }\n }\n __showMenu() {\n this.viewer.panel.show({\n id: IDS.MENU,\n content: MENU_TEMPLATE(this.viewer.navbar.collapsed, this.viewer.config.lang.menu),\n noMargin: true,\n clickHandler: (target) => {\n const li = target ? getClosest(target, \"li\") : void 0;\n const buttonId = li ? li.dataset[BUTTON_DATA] : void 0;\n if (buttonId) {\n this.viewer.navbar.getButton(buttonId).onClick();\n this.__hideMenu();\n }\n }\n });\n }\n __hideMenu() {\n this.viewer.panel.hide(IDS.MENU);\n }\n};\nMenuButton.id = \"menu\";\n\n// src/buttons/AbstractMoveButton.ts\nfunction getIcon(value) {\n let angle2 = 0;\n switch (value) {\n case 0 /* UP */:\n angle2 = 90;\n break;\n case 1 /* DOWN */:\n angle2 = -90;\n break;\n case 3 /* RIGHT */:\n angle2 = 180;\n break;\n default:\n angle2 = 0;\n break;\n }\n return ICONS.arrow.replace(\"rotate(0\", `rotate(${angle2}`);\n}\nvar AbstractMoveButton = class extends AbstractButton {\n constructor(navbar, direction) {\n super(navbar, {\n className: \"psv-move-button\",\n hoverScale: true,\n collapsable: false,\n tabbable: true,\n icon: getIcon(direction)\n });\n this.direction = direction;\n this.handler = new PressHandler();\n this.container.addEventListener(\"mousedown\", this);\n this.container.addEventListener(\"keydown\", this);\n this.container.addEventListener(\"keyup\", this);\n this.viewer.container.addEventListener(\"mouseup\", this);\n this.viewer.container.addEventListener(\"touchend\", this);\n }\n destroy() {\n this.__onMouseUp();\n this.viewer.container.removeEventListener(\"mouseup\", this);\n this.viewer.container.removeEventListener(\"touchend\", this);\n super.destroy();\n }\n handleEvent(e) {\n switch (e.type) {\n case \"mousedown\":\n this.__onMouseDown();\n break;\n case \"mouseup\":\n this.__onMouseUp();\n break;\n case \"touchend\":\n this.__onMouseUp();\n break;\n case \"keydown\":\n e.key === KEY_CODES.Enter && this.__onMouseDown();\n break;\n case \"keyup\":\n e.key === KEY_CODES.Enter && this.__onMouseUp();\n break;\n }\n }\n onClick() {\n }\n isSupported() {\n return invertResolvableBoolean(SYSTEM.isTouchEnabled);\n }\n __onMouseDown() {\n if (!this.state.enabled) {\n return;\n }\n const dynamicRoll = {};\n switch (this.direction) {\n case 0 /* UP */:\n dynamicRoll.pitch = false;\n break;\n case 1 /* DOWN */:\n dynamicRoll.pitch = true;\n break;\n case 3 /* RIGHT */:\n dynamicRoll.yaw = false;\n break;\n default:\n dynamicRoll.yaw = true;\n break;\n }\n this.viewer.stopAll();\n this.viewer.dynamics.position.roll(dynamicRoll);\n this.handler.down();\n }\n __onMouseUp() {\n if (!this.state.enabled) {\n return;\n }\n this.handler.up(() => {\n this.viewer.dynamics.position.stop();\n this.viewer.resetIdleTimer();\n });\n }\n};\nAbstractMoveButton.groupId = \"move\";\n\n// src/buttons/MoveDownButton.ts\nvar MoveDownButton = class extends AbstractMoveButton {\n constructor(navbar) {\n super(navbar, 1 /* DOWN */);\n }\n};\nMoveDownButton.id = \"moveDown\";\n\n// src/buttons/MoveLeftButton.ts\nvar MoveLeftButton = class extends AbstractMoveButton {\n constructor(navbar) {\n super(navbar, 2 /* LEFT */);\n }\n};\nMoveLeftButton.id = \"moveLeft\";\n\n// src/buttons/MoveRightButton.ts\nvar MoveRightButton = class extends AbstractMoveButton {\n constructor(navbar) {\n super(navbar, 3 /* RIGHT */);\n }\n};\nMoveRightButton.id = \"moveRight\";\n\n// src/buttons/MoveUpButton.ts\nvar MoveUpButton = class extends AbstractMoveButton {\n constructor(navbar) {\n super(navbar, 0 /* UP */);\n }\n};\nMoveUpButton.id = \"moveUp\";\n\n// src/buttons/AbstractZoomButton.ts\nvar AbstractZoomButton = class extends AbstractButton {\n constructor(navbar, icon, direction) {\n super(navbar, {\n className: \"psv-zoom-button\",\n hoverScale: true,\n collapsable: false,\n tabbable: true,\n icon\n });\n this.direction = direction;\n this.handler = new PressHandler();\n this.container.addEventListener(\"mousedown\", this);\n this.container.addEventListener(\"keydown\", this);\n this.container.addEventListener(\"keyup\", this);\n this.viewer.container.addEventListener(\"mouseup\", this);\n this.viewer.container.addEventListener(\"touchend\", this);\n }\n destroy() {\n this.__onMouseUp();\n this.viewer.container.removeEventListener(\"mouseup\", this);\n this.viewer.container.removeEventListener(\"touchend\", this);\n super.destroy();\n }\n handleEvent(e) {\n switch (e.type) {\n case \"mousedown\":\n this.__onMouseDown();\n break;\n case \"mouseup\":\n this.__onMouseUp();\n break;\n case \"touchend\":\n this.__onMouseUp();\n break;\n case \"keydown\":\n e.key === KEY_CODES.Enter && this.__onMouseDown();\n break;\n case \"keyup\":\n e.key === KEY_CODES.Enter && this.__onMouseUp();\n break;\n }\n }\n onClick() {\n }\n isSupported() {\n return invertResolvableBoolean(SYSTEM.isTouchEnabled);\n }\n __onMouseDown() {\n if (!this.state.enabled) {\n return;\n }\n this.viewer.dynamics.zoom.roll(this.direction === 1 /* OUT */);\n this.handler.down();\n }\n __onMouseUp() {\n if (!this.state.enabled) {\n return;\n }\n this.handler.up(() => this.viewer.dynamics.zoom.stop());\n }\n};\nAbstractZoomButton.groupId = \"zoom\";\n\n// src/buttons/ZoomInButton.ts\nvar ZoomInButton = class extends AbstractZoomButton {\n constructor(navbar) {\n super(navbar, ICONS.zoomIn, 0 /* IN */);\n }\n};\nZoomInButton.id = \"zoomIn\";\n\n// src/buttons/ZoomOutButton.ts\nvar ZoomOutButton = class extends AbstractZoomButton {\n constructor(navbar) {\n super(navbar, ICONS.zoomOut, 1 /* OUT */);\n }\n};\nZoomOutButton.id = \"zoomOut\";\n\n// src/buttons/ZoomRangeButton.ts\nvar ZoomRangeButton = class extends AbstractButton {\n constructor(navbar) {\n super(navbar, {\n className: \"psv-zoom-range\",\n hoverScale: false,\n collapsable: false,\n tabbable: false\n });\n this.zoomRange = document.createElement(\"div\");\n this.zoomRange.className = \"psv-zoom-range-line\";\n this.container.appendChild(this.zoomRange);\n this.zoomValue = document.createElement(\"div\");\n this.zoomValue.className = \"psv-zoom-range-handle\";\n this.zoomRange.appendChild(this.zoomValue);\n this.slider = new Slider(this.container, \"HORIZONTAL\" /* HORIZONTAL */, (data) => this.__onSliderUpdate(data));\n this.mediaMinWidth = parseInt(getStyleProperty(this.container, \"max-width\"), 10);\n this.viewer.addEventListener(ZoomUpdatedEvent.type, this);\n if (this.viewer.state.ready) {\n this.__moveZoomValue(this.viewer.getZoomLevel());\n } else {\n this.viewer.addEventListener(ReadyEvent.type, this);\n }\n }\n destroy() {\n this.slider.destroy();\n this.viewer.removeEventListener(ZoomUpdatedEvent.type, this);\n this.viewer.removeEventListener(ReadyEvent.type, this);\n super.destroy();\n }\n handleEvent(e) {\n if (e instanceof ZoomUpdatedEvent) {\n this.__moveZoomValue(e.zoomLevel);\n } else if (e instanceof ReadyEvent) {\n this.__moveZoomValue(this.viewer.getZoomLevel());\n }\n }\n onClick() {\n }\n isSupported() {\n return invertResolvableBoolean(SYSTEM.isTouchEnabled);\n }\n autoSize() {\n if (this.state.supported) {\n if (this.viewer.state.size.width <= this.mediaMinWidth && this.state.visible) {\n this.hide(false);\n } else if (this.viewer.state.size.width > this.mediaMinWidth && !this.state.visible) {\n this.show(false);\n }\n }\n }\n __moveZoomValue(level) {\n this.zoomValue.style.left = level / 100 * this.zoomRange.offsetWidth - this.zoomValue.offsetWidth / 2 + \"px\";\n }\n __onSliderUpdate(data) {\n if (data.mousedown) {\n this.viewer.zoom(data.value * 100);\n }\n }\n};\nZoomRangeButton.id = \"zoomRange\";\nZoomRangeButton.groupId = \"zoom\";\n\n// src/data/config.ts\nimport { MathUtils as MathUtils4 } from \"three\";\n\n// src/plugins/AbstractPlugin.ts\nvar AbstractPlugin = class extends TypedEventTarget {\n constructor(viewer) {\n super();\n this.viewer = viewer;\n }\n /**\n * Initializes the plugin\n */\n // eslint-disable-next-line @typescript-eslint/no-empty-function\n init() {\n }\n /**\n * Destroys the plugin\n */\n // eslint-disable-next-line @typescript-eslint/no-empty-function\n destroy() {\n }\n};\nvar AbstractConfigurablePlugin = class extends AbstractPlugin {\n constructor(viewer, config) {\n super(viewer);\n this.config = this.constructor.configParser(config);\n }\n /**\n * Update options\n */\n setOption(option, value) {\n this.setOptions({ [option]: value });\n }\n /**\n * Update options\n */\n setOptions(options) {\n const rawConfig = {\n ...this.config,\n ...options\n };\n const ctor = this.constructor;\n const parser = ctor.configParser;\n const readonly = ctor.readonlyOptions;\n const id = ctor.id;\n for (let [key, value] of Object.entries(options)) {\n if (!(key in parser.defaults)) {\n logWarn(`${id}: Unknown option \"${key}\"`);\n continue;\n }\n if (readonly.includes(key)) {\n logWarn(`${id}: Option \"${key}\" cannot be updated`);\n continue;\n }\n if (key in parser.parsers) {\n value = parser.parsers[key](value, {\n rawConfig,\n defValue: parser.defaults[key]\n });\n }\n this.config[key] = value;\n }\n }\n};\nAbstractConfigurablePlugin.readonlyOptions = [];\nfunction pluginInterop(plugin) {\n if (plugin) {\n for (const [, p] of [[\"_\", plugin], ...Object.entries(plugin)]) {\n if (p.prototype instanceof AbstractPlugin) {\n return p;\n }\n }\n }\n return null;\n}\n\n// src/data/config.ts\nvar DEFAULTS = {\n panorama: null,\n overlay: null,\n overlayOpacity: 1,\n container: null,\n adapter: [EquirectangularAdapter, null],\n plugins: [],\n caption: null,\n description: null,\n downloadUrl: null,\n downloadName: null,\n loadingImg: null,\n loadingTxt: \"Loading...\",\n size: null,\n fisheye: 0,\n minFov: 30,\n maxFov: 90,\n defaultZoomLvl: 50,\n defaultYaw: 0,\n defaultPitch: 0,\n sphereCorrection: null,\n moveSpeed: 1,\n zoomSpeed: 1,\n moveInertia: true,\n mousewheel: true,\n mousemove: true,\n mousewheelCtrlKey: false,\n touchmoveTwoFingers: false,\n useXmpData: null,\n panoData: null,\n requestHeaders: null,\n canvasBackground: null,\n rendererParameters: { alpha: true, antialias: true },\n withCredentials: false,\n // prettier-ignore\n navbar: [\n \"zoom\",\n \"move\",\n \"download\",\n \"description\",\n \"caption\",\n \"fullscreen\"\n ],\n lang: {\n zoom: \"Zoom\",\n zoomOut: \"Zoom out\",\n zoomIn: \"Zoom in\",\n moveUp: \"Move up\",\n moveDown: \"Move down\",\n moveLeft: \"Move left\",\n moveRight: \"Move right\",\n download: \"Download\",\n fullscreen: \"Fullscreen\",\n menu: \"Menu\",\n close: \"Close\",\n twoFingers: \"Use two fingers to navigate\",\n ctrlZoom: \"Use ctrl + scroll to zoom the image\",\n loadError: \"The panorama can't be loaded\"\n },\n keyboard: \"fullscreen\",\n keyboardActions: {\n [KEY_CODES.ArrowUp]: \"ROTATE_UP\" /* ROTATE_UP */,\n [KEY_CODES.ArrowDown]: \"ROTATE_DOWN\" /* ROTATE_DOWN */,\n [KEY_CODES.ArrowRight]: \"ROTATE_RIGHT\" /* ROTATE_RIGHT */,\n [KEY_CODES.ArrowLeft]: \"ROTATE_LEFT\" /* ROTATE_LEFT */,\n [KEY_CODES.PageUp]: \"ZOOM_IN\" /* ZOOM_IN */,\n [KEY_CODES.PageDown]: \"ZOOM_OUT\" /* ZOOM_OUT */,\n [KEY_CODES.Plus]: \"ZOOM_IN\" /* ZOOM_IN */,\n [KEY_CODES.Minus]: \"ZOOM_OUT\" /* ZOOM_OUT */\n }\n};\nvar READONLY_OPTIONS = {\n panorama: \"Use setPanorama method to change the panorama\",\n panoData: \"Use setPanorama method to change the panorama\",\n overlay: \"Use setOverlay method to changer the overlay\",\n overlayOpacity: \"Use setOverlay method to changer the overlay\",\n container: \"Cannot change viewer container\",\n adapter: \"Cannot change adapter\",\n plugins: \"Cannot change plugins\"\n};\nvar CONFIG_PARSERS = {\n container: (container) => {\n if (!container) {\n throw new PSVError(\"No value given for container.\");\n }\n return container;\n },\n adapter: (adapter, { defValue }) => {\n if (!adapter) {\n adapter = defValue;\n } else if (Array.isArray(adapter)) {\n adapter = [adapterInterop(adapter[0]), adapter[1]];\n } else {\n adapter = [adapterInterop(adapter), null];\n }\n if (!adapter[0]) {\n throw new PSVError(\"An undefined value was given for adapter.\");\n }\n if (!adapter[0].id) {\n throw new PSVError(`Adapter has no id.`);\n }\n return adapter;\n },\n overlayOpacity: (overlayOpacity) => {\n return MathUtils4.clamp(overlayOpacity, 0, 1);\n },\n defaultYaw: (defaultYaw) => {\n return parseAngle(defaultYaw);\n },\n defaultPitch: (defaultPitch) => {\n return parseAngle(defaultPitch, true);\n },\n defaultZoomLvl: (defaultZoomLvl) => {\n return MathUtils4.clamp(defaultZoomLvl, 0, 100);\n },\n minFov: (minFov, { rawConfig }) => {\n if (rawConfig.maxFov < minFov) {\n logWarn(\"maxFov cannot be lower than minFov\");\n minFov = rawConfig.maxFov;\n }\n return MathUtils4.clamp(minFov, 1, 179);\n },\n maxFov: (maxFov, { rawConfig }) => {\n if (maxFov < rawConfig.minFov) {\n maxFov = rawConfig.minFov;\n }\n return MathUtils4.clamp(maxFov, 1, 179);\n },\n lang: (lang) => {\n if (Array.isArray(lang.twoFingers)) {\n logWarn(\"lang.twoFingers must not be an array\");\n lang.twoFingers = lang.twoFingers[0];\n }\n return {\n ...DEFAULTS.lang,\n ...lang\n };\n },\n keyboard: (keyboard) => {\n if (!keyboard) {\n return false;\n }\n if (typeof keyboard === \"object\") {\n logWarn(`Use keyboardActions to configure the keyboard actions, keyboard option must be either true, false, 'fullscreen' or 'always'`);\n return \"fullscreen\";\n }\n return keyboard === \"always\" ? \"always\" : \"fullscreen\";\n },\n keyboardActions: (keyboardActions, { rawConfig }) => {\n if (rawConfig.keyboard && typeof rawConfig.keyboard === \"object\") {\n return rawConfig.keyboard;\n }\n return keyboardActions;\n },\n fisheye: (fisheye) => {\n if (fisheye === true) {\n return 1;\n } else if (fisheye === false) {\n return 0;\n }\n return fisheye;\n },\n requestHeaders: (requestHeaders) => {\n if (requestHeaders && typeof requestHeaders === \"object\") {\n return () => requestHeaders;\n }\n if (typeof requestHeaders === \"function\") {\n return requestHeaders;\n }\n return null;\n },\n rendererParameters: (rendererParameters, { defValue }) => ({\n ...rendererParameters,\n ...defValue\n }),\n plugins: (plugins) => {\n return plugins.map((plugin, i) => {\n if (Array.isArray(plugin)) {\n plugin = [pluginInterop(plugin[0]), plugin[1]];\n } else {\n plugin = [pluginInterop(plugin), null];\n }\n if (!plugin[0]) {\n throw new PSVError(`An undefined value was given for plugin ${i}.`);\n }\n if (!plugin[0].id) {\n throw new PSVError(`Plugin ${i} has no id.`);\n }\n return plugin;\n });\n },\n navbar: (navbar) => {\n if (navbar === false) {\n return null;\n }\n if (navbar === true) {\n return clone(DEFAULTS.navbar);\n }\n if (typeof navbar === \"string\") {\n return navbar.split(/[ ,]/);\n }\n return navbar;\n },\n useXmpData: (useXmpData) => {\n if (useXmpData !== null) {\n logWarn(`Global useXmpData is deprecated, it is now configured on the adapter.`);\n }\n return useXmpData;\n },\n canvasBackground: (canvasBackground) => {\n if (canvasBackground !== null) {\n logWarn(`Global canvasBackground is deprecated, it is now configured on the adapter.`);\n }\n return canvasBackground;\n }\n};\nvar getViewerConfig = getConfigParser(DEFAULTS, CONFIG_PARSERS);\n\n// src/components/NavbarCaption.ts\nvar NavbarCaption = class extends AbstractButton {\n constructor(navbar) {\n super(navbar, {\n className: \"psv-caption\",\n hoverScale: false,\n collapsable: false,\n tabbable: true\n });\n this.contentWidth = 0;\n this.state.width = 0;\n this.contentElt = document.createElement(\"div\");\n this.contentElt.className = \"psv-caption-content\";\n this.container.appendChild(this.contentElt);\n this.setCaption(this.viewer.config.caption);\n }\n hide() {\n this.contentElt.style.display = \"none\";\n this.state.visible = false;\n }\n show() {\n this.contentElt.style.display = \"\";\n this.state.visible = true;\n }\n onClick() {\n }\n /**\n * Changes the caption\n */\n setCaption(html) {\n this.show();\n this.contentElt.innerHTML = html ?? \"\";\n if (this.contentElt.innerHTML) {\n this.contentWidth = this.contentElt.offsetWidth;\n } else {\n this.contentWidth = 0;\n }\n this.autoSize();\n }\n /**\n * Toggles content and icon depending on available space\n */\n autoSize() {\n this.toggle(this.container.offsetWidth >= this.contentWidth);\n this.__refreshButton();\n }\n __refreshButton() {\n this.viewer.navbar.getButton(DescriptionButton.id, false)?.autoSize(true);\n }\n};\nNavbarCaption.id = \"caption\";\n\n// src/components/Navbar.ts\nvar AVAILABLE_BUTTONS = {};\nvar AVAILABLE_GROUPS = {};\nfunction registerButton(button, defaultPosition) {\n if (!button.id) {\n throw new PSVError(\"Button id is required\");\n }\n AVAILABLE_BUTTONS[button.id] = button;\n if (button.groupId) {\n (AVAILABLE_GROUPS[button.groupId] = AVAILABLE_GROUPS[button.groupId] || []).push(button);\n }\n if (defaultPosition) {\n const navbar = DEFAULTS.navbar;\n switch (defaultPosition) {\n case \"start\":\n navbar.unshift(button.id);\n break;\n case \"end\":\n navbar.push(button.id);\n break;\n default: {\n const [id, pos] = defaultPosition.split(\":\");\n const idx = navbar.indexOf(id);\n if (!id || !pos || idx === -1) {\n throw new PSVError(`Invalid defaultPosition ${defaultPosition}`);\n }\n navbar.splice(idx + (pos === \"right\" ? 1 : 0), 0, button.id);\n }\n }\n }\n}\n[\n ZoomOutButton,\n ZoomRangeButton,\n ZoomInButton,\n DescriptionButton,\n NavbarCaption,\n DownloadButton,\n FullscreenButton,\n MoveLeftButton,\n MoveRightButton,\n MoveUpButton,\n MoveDownButton\n].forEach((btn) => registerButton(btn));\nvar Navbar = class extends AbstractComponent {\n /**\n * @internal\n */\n constructor(viewer) {\n super(viewer, {\n className: `psv-navbar ${CAPTURE_EVENTS_CLASS}`\n });\n /**\n * @internal\n */\n this.collapsed = [];\n this.state.visible = false;\n }\n /**\n * Shows the navbar\n */\n show() {\n this.viewer.container.classList.add(\"psv--has-navbar\");\n this.container.classList.add(\"psv-navbar--open\");\n this.state.visible = true;\n }\n /**\n * Hides the navbar\n */\n hide() {\n this.viewer.container.classList.remove(\"psv--has-navbar\");\n this.container.classList.remove(\"psv-navbar--open\");\n this.state.visible = false;\n }\n /**\n * Change the buttons visible on the navbar\n */\n setButtons(buttons) {\n this.children.slice().forEach((item) => item.destroy());\n this.children.length = 0;\n if (buttons.indexOf(NavbarCaption.id) !== -1 && buttons.indexOf(DescriptionButton.id) === -1) {\n buttons.splice(buttons.indexOf(NavbarCaption.id), 0, DescriptionButton.id);\n }\n buttons.forEach((button) => {\n if (typeof button === \"object\") {\n new CustomButton(this, button);\n } else if (AVAILABLE_BUTTONS[button]) {\n new AVAILABLE_BUTTONS[button](this);\n } else if (AVAILABLE_GROUPS[button]) {\n AVAILABLE_GROUPS[button].forEach((buttonCtor) => {\n new buttonCtor(this);\n });\n } else {\n logWarn(`Unknown button ${button}`);\n }\n });\n new MenuButton(this);\n this.children.forEach((item) => {\n if (item instanceof AbstractButton) {\n item.checkSupported();\n }\n });\n this.autoSize();\n }\n /**\n * Changes the navbar caption\n */\n setCaption(html) {\n this.children.some((item) => {\n if (item instanceof NavbarCaption) {\n item.setCaption(html);\n return true;\n } else {\n return false;\n }\n });\n }\n /**\n * Returns a button by its identifier\n */\n getButton(id, warnNotFound = true) {\n const button = this.children.find((item) => {\n return item instanceof AbstractButton && item.id === id;\n });\n if (!button && warnNotFound) {\n logWarn(`button \"${id}\" not found in the navbar`);\n }\n return button;\n }\n /**\n * Automatically collapses buttons\n * @internal\n */\n autoSize() {\n this.children.forEach((child) => {\n if (child instanceof AbstractButton) {\n child.autoSize();\n }\n });\n const availableWidth = this.container.offsetWidth;\n let totalWidth = 0;\n const collapsableButtons = [];\n this.children.forEach((item) => {\n if (item.isVisible() && item instanceof AbstractButton) {\n totalWidth += item.width;\n if (item.collapsable) {\n collapsableButtons.push(item);\n }\n }\n });\n if (totalWidth === 0) {\n return;\n }\n if (availableWidth < totalWidth && collapsableButtons.length > 0) {\n collapsableButtons.forEach((item) => item.collapse());\n this.collapsed = collapsableButtons;\n this.getButton(MenuButton.id).show(false);\n } else if (availableWidth >= totalWidth && this.collapsed.length > 0) {\n this.collapsed.forEach((item) => item.uncollapse());\n this.collapsed = [];\n this.getButton(MenuButton.id).hide(false);\n }\n this.getButton(NavbarCaption.id, false)?.autoSize();\n }\n};\n\n// src/components/Loader.ts\nvar Loader = class extends AbstractComponent {\n /**\n * @internal\n */\n constructor(viewer) {\n super(viewer, { className: \"psv-loader-container\" });\n this.loader = document.createElement(\"div\");\n this.loader.className = \"psv-loader\";\n this.container.appendChild(this.loader);\n this.size = this.loader.offsetWidth;\n this.canvas = document.createElementNS(\"http://www.w3.org/2000/svg\", \"svg\");\n this.canvas.setAttribute(\"class\", \"psv-loader-canvas\");\n this.canvas.setAttribute(\"viewBox\", `0 0 ${this.size} ${this.size}`);\n this.loader.appendChild(this.canvas);\n this.textColor = getStyleProperty(this.loader, \"color\");\n this.color = getStyleProperty(this.canvas, \"color\");\n this.border = parseInt(getStyleProperty(this.loader, \"--psv-loader-border\"), 10);\n this.thickness = parseInt(getStyleProperty(this.loader, \"--psv-loader-tickness\"), 10);\n this.viewer.addEventListener(ConfigChangedEvent.type, this);\n this.__updateContent();\n this.hide();\n }\n /**\n * @internal\n */\n destroy() {\n this.viewer.removeEventListener(ConfigChangedEvent.type, this);\n super.destroy();\n }\n /**\n * @internal\n */\n handleEvent(e) {\n if (e instanceof ConfigChangedEvent) {\n e.containsOptions(\"loadingImg\", \"loadingTxt\") && this.__updateContent();\n }\n }\n /**\n * Sets the loader progression\n */\n setProgress(value) {\n const angle2 = Math.min(value, 99.999) / 100 * Math.PI * 2;\n const halfSize = this.size / 2;\n const startX = halfSize;\n const startY = this.thickness / 2 + this.border;\n const radius = (this.size - this.thickness) / 2 - this.border;\n const endX = Math.sin(angle2) * radius + halfSize;\n const endY = -Math.cos(angle2) * radius + halfSize;\n const largeArc = value > 50 ? \"1\" : \"0\";\n this.canvas.innerHTML = `\n \n \n `;\n this.viewer.dispatchEvent(new LoadProgressEvent(Math.round(value)));\n }\n __updateContent() {\n const current = this.loader.querySelector(\".psv-loader-image, .psv-loader-text\");\n if (current) {\n this.loader.removeChild(current);\n }\n let inner;\n if (this.viewer.config.loadingImg) {\n inner = document.createElement(\"img\");\n inner.className = \"psv-loader-image\";\n inner.src = this.viewer.config.loadingImg;\n } else if (this.viewer.config.loadingTxt) {\n inner = document.createElement(\"div\");\n inner.className = \"psv-loader-text\";\n inner.innerHTML = this.viewer.config.loadingTxt;\n }\n if (inner) {\n const size = Math.round(Math.sqrt(2 * Math.pow(this.size / 2 - this.thickness / 2 - this.border, 2)));\n inner.style.maxWidth = size + \"px\";\n inner.style.maxHeight = size + \"px\";\n this.loader.appendChild(inner);\n }\n }\n};\n\n// src/components/Notification.ts\nvar Notification = class extends AbstractComponent {\n /**\n * @internal\n */\n constructor(viewer) {\n super(viewer, {\n className: \"psv-notification\"\n });\n /**\n * @internal\n */\n this.state = {\n visible: false,\n contentId: null,\n timeout: null\n };\n this.content = document.createElement(\"div\");\n this.content.className = \"psv-notification-content\";\n this.container.appendChild(this.content);\n this.content.addEventListener(\"click\", () => this.hide());\n }\n /**\n * Checks if the notification is visible\n */\n isVisible(id) {\n return this.state.visible && (!id || !this.state.contentId || this.state.contentId === id);\n }\n /**\n * @throws {@link PSVError} always\n * @internal\n */\n toggle() {\n throw new PSVError(\"Notification cannot be toggled\");\n }\n /**\n * Displays a notification on the viewer\n *\n * @example\n * viewer.showNotification({ content: 'Hello world', timeout: 5000 })\n * @example\n * viewer.showNotification('Hello world')\n */\n show(config) {\n if (this.state.timeout) {\n clearTimeout(this.state.timeout);\n this.state.timeout = null;\n }\n if (typeof config === \"string\") {\n config = { content: config };\n }\n this.state.contentId = config.id || null;\n this.content.innerHTML = config.content;\n this.container.classList.add(\"psv-notification--visible\");\n this.state.visible = true;\n this.viewer.dispatchEvent(new ShowNotificationEvent(config.id));\n if (config.timeout) {\n this.state.timeout = setTimeout(() => this.hide(this.state.contentId), config.timeout);\n }\n }\n /**\n * Hides the notification\n */\n hide(id) {\n if (this.isVisible(id)) {\n const contentId = this.state.contentId;\n this.container.classList.remove(\"psv-notification--visible\");\n this.state.visible = false;\n this.state.contentId = null;\n this.viewer.dispatchEvent(new HideNotificationEvent(contentId));\n }\n }\n};\n\n// src/components/Overlay.ts\nvar Overlay = class extends AbstractComponent {\n /**\n * @internal\n */\n constructor(viewer) {\n super(viewer, {\n className: `psv-overlay ${CAPTURE_EVENTS_CLASS}`\n });\n /**\n * @internal\n */\n this.state = {\n visible: false,\n contentId: null,\n dissmisable: true\n };\n this.image = document.createElement(\"div\");\n this.image.className = \"psv-overlay-image\";\n this.container.appendChild(this.image);\n this.title = document.createElement(\"div\");\n this.title.className = \"psv-overlay-title\";\n this.container.appendChild(this.title);\n this.text = document.createElement(\"div\");\n this.text.className = \"psv-overlay-text\";\n this.container.appendChild(this.text);\n this.container.addEventListener(\"click\", this);\n this.viewer.addEventListener(KeypressEvent.type, this);\n super.hide();\n }\n /**\n * @internal\n */\n destroy() {\n this.viewer.removeEventListener(KeypressEvent.type, this);\n super.destroy();\n }\n /**\n * @internal\n */\n handleEvent(e) {\n if (e.type === \"click\") {\n if (this.isVisible() && this.state.dissmisable) {\n this.hide();\n e.stopPropagation();\n }\n } else if (e instanceof KeypressEvent) {\n if (this.isVisible() && this.state.dissmisable && e.key === KEY_CODES.Escape) {\n this.hide();\n e.preventDefault();\n }\n }\n }\n /**\n * Checks if the overlay is visible\n */\n isVisible(id) {\n return this.state.visible && (!id || !this.state.contentId || this.state.contentId === id);\n }\n /**\n * @throws {@link PSVError} always\n * @internal\n */\n toggle() {\n throw new PSVError(\"Overlay cannot be toggled\");\n }\n /**\n * Displays an overlay on the viewer\n */\n show(config) {\n if (typeof config === \"string\") {\n config = { title: config };\n }\n this.state.contentId = config.id || null;\n this.state.dissmisable = config.dissmisable !== false;\n this.image.innerHTML = config.image || \"\";\n this.title.innerHTML = config.title || \"\";\n this.text.innerHTML = config.text || \"\";\n super.show();\n this.viewer.dispatchEvent(new ShowOverlayEvent(config.id));\n }\n /**\n * Hides the overlay\n */\n hide(id) {\n if (this.isVisible(id)) {\n const contentId = this.state.contentId;\n super.hide();\n this.state.contentId = null;\n this.viewer.dispatchEvent(new HideOverlayEvent(contentId));\n }\n }\n};\n\n// src/components/Panel.ts\nvar PANEL_MIN_WIDTH = 200;\nvar PANEL_CLASS_NO_INTERACTION = \"psv-panel-content--no-interaction\";\nvar Panel = class extends AbstractComponent {\n /**\n * @internal\n */\n constructor(viewer) {\n super(viewer, {\n className: `psv-panel ${CAPTURE_EVENTS_CLASS}`\n });\n /**\n * @internal\n */\n this.state = {\n visible: false,\n contentId: null,\n mouseX: 0,\n mouseY: 0,\n mousedown: false,\n clickHandler: null,\n keyHandler: null,\n width: {}\n };\n const resizer = document.createElement(\"div\");\n resizer.className = \"psv-panel-resizer\";\n this.container.appendChild(resizer);\n const closeBtn = document.createElement(\"div\");\n closeBtn.className = \"psv-panel-close-button\";\n closeBtn.innerHTML = ICONS.close;\n closeBtn.title = viewer.config.lang.close;\n this.container.appendChild(closeBtn);\n this.content = document.createElement(\"div\");\n this.content.className = \"psv-panel-content\";\n this.container.appendChild(this.content);\n this.container.addEventListener(\"wheel\", (e) => e.stopPropagation());\n closeBtn.addEventListener(\"click\", () => this.hide());\n resizer.addEventListener(\"mousedown\", this);\n resizer.addEventListener(\"touchstart\", this);\n this.viewer.container.addEventListener(\"mouseup\", this);\n this.viewer.container.addEventListener(\"touchend\", this);\n this.viewer.container.addEventListener(\"mousemove\", this);\n this.viewer.container.addEventListener(\"touchmove\", this);\n this.viewer.addEventListener(KeypressEvent.type, this);\n }\n /**\n * @internal\n */\n destroy() {\n this.viewer.removeEventListener(KeypressEvent.type, this);\n this.viewer.container.removeEventListener(\"mousemove\", this);\n this.viewer.container.removeEventListener(\"touchmove\", this);\n this.viewer.container.removeEventListener(\"mouseup\", this);\n this.viewer.container.removeEventListener(\"touchend\", this);\n super.destroy();\n }\n /**\n * @internal\n */\n handleEvent(e) {\n switch (e.type) {\n case \"mousedown\":\n this.__onMouseDown(e);\n break;\n case \"touchstart\":\n this.__onTouchStart(e);\n break;\n case \"mousemove\":\n this.__onMouseMove(e);\n break;\n case \"touchmove\":\n this.__onTouchMove(e);\n break;\n case \"mouseup\":\n this.__onMouseUp(e);\n break;\n case \"touchend\":\n this.__onTouchEnd(e);\n break;\n case KeypressEvent.type:\n this.__onKeyPress(e);\n break;\n }\n }\n /**\n * Checks if the panel is visible\n */\n isVisible(id) {\n return this.state.visible && (!id || !this.state.contentId || this.state.contentId === id);\n }\n /**\n * @throws {@link PSVError} always\n * @internal\n */\n toggle() {\n throw new PSVError(\"Panel cannot be toggled\");\n }\n /**\n * Shows the panel\n */\n show(config) {\n if (typeof config === \"string\") {\n config = { content: config };\n }\n const wasVisible = this.isVisible(config.id);\n this.state.contentId = config.id || null;\n this.state.visible = true;\n if (this.state.clickHandler) {\n this.content.removeEventListener(\"click\", this.state.clickHandler);\n this.content.removeEventListener(\"keydown\", this.state.keyHandler);\n this.state.clickHandler = null;\n this.state.keyHandler = null;\n }\n if (config.id && this.state.width[config.id]) {\n this.container.style.width = this.state.width[config.id];\n } else if (config.width) {\n this.container.style.width = config.width;\n } else {\n this.container.style.width = null;\n }\n this.content.innerHTML = config.content;\n this.content.scrollTop = 0;\n this.container.classList.add(\"psv-panel--open\");\n toggleClass(this.content, \"psv-panel-content--no-margin\", config.noMargin === true);\n if (config.clickHandler) {\n this.state.clickHandler = (e) => {\n config.clickHandler(e.target);\n };\n this.state.keyHandler = (e) => {\n if (e.key === KEY_CODES.Enter) {\n config.clickHandler(e.target);\n }\n };\n this.content.addEventListener(\"click\", this.state.clickHandler);\n this.content.addEventListener(\"keydown\", this.state.keyHandler);\n if (!wasVisible) {\n setTimeout(() => {\n this.content.querySelector(\"a,button,[tabindex]\")?.focus();\n }, 300);\n }\n }\n this.viewer.dispatchEvent(new ShowPanelEvent(config.id));\n }\n /**\n * Hides the panel\n */\n hide(id) {\n if (this.isVisible(id)) {\n const contentId = this.state.contentId;\n this.state.visible = false;\n this.state.contentId = null;\n this.content.innerHTML = null;\n this.container.classList.remove(\"psv-panel--open\");\n if (this.state.clickHandler) {\n this.content.removeEventListener(\"click\", this.state.clickHandler);\n this.state.clickHandler = null;\n }\n this.viewer.dispatchEvent(new HidePanelEvent(contentId));\n }\n }\n __onMouseDown(evt) {\n evt.stopPropagation();\n this.__startResize(evt.clientX, evt.clientY);\n }\n __onTouchStart(evt) {\n evt.stopPropagation();\n if (evt.touches.length === 1) {\n const touch = evt.touches[0];\n this.__startResize(touch.clientX, touch.clientY);\n }\n }\n __onMouseUp(evt) {\n if (this.state.mousedown) {\n evt.stopPropagation();\n this.state.mousedown = false;\n this.content.classList.remove(PANEL_CLASS_NO_INTERACTION);\n }\n }\n __onTouchEnd(evt) {\n if (this.state.mousedown) {\n evt.stopPropagation();\n if (evt.touches.length === 0) {\n this.state.mousedown = false;\n this.content.classList.remove(PANEL_CLASS_NO_INTERACTION);\n }\n }\n }\n __onMouseMove(evt) {\n if (this.state.mousedown) {\n evt.stopPropagation();\n this.__resize(evt.clientX, evt.clientY);\n }\n }\n __onTouchMove(evt) {\n if (this.state.mousedown) {\n const touch = evt.touches[0];\n this.__resize(touch.clientX, touch.clientY);\n }\n }\n __onKeyPress(evt) {\n if (this.isVisible() && evt.key === KEY_CODES.Escape) {\n this.hide();\n evt.preventDefault();\n }\n }\n __startResize(clientX, clientY) {\n this.state.mouseX = clientX;\n this.state.mouseY = clientY;\n this.state.mousedown = true;\n this.content.classList.add(PANEL_CLASS_NO_INTERACTION);\n }\n __resize(clientX, clientY) {\n const x = clientX;\n const y = clientY;\n const width = Math.max(PANEL_MIN_WIDTH, this.container.offsetWidth - (x - this.state.mouseX)) + \"px\";\n if (this.state.contentId) {\n this.state.width[this.state.contentId] = width;\n }\n this.container.style.width = width;\n this.state.mouseX = x;\n this.state.mouseY = y;\n }\n};\n\n// src/components/Tooltip.ts\nvar Tooltip = class extends AbstractComponent {\n /**\n * @internal\n */\n constructor(viewer, config) {\n super(viewer, {\n className: \"psv-tooltip\"\n });\n /**\n * @internal\n */\n this.state = {\n visible: true,\n arrow: 0,\n border: 0,\n state: 0 /* NONE */,\n width: 0,\n height: 0,\n pos: \"\",\n config: null,\n data: null\n };\n this.content = document.createElement(\"div\");\n this.content.className = \"psv-tooltip-content\";\n this.container.appendChild(this.content);\n this.arrow = document.createElement(\"div\");\n this.arrow.className = \"psv-tooltip-arrow\";\n this.container.appendChild(this.arrow);\n this.container.addEventListener(\"transitionend\", this);\n this.container.addEventListener(\"touchdown\", (e) => e.stopPropagation());\n this.container.addEventListener(\"mousedown\", (e) => e.stopPropagation());\n this.container.style.top = \"-1000px\";\n this.container.style.left = \"-1000px\";\n this.show(config);\n }\n /**\n * @internal\n */\n handleEvent(e) {\n if (e.type === \"transitionend\") {\n this.__onTransitionEnd(e);\n }\n }\n /**\n * @internal\n */\n destroy() {\n delete this.state.data;\n super.destroy();\n }\n /**\n * @throws {@link PSVError} always\n * @internal\n */\n toggle() {\n throw new PSVError(\"Tooltip cannot be toggled\");\n }\n /**\n * Displays the tooltip on the viewer\n * @internal\n */\n show(config) {\n if (this.state.state !== 0 /* NONE */) {\n throw new PSVError(\"Initialized tooltip cannot be re-initialized\");\n }\n if (config.className) {\n addClasses(this.container, config.className);\n }\n if (config.style) {\n Object.assign(this.container.style, config.style);\n }\n this.state.state = 3 /* READY */;\n this.update(config.content, config);\n this.state.data = config.data;\n this.state.state = 1 /* SHOWING */;\n this.viewer.dispatchEvent(new ShowTooltipEvent(this, this.state.data));\n this.__waitImages();\n }\n /**\n * Updates the content of the tooltip, optionally with a new position\n * @throws {@link PSVError} if the configuration is invalid\n */\n update(content, config) {\n this.content.innerHTML = content;\n const rect = this.container.getBoundingClientRect();\n this.state.width = rect.right - rect.left;\n this.state.height = rect.bottom - rect.top;\n this.state.arrow = parseInt(getStyleProperty(this.arrow, \"border-top-width\"), 10);\n this.state.border = parseInt(getStyleProperty(this.container, \"border-top-left-radius\"), 10);\n this.move(config ?? this.state.config);\n }\n /**\n * Moves the tooltip to a new position\n * @throws {@link PSVError} if the configuration is invalid\n */\n move(config) {\n if (this.state.state !== 1 /* SHOWING */ && this.state.state !== 3 /* READY */) {\n throw new PSVError(\"Uninitialized tooltip cannot be moved\");\n }\n config.box = config.box ?? this.state.config?.box ?? { width: 0, height: 0 };\n this.state.config = config;\n const t = this.container;\n const a = this.arrow;\n const style = {\n posClass: cleanCssPosition(config.position, { allowCenter: false, cssOrder: false }) || [\"top\", \"center\"],\n width: this.state.width,\n height: this.state.height,\n top: 0,\n left: 0,\n arrowTop: 0,\n arrowLeft: 0\n };\n this.__computeTooltipPosition(style, config);\n let swapY = null;\n let swapX = null;\n if (style.top < 0) {\n swapY = \"bottom\";\n } else if (style.top + style.height > this.viewer.state.size.height) {\n swapY = \"top\";\n }\n if (style.left < 0) {\n swapX = \"right\";\n } else if (style.left + style.width > this.viewer.state.size.width) {\n swapX = \"left\";\n }\n if (swapX || swapY) {\n const ordered = cssPositionIsOrdered(style.posClass);\n if (swapY) {\n style.posClass[ordered ? 0 : 1] = swapY;\n }\n if (swapX) {\n style.posClass[ordered ? 1 : 0] = swapX;\n }\n this.__computeTooltipPosition(style, config);\n }\n t.style.top = style.top + \"px\";\n t.style.left = style.left + \"px\";\n a.style.top = style.arrowTop + \"px\";\n a.style.left = style.arrowLeft + \"px\";\n const newPos = style.posClass.join(\"-\");\n if (newPos !== this.state.pos) {\n t.classList.remove(`psv-tooltip--${this.state.pos}`);\n this.state.pos = newPos;\n t.classList.add(`psv-tooltip--${this.state.pos}`);\n }\n }\n /**\n * Hides the tooltip\n */\n hide() {\n this.container.classList.remove(\"psv-tooltip--visible\");\n this.state.state = 2 /* HIDING */;\n this.viewer.dispatchEvent(new HideTooltipEvent(this.state.data));\n }\n /**\n * Finalize transition\n */\n __onTransitionEnd(e) {\n if (e.propertyName === \"transform\") {\n switch (this.state.state) {\n case 1 /* SHOWING */:\n this.container.classList.add(\"psv-tooltip--visible\");\n this.state.state = 3 /* READY */;\n break;\n case 2 /* HIDING */:\n this.state.state = 0 /* NONE */;\n this.destroy();\n break;\n default:\n }\n }\n }\n /**\n * Computes the position of the tooltip and its arrow\n */\n __computeTooltipPosition(style, config) {\n const arrow = this.state.arrow;\n const top = config.top;\n const height = style.height;\n const left = config.left;\n const width = style.width;\n const offsetSide = arrow + this.state.border;\n const offsetX = config.box.width / 2 + arrow * 2;\n const offsetY = config.box.height / 2 + arrow * 2;\n switch (style.posClass.join(\"-\")) {\n case \"top-left\":\n style.top = top - offsetY - height;\n style.left = left + offsetSide - width;\n style.arrowTop = height;\n style.arrowLeft = width - offsetSide - arrow;\n break;\n case \"top-center\":\n style.top = top - offsetY - height;\n style.left = left - width / 2;\n style.arrowTop = height;\n style.arrowLeft = width / 2 - arrow;\n break;\n case \"top-right\":\n style.top = top - offsetY - height;\n style.left = left - offsetSide;\n style.arrowTop = height;\n style.arrowLeft = arrow;\n break;\n case \"bottom-left\":\n style.top = top + offsetY;\n style.left = left + offsetSide - width;\n style.arrowTop = -arrow * 2;\n style.arrowLeft = width - offsetSide - arrow;\n break;\n case \"bottom-center\":\n style.top = top + offsetY;\n style.left = left - width / 2;\n style.arrowTop = -arrow * 2;\n style.arrowLeft = width / 2 - arrow;\n break;\n case \"bottom-right\":\n style.top = top + offsetY;\n style.left = left - offsetSide;\n style.arrowTop = -arrow * 2;\n style.arrowLeft = arrow;\n break;\n case \"left-top\":\n style.top = top + offsetSide - height;\n style.left = left - offsetX - width;\n style.arrowTop = height - offsetSide - arrow;\n style.arrowLeft = width;\n break;\n case \"center-left\":\n style.top = top - height / 2;\n style.left = left - offsetX - width;\n style.arrowTop = height / 2 - arrow;\n style.arrowLeft = width;\n break;\n case \"left-bottom\":\n style.top = top - offsetSide;\n style.left = left - offsetX - width;\n style.arrowTop = arrow;\n style.arrowLeft = width;\n break;\n case \"right-top\":\n style.top = top + offsetSide - height;\n style.left = left + offsetX;\n style.arrowTop = height - offsetSide - arrow;\n style.arrowLeft = -arrow * 2;\n break;\n case \"center-right\":\n style.top = top - height / 2;\n style.left = left + offsetX;\n style.arrowTop = height / 2 - arrow;\n style.arrowLeft = -arrow * 2;\n break;\n case \"right-bottom\":\n style.top = top - offsetSide;\n style.left = left + offsetX;\n style.arrowTop = arrow;\n style.arrowLeft = -arrow * 2;\n break;\n }\n }\n /**\n * If the tooltip contains images, recompute its size once they are loaded\n */\n __waitImages() {\n const images = this.content.querySelectorAll(\"img\");\n if (images.length > 0) {\n const promises = [];\n images.forEach((image) => {\n promises.push(\n new Promise((resolve) => {\n image.onload = resolve;\n image.onerror = resolve;\n })\n );\n });\n Promise.all(promises).then(() => {\n if (this.state.state === 1 /* SHOWING */ || this.state.state === 3 /* READY */) {\n const rect = this.container.getBoundingClientRect();\n this.state.width = rect.right - rect.left;\n this.state.height = rect.bottom - rect.top;\n this.move(this.state.config);\n }\n });\n }\n }\n};\n\n// src/data/cache.ts\nimport { Cache as ThreeCache } from \"three\";\nvar Cache = {\n enabled: true,\n maxItems: 10,\n ttl: 10 * 60,\n items: {},\n purgeInterval: null,\n init() {\n if (ThreeCache.enabled) {\n logWarn(\"ThreeJS cache should be disabled\");\n ThreeCache.enabled = false;\n }\n if (!this.purgeInterval && this.enabled) {\n this.purgeInterval = setInterval(() => this.purge(), 60 * 1e3);\n }\n },\n add(url, key, data) {\n if (this.enabled && key) {\n this.items[key] = this.items[key] ?? { files: {}, lastAccess: null };\n this.items[key].files[url] = data;\n this.items[key].lastAccess = Date.now();\n }\n },\n get(url, key) {\n if (this.enabled && key && this.items[key]) {\n this.items[key].lastAccess = Date.now();\n return this.items[key].files[url];\n }\n },\n remove(url, key) {\n if (this.enabled && key && this.items[key]) {\n delete this.items[key].files[url];\n if (Object.keys(this.items[key].files).length === 0) {\n delete this.items[key];\n }\n }\n },\n purge() {\n Object.entries(this.items).sort(([, a], [, b]) => {\n return b.lastAccess - a.lastAccess;\n }).forEach(([key, { lastAccess }], index) => {\n if (index > 0 && (Date.now() - lastAccess >= this.ttl * 1e3 || index >= this.maxItems)) {\n delete this.items[key];\n }\n });\n }\n};\n\n// src/icons/error.svg\nvar error_default = '\\n';\n\n// src/services/DataHelper.ts\nimport { Euler as Euler2, MathUtils as MathUtils5, Vector3 as Vector32 } from \"three\";\n\n// src/services/AbstractService.ts\nvar AbstractService = class {\n /**\n * @internal\n */\n constructor(viewer) {\n this.viewer = viewer;\n this.config = viewer.config;\n this.state = viewer.state;\n }\n /**\n * Destroys the service\n * @internal\n */\n // eslint-disable-next-line @typescript-eslint/no-empty-function\n destroy() {\n }\n};\n\n// src/services/DataHelper.ts\nvar vector3 = new Vector32();\nvar EULER_ZERO = new Euler2(0, 0, 0, \"ZXY\");\nvar DataHelper = class extends AbstractService {\n /**\n * @internal\n */\n constructor(viewer) {\n super(viewer);\n }\n /**\n * Converts vertical FOV to zoom level\n */\n fovToZoomLevel(fov) {\n const temp = Math.round((fov - this.config.minFov) / (this.config.maxFov - this.config.minFov) * 100);\n return temp - 2 * (temp - 50);\n }\n /**\n * Converts zoom level to vertical FOV\n */\n zoomLevelToFov(level) {\n return this.config.maxFov + level / 100 * (this.config.minFov - this.config.maxFov);\n }\n /**\n * Converts vertical FOV to horizontal FOV\n */\n vFovToHFov(vFov) {\n return MathUtils5.radToDeg(2 * Math.atan(Math.tan(MathUtils5.degToRad(vFov) / 2) * this.state.aspect));\n }\n /**\n * @internal\n */\n getAnimationProperties(speed, targetPosition, targetZoom) {\n const positionProvided = !isNil(targetPosition);\n const zoomProvided = !isNil(targetZoom);\n const properties = {};\n let duration;\n if (positionProvided) {\n const currentPosition = this.viewer.getPosition();\n const dYaw = getShortestArc(currentPosition.yaw, targetPosition.yaw);\n properties.yaw = { start: currentPosition.yaw, end: currentPosition.yaw + dYaw };\n properties.pitch = { start: currentPosition.pitch, end: targetPosition.pitch };\n duration = speedToDuration(speed, getAngle(currentPosition, targetPosition));\n }\n if (zoomProvided) {\n const currentZoom = this.viewer.getZoomLevel();\n const dZoom = Math.abs(targetZoom - currentZoom);\n properties.zoom = { start: currentZoom, end: targetZoom };\n if (!duration) {\n duration = speedToDuration(speed, Math.PI / 4 * dZoom / 100);\n }\n }\n duration = Math.max(ANIMATION_MIN_DURATION, duration);\n return { duration, properties };\n }\n /**\n * Converts pixel texture coordinates to spherical radians coordinates\n * @throws {@link PSVError} when the current adapter does not support texture coordinates\n */\n textureCoordsToSphericalCoords(point) {\n const panoData = this.state.panoData;\n if (!panoData) {\n throw new PSVError(\"Current adapter does not support texture coordinates.\");\n }\n const relativeX = (point.textureX + panoData.croppedX) / panoData.fullWidth * Math.PI * 2;\n const relativeY = (point.textureY + panoData.croppedY) / panoData.fullHeight * Math.PI;\n const result = {\n yaw: relativeX >= Math.PI ? relativeX - Math.PI : relativeX + Math.PI,\n pitch: Math.PI / 2 - relativeY\n };\n if (!EULER_ZERO.equals(this.viewer.renderer.panoramaPose) || !EULER_ZERO.equals(this.viewer.renderer.sphereCorrection)) {\n this.sphericalCoordsToVector3(result, vector3);\n vector3.applyEuler(this.viewer.renderer.panoramaPose);\n vector3.applyEuler(this.viewer.renderer.sphereCorrection);\n return this.vector3ToSphericalCoords(vector3);\n } else {\n return result;\n }\n }\n /**\n * Converts spherical radians coordinates to pixel texture coordinates\n * @throws {@link PSVError} when the current adapter does not support texture coordinates\n */\n sphericalCoordsToTextureCoords(position) {\n const panoData = this.state.panoData;\n if (!panoData) {\n throw new PSVError(\"Current adapter does not support texture coordinates.\");\n }\n if (!EULER_ZERO.equals(this.viewer.renderer.panoramaPose) || !EULER_ZERO.equals(this.viewer.renderer.sphereCorrection)) {\n this.sphericalCoordsToVector3(position, vector3);\n applyEulerInverse(vector3, this.viewer.renderer.sphereCorrection);\n applyEulerInverse(vector3, this.viewer.renderer.panoramaPose);\n position = this.vector3ToSphericalCoords(vector3);\n }\n const relativeLong = position.yaw / Math.PI / 2 * panoData.fullWidth;\n const relativeLat = position.pitch / Math.PI * panoData.fullHeight;\n return {\n textureX: Math.round(\n position.yaw < Math.PI ? relativeLong + panoData.fullWidth / 2 : relativeLong - panoData.fullWidth / 2\n ) - panoData.croppedX,\n textureY: Math.round(panoData.fullHeight / 2 - relativeLat) - panoData.croppedY\n };\n }\n /**\n * Converts spherical radians coordinates to a Vector3\n */\n sphericalCoordsToVector3(position, vector, distance2 = SPHERE_RADIUS) {\n if (!vector) {\n vector = new Vector32();\n }\n vector.x = distance2 * -Math.cos(position.pitch) * Math.sin(position.yaw);\n vector.y = distance2 * Math.sin(position.pitch);\n vector.z = distance2 * Math.cos(position.pitch) * Math.cos(position.yaw);\n return vector;\n }\n /**\n * Converts a Vector3 to spherical radians coordinates\n */\n vector3ToSphericalCoords(vector) {\n const phi = Math.acos(vector.y / Math.sqrt(vector.x * vector.x + vector.y * vector.y + vector.z * vector.z));\n const theta = Math.atan2(vector.x, vector.z);\n return {\n yaw: theta < 0 ? -theta : Math.PI * 2 - theta,\n pitch: Math.PI / 2 - phi\n };\n }\n /**\n * Converts position on the viewer to a THREE.Vector3\n */\n viewerCoordsToVector3(viewerPoint) {\n const sphereIntersect = this.viewer.renderer.getIntersections(viewerPoint).filter((i) => i.object.userData[VIEWER_DATA]);\n if (sphereIntersect.length) {\n return sphereIntersect[0].point;\n } else {\n return null;\n }\n }\n /**\n * Converts position on the viewer to spherical radians coordinates\n */\n viewerCoordsToSphericalCoords(viewerPoint) {\n const vector = this.viewerCoordsToVector3(viewerPoint);\n return vector ? this.vector3ToSphericalCoords(vector) : null;\n }\n /**\n * Converts a Vector3 to position on the viewer\n */\n vector3ToViewerCoords(vector) {\n const vectorClone = vector.clone();\n vectorClone.project(this.viewer.renderer.camera);\n return {\n x: Math.round((vectorClone.x + 1) / 2 * this.state.size.width),\n y: Math.round((1 - vectorClone.y) / 2 * this.state.size.height)\n };\n }\n /**\n * Converts spherical radians coordinates to position on the viewer\n */\n sphericalCoordsToViewerCoords(position) {\n this.sphericalCoordsToVector3(position, vector3);\n return this.vector3ToViewerCoords(vector3);\n }\n /**\n * @internal\n */\n isPointVisible(point) {\n let vector;\n let viewerPoint;\n if (point instanceof Vector32) {\n vector = point;\n viewerPoint = this.vector3ToViewerCoords(point);\n } else if (isExtendedPosition(point)) {\n vector = this.sphericalCoordsToVector3(point, vector3);\n viewerPoint = this.vector3ToViewerCoords(vector);\n } else {\n return false;\n }\n return vector.dot(this.viewer.state.direction) > 0 && viewerPoint.x >= 0 && viewerPoint.x <= this.viewer.state.size.width && viewerPoint.y >= 0 && viewerPoint.y <= this.viewer.state.size.height;\n }\n /**\n * Converts pixel position to angles if present and ensure boundaries\n */\n cleanPosition(position) {\n if (position.textureX !== void 0 && position.textureY !== void 0) {\n return this.textureCoordsToSphericalCoords(position);\n }\n return {\n yaw: parseAngle(position.yaw),\n pitch: parseAngle(position.pitch, !this.state.littlePlanet)\n };\n }\n /**\n * Ensure a SphereCorrection object is valid\n */\n cleanSphereCorrection(sphereCorrection) {\n return {\n pan: parseAngle(sphereCorrection?.pan || 0),\n tilt: parseAngle(sphereCorrection?.tilt || 0, true),\n roll: parseAngle(sphereCorrection?.roll || 0, true, false)\n };\n }\n /**\n * Parse the pose angles of the pano data\n */\n cleanPanoramaPose(panoData) {\n return {\n pan: MathUtils5.degToRad(panoData?.poseHeading || 0),\n tilt: MathUtils5.degToRad(panoData?.posePitch || 0),\n roll: MathUtils5.degToRad(panoData?.poseRoll || 0)\n };\n }\n};\n\n// src/services/EventsHandler.ts\nimport { MathUtils as MathUtils6, SplineCurve, Vector2 } from \"three\";\n\n// src/icons/gesture.svg\nvar gesture_default = '\\n';\n\n// src/icons/mousewheel.svg\nvar mousewheel_default = '\\n';\n\n// src/services/EventsHandler.ts\nvar _Step = class _Step {\n constructor() {\n this.$ = _Step.IDLE;\n }\n is(...steps) {\n return steps.some((step) => this.$ & step);\n }\n set(step) {\n this.$ = step;\n }\n add(step) {\n this.$ |= step;\n }\n remove(step) {\n this.$ &= ~step;\n }\n};\n_Step.IDLE = 0;\n_Step.CLICK = 1;\n_Step.MOVING = 2;\n_Step.INERTIA = 4;\nvar Step = _Step;\nvar EventsHandler = class extends AbstractService {\n constructor(viewer) {\n super(viewer);\n this.data = {\n /** start x position of the click/touch */\n startMouseX: 0,\n /** start y position of the click/touch */\n startMouseY: 0,\n /** current x position of the cursor */\n mouseX: 0,\n /** current y position of the cursor */\n mouseY: 0,\n /** list of latest positions of the cursor, [time, x, y] */\n mouseHistory: [],\n /** distance between fingers when zooming */\n pinchDist: 0,\n /** when the Ctrl key is pressed */\n ctrlKeyDown: false,\n /** temporary storage of click data between two clicks */\n dblclickData: null,\n dblclickTimeout: null,\n longtouchTimeout: null,\n twofingersTimeout: null,\n ctrlZoomTimeout: null\n };\n this.step = new Step();\n this.keyHandler = new PressHandler();\n this.resizeObserver = new ResizeObserver(throttle(() => this.viewer.autoSize(), 50));\n this.moveThreshold = MOVE_THRESHOLD * SYSTEM.pixelRatio;\n }\n /**\n * @internal\n */\n init() {\n window.addEventListener(\"keydown\", this, { passive: false });\n window.addEventListener(\"keyup\", this);\n this.viewer.container.addEventListener(\"mousedown\", this);\n window.addEventListener(\"mousemove\", this, { passive: false });\n window.addEventListener(\"mouseup\", this);\n this.viewer.container.addEventListener(\"touchstart\", this, { passive: false });\n window.addEventListener(\"touchmove\", this, { passive: false });\n window.addEventListener(\"touchend\", this, { passive: false });\n this.viewer.container.addEventListener(\"wheel\", this, { passive: false });\n document.addEventListener(SYSTEM.fullscreenEvent, this);\n this.resizeObserver.observe(this.viewer.container);\n }\n destroy() {\n window.removeEventListener(\"keydown\", this);\n window.removeEventListener(\"keyup\", this);\n this.viewer.container.removeEventListener(\"mousedown\", this);\n window.removeEventListener(\"mousemove\", this);\n window.removeEventListener(\"mouseup\", this);\n this.viewer.container.removeEventListener(\"touchstart\", this);\n window.removeEventListener(\"touchmove\", this);\n window.removeEventListener(\"touchend\", this);\n this.viewer.container.removeEventListener(\"wheel\", this);\n document.removeEventListener(SYSTEM.fullscreenEvent, this);\n this.resizeObserver.disconnect();\n clearTimeout(this.data.dblclickTimeout);\n clearTimeout(this.data.longtouchTimeout);\n clearTimeout(this.data.twofingersTimeout);\n clearTimeout(this.data.ctrlZoomTimeout);\n super.destroy();\n }\n /**\n * @internal\n */\n handleEvent(evt) {\n switch (evt.type) {\n case \"keydown\":\n this.__onKeyDown(evt);\n break;\n case \"keyup\":\n this.__onKeyUp();\n break;\n case \"mousemove\":\n this.__onMouseMove(evt);\n break;\n case \"mouseup\":\n this.__onMouseUp(evt);\n break;\n case \"touchmove\":\n this.__onTouchMove(evt);\n break;\n case \"touchend\":\n this.__onTouchEnd(evt);\n break;\n case SYSTEM.fullscreenEvent:\n this.__onFullscreenChange();\n break;\n }\n if (!getClosest(evt.target, \".\" + CAPTURE_EVENTS_CLASS)) {\n switch (evt.type) {\n case \"mousedown\":\n this.__onMouseDown(evt);\n break;\n case \"touchstart\":\n this.__onTouchStart(evt);\n break;\n case \"wheel\":\n this.__onMouseWheel(evt);\n break;\n }\n }\n }\n /**\n * Handles keyboard events\n */\n __onKeyDown(e) {\n if (this.config.mousewheelCtrlKey) {\n this.data.ctrlKeyDown = e.key === KEY_CODES.Control;\n if (this.data.ctrlKeyDown) {\n clearTimeout(this.data.ctrlZoomTimeout);\n this.viewer.overlay.hide(IDS.CTRL_ZOOM);\n }\n }\n if (!this.viewer.dispatchEvent(new KeypressEvent(e.key))) {\n return;\n }\n if (!this.state.keyboardEnabled) {\n return;\n }\n const action = this.config.keyboardActions?.[e.key];\n if (typeof action === \"function\") {\n action(this.viewer);\n e.preventDefault();\n } else if (action && !this.keyHandler.pending) {\n if (action !== \"ZOOM_IN\" /* ZOOM_IN */ && action !== \"ZOOM_OUT\" /* ZOOM_OUT */) {\n this.viewer.stopAll();\n }\n switch (action) {\n case \"ROTATE_UP\" /* ROTATE_UP */:\n this.viewer.dynamics.position.roll({ pitch: false });\n break;\n case \"ROTATE_DOWN\" /* ROTATE_DOWN */:\n this.viewer.dynamics.position.roll({ pitch: true });\n break;\n case \"ROTATE_RIGHT\" /* ROTATE_RIGHT */:\n this.viewer.dynamics.position.roll({ yaw: false });\n break;\n case \"ROTATE_LEFT\" /* ROTATE_LEFT */:\n this.viewer.dynamics.position.roll({ yaw: true });\n break;\n case \"ZOOM_IN\" /* ZOOM_IN */:\n this.viewer.dynamics.zoom.roll(false);\n break;\n case \"ZOOM_OUT\" /* ZOOM_OUT */:\n this.viewer.dynamics.zoom.roll(true);\n break;\n }\n this.keyHandler.down();\n e.preventDefault();\n }\n }\n /**\n * Handles keyboard events\n */\n __onKeyUp() {\n this.data.ctrlKeyDown = false;\n if (!this.state.keyboardEnabled) {\n return;\n }\n this.keyHandler.up(() => {\n this.viewer.dynamics.position.stop();\n this.viewer.dynamics.zoom.stop();\n this.viewer.resetIdleTimer();\n });\n }\n /**\n * Handles mouse down events\n */\n __onMouseDown(evt) {\n this.step.add(Step.CLICK);\n this.data.startMouseX = evt.clientX;\n this.data.startMouseY = evt.clientY;\n }\n /**\n *Handles mouse up events\n */\n __onMouseUp(evt) {\n if (this.step.is(Step.CLICK, Step.MOVING)) {\n this.__stopMove(evt.clientX, evt.clientY, evt.target, evt.button === 2);\n }\n }\n /**\n * Handles mouse move events\n */\n __onMouseMove(evt) {\n if (this.config.mousemove && this.step.is(Step.CLICK, Step.MOVING)) {\n evt.preventDefault();\n this.__doMove(evt.clientX, evt.clientY);\n }\n this.__handleObjectsEvents(evt);\n }\n /**\n * Handles touch events\n */\n __onTouchStart(evt) {\n if (evt.touches.length === 1) {\n this.step.add(Step.CLICK);\n this.data.startMouseX = evt.touches[0].clientX;\n this.data.startMouseY = evt.touches[0].clientY;\n if (!this.data.longtouchTimeout) {\n this.data.longtouchTimeout = setTimeout(() => {\n const touch = evt.touches[0];\n this.__stopMove(touch.clientX, touch.clientY, touch.target, true);\n this.data.longtouchTimeout = null;\n }, LONGTOUCH_DELAY);\n }\n } else if (evt.touches.length === 2) {\n this.step.set(Step.IDLE);\n this.__cancelLongTouch();\n if (this.config.mousemove) {\n this.__cancelTwoFingersOverlay();\n this.__startMoveZoom(evt);\n evt.preventDefault();\n }\n }\n }\n /**\n * Handles touch events\n */\n __onTouchEnd(evt) {\n this.__cancelLongTouch();\n if (this.step.is(Step.CLICK, Step.MOVING)) {\n evt.preventDefault();\n this.__cancelTwoFingersOverlay();\n if (evt.touches.length === 1) {\n this.__stopMove(this.data.mouseX, this.data.mouseY);\n } else if (evt.touches.length === 0) {\n const touch = evt.changedTouches[0];\n this.__stopMove(touch.clientX, touch.clientY, touch.target);\n }\n }\n }\n /**\n * Handles touch move events\n */\n __onTouchMove(evt) {\n this.__cancelLongTouch();\n if (!this.config.mousemove) {\n return;\n }\n if (evt.touches.length === 1) {\n if (this.config.touchmoveTwoFingers) {\n if (this.step.is(Step.CLICK) && !this.data.twofingersTimeout) {\n this.data.twofingersTimeout = setTimeout(() => {\n this.viewer.overlay.show({\n id: IDS.TWO_FINGERS,\n image: gesture_default,\n title: this.config.lang.twoFingers\n });\n }, TWOFINGERSOVERLAY_DELAY);\n }\n } else if (this.step.is(Step.CLICK, Step.MOVING)) {\n evt.preventDefault();\n const touch = evt.touches[0];\n this.__doMove(touch.clientX, touch.clientY);\n }\n } else {\n this.__doMoveZoom(evt);\n this.__cancelTwoFingersOverlay();\n }\n }\n /**\n * Cancel the long touch timer if any\n */\n __cancelLongTouch() {\n if (this.data.longtouchTimeout) {\n clearTimeout(this.data.longtouchTimeout);\n this.data.longtouchTimeout = null;\n }\n }\n /**\n * Cancel the two fingers overlay timer if any\n */\n __cancelTwoFingersOverlay() {\n if (this.config.touchmoveTwoFingers) {\n if (this.data.twofingersTimeout) {\n clearTimeout(this.data.twofingersTimeout);\n this.data.twofingersTimeout = null;\n }\n this.viewer.overlay.hide(IDS.TWO_FINGERS);\n }\n }\n /**\n * Handles mouse wheel events\n */\n __onMouseWheel(evt) {\n if (!this.config.mousewheel || !evt.deltaY) {\n return;\n }\n if (this.config.mousewheelCtrlKey && !this.data.ctrlKeyDown) {\n this.viewer.overlay.show({\n id: IDS.CTRL_ZOOM,\n image: mousewheel_default,\n title: this.config.lang.ctrlZoom\n });\n clearTimeout(this.data.ctrlZoomTimeout);\n this.data.ctrlZoomTimeout = setTimeout(() => this.viewer.overlay.hide(IDS.CTRL_ZOOM), CTRLZOOM_TIMEOUT);\n return;\n }\n evt.preventDefault();\n evt.stopPropagation();\n const delta = evt.deltaY / Math.abs(evt.deltaY) * 5 * this.config.zoomSpeed;\n if (delta !== 0) {\n this.viewer.dynamics.zoom.step(-delta, 5);\n }\n }\n /**\n * Handles fullscreen events\n */\n __onFullscreenChange() {\n const fullscreen = this.viewer.isFullscreenEnabled();\n if (this.config.keyboard === \"fullscreen\") {\n if (fullscreen) {\n this.viewer.startKeyboardControl();\n } else {\n this.viewer.stopKeyboardControl();\n }\n }\n this.viewer.dispatchEvent(new FullscreenEvent(fullscreen));\n }\n /**\n * Resets all state variables\n */\n __resetMove() {\n this.step.set(Step.IDLE);\n this.data.mouseX = 0;\n this.data.mouseY = 0;\n this.data.startMouseX = 0;\n this.data.startMouseY = 0;\n this.data.mouseHistory.length = 0;\n }\n /**\n * Initializes the combines move and zoom\n */\n __startMoveZoom(evt) {\n this.viewer.stopAll();\n this.__resetMove();\n const touchData = getTouchData(evt);\n this.step.set(Step.MOVING);\n ({\n distance: this.data.pinchDist,\n center: { x: this.data.mouseX, y: this.data.mouseY }\n } = touchData);\n this.__logMouseMove(this.data.mouseX, this.data.mouseY);\n }\n /**\n * Stops the movement\n * @description If the move threshold was not reached a click event is triggered, otherwise an animation is launched to simulate inertia\n */\n __stopMove(clientX, clientY, target, rightclick = false) {\n if (this.step.is(Step.MOVING)) {\n if (this.config.moveInertia) {\n this.__logMouseMove(clientX, clientY);\n this.__stopMoveInertia(clientX, clientY);\n } else {\n this.__resetMove();\n this.viewer.resetIdleTimer();\n }\n } else {\n if (this.step.is(Step.CLICK) && !this.__moveThresholdReached(clientX, clientY)) {\n this.__doClick(clientX, clientY, target, rightclick);\n }\n this.step.remove(Step.CLICK);\n if (!this.step.is(Step.INERTIA)) {\n this.__resetMove();\n this.viewer.resetIdleTimer();\n }\n }\n }\n /**\n * Performs an animation to simulate inertia when the movement stops\n */\n __stopMoveInertia(clientX, clientY) {\n const curve = new SplineCurve(this.data.mouseHistory.map(([, x, y]) => new Vector2(x, y)));\n const direction = curve.getTangent(1);\n const speed = this.data.mouseHistory.reduce(({ total, prev }, curr) => ({\n total: !prev ? 0 : total + distance({ x: prev[1], y: prev[2] }, { x: curr[1], y: curr[2] }) / (curr[0] - prev[0]),\n prev: curr\n }), {\n total: 0,\n prev: null\n }).total / this.data.mouseHistory.length;\n if (!speed) {\n this.__resetMove();\n this.viewer.resetIdleTimer();\n return;\n }\n this.step.set(Step.INERTIA);\n let currentClientX = clientX;\n let currentClientY = clientY;\n this.state.animation = new Animation({\n properties: {\n speed: { start: speed, end: 0 }\n },\n duration: 1e3,\n easing: \"outQuad\",\n onTick: (properties) => {\n currentClientX += properties.speed * direction.x * 3 * SYSTEM.pixelRatio;\n currentClientY += properties.speed * direction.y * 3 * SYSTEM.pixelRatio;\n this.__applyMove(currentClientX, currentClientY);\n }\n });\n this.state.animation.then((done) => {\n this.state.animation = null;\n if (done) {\n this.__resetMove();\n this.viewer.resetIdleTimer();\n }\n });\n }\n /**\n * Triggers an event with all coordinates when a simple click is performed\n */\n __doClick(clientX, clientY, target, rightclick = false) {\n const boundingRect = this.viewer.container.getBoundingClientRect();\n const viewerX = clientX - boundingRect.left;\n const viewerY = clientY - boundingRect.top;\n const intersections = this.viewer.renderer.getIntersections({ x: viewerX, y: viewerY });\n const sphereIntersection = intersections.find((i) => i.object.userData[VIEWER_DATA]);\n if (sphereIntersection) {\n const sphericalCoords = this.viewer.dataHelper.vector3ToSphericalCoords(sphereIntersection.point);\n const data = {\n rightclick,\n target,\n clientX,\n clientY,\n viewerX,\n viewerY,\n yaw: sphericalCoords.yaw,\n pitch: sphericalCoords.pitch,\n objects: intersections.map((i) => i.object).filter((o) => !o.userData[VIEWER_DATA])\n };\n try {\n const textureCoords = this.viewer.dataHelper.sphericalCoordsToTextureCoords(data);\n data.textureX = textureCoords.textureX;\n data.textureY = textureCoords.textureY;\n } catch (e) {\n data.textureX = NaN;\n data.textureY = NaN;\n }\n if (!this.data.dblclickTimeout) {\n this.viewer.dispatchEvent(new ClickEvent(data));\n this.data.dblclickData = clone(data);\n this.data.dblclickTimeout = setTimeout(() => {\n this.data.dblclickTimeout = null;\n this.data.dblclickData = null;\n }, DBLCLICK_DELAY);\n } else {\n if (Math.abs(this.data.dblclickData.clientX - data.clientX) < this.moveThreshold && Math.abs(this.data.dblclickData.clientY - data.clientY) < this.moveThreshold) {\n this.viewer.dispatchEvent(new DoubleClickEvent(this.data.dblclickData));\n }\n clearTimeout(this.data.dblclickTimeout);\n this.data.dblclickTimeout = null;\n this.data.dblclickData = null;\n }\n }\n }\n /**\n * Trigger events for observed THREE objects\n */\n __handleObjectsEvents(evt) {\n if (!isEmpty(this.state.objectsObservers) && hasParent(evt.target, this.viewer.container)) {\n const viewerPos = getPosition(this.viewer.container);\n const viewerPoint = {\n x: evt.clientX - viewerPos.x,\n y: evt.clientY - viewerPos.y\n };\n const intersections = this.viewer.renderer.getIntersections(viewerPoint);\n const emit = (object, key, evtCtor) => {\n this.viewer.dispatchEvent(new evtCtor(evt, object, viewerPoint, key));\n };\n for (const [key, object] of Object.entries(this.state.objectsObservers)) {\n const intersection = intersections.find((i) => i.object.userData[key]);\n if (intersection) {\n if (object && intersection.object !== object) {\n emit(object, key, ObjectLeaveEvent);\n this.state.objectsObservers[key] = null;\n }\n if (!object) {\n this.state.objectsObservers[key] = intersection.object;\n emit(intersection.object, key, ObjectEnterEvent);\n } else {\n emit(intersection.object, key, ObjectHoverEvent);\n }\n } else if (object) {\n emit(object, key, ObjectLeaveEvent);\n this.state.objectsObservers[key] = null;\n }\n }\n }\n }\n /**\n * Starts moving when crossing moveThreshold and performs movement\n */\n __doMove(clientX, clientY) {\n if (this.step.is(Step.CLICK) && this.__moveThresholdReached(clientX, clientY)) {\n this.viewer.stopAll();\n this.__resetMove();\n this.step.set(Step.MOVING);\n this.data.mouseX = clientX;\n this.data.mouseY = clientY;\n this.__logMouseMove(clientX, clientY);\n } else if (this.step.is(Step.MOVING)) {\n this.__applyMove(clientX, clientY);\n this.__logMouseMove(clientX, clientY);\n }\n }\n /**\n * Checks if the cursor was move beyond the move threshold\n */\n __moveThresholdReached(clientX, clientY) {\n return Math.abs(clientX - this.data.startMouseX) >= this.moveThreshold || Math.abs(clientY - this.data.startMouseY) >= this.moveThreshold;\n }\n /**\n * Raw method for movement, called from mouse event and move inertia\n */\n __applyMove(clientX, clientY) {\n const rotation = {\n yaw: this.config.moveSpeed * ((clientX - this.data.mouseX) / this.state.size.width) * MathUtils6.degToRad(this.state.littlePlanet ? 90 : this.state.hFov),\n pitch: this.config.moveSpeed * ((clientY - this.data.mouseY) / this.state.size.height) * MathUtils6.degToRad(this.state.littlePlanet ? 90 : this.state.vFov)\n };\n const currentPosition = this.viewer.getPosition();\n this.viewer.rotate({\n yaw: currentPosition.yaw - rotation.yaw,\n pitch: currentPosition.pitch + rotation.pitch\n });\n this.data.mouseX = clientX;\n this.data.mouseY = clientY;\n }\n /**\n * Perfoms combined move and zoom\n */\n __doMoveZoom(evt) {\n if (this.step.is(Step.MOVING)) {\n evt.preventDefault();\n const touchData = getTouchData(evt);\n const delta = (touchData.distance - this.data.pinchDist) / SYSTEM.pixelRatio * this.config.zoomSpeed;\n this.viewer.zoom(this.viewer.getZoomLevel() + delta);\n this.__doMove(touchData.center.x, touchData.center.y);\n this.data.pinchDist = touchData.distance;\n }\n }\n /**\n * Stores each mouse position during a mouse move\n * @description Positions older than \"INERTIA_WINDOW\" are removed
\n * Positions before a pause of \"INERTIA_WINDOW\" / 10 are removed\n */\n __logMouseMove(clientX, clientY) {\n const now = Date.now();\n const last = this.data.mouseHistory.length ? this.data.mouseHistory[this.data.mouseHistory.length - 1] : [0, -1, -1];\n if (last[1] === clientX && last[2] === clientY) {\n last[0] = now;\n } else if (now === last[0]) {\n last[1] = clientX;\n last[2] = clientY;\n } else {\n this.data.mouseHistory.push([now, clientX, clientY]);\n }\n let previous = null;\n for (let i = 0; i < this.data.mouseHistory.length; ) {\n if (this.data.mouseHistory[i][0] < now - INERTIA_WINDOW) {\n this.data.mouseHistory.splice(i, 1);\n } else if (previous && this.data.mouseHistory[i][0] - previous > INERTIA_WINDOW / 10) {\n this.data.mouseHistory.splice(0, i);\n i = 0;\n previous = this.data.mouseHistory[i][0];\n } else {\n previous = this.data.mouseHistory[i][0];\n i++;\n }\n }\n }\n};\n\n// src/services/Renderer.ts\nimport {\n Group,\n PerspectiveCamera,\n Raycaster,\n Scene,\n Vector2 as Vector22,\n WebGLRenderer,\n WebGLRenderTarget,\n LinearSRGBColorSpace,\n Vector3 as Vector33\n} from \"three\";\nvar vector2 = new Vector22();\nvar Renderer = class extends AbstractService {\n /**\n * @internal\n */\n constructor(viewer) {\n super(viewer);\n this.renderer = new WebGLRenderer(this.config.rendererParameters);\n this.renderer.setPixelRatio(SYSTEM.pixelRatio);\n this.renderer.outputColorSpace = LinearSRGBColorSpace;\n this.renderer.domElement.className = \"psv-canvas\";\n this.scene = new Scene();\n this.camera = new PerspectiveCamera(50, 16 / 9, 0.1, 2 * SPHERE_RADIUS);\n this.camera.matrixWorldAutoUpdate = false;\n this.mesh = this.viewer.adapter.createMesh();\n this.mesh.userData = { [VIEWER_DATA]: true };\n this.meshContainer = new Group();\n this.meshContainer.add(this.mesh);\n this.scene.add(this.meshContainer);\n this.raycaster = new Raycaster();\n this.container = document.createElement(\"div\");\n this.container.className = \"psv-canvas-container\";\n this.container.appendChild(this.renderer.domElement);\n this.viewer.container.appendChild(this.container);\n this.viewer.addEventListener(SizeUpdatedEvent.type, this);\n this.viewer.addEventListener(ZoomUpdatedEvent.type, this);\n this.viewer.addEventListener(PositionUpdatedEvent.type, this);\n this.viewer.addEventListener(ConfigChangedEvent.type, this);\n this.hide();\n }\n get panoramaPose() {\n return this.mesh.rotation;\n }\n get sphereCorrection() {\n return this.meshContainer.rotation;\n }\n /**\n * @internal\n */\n init() {\n this.show();\n this.renderer.setAnimationLoop((t) => this.__renderLoop(t));\n }\n /**\n * @internal\n */\n destroy() {\n this.renderer.setAnimationLoop(null);\n this.cleanScene(this.scene);\n this.viewer.container.removeChild(this.container);\n this.viewer.removeEventListener(SizeUpdatedEvent.type, this);\n this.viewer.removeEventListener(ZoomUpdatedEvent.type, this);\n this.viewer.removeEventListener(PositionUpdatedEvent.type, this);\n this.viewer.removeEventListener(ConfigChangedEvent.type, this);\n super.destroy();\n }\n /**\n * @internal\n */\n handleEvent(e) {\n switch (e.type) {\n case SizeUpdatedEvent.type:\n this.__onSizeUpdated();\n break;\n case ZoomUpdatedEvent.type:\n this.__onZoomUpdated();\n break;\n case PositionUpdatedEvent.type:\n this.__onPositionUpdated();\n break;\n case ConfigChangedEvent.type:\n if (e.containsOptions(\"fisheye\")) {\n this.__onPositionUpdated();\n }\n if (e.containsOptions(\"canvasBackground\")) {\n this.container.style.background = this.config.canvasBackground;\n }\n break;\n }\n }\n /**\n * Hides the viewer\n */\n hide() {\n this.container.style.opacity = \"0\";\n }\n /**\n * Shows the viewer\n */\n show() {\n this.container.style.opacity = \"1\";\n }\n /**\n * Resets or replaces the THREE renderer by a custom one\n */\n setCustomRenderer(factory) {\n if (factory) {\n this.customRenderer = factory(this.renderer);\n } else {\n this.customRenderer = null;\n }\n this.viewer.needsUpdate();\n }\n /**\n * Updates the size of the renderer and the aspect of the camera\n */\n __onSizeUpdated() {\n this.renderer.setSize(this.state.size.width, this.state.size.height);\n this.camera.aspect = this.state.aspect;\n this.camera.updateProjectionMatrix();\n this.viewer.needsUpdate();\n }\n /**\n * Updates the fov of the camera\n */\n __onZoomUpdated() {\n this.camera.fov = this.state.vFov;\n this.camera.updateProjectionMatrix();\n this.viewer.needsUpdate();\n }\n /**\n * Updates the position of the camera\n */\n __onPositionUpdated() {\n this.camera.position.set(0, 0, 0);\n this.camera.lookAt(this.state.direction);\n if (this.config.fisheye) {\n this.camera.position.copy(this.state.direction).multiplyScalar(this.config.fisheye / 2).negate();\n }\n this.camera.updateMatrixWorld();\n this.viewer.needsUpdate();\n }\n /**\n * Main event loop, performs a render if `state.needsUpdate` is true\n */\n __renderLoop(timestamp) {\n const elapsed = !this.timestamp ? 0 : timestamp - this.timestamp;\n this.timestamp = timestamp;\n this.viewer.dispatchEvent(new BeforeRenderEvent(timestamp, elapsed));\n this.viewer.dynamics.update(elapsed);\n if (this.state.needsUpdate || this.state.continuousUpdateCount > 0) {\n (this.customRenderer || this.renderer).render(this.scene, this.camera);\n this.viewer.dispatchEvent(new RenderEvent());\n this.state.needsUpdate = false;\n }\n }\n /**\n * Applies the texture to the scene, creates the scene if needed\n * @internal\n */\n setTexture(textureData) {\n if (this.viewer.adapter.constructor.supportsOverlay) {\n this.setOverlay(null, 0);\n }\n if (this.state.textureData) {\n this.viewer.adapter.disposeTexture(this.state.textureData);\n }\n this.state.textureData = textureData;\n this.state.panoData = textureData.panoData;\n this.viewer.adapter.setTexture(this.mesh, textureData);\n this.viewer.needsUpdate();\n }\n /**\n * Applies the overlay to the mesh\n * @internal\n */\n setOverlay(textureData, opacity) {\n if (this.state.overlayData) {\n this.viewer.adapter.disposeTexture(this.state.overlayData);\n }\n this.state.overlayData = textureData;\n this.viewer.adapter.setOverlay(this.mesh, textureData, opacity);\n this.viewer.needsUpdate();\n }\n /**\n * Applies a panorama data pose to a Mesh\n * @internal\n */\n setPanoramaPose(panoData, mesh = this.mesh) {\n const cleanCorrection = this.viewer.dataHelper.cleanPanoramaPose(panoData);\n mesh.rotation.set(-cleanCorrection.tilt, -cleanCorrection.pan, -cleanCorrection.roll, \"ZXY\");\n }\n /**\n * Applies a SphereCorrection to a Group\n * @internal\n */\n setSphereCorrection(sphereCorrection, group = this.meshContainer) {\n const cleanCorrection = this.viewer.dataHelper.cleanSphereCorrection(sphereCorrection);\n group.rotation.set(cleanCorrection.tilt, cleanCorrection.pan, cleanCorrection.roll, \"ZXY\");\n }\n /**\n * Performs transition between the current and a new texture\n * @internal\n */\n transition(textureData, options) {\n const positionProvided = !isNil(options.position);\n const zoomProvided = !isNil(options.zoom);\n const e = new BeforeAnimateEvent(\n positionProvided ? this.viewer.dataHelper.cleanPosition(options.position) : void 0,\n options.zoom\n );\n this.viewer.dispatchEvent(e);\n const group = new Group();\n const mesh = this.viewer.adapter.createMesh(0.5);\n this.viewer.adapter.setTexture(mesh, textureData, true);\n this.viewer.adapter.setTextureOpacity(mesh, 0);\n this.setPanoramaPose(textureData.panoData, mesh);\n this.setSphereCorrection(options.sphereCorrection, group);\n if (positionProvided && options.transition === \"fade-only\") {\n const currentPosition = this.viewer.getPosition();\n const verticalAxis = new Vector33(0, 1, 0);\n group.rotateOnWorldAxis(verticalAxis, e.position.yaw - currentPosition.yaw);\n const horizontalAxis = new Vector33(0, 1, 0).cross(this.camera.getWorldDirection(new Vector33())).normalize();\n group.rotateOnWorldAxis(horizontalAxis, e.position.pitch - currentPosition.pitch);\n }\n group.add(mesh);\n this.scene.add(group);\n this.renderer.setRenderTarget(new WebGLRenderTarget());\n this.renderer.render(this.scene, this.camera);\n this.renderer.setRenderTarget(null);\n const { duration, properties } = this.viewer.dataHelper.getAnimationProperties(\n options.transition,\n options.transition === true ? e.position : null,\n e.zoomLevel\n );\n const animation = new Animation({\n properties: {\n ...properties,\n opacity: { start: 0, end: 1 }\n },\n duration,\n easing: \"inOutCubic\",\n onTick: (props) => {\n this.viewer.adapter.setTextureOpacity(mesh, props.opacity);\n if (positionProvided && options.transition === true) {\n this.viewer.dynamics.position.setValue({\n yaw: props.yaw,\n pitch: props.pitch\n });\n }\n if (zoomProvided) {\n this.viewer.dynamics.zoom.setValue(props.zoom);\n }\n this.viewer.needsUpdate();\n }\n });\n animation.then((completed) => {\n if (completed) {\n this.setTexture(textureData);\n this.viewer.adapter.setTextureOpacity(this.mesh, 1);\n this.setPanoramaPose(textureData.panoData);\n this.setSphereCorrection(options.sphereCorrection);\n if (positionProvided && options.transition === \"fade-only\") {\n this.viewer.rotate(options.position);\n }\n } else {\n this.viewer.adapter.disposeTexture(textureData);\n }\n this.scene.remove(group);\n mesh.geometry.dispose();\n mesh.geometry = null;\n });\n return animation;\n }\n /**\n * Returns intersections with objects in the scene\n */\n getIntersections(viewerPoint) {\n vector2.x = 2 * viewerPoint.x / this.state.size.width - 1;\n vector2.y = -2 * viewerPoint.y / this.state.size.height + 1;\n this.raycaster.setFromCamera(vector2, this.camera);\n const intersections = this.raycaster.intersectObjects(this.scene.children, true).filter((i) => i.object.isMesh && !!i.object.userData);\n if (this.customRenderer?.getIntersections) {\n intersections.push(...this.customRenderer.getIntersections(this.raycaster, vector2));\n }\n return intersections;\n }\n /**\n * Adds an object to the THREE scene\n */\n addObject(object) {\n this.scene.add(object);\n }\n /**\n * Removes an object from the THREE scene\n */\n removeObject(object) {\n this.scene.remove(object);\n }\n /**\n * Calls `dispose` on all objects and textures\n * @internal\n */\n cleanScene(object) {\n object.traverse((item) => {\n if (item.geometry) {\n item.geometry.dispose();\n }\n if (item.material) {\n if (Array.isArray(item.material)) {\n item.material.forEach((material) => {\n if (material.map) {\n material.map.dispose();\n }\n material.dispose();\n });\n } else {\n if (item.material.map) {\n item.material.map.dispose();\n }\n item.material.dispose();\n }\n }\n if (item.dispose && !(item instanceof Scene)) {\n item.dispose();\n }\n if (item !== object) {\n this.cleanScene(item);\n }\n });\n }\n};\n\n// src/services/TextureLoader.ts\nimport { FileLoader, ImageLoader } from \"three\";\nvar TextureLoader = class extends AbstractService {\n /**\n * @internal\n */\n constructor(viewer) {\n super(viewer);\n this.fileLoader = new FileLoader();\n this.fileLoader.setResponseType(\"blob\");\n this.imageLoader = new ImageLoader();\n if (this.config.withCredentials) {\n this.fileLoader.setWithCredentials(true);\n this.imageLoader.setCrossOrigin(\"use-credentials\");\n }\n }\n /**\n * @internal\n */\n destroy() {\n this.abortLoading();\n super.destroy();\n }\n /**\n * Cancels current HTTP requests\n * @internal\n */\n abortLoading() {\n }\n /**\n * Loads a Blob with FileLoader\n */\n loadFile(url, onProgress, cacheKey) {\n const cached = Cache.get(url, cacheKey);\n if (cached) {\n if (cached instanceof Blob) {\n onProgress?.(100);\n return Promise.resolve(cached);\n } else {\n Cache.remove(url, cacheKey);\n }\n }\n if (this.config.requestHeaders) {\n this.fileLoader.setRequestHeader(this.config.requestHeaders(url));\n }\n return new Promise((resolve, reject) => {\n let progress = 0;\n onProgress?.(progress);\n this.fileLoader.load(\n url,\n (result) => {\n progress = 100;\n onProgress?.(progress);\n Cache.add(url, cacheKey, result);\n resolve(result);\n },\n (e) => {\n if (e.lengthComputable) {\n const newProgress = e.loaded / e.total * 100;\n if (newProgress > progress) {\n progress = newProgress;\n onProgress?.(progress);\n }\n }\n },\n (err) => {\n reject(err);\n }\n );\n });\n }\n /**\n * Loads an image with ImageLoader or with FileLoader if progress is tracked or if request headers are configured\n */\n loadImage(url, onProgress, cacheKey) {\n const cached = Cache.get(url, cacheKey);\n if (cached) {\n onProgress?.(100);\n if (cached instanceof Blob) {\n return this.blobToImage(cached);\n } else {\n return Promise.resolve(cached);\n }\n }\n if (!onProgress && !this.config.requestHeaders) {\n return this.imageLoader.loadAsync(url).then((result) => {\n Cache.add(url, cacheKey, result);\n return result;\n });\n } else {\n return this.loadFile(url, onProgress, cacheKey).then((blob) => this.blobToImage(blob));\n }\n }\n /**\n * Converts a file loaded with {@link loadFile} into an image\n */\n blobToImage(blob) {\n return new Promise((resolve, reject) => {\n const img = document.createElement(\"img\");\n img.onload = () => {\n URL.revokeObjectURL(img.src);\n resolve(img);\n };\n img.onerror = reject;\n img.src = URL.createObjectURL(blob);\n });\n }\n /**\n * Preload a panorama file without displaying it\n */\n preloadPanorama(panorama) {\n if (this.viewer.adapter.supportsPreload(panorama)) {\n return this.viewer.adapter.loadTexture(panorama);\n } else {\n return Promise.reject(new PSVError(\"Current adapter does not support preload\"));\n }\n }\n};\n\n// src/services/ViewerDynamics.ts\nimport { MathUtils as MathUtils7 } from \"three\";\nvar ViewerDynamics = class extends AbstractService {\n /**\n * @internal\n */\n constructor(viewer) {\n super(viewer);\n this.zoom = new Dynamic(\n (zoomLevel) => {\n this.viewer.state.vFov = this.viewer.dataHelper.zoomLevelToFov(zoomLevel);\n this.viewer.state.hFov = this.viewer.dataHelper.vFovToHFov(this.viewer.state.vFov);\n this.viewer.dispatchEvent(new ZoomUpdatedEvent(zoomLevel));\n },\n {\n defaultValue: this.viewer.config.defaultZoomLvl,\n min: 0,\n max: 100,\n wrap: false\n }\n );\n this.position = new MultiDynamic(\n (position) => {\n this.viewer.dataHelper.sphericalCoordsToVector3(position, this.viewer.state.direction);\n this.viewer.dispatchEvent(new PositionUpdatedEvent(position));\n },\n {\n yaw: new Dynamic(null, {\n defaultValue: this.config.defaultYaw,\n min: 0,\n max: 2 * Math.PI,\n wrap: true\n }),\n pitch: new Dynamic(null, {\n defaultValue: this.config.defaultPitch,\n min: !this.viewer.state.littlePlanet ? -Math.PI / 2 : 0,\n max: !this.viewer.state.littlePlanet ? Math.PI / 2 : Math.PI * 2,\n wrap: this.viewer.state.littlePlanet\n })\n }\n );\n this.updateSpeeds();\n }\n /**\n * @internal\n */\n updateSpeeds() {\n this.zoom.setSpeed(this.config.zoomSpeed * 50);\n this.position.setSpeed(MathUtils7.degToRad(this.config.moveSpeed * 50));\n }\n /**\n * @internal\n */\n update(elapsed) {\n this.zoom.update(elapsed);\n this.position.update(elapsed);\n }\n};\n\n// src/services/ViewerState.ts\nimport { Vector3 as Vector34 } from \"three\";\nvar ViewerState = class {\n /**\n * @internal\n */\n // eslint-disable-next-line @typescript-eslint/no-empty-function\n constructor() {\n /**\n * when all components are loaded\n */\n this.ready = false;\n /**\n * if the view needs to be renderer\n */\n this.needsUpdate = false;\n /**\n * number of plugins requesting to continuously render the scene\n */\n this.continuousUpdateCount = 0;\n /**\n * if the keyboard events are currently listened to\n */\n this.keyboardEnabled = false;\n /**\n * direction of the camera\n */\n this.direction = new Vector34(0, 0, SPHERE_RADIUS);\n /**\n * vertical FOV\n */\n this.vFov = 60;\n /**\n * horizontal FOV\n */\n this.hFov = 60;\n /**\n * renderer aspect ratio\n */\n this.aspect = 1;\n /**\n * currently running animation\n */\n this.animation = null;\n /**\n * currently running transition\n */\n this.transitionAnimation = null;\n /**\n * promise of the last \"setPanorama()\" call\n */\n this.loadingPromise = null;\n /**\n * special tweaks for LittlePlanetAdapter\n */\n this.littlePlanet = false;\n /**\n * time of the last user action\n */\n this.idleTime = -1;\n /**\n * registered THREE objects observer\n */\n this.objectsObservers = {};\n /**\n * size of the container\n */\n this.size = {\n width: 0,\n height: 0\n };\n /**\n * panorama metadata, if supported\n */\n this.panoData = {\n fullWidth: 0,\n fullHeight: 0,\n croppedWidth: 0,\n croppedHeight: 0,\n croppedX: 0,\n croppedY: 0,\n poseHeading: 0,\n posePitch: 0,\n poseRoll: 0\n };\n }\n};\n\n// src/Viewer.ts\nvar Viewer = class extends TypedEventTarget {\n constructor(config) {\n super();\n /** @internal */\n this.plugins = {};\n /** @internal */\n this.children = [];\n this.onResize = throttle(() => this.navbar.autoSize(), 500);\n Cache.init();\n SYSTEM.load();\n this.state = new ViewerState();\n this.config = getViewerConfig(config);\n this.parent = getElement(config.container);\n this.parent[VIEWER_DATA] = this;\n this.container = document.createElement(\"div\");\n this.container.classList.add(\"psv-container\");\n this.parent.appendChild(this.container);\n checkStylesheet(this.container, \"core\");\n this.adapter = new this.config.adapter[0](this, this.config.adapter[1]);\n this.renderer = new Renderer(this);\n this.textureLoader = new TextureLoader(this);\n this.eventsHandler = new EventsHandler(this);\n this.dataHelper = new DataHelper(this);\n this.dynamics = new ViewerDynamics(this);\n this.adapter.init?.();\n this.loader = new Loader(this);\n this.navbar = new Navbar(this);\n this.panel = new Panel(this);\n this.notification = new Notification(this);\n this.overlay = new Overlay(this);\n this.resize(this.config.size);\n this.setCursor(null);\n resolveBoolean(SYSTEM.isTouchEnabled, (enabled) => {\n toggleClass(this.container, \"psv--is-touch\", enabled);\n });\n this.config.plugins.forEach(([plugin, opts]) => {\n this.plugins[plugin.id] = new plugin(this, opts);\n });\n for (const plugin of Object.values(this.plugins)) {\n plugin.init?.();\n }\n if (this.config.navbar) {\n this.navbar.setButtons(this.config.navbar);\n }\n if (!this.state.loadingPromise) {\n if (this.config.panorama) {\n this.setPanorama(this.config.panorama);\n } else {\n this.loader.show();\n }\n }\n }\n /**\n * Destroys the viewer\n */\n destroy() {\n this.stopAll();\n this.stopKeyboardControl();\n this.exitFullscreen();\n for (const [id, plugin] of Object.entries(this.plugins)) {\n plugin.destroy();\n delete this.plugins[id];\n }\n this.children.slice().forEach((child) => child.destroy());\n this.children.length = 0;\n this.eventsHandler.destroy();\n this.renderer.destroy();\n this.textureLoader.destroy();\n this.dataHelper.destroy();\n this.adapter.destroy();\n this.dynamics.destroy();\n this.parent.removeChild(this.container);\n delete this.parent[VIEWER_DATA];\n }\n init() {\n this.eventsHandler.init();\n this.renderer.init();\n if (this.config.navbar) {\n this.navbar.show();\n }\n if (this.config.keyboard === \"always\") {\n this.startKeyboardControl();\n }\n this.resetIdleTimer();\n this.state.ready = true;\n this.dispatchEvent(new ReadyEvent());\n }\n /**\n * Restarts the idle timer\n * @internal\n */\n resetIdleTimer() {\n this.state.idleTime = performance.now();\n }\n /**\n * Stops the idle timer\n * @internal\n */\n disableIdleTimer() {\n this.state.idleTime = -1;\n }\n /**\n * Returns the instance of a plugin if it exists\n * @example By plugin identifier\n * ```js\n * viewer.getPlugin('markers')\n * ```\n * @example By plugin class with TypeScript support\n * ```ts\n * viewer.getPlugin(MarkersPlugin)\n * ```\n */\n getPlugin(pluginId) {\n if (typeof pluginId === \"string\") {\n return this.plugins[pluginId];\n } else {\n const pluginCtor = pluginInterop(pluginId);\n return pluginCtor ? this.plugins[pluginCtor.id] : null;\n }\n }\n /**\n * Returns the current position of the camera\n */\n getPosition() {\n return this.dataHelper.cleanPosition(this.dynamics.position.current);\n }\n /**\n * Returns the current zoom level\n */\n getZoomLevel() {\n return this.dynamics.zoom.current;\n }\n /**\n * Returns the current viewer size\n */\n getSize() {\n return { ...this.state.size };\n }\n /**\n * Checks if the viewer is in fullscreen\n */\n isFullscreenEnabled() {\n return isFullscreenEnabled(this.parent);\n }\n /**\n * Request a new render of the scene\n */\n needsUpdate() {\n this.state.needsUpdate = true;\n }\n /**\n * Request the scene to be continuously renderer (when using videos)\n */\n needsContinuousUpdate(enabled) {\n if (enabled) {\n this.state.continuousUpdateCount++;\n } else if (this.state.continuousUpdateCount > 0) {\n this.state.continuousUpdateCount--;\n }\n }\n /**\n * Resizes the scene if the viewer is resized\n */\n autoSize() {\n if (this.container.clientWidth !== this.state.size.width || this.container.clientHeight !== this.state.size.height) {\n this.state.size.width = Math.round(this.container.clientWidth);\n this.state.size.height = Math.round(this.container.clientHeight);\n this.state.aspect = this.state.size.width / this.state.size.height;\n this.state.hFov = this.dataHelper.vFovToHFov(this.state.vFov);\n this.dispatchEvent(new SizeUpdatedEvent(this.getSize()));\n this.onResize();\n }\n }\n /**\n * Loads a new panorama file\n * @description Loads a new panorama file, optionally changing the camera position/zoom and activating the transition animation.
\n * If the \"options\" parameter is not defined, the camera will not move and the ongoing animation will continue.
\n * If another loading is already in progress it will be aborted.\n * @returns promise resolved with false if the loading was aborted by another call\n */\n setPanorama(path, options = {}) {\n this.textureLoader.abortLoading();\n this.state.transitionAnimation?.cancel();\n if (!this.state.ready) {\n [\"sphereCorrection\", \"panoData\", \"overlay\", \"overlayOpacity\"].forEach((opt) => {\n if (!(opt in options)) {\n options[opt] = this.config[opt];\n }\n });\n }\n if (isExtendedPosition(options)) {\n logWarn(`PanoramaOptions.yaw and PanoramaOptions.pitch are deprecated, use PanoramaOptions.position instead`);\n options.position = this.dataHelper.cleanPosition(options);\n }\n if (typeof options.transition === \"number\") {\n logWarn(`Use PanoramaOptions.speed to define the speed/duration of the transition`);\n options.speed = options.transition;\n options.transition = true;\n }\n if (options.transition === void 0) {\n options.transition = true;\n }\n if (options.speed === void 0) {\n options.speed = DEFAULT_TRANSITION;\n }\n if (options.showLoader === void 0) {\n options.showLoader = true;\n }\n if (options.caption === void 0) {\n options.caption = this.config.caption;\n }\n if (options.description === void 0) {\n options.description = this.config.description;\n }\n if (!options.panoData && typeof this.config.panoData === \"function\") {\n options.panoData = this.config.panoData;\n }\n const positionProvided = !isNil(options.position);\n const zoomProvided = !isNil(options.zoom);\n if (positionProvided || zoomProvided) {\n this.stopAll();\n }\n this.hideError();\n this.resetIdleTimer();\n this.config.panorama = path;\n this.config.caption = options.caption;\n this.config.description = options.description;\n const done = (err) => {\n this.loader.hide();\n this.state.loadingPromise = null;\n if (isAbortError(err)) {\n return false;\n } else if (err) {\n this.navbar.setCaption(\"\");\n this.showError(this.config.lang.loadError);\n console.error(err);\n this.dispatchEvent(new PanoramaErrorEvent(path, err));\n throw err;\n } else {\n this.setOverlay(options.overlay, options.overlayOpacity);\n this.navbar.setCaption(this.config.caption);\n return true;\n }\n };\n this.navbar.setCaption(`${this.config.loadingTxt || \"\"}`);\n if (options.showLoader || !this.state.ready) {\n this.loader.show();\n }\n const loadingPromise = this.adapter.loadTexture(this.config.panorama, options.panoData).then((textureData) => {\n if (textureData.panorama !== this.config.panorama) {\n this.adapter.disposeTexture(textureData);\n throw getAbortError();\n }\n return textureData;\n });\n if (!options.transition || !this.state.ready || !this.adapter.supportsTransition(this.config.panorama)) {\n this.state.loadingPromise = loadingPromise.then((textureData) => {\n this.renderer.show();\n this.renderer.setTexture(textureData);\n this.renderer.setPanoramaPose(textureData.panoData);\n this.renderer.setSphereCorrection(options.sphereCorrection);\n if (!this.state.ready) {\n this.init();\n }\n this.dispatchEvent(new PanoramaLoadedEvent(textureData));\n if (zoomProvided) {\n this.zoom(options.zoom);\n }\n if (positionProvided) {\n this.rotate(options.position);\n }\n }).then(\n () => done(),\n (err) => done(err)\n );\n } else {\n this.state.loadingPromise = loadingPromise.then((textureData) => {\n this.loader.hide();\n this.dispatchEvent(new PanoramaLoadedEvent(textureData));\n this.state.transitionAnimation = this.renderer.transition(textureData, options);\n return this.state.transitionAnimation;\n }).then((completed) => {\n this.state.transitionAnimation = null;\n if (!completed) {\n throw getAbortError();\n }\n }).then(\n () => done(),\n (err) => done(err)\n );\n }\n return this.state.loadingPromise;\n }\n /**\n * Loads a new overlay\n */\n setOverlay(path, opacity = this.config.overlayOpacity) {\n const supportsOverlay = this.adapter.constructor.supportsOverlay;\n if (!path) {\n if (supportsOverlay) {\n this.renderer.setOverlay(null, 0);\n }\n return Promise.resolve();\n } else {\n if (!supportsOverlay) {\n return Promise.reject(new PSVError(`Current adapter does not supports overlay`));\n }\n return this.adapter.loadTexture(\n path,\n (image) => {\n const p = this.state.panoData;\n const r = image.width / p.croppedWidth;\n return {\n fullWidth: r * p.fullWidth,\n fullHeight: r * p.fullHeight,\n croppedWidth: r * p.croppedWidth,\n croppedHeight: r * p.croppedHeight,\n croppedX: r * p.croppedX,\n croppedY: r * p.croppedY\n };\n },\n false\n ).then((textureData) => {\n this.renderer.setOverlay(textureData, opacity);\n });\n }\n }\n /**\n * Update options\n * @throws {@link PSVError} if the configuration is invalid\n */\n setOptions(options) {\n const rawConfig = {\n ...this.config,\n ...options\n };\n for (let [key, value] of Object.entries(options)) {\n if (!(key in DEFAULTS)) {\n logWarn(`Unknown option ${key}`);\n continue;\n }\n if (key in READONLY_OPTIONS) {\n logWarn(READONLY_OPTIONS[key]);\n continue;\n }\n if (key in CONFIG_PARSERS) {\n value = CONFIG_PARSERS[key](value, {\n rawConfig,\n defValue: DEFAULTS[key]\n });\n }\n this.config[key] = value;\n switch (key) {\n case \"mousemove\":\n if (!this.state.cursorOverride) {\n this.setCursor(null);\n }\n break;\n case \"caption\":\n this.navbar.setCaption(this.config.caption);\n break;\n case \"size\":\n this.resize(this.config.size);\n break;\n case \"sphereCorrection\":\n this.renderer.setSphereCorrection(this.config.sphereCorrection);\n break;\n case \"navbar\":\n case \"lang\":\n this.navbar.setButtons(this.config.navbar);\n break;\n case \"moveSpeed\":\n case \"zoomSpeed\":\n this.dynamics.updateSpeeds();\n break;\n case \"minFov\":\n case \"maxFov\":\n this.dynamics.zoom.setValue(this.dataHelper.fovToZoomLevel(this.state.vFov));\n this.dispatchEvent(new ZoomUpdatedEvent(this.getZoomLevel()));\n break;\n case \"keyboard\":\n if (this.config.keyboard === \"always\") {\n this.startKeyboardControl();\n } else {\n this.stopKeyboardControl();\n }\n break;\n default:\n break;\n }\n }\n this.needsUpdate();\n this.dispatchEvent(new ConfigChangedEvent(Object.keys(options)));\n }\n /**\n * Update options\n * @throws {@link PSVError} if the configuration is invalid\n */\n setOption(option, value) {\n this.setOptions({ [option]: value });\n }\n /**\n * Displays an error message over the viewer\n */\n showError(message) {\n this.overlay.show({\n id: IDS.ERROR,\n image: error_default,\n title: message,\n dissmisable: false\n });\n }\n /**\n * Hides the error message\n */\n hideError() {\n this.overlay.hide(IDS.ERROR);\n }\n /**\n * Rotates the view to specific position\n */\n rotate(position) {\n const e = new BeforeRotateEvent(this.dataHelper.cleanPosition(position));\n this.dispatchEvent(e);\n if (e.defaultPrevented) {\n return;\n }\n this.dynamics.position.setValue(e.position);\n }\n /**\n * Zooms to a specific level between `maxFov` and `minFov`\n */\n zoom(level) {\n this.dynamics.zoom.setValue(level);\n }\n /**\n * Increases the zoom level\n */\n zoomIn(step = 1) {\n this.dynamics.zoom.step(step);\n }\n /**\n * Decreases the zoom level\n */\n zoomOut(step = 1) {\n this.dynamics.zoom.step(-step);\n }\n /**\n * Rotates and zooms the view with a smooth animation\n */\n animate(options) {\n const positionProvided = isExtendedPosition(options);\n const zoomProvided = !isNil(options.zoom);\n const e = new BeforeAnimateEvent(\n positionProvided ? this.dataHelper.cleanPosition(options) : void 0,\n options.zoom\n );\n this.dispatchEvent(e);\n if (e.defaultPrevented) {\n return;\n }\n this.stopAll();\n const { duration, properties } = this.dataHelper.getAnimationProperties(options.speed, e.position, e.zoomLevel);\n if (!duration) {\n if (positionProvided) {\n this.rotate(e.position);\n }\n if (zoomProvided) {\n this.zoom(e.zoomLevel);\n }\n return new Animation(null);\n }\n this.state.animation = new Animation({\n properties,\n duration,\n easing: \"inOutSine\",\n onTick: (props) => {\n if (positionProvided) {\n this.dynamics.position.setValue({\n yaw: props.yaw,\n pitch: props.pitch\n });\n }\n if (zoomProvided) {\n this.dynamics.zoom.setValue(props.zoom);\n }\n }\n });\n this.state.animation.then(() => {\n this.state.animation = null;\n this.resetIdleTimer();\n });\n return this.state.animation;\n }\n /**\n * Stops the ongoing animation\n * @description The return value is a Promise because the is no guaranty the animation can be stopped synchronously.\n */\n stopAnimation() {\n if (this.state.animation) {\n this.state.animation.cancel();\n return this.state.animation;\n } else {\n return Promise.resolve();\n }\n }\n /**\n * Resizes the viewer\n */\n resize(size) {\n const s = size;\n [\"width\", \"height\"].forEach((dim) => {\n if (size && s[dim]) {\n if (/^[0-9.]+$/.test(s[dim])) {\n s[dim] += \"px\";\n }\n this.parent.style[dim] = s[dim];\n }\n });\n this.autoSize();\n }\n /**\n * Enters the fullscreen mode\n */\n enterFullscreen() {\n if (!this.isFullscreenEnabled()) {\n requestFullscreen(this.parent);\n }\n }\n /**\n * Exits the fullscreen mode\n */\n exitFullscreen() {\n if (this.isFullscreenEnabled()) {\n exitFullscreen();\n }\n }\n /**\n * Enters or exits the fullscreen mode\n */\n toggleFullscreen() {\n if (!this.isFullscreenEnabled()) {\n this.enterFullscreen();\n } else {\n this.exitFullscreen();\n }\n }\n /**\n * Enables the keyboard controls\n */\n startKeyboardControl() {\n this.state.keyboardEnabled = true;\n }\n /**\n * Disables the keyboard controls\n */\n stopKeyboardControl() {\n this.state.keyboardEnabled = false;\n }\n /**\n * Creates a new tooltip\n * @description Use {@link Tooltip.move} to update the tooltip without re-create\n * @throws {@link PSVError} if the configuration is invalid\n */\n createTooltip(config) {\n return new Tooltip(this, config);\n }\n /**\n * Changes the global mouse cursor\n */\n setCursor(cursor) {\n this.state.cursorOverride = cursor;\n if (!cursor) {\n this.container.style.cursor = this.config.mousemove ? \"move\" : \"default\";\n } else {\n this.container.style.cursor = cursor;\n }\n }\n /**\n * Subscribes to events on objects in the three.js scene\n * @param userDataKey - only objects with the following `userData` will be observed\n */\n observeObjects(userDataKey) {\n if (!this.state.objectsObservers[userDataKey]) {\n this.state.objectsObservers[userDataKey] = null;\n }\n }\n /**\n * Unsubscribes to events on objects\n */\n unobserveObjects(userDataKey) {\n delete this.state.objectsObservers[userDataKey];\n }\n /**\n * Stops all current animations\n * @internal\n */\n stopAll() {\n this.dispatchEvent(new StopAllEvent());\n this.disableIdleTimer();\n return this.stopAnimation();\n }\n};\n\n// src/index.ts\nCache2.enabled = false;\nColorManagement.enabled = false;\nexport {\n AbstractAdapter,\n AbstractButton,\n AbstractComponent,\n AbstractConfigurablePlugin,\n AbstractPlugin,\n constants_exports as CONSTANTS,\n DEFAULTS,\n EquirectangularAdapter,\n PSVError,\n SYSTEM,\n TypedEvent,\n Viewer,\n events_exports as events,\n registerButton,\n utils_exports as utils\n};\n//# sourceMappingURL=index.module.js.map","/*!\n * PhotoSphereViewer.MarkersPlugin 5.4.3\n * @copyright 2023 Damien \"Mistic\" Sorel\n * @licence MIT (https://opensource.org/licenses/MIT)\n */\nvar __defProp = Object.defineProperty;\nvar __export = (target, all) => {\n for (var name in all)\n __defProp(target, name, { get: all[name], enumerable: true });\n};\n\n// src/index.ts\nimport { DEFAULTS, registerButton } from \"@photo-sphere-viewer/core\";\n\n// src/events.ts\nvar events_exports = {};\n__export(events_exports, {\n EnterMarkerEvent: () => EnterMarkerEvent,\n GotoMarkerDoneEvent: () => GotoMarkerDoneEvent,\n HideMarkersEvent: () => HideMarkersEvent,\n LeaveMarkerEvent: () => LeaveMarkerEvent,\n MarkerVisibilityEvent: () => MarkerVisibilityEvent,\n MarkersPluginEvent: () => MarkersPluginEvent,\n RenderMarkersListEvent: () => RenderMarkersListEvent,\n SelectMarkerEvent: () => SelectMarkerEvent,\n SelectMarkerListEvent: () => SelectMarkerListEvent,\n SetMarkersEvent: () => SetMarkersEvent,\n ShowMarkersEvent: () => ShowMarkersEvent,\n UnselectMarkerEvent: () => UnselectMarkerEvent\n});\nimport { TypedEvent } from \"@photo-sphere-viewer/core\";\nvar MarkersPluginEvent = class extends TypedEvent {\n};\nvar _MarkerVisibilityEvent = class _MarkerVisibilityEvent extends MarkersPluginEvent {\n constructor(marker, visible) {\n super(_MarkerVisibilityEvent.type);\n this.marker = marker;\n this.visible = visible;\n }\n};\n_MarkerVisibilityEvent.type = \"marker-visibility\";\nvar MarkerVisibilityEvent = _MarkerVisibilityEvent;\nvar _GotoMarkerDoneEvent = class _GotoMarkerDoneEvent extends MarkersPluginEvent {\n constructor(marker) {\n super(_GotoMarkerDoneEvent.type);\n this.marker = marker;\n }\n};\n_GotoMarkerDoneEvent.type = \"goto-marker-done\";\nvar GotoMarkerDoneEvent = _GotoMarkerDoneEvent;\nvar _LeaveMarkerEvent = class _LeaveMarkerEvent extends MarkersPluginEvent {\n constructor(marker) {\n super(_LeaveMarkerEvent.type);\n this.marker = marker;\n }\n};\n_LeaveMarkerEvent.type = \"leave-marker\";\nvar LeaveMarkerEvent = _LeaveMarkerEvent;\nvar _EnterMarkerEvent = class _EnterMarkerEvent extends MarkersPluginEvent {\n constructor(marker) {\n super(_EnterMarkerEvent.type);\n this.marker = marker;\n }\n};\n_EnterMarkerEvent.type = \"enter-marker\";\nvar EnterMarkerEvent = _EnterMarkerEvent;\nvar _SelectMarkerEvent = class _SelectMarkerEvent extends MarkersPluginEvent {\n constructor(marker, doubleClick, rightClick) {\n super(_SelectMarkerEvent.type);\n this.marker = marker;\n this.doubleClick = doubleClick;\n this.rightClick = rightClick;\n }\n};\n_SelectMarkerEvent.type = \"select-marker\";\nvar SelectMarkerEvent = _SelectMarkerEvent;\nvar _SelectMarkerListEvent = class _SelectMarkerListEvent extends MarkersPluginEvent {\n constructor(marker) {\n super(_SelectMarkerListEvent.type);\n this.marker = marker;\n }\n};\n_SelectMarkerListEvent.type = \"select-marker-list\";\nvar SelectMarkerListEvent = _SelectMarkerListEvent;\nvar _UnselectMarkerEvent = class _UnselectMarkerEvent extends MarkersPluginEvent {\n constructor(marker) {\n super(_UnselectMarkerEvent.type);\n this.marker = marker;\n }\n};\n_UnselectMarkerEvent.type = \"unselect-marker\";\nvar UnselectMarkerEvent = _UnselectMarkerEvent;\nvar _HideMarkersEvent = class _HideMarkersEvent extends MarkersPluginEvent {\n constructor() {\n super(_HideMarkersEvent.type);\n }\n};\n_HideMarkersEvent.type = \"hide-markers\";\nvar HideMarkersEvent = _HideMarkersEvent;\nvar _SetMarkersEvent = class _SetMarkersEvent extends MarkersPluginEvent {\n constructor(markers) {\n super(_SetMarkersEvent.type);\n this.markers = markers;\n }\n};\n_SetMarkersEvent.type = \"set-markers\";\nvar SetMarkersEvent = _SetMarkersEvent;\nvar _ShowMarkersEvent = class _ShowMarkersEvent extends MarkersPluginEvent {\n constructor() {\n super(_ShowMarkersEvent.type);\n }\n};\n_ShowMarkersEvent.type = \"show-markers\";\nvar ShowMarkersEvent = _ShowMarkersEvent;\nvar _RenderMarkersListEvent = class _RenderMarkersListEvent extends MarkersPluginEvent {\n constructor(markers) {\n super(_RenderMarkersListEvent.type);\n this.markers = markers;\n }\n};\n_RenderMarkersListEvent.type = \"render-markers-list\";\nvar RenderMarkersListEvent = _RenderMarkersListEvent;\n\n// src/MarkersButton.ts\nimport { AbstractButton } from \"@photo-sphere-viewer/core\";\n\n// src/icons/pin.svg\nvar pin_default = '\\n';\n\n// src/MarkersButton.ts\nvar MarkersButton = class extends AbstractButton {\n constructor(navbar) {\n super(navbar, {\n className: \"psv-markers-button\",\n icon: pin_default,\n hoverScale: true,\n collapsable: true,\n tabbable: true\n });\n this.plugin = this.viewer.getPlugin(\"markers\");\n if (this.plugin) {\n this.plugin.addEventListener(ShowMarkersEvent.type, this);\n this.plugin.addEventListener(HideMarkersEvent.type, this);\n this.toggleActive(true);\n }\n }\n destroy() {\n if (this.plugin) {\n this.plugin.removeEventListener(ShowMarkersEvent.type, this);\n this.plugin.removeEventListener(HideMarkersEvent.type, this);\n }\n super.destroy();\n }\n isSupported() {\n return !!this.plugin;\n }\n handleEvent(e) {\n if (e instanceof ShowMarkersEvent) {\n this.toggleActive(true);\n } else if (e instanceof HideMarkersEvent) {\n this.toggleActive(false);\n }\n }\n onClick() {\n this.plugin.toggleAllMarkers();\n }\n};\nMarkersButton.id = \"markers\";\n\n// src/MarkersListButton.ts\nimport { AbstractButton as AbstractButton2, events } from \"@photo-sphere-viewer/core\";\n\n// src/constants.ts\nimport { utils } from \"@photo-sphere-viewer/core\";\n\n// src/icons/pin-list.svg\nvar pin_list_default = '\\n';\n\n// src/constants.ts\nvar SVG_NS = \"http://www.w3.org/2000/svg\";\nvar MARKER_DATA = \"psvMarker\";\nvar MARKER_DATA_KEY = utils.dasherize(MARKER_DATA);\nvar ID_PANEL_MARKER = \"marker\";\nvar ID_PANEL_MARKERS_LIST = \"markersList\";\nvar DEFAULT_HOVER_SCALE = {\n amount: 2,\n duration: 100,\n easing: \"linear\"\n};\nvar MARKERS_LIST_TEMPLATE = (markers, title) => `\n\n`;\n\n// src/MarkersListButton.ts\nvar MarkersListButton = class extends AbstractButton2 {\n constructor(navbar) {\n super(navbar, {\n className: \" psv-markers-list-button\",\n icon: pin_list_default,\n hoverScale: true,\n collapsable: true,\n tabbable: true\n });\n this.plugin = this.viewer.getPlugin(\"markers\");\n if (this.plugin) {\n this.viewer.addEventListener(events.ShowPanelEvent.type, this);\n this.viewer.addEventListener(events.HidePanelEvent.type, this);\n }\n }\n destroy() {\n this.viewer.removeEventListener(events.ShowPanelEvent.type, this);\n this.viewer.removeEventListener(events.HidePanelEvent.type, this);\n super.destroy();\n }\n isSupported() {\n return !!this.plugin;\n }\n handleEvent(e) {\n if (e instanceof events.ShowPanelEvent) {\n this.toggleActive(e.panelId === ID_PANEL_MARKERS_LIST);\n } else if (e instanceof events.HidePanelEvent) {\n this.toggleActive(false);\n }\n }\n onClick() {\n this.plugin.toggleMarkersList();\n }\n};\nMarkersListButton.id = \"markersList\";\n\n// src/MarkersPlugin.ts\nimport { AbstractConfigurablePlugin, PSVError as PSVError2, events as events2, utils as utils4 } from \"@photo-sphere-viewer/core\";\n\n// src/Marker.ts\nimport { CONSTANTS as CONSTANTS2, PSVError, utils as utils3 } from \"@photo-sphere-viewer/core\";\nimport {\n Group,\n MathUtils,\n Mesh,\n MeshBasicMaterial,\n PlaneGeometry,\n RepeatWrapping,\n Texture,\n Vector3 as Vector32,\n VideoTexture\n} from \"three\";\n\n// src/utils.ts\nimport { CONSTANTS, utils as utils2 } from \"@photo-sphere-viewer/core\";\nimport { Vector3 } from \"three\";\nfunction greatArcIntermediaryPoint(p1, p2, f) {\n const [\\u03BB1, \\u03C61] = p1;\n const [\\u03BB2, \\u03C62] = p2;\n const r = utils2.greatArcDistance(p1, p2);\n const a = Math.sin((1 - f) * r) / Math.sin(r);\n const b = Math.sin(f * r) / Math.sin(r);\n const x = a * Math.cos(\\u03C61) * Math.cos(\\u03BB1) + b * Math.cos(\\u03C62) * Math.cos(\\u03BB2);\n const y = a * Math.cos(\\u03C61) * Math.sin(\\u03BB1) + b * Math.cos(\\u03C62) * Math.sin(\\u03BB2);\n const z = a * Math.sin(\\u03C61) + b * Math.sin(\\u03C62);\n return [Math.atan2(y, x), Math.atan2(z, Math.sqrt(x * x + y * y))];\n}\nfunction getPolygonCoherentPoints(points) {\n const workPoints = [points[0]];\n let k = 0;\n for (let i = 1; i < points.length; i++) {\n const d = points[i - 1][0] - points[i][0];\n if (d > Math.PI) {\n k += 1;\n } else if (d < -Math.PI) {\n k -= 1;\n }\n workPoints.push([points[i][0] + k * 2 * Math.PI, points[i][1]]);\n }\n return workPoints;\n}\nfunction getPolygonCenter(polygon) {\n const points = getPolygonCoherentPoints(polygon);\n const sum = points.reduce((intermediary, point) => [intermediary[0] + point[0], intermediary[1] + point[1]]);\n return [utils2.parseAngle(sum[0] / polygon.length), sum[1] / polygon.length];\n}\nfunction getPolylineCenter(polyline) {\n const points = getPolygonCoherentPoints(polyline);\n let length = 0;\n const lengths = [];\n for (let i = 0; i < points.length - 1; i++) {\n const l = utils2.greatArcDistance(points[i], points[i + 1]) * CONSTANTS.SPHERE_RADIUS;\n lengths.push(l);\n length += l;\n }\n let consumed = 0;\n for (let j = 0; j < points.length - 1; j++) {\n if (consumed + lengths[j] > length / 2) {\n const r = (length / 2 - consumed) / lengths[j];\n return greatArcIntermediaryPoint(points[j], points[j + 1], r);\n }\n consumed += lengths[j];\n }\n return points[Math.round(points.length / 2)];\n}\nvar C = new Vector3();\nvar N = new Vector3();\nvar V = new Vector3();\nvar X = new Vector3();\nvar Y = new Vector3();\nvar A = new Vector3();\nfunction getGreatCircleIntersection(P1, P2, direction) {\n C.copy(direction).normalize();\n N.crossVectors(P1, P2).normalize();\n V.crossVectors(N, P1).normalize();\n X.copy(P1).multiplyScalar(-C.dot(V));\n Y.copy(V).multiplyScalar(C.dot(P1));\n const H = new Vector3().addVectors(X, Y).normalize();\n A.crossVectors(H, C);\n return H.applyAxisAngle(A, 0.01).multiplyScalar(CONSTANTS.SPHERE_RADIUS);\n}\n\n// src/Marker.ts\nvar MarkerType = /* @__PURE__ */ ((MarkerType2) => {\n MarkerType2[\"image\"] = \"image\";\n MarkerType2[\"imageLayer\"] = \"imageLayer\";\n MarkerType2[\"videoLayer\"] = \"videoLayer\";\n MarkerType2[\"html\"] = \"html\";\n MarkerType2[\"element\"] = \"element\";\n MarkerType2[\"polygon\"] = \"polygon\";\n MarkerType2[\"polygonPixels\"] = \"polygonPixels\";\n MarkerType2[\"polyline\"] = \"polyline\";\n MarkerType2[\"polylinePixels\"] = \"polylinePixels\";\n MarkerType2[\"square\"] = \"square\";\n MarkerType2[\"rect\"] = \"rect\";\n MarkerType2[\"circle\"] = \"circle\";\n MarkerType2[\"ellipse\"] = \"ellipse\";\n MarkerType2[\"path\"] = \"path\";\n return MarkerType2;\n})(MarkerType || {});\nvar Marker = class _Marker {\n constructor(viewer, plugin, config) {\n this.viewer = viewer;\n this.plugin = plugin;\n /** @internal */\n this.state = {\n dynamicSize: false,\n anchor: null,\n visible: false,\n staticTooltip: false,\n position: null,\n position2D: null,\n positions3D: null,\n size: null\n };\n if (!config.id) {\n throw new PSVError(\"missing marker id\");\n }\n this.type = _Marker.getType(config);\n if (this.isNormal()) {\n this.element = document.createElement(\"div\");\n } else if (this.isPolygon()) {\n this.element = document.createElementNS(SVG_NS, \"polygon\");\n } else if (this.isPolyline()) {\n this.element = document.createElementNS(SVG_NS, \"polyline\");\n } else if (this.isSvg()) {\n const svgType = this.type === \"square\" /* square */ ? \"rect\" : this.type;\n const elt = document.createElementNS(SVG_NS, svgType);\n this.element = document.createElementNS(SVG_NS, \"svg\");\n this.domElement.appendChild(elt);\n } else if (this.is3d()) {\n this.element = this.__createMesh();\n }\n if (!this.is3d()) {\n this.element.id = `psv-marker-${config.id}`;\n this.element[MARKER_DATA] = this;\n }\n if (this.isNormal() || this.isSvg()) {\n this.domElement.addEventListener(\"transitionend\", () => {\n this.domElement.style.transition = \"\";\n });\n }\n this.update(config);\n if (this.type === \"videoLayer\" /* videoLayer */) {\n this.viewer.needsContinuousUpdate(true);\n }\n }\n get id() {\n return this.config.id;\n }\n get data() {\n return this.config.data;\n }\n get domElement() {\n return !this.is3d() ? this.element : null;\n }\n get threeElement() {\n return this.is3d() ? this.element : null;\n }\n get video() {\n if (this.type === \"videoLayer\" /* videoLayer */) {\n const mesh = this.threeElement.children[0];\n return mesh.material.map.image;\n } else {\n utils3.logWarn(`Marker ${this.id} is not a video marker`);\n }\n }\n /**\n * @internal\n */\n destroy() {\n this.hideTooltip();\n if (this.is3d()) {\n delete this.threeElement.children[0].userData[MARKER_DATA];\n } else {\n delete this.element[MARKER_DATA];\n }\n if (this.type === \"videoLayer\" /* videoLayer */) {\n this.viewer.needsContinuousUpdate(false);\n }\n }\n /**\n * Checks if it is a 3D marker (imageLayer)\n */\n is3d() {\n return this.type === \"imageLayer\" /* imageLayer */ || this.type === \"videoLayer\" /* videoLayer */;\n }\n /**\n * Checks if it is a normal marker (image or html)\n */\n isNormal() {\n return this.type === \"image\" /* image */ || this.type === \"html\" /* html */ || this.type === \"element\" /* element */;\n }\n /**\n * Checks if it is a polygon/polyline marker\n */\n isPoly() {\n return this.isPolygon() || this.isPolyline();\n }\n /**\n * Checks if it is a polygon/polyline using pixel coordinates\n */\n isPolyPixels() {\n return this.type === \"polygonPixels\" /* polygonPixels */ || this.type === \"polylinePixels\" /* polylinePixels */;\n }\n /**\n * Checks if it is a polygon/polyline using radian coordinates\n */\n isPolyAngles() {\n return this.type === \"polygon\" /* polygon */ || this.type === \"polyline\" /* polyline */;\n }\n /**\n * Checks if it is a polygon marker\n */\n isPolygon() {\n return this.type === \"polygon\" /* polygon */ || this.type === \"polygonPixels\" /* polygonPixels */;\n }\n /**\n * Checks if it is a polyline marker\n */\n isPolyline() {\n return this.type === \"polyline\" /* polyline */ || this.type === \"polylinePixels\" /* polylinePixels */;\n }\n /**\n * Checks if it is an SVG marker\n */\n isSvg() {\n return this.type === \"square\" /* square */ || this.type === \"rect\" /* rect */ || this.type === \"circle\" /* circle */ || this.type === \"ellipse\" /* ellipse */ || this.type === \"path\" /* path */;\n }\n /**\n * Computes marker scale\n * @internal\n */\n getScale(zoomLevel, position, mouseover) {\n let scale = 1;\n if (typeof this.config.scale === \"function\") {\n scale = this.config.scale(zoomLevel, position);\n } else if (this.config.scale) {\n if (Array.isArray(this.config.scale.zoom)) {\n const [min, max] = this.config.scale.zoom;\n scale *= min + (max - min) * CONSTANTS2.EASINGS.inQuad(zoomLevel / 100);\n }\n if (Array.isArray(this.config.scale.yaw)) {\n const [min, max] = this.config.scale.yaw;\n const halfFov = MathUtils.degToRad(this.viewer.state.hFov) / 2;\n const arc = Math.abs(utils3.getShortestArc(this.state.position.yaw, position.yaw));\n scale *= max + (min - max) * CONSTANTS2.EASINGS.outQuad(Math.max(0, (halfFov - arc) / halfFov));\n }\n }\n if (mouseover && this.config.hoverScale) {\n scale *= this.config.hoverScale.amount;\n }\n return scale;\n }\n /**\n * Returns the markers list content for the marker, it can be either :\n * - the `listContent`\n * - the `tooltip`\n * - the `html`\n * - the `id`\n * @internal\n */\n getListContent() {\n if (this.config.listContent) {\n return this.config.listContent;\n } else if (this.config.tooltip?.content) {\n return this.config.tooltip.content;\n } else if (this.config.html) {\n return this.config.html;\n } else {\n return this.id;\n }\n }\n /**\n * Display the tooltip of this marker\n * @internal\n */\n showTooltip(clientX, clientY) {\n if (this.state.visible && this.config.tooltip?.content && this.state.position2D) {\n const config = {\n ...this.config.tooltip,\n style: {\n // prevents conflicts with tooltip tracking\n pointerEvents: this.state.staticTooltip ? \"auto\" : \"none\"\n },\n data: this,\n top: 0,\n left: 0\n };\n if (this.isPoly() || this.is3d()) {\n if (clientX || clientY) {\n const viewerPos = utils3.getPosition(this.viewer.container);\n config.top = clientY - viewerPos.y;\n config.left = clientX - viewerPos.x;\n config.box = {\n // separate the tooltip from the cursor\n width: 20,\n height: 20\n };\n } else {\n config.top = this.state.position2D.y;\n config.left = this.state.position2D.x;\n }\n } else {\n const position = this.viewer.dataHelper.vector3ToViewerCoords(this.state.positions3D[0]);\n let width = this.state.size.width;\n let height = this.state.size.height;\n if (this.config.hoverScale && !this.state.staticTooltip) {\n width *= this.config.hoverScale.amount;\n height *= this.config.hoverScale.amount;\n }\n config.top = position.y - height * this.state.anchor.y + height / 2;\n config.left = position.x - width * this.state.anchor.x + width / 2;\n config.box = { width, height };\n }\n if (this.tooltip) {\n this.tooltip.update(this.config.tooltip.content, config);\n } else {\n this.tooltip = this.viewer.createTooltip(config);\n }\n }\n }\n /**\n * Hides the tooltip of this marker\n * @internal\n */\n hideTooltip() {\n if (this.tooltip) {\n this.tooltip.hide();\n this.tooltip = null;\n }\n }\n /**\n * Updates the marker with new properties\n * @throws {@link PSVError} if the configuration is invalid\n * @internal\n */\n update(config) {\n const newType = _Marker.getType(config, true);\n if (newType !== void 0 && newType !== this.type) {\n throw new PSVError(\"cannot change marker type\");\n }\n if (utils3.isExtendedPosition(config)) {\n utils3.logWarn('Use the \"position\" property to configure the position of a marker');\n config.position = this.viewer.dataHelper.cleanPosition(config);\n }\n if (\"width\" in config && \"height\" in config) {\n utils3.logWarn('Use the \"size\" property to configure the size of a marker');\n config.size = { width: config[\"width\"], height: config[\"height\"] };\n }\n this.config = utils3.deepmerge(this.config, config);\n if (typeof this.config.tooltip === \"string\") {\n this.config.tooltip = { content: this.config.tooltip };\n }\n if (this.config.tooltip && !this.config.tooltip.trigger) {\n this.config.tooltip.trigger = \"hover\";\n }\n if (this.config.scale && Array.isArray(this.config.scale)) {\n this.config.scale = { zoom: this.config.scale };\n }\n if (typeof this.config.hoverScale === \"boolean\") {\n this.config.hoverScale = this.config.hoverScale ? this.plugin.config.defaultHoverScale || DEFAULT_HOVER_SCALE : null;\n } else if (typeof this.config.hoverScale === \"number\") {\n this.config.hoverScale = { amount: this.config.hoverScale };\n } else if (!this.config.hoverScale) {\n this.config.hoverScale = this.plugin.config.defaultHoverScale;\n }\n if (this.config.hoverScale) {\n this.config.hoverScale = {\n ...DEFAULT_HOVER_SCALE,\n ...this.plugin.config.defaultHoverScale,\n ...this.config.hoverScale\n };\n }\n if (utils3.isNil(this.config.visible)) {\n this.config.visible = true;\n }\n this.state.anchor = utils3.parsePoint(this.config.anchor);\n if (!this.is3d()) {\n const element = this.domElement;\n element.setAttribute(\"class\", \"psv-marker\");\n if (this.isNormal() || this.isSvg()) {\n element.classList.add(\"psv-marker--normal\");\n } else {\n element.classList.add(\"psv-marker--poly\");\n }\n if (this.state.visible) {\n element.classList.add(\"psv-marker--visible\");\n }\n if (this.config.tooltip) {\n element.classList.add(\"psv-marker--has-tooltip\");\n }\n if (this.config.content) {\n element.classList.add(\"psv-marker--has-content\");\n }\n if (this.config.className) {\n utils3.addClasses(element, this.config.className);\n }\n element.style.opacity = `${this.config.opacity ?? 1}`;\n if (this.config.style) {\n Object.assign(element.style, this.config.style);\n }\n }\n if (this.isNormal()) {\n this.__updateNormal();\n } else if (this.isPoly()) {\n this.__updatePoly();\n } else if (this.isSvg()) {\n this.__updateSvg();\n } else if (this.is3d()) {\n this.__update3d();\n }\n }\n /**\n * Updates a normal marker\n */\n __updateNormal() {\n const element = this.domElement;\n if (!utils3.isExtendedPosition(this.config.position)) {\n throw new PSVError(\"missing marker position\");\n }\n if (this.config.image && !this.config.size) {\n throw new PSVError(\"missing marker size\");\n }\n if (this.config.size) {\n this.state.dynamicSize = false;\n this.state.size = this.config.size;\n element.style.width = this.config.size.width + \"px\";\n element.style.height = this.config.size.height + \"px\";\n } else {\n this.state.dynamicSize = true;\n }\n switch (this.type) {\n case \"image\" /* image */:\n this.definition = this.config.image;\n element.style.backgroundImage = `url(${this.config.image})`;\n break;\n case \"html\" /* html */:\n this.definition = this.config.html;\n element.innerHTML = this.config.html;\n break;\n case \"element\" /* element */:\n if (this.definition !== this.config.element) {\n this.definition = this.config.element;\n element.childNodes.forEach((n) => n.remove());\n element.appendChild(this.config.element);\n this.config.element.style.display = \"block\";\n }\n break;\n }\n element.style.transformOrigin = `${this.state.anchor.x * 100}% ${this.state.anchor.y * 100}%`;\n this.state.position = this.viewer.dataHelper.cleanPosition(this.config.position);\n this.state.positions3D = [this.viewer.dataHelper.sphericalCoordsToVector3(this.state.position)];\n }\n /**\n * Updates an SVG marker\n */\n __updateSvg() {\n const svgElement = this.domElement.firstElementChild;\n if (!utils3.isExtendedPosition(this.config.position)) {\n throw new PSVError(\"missing marker position\");\n }\n this.state.dynamicSize = true;\n switch (this.type) {\n case \"square\" /* square */:\n this.definition = {\n x: 0,\n y: 0,\n width: this.config.square,\n height: this.config.square\n };\n break;\n case \"rect\" /* rect */:\n if (Array.isArray(this.config.rect)) {\n this.definition = {\n x: 0,\n y: 0,\n width: this.config.rect[0],\n height: this.config.rect[1]\n };\n } else {\n this.definition = {\n x: 0,\n y: 0,\n width: this.config.rect.width,\n height: this.config.rect.height\n };\n }\n break;\n case \"circle\" /* circle */:\n this.definition = {\n cx: this.config.circle,\n cy: this.config.circle,\n r: this.config.circle\n };\n break;\n case \"ellipse\" /* ellipse */:\n if (Array.isArray(this.config.ellipse)) {\n this.definition = {\n cx: this.config.ellipse[0],\n cy: this.config.ellipse[1],\n rx: this.config.ellipse[0],\n ry: this.config.ellipse[1]\n };\n } else {\n this.definition = {\n cx: this.config.ellipse.rx,\n cy: this.config.ellipse.ry,\n rx: this.config.ellipse.rx,\n ry: this.config.ellipse.ry\n };\n }\n break;\n case \"path\" /* path */:\n this.definition = {\n d: this.config.path\n };\n break;\n }\n Object.entries(this.definition).forEach(([prop, value]) => {\n svgElement.setAttributeNS(null, prop, value);\n });\n if (this.config.svgStyle) {\n Object.entries(this.config.svgStyle).forEach(([prop, value]) => {\n svgElement.setAttributeNS(null, utils3.dasherize(prop), value);\n });\n } else {\n svgElement.setAttributeNS(null, \"fill\", \"rgba(0,0,0,0.5)\");\n }\n this.domElement.style.transformOrigin = `${this.state.anchor.x * 100}% ${this.state.anchor.y * 100}%`;\n this.state.position = this.viewer.dataHelper.cleanPosition(this.config.position);\n this.state.positions3D = [this.viewer.dataHelper.sphericalCoordsToVector3(this.state.position)];\n }\n /**\n * Updates a polygon marker\n */\n __updatePoly() {\n const element = this.domElement;\n this.state.dynamicSize = true;\n if (this.config.svgStyle) {\n Object.entries(this.config.svgStyle).forEach(([prop, value]) => {\n element.setAttributeNS(null, utils3.dasherize(prop), value);\n });\n if (this.isPolyline() && !this.config.svgStyle.fill) {\n element.setAttributeNS(null, \"fill\", \"none\");\n }\n } else if (this.isPolygon()) {\n element.setAttributeNS(null, \"fill\", \"rgba(0,0,0,0.5)\");\n } else if (this.isPolyline()) {\n element.setAttributeNS(null, \"fill\", \"none\");\n element.setAttributeNS(null, \"stroke\", \"rgb(0,0,0)\");\n }\n const actualPoly = this.config[this.type];\n if (!Array.isArray(actualPoly[0])) {\n for (let i = 0; i < actualPoly.length; i++) {\n actualPoly.splice(i, 2, [actualPoly[i], actualPoly[i + 1]]);\n }\n }\n if (this.isPolyPixels()) {\n this.definition = actualPoly.map((coord) => {\n const sphericalCoords = this.viewer.dataHelper.textureCoordsToSphericalCoords({\n textureX: coord[0],\n textureY: coord[1]\n });\n return [sphericalCoords.yaw, sphericalCoords.pitch];\n });\n } else {\n this.definition = actualPoly.map((coord) => {\n return [utils3.parseAngle(coord[0]), utils3.parseAngle(coord[1], true)];\n });\n }\n const centroid = this.isPolygon() ? getPolygonCenter(this.definition) : getPolylineCenter(this.definition);\n this.state.position = { yaw: centroid[0], pitch: centroid[1] };\n this.state.positions3D = this.definition.map((coord) => {\n return this.viewer.dataHelper.sphericalCoordsToVector3({ yaw: coord[0], pitch: coord[1] });\n });\n }\n /**\n * Updates a 3D marker\n */\n __update3d() {\n const element = this.threeElement;\n const mesh = element.children[0];\n this.state.dynamicSize = false;\n if (utils3.isExtendedPosition(this.config.position)) {\n if (!this.config.size) {\n throw new PSVError(\"missing marker size\");\n }\n this.state.position = this.viewer.dataHelper.cleanPosition(this.config.position);\n this.state.size = this.config.size;\n mesh.position.set(0.5 - this.state.anchor.x, this.state.anchor.y - 0.5, 0);\n this.viewer.dataHelper.sphericalCoordsToVector3(this.state.position, element.position);\n element.lookAt(0, element.position.y, 0);\n switch (this.config.orientation) {\n case \"horizontal\":\n element.rotateX(this.state.position.pitch < 0 ? -Math.PI / 2 : Math.PI / 2);\n break;\n case \"vertical-left\":\n element.rotateY(-Math.PI * 0.4);\n break;\n case \"vertical-right\":\n element.rotateY(Math.PI * 0.4);\n break;\n }\n element.scale.set(this.config.size.width / 100, this.config.size.height / 100, 1);\n const p = mesh.geometry.getAttribute(\"position\");\n this.state.positions3D = [0, 1, 3, 2].map((i) => {\n const v3 = new Vector32();\n v3.fromBufferAttribute(p, i);\n return mesh.localToWorld(v3);\n });\n } else {\n if (this.config.position?.length !== 4) {\n throw new PSVError(\"missing marker position\");\n }\n const positions = this.config.position.map((p2) => this.viewer.dataHelper.cleanPosition(p2));\n const positions3D = positions.map((p2) => this.viewer.dataHelper.sphericalCoordsToVector3(p2));\n const centroid = getPolygonCenter(positions.map(({ yaw, pitch }) => [yaw, pitch]));\n this.state.position = { yaw: centroid[0], pitch: centroid[1] };\n this.state.positions3D = positions3D;\n const p = mesh.geometry.getAttribute(\"position\");\n [\n positions3D[0],\n positions3D[1],\n positions3D[3],\n // not a mistake!\n positions3D[2]\n ].forEach((v, i) => {\n p.setX(i, v.x);\n p.setY(i, v.y);\n p.setZ(i, v.z);\n });\n p.needsUpdate = true;\n this.__setTextureWrap(mesh.material.map);\n }\n switch (this.type) {\n case \"videoLayer\" /* videoLayer */:\n if (this.definition !== this.config.videoLayer) {\n mesh.material.map?.dispose();\n const video = document.createElement(\"video\");\n video.crossOrigin = this.viewer.config.withCredentials ? \"use-credentials\" : \"anonymous\";\n video.loop = true;\n video.playsInline = true;\n video.muted = true;\n video.autoplay = true;\n video.preload = \"metadata\";\n video.src = this.config.videoLayer;\n this.viewer.container.appendChild(video);\n mesh.material.map = new VideoTexture(video);\n if (!utils3.isExtendedPosition(this.config.position)) {\n video.addEventListener(\"loadedmetadata\", () => {\n mesh.material.map.userData[MARKER_DATA] = { width: video.videoWidth, height: video.videoHeight };\n this.__setTextureWrap(mesh.material.map);\n }, { once: true });\n }\n video.play();\n this.definition = this.config.videoLayer;\n }\n break;\n case \"imageLayer\" /* imageLayer */:\n if (this.definition !== this.config.imageLayer) {\n mesh.material.map?.dispose();\n mesh.material.map = new Texture();\n this.viewer.textureLoader.loadImage(this.config.imageLayer).then((image) => {\n if (!utils3.isExtendedPosition(this.config.position)) {\n mesh.material.map.userData[MARKER_DATA] = { width: image.width, height: image.height };\n this.__setTextureWrap(mesh.material.map);\n }\n mesh.material.map.image = image;\n mesh.material.map.anisotropy = 4;\n mesh.material.map.needsUpdate = true;\n this.viewer.needsUpdate();\n });\n this.definition = this.config.imageLayer;\n }\n break;\n }\n mesh.material.opacity = this.config.opacity ?? 1;\n }\n /**\n * For layers positionned by corners, applies offset to the texture in order to keep its proportions\n */\n __setTextureWrap(texture) {\n if (!texture) {\n return;\n }\n const imageSize = texture.userData[MARKER_DATA];\n if (!imageSize || !imageSize.height || !imageSize.width) {\n texture.repeat.set(1, 1);\n texture.offset.set(0, 0);\n return;\n }\n const positions = this.config.position.map((p) => {\n return this.viewer.dataHelper.cleanPosition(p);\n });\n const w1 = utils3.greatArcDistance(\n [positions[0].yaw, positions[0].pitch],\n [positions[1].yaw, positions[1].pitch]\n );\n const w2 = utils3.greatArcDistance(\n [positions[3].yaw, positions[3].pitch],\n [positions[2].yaw, positions[2].pitch]\n );\n const h1 = utils3.greatArcDistance(\n [positions[1].yaw, positions[1].pitch],\n [positions[2].yaw, positions[2].pitch]\n );\n const h2 = utils3.greatArcDistance(\n [positions[0].yaw, positions[0].pitch],\n [positions[3].yaw, positions[3].pitch]\n );\n const layerRatio = (w1 + w2) / (h1 + h2);\n const imageRatio = imageSize.width / imageSize.height;\n let hMargin = 0;\n let vMargin = 0;\n if (layerRatio < imageRatio) {\n hMargin = imageRatio - layerRatio;\n } else {\n vMargin = 1 / imageRatio - 1 / layerRatio;\n }\n texture.wrapS = RepeatWrapping;\n texture.wrapT = RepeatWrapping;\n texture.repeat.set(1 - hMargin, 1 - vMargin);\n texture.offset.set(hMargin / 2, vMargin / 2);\n texture.needsUpdate = true;\n }\n __createMesh() {\n const material = new MeshBasicMaterial({\n transparent: true,\n opacity: 1,\n depthTest: false\n });\n const geometry = new PlaneGeometry(1, 1);\n const mesh = new Mesh(geometry, material);\n mesh.userData = { [MARKER_DATA]: this };\n const element = new Group().add(mesh);\n Object.defineProperty(element, \"visible\", {\n enumerable: true,\n get: function() {\n return this.children[0].userData[MARKER_DATA].state.visible;\n },\n set: function(visible) {\n this.children[0].userData[MARKER_DATA].state.visible = visible;\n }\n });\n return element;\n }\n /**\n * Computes the real size of a marker\n * @description This is done by removing all it's transformations (if any) and making it visible\n * before querying its bounding rect\n */\n updateSize() {\n if (!this.state.dynamicSize) {\n return;\n }\n if (!this.isNormal() && !this.isSvg()) {\n return;\n }\n const element = this.domElement;\n const init = !this.state.size;\n if (init) {\n element.classList.add(\"psv-marker--transparent\");\n }\n if (this.isSvg()) {\n const rect = element.firstElementChild.getBoundingClientRect();\n this.state.size = {\n width: rect.width,\n height: rect.height\n };\n } else {\n this.state.size = {\n width: element.offsetWidth,\n height: element.offsetHeight\n };\n }\n if (init) {\n element.classList.remove(\"psv-marker--transparent\");\n }\n if (this.isSvg()) {\n element.style.width = this.state.size.width + \"px\";\n element.style.height = this.state.size.height + \"px\";\n }\n if (this.type !== \"element\" /* element */) {\n this.state.dynamicSize = false;\n }\n }\n /**\n * Determines the type of a marker by the available properties\n * @throws {@link PSVError} when the marker's type cannot be found\n */\n static getType(config, allowNone = false) {\n const found = [];\n Object.keys(MarkerType).forEach((type) => {\n if (config[type]) {\n found.push(type);\n }\n });\n if (found.length === 0 && !allowNone) {\n throw new PSVError(`missing marker content, either ${Object.keys(MarkerType).join(\", \")}`);\n } else if (found.length > 1) {\n throw new PSVError(`multiple marker content, either ${Object.keys(MarkerType).join(\", \")}`);\n }\n return found[0];\n }\n};\n\n// src/MarkersPlugin.ts\nvar getConfig = utils4.getConfigParser(\n {\n clickEventOnMarker: false,\n gotoMarkerSpeed: \"8rpm\",\n markers: null,\n defaultHoverScale: null\n },\n {\n defaultHoverScale(defaultHoverScale) {\n if (!defaultHoverScale) {\n return null;\n }\n if (defaultHoverScale === true) {\n defaultHoverScale = DEFAULT_HOVER_SCALE;\n }\n if (typeof defaultHoverScale === \"number\") {\n defaultHoverScale = { amount: defaultHoverScale };\n }\n return {\n ...DEFAULT_HOVER_SCALE,\n ...defaultHoverScale\n };\n }\n }\n);\nvar MarkersPlugin = class extends AbstractConfigurablePlugin {\n constructor(viewer, config) {\n super(viewer, config);\n this.markers = {};\n this.state = {\n visible: true,\n showAllTooltips: false,\n currentMarker: null,\n hoveringMarker: null,\n // require a 2nd render (only the scene) when 3d markers visibility changes\n needsReRender: false\n };\n this.container = document.createElement(\"div\");\n this.container.className = \"psv-markers\";\n this.viewer.container.appendChild(this.container);\n this.svgContainer = document.createElementNS(SVG_NS, \"svg\");\n this.svgContainer.setAttribute(\"class\", \"psv-markers-svg-container\");\n this.container.appendChild(this.svgContainer);\n this.container.addEventListener(\"mouseenter\", this, true);\n this.container.addEventListener(\"mouseleave\", this, true);\n this.container.addEventListener(\"mousemove\", this, true);\n this.container.addEventListener(\"contextmenu\", this);\n }\n /**\n * @internal\n */\n init() {\n super.init();\n utils4.checkStylesheet(this.viewer.container, \"markers-plugin\");\n this.viewer.addEventListener(events2.ClickEvent.type, this);\n this.viewer.addEventListener(events2.DoubleClickEvent.type, this);\n this.viewer.addEventListener(events2.RenderEvent.type, this);\n this.viewer.addEventListener(events2.ConfigChangedEvent.type, this);\n this.viewer.addEventListener(events2.ObjectEnterEvent.type, this);\n this.viewer.addEventListener(events2.ObjectHoverEvent.type, this);\n this.viewer.addEventListener(events2.ObjectLeaveEvent.type, this);\n this.viewer.addEventListener(events2.ReadyEvent.type, this, { once: true });\n }\n /**\n * @internal\n */\n destroy() {\n this.clearMarkers(false);\n this.viewer.unobserveObjects(MARKER_DATA);\n this.viewer.removeEventListener(events2.ClickEvent.type, this);\n this.viewer.removeEventListener(events2.DoubleClickEvent.type, this);\n this.viewer.removeEventListener(events2.RenderEvent.type, this);\n this.viewer.removeEventListener(events2.ObjectEnterEvent.type, this);\n this.viewer.removeEventListener(events2.ObjectHoverEvent.type, this);\n this.viewer.removeEventListener(events2.ObjectLeaveEvent.type, this);\n this.viewer.removeEventListener(events2.ReadyEvent.type, this);\n this.viewer.container.removeChild(this.container);\n super.destroy();\n }\n /**\n * @internal\n */\n handleEvent(e) {\n switch (e.type) {\n case events2.ReadyEvent.type:\n if (this.config.markers) {\n this.setMarkers(this.config.markers);\n delete this.config.markers;\n }\n break;\n case events2.RenderEvent.type:\n this.renderMarkers();\n break;\n case events2.ClickEvent.type:\n this.__onClick(e, false);\n break;\n case events2.DoubleClickEvent.type:\n this.__onClick(e, true);\n break;\n case events2.ObjectEnterEvent.type:\n case events2.ObjectLeaveEvent.type:\n case events2.ObjectHoverEvent.type:\n if (e.userDataKey === MARKER_DATA) {\n const event = e.originalEvent;\n const marker = e.object.userData[MARKER_DATA];\n switch (e.type) {\n case events2.ObjectEnterEvent.type:\n if (marker.config.style?.cursor) {\n this.viewer.setCursor(marker.config.style.cursor);\n } else if (marker.config.tooltip || marker.config.content) {\n this.viewer.setCursor(\"pointer\");\n }\n this.__onEnterMarker(event, marker);\n break;\n case events2.ObjectLeaveEvent.type:\n this.viewer.setCursor(null);\n this.__onLeaveMarker(marker);\n break;\n case events2.ObjectHoverEvent.type:\n this.__onHoverMarker(event, marker);\n break;\n }\n }\n break;\n case \"mouseenter\":\n this.__onEnterMarker(e, this.__getTargetMarker(e.target));\n break;\n case \"mouseleave\":\n this.__onLeaveMarker(this.__getTargetMarker(e.target));\n break;\n case \"mousemove\":\n this.__onHoverMarker(e, this.__getTargetMarker(e.target, true));\n break;\n case \"contextmenu\":\n e.preventDefault();\n break;\n }\n }\n /**\n * Toggles all markers\n */\n toggleAllMarkers() {\n if (this.state.visible) {\n this.hideAllMarkers();\n } else {\n this.showAllMarkers();\n }\n }\n /**\n * Shows all markers\n */\n showAllMarkers() {\n this.state.visible = true;\n this.renderMarkers();\n this.dispatchEvent(new ShowMarkersEvent());\n }\n /**\n * Hides all markers\n */\n hideAllMarkers() {\n this.state.visible = false;\n this.renderMarkers();\n this.dispatchEvent(new HideMarkersEvent());\n }\n /**\n * Toggles the visibility of all tooltips\n */\n toggleAllTooltips() {\n if (this.state.showAllTooltips) {\n this.hideAllTooltips();\n } else {\n this.showAllTooltips();\n }\n }\n /**\n * Displays all tooltips\n */\n showAllTooltips() {\n this.state.showAllTooltips = true;\n Object.values(this.markers).forEach((marker) => {\n marker.state.staticTooltip = true;\n marker.showTooltip();\n });\n }\n /**\n * Hides all tooltips\n */\n hideAllTooltips() {\n this.state.showAllTooltips = false;\n Object.values(this.markers).forEach((marker) => {\n marker.state.staticTooltip = false;\n marker.hideTooltip();\n });\n }\n /**\n * Returns the total number of markers\n */\n getNbMarkers() {\n return Object.keys(this.markers).length;\n }\n /**\n * Returns all the markers\n */\n getMarkers() {\n return Object.values(this.markers);\n }\n /**\n * Adds a new marker to viewer\n * @throws {@link PSVError} when the marker's id is missing or already exists\n */\n addMarker(config, render = true) {\n if (this.markers[config.id]) {\n throw new PSVError2(`marker \"${config.id}\" already exists`);\n }\n const marker = new Marker(this.viewer, this, config);\n if (marker.isPoly()) {\n this.svgContainer.appendChild(marker.domElement);\n } else if (marker.is3d()) {\n this.viewer.renderer.addObject(marker.threeElement);\n } else {\n this.container.appendChild(marker.domElement);\n }\n this.markers[marker.id] = marker;\n if (this.state.showAllTooltips) {\n marker.state.staticTooltip = true;\n }\n if (render) {\n this.__afterChangerMarkers();\n }\n }\n /**\n * Returns the internal marker object for a marker id\n * @throws {@link PSVError} when the marker cannot be found\n */\n getMarker(markerId) {\n const id = typeof markerId === \"object\" ? markerId.id : markerId;\n if (!this.markers[id]) {\n throw new PSVError2(`cannot find marker \"${id}\"`);\n }\n return this.markers[id];\n }\n /**\n * Returns the last marker selected by the user\n */\n getCurrentMarker() {\n return this.state.currentMarker;\n }\n /**\n * Updates the existing marker with the same id\n * @description Every property can be changed but you can't change its type (Eg: `image` to `html`)\n */\n updateMarker(config, render = true) {\n const marker = this.getMarker(config.id);\n marker.update(config);\n if (render) {\n this.__afterChangerMarkers();\n if (marker === this.state.hoveringMarker && marker.config.tooltip?.trigger === \"hover\" || marker.state.staticTooltip) {\n marker.showTooltip();\n }\n }\n }\n /**\n * Removes a marker from the viewer\n */\n removeMarker(markerId, render = true) {\n const marker = this.getMarker(markerId);\n if (marker.isPoly()) {\n this.svgContainer.removeChild(marker.domElement);\n } else if (marker.is3d()) {\n this.viewer.renderer.removeObject(marker.threeElement);\n } else {\n this.container.removeChild(marker.domElement);\n }\n if (this.state.hoveringMarker === marker) {\n this.state.hoveringMarker = null;\n }\n if (this.state.currentMarker === marker) {\n this.state.currentMarker = null;\n }\n marker.destroy();\n delete this.markers[marker.id];\n if (render) {\n this.__afterChangerMarkers();\n }\n }\n /**\n * Removes multiple markers\n */\n removeMarkers(markerIds, render = true) {\n markerIds.forEach((markerId) => this.removeMarker(markerId, false));\n if (render) {\n this.__afterChangerMarkers();\n }\n }\n /**\n * Replaces all markers\n */\n setMarkers(markers, render = true) {\n this.clearMarkers(false);\n markers?.forEach((marker) => {\n this.addMarker(marker, false);\n });\n if (render) {\n this.__afterChangerMarkers();\n }\n }\n /**\n * Removes all markers\n */\n clearMarkers(render = true) {\n Object.keys(this.markers).forEach((markerId) => {\n this.removeMarker(markerId, false);\n });\n if (render) {\n this.__afterChangerMarkers();\n }\n }\n /**\n * Rotate the view to face the marker\n */\n gotoMarker(markerId, speed = this.config.gotoMarkerSpeed) {\n const marker = this.getMarker(markerId);\n if (!speed) {\n this.viewer.rotate(marker.state.position);\n if (!utils4.isNil(marker.config.zoomLvl)) {\n this.viewer.zoom(marker.config.zoomLvl);\n }\n this.dispatchEvent(new GotoMarkerDoneEvent(marker));\n return Promise.resolve();\n } else {\n return this.viewer.animate({\n ...marker.state.position,\n zoom: marker.config.zoomLvl,\n speed\n }).then(() => {\n this.dispatchEvent(new GotoMarkerDoneEvent(marker));\n });\n }\n }\n /**\n * Hides a marker\n */\n hideMarker(markerId) {\n this.toggleMarker(markerId, false);\n }\n /**\n * Shows a marker\n */\n showMarker(markerId) {\n this.toggleMarker(markerId, true);\n }\n /**\n * Forces the display of the tooltip of a marker\n */\n showMarkerTooltip(markerId) {\n const marker = this.getMarker(markerId);\n marker.state.staticTooltip = true;\n marker.showTooltip();\n }\n /**\n * Hides the tooltip of a marker\n */\n hideMarkerTooltip(markerId) {\n const marker = this.getMarker(markerId);\n marker.state.staticTooltip = false;\n marker.hideTooltip();\n }\n /**\n * Toggles a marker visibility\n */\n toggleMarker(markerId, visible) {\n const marker = this.getMarker(markerId);\n marker.config.visible = utils4.isNil(visible) ? !marker.config.visible : visible;\n this.renderMarkers();\n }\n /**\n * Opens the panel with the content of the marker\n */\n showMarkerPanel(markerId) {\n const marker = this.getMarker(markerId);\n if (marker?.config?.content) {\n this.viewer.panel.show({\n id: ID_PANEL_MARKER,\n content: marker.config.content\n });\n } else {\n this.hideMarkerPanel();\n }\n }\n /**\n * Closes the panel if currently showing the content of a marker\n */\n hideMarkerPanel() {\n this.viewer.panel.hide(ID_PANEL_MARKER);\n }\n /**\n * Toggles the visibility of the list of markers\n */\n toggleMarkersList() {\n if (this.viewer.panel.isVisible(ID_PANEL_MARKERS_LIST)) {\n this.hideMarkersList();\n } else {\n this.showMarkersList();\n }\n }\n /**\n * Opens side panel with the list of markers\n */\n showMarkersList() {\n let markers = [];\n Object.values(this.markers).forEach((marker) => {\n if (marker.state.visible && !marker.config.hideList) {\n markers.push(marker);\n }\n });\n const e = new RenderMarkersListEvent(markers);\n this.dispatchEvent(e);\n markers = e.markers;\n this.viewer.panel.show({\n id: ID_PANEL_MARKERS_LIST,\n content: MARKERS_LIST_TEMPLATE(markers, this.viewer.config.lang[MarkersButton.id]),\n noMargin: true,\n clickHandler: (target) => {\n const li = utils4.getClosest(target, \"li\");\n const markerId = li ? li.dataset[MARKER_DATA] : void 0;\n if (markerId) {\n const marker = this.getMarker(markerId);\n this.dispatchEvent(new SelectMarkerListEvent(marker));\n this.gotoMarker(marker.id);\n this.hideMarkersList();\n }\n }\n });\n }\n /**\n * Closes side panel if it contains the list of markers\n */\n hideMarkersList() {\n this.viewer.panel.hide(ID_PANEL_MARKERS_LIST);\n }\n /**\n * Updates the visibility and the position of all markers\n */\n renderMarkers() {\n if (this.state.needsReRender) {\n this.state.needsReRender = false;\n return;\n }\n const zoomLevel = this.viewer.getZoomLevel();\n const viewerPosition = this.viewer.getPosition();\n Object.values(this.markers).forEach((marker) => {\n let isVisible = this.state.visible && marker.config.visible;\n let visibilityChanged = false;\n let position = null;\n if (isVisible && marker.is3d()) {\n position = this.__getMarkerPosition(marker);\n isVisible = this.__isMarkerVisible(marker, position);\n } else if (isVisible && marker.isPoly()) {\n const positions = this.__getPolyPositions(marker);\n isVisible = positions.length > (marker.isPolygon() ? 2 : 1);\n if (isVisible) {\n position = this.__getMarkerPosition(marker);\n const points = positions.map((pos) => pos.x - position.x + \",\" + (pos.y - position.y)).join(\" \");\n marker.domElement.setAttributeNS(null, \"points\", points);\n marker.domElement.setAttributeNS(null, \"transform\", `translate(${position.x} ${position.y})`);\n }\n } else if (isVisible) {\n marker.updateSize();\n position = this.__getMarkerPosition(marker);\n isVisible = this.__isMarkerVisible(marker, position);\n if (isVisible) {\n marker.domElement.style.translate = `${position.x}px ${position.y}px 0px`;\n this.__applyScale(marker, {\n zoomLevel,\n viewerPosition,\n mouseover: marker === this.state.hoveringMarker\n });\n if (marker.type === \"element\" /* element */) {\n marker.config.element.updateMarker?.({\n marker,\n position,\n viewerPosition,\n zoomLevel,\n viewerSize: this.viewer.state.size\n });\n }\n }\n }\n visibilityChanged = marker.state.visible !== isVisible;\n marker.state.visible = isVisible;\n marker.state.position2D = isVisible ? position : null;\n if (!marker.is3d()) {\n utils4.toggleClass(marker.domElement, \"psv-marker--visible\", isVisible);\n }\n if (!isVisible) {\n marker.hideTooltip();\n } else if (marker.state.staticTooltip) {\n marker.showTooltip();\n } else if (marker !== this.state.hoveringMarker) {\n marker.hideTooltip();\n }\n if (visibilityChanged) {\n this.dispatchEvent(new MarkerVisibilityEvent(marker, isVisible));\n if (marker.is3d()) {\n this.state.needsReRender = true;\n }\n }\n });\n if (this.state.needsReRender) {\n this.viewer.needsUpdate();\n }\n }\n /**\n * Computes and applies the scale to the marker\n */\n __applyScale(marker, {\n zoomLevel,\n viewerPosition,\n mouseover\n }) {\n if (mouseover !== null && marker.config.hoverScale) {\n marker.domElement.style.transition = `scale ${marker.config.hoverScale.duration}ms ${marker.config.hoverScale.easing}`;\n }\n const scale = marker.getScale(zoomLevel, viewerPosition, mouseover);\n marker.domElement.style.scale = `${scale}`;\n }\n /**\n * Determines if a point marker is visible
\n * It tests if the point is in the general direction of the camera, then check if it's in the viewport\n */\n __isMarkerVisible(marker, position) {\n if (marker.is3d()) {\n return marker.state.positions3D.some((vector) => this.viewer.dataHelper.isPointVisible(vector));\n } else {\n return marker.state.positions3D[0].dot(this.viewer.state.direction) > 0 && position.x + marker.state.size.width >= 0 && position.x - marker.state.size.width <= this.viewer.state.size.width && position.y + marker.state.size.height >= 0 && position.y - marker.state.size.height <= this.viewer.state.size.height;\n }\n }\n /**\n * Computes viewer coordinates of a marker\n */\n __getMarkerPosition(marker) {\n if (marker.isPoly() || marker.is3d()) {\n return this.viewer.dataHelper.sphericalCoordsToViewerCoords(marker.state.position);\n } else {\n const position = this.viewer.dataHelper.vector3ToViewerCoords(marker.state.positions3D[0]);\n position.x -= marker.state.size.width * marker.state.anchor.x;\n position.y -= marker.state.size.height * marker.state.anchor.y;\n return position;\n }\n }\n /**\n * Computes viewer coordinates of each point of a polygon/polyline
\n * It handles points behind the camera by creating intermediary points suitable for the projector\n */\n __getPolyPositions(marker) {\n const nbVectors = marker.state.positions3D.length;\n const positions3D = marker.state.positions3D.map((vector) => {\n return {\n vector,\n visible: vector.dot(this.viewer.state.direction) > 0\n };\n });\n const toBeComputed = [];\n positions3D.forEach((pos, i) => {\n if (!pos.visible) {\n const neighbours = [\n i === 0 ? positions3D[nbVectors - 1] : positions3D[i - 1],\n i === nbVectors - 1 ? positions3D[0] : positions3D[i + 1]\n ];\n neighbours.forEach((neighbour) => {\n if (neighbour.visible) {\n toBeComputed.push({\n visible: neighbour.vector,\n invisible: pos.vector,\n index: i\n });\n }\n });\n }\n });\n toBeComputed.reverse().forEach((pair) => {\n positions3D.splice(pair.index, 0, {\n vector: getGreatCircleIntersection(pair.visible, pair.invisible, this.viewer.state.direction),\n visible: true\n });\n });\n return positions3D.filter((pos) => pos.visible).map((pos) => this.viewer.dataHelper.vector3ToViewerCoords(pos.vector));\n }\n /**\n * Returns the marker associated to an event target\n */\n __getTargetMarker(target, closest = false) {\n const target2 = closest ? utils4.getClosest(target, \".psv-marker\") : target;\n return target2 ? target2[MARKER_DATA] : void 0;\n }\n /**\n * Handles mouse enter events, show the tooltip for non polygon markers\n */\n __onEnterMarker(e, marker) {\n if (marker) {\n this.state.hoveringMarker = marker;\n this.dispatchEvent(new EnterMarkerEvent(marker));\n if (marker.isNormal() || marker.isSvg()) {\n this.__applyScale(marker, {\n zoomLevel: this.viewer.getZoomLevel(),\n viewerPosition: this.viewer.getPosition(),\n mouseover: true\n });\n }\n if (!marker.state.staticTooltip && marker.config.tooltip?.trigger === \"hover\") {\n marker.showTooltip(e.clientX, e.clientY);\n }\n }\n }\n /**\n * Handles mouse leave events, hide the tooltip\n */\n __onLeaveMarker(marker) {\n if (marker) {\n this.dispatchEvent(new LeaveMarkerEvent(marker));\n if (marker.isNormal() || marker.isSvg()) {\n this.__applyScale(marker, {\n zoomLevel: this.viewer.getZoomLevel(),\n viewerPosition: this.viewer.getPosition(),\n mouseover: false\n });\n }\n this.state.hoveringMarker = null;\n if (!marker.state.staticTooltip && marker.config.tooltip?.trigger === \"hover\") {\n marker.hideTooltip();\n } else if (marker.state.staticTooltip) {\n marker.showTooltip();\n }\n }\n }\n /**\n * Handles mouse move events, refreshUi the tooltip for polygon markers\n */\n __onHoverMarker(e, marker) {\n if (marker && (marker.isPoly() || marker.is3d())) {\n if (marker.config.tooltip?.trigger === \"hover\") {\n marker.showTooltip(e.clientX, e.clientY);\n }\n }\n }\n /**\n * Handles mouse click events, select the marker and open the panel if necessary\n */\n __onClick(e, dblclick) {\n let marker = e.data.objects.find((o) => o.userData[MARKER_DATA])?.userData[MARKER_DATA];\n if (!marker) {\n marker = this.__getTargetMarker(e.data.target, true);\n }\n if (this.state.currentMarker && this.state.currentMarker !== marker) {\n this.dispatchEvent(new UnselectMarkerEvent(this.state.currentMarker));\n this.viewer.panel.hide(ID_PANEL_MARKER);\n if (!this.state.showAllTooltips && this.state.currentMarker.config.tooltip?.trigger === \"click\") {\n this.hideMarkerTooltip(this.state.currentMarker.id);\n }\n this.state.currentMarker = null;\n }\n if (marker) {\n this.state.currentMarker = marker;\n this.dispatchEvent(new SelectMarkerEvent(marker, dblclick, e.data.rightclick));\n if (this.config.clickEventOnMarker) {\n e.data.marker = marker;\n } else {\n e.stopImmediatePropagation();\n }\n if (this.markers[marker.id]) {\n if (marker.config.tooltip?.trigger === \"click\") {\n if (marker.tooltip) {\n this.hideMarkerTooltip(marker);\n } else {\n this.showMarkerTooltip(marker);\n }\n } else {\n this.showMarkerPanel(marker.id);\n }\n }\n }\n }\n __afterChangerMarkers() {\n this.__refreshUi();\n this.__checkObjectsObserver();\n this.viewer.needsUpdate();\n this.dispatchEvent(new SetMarkersEvent(this.getMarkers()));\n }\n /**\n * Updates the visiblity of the panel and the buttons\n */\n __refreshUi() {\n const nbMarkers = Object.values(this.markers).filter((m) => !m.config.hideList).length;\n if (nbMarkers === 0) {\n if (this.viewer.panel.isVisible(ID_PANEL_MARKERS_LIST) || this.viewer.panel.isVisible(ID_PANEL_MARKER)) {\n this.viewer.panel.hide();\n }\n } else {\n if (this.viewer.panel.isVisible(ID_PANEL_MARKERS_LIST)) {\n this.showMarkersList();\n } else if (this.viewer.panel.isVisible(ID_PANEL_MARKER)) {\n this.state.currentMarker ? this.showMarkerPanel(this.state.currentMarker.id) : this.viewer.panel.hide();\n }\n }\n this.viewer.navbar.getButton(MarkersButton.id, false)?.toggle(nbMarkers > 0);\n this.viewer.navbar.getButton(MarkersListButton.id, false)?.toggle(nbMarkers > 0);\n }\n /**\n * Adds or remove the objects observer if there are 3D markers\n */\n __checkObjectsObserver() {\n const has3d = Object.values(this.markers).some((marker) => marker.is3d());\n if (has3d) {\n this.viewer.observeObjects(MARKER_DATA);\n } else {\n this.viewer.unobserveObjects(MARKER_DATA);\n }\n }\n};\nMarkersPlugin.id = \"markers\";\nMarkersPlugin.configParser = getConfig;\nMarkersPlugin.readonlyOptions = [\"markers\"];\n\n// src/index.ts\nDEFAULTS.lang[MarkersButton.id] = \"Markers\";\nDEFAULTS.lang[MarkersListButton.id] = \"Markers list\";\nregisterButton(MarkersButton, \"caption:left\");\nregisterButton(MarkersListButton, \"caption:left\");\nexport {\n MarkersPlugin,\n events_exports as events\n};\n//# sourceMappingURL=index.module.js.map","/*!\n * PhotoSphereViewer.VisibleRangePlugin 5.4.3\n * @copyright 2023 Damien \"Mistic\" Sorel\n * @licence MIT (https://opensource.org/licenses/MIT)\n */\n\n// src/VisibleRangePlugin.ts\nimport { AbstractConfigurablePlugin, events, utils } from \"@photo-sphere-viewer/core\";\nimport { MathUtils } from \"three\";\nvar EPS = 1e-6;\nvar getConfig = utils.getConfigParser({\n verticalRange: null,\n horizontalRange: null,\n usePanoData: false\n});\nvar VisibleRangePlugin = class extends AbstractConfigurablePlugin {\n constructor(viewer, config) {\n super(viewer, config);\n }\n /**\n * @internal\n */\n init() {\n super.init();\n this.autorotate = this.viewer.getPlugin(\"autorotate\");\n this.viewer.addEventListener(events.PanoramaLoadedEvent.type, this);\n this.viewer.addEventListener(events.PositionUpdatedEvent.type, this);\n this.viewer.addEventListener(events.ZoomUpdatedEvent.type, this);\n this.viewer.addEventListener(events.BeforeAnimateEvent.type, this);\n this.viewer.addEventListener(events.BeforeRotateEvent.type, this);\n this.setVerticalRange(this.config.verticalRange);\n this.setHorizontalRange(this.config.horizontalRange);\n }\n /**\n * @internal\n */\n destroy() {\n this.viewer.removeEventListener(events.PanoramaLoadedEvent.type, this);\n this.viewer.removeEventListener(events.PositionUpdatedEvent.type, this);\n this.viewer.removeEventListener(events.ZoomUpdatedEvent.type, this);\n this.viewer.removeEventListener(events.BeforeAnimateEvent.type, this);\n this.viewer.removeEventListener(events.BeforeRotateEvent.type, this);\n super.destroy();\n }\n /**\n * @internal\n */\n handleEvent(e) {\n switch (e.type) {\n case events.PanoramaLoadedEvent.type:\n if (this.config.usePanoData) {\n this.setRangesFromPanoData();\n } else {\n this.__moveToRange();\n }\n break;\n case events.BeforeRotateEvent.type:\n case events.BeforeAnimateEvent.type: {\n const e2 = e;\n const { rangedPosition, sidesReached } = this.__applyRanges(e2.position, e2.zoomLevel);\n if (e2.position || Object.keys(sidesReached).length) {\n e2.position = rangedPosition;\n }\n break;\n }\n case events.PositionUpdatedEvent.type: {\n const currentPosition = e.position;\n const { sidesReached, rangedPosition } = this.__applyRanges(currentPosition);\n if ((sidesReached.left || sidesReached.right) && this.autorotate?.isEnabled()) {\n this.__reverseAutorotate(sidesReached.left, sidesReached.right);\n } else if (Math.abs(currentPosition.yaw - rangedPosition.yaw) > EPS || Math.abs(currentPosition.pitch - rangedPosition.pitch) > EPS) {\n this.viewer.dynamics.position.setValue(rangedPosition);\n }\n break;\n }\n case events.ZoomUpdatedEvent.type: {\n const currentPosition = this.viewer.getPosition();\n const { rangedPosition } = this.__applyRanges(currentPosition);\n if (Math.abs(currentPosition.yaw - rangedPosition.yaw) > EPS || Math.abs(currentPosition.pitch - rangedPosition.pitch) > EPS) {\n this.viewer.dynamics.position.setValue(rangedPosition);\n }\n break;\n }\n }\n }\n /**\n * Changes the vertical range\n */\n setVerticalRange(range) {\n if (range && range.length !== 2) {\n utils.logWarn(\"vertical range must have exactly two elements\");\n range = null;\n }\n if (range) {\n this.config.verticalRange = range.map((angle) => utils.parseAngle(angle, true));\n if (this.config.verticalRange[0] > this.config.verticalRange[1]) {\n utils.logWarn(\"vertical range values must be ordered\");\n this.config.verticalRange = [this.config.verticalRange[1], this.config.verticalRange[0]];\n }\n if (this.viewer.state.ready) {\n this.__moveToRange();\n }\n } else {\n this.config.verticalRange = null;\n }\n }\n /**\n * Changes the horizontal range\n */\n setHorizontalRange(range) {\n if (range && range.length !== 2) {\n utils.logWarn(\"horizontal range must have exactly two elements\");\n range = null;\n }\n if (range) {\n this.config.horizontalRange = range.map((angle) => utils.parseAngle(angle));\n if (this.viewer.state.ready) {\n this.__moveToRange();\n }\n } else {\n this.config.horizontalRange = null;\n }\n }\n /**\n * Changes the ranges according the current panorama cropping data\n */\n setRangesFromPanoData() {\n this.setVerticalRange(this.__getPanoVerticalRange());\n this.setHorizontalRange(this.__getPanoHorizontalRange());\n }\n /**\n * Gets the vertical range defined by the viewer's panoData\n */\n __getPanoVerticalRange() {\n const p = this.viewer.state.panoData;\n if (p.croppedHeight === p.fullHeight) {\n return null;\n } else {\n const getAngle = (y) => Math.PI * (1 - y / p.fullHeight) - Math.PI / 2;\n return [getAngle(p.croppedY + p.croppedHeight), getAngle(p.croppedY)];\n }\n }\n /**\n * Gets the horizontal range defined by the viewer's panoData\n */\n __getPanoHorizontalRange() {\n const p = this.viewer.state.panoData;\n if (p.croppedWidth === p.fullWidth) {\n return null;\n } else {\n const getAngle = (x) => 2 * Math.PI * (x / p.fullWidth) - Math.PI;\n return [getAngle(p.croppedX), getAngle(p.croppedX + p.croppedWidth)];\n }\n }\n /**\n * Immediately moves the viewer to respect the ranges\n */\n __moveToRange() {\n this.viewer.rotate(this.viewer.getPosition());\n }\n /**\n * Apply \"horizontalRange\" and \"verticalRange\"\n */\n __applyRanges(position = this.viewer.getPosition(), zoomLevel = this.viewer.getZoomLevel()) {\n const rangedPosition = { yaw: position.yaw, pitch: position.pitch };\n const sidesReached = {};\n const vFov = this.viewer.dataHelper.zoomLevelToFov(zoomLevel);\n const hFov = this.viewer.dataHelper.vFovToHFov(vFov);\n if (this.config.horizontalRange) {\n const range = utils.clone(this.config.horizontalRange);\n const rangeFov = range[0] > range[1] ? range[1] + (2 * Math.PI - range[0]) : range[1] - range[0];\n if (rangeFov <= MathUtils.degToRad(hFov)) {\n range[0] = utils.parseAngle(range[0] + rangeFov / 2);\n range[1] = range[0];\n } else {\n const offset = MathUtils.degToRad(hFov) / 2;\n range[0] = utils.parseAngle(range[0] + offset);\n range[1] = utils.parseAngle(range[1] - offset);\n }\n if (range[0] > range[1]) {\n if (position.yaw > range[1] && position.yaw < range[0]) {\n if (position.yaw > range[0] / 2 + range[1] / 2) {\n rangedPosition.yaw = range[0];\n sidesReached.left = true;\n } else {\n rangedPosition.yaw = range[1];\n sidesReached.right = true;\n }\n }\n } else if (position.yaw < range[0]) {\n rangedPosition.yaw = range[0];\n sidesReached.left = true;\n } else if (position.yaw > range[1]) {\n rangedPosition.yaw = range[1];\n sidesReached.right = true;\n }\n }\n if (this.config.verticalRange) {\n const range = utils.clone(this.config.verticalRange);\n const rangeFov = range[1] - range[0];\n if (rangeFov <= MathUtils.degToRad(vFov)) {\n range[0] = utils.parseAngle(range[0] + rangeFov / 2, true);\n range[1] = range[0];\n } else {\n const offset = MathUtils.degToRad(vFov) / 2;\n range[0] = utils.parseAngle(range[0] + offset, true);\n range[1] = utils.parseAngle(range[1] - offset, true);\n }\n if (position.pitch < range[0]) {\n rangedPosition.pitch = range[0];\n sidesReached.bottom = true;\n } else if (position.pitch > range[1]) {\n rangedPosition.pitch = range[1];\n sidesReached.top = true;\n }\n }\n return { rangedPosition, sidesReached };\n }\n /**\n * Reverses autorotate direction with smooth transition\n */\n __reverseAutorotate(left, right) {\n if (left && this.autorotate.config.autorotateSpeed > 0 || right && this.autorotate.config.autorotateSpeed < 0) {\n return;\n }\n this.autorotate.reverse();\n }\n};\nVisibleRangePlugin.id = \"visible-range\";\nVisibleRangePlugin.configParser = getConfig;\nVisibleRangePlugin.readonlyOptions = [\n \"horizontalRange\",\n \"verticalRange\"\n];\nexport {\n VisibleRangePlugin\n};\n//# sourceMappingURL=index.module.js.map","/* globals __VUE_SSR_CONTEXT__ */\n\n// IMPORTANT: Do NOT use ES2015 features in this file (except for modules).\n// This module is a runtime utility for cleaner component module output and will\n// be included in the final webpack user bundle.\n\nexport default function normalizeComponent(\n scriptExports,\n render,\n staticRenderFns,\n functionalTemplate,\n injectStyles,\n scopeId,\n moduleIdentifier /* server only */,\n shadowMode /* vue-cli only */\n) {\n // Vue.extend constructor export interop\n var options =\n typeof scriptExports === 'function' ? scriptExports.options : scriptExports\n\n // render functions\n if (render) {\n options.render = render\n options.staticRenderFns = staticRenderFns\n options._compiled = true\n }\n\n // functional template\n if (functionalTemplate) {\n options.functional = true\n }\n\n // scopedId\n if (scopeId) {\n options._scopeId = 'data-v-' + scopeId\n }\n\n var hook\n if (moduleIdentifier) {\n // server build\n hook = function (context) {\n // 2.3 injection\n context =\n context || // cached call\n (this.$vnode && this.$vnode.ssrContext) || // stateful\n (this.parent && this.parent.$vnode && this.parent.$vnode.ssrContext) // functional\n // 2.2 with runInNewContext: true\n if (!context && typeof __VUE_SSR_CONTEXT__ !== 'undefined') {\n context = __VUE_SSR_CONTEXT__\n }\n // inject component styles\n if (injectStyles) {\n injectStyles.call(this, context)\n }\n // register component module identifier for async chunk inferrence\n if (context && context._registeredComponents) {\n context._registeredComponents.add(moduleIdentifier)\n }\n }\n // used by ssr in case component is cached and beforeCreate\n // never gets called\n options._ssrRegister = hook\n } else if (injectStyles) {\n hook = shadowMode\n ? function () {\n injectStyles.call(\n this,\n (options.functional ? this.parent : this).$root.$options.shadowRoot\n )\n }\n : injectStyles\n }\n\n if (hook) {\n if (options.functional) {\n // for template-only hot-reload because in that case the render fn doesn't\n // go through the normalizer\n options._injectStyles = hook\n // register for functional component in vue file\n var originalRender = options.render\n options.render = function renderWithStyleInjection(h, context) {\n hook.call(context)\n return originalRender(h, context)\n }\n } else {\n // inject component registration as beforeCreate hook\n var existing = options.beforeCreate\n options.beforeCreate = existing ? [].concat(existing, hook) : [hook]\n }\n }\n\n return {\n exports: scriptExports,\n options: options\n }\n}\n","var isCallable = require('../internals/is-callable');\nvar tryToString = require('../internals/try-to-string');\n\nvar $TypeError = TypeError;\n\n// `Assert: IsCallable(argument) is true`\nmodule.exports = function (argument) {\n if (isCallable(argument)) return argument;\n throw $TypeError(tryToString(argument) + ' is not a function');\n};\n","var isObject = require('../internals/is-object');\n\nvar $String = String;\nvar $TypeError = TypeError;\n\n// `Assert: Type(argument) is Object`\nmodule.exports = function (argument) {\n if (isObject(argument)) return argument;\n throw $TypeError($String(argument) + ' is not an object');\n};\n","var toIndexedObject = require('../internals/to-indexed-object');\nvar toAbsoluteIndex = require('../internals/to-absolute-index');\nvar lengthOfArrayLike = require('../internals/length-of-array-like');\n\n// `Array.prototype.{ indexOf, includes }` methods implementation\nvar createMethod = function (IS_INCLUDES) {\n return function ($this, el, fromIndex) {\n var O = toIndexedObject($this);\n var length = lengthOfArrayLike(O);\n var index = toAbsoluteIndex(fromIndex, length);\n var value;\n // Array#includes uses SameValueZero equality algorithm\n // eslint-disable-next-line no-self-compare -- NaN check\n if (IS_INCLUDES && el != el) while (length > index) {\n value = O[index++];\n // eslint-disable-next-line no-self-compare -- NaN check\n if (value != value) return true;\n // Array#indexOf ignores holes, Array#includes - not\n } else for (;length > index; index++) {\n if ((IS_INCLUDES || index in O) && O[index] === el) return IS_INCLUDES || index || 0;\n } return !IS_INCLUDES && -1;\n };\n};\n\nmodule.exports = {\n // `Array.prototype.includes` method\n // https://tc39.es/ecma262/#sec-array.prototype.includes\n includes: createMethod(true),\n // `Array.prototype.indexOf` method\n // https://tc39.es/ecma262/#sec-array.prototype.indexof\n indexOf: createMethod(false)\n};\n","'use strict';\nvar DESCRIPTORS = require('../internals/descriptors');\nvar isArray = require('../internals/is-array');\n\nvar $TypeError = TypeError;\n// eslint-disable-next-line es/no-object-getownpropertydescriptor -- safe\nvar getOwnPropertyDescriptor = Object.getOwnPropertyDescriptor;\n\n// Safari < 13 does not throw an error in this case\nvar SILENT_ON_NON_WRITABLE_LENGTH_SET = DESCRIPTORS && !function () {\n // makes no sense without proper strict mode support\n if (this !== undefined) return true;\n try {\n // eslint-disable-next-line es/no-object-defineproperty -- safe\n Object.defineProperty([], 'length', { writable: false }).length = 1;\n } catch (error) {\n return error instanceof TypeError;\n }\n}();\n\nmodule.exports = SILENT_ON_NON_WRITABLE_LENGTH_SET ? function (O, length) {\n if (isArray(O) && !getOwnPropertyDescriptor(O, 'length').writable) {\n throw $TypeError('Cannot set read only .length');\n } return O.length = length;\n} : function (O, length) {\n return O.length = length;\n};\n","var uncurryThis = require('../internals/function-uncurry-this');\n\nvar toString = uncurryThis({}.toString);\nvar stringSlice = uncurryThis(''.slice);\n\nmodule.exports = function (it) {\n return stringSlice(toString(it), 8, -1);\n};\n","var hasOwn = require('../internals/has-own-property');\nvar ownKeys = require('../internals/own-keys');\nvar getOwnPropertyDescriptorModule = require('../internals/object-get-own-property-descriptor');\nvar definePropertyModule = require('../internals/object-define-property');\n\nmodule.exports = function (target, source, exceptions) {\n var keys = ownKeys(source);\n var defineProperty = definePropertyModule.f;\n var getOwnPropertyDescriptor = getOwnPropertyDescriptorModule.f;\n for (var i = 0; i < keys.length; i++) {\n var key = keys[i];\n if (!hasOwn(target, key) && !(exceptions && hasOwn(exceptions, key))) {\n defineProperty(target, key, getOwnPropertyDescriptor(source, key));\n }\n }\n};\n","var DESCRIPTORS = require('../internals/descriptors');\nvar definePropertyModule = require('../internals/object-define-property');\nvar createPropertyDescriptor = require('../internals/create-property-descriptor');\n\nmodule.exports = DESCRIPTORS ? function (object, key, value) {\n return definePropertyModule.f(object, key, createPropertyDescriptor(1, value));\n} : function (object, key, value) {\n object[key] = value;\n return object;\n};\n","module.exports = function (bitmap, value) {\n return {\n enumerable: !(bitmap & 1),\n configurable: !(bitmap & 2),\n writable: !(bitmap & 4),\n value: value\n };\n};\n","var isCallable = require('../internals/is-callable');\nvar definePropertyModule = require('../internals/object-define-property');\nvar makeBuiltIn = require('../internals/make-built-in');\nvar defineGlobalProperty = require('../internals/define-global-property');\n\nmodule.exports = function (O, key, value, options) {\n if (!options) options = {};\n var simple = options.enumerable;\n var name = options.name !== undefined ? options.name : key;\n if (isCallable(value)) makeBuiltIn(value, name, options);\n if (options.global) {\n if (simple) O[key] = value;\n else defineGlobalProperty(key, value);\n } else {\n try {\n if (!options.unsafe) delete O[key];\n else if (O[key]) simple = true;\n } catch (error) { /* empty */ }\n if (simple) O[key] = value;\n else definePropertyModule.f(O, key, {\n value: value,\n enumerable: false,\n configurable: !options.nonConfigurable,\n writable: !options.nonWritable\n });\n } return O;\n};\n","var global = require('../internals/global');\n\n// eslint-disable-next-line es/no-object-defineproperty -- safe\nvar defineProperty = Object.defineProperty;\n\nmodule.exports = function (key, value) {\n try {\n defineProperty(global, key, { value: value, configurable: true, writable: true });\n } catch (error) {\n global[key] = value;\n } return value;\n};\n","var fails = require('../internals/fails');\n\n// Detect IE8's incomplete defineProperty implementation\nmodule.exports = !fails(function () {\n // eslint-disable-next-line es/no-object-defineproperty -- required for testing\n return Object.defineProperty({}, 1, { get: function () { return 7; } })[1] != 7;\n});\n","var documentAll = typeof document == 'object' && document.all;\n\n// https://tc39.es/ecma262/#sec-IsHTMLDDA-internal-slot\nvar IS_HTMLDDA = typeof documentAll == 'undefined' && documentAll !== undefined;\n\nmodule.exports = {\n all: documentAll,\n IS_HTMLDDA: IS_HTMLDDA\n};\n","var global = require('../internals/global');\nvar isObject = require('../internals/is-object');\n\nvar document = global.document;\n// typeof document.createElement is 'object' in old IE\nvar EXISTS = isObject(document) && isObject(document.createElement);\n\nmodule.exports = function (it) {\n return EXISTS ? document.createElement(it) : {};\n};\n","var $TypeError = TypeError;\nvar MAX_SAFE_INTEGER = 0x1FFFFFFFFFFFFF; // 2 ** 53 - 1 == 9007199254740991\n\nmodule.exports = function (it) {\n if (it > MAX_SAFE_INTEGER) throw $TypeError('Maximum allowed index exceeded');\n return it;\n};\n","var getBuiltIn = require('../internals/get-built-in');\n\nmodule.exports = getBuiltIn('navigator', 'userAgent') || '';\n","var global = require('../internals/global');\nvar userAgent = require('../internals/engine-user-agent');\n\nvar process = global.process;\nvar Deno = global.Deno;\nvar versions = process && process.versions || Deno && Deno.version;\nvar v8 = versions && versions.v8;\nvar match, version;\n\nif (v8) {\n match = v8.split('.');\n // in old Chrome, versions of V8 isn't V8 = Chrome / 10\n // but their correct versions are not interesting for us\n version = match[0] > 0 && match[0] < 4 ? 1 : +(match[0] + match[1]);\n}\n\n// BrowserFS NodeJS `process` polyfill incorrectly set `.v8` to `0.0`\n// so check `userAgent` even if `.v8` exists, but 0\nif (!version && userAgent) {\n match = userAgent.match(/Edge\\/(\\d+)/);\n if (!match || match[1] >= 74) {\n match = userAgent.match(/Chrome\\/(\\d+)/);\n if (match) version = +match[1];\n }\n}\n\nmodule.exports = version;\n","// IE8- don't enum bug keys\nmodule.exports = [\n 'constructor',\n 'hasOwnProperty',\n 'isPrototypeOf',\n 'propertyIsEnumerable',\n 'toLocaleString',\n 'toString',\n 'valueOf'\n];\n","var global = require('../internals/global');\nvar getOwnPropertyDescriptor = require('../internals/object-get-own-property-descriptor').f;\nvar createNonEnumerableProperty = require('../internals/create-non-enumerable-property');\nvar defineBuiltIn = require('../internals/define-built-in');\nvar defineGlobalProperty = require('../internals/define-global-property');\nvar copyConstructorProperties = require('../internals/copy-constructor-properties');\nvar isForced = require('../internals/is-forced');\n\n/*\n options.target - name of the target object\n options.global - target is the global object\n options.stat - export as static methods of target\n options.proto - export as prototype methods of target\n options.real - real prototype method for the `pure` version\n options.forced - export even if the native feature is available\n options.bind - bind methods to the target, required for the `pure` version\n options.wrap - wrap constructors to preventing global pollution, required for the `pure` version\n options.unsafe - use the simple assignment of property instead of delete + defineProperty\n options.sham - add a flag to not completely full polyfills\n options.enumerable - export as enumerable property\n options.dontCallGetSet - prevent calling a getter on target\n options.name - the .name of the function if it does not match the key\n*/\nmodule.exports = function (options, source) {\n var TARGET = options.target;\n var GLOBAL = options.global;\n var STATIC = options.stat;\n var FORCED, target, key, targetProperty, sourceProperty, descriptor;\n if (GLOBAL) {\n target = global;\n } else if (STATIC) {\n target = global[TARGET] || defineGlobalProperty(TARGET, {});\n } else {\n target = (global[TARGET] || {}).prototype;\n }\n if (target) for (key in source) {\n sourceProperty = source[key];\n if (options.dontCallGetSet) {\n descriptor = getOwnPropertyDescriptor(target, key);\n targetProperty = descriptor && descriptor.value;\n } else targetProperty = target[key];\n FORCED = isForced(GLOBAL ? key : TARGET + (STATIC ? '.' : '#') + key, options.forced);\n // contained in target\n if (!FORCED && targetProperty !== undefined) {\n if (typeof sourceProperty == typeof targetProperty) continue;\n copyConstructorProperties(sourceProperty, targetProperty);\n }\n // add a flag to not completely full polyfills\n if (options.sham || (targetProperty && targetProperty.sham)) {\n createNonEnumerableProperty(sourceProperty, 'sham', true);\n }\n defineBuiltIn(target, key, sourceProperty, options);\n }\n};\n","module.exports = function (exec) {\n try {\n return !!exec();\n } catch (error) {\n return true;\n }\n};\n","var fails = require('../internals/fails');\n\nmodule.exports = !fails(function () {\n // eslint-disable-next-line es/no-function-prototype-bind -- safe\n var test = (function () { /* empty */ }).bind();\n // eslint-disable-next-line no-prototype-builtins -- safe\n return typeof test != 'function' || test.hasOwnProperty('prototype');\n});\n","var NATIVE_BIND = require('../internals/function-bind-native');\n\nvar call = Function.prototype.call;\n\nmodule.exports = NATIVE_BIND ? call.bind(call) : function () {\n return call.apply(call, arguments);\n};\n","var DESCRIPTORS = require('../internals/descriptors');\nvar hasOwn = require('../internals/has-own-property');\n\nvar FunctionPrototype = Function.prototype;\n// eslint-disable-next-line es/no-object-getownpropertydescriptor -- safe\nvar getDescriptor = DESCRIPTORS && Object.getOwnPropertyDescriptor;\n\nvar EXISTS = hasOwn(FunctionPrototype, 'name');\n// additional protection from minified / mangled / dropped function names\nvar PROPER = EXISTS && (function something() { /* empty */ }).name === 'something';\nvar CONFIGURABLE = EXISTS && (!DESCRIPTORS || (DESCRIPTORS && getDescriptor(FunctionPrototype, 'name').configurable));\n\nmodule.exports = {\n EXISTS: EXISTS,\n PROPER: PROPER,\n CONFIGURABLE: CONFIGURABLE\n};\n","var NATIVE_BIND = require('../internals/function-bind-native');\n\nvar FunctionPrototype = Function.prototype;\nvar call = FunctionPrototype.call;\nvar uncurryThisWithBind = NATIVE_BIND && FunctionPrototype.bind.bind(call, call);\n\nmodule.exports = NATIVE_BIND ? uncurryThisWithBind : function (fn) {\n return function () {\n return call.apply(fn, arguments);\n };\n};\n","var global = require('../internals/global');\nvar isCallable = require('../internals/is-callable');\n\nvar aFunction = function (argument) {\n return isCallable(argument) ? argument : undefined;\n};\n\nmodule.exports = function (namespace, method) {\n return arguments.length < 2 ? aFunction(global[namespace]) : global[namespace] && global[namespace][method];\n};\n","var aCallable = require('../internals/a-callable');\nvar isNullOrUndefined = require('../internals/is-null-or-undefined');\n\n// `GetMethod` abstract operation\n// https://tc39.es/ecma262/#sec-getmethod\nmodule.exports = function (V, P) {\n var func = V[P];\n return isNullOrUndefined(func) ? undefined : aCallable(func);\n};\n","var check = function (it) {\n return it && it.Math == Math && it;\n};\n\n// https://github.com/zloirock/core-js/issues/86#issuecomment-115759028\nmodule.exports =\n // eslint-disable-next-line es/no-global-this -- safe\n check(typeof globalThis == 'object' && globalThis) ||\n check(typeof window == 'object' && window) ||\n // eslint-disable-next-line no-restricted-globals -- safe\n check(typeof self == 'object' && self) ||\n check(typeof global == 'object' && global) ||\n // eslint-disable-next-line no-new-func -- fallback\n (function () { return this; })() || Function('return this')();\n","var uncurryThis = require('../internals/function-uncurry-this');\nvar toObject = require('../internals/to-object');\n\nvar hasOwnProperty = uncurryThis({}.hasOwnProperty);\n\n// `HasOwnProperty` abstract operation\n// https://tc39.es/ecma262/#sec-hasownproperty\n// eslint-disable-next-line es/no-object-hasown -- safe\nmodule.exports = Object.hasOwn || function hasOwn(it, key) {\n return hasOwnProperty(toObject(it), key);\n};\n","module.exports = {};\n","var DESCRIPTORS = require('../internals/descriptors');\nvar fails = require('../internals/fails');\nvar createElement = require('../internals/document-create-element');\n\n// Thanks to IE8 for its funny defineProperty\nmodule.exports = !DESCRIPTORS && !fails(function () {\n // eslint-disable-next-line es/no-object-defineproperty -- required for testing\n return Object.defineProperty(createElement('div'), 'a', {\n get: function () { return 7; }\n }).a != 7;\n});\n","var uncurryThis = require('../internals/function-uncurry-this');\nvar fails = require('../internals/fails');\nvar classof = require('../internals/classof-raw');\n\nvar $Object = Object;\nvar split = uncurryThis(''.split);\n\n// fallback for non-array-like ES3 and non-enumerable old V8 strings\nmodule.exports = fails(function () {\n // throws an error in rhino, see https://github.com/mozilla/rhino/issues/346\n // eslint-disable-next-line no-prototype-builtins -- safe\n return !$Object('z').propertyIsEnumerable(0);\n}) ? function (it) {\n return classof(it) == 'String' ? split(it, '') : $Object(it);\n} : $Object;\n","var uncurryThis = require('../internals/function-uncurry-this');\nvar isCallable = require('../internals/is-callable');\nvar store = require('../internals/shared-store');\n\nvar functionToString = uncurryThis(Function.toString);\n\n// this helper broken in `core-js@3.4.1-3.4.4`, so we can't use `shared` helper\nif (!isCallable(store.inspectSource)) {\n store.inspectSource = function (it) {\n return functionToString(it);\n };\n}\n\nmodule.exports = store.inspectSource;\n","var NATIVE_WEAK_MAP = require('../internals/weak-map-basic-detection');\nvar global = require('../internals/global');\nvar isObject = require('../internals/is-object');\nvar createNonEnumerableProperty = require('../internals/create-non-enumerable-property');\nvar hasOwn = require('../internals/has-own-property');\nvar shared = require('../internals/shared-store');\nvar sharedKey = require('../internals/shared-key');\nvar hiddenKeys = require('../internals/hidden-keys');\n\nvar OBJECT_ALREADY_INITIALIZED = 'Object already initialized';\nvar TypeError = global.TypeError;\nvar WeakMap = global.WeakMap;\nvar set, get, has;\n\nvar enforce = function (it) {\n return has(it) ? get(it) : set(it, {});\n};\n\nvar getterFor = function (TYPE) {\n return function (it) {\n var state;\n if (!isObject(it) || (state = get(it)).type !== TYPE) {\n throw TypeError('Incompatible receiver, ' + TYPE + ' required');\n } return state;\n };\n};\n\nif (NATIVE_WEAK_MAP || shared.state) {\n var store = shared.state || (shared.state = new WeakMap());\n /* eslint-disable no-self-assign -- prototype methods protection */\n store.get = store.get;\n store.has = store.has;\n store.set = store.set;\n /* eslint-enable no-self-assign -- prototype methods protection */\n set = function (it, metadata) {\n if (store.has(it)) throw TypeError(OBJECT_ALREADY_INITIALIZED);\n metadata.facade = it;\n store.set(it, metadata);\n return metadata;\n };\n get = function (it) {\n return store.get(it) || {};\n };\n has = function (it) {\n return store.has(it);\n };\n} else {\n var STATE = sharedKey('state');\n hiddenKeys[STATE] = true;\n set = function (it, metadata) {\n if (hasOwn(it, STATE)) throw TypeError(OBJECT_ALREADY_INITIALIZED);\n metadata.facade = it;\n createNonEnumerableProperty(it, STATE, metadata);\n return metadata;\n };\n get = function (it) {\n return hasOwn(it, STATE) ? it[STATE] : {};\n };\n has = function (it) {\n return hasOwn(it, STATE);\n };\n}\n\nmodule.exports = {\n set: set,\n get: get,\n has: has,\n enforce: enforce,\n getterFor: getterFor\n};\n","var classof = require('../internals/classof-raw');\n\n// `IsArray` abstract operation\n// https://tc39.es/ecma262/#sec-isarray\n// eslint-disable-next-line es/no-array-isarray -- safe\nmodule.exports = Array.isArray || function isArray(argument) {\n return classof(argument) == 'Array';\n};\n","var $documentAll = require('../internals/document-all');\n\nvar documentAll = $documentAll.all;\n\n// `IsCallable` abstract operation\n// https://tc39.es/ecma262/#sec-iscallable\nmodule.exports = $documentAll.IS_HTMLDDA ? function (argument) {\n return typeof argument == 'function' || argument === documentAll;\n} : function (argument) {\n return typeof argument == 'function';\n};\n","var fails = require('../internals/fails');\nvar isCallable = require('../internals/is-callable');\n\nvar replacement = /#|\\.prototype\\./;\n\nvar isForced = function (feature, detection) {\n var value = data[normalize(feature)];\n return value == POLYFILL ? true\n : value == NATIVE ? false\n : isCallable(detection) ? fails(detection)\n : !!detection;\n};\n\nvar normalize = isForced.normalize = function (string) {\n return String(string).replace(replacement, '.').toLowerCase();\n};\n\nvar data = isForced.data = {};\nvar NATIVE = isForced.NATIVE = 'N';\nvar POLYFILL = isForced.POLYFILL = 'P';\n\nmodule.exports = isForced;\n","// we can't use just `it == null` since of `document.all` special case\n// https://tc39.es/ecma262/#sec-IsHTMLDDA-internal-slot-aec\nmodule.exports = function (it) {\n return it === null || it === undefined;\n};\n","var isCallable = require('../internals/is-callable');\nvar $documentAll = require('../internals/document-all');\n\nvar documentAll = $documentAll.all;\n\nmodule.exports = $documentAll.IS_HTMLDDA ? function (it) {\n return typeof it == 'object' ? it !== null : isCallable(it) || it === documentAll;\n} : function (it) {\n return typeof it == 'object' ? it !== null : isCallable(it);\n};\n","module.exports = false;\n","var getBuiltIn = require('../internals/get-built-in');\nvar isCallable = require('../internals/is-callable');\nvar isPrototypeOf = require('../internals/object-is-prototype-of');\nvar USE_SYMBOL_AS_UID = require('../internals/use-symbol-as-uid');\n\nvar $Object = Object;\n\nmodule.exports = USE_SYMBOL_AS_UID ? function (it) {\n return typeof it == 'symbol';\n} : function (it) {\n var $Symbol = getBuiltIn('Symbol');\n return isCallable($Symbol) && isPrototypeOf($Symbol.prototype, $Object(it));\n};\n","var toLength = require('../internals/to-length');\n\n// `LengthOfArrayLike` abstract operation\n// https://tc39.es/ecma262/#sec-lengthofarraylike\nmodule.exports = function (obj) {\n return toLength(obj.length);\n};\n","var fails = require('../internals/fails');\nvar isCallable = require('../internals/is-callable');\nvar hasOwn = require('../internals/has-own-property');\nvar DESCRIPTORS = require('../internals/descriptors');\nvar CONFIGURABLE_FUNCTION_NAME = require('../internals/function-name').CONFIGURABLE;\nvar inspectSource = require('../internals/inspect-source');\nvar InternalStateModule = require('../internals/internal-state');\n\nvar enforceInternalState = InternalStateModule.enforce;\nvar getInternalState = InternalStateModule.get;\n// eslint-disable-next-line es/no-object-defineproperty -- safe\nvar defineProperty = Object.defineProperty;\n\nvar CONFIGURABLE_LENGTH = DESCRIPTORS && !fails(function () {\n return defineProperty(function () { /* empty */ }, 'length', { value: 8 }).length !== 8;\n});\n\nvar TEMPLATE = String(String).split('String');\n\nvar makeBuiltIn = module.exports = function (value, name, options) {\n if (String(name).slice(0, 7) === 'Symbol(') {\n name = '[' + String(name).replace(/^Symbol\\(([^)]*)\\)/, '$1') + ']';\n }\n if (options && options.getter) name = 'get ' + name;\n if (options && options.setter) name = 'set ' + name;\n if (!hasOwn(value, 'name') || (CONFIGURABLE_FUNCTION_NAME && value.name !== name)) {\n if (DESCRIPTORS) defineProperty(value, 'name', { value: name, configurable: true });\n else value.name = name;\n }\n if (CONFIGURABLE_LENGTH && options && hasOwn(options, 'arity') && value.length !== options.arity) {\n defineProperty(value, 'length', { value: options.arity });\n }\n try {\n if (options && hasOwn(options, 'constructor') && options.constructor) {\n if (DESCRIPTORS) defineProperty(value, 'prototype', { writable: false });\n // in V8 ~ Chrome 53, prototypes of some methods, like `Array.prototype.values`, are non-writable\n } else if (value.prototype) value.prototype = undefined;\n } catch (error) { /* empty */ }\n var state = enforceInternalState(value);\n if (!hasOwn(state, 'source')) {\n state.source = TEMPLATE.join(typeof name == 'string' ? name : '');\n } return value;\n};\n\n// add fake Function#toString for correct work wrapped methods / constructors with methods like LoDash isNative\n// eslint-disable-next-line no-extend-native -- required\nFunction.prototype.toString = makeBuiltIn(function toString() {\n return isCallable(this) && getInternalState(this).source || inspectSource(this);\n}, 'toString');\n","var ceil = Math.ceil;\nvar floor = Math.floor;\n\n// `Math.trunc` method\n// https://tc39.es/ecma262/#sec-math.trunc\n// eslint-disable-next-line es/no-math-trunc -- safe\nmodule.exports = Math.trunc || function trunc(x) {\n var n = +x;\n return (n > 0 ? floor : ceil)(n);\n};\n","var DESCRIPTORS = require('../internals/descriptors');\nvar IE8_DOM_DEFINE = require('../internals/ie8-dom-define');\nvar V8_PROTOTYPE_DEFINE_BUG = require('../internals/v8-prototype-define-bug');\nvar anObject = require('../internals/an-object');\nvar toPropertyKey = require('../internals/to-property-key');\n\nvar $TypeError = TypeError;\n// eslint-disable-next-line es/no-object-defineproperty -- safe\nvar $defineProperty = Object.defineProperty;\n// eslint-disable-next-line es/no-object-getownpropertydescriptor -- safe\nvar $getOwnPropertyDescriptor = Object.getOwnPropertyDescriptor;\nvar ENUMERABLE = 'enumerable';\nvar CONFIGURABLE = 'configurable';\nvar WRITABLE = 'writable';\n\n// `Object.defineProperty` method\n// https://tc39.es/ecma262/#sec-object.defineproperty\nexports.f = DESCRIPTORS ? V8_PROTOTYPE_DEFINE_BUG ? function defineProperty(O, P, Attributes) {\n anObject(O);\n P = toPropertyKey(P);\n anObject(Attributes);\n if (typeof O === 'function' && P === 'prototype' && 'value' in Attributes && WRITABLE in Attributes && !Attributes[WRITABLE]) {\n var current = $getOwnPropertyDescriptor(O, P);\n if (current && current[WRITABLE]) {\n O[P] = Attributes.value;\n Attributes = {\n configurable: CONFIGURABLE in Attributes ? Attributes[CONFIGURABLE] : current[CONFIGURABLE],\n enumerable: ENUMERABLE in Attributes ? Attributes[ENUMERABLE] : current[ENUMERABLE],\n writable: false\n };\n }\n } return $defineProperty(O, P, Attributes);\n} : $defineProperty : function defineProperty(O, P, Attributes) {\n anObject(O);\n P = toPropertyKey(P);\n anObject(Attributes);\n if (IE8_DOM_DEFINE) try {\n return $defineProperty(O, P, Attributes);\n } catch (error) { /* empty */ }\n if ('get' in Attributes || 'set' in Attributes) throw $TypeError('Accessors not supported');\n if ('value' in Attributes) O[P] = Attributes.value;\n return O;\n};\n","var DESCRIPTORS = require('../internals/descriptors');\nvar call = require('../internals/function-call');\nvar propertyIsEnumerableModule = require('../internals/object-property-is-enumerable');\nvar createPropertyDescriptor = require('../internals/create-property-descriptor');\nvar toIndexedObject = require('../internals/to-indexed-object');\nvar toPropertyKey = require('../internals/to-property-key');\nvar hasOwn = require('../internals/has-own-property');\nvar IE8_DOM_DEFINE = require('../internals/ie8-dom-define');\n\n// eslint-disable-next-line es/no-object-getownpropertydescriptor -- safe\nvar $getOwnPropertyDescriptor = Object.getOwnPropertyDescriptor;\n\n// `Object.getOwnPropertyDescriptor` method\n// https://tc39.es/ecma262/#sec-object.getownpropertydescriptor\nexports.f = DESCRIPTORS ? $getOwnPropertyDescriptor : function getOwnPropertyDescriptor(O, P) {\n O = toIndexedObject(O);\n P = toPropertyKey(P);\n if (IE8_DOM_DEFINE) try {\n return $getOwnPropertyDescriptor(O, P);\n } catch (error) { /* empty */ }\n if (hasOwn(O, P)) return createPropertyDescriptor(!call(propertyIsEnumerableModule.f, O, P), O[P]);\n};\n","var internalObjectKeys = require('../internals/object-keys-internal');\nvar enumBugKeys = require('../internals/enum-bug-keys');\n\nvar hiddenKeys = enumBugKeys.concat('length', 'prototype');\n\n// `Object.getOwnPropertyNames` method\n// https://tc39.es/ecma262/#sec-object.getownpropertynames\n// eslint-disable-next-line es/no-object-getownpropertynames -- safe\nexports.f = Object.getOwnPropertyNames || function getOwnPropertyNames(O) {\n return internalObjectKeys(O, hiddenKeys);\n};\n","// eslint-disable-next-line es/no-object-getownpropertysymbols -- safe\nexports.f = Object.getOwnPropertySymbols;\n","var uncurryThis = require('../internals/function-uncurry-this');\n\nmodule.exports = uncurryThis({}.isPrototypeOf);\n","var uncurryThis = require('../internals/function-uncurry-this');\nvar hasOwn = require('../internals/has-own-property');\nvar toIndexedObject = require('../internals/to-indexed-object');\nvar indexOf = require('../internals/array-includes').indexOf;\nvar hiddenKeys = require('../internals/hidden-keys');\n\nvar push = uncurryThis([].push);\n\nmodule.exports = function (object, names) {\n var O = toIndexedObject(object);\n var i = 0;\n var result = [];\n var key;\n for (key in O) !hasOwn(hiddenKeys, key) && hasOwn(O, key) && push(result, key);\n // Don't enum bug & hidden keys\n while (names.length > i) if (hasOwn(O, key = names[i++])) {\n ~indexOf(result, key) || push(result, key);\n }\n return result;\n};\n","'use strict';\nvar $propertyIsEnumerable = {}.propertyIsEnumerable;\n// eslint-disable-next-line es/no-object-getownpropertydescriptor -- safe\nvar getOwnPropertyDescriptor = Object.getOwnPropertyDescriptor;\n\n// Nashorn ~ JDK8 bug\nvar NASHORN_BUG = getOwnPropertyDescriptor && !$propertyIsEnumerable.call({ 1: 2 }, 1);\n\n// `Object.prototype.propertyIsEnumerable` method implementation\n// https://tc39.es/ecma262/#sec-object.prototype.propertyisenumerable\nexports.f = NASHORN_BUG ? function propertyIsEnumerable(V) {\n var descriptor = getOwnPropertyDescriptor(this, V);\n return !!descriptor && descriptor.enumerable;\n} : $propertyIsEnumerable;\n","var call = require('../internals/function-call');\nvar isCallable = require('../internals/is-callable');\nvar isObject = require('../internals/is-object');\n\nvar $TypeError = TypeError;\n\n// `OrdinaryToPrimitive` abstract operation\n// https://tc39.es/ecma262/#sec-ordinarytoprimitive\nmodule.exports = function (input, pref) {\n var fn, val;\n if (pref === 'string' && isCallable(fn = input.toString) && !isObject(val = call(fn, input))) return val;\n if (isCallable(fn = input.valueOf) && !isObject(val = call(fn, input))) return val;\n if (pref !== 'string' && isCallable(fn = input.toString) && !isObject(val = call(fn, input))) return val;\n throw $TypeError(\"Can't convert object to primitive value\");\n};\n","var getBuiltIn = require('../internals/get-built-in');\nvar uncurryThis = require('../internals/function-uncurry-this');\nvar getOwnPropertyNamesModule = require('../internals/object-get-own-property-names');\nvar getOwnPropertySymbolsModule = require('../internals/object-get-own-property-symbols');\nvar anObject = require('../internals/an-object');\n\nvar concat = uncurryThis([].concat);\n\n// all object keys, includes non-enumerable and symbols\nmodule.exports = getBuiltIn('Reflect', 'ownKeys') || function ownKeys(it) {\n var keys = getOwnPropertyNamesModule.f(anObject(it));\n var getOwnPropertySymbols = getOwnPropertySymbolsModule.f;\n return getOwnPropertySymbols ? concat(keys, getOwnPropertySymbols(it)) : keys;\n};\n","var isNullOrUndefined = require('../internals/is-null-or-undefined');\n\nvar $TypeError = TypeError;\n\n// `RequireObjectCoercible` abstract operation\n// https://tc39.es/ecma262/#sec-requireobjectcoercible\nmodule.exports = function (it) {\n if (isNullOrUndefined(it)) throw $TypeError(\"Can't call method on \" + it);\n return it;\n};\n","var shared = require('../internals/shared');\nvar uid = require('../internals/uid');\n\nvar keys = shared('keys');\n\nmodule.exports = function (key) {\n return keys[key] || (keys[key] = uid(key));\n};\n","var global = require('../internals/global');\nvar defineGlobalProperty = require('../internals/define-global-property');\n\nvar SHARED = '__core-js_shared__';\nvar store = global[SHARED] || defineGlobalProperty(SHARED, {});\n\nmodule.exports = store;\n","var IS_PURE = require('../internals/is-pure');\nvar store = require('../internals/shared-store');\n\n(module.exports = function (key, value) {\n return store[key] || (store[key] = value !== undefined ? value : {});\n})('versions', []).push({\n version: '3.26.1',\n mode: IS_PURE ? 'pure' : 'global',\n copyright: '© 2014-2022 Denis Pushkarev (zloirock.ru)',\n license: 'https://github.com/zloirock/core-js/blob/v3.26.1/LICENSE',\n source: 'https://github.com/zloirock/core-js'\n});\n","/* eslint-disable es/no-symbol -- required for testing */\nvar V8_VERSION = require('../internals/engine-v8-version');\nvar fails = require('../internals/fails');\n\n// eslint-disable-next-line es/no-object-getownpropertysymbols -- required for testing\nmodule.exports = !!Object.getOwnPropertySymbols && !fails(function () {\n var symbol = Symbol();\n // Chrome 38 Symbol has incorrect toString conversion\n // `get-own-property-symbols` polyfill symbols converted to object are not Symbol instances\n return !String(symbol) || !(Object(symbol) instanceof Symbol) ||\n // Chrome 38-40 symbols are not inherited from DOM collections prototypes to instances\n !Symbol.sham && V8_VERSION && V8_VERSION < 41;\n});\n","var toIntegerOrInfinity = require('../internals/to-integer-or-infinity');\n\nvar max = Math.max;\nvar min = Math.min;\n\n// Helper for a popular repeating case of the spec:\n// Let integer be ? ToInteger(index).\n// If integer < 0, let result be max((length + integer), 0); else let result be min(integer, length).\nmodule.exports = function (index, length) {\n var integer = toIntegerOrInfinity(index);\n return integer < 0 ? max(integer + length, 0) : min(integer, length);\n};\n","// toObject with fallback for non-array-like ES3 strings\nvar IndexedObject = require('../internals/indexed-object');\nvar requireObjectCoercible = require('../internals/require-object-coercible');\n\nmodule.exports = function (it) {\n return IndexedObject(requireObjectCoercible(it));\n};\n","var trunc = require('../internals/math-trunc');\n\n// `ToIntegerOrInfinity` abstract operation\n// https://tc39.es/ecma262/#sec-tointegerorinfinity\nmodule.exports = function (argument) {\n var number = +argument;\n // eslint-disable-next-line no-self-compare -- NaN check\n return number !== number || number === 0 ? 0 : trunc(number);\n};\n","var toIntegerOrInfinity = require('../internals/to-integer-or-infinity');\n\nvar min = Math.min;\n\n// `ToLength` abstract operation\n// https://tc39.es/ecma262/#sec-tolength\nmodule.exports = function (argument) {\n return argument > 0 ? min(toIntegerOrInfinity(argument), 0x1FFFFFFFFFFFFF) : 0; // 2 ** 53 - 1 == 9007199254740991\n};\n","var requireObjectCoercible = require('../internals/require-object-coercible');\n\nvar $Object = Object;\n\n// `ToObject` abstract operation\n// https://tc39.es/ecma262/#sec-toobject\nmodule.exports = function (argument) {\n return $Object(requireObjectCoercible(argument));\n};\n","var call = require('../internals/function-call');\nvar isObject = require('../internals/is-object');\nvar isSymbol = require('../internals/is-symbol');\nvar getMethod = require('../internals/get-method');\nvar ordinaryToPrimitive = require('../internals/ordinary-to-primitive');\nvar wellKnownSymbol = require('../internals/well-known-symbol');\n\nvar $TypeError = TypeError;\nvar TO_PRIMITIVE = wellKnownSymbol('toPrimitive');\n\n// `ToPrimitive` abstract operation\n// https://tc39.es/ecma262/#sec-toprimitive\nmodule.exports = function (input, pref) {\n if (!isObject(input) || isSymbol(input)) return input;\n var exoticToPrim = getMethod(input, TO_PRIMITIVE);\n var result;\n if (exoticToPrim) {\n if (pref === undefined) pref = 'default';\n result = call(exoticToPrim, input, pref);\n if (!isObject(result) || isSymbol(result)) return result;\n throw $TypeError(\"Can't convert object to primitive value\");\n }\n if (pref === undefined) pref = 'number';\n return ordinaryToPrimitive(input, pref);\n};\n","var toPrimitive = require('../internals/to-primitive');\nvar isSymbol = require('../internals/is-symbol');\n\n// `ToPropertyKey` abstract operation\n// https://tc39.es/ecma262/#sec-topropertykey\nmodule.exports = function (argument) {\n var key = toPrimitive(argument, 'string');\n return isSymbol(key) ? key : key + '';\n};\n","var $String = String;\n\nmodule.exports = function (argument) {\n try {\n return $String(argument);\n } catch (error) {\n return 'Object';\n }\n};\n","var uncurryThis = require('../internals/function-uncurry-this');\n\nvar id = 0;\nvar postfix = Math.random();\nvar toString = uncurryThis(1.0.toString);\n\nmodule.exports = function (key) {\n return 'Symbol(' + (key === undefined ? '' : key) + ')_' + toString(++id + postfix, 36);\n};\n","/* eslint-disable es/no-symbol -- required for testing */\nvar NATIVE_SYMBOL = require('../internals/symbol-constructor-detection');\n\nmodule.exports = NATIVE_SYMBOL\n && !Symbol.sham\n && typeof Symbol.iterator == 'symbol';\n","var DESCRIPTORS = require('../internals/descriptors');\nvar fails = require('../internals/fails');\n\n// V8 ~ Chrome 36-\n// https://bugs.chromium.org/p/v8/issues/detail?id=3334\nmodule.exports = DESCRIPTORS && fails(function () {\n // eslint-disable-next-line es/no-object-defineproperty -- required for testing\n return Object.defineProperty(function () { /* empty */ }, 'prototype', {\n value: 42,\n writable: false\n }).prototype != 42;\n});\n","var global = require('../internals/global');\nvar isCallable = require('../internals/is-callable');\n\nvar WeakMap = global.WeakMap;\n\nmodule.exports = isCallable(WeakMap) && /native code/.test(String(WeakMap));\n","var global = require('../internals/global');\nvar shared = require('../internals/shared');\nvar hasOwn = require('../internals/has-own-property');\nvar uid = require('../internals/uid');\nvar NATIVE_SYMBOL = require('../internals/symbol-constructor-detection');\nvar USE_SYMBOL_AS_UID = require('../internals/use-symbol-as-uid');\n\nvar WellKnownSymbolsStore = shared('wks');\nvar Symbol = global.Symbol;\nvar symbolFor = Symbol && Symbol['for'];\nvar createWellKnownSymbol = USE_SYMBOL_AS_UID ? Symbol : Symbol && Symbol.withoutSetter || uid;\n\nmodule.exports = function (name) {\n if (!hasOwn(WellKnownSymbolsStore, name) || !(NATIVE_SYMBOL || typeof WellKnownSymbolsStore[name] == 'string')) {\n var description = 'Symbol.' + name;\n if (NATIVE_SYMBOL && hasOwn(Symbol, name)) {\n WellKnownSymbolsStore[name] = Symbol[name];\n } else if (USE_SYMBOL_AS_UID && symbolFor) {\n WellKnownSymbolsStore[name] = symbolFor(description);\n } else {\n WellKnownSymbolsStore[name] = createWellKnownSymbol(description);\n }\n } return WellKnownSymbolsStore[name];\n};\n","'use strict';\nvar $ = require('../internals/export');\nvar toObject = require('../internals/to-object');\nvar lengthOfArrayLike = require('../internals/length-of-array-like');\nvar setArrayLength = require('../internals/array-set-length');\nvar doesNotExceedSafeInteger = require('../internals/does-not-exceed-safe-integer');\nvar fails = require('../internals/fails');\n\nvar INCORRECT_TO_LENGTH = fails(function () {\n return [].push.call({ length: 0x100000000 }, 1) !== 4294967297;\n});\n\n// V8 and Safari <= 15.4, FF < 23 throws InternalError\n// https://bugs.chromium.org/p/v8/issues/detail?id=12681\nvar SILENT_ON_NON_WRITABLE_LENGTH = !function () {\n try {\n // eslint-disable-next-line es/no-object-defineproperty -- safe\n Object.defineProperty([], 'length', { writable: false }).push();\n } catch (error) {\n return error instanceof TypeError;\n }\n}();\n\n// `Array.prototype.push` method\n// https://tc39.es/ecma262/#sec-array.prototype.push\n$({ target: 'Array', proto: true, arity: 1, forced: INCORRECT_TO_LENGTH || SILENT_ON_NON_WRITABLE_LENGTH }, {\n // eslint-disable-next-line no-unused-vars -- required for `.length`\n push: function push(item) {\n var O = toObject(this);\n var len = lengthOfArrayLike(O);\n var argCount = arguments.length;\n doesNotExceedSafeInteger(len + argCount);\n for (var i = 0; i < argCount; i++) {\n O[len] = arguments[i];\n len++;\n }\n setArrayLength(O, len);\n return len;\n }\n});\n","/*!\n * jQuery JavaScript Library v3.7.0\n * https://jquery.com/\n *\n * Copyright OpenJS Foundation and other contributors\n * Released under the MIT license\n * https://jquery.org/license\n *\n * Date: 2023-05-11T18:29Z\n */\n( function( global, factory ) {\n\n\t\"use strict\";\n\n\tif ( typeof module === \"object\" && typeof module.exports === \"object\" ) {\n\n\t\t// For CommonJS and CommonJS-like environments where a proper `window`\n\t\t// is present, execute the factory and get jQuery.\n\t\t// For environments that do not have a `window` with a `document`\n\t\t// (such as Node.js), expose a factory as module.exports.\n\t\t// This accentuates the need for the creation of a real `window`.\n\t\t// e.g. var jQuery = require(\"jquery\")(window);\n\t\t// See ticket trac-14549 for more info.\n\t\tmodule.exports = global.document ?\n\t\t\tfactory( global, true ) :\n\t\t\tfunction( w ) {\n\t\t\t\tif ( !w.document ) {\n\t\t\t\t\tthrow new Error( \"jQuery requires a window with a document\" );\n\t\t\t\t}\n\t\t\t\treturn factory( w );\n\t\t\t};\n\t} else {\n\t\tfactory( global );\n\t}\n\n// Pass this if window is not defined yet\n} )( typeof window !== \"undefined\" ? window : this, function( window, noGlobal ) {\n\n// Edge <= 12 - 13+, Firefox <=18 - 45+, IE 10 - 11, Safari 5.1 - 9+, iOS 6 - 9.1\n// throw exceptions when non-strict code (e.g., ASP.NET 4.5) accesses strict mode\n// arguments.callee.caller (trac-13335). But as of jQuery 3.0 (2016), strict mode should be common\n// enough that all such attempts are guarded in a try block.\n\"use strict\";\n\nvar arr = [];\n\nvar getProto = Object.getPrototypeOf;\n\nvar slice = arr.slice;\n\nvar flat = arr.flat ? function( array ) {\n\treturn arr.flat.call( array );\n} : function( array ) {\n\treturn arr.concat.apply( [], array );\n};\n\n\nvar push = arr.push;\n\nvar indexOf = arr.indexOf;\n\nvar class2type = {};\n\nvar toString = class2type.toString;\n\nvar hasOwn = class2type.hasOwnProperty;\n\nvar fnToString = hasOwn.toString;\n\nvar ObjectFunctionString = fnToString.call( Object );\n\nvar support = {};\n\nvar isFunction = function isFunction( obj ) {\n\n\t\t// Support: Chrome <=57, Firefox <=52\n\t\t// In some browsers, typeof returns \"function\" for HTML