diff --git a/README.md b/README.md
index ba951626c..4b8791895 100644
--- a/README.md
+++ b/README.md
@@ -1,13 +1,15 @@
# Photo Sphere Viewer
-[![Bower version](https://badge.fury.io/bo/Photo-Sphere-Viewer.svg)](http://badge.fury.io/bo/Photo-Sphere-Viewer)
-[![Online documentation](https://img.shields.io/badge/documentation-online-blue.svg)](https://mistic100.github.io/Photo-Sphere-Viewer)
+[![Bower version](https://img.shields.io/bower/v/Photo-Sphere-Viewer.svg?style=flat-square)](http://photo-sphere-viewer.js.org
+)
+[![CDN](https://img.shields.io/badge/cdn-jsdelivr-%23EB4C36.svg?style=flat-square)](http://www.jsdelivr.com/projects/photo-sphere-viewer)
Photo Sphere Viewer is a JavaScript library that allows you to display 360×180 degrees panoramas on any web page. Panoramas must use the equirectangular projection and they can be taken with Photo Sphere, the camera mode brought by Android 4.2 Jelly Bean.
Photo Sphere Viewer uses the [Three.js](http://threejs.org) library, so nothing is required for your visitors except for a browser compatible with canvas or, better, WebGL.
+## Documentation
+http://photo-sphere-viewer.js.org
## License
-
This library is available under the MIT license.
diff --git a/bower.json b/bower.json
index 228296eb2..d2e1d84fb 100644
--- a/bower.json
+++ b/bower.json
@@ -1,8 +1,8 @@
{
"name": "Photo-Sphere-Viewer",
- "version": "3.0.1",
+ "version": "3.1.0",
"authors": [{
- "name": "Jérémy Heleine",
+ "name": "Jérémy Heleine",
"email": "jeremy.heleine@gmail.com",
"homepage": "http://jeremyheleine.me"
},{
diff --git a/dist/photo-sphere-viewer.css b/dist/photo-sphere-viewer.css
index 9c69ff2a0..e47ee1324 100644
--- a/dist/photo-sphere-viewer.css
+++ b/dist/photo-sphere-viewer.css
@@ -1,7 +1,7 @@
/*!
- * Photo Sphere Viewer 3.0.1
+ * Photo Sphere Viewer 3.1.0
* Copyright (c) 2014-2015 Jérémy Heleine
- * Copyright (c) 2015 Damien "Mistic" Sorel
+ * Copyright (c) 2015-2016 Damien "Mistic" Sorel
* Licensed under MIT (http://opensource.org/licenses/MIT)
*/
@@ -131,7 +131,7 @@
position: absolute;
width: 20px;
height: 7px;
- left: 8px;
+ left: 10px;
bottom: 10px;
border: 2px solid rgba(255, 255, 255, 0.7);
border-top-width: 0;
@@ -184,7 +184,7 @@
.psv-navbar .fullscreen-button div:before, .psv-navbar .fullscreen-button div:after {
content: '';
position: absolute;
- width: 6.0px;
+ width: 6px;
height: 4px;
border-style: solid;
border-color: rgba(255, 255, 255, 0.7);
@@ -329,7 +329,7 @@
width: 100%;
height: 100%;
}
-.psv-hud .marker {
+.psv-hud .psv-marker {
position: absolute;
top: 0;
left: 0;
@@ -338,7 +338,11 @@
cursor: pointer;
display: none;
}
-.psv-hud .marker.visible {
+.psv-hud .psv-marker.transparent {
+ display: block;
+ opacity: 0;
+}
+.psv-hud .psv-marker.visible {
display: block;
}
diff --git a/dist/photo-sphere-viewer.js b/dist/photo-sphere-viewer.js
index f84ed4cfc..8855748a7 100644
--- a/dist/photo-sphere-viewer.js
+++ b/dist/photo-sphere-viewer.js
@@ -1,17 +1,17 @@
/*!
- * Photo Sphere Viewer 3.0.1
+ * Photo Sphere Viewer 3.1.0
* Copyright (c) 2014-2015 Jérémy Heleine
- * Copyright (c) 2015 Damien "Mistic" Sorel
+ * Copyright (c) 2015-2016 Damien "Mistic" Sorel
* Licensed under MIT (http://opensource.org/licenses/MIT)
*/
(function(root, factory) {
- if (typeof define === 'function' && define.amd) {
- define(['three'], factory);
- }
- else {
- root.PhotoSphereViewer = factory(root.THREE);
- }
+ if (typeof define === 'function' && define.amd) {
+ define(['three'], factory);
+ }
+ else {
+ root.PhotoSphereViewer = factory(root.THREE);
+ }
}(this, function(THREE) {
"use strict";
@@ -45,13 +45,18 @@ function PhotoSphereViewer(options) {
this.config.anim_lat = this.config.default_lat;
}
this.config.anim_lat = PSVUtils.stayBetween(this.config.anim_lat, -PhotoSphereViewer.HalfPI, PhotoSphereViewer.HalfPI);
-
+
if (this.config.tilt_up_max < this.config.tilt_down_max) {
throw new PSVError('tilt_up_max cannot be lower than tilt_down_max');
}
+ if (this.config.caption && !this.config.navbar) {
+ this.config.navbar = 'caption';
+ }
+
// references to components
- this.container = (typeof this.config.container == 'string') ? document.getElementById(this.config.container) : this.config.container;
+ this.parent = (typeof this.config.container == 'string') ? document.getElementById(this.config.container) : this.config.container;
+ this.container = null;
this.loader = null;
this.navbar = null;
this.hud = null;
@@ -61,6 +66,7 @@ function PhotoSphereViewer(options) {
this.renderer = null;
this.scene = null;
this.camera = null;
+ this.mesh = null;
this.raycaster = null;
this.actions = {};
@@ -93,7 +99,12 @@ function PhotoSphereViewer(options) {
// compute zoom level
this.prop.zoom_lvl = Math.round((this.config.default_fov - this.config.min_fov) / (this.config.max_fov - this.config.min_fov) * 100);
- this.prop.zoom_lvl-= 2 * (this.prop.zoom_lvl - 50);
+ this.prop.zoom_lvl -= 2 * (this.prop.zoom_lvl - 50);
+
+ // create actual container
+ this.container = document.createElement('div');
+ this.container.classList.add('psv-container');
+ this.parent.appendChild(this.container);
// init
this.setAnimSpeed(this.config.anim_speed);
@@ -101,8 +112,7 @@ function PhotoSphereViewer(options) {
this.rotate(this.config.default_long, this.config.default_lat);
if (this.config.size !== null) {
- this.container.style.width = this.config.size.width;
- this.container.style.height = this.config.size.height;
+ this._setViewerSize(this.config.size);
}
if (this.config.autoload) {
@@ -161,12 +171,76 @@ PhotoSphereViewer.DEFAULTS = {
markers: []
};
+/**
+ * Destroy the viewer
+ */
+PhotoSphereViewer.prototype.destroy = function() {
+ // remove listeners
+ window.removeEventListener('resize', this);
+ document.removeEventListener(PSVUtils.fullscreenEvent(), this);
+
+ if (this.config.mousemove) {
+ this.hud.container.removeEventListener('mousedown', this);
+ this.hud.container.removeEventListener('touchstart', this);
+ window.removeEventListener('mouseup', this);
+ window.removeEventListener('touchend', this);
+ this.hud.container.removeEventListener('mousemove', this);
+ this.hud.container.removeEventListener('touchmove', this);
+ }
+
+ if (this.config.mousewheel) {
+ this.hud.container.removeEventListener(PSVUtils.mouseWheelEvent(), this);
+ }
+
+ // destroy components
+ if (this.hud) this.hud.destroy();
+ if (this.loader) this.loader.destroy();
+ if (this.navbar) this.navbar.destroy();
+ if (this.panel) this.panel.destroy();
+ if (this.tooltip) this.tooltip.destroy();
+
+ // destroy ThreeJS view
+ if (this.scene) {
+ this.scene.remove(this.camera);
+ this.scene.remove(this.mesh);
+ }
+
+ if (this.mesh) {
+ if (this.mesh.material) {
+ if (this.mesh.material.geometry) this.mesh.material.geometry.dispose();
+ if (this.mesh.material.map) this.mesh.material.map.dispose();
+ this.mesh.material.dispose();
+ }
+ }
+
+ // remove container
+ if (this.canvas_container) {
+ this.container.removeChild(this.canvas_container);
+ }
+ this.parent.removeChild(this.container);
+
+ // clean references
+ this.container = null;
+ this.loader = null;
+ this.navbar = null;
+ this.hud = null;
+ this.panel = null;
+ this.tooltip = null;
+ this.canvas_container = null;
+ this.renderer = null;
+ this.scene = null;
+ this.camera = null;
+ this.mesh = null;
+ this.raycaster = null;
+ this.actions = {};
+};
+
/**
* Starts to load the panorama
* @return (void)
*/
PhotoSphereViewer.prototype.load = function() {
- this.container.classList.add('psv-container', 'loading');
+ this.container.classList.add('loading');
// Is canvas supported?
if (!PSVUtils.isCanvasSupported()) {
@@ -221,12 +295,12 @@ PhotoSphereViewer.prototype._loadXMP = function() {
}
var pano_data = {
- full_width: parseInt(PSVUtils.getAttribute(data, 'FullPanoWidthPixels')),
- full_height: parseInt(PSVUtils.getAttribute(data, 'FullPanoHeightPixels')),
- cropped_width: parseInt(PSVUtils.getAttribute(data, 'CroppedAreaImageWidthPixels')),
- cropped_height: parseInt(PSVUtils.getAttribute(data, 'CroppedAreaImageHeightPixels')),
- cropped_x: parseInt(PSVUtils.getAttribute(data, 'CroppedAreaLeftPixels')),
- cropped_y: parseInt(PSVUtils.getAttribute(data, 'CroppedAreaTopPixels')),
+ full_width: parseInt(PSVUtils.getXMPValue(data, 'FullPanoWidthPixels')),
+ full_height: parseInt(PSVUtils.getXMPValue(data, 'FullPanoHeightPixels')),
+ cropped_width: parseInt(PSVUtils.getXMPValue(data, 'CroppedAreaImageWidthPixels')),
+ cropped_height: parseInt(PSVUtils.getXMPValue(data, 'CroppedAreaImageHeightPixels')),
+ cropped_x: parseInt(PSVUtils.getXMPValue(data, 'CroppedAreaLeftPixels')),
+ cropped_y: parseInt(PSVUtils.getXMPValue(data, 'CroppedAreaTopPixels'))
};
self._loadTexture(pano_data, true);
@@ -285,7 +359,7 @@ PhotoSphereViewer.prototype._loadTexture = function(pano_data, in_cache) {
cropped_width: img.width,
cropped_height: img.height,
cropped_x: 0,
- cropped_y: 0,
+ cropped_y: 0
};
}
@@ -315,7 +389,7 @@ PhotoSphereViewer.prototype._loadTexture = function(pano_data, in_cache) {
var ctx = buffer.getContext('2d');
ctx.drawImage(img, pano_data.cropped_x, pano_data.cropped_y, pano_data.cropped_width, pano_data.cropped_height);
-
+
self.prop.size.image_width = pano_data.cropped_width;
self.prop.size.image_height = pano_data.cropped_height;
@@ -346,7 +420,7 @@ PhotoSphereViewer.prototype._loadTexture = function(pano_data, in_cache) {
*/
PhotoSphereViewer.prototype._createScene = function(img) {
this._onResize();
-
+
this.raycaster = new THREE.Raycaster();
// Renderer depends on whether WebGL is supported or not
@@ -362,18 +436,18 @@ PhotoSphereViewer.prototype._createScene = function(img) {
var texture = new THREE.Texture(img);
texture.needsUpdate = true;
- // default texture origin is at 1/4 (phiStart=0) of the panorama, I set it at 1/2 (phiStart=PI/2)
+ // The middle of the panorama is placed at longitude=0
var geometry = new THREE.SphereGeometry(200, 32, 32, -PhotoSphereViewer.HalfPI);
- var material = new THREE.MeshBasicMaterial({map: texture, overdraw: true});
+ var material = new THREE.MeshBasicMaterial({ map: texture, overdraw: true });
material.side = THREE.DoubleSide;
- var mesh = new THREE.Mesh(geometry, material);
- mesh.scale.x = -1;
+ this.mesh = new THREE.Mesh(geometry, material);
+ this.mesh.scale.x = -1;
- this.scene.add(mesh);
+ this.scene.add(this.mesh);
this.canvas_container.appendChild(this.renderer.domElement);
// Remove loader
- this.container.removeChild(this.loader.container);
+ this.loader.destroy();
this.loader = null;
this.container.classList.remove('loading');
@@ -381,23 +455,19 @@ PhotoSphereViewer.prototype._createScene = function(img) {
if (this.config.navbar) {
this.container.classList.add('has-navbar');
this.navbar = new PSVNavBar(this);
- this.container.appendChild(this.navbar.container);
}
-
+
// HUD
this.hud = new PSVHUD(this);
this.config.markers.forEach(function(marker) {
- this.hud.addMarker(marker, true);
+ this.hud.addMarker(marker, false);
}, this);
- this.container.appendChild(this.hud.container);
-
+
// Panel
this.panel = new PSVPanel(this);
- this.container.appendChild(this.panel.container);
-
+
// Tooltip
this.tooltip = new PSVTooltip(this);
- this.container.appendChild(this.tooltip.container);
// Queue animation
if (this.config.time_anim !== false) {
@@ -414,22 +484,42 @@ PhotoSphereViewer.prototype._createScene = function(img) {
* @return (void)
*/
PhotoSphereViewer.prototype._bindEvents = function() {
- window.addEventListener('resize', this._onResize.bind(this));
- document.addEventListener(PSVUtils.fullscreenEvent(), this._fullscreenToggled.bind(this));
-
+ window.addEventListener('resize', this);
+ document.addEventListener(PSVUtils.fullscreenEvent(), this);
+
// all interation events are binded to the HUD only
if (this.config.mousemove) {
this.hud.container.style.cursor = 'move';
- this.hud.container.addEventListener('mousedown', this._onMouseDown.bind(this));
- this.hud.container.addEventListener('touchstart', this._onTouchStart.bind(this));
- this.hud.container.addEventListener('mouseup', this._onMouseUp.bind(this));
- this.hud.container.addEventListener('touchend', this._onTouchEnd.bind(this));
- this.hud.container.addEventListener('mousemove', this._onMouseMove.bind(this));
- this.hud.container.addEventListener('touchmove', this._onTouchMove.bind(this));
- }
-
+ this.hud.container.addEventListener('mousedown', this);
+ this.hud.container.addEventListener('touchstart', this);
+ window.addEventListener('mouseup', this);
+ window.addEventListener('touchend', this);
+ this.hud.container.addEventListener('mousemove', this);
+ this.hud.container.addEventListener('touchmove', this);
+ }
+
if (this.config.mousewheel) {
- this.hud.container.addEventListener(PSVUtils.mouseWheelEvent(), this._onMouseWheel.bind(this));
+ this.hud.container.addEventListener(PSVUtils.mouseWheelEvent(), this);
+ }
+};
+
+/**
+ * Handle events
+ * @param e (Event)
+ */
+PhotoSphereViewer.prototype.handleEvent = function(e) {
+ switch (e.type) {
+ // @formatter:off
+ case 'resize': this._onResize(); break;
+ case 'mousedown': this._onMouseDown(e); break;
+ case 'touchstart': this._onTouchStart(e); break;
+ case 'mouseup': this._onMouseUp(e); break;
+ case 'touchend': this._onTouchEnd(e); break;
+ case 'mousemove': this._onMouseMove(e); break;
+ case 'touchmove': this._onTouchMove(e); break;
+ case PSVUtils.fullscreenEvent(): this._fullscreenToggled(); break;
+ case PSVUtils.mouseWheelEvent(): this._onMouseWheel(e); break;
+ // @formatter:on
}
};
@@ -470,9 +560,9 @@ PhotoSphereViewer.prototype._autorotate = function() {
PhotoSphereViewer.prototype.startAutorotate = function() {
clearTimeout(this.prop.start_timeout);
this.prop.start_timeout = null;
-
+
this.stopAnimation();
-
+
this._autorotate();
this.trigger('autorotate', true);
};
@@ -520,7 +610,7 @@ PhotoSphereViewer.prototype._onResize = function() {
* @param height (integer) The new canvas height
* @return (void)
*/
-PhotoSphereViewer.prototype.resize = function (width, height) {
+PhotoSphereViewer.prototype.resize = function(width, height) {
this.prop.size.width = parseInt(width);
this.prop.size.height = parseInt(height);
this.prop.size.ratio = this.prop.size.width / this.prop.size.height;
@@ -584,11 +674,11 @@ PhotoSphereViewer.prototype._startMove = function(evt) {
*/
PhotoSphereViewer.prototype._startZoom = 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)}
+ { 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.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.zooming = true;
@@ -628,7 +718,7 @@ PhotoSphereViewer.prototype._stopMove = function(evt) {
this.prop.moved = true;
}
}
-
+
this.prop.moving = false;
this.prop.zooming = false;
};
@@ -643,9 +733,9 @@ PhotoSphereViewer.prototype._click = function(evt) {
if (evt.defaultPrevented) {
return;
}
-
+
var boundingRect = this.container.getBoundingClientRect();
-
+
var data = {
client_x: parseInt(evt.clientX - boundingRect.left),
client_y: parseInt(evt.clientY - boundingRect.top)
@@ -653,27 +743,27 @@ PhotoSphereViewer.prototype._click = function(evt) {
var screen = new THREE.Vector2(
2 * data.client_x / this.prop.size.width - 1,
- - 2 * data.client_y / this.prop.size.height + 1
+ -2 * data.client_y / this.prop.size.height + 1
);
-
+
this.raycaster.setFromCamera(screen, this.camera);
-
+
var intersects = this.raycaster.intersectObjects(this.scene.children);
-
- if (intersects.length === 1) {
+
+ if (intersects.length === 1) {
var p = intersects[0].point;
- var phi = Math.acos(p.y / Math.sqrt(p.x*p.x + p.y*p.y + p.z*p.z));
+ var phi = Math.acos(p.y / Math.sqrt(p.x * p.x + p.y * p.y + p.z * p.z));
var theta = Math.atan2(p.x, p.z);
-
- data.longitude = theta < 0 ? - theta : PhotoSphereViewer.TwoPI - theta;
+
+ data.longitude = theta < 0 ? -theta : PhotoSphereViewer.TwoPI - theta;
data.latitude = PhotoSphereViewer.HalfPI - phi;
-
+
var relativeLong = data.longitude / PhotoSphereViewer.TwoPI * this.prop.size.image_width;
var relativeLat = data.latitude / PhotoSphereViewer.PI * this.prop.size.image_height;
- data.texture_x = parseInt(data.longitude < PhotoSphereViewer.PI ? relativeLong + this.prop.size.image_width/2 : relativeLong - this.prop.size.image_width/2);
- data.texture_y = parseInt(this.prop.size.image_height/2 - relativeLat);
-
+ data.texture_x = parseInt(data.longitude < PhotoSphereViewer.PI ? relativeLong + this.prop.size.image_width / 2 : relativeLong - this.prop.size.image_width / 2);
+ data.texture_y = parseInt(this.prop.size.image_height / 2 - relativeLat);
+
this.trigger('click', data);
}
};
@@ -713,7 +803,7 @@ PhotoSphereViewer.prototype._move = function(evt) {
if (this.prop.moving) {
var x = parseInt(evt.clientX);
var y = parseInt(evt.clientY);
-
+
this.rotate(
this.prop.longitude - (x - this.prop.mouse_x) * this.config.long_offset,
this.prop.latitude + (y - this.prop.mouse_y) * this.config.lat_offset
@@ -732,13 +822,13 @@ PhotoSphereViewer.prototype._move = function(evt) {
PhotoSphereViewer.prototype._zoom = function(evt) {
if (this.prop.zooming) {
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)}
+ { x: parseInt(evt.touches[0].clientX), y: parseInt(evt.touches[0].clientY) },
+ { x: parseInt(evt.touches[1].clientX), y: parseInt(evt.touches[1].clientY) }
];
-
- var p = Math.sqrt(Math.pow(t[0].x-t[1].x, 2) + Math.pow(t[0].y-t[1].y, 2));
+
+ var p = Math.sqrt(Math.pow(t[0].x - t[1].x, 2) + Math.pow(t[0].y - t[1].y, 2));
var delta = 80 * (p - this.prop.pinch_dist) / this.prop.size.width;
-
+
this.zoom(this.prop.zoom_lvl + delta);
this.prop.pinch_dist = p;
@@ -774,13 +864,13 @@ PhotoSphereViewer.prototype.animate = function(t, p, s) {
this.rotate(t, p);
return;
}
-
+
t = t - Math.floor(t / PhotoSphereViewer.TwoPI) * PhotoSphereViewer.TwoPI;
p = PSVUtils.stayBetween(p, this.config.tilt_down_max, this.config.tilt_up_max);
var t0 = this.prop.longitude;
var p0 = this.prop.latitude;
-
+
// get duration of animation
var duration;
if (s && typeof s === 'number') {
@@ -788,31 +878,31 @@ PhotoSphereViewer.prototype.animate = function(t, p, s) {
}
else {
// desired radial speed
- var speed = s ? this.parseAnimSpeed(s) : this.prop.anim_speed;
+ var speed = s ? this._parseAnimSpeed(s) : this.prop.anim_speed;
// get the angle between current position and target
- var angle = Math.acos(Math.cos(p0) * Math.cos(p) * Math.cos(t0-t) + Math.sin(p0) * Math.sin(p));
+ var angle = Math.acos(Math.cos(p0) * Math.cos(p) * Math.cos(t0 - t) + Math.sin(p0) * Math.sin(p));
duration = angle / speed;
}
-
+
var steps = duration * this.prop.fps;
-
+
// longitude offset for shortest arc
var tCandidates = [
t - t0, // direct
PhotoSphereViewer.TwoPI - t0 + t, // clock-wise cross zero
t - t0 - PhotoSphereViewer.TwoPI // counter-clock-wise cross zero
];
-
+
var tOffset = tCandidates.reduce(function(value, candidate) {
return Math.abs(candidate) < Math.abs(value) ? candidate : value;
}, Infinity);
-
+
// latitude offset
var pOffset = p - p0;
-
+
this.stopAutorotate();
this.stopAnimation();
-
+
this._animate(tOffset / steps, pOffset / steps, t, p);
};
@@ -833,12 +923,12 @@ PhotoSphereViewer.prototype._animate = function(tStep, pStep, tTarget, pTarget)
pStep = 0;
this.prop.latitude = pTarget;
}
-
+
this.rotate(
this.prop.longitude + tStep,
this.prop.latitude + pStep
);
-
+
if (tStep !== 0 || pStep !== 0) {
this.prop.animation_timeout = setTimeout(this._animate.bind(this, tStep, pStep, tTarget, pTarget), 1000 / this.prop.fps);
}
@@ -865,7 +955,7 @@ PhotoSphereViewer.prototype._onMouseWheel = function(evt) {
evt.preventDefault();
evt.stopPropagation();
- var delta = evt.deltaY!==undefined ? -evt.deltaY : (evt.wheelDelta!==undefined ? evt.wheelDelta : -evt.detail);
+ var delta = evt.deltaY !== undefined ? -evt.deltaY : (evt.wheelDelta !== undefined ? evt.wheelDelta : -evt.detail);
if (delta !== 0) {
var direction = parseInt(delta / Math.abs(delta));
@@ -934,7 +1024,7 @@ PhotoSphereViewer.prototype.toggleFullscreen = function() {
* @param speed (string) The speed, in radians/degrees/revolutions per second/minute
* @return (double) radians per second
*/
-PhotoSphereViewer.prototype.parseAnimSpeed = function(speed) {
+PhotoSphereViewer.prototype._parseAnimSpeed = function(speed) {
speed = speed.toString().trim();
// Speed extraction
@@ -976,7 +1066,7 @@ PhotoSphereViewer.prototype.parseAnimSpeed = function(speed) {
default:
throw new PSVError('unknown speed unit "' + speed_unit + '"');
}
-
+
return rad_per_second;
};
@@ -986,21 +1076,52 @@ PhotoSphereViewer.prototype.parseAnimSpeed = function(speed) {
* @return (void)
*/
PhotoSphereViewer.prototype.setAnimSpeed = function(speed) {
- this.prop.anim_speed = this.parseAnimSpeed(speed);
+ this.prop.anim_speed = this._parseAnimSpeed(speed);
+};
+
+/**
+ * Sets the viewer size
+ * @param size (Object) An object containing the wanted width and height
+ * @return (void)
+ */
+PhotoSphereViewer.prototype._setViewerSize = function(size) {
+ ['width', 'height'].forEach(function(dim) {
+ if (size[dim]) {
+ if (/^[0-9.]+$/.test(size[dim])) size[dim] += 'px';
+ this.parent.style[dim] = size[dim];
+ }
+ }, this);
};
/**
- * Adds an action
+ * Adds an event listener
+ * If "func" is an object, its "handleEvent" method will be called with an object as paremeter
+ * - type: name of the event prefixed with "psv:"
+ * - args: array of action arguments
* @param name (string) Action name
- * @param f (Function) The handler function
+ * @param func (Function|Object) The handler function, or an object with an "handleEvent" method
* @return (void)
*/
-PhotoSphereViewer.prototype.on = function(name, f) {
+PhotoSphereViewer.prototype.on = function(name, func) {
if (!(name in this.actions)) {
this.actions[name] = [];
}
- this.actions[name].push(f);
+ this.actions[name].push(func);
+};
+
+/**
+ * Removes an event listener
+ * @param name (string) Action name
+ * @param func (Function|Object)
+ */
+PhotoSphereViewer.prototype.off = function(name, func) {
+ if (name in this.actions) {
+ var idx = this.actions[name].indexOf(func);
+ if (idx !== -1) {
+ this.actions[name].splice(idx, 1);
+ }
+ }
};
/**
@@ -1012,19 +1133,29 @@ PhotoSphereViewer.prototype.on = function(name, f) {
PhotoSphereViewer.prototype.trigger = function(name, args) {
args = Array.prototype.slice.call(arguments, 1);
if ((name in this.actions) && this.actions[name].length > 0) {
- for (var i = 0, l = this.actions[name].length; i < l; ++i) {
- this.actions[name][i].apply(this, args);
- }
+ this.actions[name].forEach(function(func) {
+ if (typeof func === 'object') {
+ func.handleEvent({
+ type: 'psv:' + name,
+ args: args
+ });
+ }
+ else {
+ func.apply(this, args);
+ }
+ }, this);
}
};
+
/**
- * Base sub component class
+ * Base sub-component class
* @param psv (PhotoSphereViewer) A PhotoSphereViewer object
*/
function PSVComponent(psv) {
- this.psv = psv;
-
+ this.psv = psv;
+ this.container = null;
+
// expose some methods to the viewer
if (this.constructor.publicMethods) {
this.constructor.publicMethods.forEach(function(method) {
@@ -1033,6 +1164,26 @@ function PSVComponent(psv) {
}
}
+/**
+ * Creates the component
+ */
+PSVComponent.prototype.create = function() {
+ this.container = document.createElement('div');
+
+ this.psv.container.appendChild(this.container);
+};
+
+/**
+ * Destroys the component
+ */
+PSVComponent.prototype.destroy = function() {
+ this.psv.container.removeChild(this.container);
+
+ this.container = null;
+ this.psv = null;
+};
+
+
/**
* Loader class
* @param psv (PhotoSphereViewer) A PhotoSphereViewer object
@@ -1041,7 +1192,7 @@ function PSVLoader(psv) {
this.psv = psv;
this.container = null;
this.canvas = null;
-
+
this.create();
}
@@ -1051,12 +1202,12 @@ function PSVLoader(psv) {
PSVLoader.prototype.create = function() {
this.container = document.createElement('div');
this.container.className = 'psv-loader';
-
+
this.psv.container.appendChild(this.container);
this.canvas = document.createElement('canvas');
this.canvas.className = 'loader-canvas';
-
+
this.canvas.width = this.container.clientWidth;
this.canvas.height = this.container.clientWidth;
this.container.appendChild(this.canvas);
@@ -1075,13 +1226,23 @@ PSVLoader.prototype.create = function() {
inner.innerHTML = this.psv.config.loading_txt;
}
if (inner) {
- var a = Math.round(Math.sqrt(2 * Math.pow(this.canvas.width/2-this.tickness/2, 2)));
+ var a = Math.round(Math.sqrt(2 * Math.pow(this.canvas.width / 2 - this.tickness / 2, 2)));
inner.style.maxWidth = a + 'px';
inner.style.maxHeight = a + 'px';
this.container.appendChild(inner);
}
};
+/**
+ * Destroys the loader
+ */
+PSVLoader.prototype.destroy = function() {
+ this.psv.container.removeChild(this.container);
+
+ this.psv = null;
+ this.container = null;
+};
+
/**
* Sets the loader progression
* @param value (int) from 0 to 100
@@ -1096,164 +1257,246 @@ PSVLoader.prototype.setProgress = function(value) {
context.beginPath();
context.arc(
- this.canvas.width/2, this.canvas.height/2,
- this.canvas.width/2 - this.tickness/2,
- -Math.PI/2, value/100 * 2*Math.PI - Math.PI/2
+ this.canvas.width / 2, this.canvas.height / 2,
+ this.canvas.width / 2 - this.tickness / 2,
+ -Math.PI / 2, value / 100 * 2 * Math.PI - Math.PI / 2
);
context.stroke();
};
+
/**
* HUD class
* @param psv (PhotoSphereViewer) A PhotoSphereViewer object
*/
function PSVHUD(psv) {
PSVComponent.call(this, psv);
-
- this.container = null;
+
this.markers = {};
this.currentMarker = null;
-
+
this.create();
}
PSVHUD.prototype = Object.create(PSVComponent.prototype);
PSVHUD.prototype.constructor = PSVHUD;
-PSVHUD.publicMethods = ['addMarker', 'removeMarker', 'getMarker', 'getCurrentMarker', 'gotoMarker', 'hideMarker', 'showMarker', 'toggleMarker'];
+PSVHUD.publicMethods = ['addMarker', 'removeMarker', 'updateMarker', 'getMarker', 'getCurrentMarker', 'gotoMarker', 'hideMarker', 'showMarker', 'toggleMarker'];
/**
- * Creates the elements
+ * Creates the HUD
* @return (void)
*/
PSVHUD.prototype.create = function() {
- this.container = document.createElement('div');
+ PSVComponent.prototype.create.call(this);
+
this.container.className = 'psv-hud';
-
+
// Markers events via delegation
- this.container.addEventListener('mouseenter', this._onMouseEnter.bind(this), true);
- this.container.addEventListener('mouseleave', this._onMouseLeave.bind(this), true);
-
- this.psv.on('_click', this._onClick.bind(this), true);
-
- this.psv.on('render', this.updatePositions.bind(this));
+ this.container.addEventListener('mouseenter', this, true);
+ this.container.addEventListener('mouseleave', this, true);
+
+ // Viewer events
+ this.psv.on('_click', this);
+ this.psv.on('render', this);
+};
+
+/**
+ * Destroys the HUD
+ */
+PSVHUD.prototype.destroy = function() {
+ this.container.removeEventListener('mouseenter', this);
+ this.container.removeEventListener('mouseleave', this);
+
+ this.psv.off('_click', this);
+ this.psv.off('render', this);
+
+ PSVComponent.prototype.destroy.call(this);
+};
+
+/**
+ * Handle events
+ * @param e (Event)
+ */
+PSVHUD.prototype.handleEvent = function(e) {
+ switch (e.type) {
+ // @formatter:off
+ case 'mouseenter': this._onMouseEnter(e); break;
+ case 'mouseleave': this._onMouseLeave(e); break;
+ case 'psv:_click': this._onClick(e.args[0]); break;
+ case 'psv:render': this.updatePositions(); break;
+ // @formatter:on
+ }
};
/**
* Add a new marker to HUD
* @param marker (Object)
- * @param noRender (Boolean) disable immediate render
+ * @param render (Boolean) "false" to disable immediate render
* @return (Object) a modified marker object
*/
-PSVHUD.prototype.addMarker = function(marker, noRender) {
+PSVHUD.prototype.addMarker = function(marker, render) {
if (!marker.id) {
throw new PSVError('missing marker id');
}
-
+
if (this.markers[marker.id]) {
throw new PSVError('marker "' + marker.id + '" already exists');
}
-
- if (!marker.width || !marker.height) {
- throw new PSVError('missing marker width/height');
+
+ if (!marker.image && !marker.html) {
+ throw new PSVError('missing marker image/html');
}
-
- if (!marker.image) {
- throw new PSVError('missing marker image');
+
+ if (marker.image && (!marker.width || !marker.height)) {
+ throw new PSVError('missing marker width/height');
}
-
- if ((!marker.hasOwnProperty('x') || !marker.hasOwnProperty('y')) & (!marker.hasOwnProperty('latitude') || !marker.hasOwnProperty('longitude'))) {
+
+ if ((!marker.hasOwnProperty('x') || !marker.hasOwnProperty('y')) && (!marker.hasOwnProperty('latitude') || !marker.hasOwnProperty('longitude'))) {
throw new PSVError('missing marker position, latitude/longitude or x/y');
}
- marker = PSVUtils.clone(marker);
-
// create DOM
marker.$el = document.createElement('div');
- marker.$el.psvMarker = marker;
- marker.$el.className = 'marker';
-
+ marker.$el.id = 'psv-marker-' + marker.id;
+ marker.$el.className = 'psv-marker';
+
+ this.markers[marker.id] = marker; // will be replaced by updateMarker
+ this.container.appendChild(marker.$el);
+
+ return this.updateMarker(PSVUtils.clone(marker), render);
+
+};
+
+/**
+ * Get a marker by it's id or external object
+ * @param marker (Mixed)
+ * @return (Object)
+ */
+PSVHUD.prototype.getMarker = function(marker) {
+ var id = typeof marker === 'object' ? marker.id : marker;
+
+ if (!this.markers[id]) {
+ throw new PSVError('cannot find marker "' + id + '"');
+ }
+
+ return this.markers[id];
+};
+
+/**
+ * Get the current selected marker
+ * @return (Object)
+ */
+PSVHUD.prototype.getCurrentMarker = function() {
+ return this.currentMarker;
+};
+
+/**
+ * Update a marker
+ * @param marker (Object)
+ * @param render (Boolean) "false" to disable immediate render
+ * @return (Object) a modified marker object
+ */
+PSVHUD.prototype.updateMarker = function(marker, render) {
+ var old = this.getMarker(marker);
+
+ // clean some previous data
+ if (old.className) {
+ old.$el.classList.remove(old.className);
+ }
+ if (old.tooltip) {
+ old.$el.classList.remove('has-tooltip');
+ }
+
+ // merge objects
+ delete marker.$el;
+ marker = PSVUtils.deepmerge(old, marker);
+
+ marker.position2D = null;
+
+ // add classes
if (marker.className) {
marker.$el.classList.add(marker.className);
}
if (marker.tooltip) {
marker.$el.classList.add('has-tooltip');
+ if (typeof marker.tooltip === 'string') {
+ marker.tooltip = { content: marker.tooltip };
+ }
}
-
+
// set image
var style = marker.$el.style;
- style.width = marker.width + 'px';
- style.height = marker.height + 'px';
- style.backgroundImage = 'url(' + marker.image + ')';
-
+
+ if (marker.width && marker.height) {
+ style.width = marker.width + 'px';
+ style.height = marker.height + 'px';
+ marker.dynamicSize = false;
+ }
+ else {
+ marker.dynamicSize = true;
+ }
+
+ if (marker.style) {
+ Object.getOwnPropertyNames(marker.style).forEach(function(prop) {
+ style[prop] = marker.style[prop];
+ });
+ }
+
+ if (marker.image) {
+ style.backgroundImage = 'url(' + marker.image + ')';
+ }
+ else {
+ marker.$el.innerHTML = marker.html;
+ }
+
// parse anchor
marker.anchor = PSVUtils.parsePosition(marker.anchor);
-
+
// convert texture coordinates to spherical coordinates
if (marker.hasOwnProperty('x') && marker.hasOwnProperty('y')) {
var relativeX = marker.x / this.psv.prop.size.image_width * PhotoSphereViewer.TwoPI;
var relativeY = marker.y / this.psv.prop.size.image_height * PhotoSphereViewer.PI;
-
+
marker.longitude = relativeX >= PhotoSphereViewer.PI ? relativeX - PhotoSphereViewer.PI : relativeX + PhotoSphereViewer.PI;
marker.latitude = PhotoSphereViewer.HalfPI - relativeY;
}
-
+
// compute x/y/z position
marker.position3D = new THREE.Vector3(
-Math.cos(marker.latitude) * Math.sin(marker.longitude),
Math.sin(marker.latitude),
Math.cos(marker.latitude) * Math.cos(marker.longitude)
);
-
+
if (!marker.hasOwnProperty('visible')) {
marker.visible = true;
}
-
+
// save
+ marker.$el.psvMarker = marker;
this.markers[marker.id] = marker;
- this.container.appendChild(marker.$el);
-
- if (!noRender) {
- this.updatePositions();
- }
-
- return marker;
-};
-/**
- * Get a marker by it's id or external object
- * @param marker (Mixed)
- * @return (Object)
- */
-PSVHUD.prototype.getMarker = function(marker) {
- var id = typeof marker === 'object' ? marker.id : marker;
-
- if (!this.markers[id]) {
- throw new PSVError('cannot find marker "' + id + '"');
+ if (render !== false) {
+ this.updatePositions();
}
-
- return this.markers[id];
-};
-/**
- * Get the current selected marker
- * @return (Object)
- */
-PSVHUD.prototype.getCurrentMarker = function() {
- return this.currentMarker;
+ return marker;
};
/**
* Remove a marker
* @param marker (Mixed)
- * @param noRender (Boolean)
+ * @param render (Boolean) "false" to disable immediate render
* @return (void)
*/
-PSVHUD.prototype.removeMarker = function(marker, noRender) {
+PSVHUD.prototype.removeMarker = function(marker, render) {
marker = this.getMarker(marker);
+
+ marker.$el.parentNode.removeChild(marker.$el);
delete this.markers[marker.id];
-
- if (!noRender) {
+
+ if (render !== false) {
this.updatePositions();
}
};
@@ -1295,7 +1538,7 @@ PSVHUD.prototype.showMarker = function(marker) {
* @return (void)
*/
PSVHUD.prototype.toggleMarker = function(marker) {
- this.getMarker(marker).visible^= true;
+ this.getMarker(marker).visible ^= true;
this.updatePositions();
};
@@ -1309,15 +1552,15 @@ PSVHUD.prototype.updatePositions = function() {
for (var id in this.markers) {
var marker = this.markers[id];
var position = this._getMarkerPosition(marker);
-
+
if (this._isMarkerVisible(marker, position)) {
marker.position2D = position;
-
- marker.$el.style.transform = 'translate3D(' +
- position.left + 'px, ' +
+
+ marker.$el.style.transform = 'translate3D(' +
+ position.left + 'px, ' +
position.top + 'px, ' +
'0px)';
-
+
if (!marker.$el.classList.contains('visible')) {
marker.$el.classList.add('visible');
}
@@ -1339,10 +1582,10 @@ PSVHUD.prototype.updatePositions = function() {
PSVHUD.prototype._isMarkerVisible = function(marker, position) {
return marker.visible &&
marker.position3D.dot(this.psv.prop.direction) > 0 &&
- position.left >= 0 &&
- position.left + marker.width <= this.psv.prop.size.width &&
- position.top >= 0 &&
- position.top + marker.height <= this.psv.prop.size.height;
+ position.left + marker.width >= 0 &&
+ position.left - marker.width <= this.psv.prop.size.width &&
+ position.top + marker.height >= 0 &&
+ position.top - marker.height <= this.psv.prop.size.height;
};
/**
@@ -1351,6 +1594,16 @@ PSVHUD.prototype._isMarkerVisible = function(marker, position) {
* @return (Object) top and left position
*/
PSVHUD.prototype._getMarkerPosition = function(marker) {
+ if (marker.dynamicSize) {
+ // make the marker visible to get it's size
+ marker.$el.classList.add('transparent');
+ var rect = marker.$el.getBoundingClientRect();
+ marker.$el.classList.remove('transparent');
+
+ marker.width = rect.right - rect.left;
+ marker.height = rect.bottom - rect.top;
+ }
+
var vector = marker.position3D.clone();
vector.project(this.psv.camera);
@@ -1367,7 +1620,14 @@ PSVHUD.prototype._getMarkerPosition = function(marker) {
*/
PSVHUD.prototype._onMouseEnter = function(e) {
if (e.target && e.target.psvMarker && e.target.psvMarker.tooltip) {
- this.psv.tooltip.showTooltip(e.target.psvMarker.tooltip, e.target.psvMarker);
+ var marker = e.target.psvMarker;
+ this.psv.tooltip.showTooltip({
+ content: marker.tooltip.content,
+ position: marker.tooltip.position,
+ top: marker.position2D.top,
+ left: marker.position2D.left,
+ marker: marker
+ });
}
};
@@ -1383,24 +1643,25 @@ PSVHUD.prototype._onMouseLeave = function(e) {
};
/**
- * The mouse button is release : show/hide the panel if threeshold was not reached, or do nothing
+ * The mouse button is release : show/hide the panel if threshold was not reached, or do nothing
* @param e (Event)
* @return (void)
*/
PSVHUD.prototype._onClick = function(e) {
if (!this.psv.prop.moved) {
- if (e.target && e.target.psvMarker) {
- this.currentMarker = e.target.psvMarker;
- this.psv.trigger('select-marker', e.target.psvMarker);
+ var marker;
+ if (e.target && (marker = PSVUtils.getClosest(e.target, '.psv-marker')) && marker.psvMarker) {
+ this.currentMarker = marker.psvMarker;
+ this.psv.trigger('select-marker', marker.psvMarker);
e.preventDefault(); // prevent the public "click" event
}
- else {
+ else if (this.currentMarker) {
this.currentMarker = null;
this.psv.trigger('unselect-marker');
}
-
- if (e.target && e.target.psvMarker && e.target.psvMarker.content) {
- this.psv.panel.showPanel(e.target.psvMarker.content);
+
+ if (marker && marker.psvMarker && marker.psvMarker.content) {
+ this.psv.panel.showPanel(marker.psvMarker.content);
}
else if (this.psv.panel.prop.opened) {
e.preventDefault(); // prevent the public "click" event
@@ -1409,6 +1670,7 @@ PSVHUD.prototype._onClick = function(e) {
}
};
+
/*jshint multistr: true */
/**
@@ -1417,17 +1679,16 @@ PSVHUD.prototype._onClick = function(e) {
*/
function PSVPanel(psv) {
PSVComponent.call(this, psv);
-
- this.container = null;
+
this.content = null;
-
+
this.prop = {
mouse_x: 0,
mouse_y: 0,
mousedown: false,
opened: false
};
-
+
this.create();
}
@@ -1437,37 +1698,67 @@ PSVPanel.prototype.constructor = PSVPanel;
PSVPanel.publicMethods = ['showPanel', 'hidePanel'];
/**
- * Creates the elements
+ * Creates the panel
* @return (void)
*/
PSVPanel.prototype.create = function() {
- this.container = document.createElement('aside');
+ PSVComponent.prototype.create.call(this);
+
this.container.className = 'psv-panel';
this.container.innerHTML = '\
\
\
';
-
+
this.content = this.container.querySelector('.content');
-
+
var closeBtn = this.container.querySelector('.close-button');
closeBtn.addEventListener('click', this.hidePanel.bind(this));
-
+
// Stop event bubling from panel
if (this.psv.config.mousewheel) {
this.container.addEventListener(PSVUtils.mouseWheelEvent(), function(e) {
e.stopPropagation();
});
}
-
+
// Event for panel resizing + stop bubling
var resizer = this.container.querySelector('.resizer');
- resizer.addEventListener('mousedown', this._onMouseDown.bind(this));
- resizer.addEventListener('touchstart', this._onTouchStart.bind(this));
- this.psv.container.addEventListener('mouseup', this._onMouseUp.bind(this));
- this.psv.container.addEventListener('touchend', this._onMouseUp.bind(this));
- this.psv.container.addEventListener('mousemove', this._onMouseMove.bind(this));
- this.psv.container.addEventListener('touchmove', this._onTouchMove.bind(this));
+ resizer.addEventListener('mousedown', this);
+ resizer.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);
+};
+
+/**
+ * Destroys the panel
+ */
+PSVPanel.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);
+
+ PSVComponent.prototype.destroy.call(this);
+};
+
+/**
+ * Handle events
+ * @param e (Event)
+ */
+PSVPanel.prototype.handleEvent = function(e) {
+ switch (e.type) {
+ // @formatter:off
+ case 'mousedown': this._onMouseDown(e); break;
+ case 'touchstart': this._onTouchStart(e); break;
+ case 'mousemove': this._onMouseMove(e); break;
+ case 'touchmove': this._onMouseMove(e); break;
+ case 'mouseup': this._onMouseUp(e); break;
+ case 'touchend': this._onMouseUp(e); break;
+ // @formatter:on
+ }
};
/**
@@ -1480,7 +1771,7 @@ PSVPanel.prototype.showPanel = function(content, noMargin) {
this.content.innerHTML = content;
this.content.scrollTop = 0;
this.container.classList.add('open');
-
+
if (noMargin) {
if (!this.content.classList.contains('no-margin')) {
this.content.classList.add('no-margin');
@@ -1489,7 +1780,7 @@ PSVPanel.prototype.showPanel = function(content, noMargin) {
else {
this.content.classList.remove('no-margin');
}
-
+
this.prop.opened = true;
this.psv.trigger('open-panel');
};
@@ -1582,23 +1873,23 @@ PSVPanel.prototype._onTouchMove = function(evt) {
PSVPanel.prototype._resize = function(evt) {
var x = parseInt(evt.clientX);
var y = parseInt(evt.clientY);
-
+
this.container.style.width = (this.container.offsetWidth - (x - this.prop.mouse_x)) + 'px';
this.prop.mouse_x = x;
this.prop.mouse_y = y;
};
+
/**
* Tooltip class
* @param psv (PhotoSphereViewer) A PhotoSphereViewer object
*/
function PSVTooltip(psv) {
PSVComponent.call(this, psv);
-
+
this.config = this.psv.config.tooltip;
- this.container = null;
-
+
this.create();
}
@@ -1607,65 +1898,100 @@ PSVTooltip.prototype.constructor = PSVTooltip;
PSVTooltip.publicMethods = ['showTooltip', 'hideTooltip'];
-PSVTooltip.leftMap = {0: 'left', 0.5: 'center', 1: 'right'};
-PSVTooltip.topMap = {0: 'top', 0.5: 'center', 1: 'bottom'};
+PSVTooltip.leftMap = { 0: 'left', 0.5: 'center', 1: 'right' };
+PSVTooltip.topMap = { 0: 'top', 0.5: 'center', 1: 'bottom' };
/**
- * Creates the elements
+ * Creates the tooltip
* @return (void)
*/
PSVTooltip.prototype.create = function() {
- this.container = document.createElement('div');
+ PSVComponent.prototype.create.call(this);
+
this.container.innerHTML = '
';
this.container.className = 'psv-tooltip';
this.container.style.top = '-1000px';
this.container.style.left = '-1000px';
-
- this.psv.on('render', this.hideTooltip.bind(this));
+
+ this.psv.on('render', this);
+};
+
+/**
+ * Destroys the tooltip
+ */
+PSVTooltip.prototype.destroy = function() {
+ this.psv.off('render', this);
+
+ PSVComponent.prototype.destroy.call(this);
+};
+
+/**
+ * Handle events
+ * @param e (Event)
+ */
+PSVTooltip.prototype.handleEvent = function(e) {
+ switch (e.type) {
+ // @formatter:off
+ case 'psv:render': this.hideTooltip(); break;
+ // @formatter:on
+ }
};
/**
* Show the tooltip
- * @param tooltip (Mixed) content, className, position
- * @param marker (Object) target for positioning: width, height, position2D(top, left)
+ * @param config (Object)
+ * - content
+ * - top
+ * - left
+ * - position (default: 'top center')
+ * - className (optional)
+ * - marker (optional) -- take marker dimensions in account when positioning the tooltip
* @return (void)
*/
-PSVTooltip.prototype.showTooltip = function(tooltip, marker) {
+PSVTooltip.prototype.showTooltip = function(config) {
var t = this.container;
var c = t.querySelector('.content');
var a = t.querySelector('.arrow');
-
- if (typeof tooltip === 'string') {
- tooltip = {
- content: marker.tooltip,
- position: ['top', 'center']
+
+ if (!config.position) {
+ config.position = ['top', 'center'];
+ }
+
+ if (!config.marker) {
+ config.marker = {
+ width: 0,
+ height: 0
};
}
-
+
// parse position
- if (typeof tooltip.position === 'string') {
- var tempPos = PSVUtils.parsePosition(tooltip.position);
-
+ if (typeof config.position === 'string') {
+ var tempPos = PSVUtils.parsePosition(config.position);
+
if (!(tempPos.left in PSVTooltip.leftMap) || !(tempPos.top in PSVTooltip.topMap)) {
throw new PSVError('unable to parse tooltip position "' + tooltip.position + '"');
}
-
- tooltip.position = [PSVTooltip.topMap[tempPos.top], PSVTooltip.leftMap[tempPos.left]];
+
+ config.position = [PSVTooltip.topMap[tempPos.top], PSVTooltip.leftMap[tempPos.left]];
}
-
+
+ if (config.position[0] == 'center' && config.position[1] == 'center') {
+ throw new PSVError('unable to parse tooltip position "center center"');
+ }
+
t.className = 'psv-tooltip'; // reset the class
- if (tooltip.className) {
- t.classList.add(tooltip.className);
+ if (config.className) {
+ t.classList.add(config.className);
}
- c.innerHTML = tooltip.content;
+ c.innerHTML = config.content;
t.style.top = '0px';
t.style.left = '0px';
-
+
// compute size
var rect = t.getBoundingClientRect();
var style = {
- posClass: tooltip.position.slice(),
+ posClass: config.position.slice(),
width: rect.right - rect.left,
height: rect.bottom - rect.top,
top: 0,
@@ -1673,10 +1999,10 @@ PSVTooltip.prototype.showTooltip = function(tooltip, marker) {
arrow_top: 0,
arrow_left: 0
};
-
+
// set initial position
- this._computeTooltipPosition(style, marker);
-
+ this._computeTooltipPosition(style, config);
+
// correct position if overflow
var refresh = false;
if (style.top < this.config.offset) {
@@ -1696,18 +2022,18 @@ PSVTooltip.prototype.showTooltip = function(tooltip, marker) {
refresh = true;
}
if (refresh) {
- this._computeTooltipPosition(style, marker);
+ this._computeTooltipPosition(style, config);
}
-
+
// apply position
t.style.top = style.top + 'px';
t.style.left = style.left + 'px';
-
+
a.style.top = style.arrow_top + 'px';
a.style.left = style.arrow_left + 'px';
-
+
t.classList.add(style.posClass.join('-'));
-
+
// delay for correct transition between the two classes
var self = this;
setTimeout(function() {
@@ -1723,7 +2049,7 @@ PSVTooltip.prototype.showTooltip = function(tooltip, marker) {
PSVTooltip.prototype.hideTooltip = function() {
this.container.classList.remove('visible');
this.psv.trigger('hide-tooltip');
-
+
var self = this;
setTimeout(function() {
self.container.style.top = '-1000px';
@@ -1733,62 +2059,63 @@ PSVTooltip.prototype.hideTooltip = function() {
/**
* Compute the position of the tooltip and its arrow
- * @param style (Object) tooltip style
- * @param marker (Object)
+ * @param style (Object)
+ * @param config (Object)
* @return (void)
*/
-PSVTooltip.prototype._computeTooltipPosition = function(style, marker) {
+PSVTooltip.prototype._computeTooltipPosition = function(style, config) {
var topBottom = false;
-
+
switch (style.posClass[0]) {
case 'bottom':
- style.top = marker.position2D.top + marker.height + this.config.offset + this.config.arrow_size;
- style.arrow_top = - this.config.arrow_size * 2;
+ style.top = config.top + config.marker.height + this.config.offset + this.config.arrow_size;
+ style.arrow_top = -this.config.arrow_size * 2;
topBottom = true;
break;
-
+
case 'center':
- style.top = marker.position2D.top + marker.height/2 - style.height/2;
- style.arrow_top = style.height/2 - this.config.arrow_size;
+ style.top = config.top + config.marker.height / 2 - style.height / 2;
+ style.arrow_top = style.height / 2 - this.config.arrow_size;
break;
-
+
case 'top':
- style.top = marker.position2D.top - style.height - this.config.offset - this.config.arrow_size;
+ style.top = config.top - style.height - this.config.offset - this.config.arrow_size;
style.arrow_top = style.height;
topBottom = true;
break;
}
-
+
switch (style.posClass[1]) {
case 'right':
if (topBottom) {
- style.left = marker.position2D.left;
- style.arrow_left = marker.width/2 - this.config.arrow_size;
+ style.left = config.left;
+ style.arrow_left = config.marker.width / 2 - this.config.arrow_size;
}
else {
- style.left = marker.position2D.left + marker.width + this.config.offset + this.config.arrow_size;
- style.arrow_left = - this.config.arrow_size * 2;
+ style.left = config.left + config.marker.width + this.config.offset + this.config.arrow_size;
+ style.arrow_left = -this.config.arrow_size * 2;
}
break;
-
+
case 'center':
- style.left = marker.position2D.left + marker.width/2 - style.width/2;
- style.arrow_left = style.width/2 - this.config.arrow_size;
+ style.left = config.left + config.marker.width / 2 - style.width / 2;
+ style.arrow_left = style.width / 2 - this.config.arrow_size;
break;
-
+
case 'left':
if (topBottom) {
- style.left = marker.position2D.left - style.width + marker.width;
- style.arrow_left = style.width - marker.width/2 - this.config.arrow_size;
+ style.left = config.left - style.width + config.marker.width;
+ style.arrow_left = style.width - config.marker.width / 2 - this.config.arrow_size;
}
else {
- style.left = marker.position2D.left - style.width - this.config.offset - this.config.arrow_size;
+ style.left = config.left - style.width - this.config.offset - this.config.arrow_size;
style.arrow_left = style.width;
}
break;
}
};
+
/**
* Navigation bar class
* @param psv (PhotoSphereViewer) A PhotoSphereViewer object
@@ -1797,18 +2124,18 @@ function PSVNavBar(psv) {
PSVComponent.call(this, psv);
this.config = this.psv.config.navbar;
- this.container = null;
this.caption = null;
+ this.buttons = [];
if (this.config === true) {
this.config = PSVUtils.clone(PSVNavBar.DEFAULTS);
}
else if (typeof this.config == 'string') {
var map = {};
- this.config.split(/[ ,:]/).forEach(function(button) {
- map[button] = true;
- });
- this.config = PSVUtils.deepmerge(PSVNavBar.DEFAULTS, map);
+ Object.keys(PSVNavBar.DEFAULTS).forEach(function(button) {
+ map[button] = this.config.indexOf(button) !== -1;
+ }, this);
+ this.config = map;
}
this.create();
@@ -1828,42 +2155,37 @@ PSVNavBar.DEFAULTS = {
};
/**
- * Creates the elements
+ * Creates the navbar
* @return (void)
*/
PSVNavBar.prototype.create = function() {
- // Container
- this.container = document.createElement('div');
+ PSVComponent.prototype.create.call(this);
+
this.container.className = 'psv-navbar';
// Autorotate button
if (this.config.autorotate) {
- var autorotateBtn = new PSVNavBarAutorotateButton(this.psv);
- this.container.appendChild(autorotateBtn.button);
+ this.buttons.push(new PSVNavBarAutorotateButton(this));
}
// Zoom buttons
if (this.config.zoom) {
- var zoomBar = new PSVNavBarZoomButton(this.psv);
- this.container.appendChild(zoomBar.button);
+ this.buttons.push(new PSVNavBarZoomButton(this));
}
// Download button
if (this.config.download) {
- var downloadBtn = new PSVNavBarDownloadButton(this.psv);
- this.container.appendChild(downloadBtn.button);
+ this.buttons.push(new PSVNavBarDownloadButton(this));
}
// Markers button
if (this.config.markers) {
- var markersBtn = new PSVNavBarMarkersButton(this.psv);
- this.container.appendChild(markersBtn.button);
+ this.buttons.push(new PSVNavBarMarkersButton(this));
}
// Fullscreen button
if (this.config.fullscreen) {
- var fullscreenBtn = new PSVNavBarFullscreenButton(this.psv);
- this.container.appendChild(fullscreenBtn.button);
+ this.buttons.push(new PSVNavBarFullscreenButton(this));
}
// Caption
@@ -1873,6 +2195,19 @@ PSVNavBar.prototype.create = function() {
this.setCaption(this.psv.config.caption);
};
+/**
+ * Destroys the navbar
+ */
+PSVNavBar.prototype.destroy = function() {
+ this.buttons.forEach(function(button) {
+ button.destroy();
+ });
+
+ this.buttons.length = 0;
+
+ PSVComponent.prototype.destroy.call(this);
+};
+
/**
* Sets the bar caption
* @param (string) html
@@ -1887,12 +2222,14 @@ PSVNavBar.prototype.setCaption = function(html) {
}
};
+
/**
* Navigation bar button class
- * @param psv (PhotoSphereViewer) A PhotoSphereViewer object
+ * @param navbar (PSVNavBar) A PSVNavBar object
*/
-function PSVNavBarButton(psv) {
- this.psv = psv;
+function PSVNavBarButton(navbar) {
+ this.navbar = navbar;
+ this.psv = navbar.psv;
this.button = null;
}
@@ -1901,7 +2238,20 @@ function PSVNavBarButton(psv) {
* @return (void)
*/
PSVNavBarButton.prototype.create = function() {
- throw new PSVError('Not implemented');
+ this.button = document.createElement('div');
+ this.button.className = 'psv-button';
+ this.navbar.container.appendChild(this.button);
+};
+
+/**
+ * Destroys the button
+ */
+PSVNavBarButton.prototype.destroy = function() {
+ this.navbar.container.removeChild(this.button);
+
+ this.navbar = null;
+ this.psv = null;
+ this.button = null;
};
/**
@@ -1918,13 +2268,14 @@ PSVNavBarButton.prototype.toggleActive = function(active) {
}
};
+
/**
* Navigation bar autorotate button class
* @param psv (PhotoSphereViewer) A PhotoSphereViewer object
*/
function PSVNavBarAutorotateButton(psv) {
PSVNavBarButton.call(this, psv);
-
+
this.create();
}
@@ -1936,8 +2287,9 @@ PSVNavBarAutorotateButton.prototype.constructor = PSVNavBarAutorotateButton;
* @return (void)
*/
PSVNavBarAutorotateButton.prototype.create = function() {
- this.button = document.createElement('div');
- this.button.className = 'psv-button autorotate-button';
+ PSVNavBarButton.prototype.create.call(this);
+
+ this.button.classList.add('autorotate-button');
this.button.title = this.psv.config.lang.autorotate;
var autorotate_sphere = document.createElement('div');
@@ -1949,17 +2301,18 @@ PSVNavBarAutorotateButton.prototype.create = function() {
this.button.appendChild(autorotate_equator);
this.button.addEventListener('click', this.psv.toggleAutorotate.bind(this.psv));
-
+
this.psv.on('autorotate', this.toggleActive.bind(this));
};
+
/**
* Navigation bar fullscreen button class
* @param psv (PhotoSphereViewer) A PhotoSphereViewer object
*/
function PSVNavBarFullscreenButton(psv) {
PSVNavBarButton.call(this, psv);
-
+
this.create();
}
@@ -1971,18 +2324,41 @@ PSVNavBarFullscreenButton.prototype.constructor = PSVNavBarFullscreenButton;
* @return (void)
*/
PSVNavBarFullscreenButton.prototype.create = function() {
- this.button = document.createElement('div');
- this.button.className = 'psv-button fullscreen-button';
+ PSVNavBarButton.prototype.create.call(this);
+
+ this.button.classList.add('fullscreen-button');
this.button.title = this.psv.config.lang.fullscreen;
this.button.appendChild(document.createElement('div'));
this.button.appendChild(document.createElement('div'));
this.button.addEventListener('click', this.psv.toggleFullscreen.bind(this.psv));
-
- this.psv.on('fullscreen-updated', this.toggleActive.bind(this));
+
+ this.psv.on('fullscreen-updated', this);
+};
+
+/**
+ * Destroys the button
+ */
+PSVNavBarFullscreenButton.prototype.destroy = function() {
+ this.psv.off('fullscreen-updated', this);
+
+ PSVNavBarButton.prototype.destroy.call(this);
+};
+
+/**
+ * Handle events
+ * @param e (Event)
+ */
+PSVNavBarFullscreenButton.prototype.handleEvent = function(e) {
+ switch (e.type) {
+ // @formatter:off
+ case 'psv:fullscreen-updated': this.toggleActive(); break;
+ // @formatter:on
+ }
};
+
/**
* Navigation bar zoom button class
* @param psv (PhotoSphereViewer) A PhotoSphereViewer object
@@ -1992,7 +2368,7 @@ function PSVNavBarZoomButton(psv) {
this.zoom_range = null;
this.zoom_value = null;
-
+
this.prop = {
mousedown: false
};
@@ -2008,8 +2384,9 @@ PSVNavBarZoomButton.prototype.constructor = PSVNavBarZoomButton;
* @return (void)
*/
PSVNavBarZoomButton.prototype.create = function() {
- this.button = document.createElement('div');
- this.button.className = 'psv-button zoom-button';
+ PSVNavBarButton.prototype.create.call(this);
+
+ this.button.classList.add('zoom-button');
var zoom_minus = document.createElement('div');
zoom_minus.className = 'minus';
@@ -2037,16 +2414,16 @@ PSVNavBarZoomButton.prototype.create = function() {
zoom_plus.innerHTML = PhotoSphereViewer.ICONS['zoom-in.svg'];
this.button.appendChild(zoom_plus);
- this.zoom_range.addEventListener('mousedown', this._initZoomChangeWithMouse.bind(this));
- this.zoom_range.addEventListener('touchstart', this._initZoomChangeByTouch.bind(this));
- this.psv.container.addEventListener('mousemove', this._changeZoomWithMouse.bind(this));
- this.psv.container.addEventListener('touchmove', this._changeZoomByTouch.bind(this));
- this.psv.container.addEventListener('mouseup', this._stopZoomChange.bind(this));
- this.psv.container.addEventListener('touchend', this._stopZoomChange.bind(this));
+ 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);
zoom_minus.addEventListener('click', this.psv.zoomOut.bind(this.psv));
zoom_plus.addEventListener('click', this.psv.zoomIn.bind(this.psv));
-
- this.psv.on('zoom-updated', this._moveZoomValue.bind(this));
+
+ this.psv.on('zoom-updated', this);
var self = this;
setTimeout(function() {
@@ -2054,6 +2431,38 @@ PSVNavBarZoomButton.prototype.create = function() {
}, 0);
};
+/**
+ * Destroys the button
+ */
+PSVNavBarZoomButton.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);
+
+ this.psv.off('zoom-updated', this);
+
+ PSVNavBarButton.prototype.destroy.call(this);
+};
+
+/**
+ * Handle events
+ * @param e (Event)
+ */
+PSVNavBarZoomButton.prototype.handleEvent = function(e) {
+ switch (e.type) {
+ // @formatter:off
+ case 'mousedown': this._initZoomChangeWithMouse(e); break;
+ case 'touchstart': this._initZoomChangeByTouch(e); break;
+ case 'mousemove': this._changeZoomWithMouse(e); break;
+ case 'touchmove': this._changeZoomByTouch(e); break;
+ case 'mouseup': this._stopZoomChange(e); break;
+ case 'touchend': this._stopZoomChange(e); break;
+ case 'psv:zoom-updated': this._moveZoomValue(e.args[0]); break;
+ // @formatter:on
+ }
+};
+
/**
* Moves the zoom cursor
* @param level (integer) Zoom level (between 0 and 100)
@@ -2125,13 +2534,14 @@ PSVNavBarZoomButton.prototype._changeZoom = function(x) {
}
};
+
/**
* Navigation bar download button class
* @param psv (PhotoSphereViewer) A PhotoSphereViewer object
*/
function PSVNavBarDownloadButton(psv) {
PSVNavBarButton.call(this, psv);
-
+
this.create();
}
@@ -2143,8 +2553,9 @@ PSVNavBarDownloadButton.prototype.constructor = PSVNavBarDownloadButton;
* @return (void)
*/
PSVNavBarDownloadButton.prototype.create = function() {
- this.button = document.createElement('div');
- this.button.className = 'psv-button download-button';
+ PSVNavBarButton.prototype.create.call(this);
+
+ this.button.classList.add('download-button');
this.button.title = this.psv.config.lang.download;
this.button.appendChild(document.createElement('div'));
@@ -2165,7 +2576,6 @@ PSVNavBarDownloadButton.prototype.download = function() {
link.click();
};
-/*jshint multistr: true */
/**
* Navigation bar markers button class
@@ -2173,7 +2583,7 @@ PSVNavBarDownloadButton.prototype.download = function() {
*/
function PSVNavBarMarkersButton(psv) {
PSVNavBarButton.call(this, psv);
-
+
this.prop = {
panelOpened: false,
panelOpening: false
@@ -2190,15 +2600,39 @@ PSVNavBarMarkersButton.prototype.constructor = PSVNavBarMarkersButton;
* @return (void)
*/
PSVNavBarMarkersButton.prototype.create = function() {
- this.button = document.createElement('div');
- this.button.className = 'psv-button markers-button';
+ PSVNavBarButton.prototype.create.call(this);
+
+ this.button.classList.add('markers-button');
this.button.title = this.psv.config.lang.markers;
this.button.innerHTML = PhotoSphereViewer.ICONS['pin.svg'];
-
+
this.button.addEventListener('click', this.toggleMarkers.bind(this));
-
- this.psv.on('open-panel', this._onPanelOpened.bind(this));
- this.psv.on('close-panel', this._onPanelClosed.bind(this));
+
+ this.psv.on('open-panel', this);
+ this.psv.on('close-panel', this);
+};
+
+/**
+ * Destroys the button
+ */
+PSVNavBarMarkersButton.prototype.destroy = function() {
+ this.psv.off('open-panel', this);
+ this.psv.off('close-panel', this);
+
+ PSVNavBarButton.prototype.destroy.call(this);
+};
+
+/**
+ * Handle events
+ * @param e (Event)
+ */
+PSVNavBarMarkersButton.prototype.handleEvent = function(e) {
+ switch (e.type) {
+ // @formatter:off
+ case 'psv:open-panel': this._onPanelOpened(); break;
+ case 'psv:close-panel': this._onPanelClosed(); break;
+ // @formatter:on
+ }
};
/**
@@ -2219,30 +2653,35 @@ PSVNavBarMarkersButton.prototype.toggleMarkers = function() {
* @return (void)
*/
PSVNavBarMarkersButton.prototype.showMarkers = function() {
- var html = ' \
-
' + this.psv.config.lang.markers + ' \
-
';
-
- for (var id in this.psv.hud.markers) {
- var marker = this.psv.hud.markers[id];
-
- var name = marker.name || marker.id;
- if (marker.tooltip) {
- name = typeof marker.tooltip === 'string' ? marker.tooltip : marker.tooltip.content;
- }
-
- html+= ' \
- \
- ' + name + '
\
- ';
+ var html = ''
+ + '
' + this.psv.config.lang.markers + ' '
+ + '
';
+
+ for (var id in this.psv.hud.markers) {
+ var marker = this.psv.hud.markers[id];
+
+ var name = marker.id;
+ if (marker.html) {
+ name = marker.html;
+ }
+ else if (marker.tooltip) {
+ name = typeof marker.tooltip === 'string' ? marker.tooltip : marker.tooltip.content;
+ }
+
+ html += '';
+ if (marker.image) {
+ html += ' ';
}
-
- html+= ' \
-
';
-
+ html += '' + name + '
'
+ + '';
+ }
+
+ html += ' '
+ + '
';
+
this.prop.panelOpening = true;
this.psv.panel.showPanel(html, true);
-
+
this.psv.panel.container.querySelector('.psv-markers-list').addEventListener('click', this._onClickItem.bind(this));
};
@@ -2263,6 +2702,7 @@ PSVNavBarMarkersButton.prototype._onClickItem = function(e) {
var li;
if (e.target && (li = PSVUtils.getClosest(e.target, 'li')) && li.dataset.psvMarker) {
this.psv.hud.gotoMarker(li.dataset.psvMarker, 1000);
+ this.psv.panel.hidePanel();
}
};
@@ -2278,7 +2718,7 @@ PSVNavBarMarkersButton.prototype._onPanelOpened = function() {
else {
this.prop.panelOpened = false;
}
-
+
this.toggleActive(this.prop.panelOpened);
};
@@ -2289,10 +2729,11 @@ PSVNavBarMarkersButton.prototype._onPanelOpened = function() {
PSVNavBarMarkersButton.prototype._onPanelClosed = function() {
this.prop.panelOpened = false;
this.prop.panelOpening = false;
-
+
this.toggleActive(this.prop.panelOpened);
};
+
/**
* Custom error used in the lib
* http://stackoverflow.com/a/27724419/1207670
@@ -2300,7 +2741,7 @@ PSVNavBarMarkersButton.prototype._onPanelClosed = function() {
*/
function PSVError(message) {
this.message = message;
-
+
// Use V8's native method if available, otherwise fallback
if ('captureStackTrace' in Error) {
Error.captureStackTrace(this, PSVError);
@@ -2314,6 +2755,7 @@ PSVError.prototype = Object.create(Error.prototype);
PSVError.prototype.name = 'PSVError';
PSVError.prototype.constructor = PSVError;
+
/**
* Static utilities for PSV
*/
@@ -2371,7 +2813,7 @@ PSVUtils.hasParent = function(el, parent) {
*/
PSVUtils.getClosest = function(el, selector) {
var matches = el.matches || el.msMatchesSelector;
-
+
do {
if (matches.bind(el)(selector)) {
return el;
@@ -2386,9 +2828,9 @@ PSVUtils.getClosest = function(el, selector) {
* @return (string)
*/
PSVUtils.mouseWheelEvent = function() {
- return "onwheel" in document.createElement("div") ? "wheel" : // Modern browsers support "wheel"
- document.onmousewheel !== undefined ? "mousewheel" : // Webkit and IE support at least "mousewheel"
- "DOMMouseScroll"; // let's assume that remaining browsers are older Firefox
+ return 'onwheel' in document.createElement('div') ? 'wheel' : // Modern browsers support "wheel"
+ document.onmousewheel !== undefined ? 'mousewheel' : // Webkit and IE support at least "mousewheel"
+ 'DOMMouseScroll'; // let's assume that remaining browsers are older Firefox
};
/**
@@ -2396,8 +2838,17 @@ PSVUtils.mouseWheelEvent = function() {
* @return (string)
*/
PSVUtils.fullscreenEvent = function() {
- var map = {'exitFullscreen': 'fullscreenchange', 'webkitExitFullscreen': 'webkitfullscreenchange', 'mozCancelFullScreen': 'mozfullscreenchange', 'msExitFullscreen': 'msFullscreenEnabled'};
- for (var exit in map) if (exit in document) return map[exit];
+ var map = {
+ 'exitFullscreen': 'fullscreenchange',
+ 'webkitExitFullscreen': 'webkitfullscreenchange',
+ 'mozCancelFullScreen': 'mozfullscreenchange',
+ 'msExitFullscreen': 'msFullscreenEnabled'
+ };
+
+ for (var exit in map) {
+ if (exit in document) return map[exit];
+ }
+
return 'fullscreenchange';
};
@@ -2418,9 +2869,19 @@ PSVUtils.stayBetween = function(x, min, max) {
* @param attr (string) The wanted attribute
* @return (string) The value of the attribute
*/
-PSVUtils.getAttribute = function(data, attr) {
- var a = data.indexOf('GPano:' + attr) + attr.length + 8, b = data.indexOf('"', a);
- return data.substring(a, b);
+PSVUtils.getXMPValue = function(data, attr) {
+ var a, b;
+ // XMP data are stored in children
+ if ((a = data.indexOf('')) !== -1 && (b = data.indexOf(' ')) !== -1) {
+ return data.substring(a, b).replace('', '');
+ }
+ // XMP data are stored in attributes
+ else if ((a = data.indexOf('GPano:' + attr)) !== -1 && (b = data.indexOf('"', a)) !== -1) {
+ return data.substring(a + attr.length + 8, b);
+ }
+ else {
+ return null;
+ }
};
/**
@@ -2464,18 +2925,22 @@ PSVUtils.getStyle = function(elt, prop) {
*/
PSVUtils.parsePosition = function(value) {
if (!value) {
- return {top: 0.5, left: 0.5};
+ return { top: 0.5, left: 0.5 };
+ }
+
+ if (typeof value === 'object') {
+ return value;
}
-
+
var e = document.createElement('div');
document.body.appendChild(e);
e.style.backgroundPosition = value;
var parsed = PSVUtils.getStyle(e, 'background-position').match(/^([0-9.]+)% ([0-9.]+)%$/);
document.body.removeChild(e);
-
+
return {
- left: parsed[1]/100,
- top: parsed[2]/100
+ left: parsed[1] / 100,
+ top: parsed[2] / 100
};
};
@@ -2497,28 +2962,32 @@ PSVUtils.deepmerge = function(target, src) {
src.forEach(function(e, i) {
if (typeof dst[i] === 'undefined') {
dst[i] = e;
- } else if (typeof e === 'object') {
+ }
+ else if (typeof e === 'object') {
dst[i] = PSVUtils.deepmerge(target[i], e);
- } else {
+ }
+ else {
if (target.indexOf(e) === -1) {
dst.push(e);
}
}
});
- } else {
+ }
+ else {
if (target && typeof target === 'object') {
- Object.keys(target).forEach(function (key) {
+ Object.keys(target).forEach(function(key) {
dst[key] = target[key];
});
}
- Object.keys(src).forEach(function (key) {
+ Object.keys(src).forEach(function(key) {
if (typeof src[key] !== 'object' || !src[key]) {
dst[key] = src[key];
}
else {
if (!target[key]) {
dst[key] = src[key];
- } else {
+ }
+ else {
dst[key] = PSVUtils.deepmerge(target[key], src[key]);
}
}
@@ -2537,6 +3006,7 @@ PSVUtils.clone = function(src) {
return PSVUtils.deepmerge({}, src);
};
+
PhotoSphereViewer.ICONS['pin.svg'] = ' ';
PhotoSphereViewer.ICONS['zoom-in.svg'] = ' ';
@@ -2544,4 +3014,4 @@ PhotoSphereViewer.ICONS['zoom-in.svg'] = ' ';
return PhotoSphereViewer;
-}));
\ No newline at end of file
+}));
diff --git a/dist/photo-sphere-viewer.min.css b/dist/photo-sphere-viewer.min.css
index 73bf89036..9bcd1051c 100644
--- a/dist/photo-sphere-viewer.min.css
+++ b/dist/photo-sphere-viewer.min.css
@@ -1,8 +1,8 @@
/*!
- * Photo Sphere Viewer 3.0.1
+ * Photo Sphere Viewer 3.1.0
* Copyright (c) 2014-2015 Jérémy Heleine
- * Copyright (c) 2015 Damien "Mistic" Sorel
+ * Copyright (c) 2015-2016 Damien "Mistic" Sorel
* Licensed under MIT (http://opensource.org/licenses/MIT)
*/
-.psv-container{width:100%;height:100%;margin:0;padding:0;position:relative;background:radial-gradient(#fff,#fdfdfd 16%,#fbfbfb 33%,#f8f8f8 49%,#efefef 66%,#dfdfdf 82%,#bfbfbf 100%);overflow:hidden}.psv-container.loading{text-align:center}.psv-canvas-container{position:absolute;z-index:0}.psv-canvas-container canvas{display:block}.psv-loader{position:relative;color:rgba(61,61,61,.7);width:150px;height:150px;border:10px solid transparent}.psv-loader .loader-canvas{position:absolute;top:0;left:0}.psv-loader,.psv-loader .loader-image,.psv-loader .loader-text{display:inline-block;vertical-align:middle}.psv-loader .loader-text{font:14px sans-serif}.psv-container.loading::before,.psv-loader::before{content:'';display:inline-block;height:100%;vertical-align:middle}.psv-navbar{position:absolute;z-index:100;bottom:0;width:100%;background:rgba(61,61,61,.5)}.psv-navbar,.psv-navbar *{box-sizing:content-box}.psv-navbar .caption{color:rgba(255,255,255,.7);margin:10px;white-space:nowrap;overflow:hidden;text-align:center;font-family:sans-serif}.psv-navbar .psv-button{float:left;padding:10px;position:relative;cursor:pointer;height:20px;background:0 0}.psv-navbar .psv-button.active{background:rgba(255,255,255,.1)}.psv-navbar .psv-button svg{width:100%}.psv-navbar .psv-button svg *{fill:rgba(255,255,255,.7)}.psv-navbar .autorotate-button{width:20px}.psv-navbar .autorotate-button .equator,.psv-navbar .autorotate-button .sphere{border-radius:50%;border-width:1px;border-style:solid;border-color:rgba(255,255,255,.7);transition:.3s ease;transition-property:transform,height,margin}.psv-navbar .autorotate-button .sphere{width:18px;height:18px;transform:rotateY(0)}.psv-navbar .autorotate-button .equator{position:absolute;top:50%;width:18px;height:1.8px;margin-top:-1.9px;transform:rotateY(0)}.psv-navbar .autorotate-button:hover .sphere{transform:rotateY(180deg)}.psv-navbar .autorotate-button:hover .equator{transform:rotateY(180deg);height:4.5px;margin-top:-3.25px}.psv-navbar .download-button{width:20px;height:20px}.psv-navbar .download-button:before{content:'';position:absolute;width:20px;height:7px;left:8px;bottom:10px;border:2px solid rgba(255,255,255,.7);border-top-width:0;border-radius:0;transition:border-radius .2s ease}.psv-navbar .download-button div{position:absolute;width:12px;height:12px;top:50%;left:50%;margin:-8px -6px -6px;transition:margin-top .2s ease}.psv-navbar .download-button div:after,.psv-navbar .download-button div:before{content:'';display:block;margin:0 auto}.psv-navbar .download-button div:before{width:6px;height:6px;background:rgba(255,255,255,.7)}.psv-navbar .download-button div:after{width:0;height:0;border:6px solid transparent;border-top-color:rgba(255,255,255,.7)}.psv-navbar .download-button:hover:before{border-radius:2px}.psv-navbar .download-button:hover div{margin-top:-6px}.psv-navbar .fullscreen-button{float:right;width:26.67px;height:20px}.psv-navbar .fullscreen-button div{position:absolute;width:26.67px;height:20px}.psv-navbar .fullscreen-button div:after,.psv-navbar .fullscreen-button div:before{content:'';position:absolute;width:6px;height:4px;border-style:solid;border-color:rgba(255,255,255,.7);border-width:2px;transition:all .2s ease}.psv-navbar .fullscreen-button div:first-child:before{top:0;left:0;border-right-width:0;border-bottom-width:0}.psv-navbar .fullscreen-button div:first-child:after{top:0;right:0;border-left-width:0;border-bottom-width:0}.psv-navbar .fullscreen-button div:last-child:before{bottom:0;left:0;border-right-width:0;border-top-width:0}.psv-navbar .fullscreen-button div:last-child:after{bottom:0;right:0;border-left-width:0;border-top-width:0}.psv-navbar .fullscreen-button:hover div:after,.psv-navbar .fullscreen-button:hover div:before{width:8.67px;height:6px}.psv-navbar .zoom-button{cursor:default}.psv-navbar .zoom-button .minus,.psv-navbar .zoom-button .plus{float:left;position:relative;cursor:pointer;width:14px;height:14px}.psv-navbar .zoom-button .minus svg,.psv-navbar .zoom-button .plus svg{position:relative;top:20%}.psv-navbar .zoom-button .range{float:left;padding:9.5px 7px}.psv-navbar .zoom-button .range .line{position:relative;cursor:pointer;width:80px;height:1px;background:rgba(255,255,255,.7);transition:all .3s ease}.psv-navbar .zoom-button .range .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-hud,.psv-panel{height:100%;position:absolute}.psv-navbar .zoom-button:hover .range .line{box-shadow:0 0 2px rgba(255,255,255,.7)}.psv-navbar .zoom-button:hover .range .handle{transform:scale(1.3)}.psv-navbar .markers-button{width:20px}.psv-navbar .markers-button svg{transform:scale(1);transition:transform .3s ease}.psv-navbar .markers-button:hover svg{transform:scale(1.2)}.psv-markers-list h1{font:24px sans-serif;margin:1em 0;text-align:center;text-shadow:2px 1px #000}.psv-markers-list ul{list-style:none;margin:0;padding:0;overflow:hidden}.psv-markers-list ul li{clear:both;min-height:20px;padding:.5em 1em;cursor:pointer;transform:translateX(0);transition:transform .3s ease-in-out}.psv-markers-list ul li:before{content:'';position:absolute;top:0;left:0;height:100%;width:10px;margin-left:-10px}.psv-markers-list ul li:nth-child(odd),.psv-markers-list ul li:nth-child(odd):before{background:rgba(255,255,255,.1)}.psv-markers-list ul li:nth-child(even),.psv-markers-list ul li:nth-child(even):before{background:0 0}.psv-markers-list ul li:hover{transform:translateX(10px);transition:transform .1s ease-in-out}.psv-markers-list ul li img{float:left;width:20px}.psv-markers-list ul li p{margin:0;padding:0;padding-left:calc(20px + .5em)}.psv-hud{z-index:50;width:100%}.psv-hud .marker{position:absolute;top:0;left:0;background-size:contain;background-repeat:no-repeat;cursor:pointer;display:none}.psv-hud .marker.visible{display:block}.psv-panel{z-index:100;right:0;width:400px;max-width:calc(100% - 9px);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(.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 .close-button,.psv-panel.open .resizer{display:block}.psv-tooltip{position:absolute;z-index:75;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.bottom-center,.psv-tooltip.bottom-left,.psv-tooltip.center-left,.psv-tooltip.center-right,.psv-tooltip.top-center{transition-property:opacity,transform}.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 .arrow,.psv-tooltip.bottom-left .arrow,.psv-tooltip.bottom-right .arrow{border-bottom-color:rgba(61,61,61,.8)}.psv-tooltip.top-center .arrow,.psv-tooltip.top-left .arrow,.psv-tooltip.top-right .arrow{border-top-color:rgba(61,61,61,.8)}.psv-tooltip.bottom-center{box-shadow:0 3px 0 rgba(90,90,90,.7);transform:translate3d(0,-5px,0)}.psv-tooltip.center-left{box-shadow:-3px 0 0 rgba(90,90,90,.7);transform:translate3d(5px,0,0)}.psv-tooltip.center-left .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)}.psv-tooltip.center-right{box-shadow:3px 0 0 rgba(90,90,90,.7);transform:translate3d(-5px,0,0)}.psv-tooltip.center-right .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)}.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.top-left,.psv-tooltip.top-right{transform:translate3d(0,5px,0);transition-property:opacity,transform}.psv-tooltip.top-left{box-shadow:-3px -3px 0 rgba(90,90,90,.7)}.psv-tooltip.top-right{box-shadow:3px -3px 0 rgba(90,90,90,.7)}.psv-tooltip.visible{transform:translate3d(0,0,0);opacity:1;transition-duration:.2s}
\ No newline at end of file
+.psv-tooltip.bottom-center .arrow,.psv-tooltip.bottom-left .arrow,.psv-tooltip.bottom-right .arrow{border-bottom-color:rgba(61,61,61,.8)}.psv-container{width:100%;height:100%;margin:0;padding:0;position:relative;background:radial-gradient(#fff,#fdfdfd 16%,#fbfbfb 33%,#f8f8f8 49%,#efefef 66%,#dfdfdf 82%,#bfbfbf 100%);overflow:hidden}.psv-container.loading{text-align:center}.psv-canvas-container{position:absolute;z-index:0}.psv-canvas-container canvas{display:block}.psv-loader{position:relative;color:rgba(61,61,61,.7);width:150px;height:150px;border:10px solid transparent}.psv-loader .loader-canvas{position:absolute;top:0;left:0}.psv-loader,.psv-loader .loader-image,.psv-loader .loader-text{display:inline-block;vertical-align:middle}.psv-loader .loader-text{font:14px sans-serif}.psv-container.loading::before,.psv-loader::before{content:'';display:inline-block;height:100%;vertical-align:middle}.psv-navbar{position:absolute;z-index:100;bottom:0;width:100%;background:rgba(61,61,61,.5)}.psv-navbar,.psv-navbar *{box-sizing:content-box}.psv-navbar .caption{color:rgba(255,255,255,.7);margin:10px;white-space:nowrap;overflow:hidden;text-align:center;font-family:sans-serif}.psv-navbar .psv-button{float:left;padding:10px;position:relative;cursor:pointer;height:20px;background:0 0}.psv-navbar .psv-button.active{background:rgba(255,255,255,.1)}.psv-navbar .psv-button svg{width:100%}.psv-navbar .psv-button svg *{fill:rgba(255,255,255,.7)}.psv-navbar .autorotate-button{width:20px}.psv-navbar .autorotate-button .equator,.psv-navbar .autorotate-button .sphere{border-radius:50%;border-width:1px;border-style:solid;border-color:rgba(255,255,255,.7);transition:.3s ease;transition-property:transform,height,margin}.psv-navbar .autorotate-button .sphere{width:18px;height:18px;transform:rotateY(0)}.psv-navbar .autorotate-button .equator{position:absolute;top:50%;width:18px;height:1.8px;margin-top:-1.9px;transform:rotateY(0)}.psv-navbar .autorotate-button:hover .sphere{transform:rotateY(180deg)}.psv-navbar .autorotate-button:hover .equator{transform:rotateY(180deg);height:4.5px;margin-top:-3.25px}.psv-navbar .download-button{width:20px;height:20px}.psv-navbar .download-button:before{content:'';position:absolute;width:20px;height:7px;left:10px;bottom:10px;border:2px solid rgba(255,255,255,.7);border-top-width:0;border-radius:0;transition:border-radius .2s ease}.psv-navbar .download-button div{position:absolute;width:12px;height:12px;top:50%;left:50%;margin:-8px -6px -6px;transition:margin-top .2s ease}.psv-navbar .download-button div:after,.psv-navbar .download-button div:before{content:'';display:block;margin:0 auto}.psv-navbar .download-button div:before{width:6px;height:6px;background:rgba(255,255,255,.7)}.psv-navbar .download-button div:after{width:0;height:0;border:6px solid transparent;border-top-color:rgba(255,255,255,.7)}.psv-tooltip.top-center .arrow,.psv-tooltip.top-left .arrow,.psv-tooltip.top-right .arrow{border-top-color:rgba(61,61,61,.8)}.psv-navbar .download-button:hover:before{border-radius:2px}.psv-navbar .download-button:hover div{margin-top:-6px}.psv-navbar .fullscreen-button{float:right;width:26.67px;height:20px}.psv-navbar .fullscreen-button div{position:absolute;width:26.67px;height:20px}.psv-navbar .fullscreen-button div:after,.psv-navbar .fullscreen-button div:before{content:'';position:absolute;width:6px;height:4px;border-style:solid;border-color:rgba(255,255,255,.7);border-width:2px;transition:all .2s ease}.psv-navbar .fullscreen-button div:first-child:before{top:0;left:0;border-right-width:0;border-bottom-width:0}.psv-navbar .fullscreen-button div:first-child:after{top:0;right:0;border-left-width:0;border-bottom-width:0}.psv-navbar .fullscreen-button div:last-child:before{bottom:0;left:0;border-right-width:0;border-top-width:0}.psv-navbar .fullscreen-button div:last-child:after{bottom:0;right:0;border-left-width:0;border-top-width:0}.psv-navbar .fullscreen-button:hover div:after,.psv-navbar .fullscreen-button:hover div:before{width:8.67px;height:6px}.psv-navbar .zoom-button{cursor:default}.psv-navbar .zoom-button .minus,.psv-navbar .zoom-button .plus{float:left;position:relative;cursor:pointer;width:14px;height:14px}.psv-navbar .zoom-button .minus svg,.psv-navbar .zoom-button .plus svg{position:relative;top:20%}.psv-navbar .zoom-button .range{float:left;padding:9.5px 7px}.psv-navbar .zoom-button .range .line{position:relative;cursor:pointer;width:80px;height:1px;background:rgba(255,255,255,.7);transition:all .3s ease}.psv-navbar .zoom-button .range .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-navbar .zoom-button:hover .range .line{box-shadow:0 0 2px rgba(255,255,255,.7)}.psv-navbar .zoom-button:hover .range .handle{transform:scale(1.3)}.psv-navbar .markers-button{width:20px}.psv-navbar .markers-button svg{transform:scale(1);transition:transform .3s ease}.psv-navbar .markers-button:hover svg{transform:scale(1.2)}.psv-markers-list h1{font:24px sans-serif;margin:1em 0;text-align:center;text-shadow:2px 1px #000}.psv-markers-list ul{list-style:none;margin:0;padding:0;overflow:hidden}.psv-markers-list ul li{clear:both;min-height:20px;padding:.5em 1em;cursor:pointer;transform:translateX(0);transition:transform .3s ease-in-out}.psv-markers-list ul li:before{content:'';position:absolute;top:0;left:0;height:100%;width:10px;margin-left:-10px}.psv-markers-list ul li:nth-child(odd),.psv-markers-list ul li:nth-child(odd):before{background:rgba(255,255,255,.1)}.psv-markers-list ul li:nth-child(even),.psv-markers-list ul li:nth-child(even):before{background:0 0}.psv-markers-list ul li:hover{transform:translateX(10px);transition:transform .1s ease-in-out}.psv-markers-list ul li img{float:left;width:20px}.psv-markers-list ul li p{margin:0;padding:0;padding-left:calc(20px + .5em)}.psv-hud{position:absolute;z-index:50;width:100%;height:100%}.psv-hud .psv-marker{position:absolute;top:0;left:0;background-size:contain;background-repeat:no-repeat;cursor:pointer;display:none}.psv-hud .psv-marker.transparent{display:block;opacity:0}.psv-hud .psv-marker.visible{display:block}.psv-panel{position:absolute;z-index:100;right:0;height:100%;width:400px;max-width:calc(100% - 9px);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(.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 .close-button,.psv-panel.open .resizer{display:block}.psv-tooltip{position:absolute;z-index:75;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.bottom-center,.psv-tooltip.bottom-left,.psv-tooltip.bottom-right,.psv-tooltip.center-left,.psv-tooltip.center-right,.psv-tooltip.top-center,.psv-tooltip.top-left,.psv-tooltip.top-right{transition-property:opacity,transform}.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)}.psv-tooltip.center-left{box-shadow:-3px 0 0 rgba(90,90,90,.7);transform:translate3d(5px,0,0)}.psv-tooltip.center-left .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)}.psv-tooltip.center-right{box-shadow:3px 0 0 rgba(90,90,90,.7);transform:translate3d(-5px,0,0)}.psv-tooltip.center-right .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)}.psv-tooltip.bottom-right{box-shadow:3px 3px 0 rgba(90,90,90,.7);transform:translate3d(0,-5px,0)}.psv-tooltip.top-left{box-shadow:-3px -3px 0 rgba(90,90,90,.7);transform:translate3d(0,5px,0)}.psv-tooltip.top-right{box-shadow:3px -3px 0 rgba(90,90,90,.7);transform:translate3d(0,5px,0)}.psv-tooltip.visible{transform:translate3d(0,0,0);opacity:1;transition-duration:.2s}
\ No newline at end of file
diff --git a/dist/photo-sphere-viewer.min.js b/dist/photo-sphere-viewer.min.js
index 6192f56ad..d86e54fe1 100644
--- a/dist/photo-sphere-viewer.min.js
+++ b/dist/photo-sphere-viewer.min.js
@@ -1,9 +1,9 @@
/*!
- * Photo Sphere Viewer 3.0.1
+ * Photo Sphere Viewer 3.1.0
* Copyright (c) 2014-2015 Jérémy Heleine
- * Copyright (c) 2015 Damien "Mistic" Sorel
+ * Copyright (c) 2015-2016 Damien "Mistic" Sorel
* Licensed under MIT (http://opensource.org/licenses/MIT)
*/
-!function(a,b){"function"==typeof define&&define.amd?define(["three"],b):a.PhotoSphereViewer=b(a.THREE)}(this,function(a){"use strict";function b(a){if(!(this instanceof b))return new b(a);if(void 0===a||void 0===a.panorama||void 0===a.container)throw new o("no value given for panorama or container");if(this.config=p.deepmerge(b.DEFAULTS,a),this.config.min_fov=p.stayBetween(this.config.min_fov,1,179),this.config.max_fov=p.stayBetween(this.config.max_fov,1,179),this.config.tilt_up_max=p.stayBetween(this.config.tilt_up_max,-b.HalfPI,b.HalfPI),this.config.tilt_down_max=p.stayBetween(this.config.tilt_down_max,-b.HalfPI,b.HalfPI),null===this.config.default_fov?this.config.default_fov=this.config.max_fov:this.config.default_fov=p.stayBetween(this.config.default_fov,this.config.min_fov,this.config.max_fov),null===this.config.anim_lat&&(this.config.anim_lat=this.config.default_lat),this.config.anim_lat=p.stayBetween(this.config.anim_lat,-b.HalfPI,b.HalfPI),this.config.tilt_up_max"),g=d.substring(e,f);if(-1===e||-1===f||-1===g.indexOf("GPano:"))return void b._loadTexture(!1,!0);var h={full_width:parseInt(p.getAttribute(g,"FullPanoWidthPixels")),full_height:parseInt(p.getAttribute(g,"FullPanoHeightPixels")),cropped_width:parseInt(p.getAttribute(g,"CroppedAreaImageWidthPixels")),cropped_height:parseInt(p.getAttribute(g,"CroppedAreaImageHeightPixels")),cropped_x:parseInt(p.getAttribute(g,"CroppedAreaLeftPixels")),cropped_y:parseInt(p.getAttribute(g,"CroppedAreaTopPixels"))};b._loadTexture(h,!0)}else b.container.textContent="Cannot load image";else 3===a.readyState&&b.loader.setProgress(c+10)},a.onprogress=function(a){if(a.lengthComputable){var d=parseInt(a.loaded/a.total*100);d>c&&(c=d,b.loader.setProgress(c))}},a.onerror=function(){b.container.textContent="Cannot load image"},a.open("GET",this.config.panorama,!0),a.send(null)},b.prototype._loadTexture=function(b,c){var d=new a.ImageLoader,e=this,f=c?100:0;this.config.panorama.match(/^data:image\/[a-z]+;base64/)||d.setCrossOrigin("anonymous");var g=function(a){e.loader.setProgress(100),b||(b={full_width:a.width,full_height:a.height,cropped_width:a.width,cropped_height:a.height,cropped_x:0,cropped_y:0});var c=4096;p.isWebGLSupported()&&(c=p.getMaxTextureWidth());var d=Math.min(b.full_width,c),f=d/b.full_width;b.full_width*=f,b.full_height*=f,b.cropped_width*=f,b.cropped_height*=f,b.cropped_x*=f,b.cropped_y*=f,a.width=b.cropped_width,a.height=b.cropped_height;var g=document.createElement("canvas");g.width=b.full_width,g.height=b.full_height;var h=g.getContext("2d");h.drawImage(a,b.cropped_x,b.cropped_y,b.cropped_width,b.cropped_height),e.prop.size.image_width=b.cropped_width,e.prop.size.image_height=b.cropped_height,e._createScene(g)},h=function(a){if(a.lengthComputable){var b=parseInt(a.loaded/a.total*100);b>f&&(f=b,e.loader.setProgress(f))}},i=function(){e.container.textContent="Cannot load image"};d.load(this.config.panorama,g,h,i)},b.prototype._createScene=function(c){this._onResize(),this.raycaster=new a.Raycaster,this.renderer=p.isWebGLSupported()?new a.WebGLRenderer:new a.CanvasRenderer,this.renderer.setSize(this.prop.size.width,this.prop.size.height),this.camera=new a.PerspectiveCamera(this.config.default_fov,this.prop.size.ratio,1,300),this.camera.position.set(0,0,0),this.scene=new a.Scene,this.scene.add(this.camera);var d=new a.Texture(c);d.needsUpdate=!0;var i=new a.SphereGeometry(200,32,32,-b.HalfPI),j=new a.MeshBasicMaterial({map:d,overdraw:!0});j.side=a.DoubleSide;var k=new a.Mesh(i,j);k.scale.x=-1,this.scene.add(k),this.canvas_container.appendChild(this.renderer.domElement),this.container.removeChild(this.loader.container),this.loader=null,this.container.classList.remove("loading"),this.config.navbar&&(this.container.classList.add("has-navbar"),this.navbar=new h(this),this.container.appendChild(this.navbar.container)),this.hud=new e(this),this.config.markers.forEach(function(a){this.hud.addMarker(a,!0)},this),this.container.appendChild(this.hud.container),this.panel=new f(this),this.container.appendChild(this.panel.container),this.tooltip=new g(this),this.container.appendChild(this.tooltip.container),this.config.time_anim!==!1&&(this.prop.start_timeout=setTimeout(this.startAutorotate.bind(this),this.config.time_anim)),this._bindEvents(),this.trigger("ready"),this.render()},b.prototype._bindEvents=function(){window.addEventListener("resize",this._onResize.bind(this)),document.addEventListener(p.fullscreenEvent(),this._fullscreenToggled.bind(this)),this.config.mousemove&&(this.hud.container.style.cursor="move",this.hud.container.addEventListener("mousedown",this._onMouseDown.bind(this)),this.hud.container.addEventListener("touchstart",this._onTouchStart.bind(this)),this.hud.container.addEventListener("mouseup",this._onMouseUp.bind(this)),this.hud.container.addEventListener("touchend",this._onTouchEnd.bind(this)),this.hud.container.addEventListener("mousemove",this._onMouseMove.bind(this)),this.hud.container.addEventListener("touchmove",this._onTouchMove.bind(this))),this.config.mousewheel&&this.hud.container.addEventListener(p.mouseWheelEvent(),this._onMouseWheel.bind(this))},b.prototype.render=function(){this.prop.direction=new a.Vector3(-Math.cos(this.prop.latitude)*Math.sin(this.prop.longitude),Math.sin(this.prop.latitude),Math.cos(this.prop.latitude)*Math.cos(this.prop.longitude)),this.camera.lookAt(this.prop.direction),this.renderer.render(this.scene,this.camera),this.trigger("render")},b.prototype._autorotate=function(){this.rotate(this.prop.longitude+this.prop.anim_speed/this.prop.fps,this.prop.latitude-(this.prop.latitude-this.config.anim_lat)/200),this.prop.autorotate_timeout=setTimeout(this._autorotate.bind(this),1e3/this.prop.fps)},b.prototype.startAutorotate=function(){clearTimeout(this.prop.start_timeout),this.prop.start_timeout=null,this.stopAnimation(),this._autorotate(),this.trigger("autorotate",!0)},b.prototype.stopAutorotate=function(){clearTimeout(this.prop.start_timeout),this.prop.start_timeout=null,clearTimeout(this.prop.autorotate_timeout),this.prop.autorotate_timeout=null,this.trigger("autorotate",!1)},b.prototype.toggleAutorotate=function(){this.prop.autorotate_timeout?this.stopAutorotate():this.startAutorotate()},b.prototype._onResize=function(){(this.container.clientWidth!=this.prop.size.width||this.container.clientHeight!=this.prop.size.height)&&this.resize(this.container.clientWidth,this.container.clientHeight)},b.prototype.resize=function(a,b){this.prop.size.width=parseInt(a),this.prop.size.height=parseInt(b),this.prop.size.ratio=this.prop.size.width/this.prop.size.height,this.camera&&(this.camera.aspect=this.prop.size.ratio,this.camera.updateProjectionMatrix()),this.renderer&&(this.renderer.setSize(this.prop.size.width,this.prop.size.height),this.render()),this.trigger("size-updated",this.prop.size.width,this.prop.size.height)},b.prototype._onMouseDown=function(a){this._startMove(a)},b.prototype._onTouchStart=function(a){1===a.touches.length?this._startMove(a.touches[0]):2===a.touches.length&&this._startZoom(a)},b.prototype._startMove=function(a){this.prop.mouse_x=this.prop.start_mouse_x=parseInt(a.clientX),this.prop.mouse_y=this.prop.start_mouse_y=parseInt(a.clientY),this.prop.moving=!0,this.prop.moved=!1,this.prop.zooming=!1,this.stopAutorotate(),this.stopAnimation()},b.prototype._startZoom=function(a){var b=[{x:parseInt(a.touches[0].clientX),y:parseInt(a.touches[0].clientY)},{x:parseInt(a.touches[1].clientX),y:parseInt(a.touches[1].clientY)}];this.prop.pinch_dist=Math.sqrt(Math.pow(b[0].x-b[1].x,2)+Math.pow(b[0].y-b[1].y,2)),this.prop.moving=!1,this.prop.zooming=!0,this.stopAutorotate(),this.stopAnimation()},b.prototype._onMouseUp=function(a){this._stopMove(a)},b.prototype._onTouchEnd=function(a){this._stopMove(a.changedTouches[0])},b.prototype._stopMove=function(a){this.prop.moving&&(Math.abs(a.clientX-this.prop.start_mouse_x)j?-j:b.TwoPI-j,e.latitude=b.HalfPI-i;var k=e.longitude/b.TwoPI*this.prop.size.image_width,l=e.latitude/b.PI*this.prop.size.image_height;e.texture_x=parseInt(e.longitude0&&this.zoom(this.prop.zoom_lvl-1)},b.prototype._fullscreenToggled=function(){this.trigger("fullscreen-updated",p.isFullscreenEnabled())},b.prototype.toggleFullscreen=function(){p.isFullscreenEnabled()?p.exitFullscreen():p.requestFullscreen(this.container)},b.prototype.parseAnimSpeed=function(a){a=a.toString().trim();var c=parseFloat(a.replace(/^(-?[0-9]+(?:\.[0-9]*)?).*$/,"$1")),d=a.replace(/^-?[0-9]+(?:\.[0-9]*)?(.*)$/,"$1").trim();d.match(/(pm|per minute)$/)&&(c/=60);var e=0;switch(d){case"dpm":case"degrees per minute":case"dps":case"degrees per second":e=c*Math.PI/180;break;case"radians per minute":case"radians per second":e=c;break;case"rpm":case"revolutions per minute":case"rps":case"revolutions per second":e=c*b.TwoPI;break;default:throw new o('unknown speed unit "'+d+'"')}return e},b.prototype.setAnimSpeed=function(a){this.prop.anim_speed=this.parseAnimSpeed(a)},b.prototype.on=function(a,b){a in this.actions||(this.actions[a]=[]),this.actions[a].push(b)},b.prototype.trigger=function(a,b){if(b=Array.prototype.slice.call(arguments,1),a in this.actions&&this.actions[a].length>0)for(var c=0,d=this.actions[a].length;d>c;++c)this.actions[a][c].apply(this,b)},d.prototype.create=function(){this.container=document.createElement("div"),this.container.className="psv-loader",this.psv.container.appendChild(this.container),this.canvas=document.createElement("canvas"),this.canvas.className="loader-canvas",this.canvas.width=this.container.clientWidth,this.canvas.height=this.container.clientWidth,this.container.appendChild(this.canvas),this.tickness=(this.container.offsetWidth-this.container.clientWidth)/2;var a;if(this.psv.config.loading_img?(a=document.createElement("img"),a.className="loader-image",a.src=this.psv.config.loading_img):this.psv.config.loading_txt&&(a=document.createElement("div"),a.className="loader-text",a.innerHTML=this.psv.config.loading_txt),a){var b=Math.round(Math.sqrt(2*Math.pow(this.canvas.width/2-this.tickness/2,2)));a.style.maxWidth=b+"px",a.style.maxHeight=b+"px",this.container.appendChild(a)}},d.prototype.setProgress=function(a){var b=this.canvas.getContext("2d");b.clearRect(0,0,this.canvas.width,this.canvas.height),b.lineWidth=this.tickness,b.strokeStyle=p.getStyle(this.container,"color"),b.beginPath(),b.arc(this.canvas.width/2,this.canvas.height/2,this.canvas.width/2-this.tickness/2,-Math.PI/2,a/100*2*Math.PI-Math.PI/2),b.stroke()},e.prototype=Object.create(c.prototype),e.prototype.constructor=e,e.publicMethods=["addMarker","removeMarker","getMarker","getCurrentMarker","gotoMarker","hideMarker","showMarker","toggleMarker"],e.prototype.create=function(){this.container=document.createElement("div"),this.container.className="psv-hud",this.container.addEventListener("mouseenter",this._onMouseEnter.bind(this),!0),this.container.addEventListener("mouseleave",this._onMouseLeave.bind(this),!0),this.psv.on("_click",this._onClick.bind(this),!0),this.psv.on("render",this.updatePositions.bind(this))},e.prototype.addMarker=function(c,d){if(!c.id)throw new o("missing marker id");if(this.markers[c.id])throw new o('marker "'+c.id+'" already exists');if(!c.width||!c.height)throw new o("missing marker width/height");if(!c.image)throw new o("missing marker image");if((!c.hasOwnProperty("x")||!c.hasOwnProperty("y"))&(!c.hasOwnProperty("latitude")||!c.hasOwnProperty("longitude")))throw new o("missing marker position, latitude/longitude or x/y");c=p.clone(c),c.$el=document.createElement("div"),c.$el.psvMarker=c,c.$el.className="marker",c.className&&c.$el.classList.add(c.className),c.tooltip&&c.$el.classList.add("has-tooltip");var e=c.$el.style;if(e.width=c.width+"px",e.height=c.height+"px",e.backgroundImage="url("+c.image+")",c.anchor=p.parsePosition(c.anchor),c.hasOwnProperty("x")&&c.hasOwnProperty("y")){var f=c.x/this.psv.prop.size.image_width*b.TwoPI,g=c.y/this.psv.prop.size.image_height*b.PI;c.longitude=f>=b.PI?f-b.PI:f+b.PI,c.latitude=b.HalfPI-g}return c.position3D=new a.Vector3(-Math.cos(c.latitude)*Math.sin(c.longitude),Math.sin(c.latitude),Math.cos(c.latitude)*Math.cos(c.longitude)),c.hasOwnProperty("visible")||(c.visible=!0),this.markers[c.id]=c,this.container.appendChild(c.$el),d||this.updatePositions(),c},e.prototype.getMarker=function(a){var b="object"==typeof a?a.id:a;if(!this.markers[b])throw new o('cannot find marker "'+b+'"');return this.markers[b]},e.prototype.getCurrentMarker=function(){return this.currentMarker},e.prototype.removeMarker=function(a,b){a=this.getMarker(a),delete this.markers[a.id],b||this.updatePositions()},e.prototype.gotoMarker=function(a,b){a=this.getMarker(a),this.psv.animate(a.longitude,a.latitude,b)},e.prototype.hideMarker=function(a){this.getMarker(a).visible=!1,this.updatePositions()},e.prototype.showMarker=function(a){this.getMarker(a).visible=!0,this.updatePositions()},e.prototype.toggleMarker=function(a){this.getMarker(a).visible^=!0,this.updatePositions()},e.prototype.updatePositions=function(){this.psv.camera.updateProjectionMatrix();for(var a in this.markers){var b=this.markers[a],c=this._getMarkerPosition(b);this._isMarkerVisible(b,c)?(b.position2D=c,b.$el.style.transform="translate3D("+c.left+"px, "+c.top+"px, 0px)",b.$el.classList.contains("visible")||b.$el.classList.add("visible")):(b.position2D=null,b.$el.classList.remove("visible"))}},e.prototype._isMarkerVisible=function(a,b){return a.visible&&a.position3D.dot(this.psv.prop.direction)>0&&b.left>=0&&b.left+a.width<=this.psv.prop.size.width&&b.top>=0&&b.top+a.height<=this.psv.prop.size.height},e.prototype._getMarkerPosition=function(a){var b=a.position3D.clone();return b.project(this.psv.camera),{top:(1-b.y)/2*this.psv.prop.size.height-a.height*a.anchor.top,left:(b.x+1)/2*this.psv.prop.size.width-a.width*a.anchor.left}},e.prototype._onMouseEnter=function(a){a.target&&a.target.psvMarker&&a.target.psvMarker.tooltip&&this.psv.tooltip.showTooltip(a.target.psvMarker.tooltip,a.target.psvMarker)},e.prototype._onMouseLeave=function(a){a.target&&a.target.psvMarker&&this.psv.tooltip.hideTooltip()},e.prototype._onClick=function(a){this.psv.prop.moved||(a.target&&a.target.psvMarker?(this.currentMarker=a.target.psvMarker,this.psv.trigger("select-marker",a.target.psvMarker),a.preventDefault()):(this.currentMarker=null,this.psv.trigger("unselect-marker")),a.target&&a.target.psvMarker&&a.target.psvMarker.content?this.psv.panel.showPanel(a.target.psvMarker.content):this.psv.panel.prop.opened&&(a.preventDefault(),this.psv.panel.hidePanel()))},f.prototype=Object.create(c.prototype),f.prototype.constructor=f,f.publicMethods=["showPanel","hidePanel"],f.prototype.create=function(){this.container=document.createElement("aside"),this.container.className="psv-panel",this.container.innerHTML='
',this.content=this.container.querySelector(".content");var a=this.container.querySelector(".close-button");a.addEventListener("click",this.hidePanel.bind(this)),this.psv.config.mousewheel&&this.container.addEventListener(p.mouseWheelEvent(),function(a){a.stopPropagation()});var b=this.container.querySelector(".resizer");b.addEventListener("mousedown",this._onMouseDown.bind(this)),b.addEventListener("touchstart",this._onTouchStart.bind(this)),this.psv.container.addEventListener("mouseup",this._onMouseUp.bind(this)),this.psv.container.addEventListener("touchend",this._onMouseUp.bind(this)),this.psv.container.addEventListener("mousemove",this._onMouseMove.bind(this)),this.psv.container.addEventListener("touchmove",this._onTouchMove.bind(this))},f.prototype.showPanel=function(a,b){this.content.innerHTML=a,this.content.scrollTop=0,this.container.classList.add("open"),b?this.content.classList.contains("no-margin")||this.content.classList.add("no-margin"):this.content.classList.remove("no-margin"),this.prop.opened=!0,this.psv.trigger("open-panel")},f.prototype.hidePanel=function(){this.prop.opened=!1,this.container.classList.remove("open"),this.psv.trigger("close-panel")},f.prototype._onMouseDown=function(a){a.stopPropagation(),this._startResize(a)},f.prototype._onTouchStart=function(a){a.stopPropagation(),this._startResize(a.changedTouches[0])},f.prototype._startResize=function(a){this.prop.mouse_x=parseInt(a.clientX),this.prop.mouse_y=parseInt(a.clientY),this.prop.mousedown=!0,this.content.classList.add("no-interaction")},f.prototype._onMouseUp=function(a){this.prop.mousedown&&(a.stopPropagation(),this.prop.mousedown=!1,this.content.classList.remove("no-interaction"))},f.prototype._onMouseMove=function(a){this.prop.mousedown&&(a.stopPropagation(),this._resize(a))},f.prototype._onTouchMove=function(a){this.prop.mousedown&&(a.stopPropagation(),this._resize(a.changedTouches[0]))},f.prototype._resize=function(a){var b=parseInt(a.clientX),c=parseInt(a.clientY);this.container.style.width=this.container.offsetWidth-(b-this.prop.mouse_x)+"px",this.prop.mouse_x=b,this.prop.mouse_y=c},g.prototype=Object.create(c.prototype),g.prototype.constructor=g,g.publicMethods=["showTooltip","hideTooltip"],g.leftMap={0:"left",.5:"center",1:"right"},g.topMap={0:"top",.5:"center",1:"bottom"},g.prototype.create=function(){this.container=document.createElement("div"),this.container.innerHTML='
',this.container.className="psv-tooltip",this.container.style.top="-1000px",this.container.style.left="-1000px",this.psv.on("render",this.hideTooltip.bind(this))},g.prototype.showTooltip=function(a,b){var c=this.container,d=c.querySelector(".content"),e=c.querySelector(".arrow");if("string"==typeof a&&(a={content:b.tooltip,position:["top","center"]}),"string"==typeof a.position){var f=p.parsePosition(a.position);if(!(f.left in g.leftMap&&f.top in g.topMap))throw new o('unable to parse tooltip position "'+a.position+'"');a.position=[g.topMap[f.top],g.leftMap[f.left]]}c.className="psv-tooltip",a.className&&c.classList.add(a.className),d.innerHTML=a.content,c.style.top="0px",c.style.left="0px";var h=c.getBoundingClientRect(),i={posClass:a.position.slice(),width:h.right-h.left,height:h.bottom-h.top,top:0,left:0,arrow_top:0,arrow_left:0};this._computeTooltipPosition(i,b);var j=!1;i.topthis.psv.prop.size.height-this.config.offset&&(i.posClass[0]="top",j=!0),i.leftthis.psv.prop.size.width-this.config.offset&&(i.posClass[1]="left",j=!0),j&&this._computeTooltipPosition(i,b),c.style.top=i.top+"px",c.style.left=i.left+"px",e.style.top=i.arrow_top+"px",e.style.left=i.arrow_left+"px",c.classList.add(i.posClass.join("-"));var k=this;setTimeout(function(){c.classList.add("visible"),k.psv.trigger("show-tooltip")},100)},g.prototype.hideTooltip=function(){this.container.classList.remove("visible"),this.psv.trigger("hide-tooltip");var a=this;setTimeout(function(){a.container.style.top="-1000px",a.container.style.left="-1000px"},100)},g.prototype._computeTooltipPosition=function(a,b){var c=!1;switch(a.posClass[0]){case"bottom":a.top=b.position2D.top+b.height+this.config.offset+this.config.arrow_size,a.arrow_top=2*-this.config.arrow_size,c=!0;break;case"center":a.top=b.position2D.top+b.height/2-a.height/2,a.arrow_top=a.height/2-this.config.arrow_size;break;case"top":a.top=b.position2D.top-a.height-this.config.offset-this.config.arrow_size,a.arrow_top=a.height,c=!0}switch(a.posClass[1]){case"right":c?(a.left=b.position2D.left,a.arrow_left=b.width/2-this.config.arrow_size):(a.left=b.position2D.left+b.width+this.config.offset+this.config.arrow_size,a.arrow_left=2*-this.config.arrow_size);break;case"center":a.left=b.position2D.left+b.width/2-a.width/2,a.arrow_left=a.width/2-this.config.arrow_size;break;case"left":c?(a.left=b.position2D.left-a.width+b.width,a.arrow_left=a.width-b.width/2-this.config.arrow_size):(a.left=b.position2D.left-a.width-this.config.offset-this.config.arrow_size,a.arrow_left=a.width)}},h.prototype=Object.create(c.prototype),h.prototype.constructor=h,h.publicMethods=["setCaption"],h.DEFAULTS={autorotate:!0,zoom:!0,fullscreen:!0,download:!0,markers:!0},h.prototype.create=function(){if(this.container=document.createElement("div"),this.container.className="psv-navbar",this.config.autorotate){var a=new j(this.psv);this.container.appendChild(a.button)}if(this.config.zoom){var b=new l(this.psv);this.container.appendChild(b.button)}if(this.config.download){var c=new m(this.psv);this.container.appendChild(c.button)}if(this.config.markers){var d=new n(this.psv);this.container.appendChild(d.button)}if(this.config.fullscreen){var e=new k(this.psv);this.container.appendChild(e.button)}this.caption=document.createElement("div"),this.caption.className="caption",this.container.appendChild(this.caption),this.setCaption(this.psv.config.caption)},h.prototype.setCaption=function(a){a?(this.caption.style.display="block",this.caption.innerHTML=a):this.caption.style.display="none"},i.prototype.create=function(){throw new o("Not implemented")},i.prototype.toggleActive=function(a){a?this.button.classList.add("active"):this.button.classList.remove("active")},j.prototype=Object.create(i.prototype),j.prototype.constructor=j,j.prototype.create=function(){this.button=document.createElement("div"),this.button.className="psv-button autorotate-button",this.button.title=this.psv.config.lang.autorotate;var a=document.createElement("div");a.className="sphere",this.button.appendChild(a);var b=document.createElement("div");b.className="equator",this.button.appendChild(b),this.button.addEventListener("click",this.psv.toggleAutorotate.bind(this.psv)),this.psv.on("autorotate",this.toggleActive.bind(this))},k.prototype=Object.create(i.prototype),k.prototype.constructor=k,k.prototype.create=function(){this.button=document.createElement("div"),this.button.className="psv-button fullscreen-button",this.button.title=this.psv.config.lang.fullscreen,this.button.appendChild(document.createElement("div")),this.button.appendChild(document.createElement("div")),this.button.addEventListener("click",this.psv.toggleFullscreen.bind(this.psv)),this.psv.on("fullscreen-updated",this.toggleActive.bind(this))},l.prototype=Object.create(i.prototype),l.prototype.constructor=l,l.prototype.create=function(){this.button=document.createElement("div"),this.button.className="psv-button zoom-button";var a=document.createElement("div");a.className="minus",a.title=this.psv.config.lang.zoomOut,a.innerHTML=b.ICONS["zoom-out.svg"],this.button.appendChild(a);var c=document.createElement("div");c.className="range",this.button.appendChild(c),this.zoom_range=document.createElement("div"),this.zoom_range.className="line",this.zoom_range.title=this.psv.config.lang.zoom,c.appendChild(this.zoom_range),this.zoom_value=document.createElement("div"),this.zoom_value.className="handle",this.zoom_value.title=this.psv.config.lang.zoom,this.zoom_range.appendChild(this.zoom_value);var d=document.createElement("div");d.className="plus",d.title=this.psv.config.lang.zoomIn,d.innerHTML=b.ICONS["zoom-in.svg"],this.button.appendChild(d),this.zoom_range.addEventListener("mousedown",this._initZoomChangeWithMouse.bind(this)),this.zoom_range.addEventListener("touchstart",this._initZoomChangeByTouch.bind(this)),this.psv.container.addEventListener("mousemove",this._changeZoomWithMouse.bind(this)),this.psv.container.addEventListener("touchmove",this._changeZoomByTouch.bind(this)),this.psv.container.addEventListener("mouseup",this._stopZoomChange.bind(this)),this.psv.container.addEventListener("touchend",this._stopZoomChange.bind(this)),a.addEventListener("click",this.psv.zoomOut.bind(this.psv)),d.addEventListener("click",this.psv.zoomIn.bind(this.psv)),this.psv.on("zoom-updated",this._moveZoomValue.bind(this));var e=this;setTimeout(function(){e._moveZoomValue(e.psv.prop.zoom_lvl)},0)},l.prototype._moveZoomValue=function(a){this.zoom_value.style.left=a/100*this.zoom_range.offsetWidth-this.zoom_value.offsetWidth/2+"px"},l.prototype._initZoomChangeWithMouse=function(a){this.prop.mousedown=!0,this._changeZoom(a.clientX)},l.prototype._initZoomChangeByTouch=function(a){this.prop.mousedown=!0,this._changeZoom(a.changedTouches[0].clientX)},l.prototype._stopZoomChange=function(a){this.prop.mousedown=!1},l.prototype._changeZoomWithMouse=function(a){a.preventDefault(),this._changeZoom(a.clientX);
-},l.prototype._changeZoomByTouch=function(a){a.preventDefault(),this._changeZoom(a.changedTouches[0].clientX)},l.prototype._changeZoom=function(a){if(this.prop.mousedown){var b=parseInt(a)-this.zoom_range.getBoundingClientRect().left,c=b/this.zoom_range.offsetWidth*100;this.psv.zoom(c)}},m.prototype=Object.create(i.prototype),m.prototype.constructor=m,m.prototype.create=function(){this.button=document.createElement("div"),this.button.className="psv-button download-button",this.button.title=this.psv.config.lang.download,this.button.appendChild(document.createElement("div")),this.button.addEventListener("mouseenter",this.toggleActive.bind(this,!0)),this.button.addEventListener("mouseleave",this.toggleActive.bind(this,!1)),this.button.addEventListener("click",this.download.bind(this))},m.prototype.download=function(){var a=document.createElement("a");a.href=this.psv.config.panorama,a.download=this.psv.config.panorama,this.psv.container.appendChild(a),a.click()},n.prototype=Object.create(i.prototype),n.prototype.constructor=n,n.prototype.create=function(){this.button=document.createElement("div"),this.button.className="psv-button markers-button",this.button.title=this.psv.config.lang.markers,this.button.innerHTML=b.ICONS["pin.svg"],this.button.addEventListener("click",this.toggleMarkers.bind(this)),this.psv.on("open-panel",this._onPanelOpened.bind(this)),this.psv.on("close-panel",this._onPanelClosed.bind(this))},n.prototype.toggleMarkers=function(){this.prop.panelOpened?this.hideMarkers():this.showMarkers()},n.prototype.showMarkers=function(){var a=' '+this.psv.config.lang.markers+" ";for(var b in this.psv.hud.markers){var c=this.psv.hud.markers[b],d=c.name||c.id;c.tooltip&&(d="string"==typeof c.tooltip?c.tooltip:c.tooltip.content),a+=' '+d+"
"}a+=" ",this.prop.panelOpening=!0,this.psv.panel.showPanel(a,!0),this.psv.panel.container.querySelector(".psv-markers-list").addEventListener("click",this._onClickItem.bind(this))},n.prototype.hideMarkers=function(){this.psv.panel.hidePanel()},n.prototype._onClickItem=function(a){var b;a.target&&(b=p.getClosest(a.target,"li"))&&b.dataset.psvMarker&&this.psv.hud.gotoMarker(b.dataset.psvMarker,1e3)},n.prototype._onPanelOpened=function(){this.prop.panelOpening?(this.prop.panelOpening=!1,this.prop.panelOpened=!0):this.prop.panelOpened=!1,this.toggleActive(this.prop.panelOpened)},n.prototype._onPanelClosed=function(){this.prop.panelOpened=!1,this.prop.panelOpening=!1,this.toggleActive(this.prop.panelOpened)},o.prototype=Object.create(Error.prototype),o.prototype.name="PSVError",o.prototype.constructor=o;var p={};return p.isCanvasSupported=function(){var a=document.createElement("canvas");return!(!a.getContext||!a.getContext("2d"))},p.isWebGLSupported=function(){var a=document.createElement("canvas");return!(!window.WebGLRenderingContext||!a.getContext("webgl"))},p.getMaxTextureWidth=function(){var a=document.createElement("canvas"),b=a.getContext("webgl");return b.getParameter(b.MAX_TEXTURE_SIZE)},p.hasParent=function(a,b){do if(a===b)return!0;while(a=a.parentNode);return!1},p.getClosest=function(a,b){var c=a.matches||a.msMatchesSelector;do if(c.bind(a)(b))return a;while(a=a.parentElement);return null},p.mouseWheelEvent=function(){return"onwheel"in document.createElement("div")?"wheel":void 0!==document.onmousewheel?"mousewheel":"DOMMouseScroll"},p.fullscreenEvent=function(){var a={exitFullscreen:"fullscreenchange",webkitExitFullscreen:"webkitfullscreenchange",mozCancelFullScreen:"mozfullscreenchange",msExitFullscreen:"msFullscreenEnabled"};for(var b in a)if(b in document)return a[b];return"fullscreenchange"},p.stayBetween=function(a,b,c){return Math.max(b,Math.min(c,a))},p.getAttribute=function(a,b){var c=a.indexOf("GPano:"+b)+b.length+8,d=a.indexOf('"',c);return a.substring(c,d)},p.isFullscreenEnabled=function(){return document.fullscreenElement||document.mozFullScreenElement||document.webkitFullscreenElement||document.msFullscreenElement},p.requestFullscreen=function(a){(a.requestFullscreen||a.mozRequestFullScreen||a.webkitRequestFullscreen||a.msRequestFullscreen).call(a)},p.exitFullscreen=function(a){(document.exitFullscreen||document.mozCancelFullScreen||document.webkitExitFullscreen||document.msExitFullscreen).call(document)},p.getStyle=function(a,b){return window.getComputedStyle(a,null)[b]},p.parsePosition=function(a){if(!a)return{top:.5,left:.5};var b=document.createElement("div");document.body.appendChild(b),b.style.backgroundPosition=a;var c=p.getStyle(b,"background-position").match(/^([0-9.]+)% ([0-9.]+)%$/);return document.body.removeChild(b),{left:c[1]/100,top:c[2]/100}},p.deepmerge=function(a,b){var c=Array.isArray(b),d=c&&[]||{};return c?(a=a||[],d=d.concat(a),b.forEach(function(b,c){"undefined"==typeof d[c]?d[c]=b:"object"==typeof b?d[c]=p.deepmerge(a[c],b):-1===a.indexOf(b)&&d.push(b)})):(a&&"object"==typeof a&&Object.keys(a).forEach(function(b){d[b]=a[b]}),Object.keys(b).forEach(function(c){"object"==typeof b[c]&&b[c]&&a[c]?d[c]=p.deepmerge(a[c],b[c]):d[c]=b[c]})),d},p.clone=function(a){return p.deepmerge({},a)},b.ICONS["pin.svg"]=' ',b.ICONS["zoom-in.svg"]=' ',b.ICONS["zoom-out.svg"]=' ',b});
\ No newline at end of file
+!function(a,b){"function"==typeof define&&define.amd?define(["three"],b):a.PhotoSphereViewer=b(a.THREE)}(this,function(a){"use strict";function b(a){if(!(this instanceof b))return new b(a);if(void 0===a||void 0===a.panorama||void 0===a.container)throw new o("no value given for panorama or container");if(this.config=p.deepmerge(b.DEFAULTS,a),this.config.min_fov=p.stayBetween(this.config.min_fov,1,179),this.config.max_fov=p.stayBetween(this.config.max_fov,1,179),this.config.tilt_up_max=p.stayBetween(this.config.tilt_up_max,-b.HalfPI,b.HalfPI),this.config.tilt_down_max=p.stayBetween(this.config.tilt_down_max,-b.HalfPI,b.HalfPI),null===this.config.default_fov?this.config.default_fov=this.config.max_fov:this.config.default_fov=p.stayBetween(this.config.default_fov,this.config.min_fov,this.config.max_fov),null===this.config.anim_lat&&(this.config.anim_lat=this.config.default_lat),this.config.anim_lat=p.stayBetween(this.config.anim_lat,-b.HalfPI,b.HalfPI),this.config.tilt_up_max"),g=d.substring(e,f);if(-1===e||-1===f||-1===g.indexOf("GPano:"))return void b._loadTexture(!1,!0);var h={full_width:parseInt(p.getXMPValue(g,"FullPanoWidthPixels")),full_height:parseInt(p.getXMPValue(g,"FullPanoHeightPixels")),cropped_width:parseInt(p.getXMPValue(g,"CroppedAreaImageWidthPixels")),cropped_height:parseInt(p.getXMPValue(g,"CroppedAreaImageHeightPixels")),cropped_x:parseInt(p.getXMPValue(g,"CroppedAreaLeftPixels")),cropped_y:parseInt(p.getXMPValue(g,"CroppedAreaTopPixels"))};b._loadTexture(h,!0)}else b.container.textContent="Cannot load image";else 3===a.readyState&&b.loader.setProgress(c+10)},a.onprogress=function(a){if(a.lengthComputable){var d=parseInt(a.loaded/a.total*100);d>c&&(c=d,b.loader.setProgress(c))}},a.onerror=function(){b.container.textContent="Cannot load image"},a.open("GET",this.config.panorama,!0),a.send(null)},b.prototype._loadTexture=function(b,c){var d=new a.ImageLoader,e=this,f=c?100:0;this.config.panorama.match(/^data:image\/[a-z]+;base64/)||d.setCrossOrigin("anonymous");var g=function(a){e.loader.setProgress(100),b||(b={full_width:a.width,full_height:a.height,cropped_width:a.width,cropped_height:a.height,cropped_x:0,cropped_y:0});var c=4096;p.isWebGLSupported()&&(c=p.getMaxTextureWidth());var d=Math.min(b.full_width,c),f=d/b.full_width;b.full_width*=f,b.full_height*=f,b.cropped_width*=f,b.cropped_height*=f,b.cropped_x*=f,b.cropped_y*=f,a.width=b.cropped_width,a.height=b.cropped_height;var g=document.createElement("canvas");g.width=b.full_width,g.height=b.full_height;var h=g.getContext("2d");h.drawImage(a,b.cropped_x,b.cropped_y,b.cropped_width,b.cropped_height),e.prop.size.image_width=b.cropped_width,e.prop.size.image_height=b.cropped_height,e._createScene(g)},h=function(a){if(a.lengthComputable){var b=parseInt(a.loaded/a.total*100);b>f&&(f=b,e.loader.setProgress(f))}},i=function(){e.container.textContent="Cannot load image"};d.load(this.config.panorama,g,h,i)},b.prototype._createScene=function(c){this._onResize(),this.raycaster=new a.Raycaster,this.renderer=p.isWebGLSupported()?new a.WebGLRenderer:new a.CanvasRenderer,this.renderer.setSize(this.prop.size.width,this.prop.size.height),this.camera=new a.PerspectiveCamera(this.config.default_fov,this.prop.size.ratio,1,300),this.camera.position.set(0,0,0),this.scene=new a.Scene,this.scene.add(this.camera);var d=new a.Texture(c);d.needsUpdate=!0;var i=new a.SphereGeometry(200,32,32,-b.HalfPI),j=new a.MeshBasicMaterial({map:d,overdraw:!0});j.side=a.DoubleSide,this.mesh=new a.Mesh(i,j),this.mesh.scale.x=-1,this.scene.add(this.mesh),this.canvas_container.appendChild(this.renderer.domElement),this.loader.destroy(),this.loader=null,this.container.classList.remove("loading"),this.config.navbar&&(this.container.classList.add("has-navbar"),this.navbar=new h(this)),this.hud=new e(this),this.config.markers.forEach(function(a){this.hud.addMarker(a,!1)},this),this.panel=new f(this),this.tooltip=new g(this),this.config.time_anim!==!1&&(this.prop.start_timeout=setTimeout(this.startAutorotate.bind(this),this.config.time_anim)),this._bindEvents(),this.trigger("ready"),this.render()},b.prototype._bindEvents=function(){window.addEventListener("resize",this),document.addEventListener(p.fullscreenEvent(),this),this.config.mousemove&&(this.hud.container.style.cursor="move",this.hud.container.addEventListener("mousedown",this),this.hud.container.addEventListener("touchstart",this),window.addEventListener("mouseup",this),window.addEventListener("touchend",this),this.hud.container.addEventListener("mousemove",this),this.hud.container.addEventListener("touchmove",this)),this.config.mousewheel&&this.hud.container.addEventListener(p.mouseWheelEvent(),this)},b.prototype.handleEvent=function(a){switch(a.type){case"resize":this._onResize();break;case"mousedown":this._onMouseDown(a);break;case"touchstart":this._onTouchStart(a);break;case"mouseup":this._onMouseUp(a);break;case"touchend":this._onTouchEnd(a);break;case"mousemove":this._onMouseMove(a);break;case"touchmove":this._onTouchMove(a);break;case p.fullscreenEvent():this._fullscreenToggled();break;case p.mouseWheelEvent():this._onMouseWheel(a)}},b.prototype.render=function(){this.prop.direction=new a.Vector3(-Math.cos(this.prop.latitude)*Math.sin(this.prop.longitude),Math.sin(this.prop.latitude),Math.cos(this.prop.latitude)*Math.cos(this.prop.longitude)),this.camera.lookAt(this.prop.direction),this.renderer.render(this.scene,this.camera),this.trigger("render")},b.prototype._autorotate=function(){this.rotate(this.prop.longitude+this.prop.anim_speed/this.prop.fps,this.prop.latitude-(this.prop.latitude-this.config.anim_lat)/200),this.prop.autorotate_timeout=setTimeout(this._autorotate.bind(this),1e3/this.prop.fps)},b.prototype.startAutorotate=function(){clearTimeout(this.prop.start_timeout),this.prop.start_timeout=null,this.stopAnimation(),this._autorotate(),this.trigger("autorotate",!0)},b.prototype.stopAutorotate=function(){clearTimeout(this.prop.start_timeout),this.prop.start_timeout=null,clearTimeout(this.prop.autorotate_timeout),this.prop.autorotate_timeout=null,this.trigger("autorotate",!1)},b.prototype.toggleAutorotate=function(){this.prop.autorotate_timeout?this.stopAutorotate():this.startAutorotate()},b.prototype._onResize=function(){(this.container.clientWidth!=this.prop.size.width||this.container.clientHeight!=this.prop.size.height)&&this.resize(this.container.clientWidth,this.container.clientHeight)},b.prototype.resize=function(a,b){this.prop.size.width=parseInt(a),this.prop.size.height=parseInt(b),this.prop.size.ratio=this.prop.size.width/this.prop.size.height,this.camera&&(this.camera.aspect=this.prop.size.ratio,this.camera.updateProjectionMatrix()),this.renderer&&(this.renderer.setSize(this.prop.size.width,this.prop.size.height),this.render()),this.trigger("size-updated",this.prop.size.width,this.prop.size.height)},b.prototype._onMouseDown=function(a){this._startMove(a)},b.prototype._onTouchStart=function(a){1===a.touches.length?this._startMove(a.touches[0]):2===a.touches.length&&this._startZoom(a)},b.prototype._startMove=function(a){this.prop.mouse_x=this.prop.start_mouse_x=parseInt(a.clientX),this.prop.mouse_y=this.prop.start_mouse_y=parseInt(a.clientY),this.prop.moving=!0,this.prop.moved=!1,this.prop.zooming=!1,this.stopAutorotate(),this.stopAnimation()},b.prototype._startZoom=function(a){var b=[{x:parseInt(a.touches[0].clientX),y:parseInt(a.touches[0].clientY)},{x:parseInt(a.touches[1].clientX),y:parseInt(a.touches[1].clientY)}];this.prop.pinch_dist=Math.sqrt(Math.pow(b[0].x-b[1].x,2)+Math.pow(b[0].y-b[1].y,2)),this.prop.moving=!1,this.prop.zooming=!0,this.stopAutorotate(),this.stopAnimation()},b.prototype._onMouseUp=function(a){this._stopMove(a)},b.prototype._onTouchEnd=function(a){this._stopMove(a.changedTouches[0])},b.prototype._stopMove=function(a){this.prop.moving&&(Math.abs(a.clientX-this.prop.start_mouse_x)j?-j:b.TwoPI-j,e.latitude=b.HalfPI-i;var k=e.longitude/b.TwoPI*this.prop.size.image_width,l=e.latitude/b.PI*this.prop.size.image_height;e.texture_x=parseInt(e.longitude0&&this.zoom(this.prop.zoom_lvl-1)},b.prototype._fullscreenToggled=function(){this.trigger("fullscreen-updated",p.isFullscreenEnabled())},b.prototype.toggleFullscreen=function(){p.isFullscreenEnabled()?p.exitFullscreen():p.requestFullscreen(this.container)},b.prototype._parseAnimSpeed=function(a){a=a.toString().trim();var c=parseFloat(a.replace(/^(-?[0-9]+(?:\.[0-9]*)?).*$/,"$1")),d=a.replace(/^-?[0-9]+(?:\.[0-9]*)?(.*)$/,"$1").trim();d.match(/(pm|per minute)$/)&&(c/=60);var e=0;switch(d){case"dpm":case"degrees per minute":case"dps":case"degrees per second":e=c*Math.PI/180;break;case"radians per minute":case"radians per second":e=c;break;case"rpm":case"revolutions per minute":case"rps":case"revolutions per second":e=c*b.TwoPI;break;default:throw new o('unknown speed unit "'+d+'"')}return e},b.prototype.setAnimSpeed=function(a){this.prop.anim_speed=this._parseAnimSpeed(a)},b.prototype._setViewerSize=function(a){["width","height"].forEach(function(b){a[b]&&(/^[0-9.]+$/.test(a[b])&&(a[b]+="px"),this.parent.style[b]=a[b])},this)},b.prototype.on=function(a,b){a in this.actions||(this.actions[a]=[]),this.actions[a].push(b)},b.prototype.off=function(a,b){if(a in this.actions){var c=this.actions[a].indexOf(b);-1!==c&&this.actions[a].splice(c,1)}},b.prototype.trigger=function(a,b){b=Array.prototype.slice.call(arguments,1),a in this.actions&&this.actions[a].length>0&&this.actions[a].forEach(function(c){"object"==typeof c?c.handleEvent({type:"psv:"+a,args:b}):c.apply(this,b)},this)},c.prototype.create=function(){this.container=document.createElement("div"),this.psv.container.appendChild(this.container)},c.prototype.destroy=function(){this.psv.container.removeChild(this.container),this.container=null,this.psv=null},d.prototype.create=function(){this.container=document.createElement("div"),this.container.className="psv-loader",this.psv.container.appendChild(this.container),this.canvas=document.createElement("canvas"),this.canvas.className="loader-canvas",this.canvas.width=this.container.clientWidth,this.canvas.height=this.container.clientWidth,this.container.appendChild(this.canvas),this.tickness=(this.container.offsetWidth-this.container.clientWidth)/2;var a;if(this.psv.config.loading_img?(a=document.createElement("img"),a.className="loader-image",a.src=this.psv.config.loading_img):this.psv.config.loading_txt&&(a=document.createElement("div"),a.className="loader-text",a.innerHTML=this.psv.config.loading_txt),a){var b=Math.round(Math.sqrt(2*Math.pow(this.canvas.width/2-this.tickness/2,2)));a.style.maxWidth=b+"px",a.style.maxHeight=b+"px",this.container.appendChild(a)}},d.prototype.destroy=function(){this.psv.container.removeChild(this.container),this.psv=null,this.container=null},d.prototype.setProgress=function(a){var b=this.canvas.getContext("2d");b.clearRect(0,0,this.canvas.width,this.canvas.height),b.lineWidth=this.tickness,b.strokeStyle=p.getStyle(this.container,"color"),b.beginPath(),b.arc(this.canvas.width/2,this.canvas.height/2,this.canvas.width/2-this.tickness/2,-Math.PI/2,a/100*2*Math.PI-Math.PI/2),b.stroke()},e.prototype=Object.create(c.prototype),e.prototype.constructor=e,e.publicMethods=["addMarker","removeMarker","updateMarker","getMarker","getCurrentMarker","gotoMarker","hideMarker","showMarker","toggleMarker"],e.prototype.create=function(){c.prototype.create.call(this),this.container.className="psv-hud",this.container.addEventListener("mouseenter",this,!0),this.container.addEventListener("mouseleave",this,!0),this.psv.on("_click",this),this.psv.on("render",this)},e.prototype.destroy=function(){this.container.removeEventListener("mouseenter",this),this.container.removeEventListener("mouseleave",this),this.psv.off("_click",this),this.psv.off("render",this),c.prototype.destroy.call(this)},e.prototype.handleEvent=function(a){switch(a.type){case"mouseenter":this._onMouseEnter(a);break;case"mouseleave":this._onMouseLeave(a);break;case"psv:_click":this._onClick(a.args[0]);break;case"psv:render":this.updatePositions()}},e.prototype.addMarker=function(a,b){if(!a.id)throw new o("missing marker id");if(this.markers[a.id])throw new o('marker "'+a.id+'" already exists');if(!a.image&&!a.html)throw new o("missing marker image/html");if(a.image&&(!a.width||!a.height))throw new o("missing marker width/height");if(!(a.hasOwnProperty("x")&&a.hasOwnProperty("y")||a.hasOwnProperty("latitude")&&a.hasOwnProperty("longitude")))throw new o("missing marker position, latitude/longitude or x/y");return a.$el=document.createElement("div"),a.$el.id="psv-marker-"+a.id,a.$el.className="psv-marker",this.markers[a.id]=a,this.container.appendChild(a.$el),this.updateMarker(p.clone(a),b)},e.prototype.getMarker=function(a){var b="object"==typeof a?a.id:a;if(!this.markers[b])throw new o('cannot find marker "'+b+'"');return this.markers[b]},e.prototype.getCurrentMarker=function(){return this.currentMarker},e.prototype.updateMarker=function(c,d){var e=this.getMarker(c);e.className&&e.$el.classList.remove(e.className),e.tooltip&&e.$el.classList.remove("has-tooltip"),delete c.$el,c=p.deepmerge(e,c),c.position2D=null,c.className&&c.$el.classList.add(c.className),c.tooltip&&(c.$el.classList.add("has-tooltip"),"string"==typeof c.tooltip&&(c.tooltip={content:c.tooltip}));var f=c.$el.style;if(c.width&&c.height?(f.width=c.width+"px",f.height=c.height+"px",c.dynamicSize=!1):c.dynamicSize=!0,c.style&&Object.getOwnPropertyNames(c.style).forEach(function(a){f[a]=c.style[a]}),c.image?f.backgroundImage="url("+c.image+")":c.$el.innerHTML=c.html,c.anchor=p.parsePosition(c.anchor),c.hasOwnProperty("x")&&c.hasOwnProperty("y")){var g=c.x/this.psv.prop.size.image_width*b.TwoPI,h=c.y/this.psv.prop.size.image_height*b.PI;c.longitude=g>=b.PI?g-b.PI:g+b.PI,c.latitude=b.HalfPI-h}return c.position3D=new a.Vector3(-Math.cos(c.latitude)*Math.sin(c.longitude),Math.sin(c.latitude),Math.cos(c.latitude)*Math.cos(c.longitude)),c.hasOwnProperty("visible")||(c.visible=!0),c.$el.psvMarker=c,this.markers[c.id]=c,d!==!1&&this.updatePositions(),c},e.prototype.removeMarker=function(a,b){a=this.getMarker(a),a.$el.parentNode.removeChild(a.$el),delete this.markers[a.id],b!==!1&&this.updatePositions()},e.prototype.gotoMarker=function(a,b){a=this.getMarker(a),this.psv.animate(a.longitude,a.latitude,b)},e.prototype.hideMarker=function(a){this.getMarker(a).visible=!1,this.updatePositions()},e.prototype.showMarker=function(a){this.getMarker(a).visible=!0,this.updatePositions()},e.prototype.toggleMarker=function(a){this.getMarker(a).visible^=!0,this.updatePositions()},e.prototype.updatePositions=function(){this.psv.camera.updateProjectionMatrix();for(var a in this.markers){var b=this.markers[a],c=this._getMarkerPosition(b);this._isMarkerVisible(b,c)?(b.position2D=c,b.$el.style.transform="translate3D("+c.left+"px, "+c.top+"px, 0px)",b.$el.classList.contains("visible")||b.$el.classList.add("visible")):(b.position2D=null,b.$el.classList.remove("visible"))}},e.prototype._isMarkerVisible=function(a,b){return a.visible&&a.position3D.dot(this.psv.prop.direction)>0&&b.left+a.width>=0&&b.left-a.width<=this.psv.prop.size.width&&b.top+a.height>=0&&b.top-a.height<=this.psv.prop.size.height},e.prototype._getMarkerPosition=function(a){if(a.dynamicSize){a.$el.classList.add("transparent");var b=a.$el.getBoundingClientRect();a.$el.classList.remove("transparent"),a.width=b.right-b.left,a.height=b.bottom-b.top}var c=a.position3D.clone();return c.project(this.psv.camera),{top:(1-c.y)/2*this.psv.prop.size.height-a.height*a.anchor.top,left:(c.x+1)/2*this.psv.prop.size.width-a.width*a.anchor.left}},e.prototype._onMouseEnter=function(a){if(a.target&&a.target.psvMarker&&a.target.psvMarker.tooltip){var b=a.target.psvMarker;this.psv.tooltip.showTooltip({content:b.tooltip.content,position:b.tooltip.position,top:b.position2D.top,left:b.position2D.left,marker:b})}},e.prototype._onMouseLeave=function(a){a.target&&a.target.psvMarker&&this.psv.tooltip.hideTooltip()},e.prototype._onClick=function(a){if(!this.psv.prop.moved){var b;a.target&&(b=p.getClosest(a.target,".psv-marker"))&&b.psvMarker?(this.currentMarker=b.psvMarker,this.psv.trigger("select-marker",b.psvMarker),a.preventDefault()):this.currentMarker&&(this.currentMarker=null,this.psv.trigger("unselect-marker")),b&&b.psvMarker&&b.psvMarker.content?this.psv.panel.showPanel(b.psvMarker.content):this.psv.panel.prop.opened&&(a.preventDefault(),this.psv.panel.hidePanel())}},f.prototype=Object.create(c.prototype),f.prototype.constructor=f,f.publicMethods=["showPanel","hidePanel"],f.prototype.create=function(){c.prototype.create.call(this),this.container.className="psv-panel",this.container.innerHTML='
',this.content=this.container.querySelector(".content");var a=this.container.querySelector(".close-button");a.addEventListener("click",this.hidePanel.bind(this)),this.psv.config.mousewheel&&this.container.addEventListener(p.mouseWheelEvent(),function(a){a.stopPropagation()});var b=this.container.querySelector(".resizer");b.addEventListener("mousedown",this),b.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)},f.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),c.prototype.destroy.call(this)},f.prototype.handleEvent=function(a){switch(a.type){case"mousedown":this._onMouseDown(a);break;case"touchstart":this._onTouchStart(a);break;case"mousemove":this._onMouseMove(a);break;case"touchmove":this._onMouseMove(a);break;case"mouseup":this._onMouseUp(a);break;case"touchend":this._onMouseUp(a)}},f.prototype.showPanel=function(a,b){this.content.innerHTML=a,this.content.scrollTop=0,this.container.classList.add("open"),b?this.content.classList.contains("no-margin")||this.content.classList.add("no-margin"):this.content.classList.remove("no-margin"),this.prop.opened=!0,this.psv.trigger("open-panel")},f.prototype.hidePanel=function(){this.prop.opened=!1,this.container.classList.remove("open"),this.psv.trigger("close-panel")},f.prototype._onMouseDown=function(a){a.stopPropagation(),this._startResize(a)},f.prototype._onTouchStart=function(a){a.stopPropagation(),this._startResize(a.changedTouches[0])},f.prototype._startResize=function(a){this.prop.mouse_x=parseInt(a.clientX),this.prop.mouse_y=parseInt(a.clientY),this.prop.mousedown=!0,this.content.classList.add("no-interaction")},f.prototype._onMouseUp=function(a){this.prop.mousedown&&(a.stopPropagation(),this.prop.mousedown=!1,this.content.classList.remove("no-interaction"))},f.prototype._onMouseMove=function(a){this.prop.mousedown&&(a.stopPropagation(),this._resize(a))},f.prototype._onTouchMove=function(a){this.prop.mousedown&&(a.stopPropagation(),this._resize(a.changedTouches[0]))},f.prototype._resize=function(a){var b=parseInt(a.clientX),c=parseInt(a.clientY);this.container.style.width=this.container.offsetWidth-(b-this.prop.mouse_x)+"px",this.prop.mouse_x=b,this.prop.mouse_y=c},g.prototype=Object.create(c.prototype),g.prototype.constructor=g,g.publicMethods=["showTooltip","hideTooltip"],g.leftMap={0:"left",.5:"center",1:"right"},g.topMap={0:"top",.5:"center",1:"bottom"},g.prototype.create=function(){c.prototype.create.call(this),this.container.innerHTML='
',this.container.className="psv-tooltip",this.container.style.top="-1000px",this.container.style.left="-1000px",this.psv.on("render",this)},g.prototype.destroy=function(){this.psv.off("render",this),c.prototype.destroy.call(this)},g.prototype.handleEvent=function(a){switch(a.type){case"psv:render":this.hideTooltip()}},g.prototype.showTooltip=function(a){var b=this.container,c=b.querySelector(".content"),d=b.querySelector(".arrow");if(a.position||(a.position=["top","center"]),a.marker||(a.marker={width:0,height:0}),"string"==typeof a.position){var e=p.parsePosition(a.position);if(!(e.left in g.leftMap&&e.top in g.topMap))throw new o('unable to parse tooltip position "'+tooltip.position+'"');a.position=[g.topMap[e.top],g.leftMap[e.left]]}if("center"==a.position[0]&&"center"==a.position[1])throw new o('unable to parse tooltip position "center center"');b.className="psv-tooltip",a.className&&b.classList.add(a.className),c.innerHTML=a.content,b.style.top="0px",b.style.left="0px";var f=b.getBoundingClientRect(),h={posClass:a.position.slice(),width:f.right-f.left,height:f.bottom-f.top,top:0,left:0,arrow_top:0,arrow_left:0};this._computeTooltipPosition(h,a);var i=!1;h.topthis.psv.prop.size.height-this.config.offset&&(h.posClass[0]="top",i=!0),h.leftthis.psv.prop.size.width-this.config.offset&&(h.posClass[1]="left",i=!0),i&&this._computeTooltipPosition(h,a),b.style.top=h.top+"px",b.style.left=h.left+"px",d.style.top=h.arrow_top+"px",d.style.left=h.arrow_left+"px",b.classList.add(h.posClass.join("-"));var j=this;setTimeout(function(){b.classList.add("visible"),j.psv.trigger("show-tooltip")},100)},g.prototype.hideTooltip=function(){this.container.classList.remove("visible"),this.psv.trigger("hide-tooltip");var a=this;setTimeout(function(){a.container.style.top="-1000px",a.container.style.left="-1000px"},100)},g.prototype._computeTooltipPosition=function(a,b){var c=!1;switch(a.posClass[0]){case"bottom":a.top=b.top+b.marker.height+this.config.offset+this.config.arrow_size,a.arrow_top=2*-this.config.arrow_size,c=!0;break;case"center":a.top=b.top+b.marker.height/2-a.height/2,a.arrow_top=a.height/2-this.config.arrow_size;break;case"top":a.top=b.top-a.height-this.config.offset-this.config.arrow_size,a.arrow_top=a.height,c=!0}switch(a.posClass[1]){case"right":c?(a.left=b.left,a.arrow_left=b.marker.width/2-this.config.arrow_size):(a.left=b.left+b.marker.width+this.config.offset+this.config.arrow_size,a.arrow_left=2*-this.config.arrow_size);break;case"center":a.left=b.left+b.marker.width/2-a.width/2,a.arrow_left=a.width/2-this.config.arrow_size;break;case"left":c?(a.left=b.left-a.width+b.marker.width,a.arrow_left=a.width-b.marker.width/2-this.config.arrow_size):(a.left=b.left-a.width-this.config.offset-this.config.arrow_size,a.arrow_left=a.width)}},h.prototype=Object.create(c.prototype),h.prototype.constructor=h,h.publicMethods=["setCaption"],h.DEFAULTS={autorotate:!0,zoom:!0,fullscreen:!0,download:!0,markers:!0},h.prototype.create=function(){c.prototype.create.call(this),this.container.className="psv-navbar",this.config.autorotate&&this.buttons.push(new j(this)),
+this.config.zoom&&this.buttons.push(new l(this)),this.config.download&&this.buttons.push(new m(this)),this.config.markers&&this.buttons.push(new n(this)),this.config.fullscreen&&this.buttons.push(new k(this)),this.caption=document.createElement("div"),this.caption.className="caption",this.container.appendChild(this.caption),this.setCaption(this.psv.config.caption)},h.prototype.destroy=function(){this.buttons.forEach(function(a){a.destroy()}),this.buttons.length=0,c.prototype.destroy.call(this)},h.prototype.setCaption=function(a){a?(this.caption.style.display="block",this.caption.innerHTML=a):this.caption.style.display="none"},i.prototype.create=function(){this.button=document.createElement("div"),this.button.className="psv-button",this.navbar.container.appendChild(this.button)},i.prototype.destroy=function(){this.navbar.container.removeChild(this.button),this.navbar=null,this.psv=null,this.button=null},i.prototype.toggleActive=function(a){a?this.button.classList.add("active"):this.button.classList.remove("active")},j.prototype=Object.create(i.prototype),j.prototype.constructor=j,j.prototype.create=function(){i.prototype.create.call(this),this.button.classList.add("autorotate-button"),this.button.title=this.psv.config.lang.autorotate;var a=document.createElement("div");a.className="sphere",this.button.appendChild(a);var b=document.createElement("div");b.className="equator",this.button.appendChild(b),this.button.addEventListener("click",this.psv.toggleAutorotate.bind(this.psv)),this.psv.on("autorotate",this.toggleActive.bind(this))},k.prototype=Object.create(i.prototype),k.prototype.constructor=k,k.prototype.create=function(){i.prototype.create.call(this),this.button.classList.add("fullscreen-button"),this.button.title=this.psv.config.lang.fullscreen,this.button.appendChild(document.createElement("div")),this.button.appendChild(document.createElement("div")),this.button.addEventListener("click",this.psv.toggleFullscreen.bind(this.psv)),this.psv.on("fullscreen-updated",this)},k.prototype.destroy=function(){this.psv.off("fullscreen-updated",this),i.prototype.destroy.call(this)},k.prototype.handleEvent=function(a){switch(a.type){case"psv:fullscreen-updated":this.toggleActive()}},l.prototype=Object.create(i.prototype),l.prototype.constructor=l,l.prototype.create=function(){i.prototype.create.call(this),this.button.classList.add("zoom-button");var a=document.createElement("div");a.className="minus",a.title=this.psv.config.lang.zoomOut,a.innerHTML=b.ICONS["zoom-out.svg"],this.button.appendChild(a);var c=document.createElement("div");c.className="range",this.button.appendChild(c),this.zoom_range=document.createElement("div"),this.zoom_range.className="line",this.zoom_range.title=this.psv.config.lang.zoom,c.appendChild(this.zoom_range),this.zoom_value=document.createElement("div"),this.zoom_value.className="handle",this.zoom_value.title=this.psv.config.lang.zoom,this.zoom_range.appendChild(this.zoom_value);var d=document.createElement("div");d.className="plus",d.title=this.psv.config.lang.zoomIn,d.innerHTML=b.ICONS["zoom-in.svg"],this.button.appendChild(d),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),a.addEventListener("click",this.psv.zoomOut.bind(this.psv)),d.addEventListener("click",this.psv.zoomIn.bind(this.psv)),this.psv.on("zoom-updated",this);var e=this;setTimeout(function(){e._moveZoomValue(e.psv.prop.zoom_lvl)},0)},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),this.psv.off("zoom-updated",this),i.prototype.destroy.call(this)},l.prototype.handleEvent=function(a){switch(a.type){case"mousedown":this._initZoomChangeWithMouse(a);break;case"touchstart":this._initZoomChangeByTouch(a);break;case"mousemove":this._changeZoomWithMouse(a);break;case"touchmove":this._changeZoomByTouch(a);break;case"mouseup":this._stopZoomChange(a);break;case"touchend":this._stopZoomChange(a);break;case"psv:zoom-updated":this._moveZoomValue(a.args[0])}},l.prototype._moveZoomValue=function(a){this.zoom_value.style.left=a/100*this.zoom_range.offsetWidth-this.zoom_value.offsetWidth/2+"px"},l.prototype._initZoomChangeWithMouse=function(a){this.prop.mousedown=!0,this._changeZoom(a.clientX)},l.prototype._initZoomChangeByTouch=function(a){this.prop.mousedown=!0,this._changeZoom(a.changedTouches[0].clientX)},l.prototype._stopZoomChange=function(a){this.prop.mousedown=!1},l.prototype._changeZoomWithMouse=function(a){a.preventDefault(),this._changeZoom(a.clientX)},l.prototype._changeZoomByTouch=function(a){a.preventDefault(),this._changeZoom(a.changedTouches[0].clientX)},l.prototype._changeZoom=function(a){if(this.prop.mousedown){var b=parseInt(a)-this.zoom_range.getBoundingClientRect().left,c=b/this.zoom_range.offsetWidth*100;this.psv.zoom(c)}},m.prototype=Object.create(i.prototype),m.prototype.constructor=m,m.prototype.create=function(){i.prototype.create.call(this),this.button.classList.add("download-button"),this.button.title=this.psv.config.lang.download,this.button.appendChild(document.createElement("div")),this.button.addEventListener("mouseenter",this.toggleActive.bind(this,!0)),this.button.addEventListener("mouseleave",this.toggleActive.bind(this,!1)),this.button.addEventListener("click",this.download.bind(this))},m.prototype.download=function(){var a=document.createElement("a");a.href=this.psv.config.panorama,a.download=this.psv.config.panorama,this.psv.container.appendChild(a),a.click()},n.prototype=Object.create(i.prototype),n.prototype.constructor=n,n.prototype.create=function(){i.prototype.create.call(this),this.button.classList.add("markers-button"),this.button.title=this.psv.config.lang.markers,this.button.innerHTML=b.ICONS["pin.svg"],this.button.addEventListener("click",this.toggleMarkers.bind(this)),this.psv.on("open-panel",this),this.psv.on("close-panel",this)},n.prototype.destroy=function(){this.psv.off("open-panel",this),this.psv.off("close-panel",this),i.prototype.destroy.call(this)},n.prototype.handleEvent=function(a){switch(a.type){case"psv:open-panel":this._onPanelOpened();break;case"psv:close-panel":this._onPanelClosed()}},n.prototype.toggleMarkers=function(){this.prop.panelOpened?this.hideMarkers():this.showMarkers()},n.prototype.showMarkers=function(){var a=''+this.psv.config.lang.markers+" ";for(var b in this.psv.hud.markers){var c=this.psv.hud.markers[b],d=c.id;c.html?d=c.html:c.tooltip&&(d="string"==typeof c.tooltip?c.tooltip:c.tooltip.content),a+='',c.image&&(a+=' '),a+=""+d+"
"}a+=" ",this.prop.panelOpening=!0,this.psv.panel.showPanel(a,!0),this.psv.panel.container.querySelector(".psv-markers-list").addEventListener("click",this._onClickItem.bind(this))},n.prototype.hideMarkers=function(){this.psv.panel.hidePanel()},n.prototype._onClickItem=function(a){var b;a.target&&(b=p.getClosest(a.target,"li"))&&b.dataset.psvMarker&&(this.psv.hud.gotoMarker(b.dataset.psvMarker,1e3),this.psv.panel.hidePanel())},n.prototype._onPanelOpened=function(){this.prop.panelOpening?(this.prop.panelOpening=!1,this.prop.panelOpened=!0):this.prop.panelOpened=!1,this.toggleActive(this.prop.panelOpened)},n.prototype._onPanelClosed=function(){this.prop.panelOpened=!1,this.prop.panelOpening=!1,this.toggleActive(this.prop.panelOpened)},o.prototype=Object.create(Error.prototype),o.prototype.name="PSVError",o.prototype.constructor=o;var p={};return p.isCanvasSupported=function(){var a=document.createElement("canvas");return!(!a.getContext||!a.getContext("2d"))},p.isWebGLSupported=function(){var a=document.createElement("canvas");return!(!window.WebGLRenderingContext||!a.getContext("webgl"))},p.getMaxTextureWidth=function(){var a=document.createElement("canvas"),b=a.getContext("webgl");return b.getParameter(b.MAX_TEXTURE_SIZE)},p.hasParent=function(a,b){do if(a===b)return!0;while(a=a.parentNode);return!1},p.getClosest=function(a,b){var c=a.matches||a.msMatchesSelector;do if(c.bind(a)(b))return a;while(a=a.parentElement);return null},p.mouseWheelEvent=function(){return"onwheel"in document.createElement("div")?"wheel":void 0!==document.onmousewheel?"mousewheel":"DOMMouseScroll"},p.fullscreenEvent=function(){var a={exitFullscreen:"fullscreenchange",webkitExitFullscreen:"webkitfullscreenchange",mozCancelFullScreen:"mozfullscreenchange",msExitFullscreen:"msFullscreenEnabled"};for(var b in a)if(b in document)return a[b];return"fullscreenchange"},p.stayBetween=function(a,b,c){return Math.max(b,Math.min(c,a))},p.getXMPValue=function(a,b){var c,d;return-1!==(c=a.indexOf(""))&&-1!==(d=a.indexOf(" "))?a.substring(c,d).replace("",""):-1!==(c=a.indexOf("GPano:"+b))&&-1!==(d=a.indexOf('"',c))?a.substring(c+b.length+8,d):null},p.isFullscreenEnabled=function(){return document.fullscreenElement||document.mozFullScreenElement||document.webkitFullscreenElement||document.msFullscreenElement},p.requestFullscreen=function(a){(a.requestFullscreen||a.mozRequestFullScreen||a.webkitRequestFullscreen||a.msRequestFullscreen).call(a)},p.exitFullscreen=function(a){(document.exitFullscreen||document.mozCancelFullScreen||document.webkitExitFullscreen||document.msExitFullscreen).call(document)},p.getStyle=function(a,b){return window.getComputedStyle(a,null)[b]},p.parsePosition=function(a){if(!a)return{top:.5,left:.5};if("object"==typeof a)return a;var b=document.createElement("div");document.body.appendChild(b),b.style.backgroundPosition=a;var c=p.getStyle(b,"background-position").match(/^([0-9.]+)% ([0-9.]+)%$/);return document.body.removeChild(b),{left:c[1]/100,top:c[2]/100}},p.deepmerge=function(a,b){var c=Array.isArray(b),d=c&&[]||{};return c?(a=a||[],d=d.concat(a),b.forEach(function(b,c){"undefined"==typeof d[c]?d[c]=b:"object"==typeof b?d[c]=p.deepmerge(a[c],b):-1===a.indexOf(b)&&d.push(b)})):(a&&"object"==typeof a&&Object.keys(a).forEach(function(b){d[b]=a[b]}),Object.keys(b).forEach(function(c){"object"==typeof b[c]&&b[c]&&a[c]?d[c]=p.deepmerge(a[c],b[c]):d[c]=b[c]})),d},p.clone=function(a){return p.deepmerge({},a)},b.ICONS["pin.svg"]=' ',b.ICONS["zoom-in.svg"]=' ',b.ICONS["zoom-out.svg"]=' ',b});
\ No newline at end of file
diff --git a/example/index.htm b/example/index.htm
index 821c33ea0..8b9afd759 100644
--- a/example/index.htm
+++ b/example/index.htm
@@ -14,9 +14,8 @@
padding: 0;
}
#photosphere {
- width: 75vw;
- height: 75vh;
- margin: 12.5vh 12.5vw;
+ width: 100%;
+ height: 100%;
}
@@ -61,6 +60,7 @@ Header Level 3
var PSV = new PhotoSphereViewer({
panorama: 'Bryce-Canyon-National-Park-Mark-Doliner.jpg',
container: 'photosphere',
+ loading_img: 'photosphere-logo.gif',
navbar: true, //'fullscreen zoom',
caption: 'Bryce Canyon National Park © Mark Doliner ',
tilt_up_max: Math.PI/4,
diff --git a/example/photosphere-logo.gif b/example/photosphere-logo.gif
new file mode 100644
index 000000000..199ebdd87
Binary files /dev/null and b/example/photosphere-logo.gif differ
diff --git a/package.json b/package.json
index 2deb878e1..a89d2368c 100644
--- a/package.json
+++ b/package.json
@@ -1,6 +1,6 @@
{
"name": "Photo-Sphere-Viewer",
- "version": "3.0.1",
+ "version": "3.1.0",
"authors": [
{
"name": "Jérémy Heleine",
diff --git a/src/js/PSVNavBarMarkersButton.js b/src/js/PSVNavBarMarkersButton.js
index db5d3dd27..2e5e2adaf 100644
--- a/src/js/PSVNavBarMarkersButton.js
+++ b/src/js/PSVNavBarMarkersButton.js
@@ -123,6 +123,7 @@ PSVNavBarMarkersButton.prototype._onClickItem = function(e) {
var li;
if (e.target && (li = PSVUtils.getClosest(e.target, 'li')) && li.dataset.psvMarker) {
this.psv.hud.gotoMarker(li.dataset.psvMarker, 1000);
+ this.psv.panel.hidePanel();
}
};
diff --git a/src/js/PSVTooltip.js b/src/js/PSVTooltip.js
index 8126cc6e8..ac6ba939f 100644
--- a/src/js/PSVTooltip.js
+++ b/src/js/PSVTooltip.js
@@ -92,6 +92,10 @@ PSVTooltip.prototype.showTooltip = function(config) {
config.position = [PSVTooltip.topMap[tempPos.top], PSVTooltip.leftMap[tempPos.left]];
}
+ if (config.position[0] == 'center' && config.position[1] == 'center') {
+ throw new PSVError('unable to parse tooltip position "center center"');
+ }
+
t.className = 'psv-tooltip'; // reset the class
if (config.className) {
t.classList.add(config.className);
diff --git a/src/js/PhotoSphereViewer.js b/src/js/PhotoSphereViewer.js
index 9ef40977b..48cf3d7d0 100644
--- a/src/js/PhotoSphereViewer.js
+++ b/src/js/PhotoSphereViewer.js
@@ -165,8 +165,8 @@ PhotoSphereViewer.prototype.destroy = function() {
if (this.config.mousemove) {
this.hud.container.removeEventListener('mousedown', this);
this.hud.container.removeEventListener('touchstart', this);
- this.hud.container.removeEventListener('mouseup', this);
- this.hud.container.removeEventListener('touchend', this);
+ window.removeEventListener('mouseup', this);
+ window.removeEventListener('touchend', this);
this.hud.container.removeEventListener('mousemove', this);
this.hud.container.removeEventListener('touchmove', this);
}
@@ -475,8 +475,8 @@ PhotoSphereViewer.prototype._bindEvents = function() {
this.hud.container.style.cursor = 'move';
this.hud.container.addEventListener('mousedown', this);
this.hud.container.addEventListener('touchstart', this);
- this.hud.container.addEventListener('mouseup', this);
- this.hud.container.addEventListener('touchend', this);
+ window.addEventListener('mouseup', this);
+ window.addEventListener('touchend', this);
this.hud.container.addEventListener('mousemove', this);
this.hud.container.addEventListener('touchmove', this);
}