Pārlūkot izejas kodu

Added "watermark" feature.

Specify a "watermark" img url in the config.json file and it will appear over the panorama bottom right.

overload pnlm-watermark (or pnlm-watermark img) to change styling.
pull/171/head
Gareth Hay pirms 8 gadiem
vecāks
revīzija
1fd2f10c8a
2 mainītis faili ar 111 papildinājumiem un 95 dzēšanām
  1. +7
    -1
      src/css/pannellum.css
  2. +104
    -94
      src/js/pannellum.js

+ 7
- 1
src/css/pannellum.css Parādīt failu

@@ -49,7 +49,7 @@

.pnlm-render-container {
cursor: inherit;
/* Fix display bug in Safari 7 */
position: absolute;
height: 100%;
@@ -116,6 +116,12 @@
.pnlm-fullscreen-toggle-button-active {
background-position: 0 -78px;
}
.pnlm-watermark {
position : absolute;
right : 0px;
bottom : 0px;
z-index: 100;
}

.pnlm-panorama-info {
position: absolute;


+ 104
- 94
src/js/pannellum.js Parādīt failu

@@ -1,17 +1,17 @@
/*
* Pannellum - An HTML5 based Panorama Viewer
* Copyright (c) 2011-2016 Matthew Petroff
*
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
@@ -208,6 +208,16 @@ if (initialConfig.firstScene) {
}
processOptions();

//Watermark additions
if (config.watermark){
var watermark = document.createElement('div');
watermark.className = 'pnlm-watermark';
var wmimg = document.createElement("img");
wmimg.src = config.watermark;
watermark.appendChild(wmimg);
container.appendChild(watermark);
}

/**
* Initializes viewer.
* @private
@@ -222,9 +232,9 @@ function init() {
anError();
return;
}
var i, p;
if (config.type == 'cubemap') {
panoImage = [];
for (i = 0; i < 6; i++) {
@@ -257,21 +267,21 @@ function init() {
if (config.type == 'cubemap') {
// Quick loading counter for synchronous loading
var itemsToLoad = 6;
var onLoad = function() {
itemsToLoad--;
if (itemsToLoad === 0) {
onImageLoad();
}
};
var onError = function(e) {
var a = document.createElement('a');
a.href = e.target.src;
a.innerHTML = a.href;
anError('The file ' + a.outerHTML + ' could not be accessed.');
};
for (i = 0; i < panoImage.length; i++) {
panoImage[i].onload = onLoad;
panoImage[i].onerror = onError;
@@ -288,16 +298,16 @@ function init() {
if (config.basePath) {
p = config.basePath;
}
if (config.dynamic !== true) {
// Still image
p = absoluteURL(config.panorama) ? config.panorama : p + config.panorama;
panoImage.onload = function() {
window.URL.revokeObjectURL(this.src); // Clean up
onImageLoad();
};
var xhr = new XMLHttpRequest();
xhr.onloadend = function() {
if (xhr.status != 200) {
@@ -348,7 +358,7 @@ function init() {
xhr.send();
}
}
container.classList.add('pnlm-grab');
container.classList.remove('pnlm-grabbing');
}
@@ -435,7 +445,7 @@ function parseGPanoXMP(image) {
var start = img.indexOf('<x:xmpmeta');
if (start > -1 && config.ignoreGPanoXMP !== true) {
var xmpData = img.substring(start, img.indexOf('</x:xmpmeta>') + 12);
// Extract the requested tag from the XMP data
var getTag = function(tag) {
var result;
@@ -451,7 +461,7 @@ function parseGPanoXMP(image) {
}
return null;
};
// Relevant XMP data
var xmp = {
fullWidth: getTag('GPano:FullPanoWidthPixels'),
@@ -463,11 +473,11 @@ function parseGPanoXMP(image) {
horizonPitch: getTag('GPano:PosePitchDegrees'),
horizonRoll: getTag('GPano:PoseRollDegrees')
};
if (xmp.fullWidth !== null && xmp.croppedWidth !== null &&
xmp.fullHeight !== null && xmp.croppedHeight !== null &&
xmp.topPixels !== null) {
// Set up viewer using GPano XMP data
config.haov = xmp.croppedWidth / xmp.fullWidth * 360;
config.vaov = xmp.croppedHeight / xmp.fullHeight * 180;
@@ -483,11 +493,11 @@ function parseGPanoXMP(image) {
panoImage.horizonPitch = xmp.horizonPitch / 180 * Math.PI;
panoImage.horizonRoll = xmp.horizonRoll / 180 * Math.PI;
}
// TODO: add support for initial view settings
}
}
// Load panorama
panoImage.src = window.URL.createObjectURL(image);
});
@@ -569,12 +579,12 @@ function onDocumentMouseDown(event) {
event.preventDefault();
// But not all of it
container.focus();
// Only do something if the panorama is loaded
if (!loaded) {
return;
}
// Calculate mouse position relative to top left of viewer container
var pos = mousePosition(event);

@@ -584,25 +594,25 @@ function onDocumentMouseDown(event) {
console.log('Pitch: ' + coords[0] + ', Yaw: ' + coords[1] + ', Center Pitch: ' +
config.pitch + ', Center Yaw: ' + config.yaw + ', HFOV: ' + config.hfov);
}
// Turn off auto-rotation if enabled
config.autoRotate = false;

window.removeEventListener('deviceorientation', orientationListener);
config.roll = 0;
isUserInteracting = true;
latestInteraction = Date.now();
onPointerDownPointerX = pos.x;
onPointerDownPointerY = pos.y;
onPointerDownYaw = config.yaw;
onPointerDownPitch = config.pitch;
container.classList.add('pnlm-grabbing');
container.classList.remove('pnlm-grab');
animateInit();
}

@@ -641,9 +651,9 @@ function onDocumentMouseMove(event) {
var yaw = ((Math.atan(onPointerDownPointerX / canvas.width * 2 - 1) - Math.atan(pos.x / canvas.width * 2 - 1)) * 180 / Math.PI * config.hfov / 90) + onPointerDownYaw;
yawSpeed = (yaw - config.yaw) % 360 * 0.2;
config.yaw = yaw;
var vfov = 2 * Math.atan(Math.tan(config.hfov/360*Math.PI) * canvas.height / canvas.width) * 180 / Math.PI;
var pitch = ((Math.atan(pos.y / canvas.height * 2 - 1) - Math.atan(onPointerDownPointerY / canvas.height * 2 - 1)) * 180 / Math.PI * vfov / 90) + onPointerDownPitch;
pitchSpeed = (pitch - config.pitch) * 0.2;
config.pitch = pitch;
@@ -691,7 +701,7 @@ function onDocumentTouchStart(event) {

onPointerDownPointerX = pos0.x;
onPointerDownPointerY = pos0.y;
if (event.targetTouches.length == 2) {
// Down pointer is the center of the two fingers
var pos1 = mousePosition(event.targetTouches[1]);
@@ -702,7 +712,7 @@ function onDocumentTouchStart(event) {
}
isUserInteracting = true;
latestInteraction = Date.now();
onPointerDownYaw = config.yaw;
onPointerDownPitch = config.pitch;

@@ -725,7 +735,7 @@ function onDocumentTouchMove(event) {
var pos0 = mousePosition(event.targetTouches[0]);
var clientX = pos0.x;
var clientY = pos0.y;
if (event.targetTouches.length == 2 && onPointerDownPointerDist != -1) {
var pos1 = mousePosition(event.targetTouches[1]);
clientX += (pos1.x - pos0.x) * 0.5;
@@ -735,11 +745,11 @@ function onDocumentTouchMove(event) {
setHfov(config.hfov + (onPointerDownPointerDist - clientDist) * 0.1);
onPointerDownPointerDist = clientDist;
}
var yaw = (onPointerDownPointerX - clientX) * 0.1 + onPointerDownYaw;
yawSpeed = (yaw - config.yaw) % 360 * 0.2;
config.yaw = yaw;
var pitch = (clientY - onPointerDownPointerY) * 0.1 + onPointerDownPitch;
pitchSpeed = (pitch - config.pitch) * 0.2;
config.pitch = pitch;
@@ -827,7 +837,7 @@ function onDocumentPointerUp(event) {
*/
function onDocumentMouseWheel(event) {
event.preventDefault();
// Only do something if the panorama is loaded
if (!loaded) {
return;
@@ -847,7 +857,7 @@ function onDocumentMouseWheel(event) {
setHfov(config.hfov + event.detail * 1.5);
zoomSpeed = event.detail > 0 ? 1 : -1;
}
animateInit();
}

@@ -859,7 +869,7 @@ function onDocumentMouseWheel(event) {
function onDocumentKeyPress(event) {
// Override default action
event.preventDefault();
// Turn off auto-rotation if enabled
config.autoRotate = false;

@@ -871,7 +881,7 @@ function onDocumentKeyPress(event) {
if (event.which) {
keynumber = event.which;
}
// If escape key is pressed
if (keynumber == 27) {
// If in fullscreen mode
@@ -902,13 +912,13 @@ function clearKeys() {
function onDocumentKeyUp(event) {
// Override default action
event.preventDefault();
// Record key released
var keynumber = event.keycode;
if (event.which) {
keynumber = event.which;
}
// Change key
changeKey(keynumber, false);
}
@@ -926,53 +936,53 @@ function changeKey(keynumber, value) {
case 109: case 189: case 17:
if (keysDown[0] != value) { keyChanged = true; }
keysDown[0] = value; break;
// If plus key is released
case 107: case 187: case 16:
if (keysDown[1] != value) { keyChanged = true; }
keysDown[1] = value; break;
// If up arrow is released
case 38:
if (keysDown[2] != value) { keyChanged = true; }
keysDown[2] = value; break;
// If "w" is released
case 87:
if (keysDown[6] != value) { keyChanged = true; }
keysDown[6] = value; break;
// If down arrow is released
case 40:
if (keysDown[3] != value) { keyChanged = true; }
keysDown[3] = value; break;
// If "s" is released
case 83:
if (keysDown[7] != value) { keyChanged = true; }
keysDown[7] = value; break;
// If left arrow is released
case 37:
if (keysDown[4] != value) { keyChanged = true; }
keysDown[4] = value; break;
// If "a" is released
case 65:
if (keysDown[8] != value) { keyChanged = true; }
keysDown[8] = value; break;
// If right arrow is released
case 39:
if (keysDown[5] != value) { keyChanged = true; }
keysDown[5] = value; break;
// If "d" is released
case 68:
if (keysDown[9] != value) { keyChanged = true; }
keysDown[9] = value;
}
if (keyChanged && value) {
if (typeof performance !== 'undefined' && performance.now()) {
prevTime = performance.now();
@@ -993,11 +1003,11 @@ function keyRepeat() {
if (!loaded) {
return;
}
var prevPitch = config.pitch;
var prevYaw = config.yaw;
var prevZoom = config.hfov;
var newTime;
if (typeof performance !== 'undefined' && performance.now()) {
newTime = performance.now();
@@ -1009,41 +1019,41 @@ function keyRepeat() {
}
var diff = (newTime - prevTime) * config.hfov / 1700;
diff = Math.min(diff, 1.0);
// If minus key is down
if (keysDown[0] && config.keyboardZoom === true) {
setHfov(config.hfov + (zoomSpeed * 0.8 + 0.5) * diff);
}
// If plus key is down
if (keysDown[1] && config.keyboardZoom === true) {
setHfov(config.hfov + (zoomSpeed * 0.8 - 0.2) * diff);
}
// If up arrow or "w" is down
if (keysDown[2] || keysDown[6]) {
// Pan up
config.pitch += (pitchSpeed * 0.8 + 0.2) * diff;
}
// If down arrow or "s" is down
if (keysDown[3] || keysDown[7]) {
// Pan down
config.pitch += (pitchSpeed * 0.8 - 0.2) * diff;
}
// If left arrow or "a" is down
if (keysDown[4] || keysDown[8]) {
// Pan left
config.yaw += (yawSpeed * 0.8 - 0.2) * diff;
}
// If right arrow or "d" is down
if (keysDown[5] || keysDown[9]) {
// Pan right
config.yaw += (yawSpeed * 0.8 + 0.2) * diff;
}
// If auto-rotate
var inactivityInterval = Date.now() - latestInteraction;
if (config.autoRotate &&
@@ -1052,7 +1062,7 @@ function keyRepeat() {
if (diff > 0.000001) {
config.yaw -= config.autoRotate / 60 * diff;
}
// Deal with stopping auto rotation after a set delay
if (config.autoRotateStopDelay) {
config.autoRotateStopDelay -= newTime - prevTime;
@@ -1066,7 +1076,7 @@ function keyRepeat() {
if (diff > 0) {
// "Friction"
var friction = 0.85;
// Yaw
if (!keysDown[4] && !keysDown[5] && !keysDown[8] && !keysDown[9]) {
config.yaw += yawSpeed * diff * friction;
@@ -1086,14 +1096,14 @@ function keyRepeat() {
yawSpeed = yawSpeed * 0.8 + (config.yaw - prevYaw) / diff * 0.2;
pitchSpeed = pitchSpeed * 0.8 + (config.pitch - prevPitch) / diff * 0.2;
zoomSpeed = zoomSpeed * 0.8 + (config.hfov - prevZoom) / diff * 0.2;
// Limit speed
var maxSpeed = 5;
yawSpeed = Math.min(maxSpeed, Math.max(yawSpeed, -maxSpeed));
pitchSpeed = Math.min(maxSpeed, Math.max(pitchSpeed, -maxSpeed));
zoomSpeed = Math.min(maxSpeed, Math.max(zoomSpeed, -maxSpeed));
}
// Stop movement if opposite controls are pressed
if (keysDown[0] && keysDown[0]) {
zoomSpeed = 0;
@@ -1114,7 +1124,7 @@ function onDocumentResize() {
// Resize panorama renderer
renderer.resize();
animateInit();
// Kludge to deal with WebKit regression: https://bugs.webkit.org/show_bug.cgi?id=93525
onFullScreenChange();
}
@@ -1183,7 +1193,7 @@ function render() {

// Ensure the yaw is within min and max allowed
config.yaw = Math.max(config.minYaw, Math.min(config.maxYaw, config.yaw));
// Check if we autoRotate in a limited by min and max yaw
// If so reverse direction
if (config.autoRotate !== false && tmpyaw != config.yaw) {
@@ -1192,11 +1202,11 @@ function render() {

// Ensure the calculated pitch is within min and max allowed
config.pitch = Math.max(config.minPitch, Math.min(config.maxPitch, config.pitch));
renderer.render(config.pitch * Math.PI / 180, config.yaw * Math.PI / 180, config.hfov * Math.PI / 180, {roll: config.roll * Math.PI / 180});
renderHotSpots();
// Update compass
if (config.compass) {
compass.style.transform = 'rotate(' + (-config.yaw - config.northOffset) + 'deg)';
@@ -1309,7 +1319,7 @@ function renderInit() {
renderer.init(config.haov * Math.PI / 180, config.vaov * Math.PI / 180, config.vOffset * Math.PI / 180, renderInitCallback);
} catch(event) {
// Panorama not loaded
// Display error if there is a bad texture
if (event.type == 'webgl error' || event.type == 'no webgl') {
anError();
@@ -1331,7 +1341,7 @@ function renderInit() {
function renderInitCallback() {
if (oldRenderer !== undefined) {
oldRenderer.destroy();
// Fade if specified
if (config.sceneFadeDuration && oldRenderer.fadeImg !== undefined) {
oldRenderer.fadeImg.style.opacity = 0;
@@ -1343,17 +1353,17 @@ function renderInitCallback() {
}, config.sceneFadeDuration);
}
}
// Show compass if applicable
if (config.compass) {
compass.style.display = 'inline';
} else {
compass.style.display = 'none';
}
// Show hotspots
createHotSpots();
// Hide loading display
infoDisplay.load.box.style.display = 'none';
if (preview !== undefined) {
@@ -1361,7 +1371,7 @@ function renderInitCallback() {
preview = undefined;
}
loaded = true;
animateInit();
}

@@ -1371,7 +1381,7 @@ function renderInitCallback() {
*/
function createHotSpots() {
if (hotspotsCreated) return;
if (!config.hotSpots) {
config.hotSpots = [];
} else {
@@ -1382,11 +1392,11 @@ function createHotSpots() {
config.hotSpots.forEach(function(hs) {
var div = document.createElement('div');
div.className = 'pnlm-hotspot pnlm-tooltip pnlm-sprite pnlm-' + escapeHTML(hs.type);
var span = document.createElement('span');
if (hs.text)
span.innerHTML = escapeHTML(hs.text);
var a;
if (hs.video) {
var video = document.createElement('video'),
@@ -1436,7 +1446,7 @@ function createHotSpots() {
}
renderContainer.appendChild(div);
}
div.appendChild(span);
span.style.width = span.scrollWidth - 20 + 'px';
span.style.marginLeft = -(span.scrollWidth - 26) / 2 + 'px';
@@ -1512,14 +1522,14 @@ function mergeConfig(sceneId) {
config = {};
var k;
var photoSphereExcludes = ['haov', 'vaov', 'vOffset', 'northOffset'];
// Merge default config
for (k in defaultConfig) {
if (defaultConfig.hasOwnProperty(k)) {
config[k] = defaultConfig[k];
}
}
// Merge default scene config
for (k in initialConfig.default) {
if (initialConfig.default.hasOwnProperty(k)) {
@@ -1529,7 +1539,7 @@ function mergeConfig(sceneId) {
}
}
}
// Merge current scene config
if ((sceneId !== null) && (sceneId !== '') && (initialConfig.scenes) && (initialConfig.scenes[sceneId])) {
var scene = initialConfig.scenes[sceneId];
@@ -1543,7 +1553,7 @@ function mergeConfig(sceneId) {
}
config.scene = sceneId;
}
// Merge initial config
for (k in initialConfig) {
if (initialConfig.hasOwnProperty(k)) {
@@ -1573,7 +1583,7 @@ function processOptions() {
preview.style.backgroundImage = "url('" + encodeURI(p) + "')";
renderContainer.appendChild(preview);
}
// Process other options
for (var key in config) {
if (config.hasOwnProperty(key)) {
@@ -1582,25 +1592,25 @@ function processOptions() {
infoDisplay.title.innerHTML = escapeHTML(config[key]);
infoDisplay.container.style.display = 'inline';
break;
case 'author':
infoDisplay.author.innerHTML = 'by ' + escapeHTML(config[key]);
infoDisplay.container.style.display = 'inline';
break;
case 'fallback':
infoDisplay.errorMsg.innerHTML = '<p>Your browser does not support WebGL.<br><a href="' + encodeURI(config[key]) + '" target="_blank">Click here to view this panorama in an alternative viewer.</a></p>';
break;
case 'hfov':
setHfov(Number(config[key]));
break;
case 'pitch':
// Keep pitch within bounds
config.pitch = Math.max(config.minPitch, Math.min(config.maxPitch, config.pitch));
break;
case 'autoLoad':
if (config[key] === true && oldRenderer === undefined) {
// Show loading box
@@ -1611,7 +1621,7 @@ function processOptions() {
init();
}
break;
case 'showZoomCtrl':
if (config[key]) {
// Show zoom controls
@@ -1625,7 +1635,7 @@ function processOptions() {
case 'showFullscreenCtrl':
if (config[key] && ('fullscreen' in document || 'mozFullScreen' in document ||
'webkitIsFullScreen' in document || 'msFullscreenElement' in document)) {
// Show fullscreen control
controls.fullscreen.style.display = 'block';
} else {
@@ -1756,7 +1766,7 @@ function load() {
function loadScene(sceneId, targetPitch, targetYaw, targetHfov) {
loaded = false;
oldRenderer = renderer;
// Set up fade if specified
var fadeImg, workingPitch, workingYaw, workingHfov;
if (config.sceneFadeDuration) {
@@ -1772,7 +1782,7 @@ function loadScene(sceneId, targetPitch, targetYaw, targetHfov) {
renderContainer.appendChild(fadeImg);
oldRenderer.fadeImg = fadeImg;
}
// Set new pointing
if (targetPitch === 'same') {
workingPitch = config.pitch;
@@ -1791,13 +1801,13 @@ function loadScene(sceneId, targetPitch, targetYaw, targetHfov) {
} else {
workingHfov = targetHfov;
}
// Destroy hot spots from previous scene
destroyHotSpots();
// Create the new config for the scene
mergeConfig(sceneId);
// Reload scene
processOptions();
if (workingPitch) {


Notiek ielāde…
Atcelt
Saglabāt