瀏覽代碼

Create the rest of the elements dynamically.

pull/54/head
Matthew Petroff 9 年之前
父節點
當前提交
7bc51fc6b7
共有 4 個檔案被更改,包括 222 行新增149 行删除
  1. +35
    -27
      src/css/pannellum.css
  2. +169
    -73
      src/js/pannellum.js
  3. +17
    -48
      src/pannellum.htm
  4. +1
    -1
      utils/build/build.py

+ 35
- 27
src/css/pannellum.css 查看文件

@@ -32,7 +32,20 @@ body {
background-image: url('img/sprites.svg');
}

#container {
.container:-moz-full-screen {
height: 100% !important;
width: 100% !important;
}
.container:-webkit-full-screen {
height: 100% !important;
width: 100% !important;
}
.container:fullscreen {
height: 100% !important;
width: 100% !important;
}

.render_container {
cursor: inherit;
/* Fix display bug in Safari 7 */
@@ -41,11 +54,6 @@ body {
width: 100%;
}

#page {
width: 100%;
height: 100%;
}

.controls {
position: absolute;
background-color: #fff;
@@ -59,14 +67,14 @@ body {
background-color: #f8f8f8;
}

#zoomcontrols {
.zoom_controls {
top: 4px;
left: 4px;
width: 26px;
height: 52px;
}

#zoom_in {
.zoom_in {
width: 100%;
height: 50%;
position: absolute;
@@ -74,7 +82,7 @@ body {
border-radius: 3px 3px 0 0;
}

#zoom_out {
.zoom_out {
width: 100%;
height: 50%;
position: absolute;
@@ -85,7 +93,7 @@ body {
border-radius: 0 0 3px 3px;
}

#fullscreentoggle_button {
.fullscreentoggle_button {
top: 66px;
left: 4px;
width: 26px;
@@ -100,7 +108,7 @@ body {
background-position: 0 -78px;
}

#panorama_info {
.panorama_info {
position: absolute;
bottom: 4px;
background-color: rgba(0,0,0,0.7);
@@ -111,7 +119,7 @@ body {
display: none;
}

#title_box {
.title_box {
position: relative;
font-size: 20px;
display: table;
@@ -119,14 +127,14 @@ body {
margin-bottom: 3px;
}

#author_box {
.author_box {
position: relative;
font-size: 12px;
display: table;
padding-left: 5px;
}

#load_box {
.load_box {
position: absolute;
top: 50%;
left: 50%;
@@ -141,7 +149,7 @@ body {
color: #fff;
}

#lbox {
.lbox {
position: absolute;
top: 50%;
left: 50%;
@@ -182,7 +190,7 @@ body {
to {left:0;top:0;}
}

#load_button {
.load_button {
position: absolute;
top: 50%;
left: 50%;
@@ -198,11 +206,11 @@ body {
cursor: pointer;
}

#load_button:hover {
.load_button:hover {
background-color: rgba(0,0,0,.8);
}

#load_button p {
.load_button p {
display: table-cell;
vertical-align: middle;
}
@@ -228,11 +236,11 @@ body {
padding: 0 5px 0 5px;
}

#nocanvas {
.error_msg {
display: none;
}

#about {
.about_msg {
font-size: 11px;
line-height: 11px;
color: #fff;
@@ -251,11 +259,11 @@ body {
transition: opacity .3s ease-in-out;
}

#about a:link, #about a:visited {
.about_msg a:link, .about_msg a:visited {
color: #fff;
}

#about a:hover, #about a:active {
.about_msg a:hover, .about_msg a:active {
color: #eee;
}

@@ -308,7 +316,7 @@ div.tooltip:hover:after {
left: 3px;
}

#compass {
.compass {
width: 50px;
height: 50px;
right: 4px;
@@ -338,26 +346,26 @@ div.tooltip:hover:after {
width: 100%;
}

#preview {
.preview_img {
top: 0;
left: 0;
background-size: 100% 100%;
}

#lbar {
.lbar {
width: 150px;
margin: 0 auto;
border: #fff 1px solid;
height: 6px;
}

#lbar_fill {
.lbar_fill {
background: #fff;
height: 100%;
width: 0;
}

#lmsg {
.lmsg {
font-size: 12px;
}



+ 169
- 73
src/js/pannellum.js 查看文件

@@ -23,15 +23,14 @@

'use strict';

// Display about information on right click
document.addEventListener('contextmenu', onRightClick, false);

// Declare variables
var config,
tourConfig = {},
configFromURL,
renderer,
oldRenderer,
preview,
container = document.getElementById('container'),
isUserInteracting = false,
latestInteraction = Date.now(),
onPointerDownPointerX = 0,
@@ -73,6 +72,99 @@ var defaultConfig = {
video: false
};

container.classList.add('container');

// Display about information on right click
var aboutMsg = document.createElement('span');
aboutMsg.className = 'about_msg';
aboutMsg.innerHTML = '<a href="http://pannellum.org/" target="_blank">Pannellum</a>';
container.appendChild(aboutMsg);
document.addEventListener('contextmenu', onRightClick);


// Create container for renderer
var renderContainer = document.createElement('div');
renderContainer.className = 'render_container';
container.appendChild(renderContainer);
var dragFix = document.createElement('div');
dragFix.className = 'dragfix';
container.appendChild(dragFix);


// Create info display
var infoDisplay = {};

// Panorama info
infoDisplay.container = document.createElement('div');
infoDisplay.container.className = 'panorama_info';
infoDisplay.title = document.createElement('div');
infoDisplay.title.className = 'title_box';
infoDisplay.container.appendChild(infoDisplay.title);
infoDisplay.author = document.createElement('div');
infoDisplay.author.className = 'author_box';
infoDisplay.container.appendChild(infoDisplay.author);
container.appendChild(infoDisplay.container);

// Load box
infoDisplay.load = {};
infoDisplay.load.box = document.createElement('div');
infoDisplay.load.box.className = 'load_box';
infoDisplay.load.box.innerHTML = '<p>Loading...</p>';
infoDisplay.load.lbox = document.createElement('div');
infoDisplay.load.lbox.className = 'lbox';
infoDisplay.load.lbox.innerHTML = '<div class="loading"></div>';
infoDisplay.load.box.appendChild(infoDisplay.load.lbox);
infoDisplay.load.lbar = document.createElement('div');
infoDisplay.load.lbar.className = 'lbar';
infoDisplay.load.lbarFill = document.createElement('div');
infoDisplay.load.lbarFill.className = 'lbar_fill';
infoDisplay.load.lbar.appendChild(infoDisplay.load.lbarFill);
infoDisplay.load.box.appendChild(infoDisplay.load.lbar);
infoDisplay.load.msg = document.createElement('p');
infoDisplay.load.msg.className = 'lmsg';
infoDisplay.load.box.appendChild(infoDisplay.load.msg);
container.appendChild(infoDisplay.load.box);

// Error message
infoDisplay.errorMsg = document.createElement('div');
infoDisplay.errorMsg.className = 'error_msg infobox';
container.appendChild(infoDisplay.errorMsg);


// Create controls
var controls = {};

// Load button
controls.load = document.createElement('div');
controls.load.className = 'load_button';
controls.load.innerHTML = '<p>Click to<br>Load<br>Panorama<p>';
controls.load.addEventListener('click', load);
container.appendChild(controls.load);

// Zoom controls
controls.zoom = document.createElement('div');
controls.zoom.className = 'zoom_controls controls';
controls.zoomIn = document.createElement('div');
controls.zoomIn.className = 'zoom_in sprite control';
controls.zoomIn.addEventListener('click', zoomIn);
controls.zoom.appendChild(controls.zoomIn);
controls.zoomOut = document.createElement('div');
controls.zoomOut.className = 'zoom_out sprite control';
controls.zoomOut.addEventListener('click', zoomOut);
controls.zoom.appendChild(controls.zoomOut);
container.appendChild(controls.zoom);

// Fullscreen toggle
controls.fullscreen = document.createElement('div');
controls.fullscreen.addEventListener('click', toggleFullscreen);
controls.fullscreen.className = 'fullscreentoggle_button sprite fullscreentoggle_button_inactive controls control';
container.appendChild(controls.fullscreen);

// Compass
var compass = document.createElement('div');
compass.className = 'compass controls control';
container.appendChild(compass);

// Process options
parseURLParameters();
processOptions();
@@ -96,8 +188,8 @@ function init() {
panoImage.push(new Image());
panoImage[i].crossOrigin = 'anonymous';
}
document.getElementById('lbox').style.display = 'block';
document.getElementById('lbar').style.display = 'none';
infoDisplay.load.lbox.style.display = 'block';
infoDisplay.load.lbar.style.display = 'none';
} else if (config.type == 'multires') {
var c = JSON.parse(JSON.stringify(config.multiRes)); // Deep copy
if (config.basePath) {
@@ -115,7 +207,7 @@ function init() {
}
function onImageLoad() {
renderer = new libpannellum.renderer(document.getElementById('container'), panoImage, config.type, config.video);
renderer = new libpannellum.renderer(renderContainer, panoImage, config.type, config.video);
// Only add event listeners once
if (!listenersAdded) {
@@ -205,13 +297,13 @@ function init() {
xhr.onloadend = function() {
var img = this.response;
parseGPanoXMP(img);
document.getElementById('lmsg').innerHTML = '';
infoDisplay.load.msg.innerHTML = '';
};
xhr.onprogress = function(e) {
if (e.lengthComputable) {
// Display progress
var percent = e.loaded / e.total * 100;
document.getElementById('lbar_fill').style.width = percent + '%';
infoDisplay.load.lbarFill.style.width = percent + '%';
var unit, numerator, denominator;
if (e.total > 1e6) {
unit = 'MB';
@@ -227,11 +319,11 @@ function init() {
denominator = e.total;
}
var msg = numerator + ' / ' + denominator + ' ' + unit;
document.getElementById('lmsg').innerHTML = msg;
infoDisplay.load.msg.innerHTML = msg;
} else {
// Display loading spinner
document.getElementById('lbox').style.display = 'block';
document.getElementById('lbar').style.display = 'none';
infoDisplay.load.lbox.style.display = 'block';
infoDisplay.load.lbar.style.display = 'none';
}
};
xhr.open('GET', p, true);
@@ -240,7 +332,8 @@ function init() {
}
}
document.getElementById('page').className = 'grab';
container.classList.add('grab');
container.classList.remove('grabbing');
}

// Parse Google Photo Sphere XMP Metadata
@@ -300,29 +393,30 @@ function parseGPanoXMP(image) {

function anError(error) {
if (error !== undefined) {
document.getElementById('nocanvas').innerHTML = '<p>' + error + '</p>';
infoDisplay.errorMsg.innerHTML = '<p>' + error + '</p>';
}
document.getElementById('load_box').style.display = 'none';
document.getElementById('nocanvas').style.display = 'table';
infoDisplay.load.box.style.display = 'none';
infoDisplay.errorMsg.innerHTML = '<p>Your browser does not have the necessary WebGL support to display this panorama.</p>';
infoDisplay.errorMsg.style.display = 'table';
error = true;
document.getElementById('container').style.display = 'none';
renderContainer.style.display = 'none';
}

function clearError() {
document.getElementById('load_box').style.display = 'none';
document.getElementById('nocanvas').style.display = 'none';
infoDisplay.load.box.style.display = 'none';
infoDisplay.errorMsg.style.display = 'none';
error = false;
}

function onRightClick(event) {
document.getElementById('about').style.left = event.clientX + 'px';
document.getElementById('about').style.top = event.clientY + 'px';
aboutMsg.style.left = event.clientX + 'px';
aboutMsg.style.top = event.clientY + 'px';
clearTimeout(onRightClick.t1);
clearTimeout(onRightClick.t2);
document.getElementById('about').style.display = 'block';
document.getElementById('about').style.opacity = 1;
onRightClick.t1 = setTimeout(function() {document.getElementById('about').style.opacity = 0;}, 2000);
onRightClick.t2 = setTimeout(function() {document.getElementById('about').style.display = 'none';}, 2500);
aboutMsg.style.display = 'block';
aboutMsg.style.opacity = 1;
onRightClick.t1 = setTimeout(function() {aboutMsg.style.opacity = 0;}, 2000);
onRightClick.t2 = setTimeout(function() {aboutMsg.style.display = 'none';}, 2500);
event.preventDefault();
}

@@ -349,7 +443,8 @@ function onDocumentMouseDown(event) {
onPointerDownYaw = config.yaw;
onPointerDownPitch = config.pitch;
document.getElementById('page').className = 'grabbing';
container.classList.add('grabbing');
container.classList.remove('grab');
requestAnimationFrame(animate);
}
@@ -378,7 +473,8 @@ function onDocumentMouseUp() {
if (Date.now() - latestInteraction > 15) {
pitchSpeed = yawSpeed = 0;
}
document.getElementById('page').className = 'grab';
container.classList.add('grab');
container.classList.remove('grabbing');
}

function onDocumentTouchStart(event) {
@@ -771,8 +867,8 @@ function render() {
// Update compass
if (config.compass) {
document.getElementById('compass').style.transform = 'rotate(' + (-config.yaw - config.northOffset) + 'deg)';
document.getElementById('compass').style.webkitTransform = 'rotate(' + (-config.yaw - config.northOffset) + 'deg)';
compass.style.transform = 'rotate(' + (-config.yaw - config.northOffset) + 'deg)';
compass.style.webkitTransform = 'rotate(' + (-config.yaw - config.northOffset) + 'deg)';
}
} catch(event) {
// Panorama not loaded
@@ -809,7 +905,7 @@ function renderInitCallback() {
oldRenderer.fadeImg.style.opacity = 0;
// Remove image
setTimeout(function() {
oldRenderer.container.removeChild(oldRenderer.fadeImg);
renderContainer.removeChild(oldRenderer.fadeImg);
}, config.sceneFadeDuration);
}
}
@@ -818,18 +914,19 @@ function renderInitCallback() {
// Show compass if applicable
if (config.compass) {
document.getElementById('compass').style.display = 'inline';
compass.style.display = 'inline';
} else {
document.getElementById('compass').style.display = 'none';
compass.style.display = 'none';
}
// Show hotspots
createHotSpots();
// Hide loading display
document.getElementById('load_box').style.display = 'none';
if (document.getElementById('preview') !== null) {
document.getElementById('container').removeChild(document.getElementById('preview'));
infoDisplay.load.box.style.display = 'none';
if (preview !== undefined) {
renderContainer.removeChild(preview);
preview = undefined;
}
loaded = true;
}
@@ -852,7 +949,7 @@ function createHotSpots() {
a = document.createElement('a');
a.setAttribute('href', hs.URL);
a.setAttribute('target', '_blank');
document.getElementById('container').appendChild(a);
renderContainer.appendChild(a);
div.style.cursor = 'pointer';
span.style.cursor = 'pointer';
a.appendChild(div);
@@ -861,7 +958,7 @@ function createHotSpots() {
video.setAttribute('src',hs.video);
video.setAttribute('controls',true);
video.setAttribute('style','width:' + hs.width + 'px');
document.getElementById('container').appendChild(div);
renderContainer.appendChild(div);
span.appendChild(video);
} else if (hs.image) {
a = document.createElement('a');
@@ -871,7 +968,7 @@ function createHotSpots() {
var image = document.createElement('img');
image.setAttribute('src',hs.image);
image.setAttribute('style','width:' + hs.width + 'px');
document.getElementById('container').appendChild(div);
renderContainer.appendChild(div);
a.appendChild(image);
} else {
@@ -887,7 +984,7 @@ function createHotSpots() {
div.style.cursor = 'pointer';
span.style.cursor = 'pointer';
}
document.getElementById('container').appendChild(div);
renderContainer.appendChild(div);
}
div.appendChild(span);
@@ -905,10 +1002,10 @@ function destroyHotSpots() {
if (config.hotSpots) {
config.hotSpots.forEach(function(hs) {
var current = hs.div;
while(current.parentNode.id != 'container') {
while(current.parentNode != renderContainer) {
current = current.parentNode;
}
document.getElementById('container').removeChild(current);
renderContainer.removeChild(current);
});
}
hotspotsCreated = false;
@@ -1064,11 +1161,11 @@ function processOptions() {
p = tourConfig.basePath + p;
}
var img = new Image();
img.crossOrigin = 'anonymous';
img.id = 'preview';
img.src = p;
document.getElementById('container').appendChild(img);
preview = new Image();
preview.crossOrigin = 'anonymous';
preview.src = p;
preview.className = 'preview_img';
renderContainer.appendChild(preview);
}
// Process other options
@@ -1076,17 +1173,17 @@ function processOptions() {
if (config.hasOwnProperty(key)) {
switch(key) {
case 'title':
document.getElementById('title_box').innerHTML = config[key];
document.getElementById('panorama_info').style.display = 'inline';
infoDisplay.title.innerHTML = config[key];
infoDisplay.container.style.display = 'inline';
break;
case 'author':
document.getElementById('author_box').innerHTML = 'by ' + config[key];
document.getElementById('panorama_info').style.display = 'inline';
infoDisplay.author.innerHTML = 'by ' + config[key];
infoDisplay.container.style.display = 'inline';
break;
case 'fallback':
document.getElementById('nocanvas').innerHTML = '<p>Your browser does not support WebGL.<br><a href="' + config[key] + '" target="_blank">Click here to view this panorama in an alternative viewer.</a></p>';
infoDisplay.errorMsg.innerHTML = '<p>Your browser does not support WebGL.<br><a href="' + config[key] + '" target="_blank">Click here to view this panorama in an alternative viewer.</a></p>';
break;
case 'hfov':
@@ -1101,9 +1198,9 @@ function processOptions() {
case 'autoLoad':
if (config[key] === true) {
// Show loading box
document.getElementById('load_box').style.display = 'inline';
infoDisplay.load.box.style.display = 'inline';
// Hide load button
document.getElementById('load_button').style.display = 'none';
controls.load.style.display = 'none';
// Initialize
init();
requestAnimationFrame(animate);
@@ -1133,10 +1230,10 @@ function processOptions() {
case 'showZoomCtrl':
if (config[key]) {
// Show zoom controls
document.getElementById('zoomcontrols').style.display = 'block';
controls.zoom.style.display = 'block';
} else {
// Hide zoom controls
document.getElementById('zoomcontrols').style.display = 'none';
controls.zoom.style.display = 'none';
}
break;
@@ -1145,10 +1242,10 @@ function processOptions() {
'webkitIsFullScreen' in document || 'msFullscreenElement' in document)) {
// Show fullscreen control
document.getElementById('fullscreentoggle_button').style.display = 'block';
controls.fullscreen.style.display = 'block';
} else {
// Hide fullscreen control
document.getElementById('fullscreentoggle_button').style.display = 'none';
controls.fullscreen.style.display = 'none';
}
break;
}
@@ -1160,15 +1257,14 @@ function toggleFullscreen() {
if (loaded && !error) {
if (!fullscreenActive) {
try {
var page = document.getElementById('page');
if (page.requestFullscreen) {
page.requestFullscreen();
} else if (page.mozRequestFullScreen) {
page.mozRequestFullScreen();
} else if (page.msRequestFullscreen) {
page.msRequestFullscreen();
if (container.requestFullscreen) {
container.requestFullscreen();
} else if (container.mozRequestFullScreen) {
container.mozRequestFullScreen();
} else if (container.msRequestFullscreen) {
container.msRequestFullscreen();
} else {
page.webkitRequestFullScreen();
container.webkitRequestFullScreen();
}
} catch(event) {
// Fullscreen doesn't work
@@ -1189,23 +1285,23 @@ function toggleFullscreen() {

function onFullScreenChange() {
if (document.fullscreen || document.mozFullScreen || document.webkitIsFullScreen || document.msFullscreenElement) {
document.getElementById('fullscreentoggle_button').classList.add('fullscreentoggle_button_active');
controls.fullscreen.classList.add('fullscreentoggle_button_active');
fullscreenActive = true;
} else {
document.getElementById('fullscreentoggle_button').classList.remove('fullscreentoggle_button_active');
controls.fullscreen.classList.remove('fullscreentoggle_button_active');
fullscreenActive = false;
}
}

function zoomIn(amount) {
function zoomIn() {
if (loaded) {
setHfov(config.hfov -= amount);
setHfov(config.hfov -= 5);
}
}

function zoomOut(amount) {
function zoomOut() {
if (loaded) {
setHfov(config.hfov += amount);
setHfov(config.hfov += 5);
}
}

@@ -1230,8 +1326,8 @@ function load() {
// memory etc and not because of a lack of WebGL support etc
clearError();

document.getElementById('load_button').style.display = 'none';
document.getElementById('load_box').style.display = 'inline';
controls.load.style.display = 'none';
infoDisplay.load.box.style.display = 'inline';
init();
requestAnimationFrame(animate);
}
@@ -1250,7 +1346,7 @@ function loadScene(sceneId, targetPitch, targetYaw) {
if (data !== undefined) {
fadeImg.src = data;
}
document.getElementById('container').appendChild(fadeImg);
renderContainer.appendChild(fadeImg);
oldRenderer.fadeImg = fadeImg;
}


+ 17
- 48
src/pannellum.htm 查看文件

@@ -1,51 +1,20 @@
<!DOCTYPE HTML>
<html>
<head>
<title>pannellum</title>
<meta charset="utf-8">
<link type="text/css" rel="Stylesheet" href="css/pannellum.css" />
</head>
<body>
<div id="page">
<div id="container"></div>
<div class="dragfix"></div>
<div id="panorama_info">
<div id="title_box"></div>
<div id="author_box"></div>
</div>
<div id="zoomcontrols" class="controls">
<div id="zoom_in" onclick="zoomIn(5)" class="sprite control"></div>
<div id="zoom_out" onclick="zoomOut(5)" class="sprite control"></div>
</div>
<div id="fullscreentoggle_button" onclick="toggleFullscreen()" class="sprite fullscreentoggle_button_inactive controls control"></div>
<div id="load_box">
<p>Loading...</p>
<div id="lbox"><div class="loading"></div></div>
<div id="lbar"><div id="lbar_fill"></div></div>
<p id="lmsg"></p>
</div>
<div id="load_button" onclick="load()"><p>Click to<br>Load<br>Panorama<p></div>
<div id="nocanvas" class="infobox"><p>Your browser does not have the necessary WebGL support to display this panorama.</p></div>
<div id="compass" class="controls control"></div>
<span id="about" style="display: none;"><a href="http://pannellum.org/" target="_blank">Pannellum</a></span>
<noscript><div id="nojavascript" class="infobox"><p>Javascript is required to view this panorama.<br>(It could be worse; you could need a plugin.)</p></div></noscript>
</div>
<script type="text/javascript" src="js/libpannellum.js"></script>
<script type="text/javascript" src="js/RequestAnimationFrame.js"></script>
<script type="text/javascript" src="js/pannellum.js"></script>
</body>
<head>
<title>pannellum</title>
<meta charset="utf-8">
<link type="text/css" rel="Stylesheet" href="css/pannellum.css"/>
</head>
<body>
<div id="container">
<noscript>
<div class="infobox">
<p>Javascript is required to view this panorama.<br>(It could be worse; you could need a plugin.)</p>
</div>
</noscript>
</div>
<script type="text/javascript" src="js/libpannellum.js"></script>
<script type="text/javascript" src="js/RequestAnimationFrame.js"></script>
<script type="text/javascript" src="js/pannellum.js"></script>
</body>
</html>

+ 1
- 1
utils/build/build.py 查看文件

@@ -88,6 +88,7 @@ def build(files, css, html, filename):
print('=' * 40)
js = merge(files)
js = js.replace('"_blank">Pannellum</a>','"_blank">Pannellum</a> ' + read('../VERSION'))
js = JScompress(js)
print('=' * 40)
@@ -111,7 +112,6 @@ def build(files, css, html, filename):
html = html.replace('<script type="text/javascript" src="js/libpannellum.js"></script>','')
html = html.replace('<script type="text/javascript" src="js/RequestAnimationFrame.js"></script>','')
html = html.replace('<script type="text/javascript" src="js/pannellum.js"></script>','<script type="text/javascript">' + js + '</script>')
html = html.replace('"_blank">Pannellum</a></span>','"_blank">Pannellum</a> ' + read('../VERSION') + '</span>')
html = htmlCompress(html)
output(addHeader(html), folder + htmlfilename)


Loading…
取消
儲存