photo-sphere-viewer
Version:
A JavaScript library to display Photo Sphere panoramas
224 lines (196 loc) • 5.58 kB
JavaScript
import { PSVError } from '../PSVError';
import { VIEWER_DATA } from './constants';
const LOCALSTORAGE_TOUCH_SUPPORT = `${VIEWER_DATA}_touchSupport`;
/**
* @summary General information about the system
* @constant
* @memberOf PSV
* @property {boolean} loaded - Indicates if the system data has been loaded
* @property {Function} load - Loads the system if not already loaded
* @property {number} pixelRatio
* @property {boolean} isWebGLSupported
* @property {number} maxCanvasWidth
* @property {string} mouseWheelEvent
* @property {string} fullscreenEvent
* @property {Function} getMaxCanvasWidth - Returns the max width of a canvas allowed by the browser
* @property {{initial: boolean, promise: Promise<boolean>}} isTouchEnabled
*/
export const SYSTEM = {
loaded : false,
pixelRatio : 1,
isWebGLSupported: false,
isTouchEnabled : null,
maxTextureWidth : 0,
mouseWheelEvent : null,
fullscreenEvent : null,
};
/**
* @summary Loads the system if not already loaded
*/
SYSTEM.load = () => {
if (!SYSTEM.loaded) {
const ctx = getWebGLCtx();
SYSTEM.loaded = true;
SYSTEM.pixelRatio = window.devicePixelRatio || 1;
SYSTEM.isWebGLSupported = ctx != null;
SYSTEM.isTouchEnabled = isTouchEnabled();
SYSTEM.maxTextureWidth = getMaxTextureWidth(ctx);
SYSTEM.mouseWheelEvent = getMouseWheelEvent();
SYSTEM.fullscreenEvent = getFullscreenEvent();
}
};
let maxCanvasWidth = null;
SYSTEM.getMaxCanvasWidth = () => {
if (maxCanvasWidth === null) {
maxCanvasWidth = getMaxCanvasWidth(SYSTEM.maxTextureWidth);
}
return maxCanvasWidth;
};
/**
* @summary Tries to return a canvas webgl context
* @returns {WebGLRenderingContext}
* @private
*/
function getWebGLCtx() {
const canvas = document.createElement('canvas');
const names = ['webgl', 'experimental-webgl', 'moz-webgl', 'webkit-3d'];
let context = null;
if (!canvas.getContext) {
return null;
}
if (names.some((name) => {
try {
context = canvas.getContext(name);
return context !== null;
}
catch (e) {
return false;
}
})) {
return context;
}
else {
return null;
}
}
/**
* @summary Detects if the user is using a touch screen
* @returns {{initial: boolean, promise: Promise<boolean>}}
* @private
*/
function isTouchEnabled() {
let initial = ('ontouchstart' in window) || (navigator.maxTouchPoints > 0);
if (LOCALSTORAGE_TOUCH_SUPPORT in localStorage) {
initial = localStorage[LOCALSTORAGE_TOUCH_SUPPORT] === 'true';
}
const promise = new Promise((resolve) => {
let clear;
const listenerMouse = () => {
clear();
localStorage[LOCALSTORAGE_TOUCH_SUPPORT] = false;
resolve(false);
};
const listenerTouch = () => {
clear();
localStorage[LOCALSTORAGE_TOUCH_SUPPORT] = true;
resolve(true);
};
const listenerTimeout = () => {
clear();
localStorage[LOCALSTORAGE_TOUCH_SUPPORT] = initial;
resolve(initial);
};
window.addEventListener('mousedown', listenerMouse, false);
window.addEventListener('touchstart', listenerTouch, false);
const listenerTimeoutId = setTimeout(listenerTimeout, 10000);
clear = () => {
window.removeEventListener('mousedown', listenerMouse);
window.removeEventListener('touchstart', listenerTouch);
clearTimeout(listenerTimeoutId);
};
});
return { initial, promise };
}
/**
* @summary Gets max texture width in WebGL context
* @returns {number}
* @private
*/
function getMaxTextureWidth(ctx) {
if (ctx !== null) {
return ctx.getParameter(ctx.MAX_TEXTURE_SIZE);
}
else {
return 0;
}
}
/**
* @summary Gets max canvas width supported by the browser.
* We only test powers of 2 and height = width / 2 because that's what we need to generate WebGL textures
* @param maxWidth
* @return {number}
* @private
*/
function getMaxCanvasWidth(maxWidth) {
const canvas = document.createElement('canvas');
const ctx = canvas.getContext('2d');
canvas.width = maxWidth;
canvas.height = maxWidth / 2;
while (canvas.width > 1024) {
ctx.fillStyle = 'white';
ctx.fillRect(0, 0, 1, 1);
try {
if (ctx.getImageData(0, 0, 1, 1).data[0] > 0) {
return canvas.width;
}
}
catch (e) {
// continue
}
canvas.width /= 2;
canvas.height /= 2;
}
throw new PSVError('Unable to detect system capabilities');
}
/**
* @summary Gets the event name for mouse wheel
* @returns {string}
* @private
*/
function getMouseWheelEvent() {
if ('onwheel' in document.createElement('div')) { // Modern browsers support "wheel"
return 'wheel';
}
else if (document.onmousewheel !== undefined) { // Webkit and IE support at least "mousewheel"
return 'mousewheel';
}
else { // let's assume that remaining browsers are older Firefox
return 'DOMMouseScroll';
}
}
/**
* @summary Map between fullsceen method and fullscreen event name
* @type {Object<string, string>}
* @readonly
* @private
*/
const FULLSCREEN_EVT_MAP = {
exitFullscreen : 'fullscreenchange',
webkitExitFullscreen: 'webkitfullscreenchange',
mozCancelFullScreen : 'mozfullscreenchange',
msExitFullscreen : 'MSFullscreenChange',
};
/**
* @summary Gets the event name for fullscreen
* @returns {string}
* @private
*/
function getFullscreenEvent() {
const validExits = Object.keys(FULLSCREEN_EVT_MAP).filter(exit => exit in document);
if (validExits.length) {
return FULLSCREEN_EVT_MAP[validExits[0]];
}
else {
return null;
}
}