diff --git a/.travis.yml b/.travis.yml index 542faf55e..efb09833a 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,5 +1,3 @@ language: node_js node_js: - "8" -before_install: - - npm install -g grunt-cli diff --git a/Gruntfile.js b/Gruntfile.js index 14b5d3ce9..9d37d0ad6 100644 --- a/Gruntfile.js +++ b/Gruntfile.js @@ -108,6 +108,20 @@ module.exports = function(grunt) { } }, + /** + * Autoprefix CSS + */ + postcss: { + options: { + processors: [ + require('autoprefixer')({ browsers: 'last 2 versions, ie >= 11' }) + ] + }, + lib: { + src: 'dist/photo-sphere-viewer.css' + } + }, + /** * Minify dist CSS file */ @@ -287,6 +301,7 @@ module.exports = function(grunt) { 'wrap', 'uglify', 'sass', + 'postcss', 'cssmin', 'usebanner' ]); diff --git a/README.md b/README.md index fad2f58b9..1c2b78214 100644 --- a/README.md +++ b/README.md @@ -44,17 +44,16 @@ Photo Sphere Viewer is available on [jsDelivr](https://cdn.jsdelivr.net/npm/phot #### Prerequisites * NodeJS + NPM: `apt-get install nodejs-legacy npm` - * Grunt CLI: `npm install -g grunt-cli` #### Run -Install Node and Bower dependencies `npm install` then run `grunt` in the root directory to generate production files inside `dist`. +Install Node dependencies `npm install` then run `npm run build` in the root directory to generate production files inside `dist`. #### Other commands - * `grunt test` to run jshint/jscs/scsslint. - * `grunt serve` to open the example page with automatic build and livereload. - * `grunt doc` to generate the documentation. + * `npm run test` to run jshint/jscs/scsslint. + * `npm run serve` to open the example page with automatic build and livereload. + * `npm run doc` to generate the documentation. ## License This library is available under the MIT license. diff --git a/dist/photo-sphere-viewer.css b/dist/photo-sphere-viewer.css index 55bc2cc71..f82a3173d 100644 --- a/dist/photo-sphere-viewer.css +++ b/dist/photo-sphere-viewer.css @@ -1,5 +1,5 @@ /*! - * Photo Sphere Viewer 3.4.0 + * Photo Sphere Viewer 3.4.1 * Copyright (c) 2014-2015 Jérémy Heleine * Copyright (c) 2015-2018 Damien "Mistic" Sorel * Licensed under MIT (https://opensource.org/licenses/MIT) @@ -18,6 +18,7 @@ top: 0; left: 0; z-index: 0; + -webkit-transition: opacity linear 100ms; transition: opacity linear 100ms; } .psv-canvas { @@ -25,12 +26,14 @@ .psv-loader-container { display: -webkit-box; - display: -webkit-flex; - display: -moz-flex; display: -ms-flexbox; display: flex; - align-items: center; - justify-content: center; + -webkit-box-align: center; + -ms-flex-align: center; + align-items: center; + -webkit-box-pack: center; + -ms-flex-pack: center; + justify-content: center; position: absolute; top: 0; left: 0; @@ -64,8 +67,6 @@ .psv-navbar { display: -webkit-box; - display: -webkit-flex; - display: -moz-flex; display: -ms-flexbox; display: flex; position: absolute; @@ -75,21 +76,20 @@ width: 100%; height: 40px; background: rgba(61, 61, 61, 0.5); + -webkit-transition: bottom ease-in-out .1s; transition: bottom ease-in-out .1s; } .psv-navbar--open { bottom: 0; } .psv-navbar, .psv-navbar * { - box-sizing: content-box; } + -webkit-box-sizing: content-box; + box-sizing: content-box; } .psv-caption { - -webkit-box-flex: 10; - -webkit-flex-grow: 10; - -moz-flex-grow: 10; - -ms-flex-positive: 10; - flex-grow: 10; + -webkit-box-flex: 1; + -ms-flex: 1 1 100%; + flex: 1 1 100%; color: rgba(255, 255, 255, 0.7); - margin: 10px; overflow: hidden; text-align: center; } .psv-caption-icon { @@ -99,19 +99,15 @@ .psv-caption-icon * { fill: rgba(255, 255, 255, 0.7); } .psv-caption-content { - font-family: sans-serif; + display: inline-block; + padding: 10px; + font: 16px sans-serif; white-space: nowrap; } .psv-button { -webkit-box-flex: 0; - -webkit-flex-grow: 0; - -moz-flex-grow: 0; - -ms-flex-positive: 0; - flex-grow: 0; - -webkit-flex-shrink: 0; - -moz-flex-shrink: 0; - -ms-flex-negative: 0; - flex-shrink: 0; + -ms-flex: 0 0 auto; + flex: 0 0 auto; padding: 10px; position: relative; cursor: pointer; @@ -120,125 +116,29 @@ background: transparent; color: rgba(255, 255, 255, 0.7); } .psv-button--active { - background: rgba(255, 255, 255, 0.1); } + background: rgba(255, 255, 255, 0.2); } .psv-button--disabled { pointer-events: none; opacity: 0.5; } .psv-button .psv-button-svg { width: 100%; - transform: scale(1); - transition: transform .3s ease; } + -webkit-transform: scale(1); + transform: scale(1); + -webkit-transition: -webkit-transform 200ms ease; + transition: -webkit-transform 200ms ease; + transition: transform 200ms ease; + transition: transform 200ms ease, -webkit-transform 200ms ease; } .psv-button .psv-button-svg * { fill: rgba(255, 255, 255, 0.7); } - .psv-button--hover-scale:not(.psv-button--disabled):hover .psv-button .psv-button-svg { - transform: scale(1.2); } - -.psv-autorotate-button { - width: 25px; - height: 25px; - padding: 7.5px; } - -.psv-zoom-button { - cursor: default; - width: 128px; } - .psv-zoom-button-minus, .psv-zoom-button-plus { - float: left; - position: relative; - cursor: pointer; - width: 16px; - height: 16px; } - .psv-zoom-button-minus .psv-button-svg, .psv-zoom-button-plus .psv-button-svg { - position: relative; - top: 20%; } - .psv-zoom-button-range { - float: left; - padding: 9.5px 8px; } - .psv-zoom-button-line { - position: relative; - cursor: pointer; - width: 80px; - height: 1px; - background: rgba(255, 255, 255, 0.7); - transition: all .3s ease; } - .psv-zoom-button-handle { - position: absolute; - border-radius: 50%; - top: -3px; - width: 7px; - height: 7px; - background: rgba(255, 255, 255, 0.7); - transform: scale(1); - transition: transform .3s ease; } - .psv-zoom-button:not(.psv-button--disabled):hover .psv-zoom-button-line { - box-shadow: 0 0 2px rgba(255, 255, 255, 0.7); } - .psv-zoom-button:not(.psv-button--disabled):hover .psv-zoom-button-handle { - transform: scale(1.3); } - @media (max-width: 600px) { - .psv-zoom-button { - width: auto; - padding: 0; } - .psv-zoom-button-range { - display: none; } - .psv-zoom-button-minus, .psv-zoom-button-plus { - width: 20px; - height: 20px; - padding: 10px; } - .psv-zoom-button-minus .psv-button-svg, .psv-zoom-button-plus .psv-button-svg { - top: 0; } } - -@media (max-width: 600px) { - .psv-is-touch .psv-zoom-button { - display: none; } } - -.psv-markers-list-title { - font: 24px sans-serif; - margin: 1em 0; - text-align: center; - text-shadow: 2px 1px #000; } - -.psv-markers-list { - list-style: none; - margin: 0; - padding: 0; - overflow: hidden; } - .psv-markers-list-item { - clear: both; - min-height: 20px; - padding: 0.5em 1em; - cursor: pointer; - transform: translateX(0); - transition: transform .3s ease-in-out; } - .psv-markers-list-item::before { - content: ''; - position: absolute; - top: 0; - left: 0; - height: 100%; - width: 10px; - margin-left: -10px; } - .psv-markers-list-item:nth-child(odd), .psv-markers-list-item:nth-child(odd)::before { - background: rgba(255, 255, 255, 0.1); } - .psv-markers-list-item:nth-child(even), .psv-markers-list-item:nth-child(even)::before { - background: transparent; } - .psv-markers-list-item:hover { - transform: translateX(10px); - transition: transform .1s ease-in-out; } - .psv-markers-list-image { - float: left; - width: 20px; } - .psv-markers-list-name { - margin: 0; - padding: 0; } - .psv-markers-list-image + .psv-markers-list-name { - padding-left: calc(20px + 0.5em); } + .psv-button--hover-scale:not(.psv-button--disabled):hover .psv-button-svg { + -webkit-transform: scale(1.2); + transform: scale(1.2); } .psv-hud { - -webkit-touch-callout: none; -webkit-user-select: none; - -khtml-user-select: none; - -moz-user-select: none; - -ms-user-select: none; - user-select: none; + -moz-user-select: none; + -ms-user-select: none; + user-select: none; position: absolute; z-index: 10; width: 100%; @@ -276,11 +176,17 @@ width: 400px; max-width: calc(100% - 24px); background: rgba(10, 10, 10, 0.7); - transform: translate3d(100%, 0, 0); + -webkit-transform: translate3d(100%, 0, 0); + transform: translate3d(100%, 0, 0); opacity: 0; + -webkit-transition-property: opacity, -webkit-transform; + transition-property: opacity, -webkit-transform; transition-property: opacity, transform; - transition-timing-function: ease-in-out; - transition-duration: .1s; + transition-property: opacity, transform, -webkit-transform; + -webkit-transition-timing-function: ease-in-out; + transition-timing-function: ease-in-out; + -webkit-transition-duration: .1s; + transition-duration: .1s; cursor: default; margin-left: 9px; } .psv-container--has-navbar .psv-panel { @@ -301,19 +207,27 @@ width: 15px; height: 1px; background-color: #fff; + -webkit-transition: .2s ease-in-out; transition: .2s ease-in-out; - transition-property: width, left, transform; } + -webkit-transition-property: width, left, -webkit-transform; + transition-property: width, left, -webkit-transform; + transition-property: width, left, transform; + transition-property: width, left, transform, -webkit-transform; } .psv-panel-close-button::before { - transform: rotate(45deg); } + -webkit-transform: rotate(45deg); + transform: rotate(45deg); } .psv-panel-close-button::after { - transform: rotate(-45deg); } + -webkit-transform: rotate(-45deg); + transform: rotate(-45deg); } .psv-panel-close-button:hover::before, .psv-panel-close-button:hover::after { left: 0; width: 23px; } .psv-panel-close-button:hover::before { - transform: rotate(135deg); } + -webkit-transform: rotate(135deg); + transform: rotate(135deg); } .psv-panel-close-button:hover::after { - transform: rotate(45deg); } + -webkit-transform: rotate(45deg); + transform: rotate(45deg); } .psv-panel-resizer { display: none; position: absolute; @@ -331,29 +245,31 @@ margin-top: -14.5px; width: 1px; height: 1px; - box-shadow: 1px 0 #fff, 3px 0px #fff, 5px 0px #fff, 1px 2px #fff, 3px 2px #fff, 5px 2px #fff, 1px 4px #fff, 3px 4px #fff, 5px 4px #fff, 1px 6px #fff, 3px 6px #fff, 5px 6px #fff, 1px 8px #fff, 3px 8px #fff, 5px 8px #fff, 1px 10px #fff, 3px 10px #fff, 5px 10px #fff, 1px 12px #fff, 3px 12px #fff, 5px 12px #fff, 1px 14px #fff, 3px 14px #fff, 5px 14px #fff, 1px 16px #fff, 3px 16px #fff, 5px 16px #fff, 1px 18px #fff, 3px 18px #fff, 5px 18px #fff, 1px 20px #fff, 3px 20px #fff, 5px 20px #fff, 1px 22px #fff, 3px 22px #fff, 5px 22px #fff, 1px 24px #fff, 3px 24px #fff, 5px 24px #fff, 1px 26px #fff, 3px 26px #fff, 5px 26px #fff, 1px 28px #fff, 3px 28px #fff, 5px 28px #fff; + -webkit-box-shadow: 1px 0 #fff, 3px 0px #fff, 5px 0px #fff, 1px 2px #fff, 3px 2px #fff, 5px 2px #fff, 1px 4px #fff, 3px 4px #fff, 5px 4px #fff, 1px 6px #fff, 3px 6px #fff, 5px 6px #fff, 1px 8px #fff, 3px 8px #fff, 5px 8px #fff, 1px 10px #fff, 3px 10px #fff, 5px 10px #fff, 1px 12px #fff, 3px 12px #fff, 5px 12px #fff, 1px 14px #fff, 3px 14px #fff, 5px 14px #fff, 1px 16px #fff, 3px 16px #fff, 5px 16px #fff, 1px 18px #fff, 3px 18px #fff, 5px 18px #fff, 1px 20px #fff, 3px 20px #fff, 5px 20px #fff, 1px 22px #fff, 3px 22px #fff, 5px 22px #fff, 1px 24px #fff, 3px 24px #fff, 5px 24px #fff, 1px 26px #fff, 3px 26px #fff, 5px 26px #fff, 1px 28px #fff, 3px 28px #fff, 5px 28px #fff; + box-shadow: 1px 0 #fff, 3px 0px #fff, 5px 0px #fff, 1px 2px #fff, 3px 2px #fff, 5px 2px #fff, 1px 4px #fff, 3px 4px #fff, 5px 4px #fff, 1px 6px #fff, 3px 6px #fff, 5px 6px #fff, 1px 8px #fff, 3px 8px #fff, 5px 8px #fff, 1px 10px #fff, 3px 10px #fff, 5px 10px #fff, 1px 12px #fff, 3px 12px #fff, 5px 12px #fff, 1px 14px #fff, 3px 14px #fff, 5px 14px #fff, 1px 16px #fff, 3px 16px #fff, 5px 16px #fff, 1px 18px #fff, 3px 18px #fff, 5px 18px #fff, 1px 20px #fff, 3px 20px #fff, 5px 20px #fff, 1px 22px #fff, 3px 22px #fff, 5px 22px #fff, 1px 24px #fff, 3px 24px #fff, 5px 24px #fff, 1px 26px #fff, 3px 26px #fff, 5px 26px #fff, 1px 28px #fff, 3px 28px #fff, 5px 28px #fff; background: transparent; } .psv-panel-content { width: 100%; height: 100%; - box-sizing: border-box; + -webkit-box-sizing: border-box; + box-sizing: border-box; color: gainsboro; font: 16px sans-serif; overflow: auto; } .psv-panel-content:not(.psv-panel-content--no-margin) { padding: 1em; } .psv-panel-content--no-interaction { - -webkit-touch-callout: none; -webkit-user-select: none; - -khtml-user-select: none; - -moz-user-select: none; - -ms-user-select: none; - user-select: none; + -moz-user-select: none; + -ms-user-select: none; + user-select: none; pointer-events: none; } .psv-panel--open { - transform: translate3d(0, 0, 0); + -webkit-transform: translate3d(0, 0, 0); + transform: translate3d(0, 0, 0); opacity: 1; - transition-duration: .2s; } + -webkit-transition-duration: .2s; + transition-duration: .2s; } .psv-panel--open .psv-panel-close-button, .psv-panel--open .psv-panel-resizer { display: block; } @@ -361,15 +277,19 @@ .psv-tooltip { position: absolute; z-index: 50; - box-sizing: border-box; + -webkit-box-sizing: border-box; + box-sizing: border-box; max-width: 200px; background-color: rgba(61, 61, 61, 0.8); border-radius: 4px; padding: 0.5em 1em; opacity: 0; + -webkit-transition-property: opacity; transition-property: opacity; - transition-timing-function: ease-in-out; - transition-duration: 0.1s; } + -webkit-transition-timing-function: ease-in-out; + transition-timing-function: ease-in-out; + -webkit-transition-duration: 100ms; + transition-duration: 100ms; } .psv-tooltip-content { color: white; font: 14px sans-serif; @@ -380,71 +300,121 @@ width: 0; border: 7px solid transparent; } .psv-tooltip--bottom-center { - box-shadow: 0 3px 0 rgba(90, 90, 90, 0.7); - transform: translate3d(0, -5px, 0); - transition-property: opacity, transform; } + -webkit-box-shadow: 0 3px 0 rgba(90, 90, 90, 0.7); + box-shadow: 0 3px 0 rgba(90, 90, 90, 0.7); + -webkit-transform: translate3d(0, -5px, 0); + transform: translate3d(0, -5px, 0); + -webkit-transition-property: opacity, -webkit-transform; + transition-property: opacity, -webkit-transform; + transition-property: opacity, transform; + transition-property: opacity, transform, -webkit-transform; } .psv-tooltip--bottom-center .psv-tooltip-arrow { border-bottom-color: rgba(61, 61, 61, 0.8); } .psv-tooltip--center-left { - box-shadow: -3px 0 0 rgba(90, 90, 90, 0.7); - transform: translate3d(5px, 0, 0); - transition-property: opacity, transform; } + -webkit-box-shadow: -3px 0 0 rgba(90, 90, 90, 0.7); + box-shadow: -3px 0 0 rgba(90, 90, 90, 0.7); + -webkit-transform: translate3d(5px, 0, 0); + transform: translate3d(5px, 0, 0); + -webkit-transition-property: opacity, -webkit-transform; + transition-property: opacity, -webkit-transform; + transition-property: opacity, transform; + transition-property: opacity, transform, -webkit-transform; } .psv-tooltip--center-left .psv-tooltip-arrow { border-left-color: rgba(61, 61, 61, 0.8); } .psv-tooltip--top-center { - box-shadow: 0 -3px 0 rgba(90, 90, 90, 0.7); - transform: translate3d(0, 5px, 0); - transition-property: opacity, transform; } + -webkit-box-shadow: 0 -3px 0 rgba(90, 90, 90, 0.7); + box-shadow: 0 -3px 0 rgba(90, 90, 90, 0.7); + -webkit-transform: translate3d(0, 5px, 0); + transform: translate3d(0, 5px, 0); + -webkit-transition-property: opacity, -webkit-transform; + transition-property: opacity, -webkit-transform; + transition-property: opacity, transform; + transition-property: opacity, transform, -webkit-transform; } .psv-tooltip--top-center .psv-tooltip-arrow { border-top-color: rgba(61, 61, 61, 0.8); } .psv-tooltip--center-right { - box-shadow: 3px 0 0 rgba(90, 90, 90, 0.7); - transform: translate3d(-5px, 0, 0); - transition-property: opacity, transform; } + -webkit-box-shadow: 3px 0 0 rgba(90, 90, 90, 0.7); + box-shadow: 3px 0 0 rgba(90, 90, 90, 0.7); + -webkit-transform: translate3d(-5px, 0, 0); + transform: translate3d(-5px, 0, 0); + -webkit-transition-property: opacity, -webkit-transform; + transition-property: opacity, -webkit-transform; + transition-property: opacity, transform; + transition-property: opacity, transform, -webkit-transform; } .psv-tooltip--center-right .psv-tooltip-arrow { border-right-color: rgba(61, 61, 61, 0.8); } .psv-tooltip--bottom-left { - box-shadow: -3px 3px 0 rgba(90, 90, 90, 0.7); - transform: translate3d(0, -5px, 0); - transition-property: opacity, transform; } + -webkit-box-shadow: -3px 3px 0 rgba(90, 90, 90, 0.7); + box-shadow: -3px 3px 0 rgba(90, 90, 90, 0.7); + -webkit-transform: translate3d(0, -5px, 0); + transform: translate3d(0, -5px, 0); + -webkit-transition-property: opacity, -webkit-transform; + transition-property: opacity, -webkit-transform; + transition-property: opacity, transform; + transition-property: opacity, transform, -webkit-transform; } .psv-tooltip--bottom-left .psv-tooltip-arrow { border-bottom-color: rgba(61, 61, 61, 0.8); } .psv-tooltip--bottom-right { - box-shadow: 3px 3px 0 rgba(90, 90, 90, 0.7); - transform: translate3d(0, -5px, 0); - transition-property: opacity, transform; } + -webkit-box-shadow: 3px 3px 0 rgba(90, 90, 90, 0.7); + box-shadow: 3px 3px 0 rgba(90, 90, 90, 0.7); + -webkit-transform: translate3d(0, -5px, 0); + transform: translate3d(0, -5px, 0); + -webkit-transition-property: opacity, -webkit-transform; + transition-property: opacity, -webkit-transform; + transition-property: opacity, transform; + transition-property: opacity, transform, -webkit-transform; } .psv-tooltip--bottom-right .psv-tooltip-arrow { border-bottom-color: rgba(61, 61, 61, 0.8); } .psv-tooltip--top-left { - box-shadow: -3px -3px 0 rgba(90, 90, 90, 0.7); - transform: translate3d(0, 5px, 0); - transition-property: opacity, transform; } + -webkit-box-shadow: -3px -3px 0 rgba(90, 90, 90, 0.7); + box-shadow: -3px -3px 0 rgba(90, 90, 90, 0.7); + -webkit-transform: translate3d(0, 5px, 0); + transform: translate3d(0, 5px, 0); + -webkit-transition-property: opacity, -webkit-transform; + transition-property: opacity, -webkit-transform; + transition-property: opacity, transform; + transition-property: opacity, transform, -webkit-transform; } .psv-tooltip--top-left .psv-tooltip-arrow { border-top-color: rgba(61, 61, 61, 0.8); } .psv-tooltip--top-right { - box-shadow: 3px -3px 0 rgba(90, 90, 90, 0.7); - transform: translate3d(0, 5px, 0); - transition-property: opacity, transform; } + -webkit-box-shadow: 3px -3px 0 rgba(90, 90, 90, 0.7); + box-shadow: 3px -3px 0 rgba(90, 90, 90, 0.7); + -webkit-transform: translate3d(0, 5px, 0); + transform: translate3d(0, 5px, 0); + -webkit-transition-property: opacity, -webkit-transform; + transition-property: opacity, -webkit-transform; + transition-property: opacity, transform; + transition-property: opacity, transform, -webkit-transform; } .psv-tooltip--top-right .psv-tooltip-arrow { border-top-color: rgba(61, 61, 61, 0.8); } .psv-tooltip--visible { - transform: translate3d(0, 0, 0); + -webkit-transform: translate3d(0, 0, 0); + transform: translate3d(0, 0, 0); opacity: 1; - transition-duration: 0.1s; } + -webkit-transition-duration: 100ms; + transition-duration: 100ms; } .psv-notification { position: absolute; z-index: 100; bottom: 40px; + display: -webkit-box; + display: -ms-flexbox; display: flex; - justify-content: center; - box-sizing: border-box; + -webkit-box-pack: center; + -ms-flex-pack: center; + justify-content: center; + -webkit-box-sizing: border-box; + box-sizing: border-box; width: 100%; - padding: 0 40px; + padding: 0 2em; opacity: 0; + -webkit-transition-property: opacity, bottom; transition-property: opacity, bottom; - transition-timing-function: ease-in-out; - transition-duration: 0.1s; } + -webkit-transition-timing-function: ease-in-out; + transition-timing-function: ease-in-out; + -webkit-transition-duration: 200ms; + transition-duration: 200ms; } .psv-notification-content { max-width: 50em; background-color: rgba(61, 61, 61, 0.8); @@ -456,43 +426,153 @@ opacity: 100; bottom: 80px; } -.psv-please-rotate { +.psv-overlay { display: -webkit-box; - display: -webkit-flex; - display: -moz-flex; display: -ms-flexbox; display: flex; - -webkit-flex-direction: column; - -moz-flex-direction: column; - -ms-flex-direction: column; - flex-direction: column; - -webkit-align-items: center; - -moz-align-items: center; - -ms-align-items: center; - align-items: center; - -webkit-justify-content: center; - -moz-justify-content: center; - -ms-justify-content: center; - justify-content: center; - -ms-flex-pack: center; + -webkit-box-orient: vertical; + -webkit-box-direction: normal; + -ms-flex-direction: column; + flex-direction: column; + -webkit-box-align: center; + -ms-flex-align: center; + align-items: center; + -webkit-box-pack: center; + -ms-flex-pack: center; + justify-content: center; position: absolute; - z-index: 101; + z-index: 110; top: 0; left: 0; bottom: 0; right: 0; - background: radial-gradient(#fff 0%, #fdfdfd 16%, #fbfbfb 33%, #f8f8f8 49%, #efefef 66%, #dfdfdf 82%, #bfbfbf 100%); } - .psv-please-rotate-image { + background: radial-gradient(#fff 0%, #fdfdfd 16%, #fbfbfb 33%, #f8f8f8 49%, #efefef 66%, #dfdfdf 82%, #bfbfbf 100%); + opacity: 0.8; } + .psv-overlay-image { margin-bottom: 4vh; } - .psv-please-rotate-image svg { + .psv-overlay-image svg { width: 50vw; } @media screen and (orientation: landscape) { - .psv-please-rotate-image svg { - width: 30vw; } } - .psv-please-rotate-text { - font: 14px sans-serif; - font-size: 30px; } - .psv-please-rotate-subtext { - font: 14px sans-serif; - font-size: 20px; - opacity: .8; } + .psv-overlay-image svg { + width: 25vw; } } + .psv-overlay-text { + font: 30px sans-serif; + text-align: center; } + .psv-overlay-subtext { + font: 20px sans-serif; + opacity: .8; + text-align: center; } + +.psv-markers-list-title { + font: 24px sans-serif; + margin: 1em 0; + text-align: center; + text-shadow: 2px 1px #000; } + +.psv-markers-list { + list-style: none; + margin: 0; + padding: 0; + overflow: hidden; } + .psv-markers-list-item { + clear: both; + min-height: 20px; + padding: 0.5em 1em; + cursor: pointer; + -webkit-transform: translateX(0); + transform: translateX(0); + -webkit-transition: -webkit-transform .3s ease-in-out; + transition: -webkit-transform .3s ease-in-out; + transition: transform .3s ease-in-out; + transition: transform .3s ease-in-out, -webkit-transform .3s ease-in-out; } + .psv-markers-list-item::before { + content: ''; + position: absolute; + top: 0; + left: 0; + height: 100%; + width: 10px; + margin-left: -10px; } + .psv-markers-list-item:nth-child(odd), .psv-markers-list-item:nth-child(odd)::before { + background: rgba(255, 255, 255, 0.1); } + .psv-markers-list-item:nth-child(even), .psv-markers-list-item:nth-child(even)::before { + background: transparent; } + .psv-markers-list-item:hover { + -webkit-transform: translateX(10px); + transform: translateX(10px); + -webkit-transition: -webkit-transform .1s ease-in-out; + transition: -webkit-transform .1s ease-in-out; + transition: transform .1s ease-in-out; + transition: transform .1s ease-in-out, -webkit-transform .1s ease-in-out; } + .psv-markers-list-image { + float: left; + width: 20px; } + .psv-markers-list-name { + margin: 0; + padding: 0; } + .psv-markers-list-image + .psv-markers-list-name { + padding-left: calc(20px + 0.5em); } + +.psv-autorotate-button { + width: 25px; + height: 25px; + padding: 7.5px; } + +.psv-zoom-button { + cursor: default; + width: 128px; } + .psv-zoom-button-minus, .psv-zoom-button-plus { + float: left; + position: relative; + cursor: pointer; + width: 16px; + height: 16px; } + .psv-zoom-button-minus .psv-button-svg, .psv-zoom-button-plus .psv-button-svg { + position: relative; + top: 20%; } + .psv-zoom-button-range { + float: left; + padding: 9.5px 8px; } + .psv-zoom-button-line { + position: relative; + cursor: pointer; + width: 80px; + height: 1px; + background: rgba(255, 255, 255, 0.7); + -webkit-transition: all .3s ease; + transition: all .3s ease; } + .psv-zoom-button-handle { + position: absolute; + border-radius: 50%; + top: -3px; + width: 7px; + height: 7px; + background: rgba(255, 255, 255, 0.7); + -webkit-transform: scale(1); + transform: scale(1); + -webkit-transition: -webkit-transform .3s ease; + transition: -webkit-transform .3s ease; + transition: transform .3s ease; + transition: transform .3s ease, -webkit-transform .3s ease; } + .psv-zoom-button:not(.psv-button--disabled):hover .psv-zoom-button-line { + -webkit-box-shadow: 0 0 2px rgba(255, 255, 255, 0.7); + box-shadow: 0 0 2px rgba(255, 255, 255, 0.7); } + .psv-zoom-button:not(.psv-button--disabled):hover .psv-zoom-button-handle { + -webkit-transform: scale(1.3); + transform: scale(1.3); } + @media (max-width: 600px) { + .psv-zoom-button { + width: auto; + padding: 0; } + .psv-zoom-button-range { + display: none; } + .psv-zoom-button-minus, .psv-zoom-button-plus { + width: 20px; + height: 20px; + padding: 10px; } + .psv-zoom-button-minus .psv-button-svg, .psv-zoom-button-plus .psv-button-svg { + top: 0; } } + +@media (max-width: 600px) { + .psv-is-touch .psv-zoom-button { + display: none; } } diff --git a/dist/photo-sphere-viewer.js b/dist/photo-sphere-viewer.js index 0481d252c..ad166ac9c 100644 --- a/dist/photo-sphere-viewer.js +++ b/dist/photo-sphere-viewer.js @@ -1,5 +1,5 @@ /*! - * Photo Sphere Viewer 3.4.0 + * Photo Sphere Viewer 3.4.1 * Copyright (c) 2014-2015 Jérémy Heleine * Copyright (c) 2015-2018 Damien "Mistic" Sorel * Licensed under MIT (https://opensource.org/licenses/MIT) @@ -164,20 +164,28 @@ function PhotoSphereViewer(options) { console.warn('PhotoSphereViewer: max_fov cannot be lower than min_fov.'); } + // cache_texture must be a positive integer or false if (this.config.cache_texture && (!PSVUtils.isInteger(this.config.cache_texture) || this.config.cache_texture < 0)) { this.config.cache_texture = PhotoSphereViewer.DEFAULTS.cache_texture; console.warn('PhotoSphereViewer: invalid value for cache_texture'); } + // panorama_roll is deprecated if ('panorama_roll' in this.config) { this.config.sphere_correction.roll = this.config.panorama_roll; console.warn('PhotoSphereViewer: panorama_roll is deprecated, use sphere_correction.roll instead'); } + // gyroscope is deprecated if ('gyroscope' in this.config) { console.warn('PhotoSphereViewer: gyroscope is deprecated, the control is automatically created if DeviceOrientationControls.js is loaded'); } + // keyboard=true becomes the default map + if (this.config.keyboard === true) { + this.config.keyboard = PSVUtils.clone(PhotoSphereViewer.DEFAULTS.keyboard); + } + // min_fov/max_fov between 1 and 179 this.config.min_fov = PSVUtils.bound(this.config.min_fov, 1, 179); this.config.max_fov = PSVUtils.bound(this.config.max_fov, 1, 179); @@ -292,10 +300,10 @@ function PhotoSphereViewer(options) { this.notification = null; /** - * @member {module:components.PSVPleaseRotate} + * @member {module:components.PSVOverlay} * @readonly */ - this.pleaseRotate = null; + this.overlay = null; /** * @member {HTMLElement} @@ -498,6 +506,9 @@ function PhotoSphereViewer(options) { // load notification this.notification = new PSVNotification(this); + // load overlay + this.overlay = new PSVOverlay(this); + // attach event handlers this._bindEvents(); @@ -1423,23 +1434,6 @@ PhotoSphereViewer.CUBE_MAP = [0, 2, 4, 5, 3, 1]; */ PhotoSphereViewer.CUBE_HASHMAP = ['left', 'right', 'top', 'bottom', 'back', 'front']; -/** - * @summary Map between keyboard events `keyCode|which` and `key` - * @type {Object.} - * @readonly - * @private - */ -PhotoSphereViewer.KEYMAP = { - 33: 'PageUp', - 34: 'PageDown', - 37: 'ArrowLeft', - 38: 'ArrowUp', - 39: 'ArrowRight', - 40: 'ArrowDown', - 107: '+', - 109: '-' -}; - /** * @summary System properties * @type {Object} @@ -1520,13 +1514,25 @@ PhotoSphereViewer.DEFAULTS = { gyroscope: 'Gyroscope', stereo: 'Stereo view', stereo_notification: 'Click anywhere to exit stereo view.', - please_rotate: ['Please rotate your device', '(or tap to continue)'] + please_rotate: ['Please rotate your device', '(or tap to continue)'], + two_fingers: ['Use two fingers to navigate'] }, mousewheel: true, mousewheel_factor: 1, mousemove: true, mousemove_hover: false, - keyboard: true, + touchmove_two_fingers: false, + keyboard: { + 'ArrowUp': 'rotateLatitudeUp', + 'ArrowDown': 'rotateLatitudeDown', + 'ArrowRight': 'rotateLongitudeRight', + 'ArrowLeft': 'rotateLongitudeLeft', + 'PageUp': 'zoomIn', + 'PageDown': 'zoomOut', + '+': 'zoomIn', + '-': 'zoomOut', + ' ': 'toggleAutorotate' + }, move_inertia: true, click_event_on_marker: false, transition: { @@ -1696,16 +1702,18 @@ PhotoSphereViewer.prototype._onKeyDown = function(evt) { var dLat = 0; var dZoom = 0; - var key = evt.key || PhotoSphereViewer.KEYMAP[evt.keyCode || evt.which]; + var key = PSVUtils.getEventKey(evt); + var action = this.config.keyboard[key]; - switch (key) { + switch (action) { // @formatter:off - case 'ArrowUp': dLat = 0.01; break; - case 'ArrowDown': dLat = -0.01; break; - case 'ArrowRight': dLong = 0.01; break; - case 'ArrowLeft': dLong = -0.01; break; - case 'PageUp':case '+': dZoom = 1; break; - case 'PageDown':case '-': dZoom = -1; break; + case 'rotateLatitudeUp': dLat = 0.01; break; + case 'rotateLatitudeDown': dLat = -0.01; break; + case 'rotateLongitudeRight': dLong = 0.01; break; + case 'rotateLongitudeLeft': dLong = -0.01; break; + case 'zoomIn': dZoom = 1; break; + case 'zoomOut': dZoom = -1; break; + case 'toggleAutorotate': this.toggleAutorotate(); break; // @formatter:on } @@ -1764,10 +1772,12 @@ PhotoSphereViewer.prototype._onMouseMove = function(evt) { */ PhotoSphereViewer.prototype._onTouchStart = function(evt) { if (evt.touches.length === 1) { - this._startMove(evt.touches[0]); + if (!this.config.touchmove_two_fingers) { + this._startMove(evt.touches[0]); + } } else if (evt.touches.length === 2) { - this._startZoom(evt); + this._startMoveZoom(evt); } }; @@ -1777,7 +1787,16 @@ PhotoSphereViewer.prototype._onTouchStart = function(evt) { * @private */ PhotoSphereViewer.prototype._onTouchEnd = function(evt) { - this._stopMove(evt.changedTouches[0]); + if (evt.touches.length === 1) { + this._stopMoveZoom(); + } + else if (evt.touches.length === 0) { + this._stopMove(evt.changedTouches[0]); + + if (this.config.touchmove_two_fingers) { + this.overlay.hideOverlay(); + } + } }; /** @@ -1787,12 +1806,20 @@ PhotoSphereViewer.prototype._onTouchEnd = function(evt) { */ PhotoSphereViewer.prototype._onTouchMove = function(evt) { if (evt.touches.length === 1) { - evt.preventDefault(); - this._move(evt.touches[0]); + if (this.config.touchmove_two_fingers) { + this.overlay.showOverlay({ + image: PhotoSphereViewer.ICONS['gesture.svg'], + text: this.config.lang.two_fingers[0] + }); + } + else { + evt.preventDefault(); + this._move(evt.touches[0]); + } } else if (evt.touches.length === 2) { evt.preventDefault(); - this._zoom(evt); + this._moveZoom(evt); } }; @@ -1815,18 +1842,20 @@ PhotoSphereViewer.prototype._startMove = function(evt) { }; /** - * @summary Initializes the zoom + * @summary Initializes the combines move and zoom * @param {TouchEvent} evt * @private */ -PhotoSphereViewer.prototype._startZoom = function(evt) { +PhotoSphereViewer.prototype._startMoveZoom = function(evt) { var t = [ { x: parseInt(evt.touches[0].clientX), y: parseInt(evt.touches[0].clientY) }, { x: parseInt(evt.touches[1].clientX), y: parseInt(evt.touches[1].clientY) } ]; this.prop.pinch_dist = Math.sqrt(Math.pow(t[0].x - t[1].x, 2) + Math.pow(t[0].y - t[1].y, 2)); - this.prop.moving = false; + this.prop.mouse_x = this.prop.start_mouse_x = (t[0].x + t[1].x) / 2; + this.prop.mouse_y = this.prop.start_mouse_x = (t[0].y + t[1].y) / 2; + this.prop.moving = true; this.prop.zooming = true; }; @@ -1858,7 +1887,15 @@ PhotoSphereViewer.prototype._stopMove = function(evt) { this.prop.mouse_history.length = 0; } +}; +/** + * @summary Stops the combined move and zoom + * @private + */ +PhotoSphereViewer.prototype._stopMoveZoom = function() { + this.prop.mouse_history.length = 0; + this.prop.moving = false; this.prop.zooming = false; }; @@ -2007,12 +2044,12 @@ PhotoSphereViewer.prototype._moveAbsolute = function(evt) { }; /** - * @summary Perfoms zoom + * @summary Perfoms combines move and zoom * @param {TouchEvent} evt * @private */ -PhotoSphereViewer.prototype._zoom = function(evt) { - if (this.prop.zooming) { +PhotoSphereViewer.prototype._moveZoom = function(evt) { + if (this.prop.zooming && this.prop.moving) { var t = [ { x: parseInt(evt.touches[0].clientX), y: parseInt(evt.touches[0].clientY) }, { x: parseInt(evt.touches[1].clientX), y: parseInt(evt.touches[1].clientY) } @@ -2023,6 +2060,11 @@ PhotoSphereViewer.prototype._zoom = function(evt) { this.zoom(this.prop.zoom_lvl + delta); + this._move({ + clientX: (t[0].x + t[1].x) / 2, + clientY: (t[0].y + t[1].y) / 2 + }); + this.prop.pinch_dist = p; } }; @@ -2225,8 +2267,8 @@ PhotoSphereViewer.prototype.destroy = function() { if (this.panel) { this.panel.destroy(); } - if (this.pleaseRotate) { - this.pleaseRotate.destroy(); + if (this.overlay) { + this.overlay.destroy(); } // destroy ThreeJS view @@ -2251,7 +2293,7 @@ PhotoSphereViewer.prototype.destroy = function() { delete this.panel; delete this.tooltip; delete this.notification; - delete this.pleaseRotate; + delete this.overlay; delete this.canvas_container; delete this.renderer; delete this.noSleep; @@ -2413,8 +2455,8 @@ PhotoSphereViewer.prototype.toggleAutorotate = function() { */ PhotoSphereViewer.prototype.startGyroscopeControl = function() { if (PSVUtils.checkTHREE('DeviceOrientationControls')) { - return PhotoSphereViewer.SYSTEM.deviceOrientationSupported.then( - function() { + return PhotoSphereViewer.SYSTEM.deviceOrientationSupported.then(function(supported) { + if (supported) { this._stopAll(); this.doControls = new THREE.DeviceOrientationControls(this.camera); @@ -2438,12 +2480,12 @@ PhotoSphereViewer.prototype.startGyroscopeControl = function() { * @param {boolean} enabled */ this.trigger('gyroscope-updated', true); - }.bind(this), - function() { + } + else { console.warn('PhotoSphereViewer: gyroscope not available'); return D.rejected(); } - ); + }.bind(this)); } else { throw new PSVError('Missing Three.js components: DeviceOrientationControls. Get them from three.js-examples package.'); @@ -2598,17 +2640,25 @@ PhotoSphereViewer.prototype.stopStereoView = function() { * @summary Tries to lock the device in landscape or display a message */ PhotoSphereViewer.prototype.lockOrientation = function() { + var displayRotateMessageTimeout; + var displayRotateMessage = function() { - if (window.innerHeight > window.innerWidth) { - if (!this.pleaseRotate) { - this.pleaseRotate = new PSVPleaseRotate(this); - } - this.pleaseRotate.show(); + if (this.isStereoEnabled() && window.innerHeight > window.innerWidth) { + this.overlay.showOverlay({ + image: PhotoSphereViewer.ICONS['mobile-rotate.svg'], + text: this.config.lang.please_rotate[0], + subtext: this.config.lang.please_rotate[1] + }); + } + + if (displayRotateMessageTimeout) { + window.clearTimeout(displayRotateMessageTimeout); } }; if (window.screen && window.screen.orientation) { window.screen.orientation.lock('landscape').then(null, displayRotateMessage.bind(this)); + displayRotateMessageTimeout = setTimeout(displayRotateMessage.bind(this), 500); } else { displayRotateMessage.apply(this); @@ -2623,9 +2673,7 @@ PhotoSphereViewer.prototype.unlockOrientation = function() { window.screen.orientation.unlock(); } else { - if (this.pleaseRotate) { - this.pleaseRotate.hide(); - } + this.overlay.hideOverlay(); } }; @@ -4272,11 +4320,11 @@ function PSVNavBarCaption(navbar, caption) { this.content = null; /** - * @member {SVGElement} + * @member {PSVNavBarCaptionButton} * @readonly * @private */ - this.icon = null; + this.button = null; /** * @member {Object} @@ -4284,8 +4332,7 @@ function PSVNavBarCaption(navbar, caption) { */ this.prop = { caption: '', - width: 0, - hidden: false + width: 0 }; this.create(); @@ -4305,16 +4352,13 @@ PSVNavBarCaption.publicMethods = ['setCaption']; PSVNavBarCaption.prototype.create = function() { PSVComponent.prototype.create.call(this); - this.container.innerHTML = PhotoSphereViewer.ICONS['info.svg']; - this.icon = this.container.querySelector('svg'); - this.icon.setAttribute('class', 'psv-caption-icon'); - this.icon.style.display = 'none'; + this.button = new PSVNavBarCaptionButton(this); + this.button.hide(); - this.content = document.createElement('span'); + this.content = document.createElement('div'); this.content.className = 'psv-caption-content'; this.container.appendChild(this.content); - this.icon.addEventListener('click', this); window.addEventListener('resize', this); }; @@ -4338,7 +4382,6 @@ PSVNavBarCaption.prototype.handleEvent = function(e) { switch (e.type) { // @formatter:off case 'resize': this._onResize(); break; - case 'click': this._onClick(); break; // @formatter:on } }; @@ -4371,28 +4414,15 @@ PSVNavBarCaption.prototype._onResize = function() { var width = parseInt(PSVUtils.getStyle(this.container, 'width')); // get real inner width if (width >= this.prop.width) { - this.icon.style.display = 'none'; + this.button.hide(); this.content.style.display = ''; } else { - this.icon.style.display = ''; + this.button.show(); this.content.style.display = 'none'; } }; -/** - * @summary Display caption as notification - * @private - */ -PSVNavBarCaption.prototype._onClick = function() { - if (this.psv.isNotificationVisible()) { - this.psv.hideNotification(); - } - else { - this.psv.showNotification(this.prop.caption); - } -}; - /** * Notification class @@ -4495,6 +4525,120 @@ PSVNotification.prototype.hideNotification = function() { }; +/** + * Overlay class + * @param {PhotoSphereViewer} psv + * @constructor + * @extends module:components.PSVComponent + * @memberof module:components + */ +function PSVOverlay(psv) { + PSVComponent.call(this, psv); + + this.create(); + this.hide(); +} + +PSVOverlay.prototype = Object.create(PSVComponent.prototype); +PSVOverlay.prototype.constructor = PSVOverlay; + +PSVOverlay.className = 'psv-overlay'; +PSVOverlay.publicMethods = ['showOverlay', 'hideOverlay', 'isOverlayVisible']; + +/** + * @override + */ +PSVOverlay.prototype.create = function() { + PSVComponent.prototype.create.call(this); + + this.image = document.createElement('div'); + this.image.className = 'psv-overlay-image'; + this.container.appendChild(this.image); + + this.text = document.createElement('div'); + this.text.className = 'psv-overlay-text'; + this.container.appendChild(this.text); + + this.subtext = document.createElement('div'); + this.subtext.className = 'psv-overlay-subtext'; + this.container.appendChild(this.subtext); + + this.container.addEventListener('click', this.hideOverlay.bind(this)); +}; + +/** + * @override + */ +PSVOverlay.prototype.destroy = function() { + delete this.image; + delete this.text; + delete this.subtext; + + PSVComponent.prototype.destroy.call(this); +}; + +/** + * @summary Checks if the overlay is visible + * @returns {boolean} + */ +PSVOverlay.prototype.isOverlayVisible = function() { + return this.visible; +}; + +/** + * @summary Displays an overlay on the viewer + * @param {Object|string} config + * @param {string} config.image + * @param {string} config.text + * @param {string} config.subtext + * + * @example + * viewer.showOverlay({ + * image: '', + * text: '....', + * subtext: '....' + * }) + */ +PSVOverlay.prototype.showOverlay = function(config) { + if (typeof config === 'string') { + config = { + text: config + }; + } + + this.image.innerHTML = config.image || ''; + this.text.innerHTML = config.text || ''; + this.subtext.innerHTML = config.subtext || ''; + + this.show(); + + /** + * @event show-overlay + * @memberof module:components.PSVOverlay + * @summary Trigered when the overlay is shown + */ + this.psv.trigger('show-overlay'); +}; + +/** + * @summary Hides the notification + * @fires module:components.PSVOverlay.hide-notification + */ +PSVOverlay.prototype.hideOverlay = function() { + if (this.isOverlayVisible()) { + this.hide(); + + /** + * @event hide-overlay + * @memberof module:components.PSVOverlay + * @summary Trigered when the overlay is hidden + */ + this.psv.trigger('hide-overlay'); + } +}; + + + /** * Panel class * @param {PhotoSphereViewer} psv @@ -4723,68 +4867,6 @@ PSVPanel.prototype._resize = function(evt) { }; -/** - * "Please rotate" class - * @param {PhotoSphereViewer} psv - * @constructor - * @extends module:components.PSVComponent - * @memberof module:components - */ -function PSVPleaseRotate(psv) { - PSVComponent.call(this, psv); - - this.create(); -} - -PSVPleaseRotate.prototype = Object.create(PSVComponent.prototype); -PSVPleaseRotate.prototype.constructor = PSVPleaseRotate; - -PSVPleaseRotate.className = 'psv-please-rotate'; - -/** - * @override - */ -PSVPleaseRotate.prototype.create = function() { - PSVComponent.prototype.create.call(this); - - this.container.innerHTML = - '
' + PhotoSphereViewer.ICONS['mobile-rotate.svg'] + '
' + - '
' + this.psv.config.lang.please_rotate[0] + '
' + - '
' + this.psv.config.lang.please_rotate[1] + '
'; - - this.container.addEventListener('click', this); - window.addEventListener('orientationchange', this); -}; - -/** - * @override - */ -PSVPleaseRotate.prototype.destroy = function() { - window.removeEventListener('orientationchange', this); - - PSVComponent.prototype.destroy.call(this); -}; - -/** - * @summary Handles events - * @param {Event} e - * @private - */ -PSVPleaseRotate.prototype.handleEvent = function(e) { - switch (e.type) { - // @formatter:off - case 'click': this.hide(); break; - case 'orientationchange': - if (Math.abs(window.orientation) === 90) { - this.hide(); - } - break; - // @formatter:on - } -}; - - - /** * Tooltip class * @param {module:components.PSVHUD} hud @@ -5176,6 +5258,20 @@ PSVNavBarButton.prototype.create = function() { } e.stopPropagation(); }.bind(this)); + + var supported = this.supported(); + if (typeof supported.then === 'function') { + this.hide(); + + supported.then(function(supported) { + if (supported) { + this.show(); + } + }.bind(this)); + } + else if (!supported) { + this.hide(); + } }; /** @@ -5186,6 +5282,14 @@ PSVNavBarButton.prototype.destroy = function() { PSVComponent.prototype.destroy.call(this); }; +/** + * @summary Checks if the button can be displayed + * @returns {boolean|Promise} + */ +PSVNavBarButton.prototype.supported = function() { + return true; +}; + /** * @summary Changes the active state of the button * @param {boolean} [active] - forced state @@ -5307,6 +5411,72 @@ PSVNavBarAutorotateButton.prototype._onClick = function() { }; +/** + * Navigation bar caption button class + * @param {module:components.PSVNavBarCaption} caption + * @constructor + * @extends module:components/buttons.PSVNavBarButton + * @memberof module:components/buttons + */ +function PSVNavBarCaptionButton(caption) { + PSVNavBarButton.call(this, caption); + + this.create(); +} + +PSVNavBarCaptionButton.prototype = Object.create(PSVNavBarButton.prototype); +PSVNavBarCaptionButton.prototype.constructor = PSVNavBarCaptionButton; + +PSVNavBarCaptionButton.id = 'markers'; +PSVNavBarCaptionButton.className = 'psv-button psv-button--hover-scale psv-caption-button'; +PSVNavBarCaptionButton.icon = 'info.svg'; + +/** + * @override + */ +PSVNavBarCaptionButton.prototype.create = function() { + PSVNavBarButton.prototype.create.call(this); + + this.psv.on('hide-notification', this); +}; + +/** + * @override + */ +PSVNavBarCaptionButton.prototype.destroy = function() { + this.psv.off('hide-notification', this); + + PSVNavBarButton.prototype.destroy.call(this); +}; + +/** + * @summary Handles events + * @param {Event} e + * @private + */ +PSVNavBarCaptionButton.prototype.handleEvent = function(e) { + switch (e.type) { + // @formatter:off + case 'hide-notification': this.toggleActive(false); break; + // @formatter:on + } +}; + +/** + * @override + * @description Toggles markers list + */ +PSVNavBarCaptionButton.prototype._onClick = function() { + if (this.psv.isNotificationVisible()) { + this.psv.hideNotification(); + } + else { + this.psv.showNotification(this.parent.prop.caption); + this.toggleActive(true); + } +}; + + /** * Navigation bar custom button class * @param {module:components.PSVNavBar} navbar @@ -5451,11 +5621,6 @@ PSVNavBarFullscreenButton.iconActive = 'fullscreen-out.svg'; PSVNavBarFullscreenButton.prototype.create = function() { PSVNavBarButton.prototype.create.call(this); - if (!PhotoSphereViewer.SYSTEM.fullscreenEvent) { - this.hide(); - console.warn('PhotoSphereViewer: fullscreen not supported.'); - } - this.psv.on('fullscreen-updated', this); }; @@ -5468,6 +5633,13 @@ PSVNavBarFullscreenButton.prototype.destroy = function() { PSVNavBarButton.prototype.destroy.call(this); }; +/** + * @override + */ +PSVNavBarFullscreenButton.prototype.supported = function() { + return !!PhotoSphereViewer.SYSTEM.fullscreenEvent; +}; + /** * Handle events * @param {Event} e @@ -5517,13 +5689,6 @@ PSVNavBarGyroscopeButton.icon = 'compass.svg'; PSVNavBarGyroscopeButton.prototype.create = function() { PSVNavBarButton.prototype.create.call(this); - PhotoSphereViewer.SYSTEM.deviceOrientationSupported.then( - this._onAvailabilityChange.bind(this, true), - this._onAvailabilityChange.bind(this, false) - ); - - this.hide(); - this.psv.on('gyroscope-updated', this); }; @@ -5536,6 +5701,18 @@ PSVNavBarGyroscopeButton.prototype.destroy = function() { PSVNavBarButton.prototype.destroy.call(this); }; +/** + * @override + */ +PSVNavBarGyroscopeButton.prototype.supported = function() { + if (!PSVUtils.checkTHREE('DeviceOrientationControls')) { + return false; + } + else { + return PhotoSphereViewer.SYSTEM.deviceOrientationSupported; + } +}; + /** * @summary Handles events * @param {Event} e @@ -5557,18 +5734,6 @@ PSVNavBarGyroscopeButton.prototype._onClick = function() { this.psv.toggleGyroscopeControl(); }; -/** - * @summary Updates button display when API is ready - * @param {boolean} available - * @private - * @throws {PSVError} when {@link THREE.DeviceOrientationControls} is not loaded - */ -PSVNavBarGyroscopeButton.prototype._onAvailabilityChange = function(available) { - if (available && PSVUtils.checkTHREE('DeviceOrientationControls')) { - this.show(); - } -}; - /** * Navigation bar markers button class @@ -5626,13 +5791,6 @@ PSVNavBarStereoButton.icon = 'stereo.svg'; PSVNavBarStereoButton.prototype.create = function() { PSVNavBarButton.prototype.create.call(this); - PhotoSphereViewer.SYSTEM.deviceOrientationSupported.then( - this._onAvailabilityChange.bind(this, true), - this._onAvailabilityChange.bind(this, false) - ); - - this.hide(); - this.psv.on('stereo-updated', this); }; @@ -5645,6 +5803,18 @@ PSVNavBarStereoButton.prototype.destroy = function() { PSVNavBarButton.prototype.destroy.call(this); }; +/** + * @override + */ +PSVNavBarStereoButton.prototype.supported = function() { + if (!PhotoSphereViewer.SYSTEM.fullscreenEvent || !PSVUtils.checkTHREE('DeviceOrientationControls')) { + return false; + } + else { + return PhotoSphereViewer.SYSTEM.deviceOrientationSupported; + } +}; + /** * @summary Handles events * @param {Event} e @@ -5666,19 +5836,6 @@ PSVNavBarStereoButton.prototype._onClick = function() { this.psv.toggleStereoView(); }; -/** - * @summary Updates button display when API is ready - * @param {boolean} available - * @private - * @throws {PSVError} when {@link THREE.DeviceOrientationControls} is not loaded - */ -PSVNavBarStereoButton.prototype._onAvailabilityChange = function(available) { - if (available && PSVUtils.checkTHREE('DeviceOrientationControls', 'StereoEffect')) { - this.show(); - } -}; - - /** * Navigation bar zoom button class @@ -6557,7 +6714,7 @@ PSVUtils.isWebGLSupported = function() { /** * @summary Detects if device orientation is supported * @description We can only be sure device orientation is supported once received an event with coherent data - * @returns {Promise} + * @returns {Promise} */ PSVUtils.isDeviceOrientationSupported = function() { var defer = D(); @@ -6565,10 +6722,10 @@ PSVUtils.isDeviceOrientationSupported = function() { if ('DeviceOrientationEvent' in window) { var listener = function(event) { if (event && event.alpha !== null && !isNaN(event.alpha)) { - defer.resolve(); + defer.resolve(true); } else { - defer.reject(); + defer.resolve(false); } window.removeEventListener('deviceorientation', listener); @@ -6583,7 +6740,7 @@ PSVUtils.isDeviceOrientationSupported = function() { }, 2000); } else { - defer.reject(); + defer.resolve(false); } return defer.promise; @@ -6713,7 +6870,7 @@ PSVUtils.hasParent = function(el, parent) { /** * @summary Gets the closest parent (can by itself) - * @param {HTMLElement} el (HTMLElement) + * @param {HTMLElement|SVGElement} el * @param {string} selector * @returns {HTMLElement} */ @@ -6724,7 +6881,7 @@ PSVUtils.getClosest = function(el, selector) { if (matches.bind(el)(selector)) { return el; } - } while (!!(el = el.parentElement)); + } while (!!(el instanceof SVGElement ? el = el.parentNode : el = el.parentElement)); return null; }; @@ -6739,6 +6896,61 @@ PSVUtils.mouseWheelEvent = function() { 'DOMMouseScroll'; // let's assume that remaining browsers are older Firefox }; +/** + * @summary Returns the key name of a KeyboardEvent + * @param {KeyboardEvent} evt + * @returns {string} + */ +PSVUtils.getEventKey = function(evt) { + var key = evt.key || PSVUtils.getEventKey.KEYMAP[evt.keyCode || evt.which]; + + if (key && PSVUtils.getEventKey.MS_KEYMAP[key]) { + key = PSVUtils.getEventKey.MS_KEYMAP[key]; + } + + return key; +}; + +/** + * @summary Map between keyboard events `keyCode|which` and `key` + * @type {Object.} + * @readonly + * @protected + */ +PSVUtils.getEventKey.KEYMAP = { + 13: 'Enter', + 27: 'Escape', + 32: ' ', + 33: 'PageUp', + 34: 'PageDown', + 37: 'ArrowLeft', + 38: 'ArrowUp', + 39: 'ArrowRight', + 40: 'ArrowDown', + 46: 'Delete', + 107: '+', + 109: '-' +}; + +/** + * @summary Map for non standard keyboard events `key` for IE and Edge + * @see https://github.com/shvaikalesh/shim-keyboard-event-key + * @type {Object.} + * @readonly + * @protected + */ +PSVUtils.getEventKey.MS_KEYMAP = { + Add: '+', + Del: 'Delete', + Down: 'ArrowDown', + Esc: 'Escape', + Left: 'ArrowLeft', + Right: 'ArrowRight', + Spacebar: ' ', + Subtract: '-', + Up: 'ArrowUp' +}; + /** * @summary Gets the event name for fullscreen * @returns {string} @@ -7490,6 +7702,8 @@ PhotoSphereViewer.ICONS['fullscreen-in.svg'] = ''; +PhotoSphereViewer.ICONS['gesture.svg'] = ''; + PhotoSphereViewer.ICONS['info.svg'] = ''; PhotoSphereViewer.ICONS['mobile-rotate.svg'] = ''; diff --git a/dist/photo-sphere-viewer.min.css b/dist/photo-sphere-viewer.min.css index 91ac741c5..fb4fc6c59 100644 --- a/dist/photo-sphere-viewer.min.css +++ b/dist/photo-sphere-viewer.min.css @@ -1,7 +1,7 @@ /*! - * Photo Sphere Viewer 3.4.0 + * Photo Sphere Viewer 3.4.1 * Copyright (c) 2014-2015 Jérémy Heleine * Copyright (c) 2015-2018 Damien "Mistic" Sorel * Licensed under MIT (https://opensource.org/licenses/MIT) */ -.psv-container{width:100%;height:100%;margin:0;padding:0;position:relative;background:radial-gradient(#fff 0,#fdfdfd 16%,#fbfbfb 33%,#f8f8f8 49%,#efefef 66%,#dfdfdf 82%,#bfbfbf 100%);overflow:hidden}.psv-canvas-container{position:absolute;top:0;left:0;z-index:0;transition:opacity linear .1s}.psv-canvas{display:block}.psv-loader-container{display:-webkit-box;display:-webkit-flex;display:-moz-flex;display:-ms-flexbox;display:flex;align-items:center;justify-content:center;position:absolute;top:0;left:0;width:100%;height:100%;z-index:100}.psv-loader{position:relative;text-align:center;color:rgba(61,61,61,.7);width:150px;height:150px;border:10px solid transparent}.psv-loader::before{content:'';display:inline-block;height:100%;vertical-align:middle}.psv-loader,.psv-loader-image,.psv-loader-text{display:inline-block;vertical-align:middle}.psv-loader-canvas{position:absolute;top:0;left:0;width:100%;height:100%}.psv-loader-text{font:14px sans-serif}.psv-navbar{display:-webkit-box;display:-webkit-flex;display:-moz-flex;display:-ms-flexbox;display:flex;position:absolute;z-index:90;bottom:-40px;left:0;width:100%;height:40px;background:rgba(61,61,61,.5);transition:bottom ease-in-out .1s}.psv-navbar--open{bottom:0}.psv-navbar,.psv-navbar *{box-sizing:content-box}.psv-caption{-webkit-box-flex:10;-webkit-flex-grow:10;-moz-flex-grow:10;-ms-flex-positive:10;flex-grow:10;color:rgba(255,255,255,.7);margin:10px;overflow:hidden;text-align:center}.psv-caption-icon{height:20px;width:20px;cursor:pointer}.psv-caption-icon *{fill:rgba(255,255,255,.7)}.psv-caption-content{font-family:sans-serif;white-space:nowrap}.psv-button{-webkit-box-flex:0;-webkit-flex-grow:0;-moz-flex-grow:0;-ms-flex-positive:0;flex-grow:0;-webkit-flex-shrink:0;-moz-flex-shrink:0;-ms-flex-negative:0;flex-shrink:0;padding:10px;position:relative;cursor:pointer;height:20px;width:20px;background:0 0;color:rgba(255,255,255,.7)}.psv-button--active{background:rgba(255,255,255,.1)}.psv-button--disabled{pointer-events:none;opacity:.5}.psv-button .psv-button-svg{width:100%;transform:scale(1);transition:transform .3s ease}.psv-button .psv-button-svg *{fill:rgba(255,255,255,.7)}.psv-button--hover-scale:not(.psv-button--disabled):hover .psv-button .psv-button-svg{transform:scale(1.2)}.psv-autorotate-button{width:25px;height:25px;padding:7.5px}.psv-zoom-button{cursor:default;width:128px}.psv-zoom-button-minus,.psv-zoom-button-plus{float:left;position:relative;cursor:pointer;width:16px;height:16px}.psv-zoom-button-minus .psv-button-svg,.psv-zoom-button-plus .psv-button-svg{position:relative;top:20%}.psv-zoom-button-range{float:left;padding:9.5px 8px}.psv-zoom-button-line{position:relative;cursor:pointer;width:80px;height:1px;background:rgba(255,255,255,.7);transition:all .3s ease}.psv-zoom-button-handle{position:absolute;border-radius:50%;top:-3px;width:7px;height:7px;background:rgba(255,255,255,.7);transform:scale(1);transition:transform .3s ease}.psv-zoom-button:not(.psv-button--disabled):hover .psv-zoom-button-line{box-shadow:0 0 2px rgba(255,255,255,.7)}.psv-zoom-button:not(.psv-button--disabled):hover .psv-zoom-button-handle{transform:scale(1.3)}@media (max-width:600px){.psv-zoom-button{width:auto;padding:0}.psv-zoom-button-range{display:none}.psv-zoom-button-minus,.psv-zoom-button-plus{width:20px;height:20px;padding:10px}.psv-zoom-button-minus .psv-button-svg,.psv-zoom-button-plus .psv-button-svg{top:0}}@media (max-width:600px){.psv-is-touch .psv-zoom-button{display:none}}.psv-markers-list-title{font:24px sans-serif;margin:1em 0;text-align:center;text-shadow:2px 1px #000}.psv-markers-list{list-style:none;margin:0;padding:0;overflow:hidden}.psv-markers-list-item{clear:both;min-height:20px;padding:.5em 1em;cursor:pointer;transform:translateX(0);transition:transform .3s ease-in-out}.psv-markers-list-item::before{content:'';position:absolute;top:0;left:0;height:100%;width:10px;margin-left:-10px}.psv-markers-list-item:nth-child(odd),.psv-markers-list-item:nth-child(odd)::before{background:rgba(255,255,255,.1)}.psv-markers-list-item:nth-child(even),.psv-markers-list-item:nth-child(even)::before{background:0 0}.psv-markers-list-item:hover{transform:translateX(10px);transition:transform .1s ease-in-out}.psv-markers-list-image{float:left;width:20px}.psv-markers-list-name{margin:0;padding:0}.psv-markers-list-image+.psv-markers-list-name{padding-left:calc(20px + .5em)}.psv-hud{-webkit-touch-callout:none;-webkit-user-select:none;-khtml-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none;position:absolute;z-index:10;width:100%;height:100%}.psv-hud-svg-container{position:absolute;top:0;left:0;width:100%;height:100%;z-index:20}.psv-marker{cursor:pointer;display:none}.psv-marker--normal{position:absolute;top:0;left:0;z-index:30;background-size:contain;background-repeat:no-repeat}.psv-marker--transparent{display:block;opacity:0}.psv-marker--visible{display:block}.psv-panel{position:absolute;z-index:90;right:0;height:100%;width:400px;max-width:calc(100% - 24px);background:rgba(10,10,10,.7);transform:translate3d(100%,0,0);opacity:0;transition-property:opacity,transform;transition-timing-function:ease-in-out;transition-duration:.1s;cursor:default;margin-left:9px}.psv-container--has-navbar .psv-panel{height:calc(100% - 40px)}.psv-panel-close-button{display:none;position:absolute;top:0;left:-24px;width:24px;height:24px;background:rgba(0,0,0,.9)}.psv-panel-close-button::after,.psv-panel-close-button::before{content:'';position:absolute;top:50%;left:4px;width:15px;height:1px;background-color:#fff;transition:.2s ease-in-out;transition-property:width,left,transform}.psv-panel-close-button::before{transform:rotate(45deg)}.psv-panel-close-button::after{transform:rotate(-45deg)}.psv-panel-close-button:hover::after,.psv-panel-close-button:hover::before{left:0;width:23px}.psv-panel-close-button:hover::before{transform:rotate(135deg)}.psv-panel-close-button:hover::after{transform:rotate(45deg)}.psv-panel-resizer{display:none;position:absolute;top:0;left:-9px;width:9px;height:100%;background-color:rgba(0,0,0,.9);cursor:col-resize}.psv-panel-resizer::before{content:'';position:absolute;top:50%;left:1px;margin-top:-14.5px;width:1px;height:1px;box-shadow:1px 0 #fff,3px 0 #fff,5px 0 #fff,1px 2px #fff,3px 2px #fff,5px 2px #fff,1px 4px #fff,3px 4px #fff,5px 4px #fff,1px 6px #fff,3px 6px #fff,5px 6px #fff,1px 8px #fff,3px 8px #fff,5px 8px #fff,1px 10px #fff,3px 10px #fff,5px 10px #fff,1px 12px #fff,3px 12px #fff,5px 12px #fff,1px 14px #fff,3px 14px #fff,5px 14px #fff,1px 16px #fff,3px 16px #fff,5px 16px #fff,1px 18px #fff,3px 18px #fff,5px 18px #fff,1px 20px #fff,3px 20px #fff,5px 20px #fff,1px 22px #fff,3px 22px #fff,5px 22px #fff,1px 24px #fff,3px 24px #fff,5px 24px #fff,1px 26px #fff,3px 26px #fff,5px 26px #fff,1px 28px #fff,3px 28px #fff,5px 28px #fff;background:0 0}.psv-panel-content{width:100%;height:100%;box-sizing:border-box;color:#dcdcdc;font:16px sans-serif;overflow:auto}.psv-panel-content:not(.psv-panel-content--no-margin){padding:1em}.psv-panel-content--no-interaction{-webkit-touch-callout:none;-webkit-user-select:none;-khtml-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none;pointer-events:none}.psv-panel--open{transform:translate3d(0,0,0);opacity:1;transition-duration:.2s}.psv-panel--open .psv-panel-close-button,.psv-panel--open .psv-panel-resizer{display:block}.psv-tooltip{position:absolute;z-index:50;box-sizing:border-box;max-width:200px;background-color:rgba(61,61,61,.8);border-radius:4px;padding:.5em 1em;opacity:0;transition-property:opacity;transition-timing-function:ease-in-out;transition-duration:.1s}.psv-tooltip-content{color:#fff;font:14px sans-serif;text-shadow:0 1px #000}.psv-tooltip-arrow{position:absolute;height:0;width:0;border:7px solid transparent}.psv-tooltip--bottom-center{box-shadow:0 3px 0 rgba(90,90,90,.7);transform:translate3d(0,-5px,0);transition-property:opacity,transform}.psv-tooltip--bottom-center .psv-tooltip-arrow{border-bottom-color:rgba(61,61,61,.8)}.psv-tooltip--center-left{box-shadow:-3px 0 0 rgba(90,90,90,.7);transform:translate3d(5px,0,0);transition-property:opacity,transform}.psv-tooltip--center-left .psv-tooltip-arrow{border-left-color:rgba(61,61,61,.8)}.psv-tooltip--top-center{box-shadow:0 -3px 0 rgba(90,90,90,.7);transform:translate3d(0,5px,0);transition-property:opacity,transform}.psv-tooltip--top-center .psv-tooltip-arrow{border-top-color:rgba(61,61,61,.8)}.psv-tooltip--center-right{box-shadow:3px 0 0 rgba(90,90,90,.7);transform:translate3d(-5px,0,0);transition-property:opacity,transform}.psv-tooltip--center-right .psv-tooltip-arrow{border-right-color:rgba(61,61,61,.8)}.psv-tooltip--bottom-left{box-shadow:-3px 3px 0 rgba(90,90,90,.7);transform:translate3d(0,-5px,0);transition-property:opacity,transform}.psv-tooltip--bottom-left .psv-tooltip-arrow{border-bottom-color:rgba(61,61,61,.8)}.psv-tooltip--bottom-right{box-shadow:3px 3px 0 rgba(90,90,90,.7);transform:translate3d(0,-5px,0);transition-property:opacity,transform}.psv-tooltip--bottom-right .psv-tooltip-arrow{border-bottom-color:rgba(61,61,61,.8)}.psv-tooltip--top-left{box-shadow:-3px -3px 0 rgba(90,90,90,.7);transform:translate3d(0,5px,0);transition-property:opacity,transform}.psv-tooltip--top-left .psv-tooltip-arrow{border-top-color:rgba(61,61,61,.8)}.psv-tooltip--top-right{box-shadow:3px -3px 0 rgba(90,90,90,.7);transform:translate3d(0,5px,0);transition-property:opacity,transform}.psv-tooltip--top-right .psv-tooltip-arrow{border-top-color:rgba(61,61,61,.8)}.psv-tooltip--visible{transform:translate3d(0,0,0);opacity:1;transition-duration:.1s}.psv-notification{position:absolute;z-index:100;bottom:40px;display:flex;justify-content:center;box-sizing:border-box;width:100%;padding:0 40px;opacity:0;transition-property:opacity,bottom;transition-timing-function:ease-in-out;transition-duration:.1s}.psv-notification-content{max-width:50em;background-color:rgba(61,61,61,.8);border-radius:4px;padding:.5em 1em;font:14px sans-serif;color:#fff}.psv-notification--visible{opacity:100;bottom:80px}.psv-please-rotate{display:-webkit-box;display:-webkit-flex;display:-moz-flex;display:-ms-flexbox;display:flex;-webkit-flex-direction:column;-moz-flex-direction:column;-ms-flex-direction:column;flex-direction:column;-webkit-align-items:center;-moz-align-items:center;-ms-align-items:center;align-items:center;-webkit-justify-content:center;-moz-justify-content:center;-ms-justify-content:center;justify-content:center;-ms-flex-pack:center;position:absolute;z-index:101;top:0;left:0;bottom:0;right:0;background:radial-gradient(#fff 0,#fdfdfd 16%,#fbfbfb 33%,#f8f8f8 49%,#efefef 66%,#dfdfdf 82%,#bfbfbf 100%)}.psv-please-rotate-image{margin-bottom:4vh}.psv-please-rotate-image svg{width:50vw}@media screen and (orientation:landscape){.psv-please-rotate-image svg{width:30vw}}.psv-please-rotate-text{font:14px sans-serif;font-size:30px}.psv-please-rotate-subtext{font:14px sans-serif;font-size:20px;opacity:.8} \ No newline at end of file +.psv-container{width:100%;height:100%;margin:0;padding:0;position:relative;background:radial-gradient(#fff 0,#fdfdfd 16%,#fbfbfb 33%,#f8f8f8 49%,#efefef 66%,#dfdfdf 82%,#bfbfbf 100%);overflow:hidden}.psv-canvas-container{position:absolute;top:0;left:0;z-index:0;-webkit-transition:opacity linear .1s;transition:opacity linear .1s}.psv-canvas{display:block}.psv-loader-container{display:-webkit-box;display:-ms-flexbox;display:flex;-webkit-box-align:center;-ms-flex-align:center;align-items:center;-webkit-box-pack:center;-ms-flex-pack:center;justify-content:center;position:absolute;top:0;left:0;width:100%;height:100%;z-index:100}.psv-loader{position:relative;text-align:center;color:rgba(61,61,61,.7);width:150px;height:150px;border:10px solid transparent}.psv-loader::before{content:'';display:inline-block;height:100%;vertical-align:middle}.psv-loader,.psv-loader-image,.psv-loader-text{display:inline-block;vertical-align:middle}.psv-loader-canvas{position:absolute;top:0;left:0;width:100%;height:100%}.psv-loader-text{font:14px sans-serif}.psv-navbar{display:-webkit-box;display:-ms-flexbox;display:flex;position:absolute;z-index:90;bottom:-40px;left:0;width:100%;height:40px;background:rgba(61,61,61,.5);-webkit-transition:bottom ease-in-out .1s;transition:bottom ease-in-out .1s}.psv-navbar--open{bottom:0}.psv-navbar,.psv-navbar *{-webkit-box-sizing:content-box;box-sizing:content-box}.psv-caption{-webkit-box-flex:1;-ms-flex:1 1 100%;flex:1 1 100%;color:rgba(255,255,255,.7);overflow:hidden;text-align:center}.psv-caption-icon{height:20px;width:20px;cursor:pointer}.psv-caption-icon *{fill:rgba(255,255,255,.7)}.psv-caption-content{display:inline-block;padding:10px;font:16px sans-serif;white-space:nowrap}.psv-button{-webkit-box-flex:0;-ms-flex:0 0 auto;flex:0 0 auto;padding:10px;position:relative;cursor:pointer;height:20px;width:20px;background:0 0;color:rgba(255,255,255,.7)}.psv-button--active{background:rgba(255,255,255,.2)}.psv-button--disabled{pointer-events:none;opacity:.5}.psv-button .psv-button-svg{width:100%;-webkit-transform:scale(1);transform:scale(1);-webkit-transition:-webkit-transform .2s ease;transition:-webkit-transform .2s ease;transition:transform .2s ease;transition:transform .2s ease,-webkit-transform .2s ease}.psv-button .psv-button-svg *{fill:rgba(255,255,255,.7)}.psv-button--hover-scale:not(.psv-button--disabled):hover .psv-button-svg{-webkit-transform:scale(1.2);transform:scale(1.2)}.psv-hud{-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none;position:absolute;z-index:10;width:100%;height:100%}.psv-hud-svg-container{position:absolute;top:0;left:0;width:100%;height:100%;z-index:20}.psv-marker{cursor:pointer;display:none}.psv-marker--normal{position:absolute;top:0;left:0;z-index:30;background-size:contain;background-repeat:no-repeat}.psv-marker--transparent{display:block;opacity:0}.psv-marker--visible{display:block}.psv-panel{position:absolute;z-index:90;right:0;height:100%;width:400px;max-width:calc(100% - 24px);background:rgba(10,10,10,.7);-webkit-transform:translate3d(100%,0,0);transform:translate3d(100%,0,0);opacity:0;-webkit-transition-property:opacity,-webkit-transform;transition-property:opacity,-webkit-transform;transition-property:opacity,transform;transition-property:opacity,transform,-webkit-transform;-webkit-transition-timing-function:ease-in-out;transition-timing-function:ease-in-out;-webkit-transition-duration:.1s;transition-duration:.1s;cursor:default;margin-left:9px}.psv-container--has-navbar .psv-panel{height:calc(100% - 40px)}.psv-panel-close-button{display:none;position:absolute;top:0;left:-24px;width:24px;height:24px;background:rgba(0,0,0,.9)}.psv-panel-close-button::after,.psv-panel-close-button::before{content:'';position:absolute;top:50%;left:4px;width:15px;height:1px;background-color:#fff;-webkit-transition:.2s ease-in-out;transition:.2s ease-in-out;-webkit-transition-property:width,left,-webkit-transform;transition-property:width,left,-webkit-transform;transition-property:width,left,transform;transition-property:width,left,transform,-webkit-transform}.psv-panel-close-button::before{-webkit-transform:rotate(45deg);transform:rotate(45deg)}.psv-panel-close-button::after{-webkit-transform:rotate(-45deg);transform:rotate(-45deg)}.psv-panel-close-button:hover::after,.psv-panel-close-button:hover::before{left:0;width:23px}.psv-panel-close-button:hover::before{-webkit-transform:rotate(135deg);transform:rotate(135deg)}.psv-panel-close-button:hover::after{-webkit-transform:rotate(45deg);transform:rotate(45deg)}.psv-panel-resizer{display:none;position:absolute;top:0;left:-9px;width:9px;height:100%;background-color:rgba(0,0,0,.9);cursor:col-resize}.psv-panel-resizer::before{content:'';position:absolute;top:50%;left:1px;margin-top:-14.5px;width:1px;height:1px;-webkit-box-shadow:1px 0 #fff,3px 0 #fff,5px 0 #fff,1px 2px #fff,3px 2px #fff,5px 2px #fff,1px 4px #fff,3px 4px #fff,5px 4px #fff,1px 6px #fff,3px 6px #fff,5px 6px #fff,1px 8px #fff,3px 8px #fff,5px 8px #fff,1px 10px #fff,3px 10px #fff,5px 10px #fff,1px 12px #fff,3px 12px #fff,5px 12px #fff,1px 14px #fff,3px 14px #fff,5px 14px #fff,1px 16px #fff,3px 16px #fff,5px 16px #fff,1px 18px #fff,3px 18px #fff,5px 18px #fff,1px 20px #fff,3px 20px #fff,5px 20px #fff,1px 22px #fff,3px 22px #fff,5px 22px #fff,1px 24px #fff,3px 24px #fff,5px 24px #fff,1px 26px #fff,3px 26px #fff,5px 26px #fff,1px 28px #fff,3px 28px #fff,5px 28px #fff;box-shadow:1px 0 #fff,3px 0 #fff,5px 0 #fff,1px 2px #fff,3px 2px #fff,5px 2px #fff,1px 4px #fff,3px 4px #fff,5px 4px #fff,1px 6px #fff,3px 6px #fff,5px 6px #fff,1px 8px #fff,3px 8px #fff,5px 8px #fff,1px 10px #fff,3px 10px #fff,5px 10px #fff,1px 12px #fff,3px 12px #fff,5px 12px #fff,1px 14px #fff,3px 14px #fff,5px 14px #fff,1px 16px #fff,3px 16px #fff,5px 16px #fff,1px 18px #fff,3px 18px #fff,5px 18px #fff,1px 20px #fff,3px 20px #fff,5px 20px #fff,1px 22px #fff,3px 22px #fff,5px 22px #fff,1px 24px #fff,3px 24px #fff,5px 24px #fff,1px 26px #fff,3px 26px #fff,5px 26px #fff,1px 28px #fff,3px 28px #fff,5px 28px #fff;background:0 0}.psv-panel-content{width:100%;height:100%;-webkit-box-sizing:border-box;box-sizing:border-box;color:#dcdcdc;font:16px sans-serif;overflow:auto}.psv-panel-content:not(.psv-panel-content--no-margin){padding:1em}.psv-panel-content--no-interaction{-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none;pointer-events:none}.psv-panel--open{-webkit-transform:translate3d(0,0,0);transform:translate3d(0,0,0);opacity:1;-webkit-transition-duration:.2s;transition-duration:.2s}.psv-panel--open .psv-panel-close-button,.psv-panel--open .psv-panel-resizer{display:block}.psv-tooltip{position:absolute;z-index:50;-webkit-box-sizing:border-box;box-sizing:border-box;max-width:200px;background-color:rgba(61,61,61,.8);border-radius:4px;padding:.5em 1em;opacity:0;-webkit-transition-property:opacity;transition-property:opacity;-webkit-transition-timing-function:ease-in-out;transition-timing-function:ease-in-out;-webkit-transition-duration:.1s;transition-duration:.1s}.psv-tooltip-content{color:#fff;font:14px sans-serif;text-shadow:0 1px #000}.psv-tooltip-arrow{position:absolute;height:0;width:0;border:7px solid transparent}.psv-tooltip--bottom-center{-webkit-box-shadow:0 3px 0 rgba(90,90,90,.7);box-shadow:0 3px 0 rgba(90,90,90,.7);-webkit-transform:translate3d(0,-5px,0);transform:translate3d(0,-5px,0);-webkit-transition-property:opacity,-webkit-transform;transition-property:opacity,-webkit-transform;transition-property:opacity,transform;transition-property:opacity,transform,-webkit-transform}.psv-tooltip--bottom-center .psv-tooltip-arrow{border-bottom-color:rgba(61,61,61,.8)}.psv-tooltip--center-left{-webkit-box-shadow:-3px 0 0 rgba(90,90,90,.7);box-shadow:-3px 0 0 rgba(90,90,90,.7);-webkit-transform:translate3d(5px,0,0);transform:translate3d(5px,0,0);-webkit-transition-property:opacity,-webkit-transform;transition-property:opacity,-webkit-transform;transition-property:opacity,transform;transition-property:opacity,transform,-webkit-transform}.psv-tooltip--center-left .psv-tooltip-arrow{border-left-color:rgba(61,61,61,.8)}.psv-tooltip--top-center{-webkit-box-shadow:0 -3px 0 rgba(90,90,90,.7);box-shadow:0 -3px 0 rgba(90,90,90,.7);-webkit-transform:translate3d(0,5px,0);transform:translate3d(0,5px,0);-webkit-transition-property:opacity,-webkit-transform;transition-property:opacity,-webkit-transform;transition-property:opacity,transform;transition-property:opacity,transform,-webkit-transform}.psv-tooltip--top-center .psv-tooltip-arrow{border-top-color:rgba(61,61,61,.8)}.psv-tooltip--center-right{-webkit-box-shadow:3px 0 0 rgba(90,90,90,.7);box-shadow:3px 0 0 rgba(90,90,90,.7);-webkit-transform:translate3d(-5px,0,0);transform:translate3d(-5px,0,0);-webkit-transition-property:opacity,-webkit-transform;transition-property:opacity,-webkit-transform;transition-property:opacity,transform;transition-property:opacity,transform,-webkit-transform}.psv-tooltip--center-right .psv-tooltip-arrow{border-right-color:rgba(61,61,61,.8)}.psv-tooltip--bottom-left{-webkit-box-shadow:-3px 3px 0 rgba(90,90,90,.7);box-shadow:-3px 3px 0 rgba(90,90,90,.7);-webkit-transform:translate3d(0,-5px,0);transform:translate3d(0,-5px,0);-webkit-transition-property:opacity,-webkit-transform;transition-property:opacity,-webkit-transform;transition-property:opacity,transform;transition-property:opacity,transform,-webkit-transform}.psv-tooltip--bottom-left .psv-tooltip-arrow{border-bottom-color:rgba(61,61,61,.8)}.psv-tooltip--bottom-right{-webkit-box-shadow:3px 3px 0 rgba(90,90,90,.7);box-shadow:3px 3px 0 rgba(90,90,90,.7);-webkit-transform:translate3d(0,-5px,0);transform:translate3d(0,-5px,0);-webkit-transition-property:opacity,-webkit-transform;transition-property:opacity,-webkit-transform;transition-property:opacity,transform;transition-property:opacity,transform,-webkit-transform}.psv-tooltip--bottom-right .psv-tooltip-arrow{border-bottom-color:rgba(61,61,61,.8)}.psv-tooltip--top-left{-webkit-box-shadow:-3px -3px 0 rgba(90,90,90,.7);box-shadow:-3px -3px 0 rgba(90,90,90,.7);-webkit-transform:translate3d(0,5px,0);transform:translate3d(0,5px,0);-webkit-transition-property:opacity,-webkit-transform;transition-property:opacity,-webkit-transform;transition-property:opacity,transform;transition-property:opacity,transform,-webkit-transform}.psv-tooltip--top-left .psv-tooltip-arrow{border-top-color:rgba(61,61,61,.8)}.psv-tooltip--top-right{-webkit-box-shadow:3px -3px 0 rgba(90,90,90,.7);box-shadow:3px -3px 0 rgba(90,90,90,.7);-webkit-transform:translate3d(0,5px,0);transform:translate3d(0,5px,0);-webkit-transition-property:opacity,-webkit-transform;transition-property:opacity,-webkit-transform;transition-property:opacity,transform;transition-property:opacity,transform,-webkit-transform}.psv-tooltip--top-right .psv-tooltip-arrow{border-top-color:rgba(61,61,61,.8)}.psv-tooltip--visible{-webkit-transform:translate3d(0,0,0);transform:translate3d(0,0,0);opacity:1;-webkit-transition-duration:.1s;transition-duration:.1s}.psv-notification{position:absolute;z-index:100;bottom:40px;display:-webkit-box;display:-ms-flexbox;display:flex;-webkit-box-pack:center;-ms-flex-pack:center;justify-content:center;-webkit-box-sizing:border-box;box-sizing:border-box;width:100%;padding:0 2em;opacity:0;-webkit-transition-property:opacity,bottom;transition-property:opacity,bottom;-webkit-transition-timing-function:ease-in-out;transition-timing-function:ease-in-out;-webkit-transition-duration:.2s;transition-duration:.2s}.psv-notification-content{max-width:50em;background-color:rgba(61,61,61,.8);border-radius:4px;padding:.5em 1em;font:14px sans-serif;color:#fff}.psv-notification--visible{opacity:100;bottom:80px}.psv-overlay{display:-webkit-box;display:-ms-flexbox;display:flex;-webkit-box-orient:vertical;-webkit-box-direction:normal;-ms-flex-direction:column;flex-direction:column;-webkit-box-align:center;-ms-flex-align:center;align-items:center;-webkit-box-pack:center;-ms-flex-pack:center;justify-content:center;position:absolute;z-index:110;top:0;left:0;bottom:0;right:0;background:radial-gradient(#fff 0,#fdfdfd 16%,#fbfbfb 33%,#f8f8f8 49%,#efefef 66%,#dfdfdf 82%,#bfbfbf 100%);opacity:.8}.psv-overlay-image{margin-bottom:4vh}.psv-overlay-image svg{width:50vw}@media screen and (orientation:landscape){.psv-overlay-image svg{width:25vw}}.psv-overlay-text{font:30px sans-serif;text-align:center}.psv-overlay-subtext{font:20px sans-serif;opacity:.8;text-align:center}.psv-markers-list-title{font:24px sans-serif;margin:1em 0;text-align:center;text-shadow:2px 1px #000}.psv-markers-list{list-style:none;margin:0;padding:0;overflow:hidden}.psv-markers-list-item{clear:both;min-height:20px;padding:.5em 1em;cursor:pointer;-webkit-transform:translateX(0);transform:translateX(0);-webkit-transition:-webkit-transform .3s ease-in-out;transition:-webkit-transform .3s ease-in-out;transition:transform .3s ease-in-out;transition:transform .3s ease-in-out,-webkit-transform .3s ease-in-out}.psv-markers-list-item::before{content:'';position:absolute;top:0;left:0;height:100%;width:10px;margin-left:-10px}.psv-markers-list-item:nth-child(odd),.psv-markers-list-item:nth-child(odd)::before{background:rgba(255,255,255,.1)}.psv-markers-list-item:nth-child(even),.psv-markers-list-item:nth-child(even)::before{background:0 0}.psv-markers-list-item:hover{-webkit-transform:translateX(10px);transform:translateX(10px);-webkit-transition:-webkit-transform .1s ease-in-out;transition:-webkit-transform .1s ease-in-out;transition:transform .1s ease-in-out;transition:transform .1s ease-in-out,-webkit-transform .1s ease-in-out}.psv-markers-list-image{float:left;width:20px}.psv-markers-list-name{margin:0;padding:0}.psv-markers-list-image+.psv-markers-list-name{padding-left:calc(20px + .5em)}.psv-autorotate-button{width:25px;height:25px;padding:7.5px}.psv-zoom-button{cursor:default;width:128px}.psv-zoom-button-minus,.psv-zoom-button-plus{float:left;position:relative;cursor:pointer;width:16px;height:16px}.psv-zoom-button-minus .psv-button-svg,.psv-zoom-button-plus .psv-button-svg{position:relative;top:20%}.psv-zoom-button-range{float:left;padding:9.5px 8px}.psv-zoom-button-line{position:relative;cursor:pointer;width:80px;height:1px;background:rgba(255,255,255,.7);-webkit-transition:all .3s ease;transition:all .3s ease}.psv-zoom-button-handle{position:absolute;border-radius:50%;top:-3px;width:7px;height:7px;background:rgba(255,255,255,.7);-webkit-transform:scale(1);transform:scale(1);-webkit-transition:-webkit-transform .3s ease;transition:-webkit-transform .3s ease;transition:transform .3s ease;transition:transform .3s ease,-webkit-transform .3s ease}.psv-zoom-button:not(.psv-button--disabled):hover .psv-zoom-button-line{-webkit-box-shadow:0 0 2px rgba(255,255,255,.7);box-shadow:0 0 2px rgba(255,255,255,.7)}.psv-zoom-button:not(.psv-button--disabled):hover .psv-zoom-button-handle{-webkit-transform:scale(1.3);transform:scale(1.3)}@media (max-width:600px){.psv-zoom-button{width:auto;padding:0}.psv-zoom-button-range{display:none}.psv-zoom-button-minus,.psv-zoom-button-plus{width:20px;height:20px;padding:10px}.psv-zoom-button-minus .psv-button-svg,.psv-zoom-button-plus .psv-button-svg{top:0}}@media (max-width:600px){.psv-is-touch .psv-zoom-button{display:none}} \ No newline at end of file diff --git a/dist/photo-sphere-viewer.min.js b/dist/photo-sphere-viewer.min.js index 2268c1b64..ddc77745f 100644 --- a/dist/photo-sphere-viewer.min.js +++ b/dist/photo-sphere-viewer.min.js @@ -1,7 +1,7 @@ /*! - * Photo Sphere Viewer 3.4.0 + * Photo Sphere Viewer 3.4.1 * Copyright (c) 2014-2015 Jérémy Heleine * Copyright (c) 2015-2018 Damien "Mistic" Sorel * Licensed under MIT (https://opensource.org/licenses/MIT) */ -!function(t,e){"function"==typeof define&&define.amd?define(["three","d.js","uevent","dot/doT"],e):"object"==typeof module&&module.exports?module.exports=e(require("three"),require("d.js"),require("uevent"),require("dot/doT")):t.PhotoSphereViewer=e(t.THREE,t.D,t.uEvent,t.doT)}(this,function(t,e,i,o){"use strict";function n(e){if(!(this instanceof n))return new n(e);if(n.SYSTEM.loaded||n._loadSystem(),this.config=x.clone(n.DEFAULTS),x.deepmerge(this.config,e),!e.container)throw new E("No value given for container.");if(!n.SYSTEM.isCanvasSupported)throw new E("Canvas is not supported.");if(!(n.SYSTEM.isWebGLSupported&&this.config.webgl||x.checkTHREE("CanvasRenderer","Projector")))throw new E("Missing Three.js components: CanvasRenderer, Projector. Get them from three.js-examples package.");if(this.config.longitude_range&&2!==this.config.longitude_range.length&&(this.config.longitude_range=null,console.warn("PhotoSphereViewer: longitude_range must have exactly two elements.")),this.config.latitude_range?2!==this.config.latitude_range.length?(this.config.latitude_range=null,console.warn("PhotoSphereViewer: latitude_range must have exactly two elements.")):this.config.latitude_range[0]>this.config.latitude_range[1]&&(this.config.latitude_range=[this.config.latitude_range[1],this.config.latitude_range[0]],console.warn("PhotoSphereViewer: latitude_range values must be ordered.")):void 0===this.config.tilt_up_max&&void 0===this.config.tilt_down_max||(this.config.latitude_range=[void 0!==this.config.tilt_down_max?this.config.tilt_down_max-Math.PI/4:-x.HalfPI,void 0!==this.config.tilt_up_max?this.config.tilt_up_max+Math.PI/4:x.HalfPI],console.warn("PhotoSphereViewer: tilt_up_max and tilt_down_max are deprecated, use latitude_range instead.")),this.config.max_fov"),r=t.substring(e,s);if(-1===e||-1===s||-1===r.indexOf("GPano:"))i.resolve(null);else{var a={full_width:parseInt(x.getXMPValue(r,"FullPanoWidthPixels")),full_height:parseInt(x.getXMPValue(r,"FullPanoHeightPixels")),cropped_width:parseInt(x.getXMPValue(r,"CroppedAreaImageWidthPixels")),cropped_height:parseInt(x.getXMPValue(r,"CroppedAreaImageHeightPixels")),cropped_x:parseInt(x.getXMPValue(r,"CroppedAreaLeftPixels")),cropped_y:parseInt(x.getXMPValue(r,"CroppedAreaTopPixels"))};a.full_width&&a.full_height&&a.cropped_width&&a.cropped_height?i.resolve(a):(console.warn("PhotoSphereViewer: invalid XMP data"),i.resolve(null))}}else 3===o.readyState&&this.loader.setProgress(n+=10)}.bind(this),o.onprogress=function(t){if(t.lengthComputable){var e=parseInt(t.loaded/t.total*100);e>n&&(n=e,this.loader.setProgress(n))}}.bind(this),o.onerror=function(){throw this.container.textContent="Cannot load image",new E("Cannot load image")}.bind(this),o.open("GET",t,!0),o.send(null),i.promise},n.prototype._loadTexture=function(t){var e=[];if(Array.isArray(t)){if(6!==t.length)throw new E("Must provide exactly 6 image paths when using cubemap.");for(var i=0;i<6;i++)e[i]=t[n.CUBE_MAP[i]];t=e}else if("object"==typeof t){if(!n.CUBE_HASHMAP.every(function(e){return!!t[e]}))throw new E("Must provide exactly left, front, right, back, top, bottom when using cubemap.");n.CUBE_HASHMAP.forEach(function(i,o){e[o]=t[i]}),t=e}if(Array.isArray(t)){if(!1===this.prop.isCubemap)throw new E("The viewer was initialized with an equirectangular panorama, cannot switch to cubemap.");return this.config.fisheye&&console.warn("PhotoSphereViewer: fisheye effect with cubemap texture can generate distorsions."),this.config.cache_texture===n.DEFAULTS.cache_texture&&(this.config.cache_texture*=6),this.prop.isCubemap=!0,this._loadCubemapTexture(t)}if(!0===this.prop.isCubemap)throw new E("The viewer was initialized with an cubemap, cannot switch to equirectangular panorama.");return this.prop.isCubemap=!1,this._loadEquirectangularTexture(t)},n.prototype._loadEquirectangularTexture=function(i){if(this.config.cache_texture){var o=this.getPanoramaCache(i);if(o)return this.prop.pano_data=o.pano_data,e.resolved(o.image)}return this._loadXMP(i).then(function(o){var s=e(),r=new t.ImageLoader,a=o?100:0;this.config.with_credentials?r.setCrossOrigin("use-credentials"):r.setCrossOrigin("anonymous");return r.load(i,function(e){a=100,this.loader.setProgress(a),this.trigger("panorama-load-progress",i,a),!o&&this.config.pano_data&&(o=x.clone(this.config.pano_data)),o||(o={full_width:e.width,full_height:e.height,cropped_width:e.width,cropped_height:e.height,cropped_x:0,cropped_y:0}),this.prop.pano_data=o;var r,h=Math.min(o.full_width,n.SYSTEM.maxTextureWidth)/o.full_width;if(1!==h||o.cropped_width!==o.full_width||o.cropped_height!==o.full_height){var p=x.clone(o);p.full_width*=h,p.full_height*=h,p.cropped_width*=h,p.cropped_height*=h,p.cropped_x*=h,p.cropped_y*=h,e.width=p.cropped_width,e.height=p.cropped_height;var c=document.createElement("canvas");c.width=p.full_width,c.height=p.full_height,c.getContext("2d").drawImage(e,p.cropped_x,p.cropped_y,p.cropped_width,p.cropped_height),r=new t.Texture(c)}else r=new t.Texture(e);r.needsUpdate=!0,r.minFilter=t.LinearFilter,r.generateMipmaps=!1,this.config.cache_texture&&this._putPanoramaCache({panorama:i,image:r,pano_data:o}),s.resolve(r)}.bind(this),function(t){if(t.lengthComputable){var e=parseInt(t.loaded/t.total*100);e>a&&(a=e,this.loader.setProgress(a),this.trigger("panorama-load-progress",i,a))}}.bind(this),function(t){throw this.container.textContent="Cannot load image",s.reject(t),new E("Cannot load image")}.bind(this)),s.promise}.bind(this))},n.prototype._loadCubemapTexture=function(i){var o=e(),s=new t.ImageLoader,r=[0,0,0,0,0,0],a=[],h=0;this.config.with_credentials?s.setCrossOrigin("use-credentials"):s.setCrossOrigin("anonymous");for(var p=function(e,s){h++,r[e]=100,this.loader.setProgress(x.sum(r)/6),this.trigger("panorama-load-progress",i[e],r[e]);var p=Math.min(s.width,n.SYSTEM.maxTextureWidth/2)/s.width;if(1!==p){var c=document.createElement("canvas");c.width=s.width*p,c.height=s.height*p;c.getContext("2d").drawImage(s,0,0,c.width,c.height),a[e]=new t.Texture(c)}else a[e]=new t.Texture(s);this.config.cache_texture&&this._putPanoramaCache({panorama:i[e],image:a[e]}),6===h&&(a.forEach(function(e){e.needsUpdate=!0,e.minFilter=t.LinearFilter,e.generateMipmaps=!1}),o.resolve(a))},c=function(t,e){if(e.lengthComputable){var o=parseInt(e.loaded/e.total*100);o>r[t]&&(r[t]=o,this.loader.setProgress(x.sum(r)/6),this.trigger("panorama-load-progress",i[t],r[t]))}},l=function(t,e){throw this.container.textContent="Cannot load image",o.reject(e),new E("Cannot load image "+t)},u=0;u<6;u++){if(this.config.cache_texture){var d=this.getPanoramaCache(i[u]);if(d){h++,r[u]=100,a[u]=d.image;continue}}s.load(i[u],p.bind(this,u),c.bind(this,u),l.bind(this,u))}return 6===h&&o.resolve(a),o.promise},n.prototype._setTexture=function(t){if(this.scene||this._createScene(),this.prop.isCubemap)for(var e=0;e<6;e++)this.mesh.material[e].map&&this.mesh.material[e].map.dispose(),this.mesh.material[e].map=t[e];else this.mesh.material.map&&this.mesh.material.map.dispose(),this.mesh.material.map=t;this.trigger("panorama-loaded"),this._render()},n.prototype._createScene=function(){this.raycaster=new t.Raycaster,this.renderer=n.SYSTEM.isWebGLSupported&&this.config.webgl?new t.WebGLRenderer:new t.CanvasRenderer,this.renderer.setSize(this.prop.size.width,this.prop.size.height),this.renderer.setPixelRatio(n.SYSTEM.pixelRatio);var e=n.SPHERE_RADIUS;this.prop.isCubemap&&(e*=Math.sqrt(3)),this.config.fisheye&&(e+=n.SPHERE_RADIUS),this.camera=new t.PerspectiveCamera(this.config.default_fov,this.prop.size.width/this.prop.size.height,1,e),this.camera.position.set(0,0,0),this.scene=new t.Scene,this.scene.add(this.camera),this.prop.isCubemap?this.mesh=this._createCubemap():this.mesh=this._createSphere(),this.scene.add(this.mesh),this.canvas_container=document.createElement("div"),this.canvas_container.className="psv-canvas-container",this.renderer.domElement.className="psv-canvas",this.container.appendChild(this.canvas_container),this.canvas_container.appendChild(this.renderer.domElement)},n.prototype._createSphere=function(e){e=e||1;var i=new t.SphereGeometry(n.SPHERE_RADIUS*e,n.SPHERE_VERTICES,n.SPHERE_VERTICES,-x.HalfPI),o=new t.MeshBasicMaterial({side:t.DoubleSide,overdraw:n.SYSTEM.isWebGLSupported&&this.config.webgl?0:1}),s=new t.Mesh(i,o);return s.scale.x=-1,s.rotation.x=this.config.sphere_correction.tilt,s.rotation.y=this.config.sphere_correction.pan,s.rotation.z=this.config.sphere_correction.roll,s},n.prototype._createCubemap=function(e){e=e||1;for(var i=new t.BoxGeometry(2*n.SPHERE_RADIUS*e,2*n.SPHERE_RADIUS*e,2*n.SPHERE_RADIUS*e,n.CUBE_VERTICES,n.CUBE_VERTICES,n.CUBE_VERTICES),o=[],s=0;s<6;s++)o.push(new t.MeshBasicMaterial({side:t.BackSide,overdraw:n.SYSTEM.isWebGLSupported&&this.config.webgl?0:1}));var r=new t.Mesh(i,o);return r.position.x-=n.SPHERE_RADIUS*e,r.position.y-=n.SPHERE_RADIUS*e,r.position.z-=n.SPHERE_RADIUS*e,r.applyMatrix((new t.Matrix4).makeScale(1,1,-1)),r},n.prototype._transition=function(e,i){var o;if(this.prop.isCubemap?(i&&(console.warn("PhotoSphereViewer: cannot perform cubemap transition to different position."),i=void 0),(o=this._createCubemap(.9)).material.forEach(function(t,i){t.map=e[i],t.transparent=!0,t.opacity=0})):((o=this._createSphere(.9)).material.map=e,o.material.transparent=!0,o.material.opacity=0),i){o.rotateY(i.longitude-this.prop.position.longitude);var n=new t.Vector3(0,1,0).cross(this.camera.getWorldDirection()).normalize(),s=(new t.Quaternion).setFromAxisAngle(n,i.latitude-this.prop.position.latitude);o.quaternion.multiplyQuaternions(s,o.quaternion),(this.config.latitude_range||this.config.longitude_range)&&(this.config.longitude_range=this.config.latitude_range=null,console.warn("PhotoSphereViewer: trying to perform transition with longitude_range and/or latitude_range, ranges cleared."))}return this.scene.add(o),this.needsUpdate(),x.animation({properties:{opacity:{start:0,end:1}},duration:this.config.transition.duration,easing:"outCubic",onTick:function(t){if(this.prop.isCubemap)for(var e=0;e<6;e++)o.material[e].opacity=t.opacity;else o.material.opacity=t.opacity;this.needsUpdate()}.bind(this)}).then(function(){this._setTexture(e),this.scene.remove(o),o.geometry.dispose(),o.geometry=null,i&&this.rotate(i)}.bind(this))},n.prototype._reverseAutorotate=function(){var t=this,e=-this.config.anim_speed,i=this.config.longitude_range;this.config.longitude_range=null,x.animation({properties:{speed:{start:this.config.anim_speed,end:0}},duration:300,easing:"inSine",onTick:function(e){t.config.anim_speed=e.speed}}).then(function(){return x.animation({properties:{speed:{start:0,end:e}},duration:300,easing:"outSine",onTick:function(e){t.config.anim_speed=e.speed}})}).then(function(){t.config.longitude_range=i,t.config.anim_speed=e})},n.prototype._putPanoramaCache=function(t){if(!this.config.cache_texture)throw new E("Cannot add panorama to cache, cache_texture is disabled");var e=this.getPanoramaCache(t.panorama);e?(e.image=t.image,e.pano_data=t.pano_data):(this.prop.cache=this.prop.cache.slice(0,this.config.cache_texture-1),this.prop.cache.unshift(t)),this.trigger("panorama-cached",t.panorama)},n.prototype._stopAll=function(){this.stopAutorotate(),this.stopAnimation(),this.stopGyroscopeControl(),this.stopStereoView()},n.MOVE_THRESHOLD=4,n.ANGLE_THRESHOLD=.003,n.DBLCLICK_DELAY=300,n.INERTIA_WINDOW=300,n.SPHERE_RADIUS=100,n.SPHERE_VERTICES=64,n.CUBE_VERTICES=8,n.CUBE_MAP=[0,2,4,5,3,1],n.CUBE_HASHMAP=["left","right","top","bottom","back","front"],n.KEYMAP={33:"PageUp",34:"PageDown",37:"ArrowLeft",38:"ArrowUp",39:"ArrowRight",40:"ArrowDown",107:"+",109:"-"},n.SYSTEM={loaded:!1,pixelRatio:1,isWebGLSupported:!1,isCanvasSupported:!1,deviceOrientationSupported:null,maxTextureWidth:0,mouseWheelEvent:null,fullscreenEvent:null},n.ICONS={},n.DEFAULTS={panorama:null,container:null,caption:null,usexmpdata:!0,pano_data:null,webgl:!0,min_fov:30,max_fov:90,default_fov:null,default_long:0,default_lat:0,sphere_correction:{pan:0,tilt:0,roll:0},longitude_range:null,latitude_range:null,move_speed:1,zoom_speed:2,time_anim:2e3,anim_speed:"2rpm",anim_lat:null,fisheye:!1,navbar:["autorotate","zoom","download","markers","caption","gyroscope","stereo","fullscreen"],tooltip:{offset:5,arrow_size:7,delay:100},lang:{autorotate:"Automatic rotation",zoom:"Zoom",zoomOut:"Zoom out",zoomIn:"Zoom in",download:"Download",fullscreen:"Fullscreen",markers:"Markers",gyroscope:"Gyroscope",stereo:"Stereo view",stereo_notification:"Click anywhere to exit stereo view.",please_rotate:["Please rotate your device","(or tap to continue)"]},mousewheel:!0,mousewheel_factor:1,mousemove:!0,mousemove_hover:!1,keyboard:!0,move_inertia:!0,click_event_on_marker:!1,transition:{duration:1500,loader:!0},loading_img:null,loading_txt:"Loading...",size:null,cache_texture:0,templates:{},markers:[],with_credentials:!1},n.TEMPLATES={markersList:'

{{= it.config.lang.markers }}

    {{~ it.markers: marker }}
  • {{? marker.image }}{{?}}

    {{? marker.tooltip }}{{= marker.tooltip.content }}{{?? marker.html }}{{= marker.html }}{{??}}{{= marker.id }}{{?}}

  • {{~}}
'},n.prototype._bindEvents=function(){window.addEventListener("resize",this),this.config.mousemove&&(this.hud.container.style.cursor="move",this.config.mousemove_hover?(this.hud.container.addEventListener("mouseenter",this),this.hud.container.addEventListener("mouseleave",this)):(this.hud.container.addEventListener("mousedown",this),window.addEventListener("mouseup",this)),this.hud.container.addEventListener("touchstart",this),window.addEventListener("touchend",this),this.hud.container.addEventListener("mousemove",this),this.hud.container.addEventListener("touchmove",this)),n.SYSTEM.fullscreenEvent&&document.addEventListener(n.SYSTEM.fullscreenEvent,this),this.config.mousewheel&&this.hud.container.addEventListener(n.SYSTEM.mouseWheelEvent,this),this.on("_side-reached",function(t){this.isAutorotateEnabled()&&("left"!==t&&"right"!==t||this._reverseAutorotate())})},n.prototype._unbindEvents=function(){window.removeEventListener("resize",this),this.config.mousemove&&(this.hud.container.removeEventListener("mousedown",this),this.hud.container.removeEventListener("mouseenter",this),this.hud.container.removeEventListener("touchstart",this),window.removeEventListener("mouseup",this),window.removeEventListener("touchend",this),this.hud.container.removeEventListener("mouseleave",this),this.hud.container.removeEventListener("mousemove",this),this.hud.container.removeEventListener("touchmove",this)),n.SYSTEM.fullscreenEvent&&document.removeEventListener(n.SYSTEM.fullscreenEvent,this),this.config.mousewheel&&this.hud.container.removeEventListener(n.SYSTEM.mouseWheelEvent,this),this.off("_side-reached")},n.prototype.handleEvent=function(t){switch(t.type){case"resize":x.throttle(this._onResize(),50);break;case"keydown":this._onKeyDown(t);break;case"mousedown":case"mouseenter":this._onMouseDown(t);break;case"touchstart":this._onTouchStart(t);break;case"mouseup":case"mouseleave":this._onMouseUp(t);break;case"touchend":this._onTouchEnd(t);break;case"mousemove":this._onMouseMove(t);break;case"touchmove":this._onTouchMove(t);break;case n.SYSTEM.fullscreenEvent:this._fullscreenToggled();break;case n.SYSTEM.mouseWheelEvent:this._onMouseWheel(t)}},n.prototype._onResize=function(){this.container.clientWidth===this.prop.size.width&&this.container.clientHeight===this.prop.size.height||(this.prop.size.width=parseInt(this.container.clientWidth),this.prop.size.height=parseInt(this.container.clientHeight),this.prop.aspect=this.prop.size.width/this.prop.size.height,this.needsUpdate(),this.renderer&&(this.stereoEffect||this.renderer).setSize(this.prop.size.width,this.prop.size.height),this.trigger("size-updated",this.getSize()))},n.prototype._onKeyDown=function(t){var e=0,i=0,o=0;switch(t.key||n.KEYMAP[t.keyCode||t.which]){case"ArrowUp":i=.01;break;case"ArrowDown":i=-.01;break;case"ArrowRight":e=.01;break;case"ArrowLeft":e=-.01;break;case"PageUp":case"+":o=1;break;case"PageDown":case"-":o=-1}0!==o?this.zoom(this.prop.zoom_lvl+o*this.config.zoom_speed):0===i&&0===e||this.rotate({longitude:this.prop.position.longitude+e*this.prop.move_speed*this.prop.hFov,latitude:this.prop.position.latitude+i*this.prop.move_speed*this.prop.vFov})},n.prototype._onMouseDown=function(t){this._startMove(t)},n.prototype._onMouseUp=function(t){this._stopMove(t),this.isStereoEnabled()&&this.stopStereoView()},n.prototype._onMouseMove=function(t){0!==t.buttons?(t.preventDefault(),this._move(t)):this.config.mousemove_hover&&this._moveAbsolute(t)},n.prototype._onTouchStart=function(t){1===t.touches.length?this._startMove(t.touches[0]):2===t.touches.length&&this._startZoom(t)},n.prototype._onTouchEnd=function(t){this._stopMove(t.changedTouches[0])},n.prototype._onTouchMove=function(t){1===t.touches.length?(t.preventDefault(),this._move(t.touches[0])):2===t.touches.length&&(t.preventDefault(),this._zoom(t))},n.prototype._startMove=function(t){this.stopAutorotate(),this.stopAnimation(),this.prop.mouse_x=this.prop.start_mouse_x=parseInt(t.clientX),this.prop.mouse_y=this.prop.start_mouse_y=parseInt(t.clientY),this.prop.moving=!0,this.prop.zooming=!1,this.prop.mouse_history.length=0,this._logMouseMove(t)},n.prototype._startZoom=function(t){var e=[{x:parseInt(t.touches[0].clientX),y:parseInt(t.touches[0].clientY)},{x:parseInt(t.touches[1].clientX),y:parseInt(t.touches[1].clientY)}];this.prop.pinch_dist=Math.sqrt(Math.pow(e[0].x-e[1].x,2)+Math.pow(e[0].y-e[1].y,2)),this.prop.moving=!1,this.prop.zooming=!0},n.prototype._stopMove=function(t){x.getClosest(t.target,".psv-hud")&&(this.prop.moving&&(Math.abs(t.clientX-this.prop.start_mouse_x)n.INERTIA_WINDOW/10?(this.prop.mouse_history.splice(0,o),o=0,i=this.prop.mouse_history[0][o]):(o++,i=this.prop.mouse_history[0][o])},n.prototype.load=function(){if(!this.config.panorama)throw new E("No value given for panorama.");return this.setPanorama(this.config.panorama,!1)},n.prototype.getPosition=function(){return{longitude:this.prop.position.longitude,latitude:this.prop.position.latitude}},n.prototype.getZoomLevel=function(){return this.prop.zoom_lvl},n.prototype.getSize=function(){return{width:this.prop.size.width,height:this.prop.size.height}},n.prototype.isAutorotateEnabled=function(){return!!this.prop.autorotate_cb},n.prototype.isGyroscopeEnabled=function(){return!!this.prop.orientation_cb},n.prototype.isStereoEnabled=function(){return!!this.stereoEffect},n.prototype.isFullscreenEnabled=function(){return x.isFullscreenEnabled(this.container)},n.prototype.needsUpdate=function(){this.prop.needsUpdate=!0},n.prototype.render=function(){this._render()},n.prototype.destroy=function(){window.cancelAnimationFrame(this.prop.main_reqid),this._stopAll(),this.stopKeyboardControl(),this.stopNoSleep(),this.exitFullscreen(),this.unlockOrientation(),this._unbindEvents(),this.tooltip&&this.tooltip.destroy(),this.notification&&this.notification.destroy(),this.hud&&this.hud.destroy(),this.loader&&this.loader.destroy(),this.navbar&&this.navbar.destroy(),this.panel&&this.panel.destroy(),this.pleaseRotate&&this.pleaseRotate.destroy(),this.scene&&x.cleanTHREEScene(this.scene),this.canvas_container&&this.container.removeChild(this.canvas_container),this.parent.removeChild(this.container),delete this.parent.photoSphereViewer,delete this.parent,delete this.container,delete this.loader,delete this.navbar,delete this.hud,delete this.panel,delete this.tooltip,delete this.notification,delete this.pleaseRotate,delete this.canvas_container,delete this.renderer,delete this.noSleep,delete this.scene,delete this.camera,delete this.mesh,delete this.raycaster,delete this.passes,delete this.config,this.prop.cache.length=0},n.prototype.setPanorama=function(t,e,i){if(null!==this.prop.loading_promise)throw new E("Loading already in progress");return"boolean"==typeof e&&(i=e,e=void 0),e&&(this.cleanPosition(e),this._stopAll()),this.config.panorama=t,i&&this.config.transition&&this.scene?(this.config.transition.loader&&this.loader.show(),this.prop.loading_promise=this._loadTexture(this.config.panorama).then(function(t){return this.loader.hide(),this._transition(t,e)}.bind(this)).ensure(function(){this.loader.hide(),this.prop.loading_promise=null}.bind(this)).rethrow()):(this.loader.show(),this.canvas_container&&(this.canvas_container.style.opacity=0),this.prop.loading_promise=this._loadTexture(this.config.panorama).then(function(t){this._setTexture(t),e&&this.rotate(e)}.bind(this)).ensure(function(){this.loader.hide(),this.canvas_container.style.opacity=1,this.prop.loading_promise=null}.bind(this)).rethrow()),this.prop.loading_promise},n.prototype.startAutorotate=function(){this._stopAll(),this.prop.autorotate_cb=this._getAutorotateUpdate(),this.on("before-render",this.prop.autorotate_cb),this.trigger("autorotate",!0)},n.prototype._getAutorotateUpdate=function(){var t,e;return function(i){e=void 0===t?0:i-t,t=i,this.rotate({longitude:this.prop.position.longitude+this.config.anim_speed*e/1e3,latitude:this.prop.position.latitude-(this.prop.position.latitude-this.config.anim_lat)/200})}},n.prototype.stopAutorotate=function(){this.prop.start_timeout&&(window.clearTimeout(this.prop.start_timeout),this.prop.start_timeout=null),this.isAutorotateEnabled()&&(this.off("before-render",this.prop.autorotate_cb),this.prop.autorotate_cb=null,this.trigger("autorotate",!1))},n.prototype.toggleAutorotate=function(){this.isAutorotateEnabled()?this.stopAutorotate():this.startAutorotate()},n.prototype.startGyroscopeControl=function(){if(x.checkTHREE("DeviceOrientationControls"))return n.SYSTEM.deviceOrientationSupported.then(function(){this._stopAll(),this.doControls=new t.DeviceOrientationControls(this.camera),this.doControls.alphaOffset=this.prop.position.longitude,this.doControls.update();var e=this.camera.getWorldDirection(new t.Vector3),i=this.vector3ToSphericalCoords(e);this.prop.gyro_alpha_offset=i.longitude,this.prop.orientation_cb=this._getOrientationUpdate(),this.on("before-render",this.prop.orientation_cb),this.trigger("gyroscope-updated",!0)}.bind(this),function(){return console.warn("PhotoSphereViewer: gyroscope not available"),e.rejected()});throw new E("Missing Three.js components: DeviceOrientationControls. Get them from three.js-examples package.")},n.prototype._getOrientationUpdate=function(){return function(){this.doControls.alphaOffset=this.prop.gyro_alpha_offset,this.doControls.update(),this.camera.getWorldDirection(this.prop.direction),this.prop.direction.multiplyScalar(n.SPHERE_RADIUS);var t=this.vector3ToSphericalCoords(this.prop.direction);this.prop.position.longitude=t.longitude,this.prop.position.latitude=t.latitude,this.needsUpdate()}},n.prototype.stopGyroscopeControl=function(){this.isGyroscopeEnabled()&&(this.off("before-render",this.prop.orientation_cb),this.prop.orientation_cb=null,this.doControls.disconnect(),this.doControls=null,this.trigger("gyroscope-updated",!1))},n.prototype.toggleGyroscopeControl=function(){this.isGyroscopeEnabled()?this.stopGyroscopeControl():this.startGyroscopeControl()},n.prototype.startNoSleep=function(){"NoSleep"in window?(this.noSleep||(this.noSleep=new NoSleep),this.noSleep.enable()):console.warn("PhotoSphereViewer: NoSleep is not available")},n.prototype.stopNoSleep=function(){this.noSleep&&this.noSleep.disable()},n.prototype.startStereoView=function(){if(!x.checkTHREE("DeviceOrientationControls","StereoEffect"))throw new E("Missing Three.js components: StereoEffect, DeviceOrientationControls. Get them from three.js-examples package.");this.startNoSleep(),this.enterFullscreen(),this.lockOrientation(),this.startGyroscopeControl().then(function(){this.stereoEffect=new t.StereoEffect(this.renderer),this.needsUpdate(),this.hud.hide(),this.navbar.hide(),this.panel.hidePanel(),this.trigger("stereo-updated",!0),this.notification.showNotification({content:this.config.lang.stereo_notification,timeout:3e3})}.bind(this),function(){this.unlockOrientation(),this.exitFullscreen(),this.stopNoSleep()}.bind(this))},n.prototype.stopStereoView=function(){this.isStereoEnabled()&&(this.stereoEffect=null,this.needsUpdate(),this.hud.show(),this.navbar.show(),this.unlockOrientation(),this.exitFullscreen(),this.stopNoSleep(),this.stopGyroscopeControl(),this.trigger("stereo-updated",!1))},n.prototype.lockOrientation=function(){var t=function(){window.innerHeight>window.innerWidth&&(this.pleaseRotate||(this.pleaseRotate=new u(this)),this.pleaseRotate.show())};window.screen&&window.screen.orientation?window.screen.orientation.lock("landscape").then(null,t.bind(this)):t.apply(this)},n.prototype.unlockOrientation=function(){window.screen&&window.screen.orientation?window.screen.orientation.unlock():this.pleaseRotate&&this.pleaseRotate.hide()},n.prototype.toggleStereoView=function(){this.isStereoEnabled()?this.stopStereoView():this.startStereoView()},n.prototype.rotate=function(t){this.cleanPosition(t),this.applyRanges(t).forEach(this.trigger.bind(this,"_side-reached")),this.prop.position.longitude=t.longitude,this.prop.position.latitude=t.latitude,this.needsUpdate(),this.trigger("position-updated",this.getPosition())},n.prototype.animate=function(t,i){if(this._stopAll(),this.cleanPosition(t),!i||Math.abs(t.longitude-this.prop.position.longitude)0&&this.zoom(this.prop.zoom_lvl-this.config.zoom_speed)},n.prototype.resize=function(t){t.width&&(this.container.style.width=t.width),t.height&&(this.container.style.height=t.height),this._onResize()},n.prototype.enterFullscreen=function(){x.requestFullscreen(this.container)},n.prototype.exitFullscreen=function(){x.exitFullscreen()},n.prototype.toggleFullscreen=function(){this.isFullscreenEnabled()?this.exitFullscreen():this.enterFullscreen()},n.prototype.startKeyboardControl=function(){window.addEventListener("keydown",this)},n.prototype.stopKeyboardControl=function(){window.removeEventListener("keydown",this)},n.prototype.preloadPanorama=function(t){if(!this.config.cache_texture)throw new E("Cannot preload panorama, cache_texture is disabled");return this._loadTexture(t)},n.prototype.clearPanoramaCache=function(t){if(!this.config.cache_texture)throw new E("Cannot clear cache, cache_texture is disabled");if(t){for(var e=0,i=this.prop.cache.length;e=Math.PI?e-Math.PI:e+Math.PI,latitude:x.HalfPI-i}},n.prototype.sphericalCoordsToTextureCoords=function(t){if(this.prop.isCubemap)throw new E("Unable to use texture coords with cubemap.");var e=t.longitude/x.TwoPI*this.prop.pano_data.full_width,i=t.latitude/Math.PI*this.prop.pano_data.full_height;return{x:parseInt(t.longitudei[1]?e.longitude>i[1]&&e.longitudei[0]/2+i[1]/2?(e.longitude=i[0],n.push("left")):(e.longitude=i[1],n.push("right"))):e.longitudei[1]&&(e.longitude=i[1],n.push("right"))),this.config.latitude_range&&(i=x.clone(this.config.latitude_range),o=t.Math.degToRad(this.prop.vFov)/2,i[0]=x.parseAngle(Math.min(i[0]+o,i[1]),!0),i[1]=x.parseAngle(Math.max(i[1]-o,i[0]),!0),e.latitudei[1]&&(e.latitude=i[1],n.push("top"))),n};function s(t){this.psv=t instanceof n?t:t.psv,this.parent=t,this.container=null,this.visible=!0,this.constructor.publicMethods&&this.constructor.publicMethods.forEach(function(t){this.psv[t]=this[t].bind(this)},this)}s.className=null,s.publicMethods=[],s.prototype.create=function(){this.container=document.createElement("div"),this.constructor.className&&(this.container.className=this.constructor.className),this.parent.container.appendChild(this.container)},s.prototype.destroy=function(){this.parent.container.removeChild(this.container),this.constructor.publicMethods&&this.constructor.publicMethods.forEach(function(t){delete this.psv[t]},this),delete this.container,delete this.psv,delete this.parent},s.prototype.hide=function(){this.container.style.display="none",this.visible=!1},s.prototype.show=function(){this.container.style.display="",this.visible=!0};function r(t){s.call(this,t),this.svgContainer=null,this.markers={},this.currentMarker=null,this.hoveringMarker=null,this.prop={panelOpened:!1,panelOpening:!1,markersButton:this.psv.navbar.getNavbarButton("markers",!0)},this.create()}r.prototype=Object.create(s.prototype),r.prototype.constructor=r,r.className="psv-hud",r.publicMethods=["addMarker","removeMarker","updateMarker","clearMarkers","getMarker","getCurrentMarker","gotoMarker","hideMarker","showMarker","toggleMarker","toggleMarkersList","showMarkersList","hideMarkersList"],r.prototype.create=function(){s.prototype.create.call(this),this.svgContainer=document.createElementNS(x.svgNS,"svg"),this.svgContainer.setAttribute("class","psv-hud-svg-container"),this.container.appendChild(this.svgContainer),this.container.addEventListener("mouseenter",this,!0),this.container.addEventListener("mouseleave",this,!0),this.container.addEventListener("mousemove",this,!0),this.psv.on("click",this),this.psv.on("dblclick",this),this.psv.on("render",this),this.psv.on("open-panel",this),this.psv.on("close-panel",this)},r.prototype.destroy=function(){this.clearMarkers(!1),this.container.removeEventListener("mouseenter",this),this.container.removeEventListener("mouseleave",this),this.container.removeEventListener("mousemove",this),this.psv.off("click",this),this.psv.off("dblclick",this),this.psv.off("render",this),this.psv.off("open-panel",this),this.psv.off("close-panel",this),delete this.svgContainer,s.prototype.destroy.call(this)},r.prototype.handleEvent=function(t){switch(t.type){case"mouseenter":this._onMouseEnter(t);break;case"mouseleave":this._onMouseLeave(t);break;case"mousemove":this._onMouseMove(t);break;case"click":this._onClick(t.args[0],t,!1);break;case"dblclick":this._onClick(t.args[0],t,!0);break;case"render":this.renderMarkers();break;case"open-panel":this._onPanelOpened();break;case"close-panel":this._onPanelClosed()}},r.prototype.addMarker=function(t,e){if(!t.id)throw new E("missing marker id");if(this.markers[t.id])throw new E('marker "'+t.id+'" already exists');var i=new k(t,this.psv);return i.isNormal()?this.container.appendChild(i.$el):this.svgContainer.appendChild(i.$el),this.markers[i.id]=i,!1!==e&&this.renderMarkers(),i},r.prototype.getMarker=function(t){var e="object"==typeof t?t.id:t;if(!this.markers[e])throw new E('cannot find marker "'+e+'"');return this.markers[e]},r.prototype.getCurrentMarker=function(){return this.currentMarker},r.prototype.updateMarker=function(t,e){var i=this.getMarker(t);return i.update(t),!1!==e&&this.renderMarkers(),i},r.prototype.removeMarker=function(t,e){(t=this.getMarker(t)).isNormal()?this.container.removeChild(t.$el):this.svgContainer.removeChild(t.$el),this.hoveringMarker===t&&this.psv.tooltip.hideTooltip(),t.destroy(),delete this.markers[t.id],!1!==e&&this.renderMarkers()},r.prototype.clearMarkers=function(t){Object.keys(this.markers).forEach(function(t){this.removeMarker(t,!1)},this),!1!==t&&this.renderMarkers()},r.prototype.gotoMarker=function(t,e){return t=this.getMarker(t),this.psv.animate(t,e).then(function(){this.psv.trigger("goto-marker-done",t)}.bind(this))},r.prototype.hideMarker=function(t){this.getMarker(t).visible=!1,this.renderMarkers()},r.prototype.showMarker=function(t){this.getMarker(t).visible=!0,this.renderMarkers()},r.prototype.toggleMarker=function(t){this.getMarker(t).visible^=!0,this.renderMarkers()},r.prototype.toggleMarkersList=function(){this.prop.panelOpened?this.hideMarkersList():this.showMarkersList()},r.prototype.showMarkersList=function(){var t=[];x.forEach(this.markers,function(e){t.push(e)});var e=this.psv.config.templates.markersList({markers:this.psv.change("render-markers-list",t),config:this.psv.config});this.prop.panelOpening=!0,this.psv.panel.showPanel(e,!0),this.psv.panel.container.querySelector(".psv-markers-list").addEventListener("click",this._onClickItem.bind(this))},r.prototype.hideMarkersList=function(){this.prop.panelOpened&&this.psv.panel.hidePanel()},r.prototype.renderMarkers=function(){if(this.visible){var e=this.psv.isGyroscopeEnabled()?t.Math.radToDeg(this.psv.camera.rotation.z):0;x.forEach(this.markers,function(t){var i=t.visible;if(i&&t.isPoly()){var o=this._getPolyPositions(t);if(i=o.length>(t.isPolygon()?2:1)){t.position2D=this._getPolyDimensions(t,o);var n=o.map(function(t){return t.x+","+t.y}).join(" ");t.$el.setAttributeNS(null,"points",n)}}else if(i){var s=this._getMarkerPosition(t);if(i=this._isMarkerVisible(t,s)){t.position2D=s;var r=t.getScale(this.psv.getZoomLevel());t.isSvg()?t.$el.setAttributeNS(null,"transform","translate("+s.x+", "+s.y+")"+(1!==r?" scale("+r+", "+r+")":"")+(!t.lockRotation&&e?" rotate("+e+")":"")):t.$el.style.transform="translate3D("+s.x+"px, "+s.y+"px, 0px)"+(1!==r?" scale("+r+", "+r+")":"")+(!t.lockRotation&&e?" rotateZ("+e+"deg)":"")}}x.toggleClass(t.$el,"psv-marker--visible",i)}.bind(this))}},r.prototype._isMarkerVisible=function(t,e){return t.position3D.dot(this.psv.prop.direction)>0&&e.x+t.width>=0&&e.x-t.width<=this.psv.prop.size.width&&e.y+t.height>=0&&e.y-t.height<=this.psv.prop.size.height},r.prototype._getMarkerPosition=function(t){if(t._dynamicSize){x.toggleClass(t.$el,"psv-marker--transparent",!0);var e=t.$el.style.transform;t.$el.style.transform=null;var i=t.$el.getBoundingClientRect();t.$el.style.transform=e,x.toggleClass(t.$el,"psv-marker--transparent",!1),t.width=i.right-i.left,t.height=i.bottom-i.top}var o=this.psv.vector3ToViewerCoords(t.position3D);return o.x-=t.width*t.anchor.left,o.y-=t.height*t.anchor.top,o},r.prototype._getPolyPositions=function(t){var e=t.positions3D.length,i=t.positions3D.map(function(t){return{vector:t,visible:t.dot(this.psv.prop.direction)>0}},this),o=[];return i.forEach(function(t,n){if(!t.visible){[0===n?i[e-1]:i[n-1],n===e-1?i[0]:i[n+1]].forEach(function(e){e.visible&&o.push({visible:e,invisible:t,index:n})})}}),o.reverse().forEach(function(t){i.splice(t.index,0,{vector:this._getPolyIntermediaryPoint(t.visible.vector,t.invisible.vector),visible:!0})},this),i.filter(function(t){return t.visible}).map(function(t){return this.psv.vector3ToViewerCoords(t.vector)},this)},r.prototype._getPolyIntermediaryPoint=function(e,i){var o=this.psv.prop.direction.clone().normalize(),s=(new t.Vector3).crossVectors(e,i).normalize(),r=(new t.Vector3).crossVectors(s,e).normalize(),a=(new t.Vector3).addVectors(e.clone().multiplyScalar(-o.dot(r)),r.clone().multiplyScalar(o.dot(e))).normalize(),h=(new t.Vector3).crossVectors(a,o);return a.applyAxisAngle(h,.01).multiplyScalar(n.SPHERE_RADIUS)},r.prototype._getPolyDimensions=function(t,e){var i=1/0,o=1/0,n=-1/0,s=-1/0;return e.forEach(function(t){i=Math.min(i,t.x),o=Math.min(o,t.y),n=Math.max(n,t.x),s=Math.max(s,t.y)}),t.width=n-i,t.height=s-o,{x:i,y:o}},r.prototype._onMouseEnter=function(t){var e;t.target&&(e=t.target.psvMarker)&&!e.isPoly()&&(this.hoveringMarker=e,this.psv.trigger("over-marker",e),e.tooltip&&this.psv.tooltip.showTooltip({content:e.tooltip.content,position:e.tooltip.position,left:e.position2D.x,top:e.position2D.y,box:{width:e.width,height:e.height}}))},r.prototype._onMouseLeave=function(t){var e;if(t.target&&(e=t.target.psvMarker)){if(e.isPoly()&&t.relatedTarget&&x.hasParent(t.relatedTarget,this.psv.tooltip.container))return;this.psv.trigger("leave-marker",e),this.hoveringMarker=null,this.psv.tooltip.hideTooltip()}},r.prototype._onMouseMove=function(t){if(!this.psv.prop.moving){var e;if(t.target&&(e=t.target.psvMarker)&&e.isPoly()||t.target&&x.hasParent(t.target,this.psv.tooltip.container)&&(e=this.hoveringMarker)){this.hoveringMarker||(this.psv.trigger("over-marker",e),this.hoveringMarker=e);var i=this.psv.container.getBoundingClientRect();e.tooltip&&this.psv.tooltip.showTooltip({content:e.tooltip.content,position:e.tooltip.position,top:t.clientY-i.top-this.psv.config.tooltip.arrow_size/2,left:t.clientX-i.left-this.psv.config.tooltip.arrow_size,box:{width:2*this.psv.config.tooltip.arrow_size,height:2*this.psv.config.tooltip.arrow_size}})}else this.hoveringMarker&&this.hoveringMarker.isPoly()&&(this.psv.trigger("leave-marker",this.hoveringMarker),this.hoveringMarker=null,this.psv.tooltip.hideTooltip())}},r.prototype._onClick=function(t,e,i){var o;t.target&&(o=x.getClosest(t.target,".psv-marker"))&&o.psvMarker?(this.currentMarker=o.psvMarker,this.psv.trigger("select-marker",this.currentMarker,i),this.psv.config.click_event_on_marker?t.marker=o.psvMarker:e.stopPropagation()):this.currentMarker&&(this.psv.trigger("unselect-marker",this.currentMarker),this.currentMarker=null),o&&o.psvMarker&&o.psvMarker.content?this.psv.panel.showPanel(o.psvMarker.content):this.psv.panel.prop.opened&&(e.stopPropagation(),this.psv.panel.hidePanel())},r.prototype._onClickItem=function(t){var e;if(t.target&&(e=x.getClosest(t.target,"li"))&&e.dataset.psvMarker){var i=this.getMarker(e.dataset.psvMarker);this.psv.trigger("select-marker-list",i),this.gotoMarker(i,1e3),this.psv.panel.hidePanel()}},r.prototype._onPanelOpened=function(){this.prop.panelOpening?(this.prop.panelOpening=!1,this.prop.panelOpened=!0):this.prop.panelOpened=!1,this.prop.markersButton&&this.prop.markersButton.toggleActive(this.prop.panelOpened)},r.prototype._onPanelClosed=function(){this.prop.panelOpened=!1,this.prop.panelOpening=!1,this.prop.markersButton&&this.prop.markersButton.toggleActive(!1)};function a(t){s.call(this,t),this.canvas=null,this.loader=null,this.create()}a.prototype=Object.create(s.prototype),a.prototype.constructor=a,a.className="psv-loader-container",a.prototype.create=function(){s.prototype.create.call(this);var t=n.SYSTEM.pixelRatio;this.loader=document.createElement("div"),this.loader.className="psv-loader",this.container.appendChild(this.loader),this.canvas=document.createElement("canvas"),this.canvas.className="psv-loader-canvas",this.canvas.width=this.loader.clientWidth*t,this.canvas.height=this.loader.clientWidth*t,this.loader.appendChild(this.canvas),this.tickness=(this.loader.offsetWidth-this.loader.clientWidth)/2*t;var e;if(this.psv.config.loading_img?((e=document.createElement("img")).className="psv-loader-image",e.src=this.psv.config.loading_img):this.psv.config.loading_txt&&((e=document.createElement("div")).className="psv-loader-text",e.innerHTML=this.psv.config.loading_txt),e){var i=Math.round(Math.sqrt(2*Math.pow((this.canvas.width/2-this.tickness/2)/t,2)));e.style.maxWidth=i+"px",e.style.maxHeight=i+"px",this.loader.appendChild(e)}},a.prototype.destroy=function(){delete this.loader,delete this.canvas,s.prototype.destroy.call(this)},a.prototype.setProgress=function(t){var e=this.canvas.getContext("2d");e.clearRect(0,0,this.canvas.width,this.canvas.height),e.lineWidth=this.tickness,e.strokeStyle=x.getStyle(this.loader,"color"),e.beginPath(),e.arc(this.canvas.width/2,this.canvas.height/2,this.canvas.width/2-this.tickness/2,-Math.PI/2,t/100*2*Math.PI-Math.PI/2),e.stroke()};function h(t){if(s.call(this,t),this.config=this.psv.config.navbar,this.items=[],!0===this.config)this.config=x.clone(n.DEFAULTS.navbar);else if("string"==typeof this.config)this.config=this.config.split(" ");else if(!Array.isArray(this.config)){console.warn('PhotoSphereViewer: hashmap form of "navbar" is deprecated, use an array instead.');var e=this.config;this.config=[],x.forEach(e,function(t,e){t&&this.config.push(e)}.bind(this)),this.config.sort(function(t,e){return n.DEFAULTS.navbar.indexOf(t)-n.DEFAULTS.navbar.indexOf(e)})}this.create()}h.prototype=Object.create(s.prototype),h.prototype.constructor=h,h.className="psv-navbar psv-navbar--open",h.publicMethods=["showNavbar","hideNavbar","toggleNavbar","getNavbarButton"],h.prototype.create=function(){s.prototype.create.call(this),this.config.forEach(function(t){if("object"==typeof t)this.items.push(new m(this,t));else switch(t){case g.id:this.items.push(new g(this));break;case M.id:this.items.push(new M(this));break;case v.id:this.items.push(new v(this));break;case w.id:this.items.push(new w(this));break;case y.id:this.items.push(new y(this));break;case b.id:this.items.push(new b(this));break;case _.id:this.items.push(new _(this));break;case"caption":this.items.push(new p(this,this.psv.config.caption));break;default:if(0!==t.indexOf("spacer"))throw new E("Unknown button "+t);console.warn("PhotoSphereViewer: navbar spacers have been removed.")}},this)},h.prototype.destroy=function(){this.items.forEach(function(t){t.destroy()}),this.items.length=0,delete this.config,s.prototype.destroy.call(this)},h.prototype.getNavbarButton=function(t,e){var i=null;return this.items.some(function(e){return e.id===t&&(i=e,!0)}),i||e||console.warn('PhotoSphereViewer: button "'+t+'" not found in the navbar.'),i},h.prototype.showNavbar=function(){this.toggleNavbar(!0)},h.prototype.hideNavbar=function(){this.toggleNavbar(!1)},h.prototype.toggleNavbar=function(t){x.toggleClass(this.container,"psv-navbar--open",t)};function p(t,e){s.call(this,t),this.content=null,this.icon=null,this.prop={caption:"",width:0,hidden:!1},this.create(),this.setCaption(e)}p.prototype=Object.create(s.prototype),p.prototype.constructor=p,p.className="psv-caption",p.publicMethods=["setCaption"],p.prototype.create=function(){s.prototype.create.call(this),this.container.innerHTML=n.ICONS["info.svg"],this.icon=this.container.querySelector("svg"),this.icon.setAttribute("class","psv-caption-icon"),this.icon.style.display="none",this.content=document.createElement("span"),this.content.className="psv-caption-content",this.container.appendChild(this.content),this.icon.addEventListener("click",this),window.addEventListener("resize",this)},p.prototype.destroy=function(){window.removeEventListener("resize",this),delete this.content,s.prototype.destroy.call(this)},p.prototype.handleEvent=function(t){switch(t.type){case"resize":this._onResize();break;case"click":this._onClick()}},p.prototype.setCaption=function(t){this.prop.caption=t||"",this.content.innerHTML=this.prop.caption,this.content.style.display="",this.prop.width=this.content.offsetWidth,this._onResize()},p.prototype._onResize=function(){parseInt(x.getStyle(this.container,"width"))>=this.prop.width?(this.icon.style.display="none",this.content.style.display=""):(this.icon.style.display="",this.content.style.display="none")},p.prototype._onClick=function(){this.psv.isNotificationVisible()?this.psv.hideNotification():this.psv.showNotification(this.prop.caption)};function c(t){s.call(this,t),this.create()}c.prototype=Object.create(s.prototype),c.prototype.constructor=c,c.className="psv-notification",c.publicMethods=["showNotification","hideNotification","isNotificationVisible"],c.prototype.create=function(){s.prototype.create.call(this),this.content=document.createElement("div"),this.content.className="psv-notification-content",this.container.appendChild(this.content),this.content.addEventListener("click",this.hideNotification.bind(this))},c.prototype.destroy=function(){delete this.content,s.prototype.destroy.call(this)},c.prototype.isNotificationVisible=function(){return this.container.classList.contains("psv-notification--visible")},c.prototype.showNotification=function(t){"string"==typeof t&&(t={content:t}),this.content.innerHTML=t.content,this.container.classList.add("psv-notification--visible"),this.psv.trigger("show-notification"),t.timeout&&setTimeout(this.hideNotification.bind(this),t.timeout)},c.prototype.hideNotification=function(){this.isNotificationVisible()&&(this.container.classList.remove("psv-notification--visible"),this.psv.trigger("hide-notification"))};function l(t){s.call(this,t),this.content=null,this.prop={mouse_x:0,mouse_y:0,mousedown:!1,opened:!1},this.create()}l.prototype=Object.create(s.prototype),l.prototype.constructor=l,l.className="psv-panel",l.publicMethods=["showPanel","hidePanel"],l.prototype.create=function(){s.prototype.create.call(this),this.container.innerHTML='
',this.content=this.container.querySelector(".psv-panel-content");this.container.querySelector(".psv-panel-close-button").addEventListener("click",this.hidePanel.bind(this)),this.psv.config.mousewheel&&this.container.addEventListener(n.SYSTEM.mouseWheelEvent,function(t){t.stopPropagation()});var t=this.container.querySelector(".psv-panel-resizer");t.addEventListener("mousedown",this),t.addEventListener("touchstart",this),this.psv.container.addEventListener("mouseup",this),this.psv.container.addEventListener("touchend",this),this.psv.container.addEventListener("mousemove",this),this.psv.container.addEventListener("touchmove",this)},l.prototype.destroy=function(){this.psv.container.removeEventListener("mousemove",this),this.psv.container.removeEventListener("touchmove",this),this.psv.container.removeEventListener("mouseup",this),this.psv.container.removeEventListener("touchend",this),delete this.prop,delete this.content,s.prototype.destroy.call(this)},l.prototype.handleEvent=function(t){switch(t.type){case"mousedown":this._onMouseDown(t);break;case"touchstart":this._onTouchStart(t);break;case"mousemove":this._onMouseMove(t);break;case"touchmove":this._onTouchMove(t);break;case"mouseup":case"touchend":this._onMouseUp(t)}},l.prototype.showPanel=function(t,e){this.content.innerHTML=t,this.content.scrollTop=0,this.container.classList.add("psv-panel--open"),x.toggleClass(this.content,"psv-panel-content--no-margin",!0===e),this.prop.opened=!0,this.psv.trigger("open-panel")},l.prototype.hidePanel=function(){this.content.innerHTML=null,this.prop.opened=!1,this.container.classList.remove("psv-panel--open"),this.psv.trigger("close-panel")},l.prototype._onMouseDown=function(t){t.stopPropagation(),this._startResize(t)},l.prototype._onTouchStart=function(t){t.stopPropagation(),this._startResize(t.changedTouches[0])},l.prototype._onMouseUp=function(t){this.prop.mousedown&&(t.stopPropagation(),this.prop.mousedown=!1,this.content.classList.remove("psv-panel-content--no-interaction"))},l.prototype._onMouseMove=function(t){this.prop.mousedown&&(t.stopPropagation(),this._resize(t))},l.prototype._onTouchMove=function(t){this.prop.mousedown&&this._resize(t.touches[0])},l.prototype._startResize=function(t){this.prop.mouse_x=parseInt(t.clientX),this.prop.mouse_y=parseInt(t.clientY),this.prop.mousedown=!0,this.content.classList.add("psv-panel-content--no-interaction")},l.prototype._resize=function(t){var e=parseInt(t.clientX),i=parseInt(t.clientY);this.container.style.width=this.container.offsetWidth-(e-this.prop.mouse_x)+"px",this.prop.mouse_x=e,this.prop.mouse_y=i};function u(t){s.call(this,t),this.create()}u.prototype=Object.create(s.prototype),u.prototype.constructor=u,u.className="psv-please-rotate",u.prototype.create=function(){s.prototype.create.call(this),this.container.innerHTML='
'+n.ICONS["mobile-rotate.svg"]+'
'+this.psv.config.lang.please_rotate[0]+'
'+this.psv.config.lang.please_rotate[1]+"
",this.container.addEventListener("click",this),window.addEventListener("orientationchange",this)},u.prototype.destroy=function(){window.removeEventListener("orientationchange",this),s.prototype.destroy.call(this)},u.prototype.handleEvent=function(t){switch(t.type){case"click":this.hide();break;case"orientationchange":90===Math.abs(window.orientation)&&this.hide()}};function d(t){s.call(this,t),this.config=this.psv.config.tooltip,this.prop={timeout:null},this.create()}d.prototype=Object.create(s.prototype),d.prototype.constructor=d,d.className="psv-tooltip",d.publicMethods=["showTooltip","hideTooltip","isTooltipVisible"],d.leftMap={0:"left",.5:"center",1:"right"},d.topMap={0:"top",.5:"center",1:"bottom"},d.prototype.create=function(){s.prototype.create.call(this),this.container.innerHTML='
',this.container.style.top="-1000px",this.container.style.left="-1000px",this.content=this.container.querySelector(".psv-tooltip-content"),this.arrow=this.container.querySelector(".psv-tooltip-arrow"),this.psv.on("render",this)},d.prototype.destroy=function(){this.psv.off("render",this),delete this.config,delete this.prop,s.prototype.destroy.call(this)},d.prototype.handleEvent=function(t){switch(t.type){case"render":this.hideTooltip()}},d.prototype.isTooltipVisible=function(){return this.container.classList.contains("psv-tooltip--visible")},d.prototype.showTooltip=function(t){this.prop.timeout&&(window.clearTimeout(this.prop.timeout),this.prop.timeout=null);var e=this.isTooltipVisible(),i=this.container,o=this.content,n=this.arrow;if(t.position||(t.position=["top","center"]),t.box||(t.box={width:0,height:0}),"string"==typeof t.position){var s=x.parsePosition(t.position);if(!(s.left in d.leftMap&&s.top in d.topMap))throw new E('unable to parse tooltip position "'+t.position+'"');t.position=[d.topMap[s.top],d.leftMap[s.left]]}if("center"===t.position[0]&&"center"===t.position[1])throw new E('unable to parse tooltip position "center center"');if(e)for(var r=i.classList.length-1;r>=0;r--){var a=i.classList.item(r);"psv-tooltip"!==a&&"psv-tooltip--visible"!==a&&i.classList.remove(a)}else i.className="psv-tooltip";t.className&&x.addClasses(i,t.className),o.innerHTML=t.content,i.style.top="0px",i.style.left="0px";var h=i.getBoundingClientRect(),p={posClass:t.position.slice(),width:h.right-h.left,height:h.bottom-h.top,top:0,left:0,arrow_top:0,arrow_left:0};this._computeTooltipPosition(p,t);var c=!1;p.topthis.psv.prop.size.height-this.config.offset&&(p.posClass[0]="top",c=!0),p.leftthis.psv.prop.size.width-this.config.offset&&(p.posClass[1]="left",c=!0),c&&this._computeTooltipPosition(p,t),i.style.top=p.top+"px",i.style.left=p.left+"px",n.style.top=p.arrow_top+"px",n.style.left=p.arrow_left+"px",i.classList.add("psv-tooltip--"+p.posClass.join("-")),e||(this.prop.timeout=window.setTimeout(function(){i.classList.add("psv-tooltip--visible"),this.prop.timeout=null,this.psv.trigger("show-tooltip")}.bind(this),this.config.delay))},d.prototype.hideTooltip=function(){this.prop.timeout&&(window.clearTimeout(this.prop.timeout),this.prop.timeout=null),this.isTooltipVisible()&&(this.container.classList.remove("psv-tooltip--visible"),this.prop.timeout=window.setTimeout(function(){this.content.innerHTML=null,this.container.style.top="-1000px",this.container.style.left="-1000px",this.prop.timeout=null}.bind(this),this.config.delay),this.psv.trigger("hide-tooltip"))},d.prototype._computeTooltipPosition=function(t,e){var i=!1;switch(t.posClass[0]){case"bottom":t.top=e.top+e.box.height+this.config.offset+this.config.arrow_size,t.arrow_top=2*-this.config.arrow_size,i=!0;break;case"center":t.top=e.top+e.box.height/2-t.height/2,t.arrow_top=t.height/2-this.config.arrow_size;break;case"top":t.top=e.top-t.height-this.config.offset-this.config.arrow_size,t.arrow_top=t.height,i=!0}switch(t.posClass[1]){case"right":i?(t.left=e.left+e.box.width/2-this.config.offset-this.config.arrow_size,t.arrow_left=this.config.offset):(t.left=e.left+e.box.width+this.config.offset+this.config.arrow_size,t.arrow_left=2*-this.config.arrow_size);break;case"center":t.left=e.left+e.box.width/2-t.width/2,t.arrow_left=t.width/2-this.config.arrow_size;break;case"left":i?(t.left=e.left-t.width+e.box.width/2+this.config.offset+this.config.arrow_size,t.arrow_left=t.width-this.config.offset-2*this.config.arrow_size):(t.left=e.left-t.width-this.config.offset-this.config.arrow_size,t.arrow_left=t.width)}};function f(t){s.call(this,t),this.id=void 0,this.constructor.id&&(this.id=this.constructor.id),this.enabled=!0}f.prototype=Object.create(s.prototype),f.prototype.constructor=f,f.id=null,f.icon=null,f.iconActive=null,f.prototype.create=function(){s.prototype.create.call(this),this.constructor.icon&&this._setIcon(this.constructor.icon),this.id&&this.psv.config.lang[this.id]&&(this.container.title=this.psv.config.lang[this.id]),this.container.addEventListener("click",function(t){this.enabled&&this._onClick(),t.stopPropagation()}.bind(this))},f.prototype.destroy=function(){s.prototype.destroy.call(this)},f.prototype.toggleActive=function(t){x.toggleClass(this.container,"psv-button--active",t),this.constructor.iconActive&&this._setIcon(t?this.constructor.iconActive:this.constructor.icon)},f.prototype.disable=function(){this.container.classList.add("psv-button--disabled"),this.enabled=!1},f.prototype.enable=function(){this.container.classList.remove("psv-button--disabled"),this.enabled=!0},f.prototype._setIcon=function(t,e){e||(e=this.container),t?(e.innerHTML=n.ICONS[t],e.querySelector("svg").setAttribute("class","psv-button-svg")):e.innerHTML=""},f.prototype._onClick=function(){};function g(t){f.call(this,t),this.create()}g.prototype=Object.create(f.prototype),g.prototype.constructor=g,g.id="autorotate",g.className="psv-button psv-button--hover-scale psv-autorotate-button",g.icon="play.svg",g.iconActive="play-active.svg",g.prototype.create=function(){f.prototype.create.call(this),this.psv.on("autorotate",this)},g.prototype.destroy=function(){this.psv.off("autorotate",this),f.prototype.destroy.call(this)},g.prototype.handleEvent=function(t){switch(t.type){case"autorotate":this.toggleActive(t.args[0])}},g.prototype._onClick=function(){this.psv.toggleAutorotate()};function m(t,e){f.call(this,t),this.config=e,this.config.id&&(this.id=this.config.id),this.create()}m.prototype=Object.create(f.prototype),m.prototype.constructor=m,m.className="psv-button psv-custom-button",m.prototype.create=function(){f.prototype.create.call(this),this.config.className&&x.addClasses(this.container,this.config.className),this.config.title&&(this.container.title=this.config.title),this.config.content&&(this.container.innerHTML=this.config.content),!1!==this.config.enabled&&!0!==this.config.disabled||this.disable(),!1!==this.config.visible&&!0!==this.config.hidden||this.hide()},m.prototype.destroy=function(){delete this.config,f.prototype.destroy.call(this)},m.prototype._onClick=function(){this.config.onClick&&this.config.onClick.apply(this.psv)};function v(t){f.call(this,t),this.create()}v.prototype=Object.create(f.prototype),v.prototype.constructor=v,v.id="download",v.className="psv-button psv-button--hover-scale psv-download-button",v.icon="download.svg",v.prototype._onClick=function(){var t=document.createElement("a");t.href=this.psv.config.panorama,t.download=this.psv.config.panorama,this.psv.container.appendChild(t),t.click()};function y(t){f.call(this,t),this.create()}y.prototype=Object.create(f.prototype),y.prototype.constructor=y,y.id="fullscreen",y.className="psv-button psv-button--hover-scale psv-fullscreen-button",y.icon="fullscreen-in.svg",y.iconActive="fullscreen-out.svg",y.prototype.create=function(){f.prototype.create.call(this),n.SYSTEM.fullscreenEvent||(this.hide(),console.warn("PhotoSphereViewer: fullscreen not supported.")),this.psv.on("fullscreen-updated",this)},y.prototype.destroy=function(){this.psv.off("fullscreen-updated",this),f.prototype.destroy.call(this)},y.prototype.handleEvent=function(t){switch(t.type){case"fullscreen-updated":this.toggleActive(t.args[0])}},y.prototype._onClick=function(){this.psv.toggleFullscreen()};function _(t){f.call(this,t),this.create()}_.prototype=Object.create(f.prototype),_.prototype.constructor=_,_.id="gyroscope",_.className="psv-button psv-button--hover-scale psv-gyroscope-button",_.icon="compass.svg",_.prototype.create=function(){f.prototype.create.call(this),n.SYSTEM.deviceOrientationSupported.then(this._onAvailabilityChange.bind(this,!0),this._onAvailabilityChange.bind(this,!1)),this.hide(),this.psv.on("gyroscope-updated",this)},_.prototype.destroy=function(){this.psv.off("gyroscope-updated",this),f.prototype.destroy.call(this)},_.prototype.handleEvent=function(t){switch(t.type){case"gyroscope-updated":this.toggleActive(t.args[0])}},_.prototype._onClick=function(){this.psv.toggleGyroscopeControl()},_.prototype._onAvailabilityChange=function(t){t&&x.checkTHREE("DeviceOrientationControls")&&this.show()};function w(t){f.call(this,t),this.create()}w.prototype=Object.create(f.prototype),w.prototype.constructor=w,w.id="markers",w.className="psv-button psv-button--hover-scale psv-markers-button",w.icon="pin.svg",w.prototype._onClick=function(){this.psv.hud.toggleMarkersList()};function b(t){f.call(this,t),this.create()}b.prototype=Object.create(f.prototype),b.prototype.constructor=b,b.id="stereo",b.className="psv-button psv-button--hover-scale psv-stereo-button",b.icon="stereo.svg",b.prototype.create=function(){f.prototype.create.call(this),n.SYSTEM.deviceOrientationSupported.then(this._onAvailabilityChange.bind(this,!0),this._onAvailabilityChange.bind(this,!1)),this.hide(),this.psv.on("stereo-updated",this)},b.prototype.destroy=function(){this.psv.off("stereo-updated",this),f.prototype.destroy.call(this)},b.prototype.handleEvent=function(t){switch(t.type){case"stereo-updated":this.toggleActive(t.args[0])}},b.prototype._onClick=function(){this.psv.toggleStereoView()},b.prototype._onAvailabilityChange=function(t){t&&x.checkTHREE("DeviceOrientationControls","StereoEffect")&&this.show()};function M(t){f.call(this,t),this.zoom_range=null,this.zoom_value=null,this.prop={mousedown:!1,buttondown:!1,longPressInterval:null,longPressTimeout:null},this.create()}M.prototype=Object.create(f.prototype),M.prototype.constructor=M,M.id="zoom",M.className="psv-button psv-zoom-button",M.prototype.create=function(){f.prototype.create.call(this);var t=document.createElement("div");t.className="psv-zoom-button-minus",t.title=this.psv.config.lang.zoomOut,this._setIcon("zoom-out.svg",t),this.container.appendChild(t);var e=document.createElement("div");e.className="psv-zoom-button-range",this.container.appendChild(e),this.zoom_range=document.createElement("div"),this.zoom_range.className="psv-zoom-button-line",e.appendChild(this.zoom_range),this.zoom_value=document.createElement("div"),this.zoom_value.className="psv-zoom-button-handle",this.zoom_range.appendChild(this.zoom_value);var i=document.createElement("div");i.className="psv-zoom-button-plus",i.title=this.psv.config.lang.zoomIn,this._setIcon("zoom-in.svg",i),this.container.appendChild(i),this.zoom_range.addEventListener("mousedown",this),this.zoom_range.addEventListener("touchstart",this),this.psv.container.addEventListener("mousemove",this),this.psv.container.addEventListener("touchmove",this),this.psv.container.addEventListener("mouseup",this),this.psv.container.addEventListener("touchend",this),t.addEventListener("mousedown",this._zoomOut.bind(this)),i.addEventListener("mousedown",this._zoomIn.bind(this)),this.psv.on("zoom-updated",this),this.psv.once("ready",function(){this._moveZoomValue(this.psv.prop.zoom_lvl)}.bind(this))},M.prototype.destroy=function(){this._stopZoomChange(),this.psv.container.removeEventListener("mousemove",this),this.psv.container.removeEventListener("touchmove",this),this.psv.container.removeEventListener("mouseup",this),this.psv.container.removeEventListener("touchend",this),delete this.zoom_range,delete this.zoom_value,this.psv.off("zoom-updated",this),f.prototype.destroy.call(this)},M.prototype.handleEvent=function(t){switch(t.type){case"mousedown":this._initZoomChangeWithMouse(t);break;case"touchstart":this._initZoomChangeByTouch(t);break;case"mousemove":this._changeZoomWithMouse(t);break;case"touchmove":this._changeZoomByTouch(t);break;case"mouseup":case"touchend":this._stopZoomChange(t);break;case"zoom-updated":this._moveZoomValue(t.args[0])}},M.prototype._moveZoomValue=function(t){this.zoom_value.style.left=t/100*this.zoom_range.offsetWidth-this.zoom_value.offsetWidth/2+"px"},M.prototype._initZoomChangeWithMouse=function(t){this.enabled&&(this.prop.mousedown=!0,this._changeZoom(t.clientX))},M.prototype._initZoomChangeByTouch=function(t){this.enabled&&(this.prop.mousedown=!0,this._changeZoom(t.changedTouches[0].clientX))},M.prototype._zoomIn=function(){this.enabled&&(this.prop.buttondown=!0,this.psv.zoomIn(),this.prop.longPressTimeout=window.setTimeout(this._startLongPressInterval.bind(this,1),200))},M.prototype._zoomOut=function(){this.enabled&&(this.prop.buttondown=!0,this.psv.zoomOut(),this.prop.longPressTimeout=window.setTimeout(this._startLongPressInterval.bind(this,-1),200))},M.prototype._startLongPressInterval=function(t){this.prop.buttondown&&(this.prop.longPressInterval=window.setInterval(function(){this.psv.zoom(this.psv.prop.zoom_lvl+t)}.bind(this),50))},M.prototype._stopZoomChange=function(){this.enabled&&(window.clearInterval(this.prop.longPressInterval),window.clearTimeout(this.prop.longPressTimeout),this.prop.longPressInterval=null,this.prop.mousedown=!1,this.prop.buttondown=!1)},M.prototype._changeZoomWithMouse=function(t){this.enabled&&(t.preventDefault(),this._changeZoom(t.clientX))},M.prototype._changeZoomByTouch=function(t){this.enabled&&this._changeZoom(t.changedTouches[0].clientX)},M.prototype._changeZoom=function(t){if(this.prop.mousedown){var e=(parseInt(t)-this.zoom_range.getBoundingClientRect().left)/this.zoom_range.offsetWidth*100;this.psv.zoom(e)}};function E(t){this.message=t,"captureStackTrace"in Error?Error.captureStackTrace(this,E):this.stack=(new Error).stack}E.prototype=Object.create(Error.prototype),E.prototype.name="PSVError",E.prototype.constructor=E,n.Error=E;function k(t,e){if(!t.id)throw new E("missing marker id");if(t.image&&(!t.width||!t.height))throw new E("missing marker width/height");if((t.image||t.html)&&!(t.hasOwnProperty("x")&&t.hasOwnProperty("y")||t.hasOwnProperty("latitude")&&t.hasOwnProperty("longitude")))throw new E("missing marker position, latitude/longitude or x/y");this.psv=e,this.visible=!0,this._dynamicSize=!1;var i,o=t.id,n=k.getType(t,!1);Object.defineProperties(this,{id:{configurable:!1,enumerable:!0,get:function(){return o},set:function(){}},type:{configurable:!1,enumerable:!0,get:function(){return n},set:function(){}},$el:{configurable:!1,enumerable:!0,get:function(){return i},set:function(){}},_def:{configurable:!1,enumerable:!0,get:function(){return this[n]},set:function(t){this[n]=t}}}),(i=this.isNormal()?document.createElement("div"):this.isPolygon()?document.createElementNS(x.svgNS,"polygon"):this.isPolyline()?document.createElementNS(x.svgNS,"polyline"):document.createElementNS(x.svgNS,this.type)).id="psv-marker-"+this.id,i.psvMarker=this,this.update(t)}k.types=["image","html","polygon_px","polygon_rad","polyline_px","polyline_rad","rect","circle","ellipse","path"],k.getType=function(t,e){var i=[];if(k.types.forEach(function(e){t[e]&&i.push(e)}),0===i.length&&!e)throw new E("missing marker content, either "+k.types.join(", "));if(i.length>1)throw new E("multiple marker content, either "+k.types.join(", "));return i[0]},k.prototype.destroy=function(){delete this.$el.psvMarker},k.prototype.isNormal=function(){return"image"===this.type||"html"===this.type},k.prototype.isPoly=function(){return this.isPolygon()||this.isPolyline()},k.prototype.isPolygon=function(){return"polygon_px"===this.type||"polygon_rad"===this.type},k.prototype.isPolyline=function(){return"polyline_px"===this.type||"polyline_rad"===this.type},k.prototype.isSvg=function(){return"rect"===this.type||"circle"===this.type||"ellipse"===this.type||"path"===this.type},k.prototype.getScale=function(t){return Array.isArray(this.scale)?this.scale[0]+(this.scale[1]-this.scale[0])*x.animation.easings.inQuad(t/100):"function"==typeof this.scale?this.scale(t):"number"==typeof this.scale?this.scale*x.animation.easings.inQuad(t/100):1},k.prototype.update=function(t){if(t&&t!==this){var e=k.getType(t,!0);if(void 0!==e&&e!==this.type)throw new E("cannot change marker type");x.deepmerge(this,t)}this.isNormal()?this.$el.setAttribute("class","psv-marker psv-marker--normal"):this.$el.setAttribute("class","psv-marker psv-marker--svg"),this.className&&x.addClasses(this.$el,this.className),this.tooltip&&(x.addClasses(this.$el,"has-tooltip"),"string"==typeof this.tooltip&&(this.tooltip={content:this.tooltip})),this.style&&x.deepmerge(this.$el.style,this.style),this.anchor=x.parsePosition(this.anchor),this.isNormal()?this._updateNormal():this.isPolygon()?this._updatePoly("polygon_rad","polygon_px"):this.isPolyline()?this._updatePoly("polyline_rad","polyline_px"):this._updateSvg()},k.prototype._updateNormal=function(){this.width&&this.height?(this.$el.style.width=this.width+"px",this.$el.style.height=this.height+"px",this._dynamicSize=!1):this._dynamicSize=!0,this.image?this.$el.style.backgroundImage="url("+this.image+")":this.$el.innerHTML=this.html,this.$el.style.transformOrigin=100*this.anchor.left+"% "+100*this.anchor.top+"%",this.psv.cleanPosition(this),this.position3D=this.psv.sphericalCoordsToVector3(this)},k.prototype._updateSvg=function(){switch(this._dynamicSize=!0,this.type){case"rect":"number"==typeof this._def?this._def={x:0,y:0,width:this._def,height:this._def}:Array.isArray(this._def)?this._def={x:0,y:0,width:this._def[0],height:this._def[1]}:this._def.x=this._def.y=0;break;case"circle":"number"==typeof this._def?this._def={cx:this._def,cy:this._def,r:this._def}:Array.isArray(this._def)?this._def={cx:this._def[0],cy:this._def[0],r:this._def[0]}:this._def.cx=this._def.cy=this._def.r;break;case"ellipse":"number"==typeof this._def?this._def={cx:this._def,cy:this._def,rx:this._def,ry:this._def}:Array.isArray(this._def)?this._def={cx:this._def[0],cy:this._def[1],rx:this._def[0],ry:this._def[1]}:(this._def.cx=this._def.rx,this._def.cy=this._def.ry);break;case"path":"string"==typeof this._def&&(this._def={d:this._def})}Object.getOwnPropertyNames(this._def).forEach(function(t){this.$el.setAttributeNS(null,t,this._def[t])},this),this.svgStyle?Object.getOwnPropertyNames(this.svgStyle).forEach(function(t){this.$el.setAttributeNS(null,x.dasherize(t),this.svgStyle[t])},this):this.$el.setAttributeNS(null,"fill","rgba(0,0,0,0.5)"),this.psv.cleanPosition(this),this.position3D=this.psv.sphericalCoordsToVector3(this)},k.prototype._updatePoly=function(t,e){this._dynamicSize=!0,this.svgStyle?(Object.getOwnPropertyNames(this.svgStyle).forEach(function(t){this.$el.setAttributeNS(null,x.dasherize(t),this.svgStyle[t])},this),this.isPolyline()&&!this.svgStyle.fill&&this.$el.setAttributeNS(null,"fill","none")):this.isPolygon()?this.$el.setAttributeNS(null,"fill","rgba(0,0,0,0.5)"):this.isPolyline()&&(this.$el.setAttributeNS(null,"fill","none"),this.$el.setAttributeNS(null,"stroke","rgb(0,0,0)")),[this[t],this[e]].forEach(function(t){if(t&&"object"!=typeof t[0])for(var e=0;e0?" "+e:e,t.setAttribute("class",o)}},x.addClasses=function(t,e){e&&e.split(" ").forEach(function(e){x.toggleClass(t,e,!0)})},x.removeClasses=function(t,e){e&&e.split(" ").forEach(function(e){x.toggleClass(t,e,!1)})},x.hasParent=function(t,e){do{if(t===e)return!0}while(t=t.parentNode);return!1},x.getClosest=function(t,e){var i=t.matches||t.msMatchesSelector;do{if(i.bind(t)(e))return t}while(t=t.parentElement);return null},x.mouseWheelEvent=function(){return"onwheel"in document.createElement("div")?"wheel":void 0!==document.onmousewheel?"mousewheel":"DOMMouseScroll"},x.fullscreenEvent=function(){var t={exitFullscreen:"fullscreenchange",webkitExitFullscreen:"webkitfullscreenchange",mozCancelFullScreen:"mozfullscreenchange",msExitFullscreen:"MSFullscreenChange"};for(var e in t)if(t.hasOwnProperty(e)&&e in document)return t[e];return null},x.bound=function(t,e,i){return Math.max(e,Math.min(i,t))},x.isInteger=Number.isInteger||function(t){return"number"==typeof t&&isFinite(t)&&Math.floor(t)===t},x.sum=function(t){return t.reduce(function(t,e){return t+e},0)},x.dasherize=function(t){return t.replace(/[A-Z](?:(?=[^A-Z])|[A-Z]*(?=[A-Z][^A-Z]|$))/g,function(t,e){return(e>0?"-":"")+t.toLowerCase()})},x.getXMPValue=function(t,e){var i;return null!==(i=t.match("(.*)"))?i[1]:null!==(i=t.match("GPano:"+e+'="(.*?)"'))?i[1]:null},x.isFullscreenEnabled=function(t){return(document.fullscreenElement||document.mozFullScreenElement||document.webkitFullscreenElement||document.msFullscreenElement)===t},x.requestFullscreen=function(t){(t.requestFullscreen||t.mozRequestFullScreen||t.webkitRequestFullscreen||t.msRequestFullscreen).call(t)},x.exitFullscreen=function(){(document.exitFullscreen||document.mozCancelFullScreen||document.webkitExitFullscreen||document.msExitFullscreen).call(document)},x.getStyle=function(t,e){return window.getComputedStyle(t,null)[e]},x.getShortestArc=function(t,e){return[0,x.TwoPI,-x.TwoPI].reduce(function(i,o){return o=e-t+o,Math.abs(o)e?(s&&(clearTimeout(s),s=null),r=h,n=t.apply(i,o),s||(i=o=null)):s||(s=setTimeout(a,p)),n}},x.isPlainObject=function(t){if("object"==typeof t&&null!==t){if("function"==typeof Object.getPrototypeOf){var e=Object.getPrototypeOf(t);return e===Object.prototype||null===e}return"[object Object]"===Object.prototype.toString.call(t)}return!1},x.deepmerge=function(t,e){var i=e;return function t(e,o){return Array.isArray(o)?(e&&Array.isArray(e)?e.length=0:e=[],o.forEach(function(i,o){e[o]=t(null,i)})):"object"==typeof o?(e&&!Array.isArray(e)||(e={}),Object.keys(o).forEach(function(n){"object"==typeof o[n]&&o[n]&&x.isPlainObject(o[n])?o[n]!=i&&(e[n]?t(e[n],o[n]):e[n]=t(null,o[n])):e[n]=o[n]})):e=o,e}(t,e)},x.clone=function(t){return x.deepmerge(null,t)},x.normalizeWheel=function(t){var e=0,i=0,o=0,n=0;return"detail"in t&&(i=t.detail),"wheelDelta"in t&&(i=-t.wheelDelta/120),"wheelDeltaY"in t&&(i=-t.wheelDeltaY/120),"wheelDeltaX"in t&&(e=-t.wheelDeltaX/120),"axis"in t&&t.axis===t.HORIZONTAL_AXIS&&(e=i,i=0),o=10*e,n=10*i,"deltaY"in t&&(n=t.deltaY),"deltaX"in t&&(o=t.deltaX),(o||n)&&t.deltaMode&&(1===t.deltaMode?(o*=40,n*=40):(o*=800,n*=800)),o&&!e&&(e=o<1?-1:1),n&&!i&&(i=n<1?-1:1),{spinX:e,spinY:i,pixelX:o,pixelY:n}},x.forEach=function(t,e){for(var i in t)t.hasOwnProperty(i)&&e(t[i],i)},function(t){if(t.requestAnimationFrame=t.requestAnimationFrame||t.mozRequestAnimationFrame||t.webkitRequestAnimationFrame||t.msRequestAnimationFrame,t.cancelAnimationFrame=t.cancelAnimationFrame||t.mozCancelAnimationFrame||t.webkitCancelAnimationFrame||t.msCancelAnimationFrame,!t.requestAnimationFrame){var e,i=[],o=[],n=0;t.requestAnimationFrame=function(t){return i.push([++n,t]),e||(e=setInterval(function(){if(i.length){var t=+new Date,n=o;for(o=i,i=n;o.length;)o.shift()[1](t)}else clearInterval(e),e=void 0},20)),n},t.cancelAnimationFrame=function(t){var e,n;for(e=0,n=i.length;ethis.config.latitude_range[1]&&(this.config.latitude_range=[this.config.latitude_range[1],this.config.latitude_range[0]],console.warn("PhotoSphereViewer: latitude_range values must be ordered.")):void 0===this.config.tilt_up_max&&void 0===this.config.tilt_down_max||(this.config.latitude_range=[void 0!==this.config.tilt_down_max?this.config.tilt_down_max-Math.PI/4:-S.HalfPI,void 0!==this.config.tilt_up_max?this.config.tilt_up_max+Math.PI/4:S.HalfPI],console.warn("PhotoSphereViewer: tilt_up_max and tilt_down_max are deprecated, use latitude_range instead.")),this.config.max_fov"),o=t.substring(e,i);if(-1===e||-1===i||-1===o.indexOf("GPano:"))s.resolve(null);else{var n={full_width:parseInt(S.getXMPValue(o,"FullPanoWidthPixels")),full_height:parseInt(S.getXMPValue(o,"FullPanoHeightPixels")),cropped_width:parseInt(S.getXMPValue(o,"CroppedAreaImageWidthPixels")),cropped_height:parseInt(S.getXMPValue(o,"CroppedAreaImageHeightPixels")),cropped_x:parseInt(S.getXMPValue(o,"CroppedAreaLeftPixels")),cropped_y:parseInt(S.getXMPValue(o,"CroppedAreaTopPixels"))};n.full_width&&n.full_height&&n.cropped_width&&n.cropped_height?s.resolve(n):(console.warn("PhotoSphereViewer: invalid XMP data"),s.resolve(null))}}else 3===r.readyState&&this.loader.setProgress(a+=10)}.bind(this),r.onprogress=function(t){if(t.lengthComputable){var e=parseInt(t.loaded/t.total*100);ar[t]&&(r[t]=i,this.loader.setProgress(S.sum(r)/6),this.trigger("panorama-load-progress",n[t],r[t]))}},o=function(t,e){throw this.container.textContent="Cannot load image",s.reject(e),new x("Cannot load image "+t)},p=0;p<6;p++){if(this.config.cache_texture){var c=this.getPanoramaCache(n[p]);if(c){h++,r[p]=100,a[p]=c.image;continue}}t.load(n[p],e.bind(this,p),i.bind(this,p),o.bind(this,p))}return 6===h&&s.resolve(a),s.promise},d.prototype._setTexture=function(t){if(this.scene||this._createScene(),this.prop.isCubemap)for(var e=0;e<6;e++)this.mesh.material[e].map&&this.mesh.material[e].map.dispose(),this.mesh.material[e].map=t[e];else this.mesh.material.map&&this.mesh.material.map.dispose(),this.mesh.material.map=t;this.trigger("panorama-loaded"),this._render()},d.prototype._createScene=function(){this.raycaster=new l.Raycaster,this.renderer=d.SYSTEM.isWebGLSupported&&this.config.webgl?new l.WebGLRenderer:new l.CanvasRenderer,this.renderer.setSize(this.prop.size.width,this.prop.size.height),this.renderer.setPixelRatio(d.SYSTEM.pixelRatio);var t=d.SPHERE_RADIUS;this.prop.isCubemap&&(t*=Math.sqrt(3)),this.config.fisheye&&(t+=d.SPHERE_RADIUS),this.camera=new l.PerspectiveCamera(this.config.default_fov,this.prop.size.width/this.prop.size.height,1,t),this.camera.position.set(0,0,0),this.scene=new l.Scene,this.scene.add(this.camera),this.prop.isCubemap?this.mesh=this._createCubemap():this.mesh=this._createSphere(),this.scene.add(this.mesh),this.canvas_container=document.createElement("div"),this.canvas_container.className="psv-canvas-container",this.renderer.domElement.className="psv-canvas",this.container.appendChild(this.canvas_container),this.canvas_container.appendChild(this.renderer.domElement)},d.prototype._createSphere=function(t){t=t||1;var e=new l.SphereGeometry(d.SPHERE_RADIUS*t,d.SPHERE_VERTICES,d.SPHERE_VERTICES,-S.HalfPI),i=new l.MeshBasicMaterial({side:l.DoubleSide,overdraw:d.SYSTEM.isWebGLSupported&&this.config.webgl?0:1}),o=new l.Mesh(e,i);return o.scale.x=-1,o.rotation.x=this.config.sphere_correction.tilt,o.rotation.y=this.config.sphere_correction.pan,o.rotation.z=this.config.sphere_correction.roll,o},d.prototype._createCubemap=function(t){t=t||1;for(var e=new l.BoxGeometry(2*d.SPHERE_RADIUS*t,2*d.SPHERE_RADIUS*t,2*d.SPHERE_RADIUS*t,d.CUBE_VERTICES,d.CUBE_VERTICES,d.CUBE_VERTICES),i=[],o=0;o<6;o++)i.push(new l.MeshBasicMaterial({side:l.BackSide,overdraw:d.SYSTEM.isWebGLSupported&&this.config.webgl?0:1}));var n=new l.Mesh(e,i);return n.position.x-=d.SPHERE_RADIUS*t,n.position.y-=d.SPHERE_RADIUS*t,n.position.z-=d.SPHERE_RADIUS*t,n.applyMatrix((new l.Matrix4).makeScale(1,1,-1)),n},d.prototype._transition=function(i,t){var o;if(this.prop.isCubemap?(t&&(console.warn("PhotoSphereViewer: cannot perform cubemap transition to different position."),t=void 0),(o=this._createCubemap(.9)).material.forEach(function(t,e){t.map=i[e],t.transparent=!0,t.opacity=0})):((o=this._createSphere(.9)).material.map=i,o.material.transparent=!0,o.material.opacity=0),t){o.rotateY(t.longitude-this.prop.position.longitude);var e=new l.Vector3(0,1,0).cross(this.camera.getWorldDirection()).normalize(),n=(new l.Quaternion).setFromAxisAngle(e,t.latitude-this.prop.position.latitude);o.quaternion.multiplyQuaternions(n,o.quaternion),(this.config.latitude_range||this.config.longitude_range)&&(this.config.longitude_range=this.config.latitude_range=null,console.warn("PhotoSphereViewer: trying to perform transition with longitude_range and/or latitude_range, ranges cleared."))}return this.scene.add(o),this.needsUpdate(),S.animation({properties:{opacity:{start:0,end:1}},duration:this.config.transition.duration,easing:"outCubic",onTick:function(t){if(this.prop.isCubemap)for(var e=0;e<6;e++)o.material[e].opacity=t.opacity;else o.material.opacity=t.opacity;this.needsUpdate()}.bind(this)}).then(function(){this._setTexture(i),this.scene.remove(o),o.geometry.dispose(),o.geometry=null,t&&this.rotate(t)}.bind(this))},d.prototype._reverseAutorotate=function(){var e=this,t=-this.config.anim_speed,i=this.config.longitude_range;this.config.longitude_range=null,S.animation({properties:{speed:{start:this.config.anim_speed,end:0}},duration:300,easing:"inSine",onTick:function(t){e.config.anim_speed=t.speed}}).then(function(){return S.animation({properties:{speed:{start:0,end:t}},duration:300,easing:"outSine",onTick:function(t){e.config.anim_speed=t.speed}})}).then(function(){e.config.longitude_range=i,e.config.anim_speed=t})},d.prototype._putPanoramaCache=function(t){if(!this.config.cache_texture)throw new x("Cannot add panorama to cache, cache_texture is disabled");var e=this.getPanoramaCache(t.panorama);e?(e.image=t.image,e.pano_data=t.pano_data):(this.prop.cache=this.prop.cache.slice(0,this.config.cache_texture-1),this.prop.cache.unshift(t)),this.trigger("panorama-cached",t.panorama)},d.prototype._stopAll=function(){this.stopAutorotate(),this.stopAnimation(),this.stopGyroscopeControl(),this.stopStereoView()},d.MOVE_THRESHOLD=4,d.ANGLE_THRESHOLD=.003,d.DBLCLICK_DELAY=300,d.INERTIA_WINDOW=300,d.SPHERE_RADIUS=100,d.SPHERE_VERTICES=64,d.CUBE_VERTICES=8,d.CUBE_MAP=[0,2,4,5,3,1],d.CUBE_HASHMAP=["left","right","top","bottom","back","front"],d.SYSTEM={loaded:!1,pixelRatio:1,isWebGLSupported:!1,isCanvasSupported:!1,deviceOrientationSupported:null,maxTextureWidth:0,mouseWheelEvent:null,fullscreenEvent:null},d.ICONS={},d.DEFAULTS={panorama:null,container:null,caption:null,usexmpdata:!0,pano_data:null,webgl:!0,min_fov:30,max_fov:90,default_fov:null,default_long:0,default_lat:0,sphere_correction:{pan:0,tilt:0,roll:0},longitude_range:null,latitude_range:null,move_speed:1,zoom_speed:2,time_anim:2e3,anim_speed:"2rpm",anim_lat:null,fisheye:!1,navbar:["autorotate","zoom","download","markers","caption","gyroscope","stereo","fullscreen"],tooltip:{offset:5,arrow_size:7,delay:100},lang:{autorotate:"Automatic rotation",zoom:"Zoom",zoomOut:"Zoom out",zoomIn:"Zoom in",download:"Download",fullscreen:"Fullscreen",markers:"Markers",gyroscope:"Gyroscope",stereo:"Stereo view",stereo_notification:"Click anywhere to exit stereo view.",please_rotate:["Please rotate your device","(or tap to continue)"],two_fingers:["Use two fingers to navigate"]},mousewheel:!0,mousewheel_factor:1,mousemove:!0,mousemove_hover:!1,touchmove_two_fingers:!1,keyboard:{ArrowUp:"rotateLatitudeUp",ArrowDown:"rotateLatitudeDown",ArrowRight:"rotateLongitudeRight",ArrowLeft:"rotateLongitudeLeft",PageUp:"zoomIn",PageDown:"zoomOut","+":"zoomIn","-":"zoomOut"," ":"toggleAutorotate"},move_inertia:!0,click_event_on_marker:!1,transition:{duration:1500,loader:!0},loading_img:null,loading_txt:"Loading...",size:null,cache_texture:0,templates:{},markers:[],with_credentials:!1},d.TEMPLATES={markersList:'

{{= it.config.lang.markers }}

    {{~ it.markers: marker }}
  • {{? marker.image }}{{?}}

    {{? marker.tooltip }}{{= marker.tooltip.content }}{{?? marker.html }}{{= marker.html }}{{??}}{{= marker.id }}{{?}}

  • {{~}}
'},d.prototype._bindEvents=function(){window.addEventListener("resize",this),this.config.mousemove&&(this.hud.container.style.cursor="move",this.config.mousemove_hover?(this.hud.container.addEventListener("mouseenter",this),this.hud.container.addEventListener("mouseleave",this)):(this.hud.container.addEventListener("mousedown",this),window.addEventListener("mouseup",this)),this.hud.container.addEventListener("touchstart",this),window.addEventListener("touchend",this),this.hud.container.addEventListener("mousemove",this),this.hud.container.addEventListener("touchmove",this)),d.SYSTEM.fullscreenEvent&&document.addEventListener(d.SYSTEM.fullscreenEvent,this),this.config.mousewheel&&this.hud.container.addEventListener(d.SYSTEM.mouseWheelEvent,this),this.on("_side-reached",function(t){this.isAutorotateEnabled()&&("left"!==t&&"right"!==t||this._reverseAutorotate())})},d.prototype._unbindEvents=function(){window.removeEventListener("resize",this),this.config.mousemove&&(this.hud.container.removeEventListener("mousedown",this),this.hud.container.removeEventListener("mouseenter",this),this.hud.container.removeEventListener("touchstart",this),window.removeEventListener("mouseup",this),window.removeEventListener("touchend",this),this.hud.container.removeEventListener("mouseleave",this),this.hud.container.removeEventListener("mousemove",this),this.hud.container.removeEventListener("touchmove",this)),d.SYSTEM.fullscreenEvent&&document.removeEventListener(d.SYSTEM.fullscreenEvent,this),this.config.mousewheel&&this.hud.container.removeEventListener(d.SYSTEM.mouseWheelEvent,this),this.off("_side-reached")},d.prototype.handleEvent=function(t){switch(t.type){case"resize":S.throttle(this._onResize(),50);break;case"keydown":this._onKeyDown(t);break;case"mousedown":case"mouseenter":this._onMouseDown(t);break;case"touchstart":this._onTouchStart(t);break;case"mouseup":case"mouseleave":this._onMouseUp(t);break;case"touchend":this._onTouchEnd(t);break;case"mousemove":this._onMouseMove(t);break;case"touchmove":this._onTouchMove(t);break;case d.SYSTEM.fullscreenEvent:this._fullscreenToggled();break;case d.SYSTEM.mouseWheelEvent:this._onMouseWheel(t)}},d.prototype._onResize=function(){this.container.clientWidth===this.prop.size.width&&this.container.clientHeight===this.prop.size.height||(this.prop.size.width=parseInt(this.container.clientWidth),this.prop.size.height=parseInt(this.container.clientHeight),this.prop.aspect=this.prop.size.width/this.prop.size.height,this.needsUpdate(),this.renderer&&(this.stereoEffect||this.renderer).setSize(this.prop.size.width,this.prop.size.height),this.trigger("size-updated",this.getSize()))},d.prototype._onKeyDown=function(t){var e=0,i=0,o=0,n=S.getEventKey(t);switch(this.config.keyboard[n]){case"rotateLatitudeUp":i=.01;break;case"rotateLatitudeDown":i=-.01;break;case"rotateLongitudeRight":e=.01;break;case"rotateLongitudeLeft":e=-.01;break;case"zoomIn":o=1;break;case"zoomOut":o=-1;break;case"toggleAutorotate":this.toggleAutorotate()}0!==o?this.zoom(this.prop.zoom_lvl+o*this.config.zoom_speed):0===i&&0===e||this.rotate({longitude:this.prop.position.longitude+e*this.prop.move_speed*this.prop.hFov,latitude:this.prop.position.latitude+i*this.prop.move_speed*this.prop.vFov})},d.prototype._onMouseDown=function(t){this._startMove(t)},d.prototype._onMouseUp=function(t){this._stopMove(t),this.isStereoEnabled()&&this.stopStereoView()},d.prototype._onMouseMove=function(t){0!==t.buttons?(t.preventDefault(),this._move(t)):this.config.mousemove_hover&&this._moveAbsolute(t)},d.prototype._onTouchStart=function(t){1===t.touches.length?this.config.touchmove_two_fingers||this._startMove(t.touches[0]):2===t.touches.length&&this._startMoveZoom(t)},d.prototype._onTouchEnd=function(t){1===t.touches.length?this._stopMoveZoom():0===t.touches.length&&(this._stopMove(t.changedTouches[0]),this.config.touchmove_two_fingers&&this.overlay.hideOverlay())},d.prototype._onTouchMove=function(t){1===t.touches.length?this.config.touchmove_two_fingers?this.overlay.showOverlay({image:d.ICONS["gesture.svg"],text:this.config.lang.two_fingers[0]}):(t.preventDefault(),this._move(t.touches[0])):2===t.touches.length&&(t.preventDefault(),this._moveZoom(t))},d.prototype._startMove=function(t){this.stopAutorotate(),this.stopAnimation(),this.prop.mouse_x=this.prop.start_mouse_x=parseInt(t.clientX),this.prop.mouse_y=this.prop.start_mouse_y=parseInt(t.clientY),this.prop.moving=!0,this.prop.zooming=!1,this.prop.mouse_history.length=0,this._logMouseMove(t)},d.prototype._startMoveZoom=function(t){var e=[{x:parseInt(t.touches[0].clientX),y:parseInt(t.touches[0].clientY)},{x:parseInt(t.touches[1].clientX),y:parseInt(t.touches[1].clientY)}];this.prop.pinch_dist=Math.sqrt(Math.pow(e[0].x-e[1].x,2)+Math.pow(e[0].y-e[1].y,2)),this.prop.mouse_x=this.prop.start_mouse_x=(e[0].x+e[1].x)/2,this.prop.mouse_y=this.prop.start_mouse_x=(e[0].y+e[1].y)/2,this.prop.moving=!0,this.prop.zooming=!0},d.prototype._stopMove=function(t){S.getClosest(t.target,".psv-hud")&&this.prop.moving&&(Math.abs(t.clientX-this.prop.start_mouse_x)d.INERTIA_WINDOW/10?(this.prop.mouse_history.splice(0,o),o=0):o++,this.prop.mouse_history[0][o])},d.prototype.load=function(){if(!this.config.panorama)throw new x("No value given for panorama.");return this.setPanorama(this.config.panorama,!1)},d.prototype.getPosition=function(){return{longitude:this.prop.position.longitude,latitude:this.prop.position.latitude}},d.prototype.getZoomLevel=function(){return this.prop.zoom_lvl},d.prototype.getSize=function(){return{width:this.prop.size.width,height:this.prop.size.height}},d.prototype.isAutorotateEnabled=function(){return!!this.prop.autorotate_cb},d.prototype.isGyroscopeEnabled=function(){return!!this.prop.orientation_cb},d.prototype.isStereoEnabled=function(){return!!this.stereoEffect},d.prototype.isFullscreenEnabled=function(){return S.isFullscreenEnabled(this.container)},d.prototype.needsUpdate=function(){this.prop.needsUpdate=!0},d.prototype.render=function(){this._render()},d.prototype.destroy=function(){window.cancelAnimationFrame(this.prop.main_reqid),this._stopAll(),this.stopKeyboardControl(),this.stopNoSleep(),this.exitFullscreen(),this.unlockOrientation(),this._unbindEvents(),this.tooltip&&this.tooltip.destroy(),this.notification&&this.notification.destroy(),this.hud&&this.hud.destroy(),this.loader&&this.loader.destroy(),this.navbar&&this.navbar.destroy(),this.panel&&this.panel.destroy(),this.overlay&&this.overlay.destroy(),this.scene&&S.cleanTHREEScene(this.scene),this.canvas_container&&this.container.removeChild(this.canvas_container),this.parent.removeChild(this.container),delete this.parent.photoSphereViewer,delete this.parent,delete this.container,delete this.loader,delete this.navbar,delete this.hud,delete this.panel,delete this.tooltip,delete this.notification,delete this.overlay,delete this.canvas_container,delete this.renderer,delete this.noSleep,delete this.scene,delete this.camera,delete this.mesh,delete this.raycaster,delete this.passes,delete this.config,this.prop.cache.length=0},d.prototype.setPanorama=function(t,e,i){if(null!==this.prop.loading_promise)throw new x("Loading already in progress");return"boolean"==typeof e&&(i=e,e=void 0),e&&(this.cleanPosition(e),this._stopAll()),this.config.panorama=t,i&&this.config.transition&&this.scene?(this.config.transition.loader&&this.loader.show(),this.prop.loading_promise=this._loadTexture(this.config.panorama).then(function(t){return this.loader.hide(),this._transition(t,e)}.bind(this)).ensure(function(){this.loader.hide(),this.prop.loading_promise=null}.bind(this)).rethrow()):(this.loader.show(),this.canvas_container&&(this.canvas_container.style.opacity=0),this.prop.loading_promise=this._loadTexture(this.config.panorama).then(function(t){this._setTexture(t),e&&this.rotate(e)}.bind(this)).ensure(function(){this.loader.hide(),this.canvas_container.style.opacity=1,this.prop.loading_promise=null}.bind(this)).rethrow()),this.prop.loading_promise},d.prototype.startAutorotate=function(){this._stopAll(),this.prop.autorotate_cb=this._getAutorotateUpdate(),this.on("before-render",this.prop.autorotate_cb),this.trigger("autorotate",!0)},d.prototype._getAutorotateUpdate=function(){var e,i;return function(t){i=void 0===e?0:t-e,e=t,this.rotate({longitude:this.prop.position.longitude+this.config.anim_speed*i/1e3,latitude:this.prop.position.latitude-(this.prop.position.latitude-this.config.anim_lat)/200})}},d.prototype.stopAutorotate=function(){this.prop.start_timeout&&(window.clearTimeout(this.prop.start_timeout),this.prop.start_timeout=null),this.isAutorotateEnabled()&&(this.off("before-render",this.prop.autorotate_cb),this.prop.autorotate_cb=null,this.trigger("autorotate",!1))},d.prototype.toggleAutorotate=function(){this.isAutorotateEnabled()?this.stopAutorotate():this.startAutorotate()},d.prototype.startGyroscopeControl=function(){if(S.checkTHREE("DeviceOrientationControls"))return d.SYSTEM.deviceOrientationSupported.then(function(t){if(!t)return console.warn("PhotoSphereViewer: gyroscope not available"),u.rejected();this._stopAll(),this.doControls=new l.DeviceOrientationControls(this.camera),this.doControls.alphaOffset=this.prop.position.longitude,this.doControls.update();var e=this.camera.getWorldDirection(new l.Vector3),i=this.vector3ToSphericalCoords(e);this.prop.gyro_alpha_offset=i.longitude,this.prop.orientation_cb=this._getOrientationUpdate(),this.on("before-render",this.prop.orientation_cb),this.trigger("gyroscope-updated",!0)}.bind(this));throw new x("Missing Three.js components: DeviceOrientationControls. Get them from three.js-examples package.")},d.prototype._getOrientationUpdate=function(){return function(){this.doControls.alphaOffset=this.prop.gyro_alpha_offset,this.doControls.update(),this.camera.getWorldDirection(this.prop.direction),this.prop.direction.multiplyScalar(d.SPHERE_RADIUS);var t=this.vector3ToSphericalCoords(this.prop.direction);this.prop.position.longitude=t.longitude,this.prop.position.latitude=t.latitude,this.needsUpdate()}},d.prototype.stopGyroscopeControl=function(){this.isGyroscopeEnabled()&&(this.off("before-render",this.prop.orientation_cb),this.prop.orientation_cb=null,this.doControls.disconnect(),this.doControls=null,this.trigger("gyroscope-updated",!1))},d.prototype.toggleGyroscopeControl=function(){this.isGyroscopeEnabled()?this.stopGyroscopeControl():this.startGyroscopeControl()},d.prototype.startNoSleep=function(){"NoSleep"in window?(this.noSleep||(this.noSleep=new NoSleep),this.noSleep.enable()):console.warn("PhotoSphereViewer: NoSleep is not available")},d.prototype.stopNoSleep=function(){this.noSleep&&this.noSleep.disable()},d.prototype.startStereoView=function(){if(!S.checkTHREE("DeviceOrientationControls","StereoEffect"))throw new x("Missing Three.js components: StereoEffect, DeviceOrientationControls. Get them from three.js-examples package.");this.startNoSleep(),this.enterFullscreen(),this.lockOrientation(),this.startGyroscopeControl().then(function(){this.stereoEffect=new l.StereoEffect(this.renderer),this.needsUpdate(),this.hud.hide(),this.navbar.hide(),this.panel.hidePanel(),this.trigger("stereo-updated",!0),this.notification.showNotification({content:this.config.lang.stereo_notification,timeout:3e3})}.bind(this),function(){this.unlockOrientation(),this.exitFullscreen(),this.stopNoSleep()}.bind(this))},d.prototype.stopStereoView=function(){this.isStereoEnabled()&&(this.stereoEffect=null,this.needsUpdate(),this.hud.show(),this.navbar.show(),this.unlockOrientation(),this.exitFullscreen(),this.stopNoSleep(),this.stopGyroscopeControl(),this.trigger("stereo-updated",!1))},d.prototype.lockOrientation=function(){var t,e=function(){this.isStereoEnabled()&&window.innerHeight>window.innerWidth&&this.overlay.showOverlay({image:d.ICONS["mobile-rotate.svg"],text:this.config.lang.please_rotate[0],subtext:this.config.lang.please_rotate[1]}),t&&window.clearTimeout(t)};window.screen&&window.screen.orientation?(window.screen.orientation.lock("landscape").then(null,e.bind(this)),t=setTimeout(e.bind(this),500)):e.apply(this)},d.prototype.unlockOrientation=function(){window.screen&&window.screen.orientation?window.screen.orientation.unlock():this.overlay.hideOverlay()},d.prototype.toggleStereoView=function(){this.isStereoEnabled()?this.stopStereoView():this.startStereoView()},d.prototype.rotate=function(t){this.cleanPosition(t),this.applyRanges(t).forEach(this.trigger.bind(this,"_side-reached")),this.prop.position.longitude=t.longitude,this.prop.position.latitude=t.latitude,this.needsUpdate(),this.trigger("position-updated",this.getPosition())},d.prototype.animate=function(t,e){if(this._stopAll(),this.cleanPosition(t),!e||Math.abs(t.longitude-this.prop.position.longitude)=Math.PI?e-Math.PI:e+Math.PI,latitude:S.HalfPI-i}},d.prototype.sphericalCoordsToTextureCoords=function(t){if(this.prop.isCubemap)throw new x("Unable to use texture coords with cubemap.");var e=t.longitude/S.TwoPI*this.prop.pano_data.full_width,i=t.latitude/Math.PI*this.prop.pano_data.full_height;return{x:parseInt(t.longitudee[1]?t.longitude>e[1]&&t.longitudee[0]/2+e[1]/2?(t.longitude=e[0],o.push("left")):(t.longitude=e[1],o.push("right"))):t.longitudee[1]&&(t.longitude=e[1],o.push("right"))),this.config.latitude_range&&(e=S.clone(this.config.latitude_range),i=l.Math.degToRad(this.prop.vFov)/2,e[0]=S.parseAngle(Math.min(e[0]+i,e[1]),!0),e[1]=S.parseAngle(Math.max(e[1]-i,e[0]),!0),t.latitudee[1]&&(t.latitude=e[1],o.push("top"))),o},n.className=null,n.publicMethods=[],n.prototype.create=function(){this.container=document.createElement("div"),this.constructor.className&&(this.container.className=this.constructor.className),this.parent.container.appendChild(this.container)},n.prototype.destroy=function(){this.parent.container.removeChild(this.container),this.constructor.publicMethods&&this.constructor.publicMethods.forEach(function(t){delete this.psv[t]},this),delete this.container,delete this.psv,delete this.parent},n.prototype.hide=function(){this.container.style.display="none",this.visible=!1},n.prototype.show=function(){this.container.style.display="",this.visible=!0},((s.prototype=Object.create(n.prototype)).constructor=s).className="psv-hud",s.publicMethods=["addMarker","removeMarker","updateMarker","clearMarkers","getMarker","getCurrentMarker","gotoMarker","hideMarker","showMarker","toggleMarker","toggleMarkersList","showMarkersList","hideMarkersList"],s.prototype.create=function(){n.prototype.create.call(this),this.svgContainer=document.createElementNS(S.svgNS,"svg"),this.svgContainer.setAttribute("class","psv-hud-svg-container"),this.container.appendChild(this.svgContainer),this.container.addEventListener("mouseenter",this,!0),this.container.addEventListener("mouseleave",this,!0),this.container.addEventListener("mousemove",this,!0),this.psv.on("click",this),this.psv.on("dblclick",this),this.psv.on("render",this),this.psv.on("open-panel",this),this.psv.on("close-panel",this)},s.prototype.destroy=function(){this.clearMarkers(!1),this.container.removeEventListener("mouseenter",this),this.container.removeEventListener("mouseleave",this),this.container.removeEventListener("mousemove",this),this.psv.off("click",this),this.psv.off("dblclick",this),this.psv.off("render",this),this.psv.off("open-panel",this),this.psv.off("close-panel",this),delete this.svgContainer,n.prototype.destroy.call(this)},s.prototype.handleEvent=function(t){switch(t.type){case"mouseenter":this._onMouseEnter(t);break;case"mouseleave":this._onMouseLeave(t);break;case"mousemove":this._onMouseMove(t);break;case"click":this._onClick(t.args[0],t,!1);break;case"dblclick":this._onClick(t.args[0],t,!0);break;case"render":this.renderMarkers();break;case"open-panel":this._onPanelOpened();break;case"close-panel":this._onPanelClosed()}},s.prototype.addMarker=function(t,e){if(!t.id)throw new x("missing marker id");if(this.markers[t.id])throw new x('marker "'+t.id+'" already exists');var i=new k(t,this.psv);return i.isNormal()?this.container.appendChild(i.$el):this.svgContainer.appendChild(i.$el),this.markers[i.id]=i,!1!==e&&this.renderMarkers(),i},s.prototype.getMarker=function(t){var e="object"==typeof t?t.id:t;if(!this.markers[e])throw new x('cannot find marker "'+e+'"');return this.markers[e]},s.prototype.getCurrentMarker=function(){return this.currentMarker},s.prototype.updateMarker=function(t,e){var i=this.getMarker(t);return i.update(t),!1!==e&&this.renderMarkers(),i},s.prototype.removeMarker=function(t,e){(t=this.getMarker(t)).isNormal()?this.container.removeChild(t.$el):this.svgContainer.removeChild(t.$el),this.hoveringMarker===t&&this.psv.tooltip.hideTooltip(),t.destroy(),delete this.markers[t.id],!1!==e&&this.renderMarkers()},s.prototype.clearMarkers=function(t){Object.keys(this.markers).forEach(function(t){this.removeMarker(t,!1)},this),!1!==t&&this.renderMarkers()},s.prototype.gotoMarker=function(t,e){return t=this.getMarker(t),this.psv.animate(t,e).then(function(){this.psv.trigger("goto-marker-done",t)}.bind(this))},s.prototype.hideMarker=function(t){this.getMarker(t).visible=!1,this.renderMarkers()},s.prototype.showMarker=function(t){this.getMarker(t).visible=!0,this.renderMarkers()},s.prototype.toggleMarker=function(t){this.getMarker(t).visible^=!0,this.renderMarkers()},s.prototype.toggleMarkersList=function(){this.prop.panelOpened?this.hideMarkersList():this.showMarkersList()},s.prototype.showMarkersList=function(){var e=[];S.forEach(this.markers,function(t){e.push(t)});var t=this.psv.config.templates.markersList({markers:this.psv.change("render-markers-list",e),config:this.psv.config});this.prop.panelOpening=!0,this.psv.panel.showPanel(t,!0),this.psv.panel.container.querySelector(".psv-markers-list").addEventListener("click",this._onClickItem.bind(this))},s.prototype.hideMarkersList=function(){this.prop.panelOpened&&this.psv.panel.hidePanel()},s.prototype.renderMarkers=function(){if(this.visible){var r=this.psv.isGyroscopeEnabled()?l.Math.radToDeg(this.psv.camera.rotation.z):0;S.forEach(this.markers,function(t){var e=t.visible;if(e&&t.isPoly()){var i=this._getPolyPositions(t);if(e=i.length>(t.isPolygon()?2:1)){t.position2D=this._getPolyDimensions(t,i);var o=i.map(function(t){return t.x+","+t.y}).join(" ");t.$el.setAttributeNS(null,"points",o)}}else if(e){var n=this._getMarkerPosition(t);if(e=this._isMarkerVisible(t,n)){t.position2D=n;var s=t.getScale(this.psv.getZoomLevel());t.isSvg()?t.$el.setAttributeNS(null,"transform","translate("+n.x+", "+n.y+")"+(1!==s?" scale("+s+", "+s+")":"")+(!t.lockRotation&&r?" rotate("+r+")":"")):t.$el.style.transform="translate3D("+n.x+"px, "+n.y+"px, 0px)"+(1!==s?" scale("+s+", "+s+")":"")+(!t.lockRotation&&r?" rotateZ("+r+"deg)":"")}}S.toggleClass(t.$el,"psv-marker--visible",e)}.bind(this))}},s.prototype._isMarkerVisible=function(t,e){return 0=this.prop.width?(this.button.hide(),this.content.style.display=""):(this.button.show(),this.content.style.display="none")},((h.prototype=Object.create(n.prototype)).constructor=h).className="psv-notification",h.publicMethods=["showNotification","hideNotification","isNotificationVisible"],h.prototype.create=function(){n.prototype.create.call(this),this.content=document.createElement("div"),this.content.className="psv-notification-content",this.container.appendChild(this.content),this.content.addEventListener("click",this.hideNotification.bind(this))},h.prototype.destroy=function(){delete this.content,n.prototype.destroy.call(this)},h.prototype.isNotificationVisible=function(){return this.container.classList.contains("psv-notification--visible")},h.prototype.showNotification=function(t){"string"==typeof t&&(t={content:t}),this.content.innerHTML=t.content,this.container.classList.add("psv-notification--visible"),this.psv.trigger("show-notification"),t.timeout&&setTimeout(this.hideNotification.bind(this),t.timeout)},h.prototype.hideNotification=function(){this.isNotificationVisible()&&(this.container.classList.remove("psv-notification--visible"),this.psv.trigger("hide-notification"))},((p.prototype=Object.create(n.prototype)).constructor=p).className="psv-overlay",p.publicMethods=["showOverlay","hideOverlay","isOverlayVisible"],p.prototype.create=function(){n.prototype.create.call(this),this.image=document.createElement("div"),this.image.className="psv-overlay-image",this.container.appendChild(this.image),this.text=document.createElement("div"),this.text.className="psv-overlay-text",this.container.appendChild(this.text),this.subtext=document.createElement("div"),this.subtext.className="psv-overlay-subtext",this.container.appendChild(this.subtext),this.container.addEventListener("click",this.hideOverlay.bind(this))},p.prototype.destroy=function(){delete this.image,delete this.text,delete this.subtext,n.prototype.destroy.call(this)},p.prototype.isOverlayVisible=function(){return this.visible},p.prototype.showOverlay=function(t){"string"==typeof t&&(t={text:t}),this.image.innerHTML=t.image||"",this.text.innerHTML=t.text||"",this.subtext.innerHTML=t.subtext||"",this.show(),this.psv.trigger("show-overlay")},p.prototype.hideOverlay=function(){this.isOverlayVisible()&&(this.hide(),this.psv.trigger("hide-overlay"))},((c.prototype=Object.create(n.prototype)).constructor=c).className="psv-panel",c.publicMethods=["showPanel","hidePanel"],c.prototype.create=function(){n.prototype.create.call(this),this.container.innerHTML='
',this.content=this.container.querySelector(".psv-panel-content"),this.container.querySelector(".psv-panel-close-button").addEventListener("click",this.hidePanel.bind(this)),this.psv.config.mousewheel&&this.container.addEventListener(d.SYSTEM.mouseWheelEvent,function(t){t.stopPropagation()});var t=this.container.querySelector(".psv-panel-resizer");t.addEventListener("mousedown",this),t.addEventListener("touchstart",this),this.psv.container.addEventListener("mouseup",this),this.psv.container.addEventListener("touchend",this),this.psv.container.addEventListener("mousemove",this),this.psv.container.addEventListener("touchmove",this)},c.prototype.destroy=function(){this.psv.container.removeEventListener("mousemove",this),this.psv.container.removeEventListener("touchmove",this),this.psv.container.removeEventListener("mouseup",this),this.psv.container.removeEventListener("touchend",this),delete this.prop,delete this.content,n.prototype.destroy.call(this)},c.prototype.handleEvent=function(t){switch(t.type){case"mousedown":this._onMouseDown(t);break;case"touchstart":this._onTouchStart(t);break;case"mousemove":this._onMouseMove(t);break;case"touchmove":this._onTouchMove(t);break;case"mouseup":case"touchend":this._onMouseUp(t)}},c.prototype.showPanel=function(t,e){this.content.innerHTML=t,this.content.scrollTop=0,this.container.classList.add("psv-panel--open"),S.toggleClass(this.content,"psv-panel-content--no-margin",!0===e),this.prop.opened=!0,this.psv.trigger("open-panel")},c.prototype.hidePanel=function(){this.content.innerHTML=null,this.prop.opened=!1,this.container.classList.remove("psv-panel--open"),this.psv.trigger("close-panel")},c.prototype._onMouseDown=function(t){t.stopPropagation(),this._startResize(t)},c.prototype._onTouchStart=function(t){t.stopPropagation(),this._startResize(t.changedTouches[0])},c.prototype._onMouseUp=function(t){this.prop.mousedown&&(t.stopPropagation(),this.prop.mousedown=!1,this.content.classList.remove("psv-panel-content--no-interaction"))},c.prototype._onMouseMove=function(t){this.prop.mousedown&&(t.stopPropagation(),this._resize(t))},c.prototype._onTouchMove=function(t){this.prop.mousedown&&this._resize(t.touches[0])},c.prototype._startResize=function(t){this.prop.mouse_x=parseInt(t.clientX),this.prop.mouse_y=parseInt(t.clientY),this.prop.mousedown=!0,this.content.classList.add("psv-panel-content--no-interaction")},c.prototype._resize=function(t){var e=parseInt(t.clientX),i=parseInt(t.clientY);this.container.style.width=this.container.offsetWidth-(e-this.prop.mouse_x)+"px",this.prop.mouse_x=e,this.prop.mouse_y=i},((f.prototype=Object.create(n.prototype)).constructor=f).className="psv-tooltip",f.publicMethods=["showTooltip","hideTooltip","isTooltipVisible"],f.leftMap={0:"left",.5:"center",1:"right"},f.topMap={0:"top",.5:"center",1:"bottom"},f.prototype.create=function(){n.prototype.create.call(this),this.container.innerHTML='
',this.container.style.top="-1000px",this.container.style.left="-1000px",this.content=this.container.querySelector(".psv-tooltip-content"),this.arrow=this.container.querySelector(".psv-tooltip-arrow"),this.psv.on("render",this)},f.prototype.destroy=function(){this.psv.off("render",this),delete this.config,delete this.prop,n.prototype.destroy.call(this)},f.prototype.handleEvent=function(t){switch(t.type){case"render":this.hideTooltip()}},f.prototype.isTooltipVisible=function(){return this.container.classList.contains("psv-tooltip--visible")},f.prototype.showTooltip=function(t){this.prop.timeout&&(window.clearTimeout(this.prop.timeout),this.prop.timeout=null);var e=this.isTooltipVisible(),i=this.container,o=this.content,n=this.arrow;if(t.position||(t.position=["top","center"]),t.box||(t.box={width:0,height:0}),"string"==typeof t.position){var s=S.parsePosition(t.position);if(!(s.left in f.leftMap&&s.top in f.topMap))throw new x('unable to parse tooltip position "'+t.position+'"');t.position=[f.topMap[s.top],f.leftMap[s.left]]}if("center"===t.position[0]&&"center"===t.position[1])throw new x('unable to parse tooltip position "center center"');if(e)for(var r=i.classList.length-1;0<=r;r--){var a=i.classList.item(r);"psv-tooltip"!==a&&"psv-tooltip--visible"!==a&&i.classList.remove(a)}else i.className="psv-tooltip";t.className&&S.addClasses(i,t.className),o.innerHTML=t.content,i.style.top="0px",i.style.left="0px";var h=i.getBoundingClientRect(),p={posClass:t.position.slice(),width:h.right-h.left,height:h.bottom-h.top,top:0,left:0,arrow_top:0,arrow_left:0};this._computeTooltipPosition(p,t);var c=!1;p.topthis.psv.prop.size.height-this.config.offset&&(p.posClass[0]="top",c=!0),p.leftthis.psv.prop.size.width-this.config.offset&&(p.posClass[1]="left",c=!0),c&&this._computeTooltipPosition(p,t),i.style.top=p.top+"px",i.style.left=p.left+"px",n.style.top=p.arrow_top+"px",n.style.left=p.arrow_left+"px",i.classList.add("psv-tooltip--"+p.posClass.join("-")),e||(this.prop.timeout=window.setTimeout(function(){i.classList.add("psv-tooltip--visible"),this.prop.timeout=null,this.psv.trigger("show-tooltip")}.bind(this),this.config.delay))},f.prototype.hideTooltip=function(){this.prop.timeout&&(window.clearTimeout(this.prop.timeout),this.prop.timeout=null),this.isTooltipVisible()&&(this.container.classList.remove("psv-tooltip--visible"),this.prop.timeout=window.setTimeout(function(){this.content.innerHTML=null,this.container.style.top="-1000px",this.container.style.left="-1000px",this.prop.timeout=null}.bind(this),this.config.delay),this.psv.trigger("hide-tooltip"))},f.prototype._computeTooltipPosition=function(t,e){var i=!1;switch(t.posClass[0]){case"bottom":t.top=e.top+e.box.height+this.config.offset+this.config.arrow_size,t.arrow_top=2*-this.config.arrow_size,i=!0;break;case"center":t.top=e.top+e.box.height/2-t.height/2,t.arrow_top=t.height/2-this.config.arrow_size;break;case"top":t.top=e.top-t.height-this.config.offset-this.config.arrow_size,t.arrow_top=t.height,i=!0}switch(t.posClass[1]){case"right":t.arrow_left=i?(t.left=e.left+e.box.width/2-this.config.offset-this.config.arrow_size,this.config.offset):(t.left=e.left+e.box.width+this.config.offset+this.config.arrow_size,2*-this.config.arrow_size);break;case"center":t.left=e.left+e.box.width/2-t.width/2,t.arrow_left=t.width/2-this.config.arrow_size;break;case"left":t.arrow_left=i?(t.left=e.left-t.width+e.box.width/2+this.config.offset+this.config.arrow_size,t.width-this.config.offset-2*this.config.arrow_size):(t.left=e.left-t.width-this.config.offset-this.config.arrow_size,t.width)}},((g.prototype=Object.create(n.prototype)).constructor=g).id=null,g.icon=null,g.iconActive=null,g.prototype.create=function(){n.prototype.create.call(this),this.constructor.icon&&this._setIcon(this.constructor.icon),this.id&&this.psv.config.lang[this.id]&&(this.container.title=this.psv.config.lang[this.id]),this.container.addEventListener("click",function(t){this.enabled&&this._onClick(),t.stopPropagation()}.bind(this));var t=this.supported();"function"==typeof t.then?(this.hide(),t.then(function(t){t&&this.show()}.bind(this))):t||this.hide()},g.prototype.destroy=function(){n.prototype.destroy.call(this)},g.prototype.supported=function(){return!0},g.prototype.toggleActive=function(t){S.toggleClass(this.container,"psv-button--active",t),this.constructor.iconActive&&this._setIcon(t?this.constructor.iconActive:this.constructor.icon)},g.prototype.disable=function(){this.container.classList.add("psv-button--disabled"),this.enabled=!1},g.prototype.enable=function(){this.container.classList.remove("psv-button--disabled"),this.enabled=!0},g.prototype._setIcon=function(t,e){e||(e=this.container),t?(e.innerHTML=d.ICONS[t],e.querySelector("svg").setAttribute("class","psv-button-svg")):e.innerHTML=""},g.prototype._onClick=function(){},((i.prototype=Object.create(g.prototype)).constructor=i).id="autorotate",i.className="psv-button psv-button--hover-scale psv-autorotate-button",i.icon="play.svg",i.iconActive="play-active.svg",i.prototype.create=function(){g.prototype.create.call(this),this.psv.on("autorotate",this)},i.prototype.destroy=function(){this.psv.off("autorotate",this),g.prototype.destroy.call(this)},i.prototype.handleEvent=function(t){switch(t.type){case"autorotate":this.toggleActive(t.args[0])}},i.prototype._onClick=function(){this.psv.toggleAutorotate()},((m.prototype=Object.create(g.prototype)).constructor=m).id="markers",m.className="psv-button psv-button--hover-scale psv-caption-button",m.icon="info.svg",m.prototype.create=function(){g.prototype.create.call(this),this.psv.on("hide-notification",this)},m.prototype.destroy=function(){this.psv.off("hide-notification",this),g.prototype.destroy.call(this)},m.prototype.handleEvent=function(t){switch(t.type){case"hide-notification":this.toggleActive(!1)}},m.prototype._onClick=function(){this.psv.isNotificationVisible()?this.psv.hideNotification():(this.psv.showNotification(this.parent.prop.caption),this.toggleActive(!0))},((v.prototype=Object.create(g.prototype)).constructor=v).className="psv-button psv-custom-button",v.prototype.create=function(){g.prototype.create.call(this),this.config.className&&S.addClasses(this.container,this.config.className),this.config.title&&(this.container.title=this.config.title),this.config.content&&(this.container.innerHTML=this.config.content),!1!==this.config.enabled&&!0!==this.config.disabled||this.disable(),!1!==this.config.visible&&!0!==this.config.hidden||this.hide()},v.prototype.destroy=function(){delete this.config,g.prototype.destroy.call(this)},v.prototype._onClick=function(){this.config.onClick&&this.config.onClick.apply(this.psv)},((y.prototype=Object.create(g.prototype)).constructor=y).id="download",y.className="psv-button psv-button--hover-scale psv-download-button",y.icon="download.svg",y.prototype._onClick=function(){var t=document.createElement("a");t.href=this.psv.config.panorama,t.download=this.psv.config.panorama,this.psv.container.appendChild(t),t.click()},((_.prototype=Object.create(g.prototype)).constructor=_).id="fullscreen",_.className="psv-button psv-button--hover-scale psv-fullscreen-button",_.icon="fullscreen-in.svg",_.iconActive="fullscreen-out.svg",_.prototype.create=function(){g.prototype.create.call(this),this.psv.on("fullscreen-updated",this)},_.prototype.destroy=function(){this.psv.off("fullscreen-updated",this),g.prototype.destroy.call(this)},_.prototype.supported=function(){return!!d.SYSTEM.fullscreenEvent},_.prototype.handleEvent=function(t){switch(t.type){case"fullscreen-updated":this.toggleActive(t.args[0])}},_.prototype._onClick=function(){this.psv.toggleFullscreen()},((w.prototype=Object.create(g.prototype)).constructor=w).id="gyroscope",w.className="psv-button psv-button--hover-scale psv-gyroscope-button",w.icon="compass.svg",w.prototype.create=function(){g.prototype.create.call(this),this.psv.on("gyroscope-updated",this)},w.prototype.destroy=function(){this.psv.off("gyroscope-updated",this),g.prototype.destroy.call(this)},w.prototype.supported=function(){return!!S.checkTHREE("DeviceOrientationControls")&&d.SYSTEM.deviceOrientationSupported},w.prototype.handleEvent=function(t){switch(t.type){case"gyroscope-updated":this.toggleActive(t.args[0])}},w.prototype._onClick=function(){this.psv.toggleGyroscopeControl()},((b.prototype=Object.create(g.prototype)).constructor=b).id="markers",b.className="psv-button psv-button--hover-scale psv-markers-button",b.icon="pin.svg",b.prototype._onClick=function(){this.psv.hud.toggleMarkersList()},((E.prototype=Object.create(g.prototype)).constructor=E).id="stereo",E.className="psv-button psv-button--hover-scale psv-stereo-button",E.icon="stereo.svg",E.prototype.create=function(){g.prototype.create.call(this),this.psv.on("stereo-updated",this)},E.prototype.destroy=function(){this.psv.off("stereo-updated",this),g.prototype.destroy.call(this)},E.prototype.supported=function(){return!(!d.SYSTEM.fullscreenEvent||!S.checkTHREE("DeviceOrientationControls"))&&d.SYSTEM.deviceOrientationSupported},E.prototype.handleEvent=function(t){switch(t.type){case"stereo-updated":this.toggleActive(t.args[0])}},E.prototype._onClick=function(){this.psv.toggleStereoView()},((M.prototype=Object.create(g.prototype)).constructor=M).id="zoom",M.className="psv-button psv-zoom-button",M.prototype.create=function(){g.prototype.create.call(this);var t=document.createElement("div");t.className="psv-zoom-button-minus",t.title=this.psv.config.lang.zoomOut,this._setIcon("zoom-out.svg",t),this.container.appendChild(t);var e=document.createElement("div");e.className="psv-zoom-button-range",this.container.appendChild(e),this.zoom_range=document.createElement("div"),this.zoom_range.className="psv-zoom-button-line",e.appendChild(this.zoom_range),this.zoom_value=document.createElement("div"),this.zoom_value.className="psv-zoom-button-handle",this.zoom_range.appendChild(this.zoom_value);var i=document.createElement("div");i.className="psv-zoom-button-plus",i.title=this.psv.config.lang.zoomIn,this._setIcon("zoom-in.svg",i),this.container.appendChild(i),this.zoom_range.addEventListener("mousedown",this),this.zoom_range.addEventListener("touchstart",this),this.psv.container.addEventListener("mousemove",this),this.psv.container.addEventListener("touchmove",this),this.psv.container.addEventListener("mouseup",this),this.psv.container.addEventListener("touchend",this),t.addEventListener("mousedown",this._zoomOut.bind(this)),i.addEventListener("mousedown",this._zoomIn.bind(this)),this.psv.on("zoom-updated",this),this.psv.once("ready",function(){this._moveZoomValue(this.psv.prop.zoom_lvl)}.bind(this))},M.prototype.destroy=function(){this._stopZoomChange(),this.psv.container.removeEventListener("mousemove",this),this.psv.container.removeEventListener("touchmove",this),this.psv.container.removeEventListener("mouseup",this),this.psv.container.removeEventListener("touchend",this),delete this.zoom_range,delete this.zoom_value,this.psv.off("zoom-updated",this),g.prototype.destroy.call(this)},M.prototype.handleEvent=function(t){switch(t.type){case"mousedown":this._initZoomChangeWithMouse(t);break;case"touchstart":this._initZoomChangeByTouch(t);break;case"mousemove":this._changeZoomWithMouse(t);break;case"touchmove":this._changeZoomByTouch(t);break;case"mouseup":case"touchend":this._stopZoomChange(t);break;case"zoom-updated":this._moveZoomValue(t.args[0])}},M.prototype._moveZoomValue=function(t){this.zoom_value.style.left=t/100*this.zoom_range.offsetWidth-this.zoom_value.offsetWidth/2+"px"},M.prototype._initZoomChangeWithMouse=function(t){this.enabled&&(this.prop.mousedown=!0,this._changeZoom(t.clientX))},M.prototype._initZoomChangeByTouch=function(t){this.enabled&&(this.prop.mousedown=!0,this._changeZoom(t.changedTouches[0].clientX))},M.prototype._zoomIn=function(){this.enabled&&(this.prop.buttondown=!0,this.psv.zoomIn(),this.prop.longPressTimeout=window.setTimeout(this._startLongPressInterval.bind(this,1),200))},M.prototype._zoomOut=function(){this.enabled&&(this.prop.buttondown=!0,this.psv.zoomOut(),this.prop.longPressTimeout=window.setTimeout(this._startLongPressInterval.bind(this,-1),200))},M.prototype._startLongPressInterval=function(t){this.prop.buttondown&&(this.prop.longPressInterval=window.setInterval(function(){this.psv.zoom(this.psv.prop.zoom_lvl+t)}.bind(this),50))},M.prototype._stopZoomChange=function(){this.enabled&&(window.clearInterval(this.prop.longPressInterval),window.clearTimeout(this.prop.longPressTimeout),this.prop.longPressInterval=null,this.prop.mousedown=!1,this.prop.buttondown=!1)},M.prototype._changeZoomWithMouse=function(t){this.enabled&&(t.preventDefault(),this._changeZoom(t.clientX))},M.prototype._changeZoomByTouch=function(t){this.enabled&&this._changeZoom(t.changedTouches[0].clientX)},M.prototype._changeZoom=function(t){if(this.prop.mousedown){var e=(parseInt(t)-this.zoom_range.getBoundingClientRect().left)/this.zoom_range.offsetWidth*100;this.psv.zoom(e)}},(x.prototype=Object.create(Error.prototype)).name="PSVError",d.Error=x.prototype.constructor=x,k.types=["image","html","polygon_px","polygon_rad","polyline_px","polyline_rad","rect","circle","ellipse","path"],k.getType=function(e,t){var i=[];if(k.types.forEach(function(t){e[t]&&i.push(t)}),0===i.length&&!t)throw new x("missing marker content, either "+k.types.join(", "));if(1(.*)"))?i[1]:null!==(i=t.match("GPano:"+e+'="(.*?)"'))?i[1]:null},S.isFullscreenEnabled=function(t){return(document.fullscreenElement||document.mozFullScreenElement||document.webkitFullscreenElement||document.msFullscreenElement)===t},S.requestFullscreen=function(t){(t.requestFullscreen||t.mozRequestFullScreen||t.webkitRequestFullscreen||t.msRequestFullscreen).call(t)},S.exitFullscreen=function(){(document.exitFullscreen||document.mozCancelFullScreen||document.webkitExitFullscreen||document.msExitFullscreen).call(document)},S.getStyle=function(t,e){return window.getComputedStyle(t,null)[e]},S.getShortestArc=function(i,o){return[0,S.TwoPI,-S.TwoPI].reduce(function(t,e){return e=o-i+e,Math.abs(e)Header Level 3 fisheye: true, move_speed: 1.1, time_anim: false, +// touchmove_two_fingers: true, // mousemove_hover: true, // webgl: false, navbar: [ diff --git a/package.json b/package.json index d696784c1..22ba3bb1d 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "photo-sphere-viewer", - "version": "3.4.0", + "version": "3.4.1", "authors": [ { "name": "Jérémy Heleine", @@ -22,21 +22,24 @@ "dot": ">=1.0.3" }, "devDependencies": { + "autoprefixer": "^9.1.5", "foodoc": "^0.0.9", "grunt": "^1.0.0", "grunt-banner": "^0.6.0", + "grunt-cli": "^1.3.1", "grunt-contrib-clean": "^1.0.0", "grunt-contrib-concat": "^1.0.0", "grunt-contrib-connect": "^1.0.0", "grunt-contrib-copy": "^1.0.0", - "grunt-contrib-cssmin": "^2.0.0", + "grunt-contrib-cssmin": "^3.0.0", "grunt-contrib-jshint": "^1.0.0", - "grunt-contrib-uglify": "^3.0.0", + "grunt-contrib-uglify": "^4.0.0", "grunt-contrib-watch": "^1.0.0", "grunt-jscs": "^3.0.1", "grunt-jsdoc": "^2.1.0", "grunt-mocha-test": "^0.13.2", "grunt-open": "^0.2.3", + "grunt-postcss": "^0.9.0", "grunt-sass": "^3.0.0", "grunt-sass-lint": "^0.2.2", "grunt-wrap": "^0.3.0", @@ -61,6 +64,7 @@ "scripts": { "build": "grunt build", "test": "grunt test", - "start": "grunt serve" + "start": "grunt serve", + "doc": "grunt doc" } } diff --git a/src/icons/gesture.svg b/src/icons/gesture.svg new file mode 100644 index 000000000..0d008b030 --- /dev/null +++ b/src/icons/gesture.svg @@ -0,0 +1 @@ + diff --git a/src/js/PSVUtils.js b/src/js/PSVUtils.js index eba9081ff..9444b2481 100644 --- a/src/js/PSVUtils.js +++ b/src/js/PSVUtils.js @@ -96,7 +96,7 @@ PSVUtils.isWebGLSupported = function() { /** * @summary Detects if device orientation is supported * @description We can only be sure device orientation is supported once received an event with coherent data - * @returns {Promise} + * @returns {Promise} */ PSVUtils.isDeviceOrientationSupported = function() { var defer = D(); @@ -104,10 +104,10 @@ PSVUtils.isDeviceOrientationSupported = function() { if ('DeviceOrientationEvent' in window) { var listener = function(event) { if (event && event.alpha !== null && !isNaN(event.alpha)) { - defer.resolve(); + defer.resolve(true); } else { - defer.reject(); + defer.resolve(false); } window.removeEventListener('deviceorientation', listener); @@ -122,7 +122,7 @@ PSVUtils.isDeviceOrientationSupported = function() { }, 2000); } else { - defer.reject(); + defer.resolve(false); } return defer.promise; @@ -252,7 +252,7 @@ PSVUtils.hasParent = function(el, parent) { /** * @summary Gets the closest parent (can by itself) - * @param {HTMLElement} el (HTMLElement) + * @param {HTMLElement|SVGElement} el * @param {string} selector * @returns {HTMLElement} */ @@ -263,7 +263,7 @@ PSVUtils.getClosest = function(el, selector) { if (matches.bind(el)(selector)) { return el; } - } while (!!(el = el.parentElement)); + } while (!!(el instanceof SVGElement ? el = el.parentNode : el = el.parentElement)); return null; }; @@ -278,6 +278,61 @@ PSVUtils.mouseWheelEvent = function() { 'DOMMouseScroll'; // let's assume that remaining browsers are older Firefox }; +/** + * @summary Returns the key name of a KeyboardEvent + * @param {KeyboardEvent} evt + * @returns {string} + */ +PSVUtils.getEventKey = function(evt) { + var key = evt.key || PSVUtils.getEventKey.KEYMAP[evt.keyCode || evt.which]; + + if (key && PSVUtils.getEventKey.MS_KEYMAP[key]) { + key = PSVUtils.getEventKey.MS_KEYMAP[key]; + } + + return key; +}; + +/** + * @summary Map between keyboard events `keyCode|which` and `key` + * @type {Object.} + * @readonly + * @protected + */ +PSVUtils.getEventKey.KEYMAP = { + 13: 'Enter', + 27: 'Escape', + 32: ' ', + 33: 'PageUp', + 34: 'PageDown', + 37: 'ArrowLeft', + 38: 'ArrowUp', + 39: 'ArrowRight', + 40: 'ArrowDown', + 46: 'Delete', + 107: '+', + 109: '-' +}; + +/** + * @summary Map for non standard keyboard events `key` for IE and Edge + * @see https://github.com/shvaikalesh/shim-keyboard-event-key + * @type {Object.} + * @readonly + * @protected + */ +PSVUtils.getEventKey.MS_KEYMAP = { + Add: '+', + Del: 'Delete', + Down: 'ArrowDown', + Esc: 'Escape', + Left: 'ArrowLeft', + Right: 'ArrowRight', + Spacebar: ' ', + Subtract: '-', + Up: 'ArrowUp' +}; + /** * @summary Gets the event name for fullscreen * @returns {string} diff --git a/src/js/PhotoSphereViewer.defaults.js b/src/js/PhotoSphereViewer.defaults.js index 3783e912e..7c630576a 100644 --- a/src/js/PhotoSphereViewer.defaults.js +++ b/src/js/PhotoSphereViewer.defaults.js @@ -71,23 +71,6 @@ PhotoSphereViewer.CUBE_MAP = [0, 2, 4, 5, 3, 1]; */ PhotoSphereViewer.CUBE_HASHMAP = ['left', 'right', 'top', 'bottom', 'back', 'front']; -/** - * @summary Map between keyboard events `keyCode|which` and `key` - * @type {Object.} - * @readonly - * @private - */ -PhotoSphereViewer.KEYMAP = { - 33: 'PageUp', - 34: 'PageDown', - 37: 'ArrowLeft', - 38: 'ArrowUp', - 39: 'ArrowRight', - 40: 'ArrowDown', - 107: '+', - 109: '-' -}; - /** * @summary System properties * @type {Object} @@ -168,13 +151,25 @@ PhotoSphereViewer.DEFAULTS = { gyroscope: 'Gyroscope', stereo: 'Stereo view', stereo_notification: 'Click anywhere to exit stereo view.', - please_rotate: ['Please rotate your device', '(or tap to continue)'] + please_rotate: ['Please rotate your device', '(or tap to continue)'], + two_fingers: ['Use two fingers to navigate'] }, mousewheel: true, mousewheel_factor: 1, mousemove: true, mousemove_hover: false, - keyboard: true, + touchmove_two_fingers: false, + keyboard: { + 'ArrowUp': 'rotateLatitudeUp', + 'ArrowDown': 'rotateLatitudeDown', + 'ArrowRight': 'rotateLongitudeRight', + 'ArrowLeft': 'rotateLongitudeLeft', + 'PageUp': 'zoomIn', + 'PageDown': 'zoomOut', + '+': 'zoomIn', + '-': 'zoomOut', + ' ': 'toggleAutorotate' + }, move_inertia: true, click_event_on_marker: false, transition: { diff --git a/src/js/PhotoSphereViewer.events.js b/src/js/PhotoSphereViewer.events.js index b57b03cb9..db77aac66 100644 --- a/src/js/PhotoSphereViewer.events.js +++ b/src/js/PhotoSphereViewer.events.js @@ -131,16 +131,18 @@ PhotoSphereViewer.prototype._onKeyDown = function(evt) { var dLat = 0; var dZoom = 0; - var key = evt.key || PhotoSphereViewer.KEYMAP[evt.keyCode || evt.which]; + var key = PSVUtils.getEventKey(evt); + var action = this.config.keyboard[key]; - switch (key) { + switch (action) { // @formatter:off - case 'ArrowUp': dLat = 0.01; break; - case 'ArrowDown': dLat = -0.01; break; - case 'ArrowRight': dLong = 0.01; break; - case 'ArrowLeft': dLong = -0.01; break; - case 'PageUp':case '+': dZoom = 1; break; - case 'PageDown':case '-': dZoom = -1; break; + case 'rotateLatitudeUp': dLat = 0.01; break; + case 'rotateLatitudeDown': dLat = -0.01; break; + case 'rotateLongitudeRight': dLong = 0.01; break; + case 'rotateLongitudeLeft': dLong = -0.01; break; + case 'zoomIn': dZoom = 1; break; + case 'zoomOut': dZoom = -1; break; + case 'toggleAutorotate': this.toggleAutorotate(); break; // @formatter:on } @@ -199,10 +201,12 @@ PhotoSphereViewer.prototype._onMouseMove = function(evt) { */ PhotoSphereViewer.prototype._onTouchStart = function(evt) { if (evt.touches.length === 1) { - this._startMove(evt.touches[0]); + if (!this.config.touchmove_two_fingers) { + this._startMove(evt.touches[0]); + } } else if (evt.touches.length === 2) { - this._startZoom(evt); + this._startMoveZoom(evt); } }; @@ -212,7 +216,16 @@ PhotoSphereViewer.prototype._onTouchStart = function(evt) { * @private */ PhotoSphereViewer.prototype._onTouchEnd = function(evt) { - this._stopMove(evt.changedTouches[0]); + if (evt.touches.length === 1) { + this._stopMoveZoom(); + } + else if (evt.touches.length === 0) { + this._stopMove(evt.changedTouches[0]); + + if (this.config.touchmove_two_fingers) { + this.overlay.hideOverlay(); + } + } }; /** @@ -222,12 +235,20 @@ PhotoSphereViewer.prototype._onTouchEnd = function(evt) { */ PhotoSphereViewer.prototype._onTouchMove = function(evt) { if (evt.touches.length === 1) { - evt.preventDefault(); - this._move(evt.touches[0]); + if (this.config.touchmove_two_fingers) { + this.overlay.showOverlay({ + image: PhotoSphereViewer.ICONS['gesture.svg'], + text: this.config.lang.two_fingers[0] + }); + } + else { + evt.preventDefault(); + this._move(evt.touches[0]); + } } else if (evt.touches.length === 2) { evt.preventDefault(); - this._zoom(evt); + this._moveZoom(evt); } }; @@ -250,18 +271,20 @@ PhotoSphereViewer.prototype._startMove = function(evt) { }; /** - * @summary Initializes the zoom + * @summary Initializes the combines move and zoom * @param {TouchEvent} evt * @private */ -PhotoSphereViewer.prototype._startZoom = function(evt) { +PhotoSphereViewer.prototype._startMoveZoom = function(evt) { var t = [ { x: parseInt(evt.touches[0].clientX), y: parseInt(evt.touches[0].clientY) }, { x: parseInt(evt.touches[1].clientX), y: parseInt(evt.touches[1].clientY) } ]; this.prop.pinch_dist = Math.sqrt(Math.pow(t[0].x - t[1].x, 2) + Math.pow(t[0].y - t[1].y, 2)); - this.prop.moving = false; + this.prop.mouse_x = this.prop.start_mouse_x = (t[0].x + t[1].x) / 2; + this.prop.mouse_y = this.prop.start_mouse_x = (t[0].y + t[1].y) / 2; + this.prop.moving = true; this.prop.zooming = true; }; @@ -293,7 +316,15 @@ PhotoSphereViewer.prototype._stopMove = function(evt) { this.prop.mouse_history.length = 0; } +}; +/** + * @summary Stops the combined move and zoom + * @private + */ +PhotoSphereViewer.prototype._stopMoveZoom = function() { + this.prop.mouse_history.length = 0; + this.prop.moving = false; this.prop.zooming = false; }; @@ -442,12 +473,12 @@ PhotoSphereViewer.prototype._moveAbsolute = function(evt) { }; /** - * @summary Perfoms zoom + * @summary Perfoms combines move and zoom * @param {TouchEvent} evt * @private */ -PhotoSphereViewer.prototype._zoom = function(evt) { - if (this.prop.zooming) { +PhotoSphereViewer.prototype._moveZoom = function(evt) { + if (this.prop.zooming && this.prop.moving) { var t = [ { x: parseInt(evt.touches[0].clientX), y: parseInt(evt.touches[0].clientY) }, { x: parseInt(evt.touches[1].clientX), y: parseInt(evt.touches[1].clientY) } @@ -458,6 +489,11 @@ PhotoSphereViewer.prototype._zoom = function(evt) { this.zoom(this.prop.zoom_lvl + delta); + this._move({ + clientX: (t[0].x + t[1].x) / 2, + clientY: (t[0].y + t[1].y) / 2 + }); + this.prop.pinch_dist = p; } }; diff --git a/src/js/PhotoSphereViewer.js b/src/js/PhotoSphereViewer.js index 49fa90abf..d1ff827a4 100644 --- a/src/js/PhotoSphereViewer.js +++ b/src/js/PhotoSphereViewer.js @@ -145,20 +145,28 @@ function PhotoSphereViewer(options) { console.warn('PhotoSphereViewer: max_fov cannot be lower than min_fov.'); } + // cache_texture must be a positive integer or false if (this.config.cache_texture && (!PSVUtils.isInteger(this.config.cache_texture) || this.config.cache_texture < 0)) { this.config.cache_texture = PhotoSphereViewer.DEFAULTS.cache_texture; console.warn('PhotoSphereViewer: invalid value for cache_texture'); } + // panorama_roll is deprecated if ('panorama_roll' in this.config) { this.config.sphere_correction.roll = this.config.panorama_roll; console.warn('PhotoSphereViewer: panorama_roll is deprecated, use sphere_correction.roll instead'); } + // gyroscope is deprecated if ('gyroscope' in this.config) { console.warn('PhotoSphereViewer: gyroscope is deprecated, the control is automatically created if DeviceOrientationControls.js is loaded'); } + // keyboard=true becomes the default map + if (this.config.keyboard === true) { + this.config.keyboard = PSVUtils.clone(PhotoSphereViewer.DEFAULTS.keyboard); + } + // min_fov/max_fov between 1 and 179 this.config.min_fov = PSVUtils.bound(this.config.min_fov, 1, 179); this.config.max_fov = PSVUtils.bound(this.config.max_fov, 1, 179); @@ -273,10 +281,10 @@ function PhotoSphereViewer(options) { this.notification = null; /** - * @member {module:components.PSVPleaseRotate} + * @member {module:components.PSVOverlay} * @readonly */ - this.pleaseRotate = null; + this.overlay = null; /** * @member {HTMLElement} @@ -479,6 +487,9 @@ function PhotoSphereViewer(options) { // load notification this.notification = new PSVNotification(this); + // load overlay + this.overlay = new PSVOverlay(this); + // attach event handlers this._bindEvents(); diff --git a/src/js/PhotoSphereViewer.public.js b/src/js/PhotoSphereViewer.public.js index 905a5feb8..553c3301f 100644 --- a/src/js/PhotoSphereViewer.public.js +++ b/src/js/PhotoSphereViewer.public.js @@ -124,8 +124,8 @@ PhotoSphereViewer.prototype.destroy = function() { if (this.panel) { this.panel.destroy(); } - if (this.pleaseRotate) { - this.pleaseRotate.destroy(); + if (this.overlay) { + this.overlay.destroy(); } // destroy ThreeJS view @@ -150,7 +150,7 @@ PhotoSphereViewer.prototype.destroy = function() { delete this.panel; delete this.tooltip; delete this.notification; - delete this.pleaseRotate; + delete this.overlay; delete this.canvas_container; delete this.renderer; delete this.noSleep; @@ -312,8 +312,8 @@ PhotoSphereViewer.prototype.toggleAutorotate = function() { */ PhotoSphereViewer.prototype.startGyroscopeControl = function() { if (PSVUtils.checkTHREE('DeviceOrientationControls')) { - return PhotoSphereViewer.SYSTEM.deviceOrientationSupported.then( - function() { + return PhotoSphereViewer.SYSTEM.deviceOrientationSupported.then(function(supported) { + if (supported) { this._stopAll(); this.doControls = new THREE.DeviceOrientationControls(this.camera); @@ -337,12 +337,12 @@ PhotoSphereViewer.prototype.startGyroscopeControl = function() { * @param {boolean} enabled */ this.trigger('gyroscope-updated', true); - }.bind(this), - function() { + } + else { console.warn('PhotoSphereViewer: gyroscope not available'); return D.rejected(); } - ); + }.bind(this)); } else { throw new PSVError('Missing Three.js components: DeviceOrientationControls. Get them from three.js-examples package.'); @@ -497,17 +497,25 @@ PhotoSphereViewer.prototype.stopStereoView = function() { * @summary Tries to lock the device in landscape or display a message */ PhotoSphereViewer.prototype.lockOrientation = function() { + var displayRotateMessageTimeout; + var displayRotateMessage = function() { - if (window.innerHeight > window.innerWidth) { - if (!this.pleaseRotate) { - this.pleaseRotate = new PSVPleaseRotate(this); - } - this.pleaseRotate.show(); + if (this.isStereoEnabled() && window.innerHeight > window.innerWidth) { + this.overlay.showOverlay({ + image: PhotoSphereViewer.ICONS['mobile-rotate.svg'], + text: this.config.lang.please_rotate[0], + subtext: this.config.lang.please_rotate[1] + }); + } + + if (displayRotateMessageTimeout) { + window.clearTimeout(displayRotateMessageTimeout); } }; if (window.screen && window.screen.orientation) { window.screen.orientation.lock('landscape').then(null, displayRotateMessage.bind(this)); + displayRotateMessageTimeout = setTimeout(displayRotateMessage.bind(this), 500); } else { displayRotateMessage.apply(this); @@ -522,9 +530,7 @@ PhotoSphereViewer.prototype.unlockOrientation = function() { window.screen.orientation.unlock(); } else { - if (this.pleaseRotate) { - this.pleaseRotate.hide(); - } + this.overlay.hideOverlay(); } }; diff --git a/src/js/buttons/PSVNavBarButton.js b/src/js/buttons/PSVNavBarButton.js index fcee3a76a..c52d6559c 100644 --- a/src/js/buttons/PSVNavBarButton.js +++ b/src/js/buttons/PSVNavBarButton.js @@ -76,6 +76,20 @@ PSVNavBarButton.prototype.create = function() { } e.stopPropagation(); }.bind(this)); + + var supported = this.supported(); + if (typeof supported.then === 'function') { + this.hide(); + + supported.then(function(supported) { + if (supported) { + this.show(); + } + }.bind(this)); + } + else if (!supported) { + this.hide(); + } }; /** @@ -86,6 +100,14 @@ PSVNavBarButton.prototype.destroy = function() { PSVComponent.prototype.destroy.call(this); }; +/** + * @summary Checks if the button can be displayed + * @returns {boolean|Promise} + */ +PSVNavBarButton.prototype.supported = function() { + return true; +}; + /** * @summary Changes the active state of the button * @param {boolean} [active] - forced state diff --git a/src/js/buttons/PSVNavBarCaptionButton.js b/src/js/buttons/PSVNavBarCaptionButton.js new file mode 100644 index 000000000..d4078df62 --- /dev/null +++ b/src/js/buttons/PSVNavBarCaptionButton.js @@ -0,0 +1,64 @@ +/** + * Navigation bar caption button class + * @param {module:components.PSVNavBarCaption} caption + * @constructor + * @extends module:components/buttons.PSVNavBarButton + * @memberof module:components/buttons + */ +function PSVNavBarCaptionButton(caption) { + PSVNavBarButton.call(this, caption); + + this.create(); +} + +PSVNavBarCaptionButton.prototype = Object.create(PSVNavBarButton.prototype); +PSVNavBarCaptionButton.prototype.constructor = PSVNavBarCaptionButton; + +PSVNavBarCaptionButton.id = 'markers'; +PSVNavBarCaptionButton.className = 'psv-button psv-button--hover-scale psv-caption-button'; +PSVNavBarCaptionButton.icon = 'info.svg'; + +/** + * @override + */ +PSVNavBarCaptionButton.prototype.create = function() { + PSVNavBarButton.prototype.create.call(this); + + this.psv.on('hide-notification', this); +}; + +/** + * @override + */ +PSVNavBarCaptionButton.prototype.destroy = function() { + this.psv.off('hide-notification', this); + + PSVNavBarButton.prototype.destroy.call(this); +}; + +/** + * @summary Handles events + * @param {Event} e + * @private + */ +PSVNavBarCaptionButton.prototype.handleEvent = function(e) { + switch (e.type) { + // @formatter:off + case 'hide-notification': this.toggleActive(false); break; + // @formatter:on + } +}; + +/** + * @override + * @description Toggles markers list + */ +PSVNavBarCaptionButton.prototype._onClick = function() { + if (this.psv.isNotificationVisible()) { + this.psv.hideNotification(); + } + else { + this.psv.showNotification(this.parent.prop.caption); + this.toggleActive(true); + } +}; diff --git a/src/js/buttons/PSVNavBarFullscreenButton.js b/src/js/buttons/PSVNavBarFullscreenButton.js index 5438cc660..9b5fdffac 100644 --- a/src/js/buttons/PSVNavBarFullscreenButton.js +++ b/src/js/buttons/PSVNavBarFullscreenButton.js @@ -25,11 +25,6 @@ PSVNavBarFullscreenButton.iconActive = 'fullscreen-out.svg'; PSVNavBarFullscreenButton.prototype.create = function() { PSVNavBarButton.prototype.create.call(this); - if (!PhotoSphereViewer.SYSTEM.fullscreenEvent) { - this.hide(); - console.warn('PhotoSphereViewer: fullscreen not supported.'); - } - this.psv.on('fullscreen-updated', this); }; @@ -42,6 +37,13 @@ PSVNavBarFullscreenButton.prototype.destroy = function() { PSVNavBarButton.prototype.destroy.call(this); }; +/** + * @override + */ +PSVNavBarFullscreenButton.prototype.supported = function() { + return !!PhotoSphereViewer.SYSTEM.fullscreenEvent; +}; + /** * Handle events * @param {Event} e diff --git a/src/js/buttons/PSVNavBarGyroscopeButton.js b/src/js/buttons/PSVNavBarGyroscopeButton.js index eb90c8b29..af4453c94 100644 --- a/src/js/buttons/PSVNavBarGyroscopeButton.js +++ b/src/js/buttons/PSVNavBarGyroscopeButton.js @@ -25,13 +25,6 @@ PSVNavBarGyroscopeButton.icon = 'compass.svg'; PSVNavBarGyroscopeButton.prototype.create = function() { PSVNavBarButton.prototype.create.call(this); - PhotoSphereViewer.SYSTEM.deviceOrientationSupported.then( - this._onAvailabilityChange.bind(this, true), - this._onAvailabilityChange.bind(this, false) - ); - - this.hide(); - this.psv.on('gyroscope-updated', this); }; @@ -44,6 +37,18 @@ PSVNavBarGyroscopeButton.prototype.destroy = function() { PSVNavBarButton.prototype.destroy.call(this); }; +/** + * @override + */ +PSVNavBarGyroscopeButton.prototype.supported = function() { + if (!PSVUtils.checkTHREE('DeviceOrientationControls')) { + return false; + } + else { + return PhotoSphereViewer.SYSTEM.deviceOrientationSupported; + } +}; + /** * @summary Handles events * @param {Event} e @@ -64,15 +69,3 @@ PSVNavBarGyroscopeButton.prototype.handleEvent = function(e) { PSVNavBarGyroscopeButton.prototype._onClick = function() { this.psv.toggleGyroscopeControl(); }; - -/** - * @summary Updates button display when API is ready - * @param {boolean} available - * @private - * @throws {PSVError} when {@link THREE.DeviceOrientationControls} is not loaded - */ -PSVNavBarGyroscopeButton.prototype._onAvailabilityChange = function(available) { - if (available && PSVUtils.checkTHREE('DeviceOrientationControls')) { - this.show(); - } -}; diff --git a/src/js/buttons/PSVNavBarStereoButton.js b/src/js/buttons/PSVNavBarStereoButton.js index eb1686849..4522d1534 100644 --- a/src/js/buttons/PSVNavBarStereoButton.js +++ b/src/js/buttons/PSVNavBarStereoButton.js @@ -25,13 +25,6 @@ PSVNavBarStereoButton.icon = 'stereo.svg'; PSVNavBarStereoButton.prototype.create = function() { PSVNavBarButton.prototype.create.call(this); - PhotoSphereViewer.SYSTEM.deviceOrientationSupported.then( - this._onAvailabilityChange.bind(this, true), - this._onAvailabilityChange.bind(this, false) - ); - - this.hide(); - this.psv.on('stereo-updated', this); }; @@ -44,6 +37,18 @@ PSVNavBarStereoButton.prototype.destroy = function() { PSVNavBarButton.prototype.destroy.call(this); }; +/** + * @override + */ +PSVNavBarStereoButton.prototype.supported = function() { + if (!PhotoSphereViewer.SYSTEM.fullscreenEvent || !PSVUtils.checkTHREE('DeviceOrientationControls')) { + return false; + } + else { + return PhotoSphereViewer.SYSTEM.deviceOrientationSupported; + } +}; + /** * @summary Handles events * @param {Event} e @@ -64,16 +69,3 @@ PSVNavBarStereoButton.prototype.handleEvent = function(e) { PSVNavBarStereoButton.prototype._onClick = function() { this.psv.toggleStereoView(); }; - -/** - * @summary Updates button display when API is ready - * @param {boolean} available - * @private - * @throws {PSVError} when {@link THREE.DeviceOrientationControls} is not loaded - */ -PSVNavBarStereoButton.prototype._onAvailabilityChange = function(available) { - if (available && PSVUtils.checkTHREE('DeviceOrientationControls', 'StereoEffect')) { - this.show(); - } -}; - diff --git a/src/js/components/PSVNavBarCaption.js b/src/js/components/PSVNavBarCaption.js index 47ae14af2..6a494295d 100644 --- a/src/js/components/PSVNavBarCaption.js +++ b/src/js/components/PSVNavBarCaption.js @@ -17,11 +17,11 @@ function PSVNavBarCaption(navbar, caption) { this.content = null; /** - * @member {SVGElement} + * @member {PSVNavBarCaptionButton} * @readonly * @private */ - this.icon = null; + this.button = null; /** * @member {Object} @@ -29,8 +29,7 @@ function PSVNavBarCaption(navbar, caption) { */ this.prop = { caption: '', - width: 0, - hidden: false + width: 0 }; this.create(); @@ -50,16 +49,13 @@ PSVNavBarCaption.publicMethods = ['setCaption']; PSVNavBarCaption.prototype.create = function() { PSVComponent.prototype.create.call(this); - this.container.innerHTML = PhotoSphereViewer.ICONS['info.svg']; - this.icon = this.container.querySelector('svg'); - this.icon.setAttribute('class', 'psv-caption-icon'); - this.icon.style.display = 'none'; + this.button = new PSVNavBarCaptionButton(this); + this.button.hide(); - this.content = document.createElement('span'); + this.content = document.createElement('div'); this.content.className = 'psv-caption-content'; this.container.appendChild(this.content); - this.icon.addEventListener('click', this); window.addEventListener('resize', this); }; @@ -83,7 +79,6 @@ PSVNavBarCaption.prototype.handleEvent = function(e) { switch (e.type) { // @formatter:off case 'resize': this._onResize(); break; - case 'click': this._onClick(); break; // @formatter:on } }; @@ -116,24 +111,11 @@ PSVNavBarCaption.prototype._onResize = function() { var width = parseInt(PSVUtils.getStyle(this.container, 'width')); // get real inner width if (width >= this.prop.width) { - this.icon.style.display = 'none'; + this.button.hide(); this.content.style.display = ''; } else { - this.icon.style.display = ''; + this.button.show(); this.content.style.display = 'none'; } }; - -/** - * @summary Display caption as notification - * @private - */ -PSVNavBarCaption.prototype._onClick = function() { - if (this.psv.isNotificationVisible()) { - this.psv.hideNotification(); - } - else { - this.psv.showNotification(this.prop.caption); - } -}; diff --git a/src/js/components/PSVOverlay.js b/src/js/components/PSVOverlay.js new file mode 100644 index 000000000..e7e34c0e7 --- /dev/null +++ b/src/js/components/PSVOverlay.js @@ -0,0 +1,112 @@ +/** + * Overlay class + * @param {PhotoSphereViewer} psv + * @constructor + * @extends module:components.PSVComponent + * @memberof module:components + */ +function PSVOverlay(psv) { + PSVComponent.call(this, psv); + + this.create(); + this.hide(); +} + +PSVOverlay.prototype = Object.create(PSVComponent.prototype); +PSVOverlay.prototype.constructor = PSVOverlay; + +PSVOverlay.className = 'psv-overlay'; +PSVOverlay.publicMethods = ['showOverlay', 'hideOverlay', 'isOverlayVisible']; + +/** + * @override + */ +PSVOverlay.prototype.create = function() { + PSVComponent.prototype.create.call(this); + + this.image = document.createElement('div'); + this.image.className = 'psv-overlay-image'; + this.container.appendChild(this.image); + + this.text = document.createElement('div'); + this.text.className = 'psv-overlay-text'; + this.container.appendChild(this.text); + + this.subtext = document.createElement('div'); + this.subtext.className = 'psv-overlay-subtext'; + this.container.appendChild(this.subtext); + + this.container.addEventListener('click', this.hideOverlay.bind(this)); +}; + +/** + * @override + */ +PSVOverlay.prototype.destroy = function() { + delete this.image; + delete this.text; + delete this.subtext; + + PSVComponent.prototype.destroy.call(this); +}; + +/** + * @summary Checks if the overlay is visible + * @returns {boolean} + */ +PSVOverlay.prototype.isOverlayVisible = function() { + return this.visible; +}; + +/** + * @summary Displays an overlay on the viewer + * @param {Object|string} config + * @param {string} config.image + * @param {string} config.text + * @param {string} config.subtext + * + * @example + * viewer.showOverlay({ + * image: '', + * text: '....', + * subtext: '....' + * }) + */ +PSVOverlay.prototype.showOverlay = function(config) { + if (typeof config === 'string') { + config = { + text: config + }; + } + + this.image.innerHTML = config.image || ''; + this.text.innerHTML = config.text || ''; + this.subtext.innerHTML = config.subtext || ''; + + this.show(); + + /** + * @event show-overlay + * @memberof module:components.PSVOverlay + * @summary Trigered when the overlay is shown + */ + this.psv.trigger('show-overlay'); +}; + +/** + * @summary Hides the notification + * @fires module:components.PSVOverlay.hide-notification + */ +PSVOverlay.prototype.hideOverlay = function() { + if (this.isOverlayVisible()) { + this.hide(); + + /** + * @event hide-overlay + * @memberof module:components.PSVOverlay + * @summary Trigered when the overlay is hidden + */ + this.psv.trigger('hide-overlay'); + } +}; + diff --git a/src/js/components/PSVPleaseRotate.js b/src/js/components/PSVPleaseRotate.js deleted file mode 100644 index 44142f116..000000000 --- a/src/js/components/PSVPleaseRotate.js +++ /dev/null @@ -1,60 +0,0 @@ -/** - * "Please rotate" class - * @param {PhotoSphereViewer} psv - * @constructor - * @extends module:components.PSVComponent - * @memberof module:components - */ -function PSVPleaseRotate(psv) { - PSVComponent.call(this, psv); - - this.create(); -} - -PSVPleaseRotate.prototype = Object.create(PSVComponent.prototype); -PSVPleaseRotate.prototype.constructor = PSVPleaseRotate; - -PSVPleaseRotate.className = 'psv-please-rotate'; - -/** - * @override - */ -PSVPleaseRotate.prototype.create = function() { - PSVComponent.prototype.create.call(this); - - this.container.innerHTML = - '
' + PhotoSphereViewer.ICONS['mobile-rotate.svg'] + '
' + - '
' + this.psv.config.lang.please_rotate[0] + '
' + - '
' + this.psv.config.lang.please_rotate[1] + '
'; - - this.container.addEventListener('click', this); - window.addEventListener('orientationchange', this); -}; - -/** - * @override - */ -PSVPleaseRotate.prototype.destroy = function() { - window.removeEventListener('orientationchange', this); - - PSVComponent.prototype.destroy.call(this); -}; - -/** - * @summary Handles events - * @param {Event} e - * @private - */ -PSVPleaseRotate.prototype.handleEvent = function(e) { - switch (e.type) { - // @formatter:off - case 'click': this.hide(); break; - case 'orientationchange': - if (Math.abs(window.orientation) === 90) { - this.hide(); - } - break; - // @formatter:on - } -}; - diff --git a/src/scss/_mixins.scss b/src/scss/_mixins.scss index 9bedbf444..34554b572 100644 --- a/src/scss/_mixins.scss +++ b/src/scss/_mixins.scss @@ -1,57 +1,3 @@ -@mixin user-select($value) { - -webkit-touch-callout: $value; - -webkit-user-select: $value; - -khtml-user-select: $value; - -moz-user-select: $value; - -ms-user-select: $value; - user-select: $value; -} - -@mixin flexbox { - display: -webkit-box; - display: -webkit-flex; - display: -moz-flex; - display: -ms-flexbox; - display: flex; -} - -@mixin flex-grow($int: 0) { - -webkit-box-flex: $int; - -webkit-flex-grow: $int; - -moz-flex-grow: $int; - -ms-flex-positive: $int; - flex-grow: $int; -} - -@mixin flex-shrink($int: 1) { - -webkit-flex-shrink: $int; - -moz-flex-shrink: $int; - -ms-flex-negative: $int; - flex-shrink: $int; -} - -@mixin flex-direction($direction) { - -webkit-flex-direction: $direction; - -moz-flex-direction: $direction; - -ms-flex-direction: $direction; - flex-direction: $direction; -} - -@mixin justify-content($justify) { - -webkit-justify-content: $justify; - -moz-justify-content: $justify; - -ms-justify-content: $justify; - justify-content: $justify; - -ms-flex-pack: $justify; -} - -@mixin align-items($align) { - -webkit-align-items: $align; - -moz-align-items: $align; - -ms-align-items: $align; - align-items: $align; -} - @function make-dot-shadow($color, $width, $height) { $val: 1px 0 $color; $x: 3; diff --git a/src/scss/_vars.scss b/src/scss/_vars.scss index eb9b19d32..72374e648 100644 --- a/src/scss/_vars.scss +++ b/src/scss/_vars.scss @@ -16,16 +16,19 @@ $psv-loader-font: 14px sans-serif !default; $psv-navbar-height: 40px !default; $psv-navbar-background: rgba(61, 61, 61, .5) !default; -$psv-caption-font: sans-serif !default; +$psv-caption-font: 16px sans-serif !default; $psv-caption-color: rgba(255, 255, 255, .7) !default; $psv-buttons-height: 20px !default; $psv-buttons-padding: 10px !default; $psv-buttons-background: transparent !default; -$psv-buttons-active-background: rgba(255, 255, 255, .1) !default; +$psv-buttons-active-background: rgba(255, 255, 255, .2) !default; $psv-buttons-color: rgba(255, 255, 255, .7) !default; $psv-buttons-disabled-opacity: .5 !default; +$psv-buttons-hover-scale: 1.2 !default; +$psv-buttons-hover-scale-delay: 200ms !default; + $psv-zoom-range-width: 80px !default; $psv-zoom-range-tickness: 1px !default; $psv-zoom-disk-diameter: 7px !default; @@ -38,7 +41,7 @@ $psv-tooltip-background-color: rgba(61, 61, 61, .8) !default; // set tooltip.offset JS config to the same value $psv-tooltip-animate-offset: 5px !default; // set tooltip.delay JS config to the same value -$psv-tooltip-animate-delay: .1s !default; +$psv-tooltip-animate-delay: 100ms !default; $psv-tooltip-radius: 4px !default; $psv-tooltip-padding: .5em 1em !default; // set tooltip.arrow_size JS config to the same value @@ -87,8 +90,8 @@ $psv-markers-list-title-font: 24px sans-serif !default; //*** NOTIFICATION *** -$psv-notification-bottom: ($psv-navbar-height, $psv-navbar-height * 2) !default; -$psv-notification-animate-delay: $psv-tooltip-animate-delay !default; +$psv-notification-bottom: (from: $psv-navbar-height, to: $psv-navbar-height * 2) !default; +$psv-notification-animate-delay: 200ms !default; $psv-notification-background-color: $psv-tooltip-background-color !default; $psv-notification-radius: $psv-tooltip-radius !default; $psv-notification-padding: $psv-tooltip-padding !default; @@ -96,6 +99,14 @@ $psv-notification-font: $psv-tooltip-font !default; $psv-notification-text-color: $psv-tooltip-text-color !default; +//*** OVERLAY *** +$psv-overlay-opacity: .8 !default; +$psv-overlay-font-family: sans-serif !default; +$psv-overlay-text-size: 30px !default; +$psv-overlay-subtext-size: 20px !default; +$psv-overlay-image-size: (portrait: 50vw, landscape: 25vw) !default; + + //*** Z-INDEXES *** $psv-canvas-zindex: 0 !default; $psv-hud-zindex: 10 !default; @@ -106,3 +117,4 @@ $psv-panel-zindex: 90 !default; $psv-navbar-zindex: 90 !default; $psv-loader-zindex: 100 !default; $psv-notification-zindex: 100 !default; +$psv-overlay-zindex: 110 !default; diff --git a/src/scss/hud.scss b/src/scss/hud.scss index bc90eb335..6fe8b0672 100644 --- a/src/scss/hud.scss +++ b/src/scss/hud.scss @@ -1,5 +1,5 @@ .psv-hud { - @include user-select(none); + user-select: none; position: absolute; z-index: $psv-hud-zindex; width: 100%; diff --git a/src/scss/loader.scss b/src/scss/loader.scss index 110d7a0da..d08af09fe 100644 --- a/src/scss/loader.scss +++ b/src/scss/loader.scss @@ -1,5 +1,5 @@ .psv-loader-container { - @include flexbox; + display: flex; align-items: center; justify-content: center; position: absolute; diff --git a/src/scss/buttons/markers.scss b/src/scss/markers-list.scss similarity index 100% rename from src/scss/buttons/markers.scss rename to src/scss/markers-list.scss diff --git a/src/scss/navbar.scss b/src/scss/navbar.scss index 95853f402..d7bfee723 100644 --- a/src/scss/navbar.scss +++ b/src/scss/navbar.scss @@ -1,5 +1,5 @@ .psv-navbar { - @include flexbox; + display: flex; position: absolute; z-index: $psv-navbar-zindex; bottom: -$psv-navbar-height; @@ -20,9 +20,8 @@ } .psv-caption { - @include flex-grow(10); + flex: 1 1 100%; color: $psv-caption-color; - margin: $psv-buttons-padding; overflow: hidden; text-align: center; @@ -37,14 +36,15 @@ } &-content { - font-family: $psv-caption-font; + display: inline-block; + padding: $psv-buttons-padding; + font: $psv-caption-font; white-space: nowrap; } } .psv-button { - @include flex-grow(0); - @include flex-shrink(0); + flex: 0 0 auto; padding: $psv-buttons-padding; position: relative; cursor: pointer; @@ -65,18 +65,14 @@ .psv-button-svg { width: 100%; transform: scale(1); - transition: transform .3s ease; + transition: transform $psv-buttons-hover-scale-delay ease; * { fill: $psv-buttons-color; } + } - .psv-button--hover-scale:not(.psv-button--disabled):hover & { - transform: scale(1.2); - } + &--hover-scale:not(&--disabled):hover &-svg { + transform: scale($psv-buttons-hover-scale); } } - -@import 'buttons/autorotate'; -@import 'buttons/zoom'; -@import 'buttons/markers'; diff --git a/src/scss/notification.scss b/src/scss/notification.scss index 4779f6b30..a0dbb88b1 100644 --- a/src/scss/notification.scss +++ b/src/scss/notification.scss @@ -1,12 +1,12 @@ .psv-notification { position: absolute; z-index: $psv-notification-zindex; - bottom: nth($psv-notification-bottom, 1); + bottom: map-get($psv-notification-bottom, from); display: flex; justify-content: center; box-sizing: border-box; width: 100%; - padding: 0 #{nth($psv-notification-bottom, 2) - nth($psv-notification-bottom, 1)}; + padding: 0 2em; opacity: 0; transition-property: opacity, bottom; transition-timing-function: ease-in-out; @@ -23,6 +23,6 @@ &--visible { opacity: 100; - bottom: nth($psv-notification-bottom, 2); + bottom: map-get($psv-notification-bottom, to); } } diff --git a/src/scss/overlay.scss b/src/scss/overlay.scss new file mode 100644 index 000000000..a64fc8b89 --- /dev/null +++ b/src/scss/overlay.scss @@ -0,0 +1,37 @@ +.psv-overlay { + display: flex; + flex-direction: column; + align-items: center; + justify-content: center; + position: absolute; + z-index: $psv-overlay-zindex; + top: 0; + left: 0; + bottom: 0; + right: 0; + background: $psv-main-background; + opacity: $psv-overlay-opacity; + + &-image { + margin-bottom: 4vh; + + svg { + width: map-get($psv-overlay-image-size, portrait); + + @media screen and (orientation: landscape) { + width: map-get($psv-overlay-image-size, landscape); + } + } + } + + &-text { + font: $psv-overlay-text-size $psv-overlay-font-family; + text-align: center; + } + + &-subtext { + font: $psv-overlay-subtext-size $psv-overlay-font-family; + opacity: .8; + text-align: center; + } +} diff --git a/src/scss/panel.scss b/src/scss/panel.scss index e68da815e..a2facfd5b 100644 --- a/src/scss/panel.scss +++ b/src/scss/panel.scss @@ -105,7 +105,7 @@ $psv-panel-resizer-grip-width: $psv-panel-resizer-width - 4px; } &--no-interaction { - @include user-select(none); + user-select: none; pointer-events: none; } } diff --git a/src/scss/photo-sphere-viewer.scss b/src/scss/photo-sphere-viewer.scss index d7d8f8fad..81445c855 100644 --- a/src/scss/photo-sphere-viewer.scss +++ b/src/scss/photo-sphere-viewer.scss @@ -29,4 +29,7 @@ @import 'panel'; @import 'tooltip'; @import 'notification'; -@import 'please-rotate'; +@import 'overlay'; +@import 'markers-list'; +@import 'buttons/autorotate'; +@import 'buttons/zoom'; diff --git a/src/scss/please-rotate.scss b/src/scss/please-rotate.scss deleted file mode 100644 index 1fd82601c..000000000 --- a/src/scss/please-rotate.scss +++ /dev/null @@ -1,36 +0,0 @@ -.psv-please-rotate { - @include flexbox; - @include flex-direction(column); - @include align-items(center); - @include justify-content(center); - position: absolute; - z-index: $psv-notification-zindex + 1; - top: 0; - left: 0; - bottom: 0; - right: 0; - background: $psv-main-background; - - &-image { - margin-bottom: 4vh; - - svg { - width: 50vw; - - @media screen and (orientation: landscape) { - width: 30vw; - } - } - } - - &-text { - font: $psv-loader-font; - font-size: 30px; - } - - &-subtext { - font: $psv-loader-font; - font-size: 20px; - opacity: .8; - } -}