pannellum-react
Advanced tools
Comparing version
@@ -1,8 +0,8 @@ | ||
var _class, _temp; | ||
function _assertThisInitialized(self) { if (self === void 0) { throw new ReferenceError("this hasn't been initialised - super() hasn't been called"); } return self; } | ||
function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } } | ||
function _inheritsLoose(subClass, superClass) { subClass.prototype = Object.create(superClass.prototype); subClass.prototype.constructor = subClass; _setPrototypeOf(subClass, superClass); } | ||
function _possibleConstructorReturn(self, call) { if (!self) { throw new ReferenceError("this hasn't been initialised - super() hasn't been called"); } return call && (typeof call === "object" || typeof call === "function") ? call : self; } | ||
function _setPrototypeOf(o, p) { _setPrototypeOf = Object.setPrototypeOf || function _setPrototypeOf(o, p) { o.__proto__ = p; return o; }; return _setPrototypeOf(o, p); } | ||
function _inherits(subClass, superClass) { if (typeof superClass !== "function" && superClass !== null) { throw new TypeError("Super expression must either be null or a function, not " + typeof superClass); } subClass.prototype = Object.create(superClass && superClass.prototype, { constructor: { value: subClass, enumerable: false, writable: true, configurable: true } }); if (superClass) Object.setPrototypeOf ? Object.setPrototypeOf(subClass, superClass) : subClass.__proto__ = superClass; } | ||
function _defineProperty(obj, key, value) { if (key in obj) { Object.defineProperty(obj, key, { value: value, enumerable: true, configurable: true, writable: true }); } else { obj[key] = value; } return obj; } | ||
@@ -13,3 +13,2 @@ import propTypes from "prop-types"; | ||
import "../pannellum/css/style-textInfo.css"; | ||
import "../pannellum/js/libpannellum.js"; | ||
@@ -19,16 +18,16 @@ import "../pannellum/js/pannellum.js"; | ||
var Pannellum = (_temp = _class = function (_PureComponent) { | ||
_inherits(Pannellum, _PureComponent); | ||
var Pannellum = /*#__PURE__*/function (_PureComponent) { | ||
_inheritsLoose(Pannellum, _PureComponent); | ||
function Pannellum(props) { | ||
_classCallCheck(this, Pannellum); | ||
var _this; | ||
var _this = _possibleConstructorReturn(this, _PureComponent.call(this, props)); | ||
_this = _PureComponent.call(this, props) || this; | ||
_this.renderImage = function (state) { | ||
var children = _this.props.children; | ||
// make the array of sub components, even if its one, it become array of one | ||
_defineProperty(_assertThisInitialized(_this), "renderImage", function (state) { | ||
var children = _this.props.children; // make the array of sub components, even if its one, it become array of one | ||
var hotspots = [].concat(children); | ||
var hotspotArray = []; | ||
if (Array.isArray(hotspots)) { | ||
@@ -46,2 +45,3 @@ hotspots.map(function (hotspot) { | ||
}); | ||
case "custom": | ||
@@ -56,4 +56,7 @@ return hotspotArray.push({ | ||
clickHandlerFunc: hotspot.props.handleClick ? hotspot.props.handleClick : _this.handleClickHotspot, | ||
clickHandlerArgs: hotspot.props.handleClickArg ? hotspot.props.handleClickArg : { name: "test" } | ||
clickHandlerArgs: hotspot.props.handleClickArg ? hotspot.props.handleClickArg : { | ||
name: "test" | ||
} | ||
}); | ||
default: | ||
@@ -100,7 +103,5 @@ return []; | ||
}; | ||
Object.keys(jsonConfig).forEach(function (key) { | ||
return jsonConfig[key] === "" && delete jsonConfig[key]; | ||
}); | ||
// this.setState({ jsonConfig }); | ||
}); // this.setState({ jsonConfig }); | ||
@@ -110,24 +111,33 @@ if (state === "update") { | ||
} | ||
_this.panorama = pannellum.viewer(_this.props.id ? _this.props.id : _this.state.id, jsonConfig); | ||
_this.panorama.on("load", _this.props.onLoad); | ||
_this.panorama.on("scenechange", _this.props.onScenechange); | ||
_this.panorama.on("scenechangefadedone", _this.props.onScenechangefadedone); | ||
_this.panorama.on("error", _this.props.onError); | ||
_this.panorama.on("errorcleared", _this.props.onErrorcleared); | ||
_this.panorama.on("mousedown", _this.props.onMousedown); | ||
_this.panorama.on("mouseup", _this.props.onMouseup); | ||
_this.panorama.on("touchstart", _this.props.onTouchstart); | ||
_this.panorama.on("touchend", _this.props.onTouchend); | ||
}; | ||
}); | ||
_this.componentDidMount = function () { | ||
_defineProperty(_assertThisInitialized(_this), "componentDidMount", function () { | ||
_this.renderImage("mount"); | ||
}; | ||
}); | ||
_this.handleClickHotspot = function (e, args) { | ||
_defineProperty(_assertThisInitialized(_this), "handleClickHotspot", function (e, args) { | ||
console.log("hotspot clicked", args.name); | ||
}; | ||
}); | ||
_this.hotspotTooltip = function (hotSpotDiv, args) { | ||
_defineProperty(_assertThisInitialized(_this), "hotspotTooltip", function (hotSpotDiv, args) { | ||
hotSpotDiv.setAttribute("id", "textInfo"); | ||
@@ -145,11 +155,11 @@ var hDiv = document.createElement("div"); | ||
hDiv.appendChild(outDiv); | ||
}; | ||
}); | ||
_this.getViewer = function () { | ||
_defineProperty(_assertThisInitialized(_this), "getViewer", function () { | ||
return _this.panorama; | ||
}; | ||
}); | ||
_this.forceRender = function () { | ||
_defineProperty(_assertThisInitialized(_this), "forceRender", function () { | ||
_this.renderImage("update"); | ||
}; | ||
}); | ||
@@ -162,6 +172,9 @@ _this.state = { | ||
Pannellum.prototype.componentDidUpdate = function componentDidUpdate(prevProps, prevState, snapshot) { | ||
var _proto = Pannellum.prototype; | ||
_proto.componentDidUpdate = function componentDidUpdate(prevProps, prevState, snapshot) { | ||
if (prevProps.image !== this.props.image || prevProps.width !== this.props.width || prevProps.height !== this.props.height || prevProps.compass !== this.props.compass || prevProps.title !== this.props.title || prevProps.author !== this.props.author || prevProps.preview !== this.props.preview || prevProps.previewTitle !== this.props.previewTitle || prevProps.previewAuthor !== this.props.previewAuthor || prevProps.showZoomCtrl !== this.props.showZoomCtrl || prevProps.showFullscreenCtrl !== this.props.showFullscreenCtrl || prevProps.showControls !== this.props.showControls || prevProps.children.length !== this.props.children.length) { | ||
this.renderImage("update"); | ||
} | ||
if (prevProps.maxYaw !== this.props.maxYaw || prevProps.minYaw !== this.props.minYaw || prevProps.maxPitch !== this.props.maxPitch || prevProps.minPitch !== this.props.minPitch || prevProps.maxHfov !== this.props.maxHfov || prevProps.minHfov !== this.props.minHfov) { | ||
@@ -172,8 +185,11 @@ this.panorama.setYawBounds([this.props.minYaw, this.props.maxYaw]); | ||
} | ||
if (prevProps.yaw !== this.props.yaw) { | ||
this.panorama.setYaw(this.props.yaw); | ||
} | ||
if (prevProps.pitch !== this.props.pitch) { | ||
this.panorama.setPitch(this.props.pitch); | ||
} | ||
if (prevProps.hfov !== this.props.hfov) { | ||
@@ -184,9 +200,8 @@ this.panorama.setHfov(this.props.hfov); | ||
Pannellum.prototype.render = function render() { | ||
_proto.render = function render() { | ||
var _this2 = this; | ||
var _props = this.props, | ||
width = _props.width, | ||
height = _props.height; | ||
var _this$props = this.props, | ||
width = _this$props.width, | ||
height = _this$props.height; | ||
var divStyle = { | ||
@@ -196,3 +211,3 @@ width: width, | ||
}; | ||
return React.createElement("div", { | ||
return /*#__PURE__*/React.createElement("div", { | ||
id: this.props.id ? this.props.id : this.state.id, | ||
@@ -207,3 +222,5 @@ style: divStyle, | ||
return Pannellum; | ||
}(PureComponent), _class.defaultProps = { | ||
}(PureComponent); | ||
_defineProperty(Pannellum, "defaultProps", { | ||
children: [], | ||
@@ -252,3 +269,4 @@ width: "100%", | ||
onRender: null | ||
}, _temp); | ||
}); | ||
Pannellum.propTypes = process.env.NODE_ENV !== "production" ? { | ||
@@ -307,3 +325,5 @@ children: propTypes.oneOfType([propTypes.arrayOf(propTypes.node), propTypes.node]), | ||
Pannellum.Hotspot = function () {}; | ||
Pannellum.Hotspot = function () {}; | ||
export default Pannellum; |
@@ -1,8 +0,8 @@ | ||
var _class, _temp; | ||
function _assertThisInitialized(self) { if (self === void 0) { throw new ReferenceError("this hasn't been initialised - super() hasn't been called"); } return self; } | ||
function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } } | ||
function _inheritsLoose(subClass, superClass) { subClass.prototype = Object.create(superClass.prototype); subClass.prototype.constructor = subClass; _setPrototypeOf(subClass, superClass); } | ||
function _possibleConstructorReturn(self, call) { if (!self) { throw new ReferenceError("this hasn't been initialised - super() hasn't been called"); } return call && (typeof call === "object" || typeof call === "function") ? call : self; } | ||
function _setPrototypeOf(o, p) { _setPrototypeOf = Object.setPrototypeOf || function _setPrototypeOf(o, p) { o.__proto__ = p; return o; }; return _setPrototypeOf(o, p); } | ||
function _inherits(subClass, superClass) { if (typeof superClass !== "function" && superClass !== null) { throw new TypeError("Super expression must either be null or a function, not " + typeof superClass); } subClass.prototype = Object.create(superClass && superClass.prototype, { constructor: { value: subClass, enumerable: false, writable: true, configurable: true } }); if (superClass) Object.setPrototypeOf ? Object.setPrototypeOf(subClass, superClass) : subClass.__proto__ = superClass; } | ||
function _defineProperty(obj, key, value) { if (key in obj) { Object.defineProperty(obj, key, { value: value, enumerable: true, configurable: true, writable: true }); } else { obj[key] = value; } return obj; } | ||
@@ -20,20 +20,19 @@ import propTypes from 'prop-types'; | ||
var PannellumVideo = (_temp = _class = function (_Component) { | ||
_inherits(PannellumVideo, _Component); | ||
var PannellumVideo = /*#__PURE__*/function (_Component) { | ||
_inheritsLoose(PannellumVideo, _Component); | ||
function PannellumVideo(props) { | ||
_classCallCheck(this, PannellumVideo); | ||
var _this; | ||
var _this = _possibleConstructorReturn(this, _Component.call(this, props)); | ||
_this = _Component.call(this, props) || this; | ||
_this.renderVideo = function (state) { | ||
var children = _this.props.children; | ||
// make the array of sub components, even if its one, it become array of one | ||
_defineProperty(_assertThisInitialized(_this), "renderVideo", function (state) { | ||
var children = _this.props.children; // make the array of sub components, even if its one, it become array of one | ||
var hotspots = [].concat(children); | ||
var hotspotArray = []; | ||
if (Array.isArray(hotspots)) { | ||
hotspots.map(function (hotspot) { | ||
switch (hotspot.props.type) { | ||
case "info": | ||
@@ -48,2 +47,3 @@ return hotspotArray.push({ | ||
}); | ||
case "custom": | ||
@@ -58,4 +58,7 @@ return hotspotArray.push({ | ||
"clickHandlerFunc": hotspot.props.handleClick ? hotspot.props.handleClick : _this.handleClickHotspot, | ||
"clickHandlerArgs": hotspot.props.handleClickArg ? hotspot.props.handleClickArg : { name: "test" } | ||
"clickHandlerArgs": hotspot.props.handleClickArg ? hotspot.props.handleClickArg : { | ||
name: "test" | ||
} | ||
}); | ||
default: | ||
@@ -68,19 +71,22 @@ return []; | ||
if (state === "update") { | ||
_this.video = videojs(_this.videoNode); | ||
var cuurentHS = [].concat(_this.video.pnlmViewer.getConfig().hotSpots); | ||
_this.video.pnlmViewer.setYaw(_this.props.yaw); | ||
_this.video.pnlmViewer.setPitch(_this.props.pitch); | ||
_this.video.pnlmViewer.setHfov(_this.props.hfov); | ||
_this.video.pnlmViewer.setHfovBounds([_this.props.minHfov, _this.props.maxHfov]); | ||
//remove all hotspots | ||
_this.video.pnlmViewer.setHfovBounds([_this.props.minHfov, _this.props.maxHfov]); //remove all hotspots | ||
cuurentHS.map(function (hs) { | ||
return _this.video.pnlmViewer.removeHotSpot(hs.id); | ||
}); | ||
// Adding new hotspots | ||
}); // Adding new hotspots | ||
hotspotArray.map(function (hs) { | ||
return _this.video.pnlmViewer.addHotSpot(hs); | ||
}); | ||
// setting new video | ||
}); // setting new video | ||
_this.video.src({ | ||
@@ -90,2 +96,3 @@ type: 'video/mp4', | ||
}); | ||
return _this.video.play(); | ||
@@ -116,16 +123,21 @@ } else { | ||
}); | ||
_this.video.src({ type: 'video/mp4', src: _this.props.video }); | ||
_this.video.src({ | ||
type: 'video/mp4', | ||
src: _this.props.video | ||
}); | ||
_this.video.play(); | ||
} | ||
}; | ||
}); | ||
_this.componentDidMount = function () { | ||
_defineProperty(_assertThisInitialized(_this), "componentDidMount", function () { | ||
_this.renderVideo("mount"); | ||
}; | ||
}); | ||
_this.handleClickHotspot = function (e, args) { | ||
_defineProperty(_assertThisInitialized(_this), "handleClickHotspot", function (e, args) { | ||
console.log("hotspot clicked", args.name); | ||
}; | ||
}); | ||
_this.hotspotTooltip = function (hotSpotDiv, args) { | ||
_defineProperty(_assertThisInitialized(_this), "hotspotTooltip", function (hotSpotDiv, args) { | ||
hotSpotDiv.setAttribute("id", "textInfo"); | ||
@@ -143,7 +155,7 @@ var hDiv = document.createElement('div'); | ||
hDiv.appendChild(outDiv); | ||
}; | ||
}); | ||
_this.getViewer = function () { | ||
_defineProperty(_assertThisInitialized(_this), "getViewer", function () { | ||
return _this.video.pnlmViewer; | ||
}; | ||
}); | ||
@@ -156,3 +168,5 @@ _this.state = { | ||
PannellumVideo.prototype.componentDidUpdate = function componentDidUpdate(prevProps) { | ||
var _proto = PannellumVideo.prototype; | ||
_proto.componentDidUpdate = function componentDidUpdate(prevProps) { | ||
// videojs(this.videoNode).dispose(); | ||
@@ -163,14 +177,13 @@ // this.videoNode.setAttribute("src", this.props.video ); | ||
PannellumVideo.prototype.componentWillUnmount = function componentWillUnmount() { | ||
_proto.componentWillUnmount = function componentWillUnmount() { | ||
videojs(this.videoNode).dispose(); | ||
}; | ||
PannellumVideo.prototype.render = function render() { | ||
_proto.render = function render() { | ||
var _this2 = this; | ||
var _props = this.props, | ||
width = _props.width, | ||
height = _props.height, | ||
video = _props.video; | ||
var _this$props = this.props, | ||
width = _this$props.width, | ||
height = _this$props.height, | ||
video = _this$props.video; | ||
var divStyle = { | ||
@@ -180,20 +193,20 @@ width: width, | ||
}; | ||
return React.createElement( | ||
'div', | ||
{ 'data-vjs-player': true }, | ||
React.createElement('video', { | ||
id: this.props.id ? this.props.id : this.state.id, | ||
className: 'video-js vjs-default-skin vjs-big-play-centered', | ||
ref: function ref(node) { | ||
return _this2.videoNode = node; | ||
}, | ||
preload: 'none', | ||
crossOrigin: 'anonymous', | ||
style: divStyle | ||
}) | ||
); | ||
return /*#__PURE__*/React.createElement("div", { | ||
"data-vjs-player": true | ||
}, /*#__PURE__*/React.createElement("video", { | ||
id: this.props.id ? this.props.id : this.state.id, | ||
className: "video-js vjs-default-skin vjs-big-play-centered", | ||
ref: function ref(node) { | ||
return _this2.videoNode = node; | ||
}, | ||
preload: "none", | ||
crossOrigin: "anonymous", | ||
style: divStyle | ||
})); | ||
}; | ||
return PannellumVideo; | ||
}(Component), _class.defaultProps = { | ||
}(Component); | ||
_defineProperty(PannellumVideo, "defaultProps", { | ||
children: [], | ||
@@ -219,3 +232,4 @@ width: '100%', | ||
muted: true | ||
}, _temp); | ||
}); | ||
PannellumVideo.propTypes = process.env.NODE_ENV !== "production" ? { | ||
@@ -249,4 +263,2 @@ children: propTypes.oneOfType([propTypes.arrayOf(propTypes.node), propTypes.node]), | ||
} : {}; | ||
export default PannellumVideo; |
import Pannellum from "./elements/Pannellum"; | ||
import PannellumVideo from "./elements/PannellumVideo"; | ||
export { Pannellum, PannellumVideo }; |
@@ -23,5 +23,3 @@ /* | ||
*/ | ||
window.libpannellum = function (window, document, undefined) { | ||
/** | ||
@@ -36,3 +34,2 @@ * Creates a new panorama renderer. | ||
container.appendChild(canvas); | ||
var program, gl, vs, fs; | ||
@@ -46,3 +43,2 @@ var fallbackImgSize; | ||
var globalParams; | ||
/** | ||
@@ -66,2 +62,3 @@ * Initialize renderer. | ||
*/ | ||
this.init = function (_image, _imageType, _dynamic, haov, vaov, voffset, callback, params) { | ||
@@ -75,3 +72,5 @@ // Default argument for image type | ||
console.log('Error: invalid image type specified!'); | ||
throw { type: 'config error' }; | ||
throw { | ||
type: 'config error' | ||
}; | ||
} | ||
@@ -82,5 +81,4 @@ | ||
dynamic = _dynamic; | ||
globalParams = params || {}; | ||
globalParams = params || {}; // Clear old data | ||
// Clear old data | ||
if (program) { | ||
@@ -91,2 +89,3 @@ if (vs) { | ||
} | ||
if (fs) { | ||
@@ -96,7 +95,10 @@ gl.detachShader(program, fs); | ||
} | ||
gl.bindBuffer(gl.ARRAY_BUFFER, null); | ||
gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, null); | ||
if (program.texture) { | ||
gl.deleteTexture(program.texture); | ||
} | ||
if (program.nodeCache) { | ||
@@ -107,10 +109,12 @@ for (var i = 0; i < program.nodeCache.length; i++) { | ||
} | ||
gl.deleteProgram(program); | ||
program = undefined; | ||
} | ||
pose = undefined; | ||
var s; | ||
var faceMissing = false; | ||
var cubeImgWidth; | ||
if (imageType == 'cubemap') { | ||
@@ -122,2 +126,3 @@ for (s = 0; s < 6; s++) { | ||
} | ||
if (cubeImgWidth != image[s].width) { | ||
@@ -131,2 +136,3 @@ console.log('Cube faces have inconsistent widths: ' + cubeImgWidth + ' vs. ' + image[s].width); | ||
} | ||
function fillMissingFaces(imgSize) { | ||
@@ -136,2 +142,3 @@ if (faceMissing) { | ||
var nbytes = imgSize * imgSize * 4; // RGB, plus non-functional alpha | ||
var imageArray = new Uint8ClampedArray(nbytes); | ||
@@ -141,4 +148,4 @@ var rgb = params.backgroundColor ? params.backgroundColor : [0, 0, 0]; | ||
rgb[1] *= 255; | ||
rgb[2] *= 255; | ||
// Maybe filling could be done faster, see e.g. https://stackoverflow.com/questions/1295584/most-efficient-way-to-create-a-zero-filled-javascript-array | ||
rgb[2] *= 255; // Maybe filling could be done faster, see e.g. https://stackoverflow.com/questions/1295584/most-efficient-way-to-create-a-zero-filled-javascript-array | ||
for (var i = 0; i < nbytes; i++) { | ||
@@ -149,3 +156,5 @@ imageArray[i++] = rgb[0]; | ||
} | ||
var backgroundSquare = new ImageData(imageArray, imgSize, imgSize); | ||
for (s = 0; s < 6; s++) { | ||
@@ -157,5 +166,3 @@ if (image[s].width == 0) { | ||
} | ||
} | ||
// This awful browser specific test exists because iOS 8/9 and IE 11 | ||
} // This awful browser specific test exists because iOS 8/9 and IE 11 | ||
// don't display non-power-of-two cubemap textures but also don't | ||
@@ -167,13 +174,17 @@ // throw an error (tested on an iPhone 5c / iOS 8.1.3 / iOS 9.2 / | ||
// instead. | ||
if (!(imageType == 'cubemap' && (cubeImgWidth & cubeImgWidth - 1) !== 0 && (navigator.userAgent.toLowerCase().match(/(iphone|ipod|ipad).* os 8_/) || navigator.userAgent.toLowerCase().match(/(iphone|ipod|ipad).* os 9_/) || navigator.userAgent.toLowerCase().match(/(iphone|ipod|ipad).* os 10_/) || navigator.userAgent.match(/Trident.*rv[ :]*11\./)))) { | ||
// Enable WebGL on canvas | ||
if (!gl) { | ||
gl = canvas.getContext('experimental-webgl', { alpha: false, depth: false }); | ||
gl = canvas.getContext('experimental-webgl', { | ||
alpha: false, | ||
depth: false | ||
}); | ||
} | ||
if (gl && gl.getError() == 1286) { | ||
handleWebGLError1286(); | ||
} | ||
} | ||
// If there is no WebGL, fall back to CSS 3D transform renderer. | ||
} // If there is no WebGL, fall back to CSS 3D transform renderer. | ||
// This will discard the image loaded so far and load the fallback image. | ||
@@ -183,2 +194,4 @@ // While browser specific tests are usually frowned upon, the | ||
// (it doesn't work properly in Firefox). | ||
if (!gl && (imageType == 'multires' && image.hasOwnProperty('fallbackPath') || imageType == 'cubemap') && ('WebkitAppearance' in document.documentElement.style || navigator.userAgent.match(/Trident.*rv[ :]*11\./) || navigator.appVersion.indexOf('MSIE 10') !== -1)) { | ||
@@ -188,10 +201,10 @@ // Remove old world if it exists | ||
container.removeChild(world); | ||
} | ||
} // Initialize renderer | ||
// Initialize renderer | ||
world = document.createElement('div'); | ||
world.className = 'pnlm-world'; | ||
world.className = 'pnlm-world'; // Add images | ||
// Add images | ||
var path; | ||
if (image.basePath) { | ||
@@ -202,4 +215,6 @@ path = image.basePath + image.fallbackPath; | ||
} | ||
var sides = ['f', 'r', 'b', 'l', 'u', 'd']; | ||
var loaded = 0; | ||
var onLoad = function onLoad() { | ||
@@ -217,7 +232,7 @@ // Draw image on canvas | ||
var imgData = faceContext.getImageData(0, 0, faceCanvas.width, faceCanvas.height); | ||
var data = imgData.data; | ||
var data = imgData.data; // Duplicate edge pixels | ||
// Duplicate edge pixels | ||
var i; | ||
var j; | ||
for (i = 2; i < faceCanvas.width - 2; i++) { | ||
@@ -229,2 +244,3 @@ for (j = 0; j < 4; j++) { | ||
} | ||
for (i = 2; i < faceCanvas.height - 2; i++) { | ||
@@ -236,2 +252,3 @@ for (j = 0; j < 4; j++) { | ||
} | ||
for (j = 0; j < 4; j++) { | ||
@@ -243,2 +260,3 @@ data[(faceCanvas.width + 1) * 4 + j] = data[(faceCanvas.width * 2 + 2) * 4 + j]; | ||
} | ||
for (i = 1; i < faceCanvas.width - 1; i++) { | ||
@@ -250,2 +268,3 @@ for (j = 0; j < 4; j++) { | ||
} | ||
for (i = 1; i < faceCanvas.height - 1; i++) { | ||
@@ -257,2 +276,3 @@ for (j = 0; j < 4; j++) { | ||
} | ||
for (j = 0; j < 4; j++) { | ||
@@ -263,9 +283,9 @@ data[j] = data[(faceCanvas.width + 1) * 4 + j]; | ||
data[(faceCanvas.width * faceCanvas.height - 1) * 4 + j] = data[(faceCanvas.width * (faceCanvas.height - 1) - 2) * 4 + j]; | ||
} | ||
} // Draw image width duplicated edge pixels on canvas | ||
// Draw image width duplicated edge pixels on canvas | ||
faceContext.putImageData(imgData, 0, 0); | ||
incLoaded.call(this); | ||
}; | ||
var incLoaded = function incLoaded() { | ||
@@ -276,2 +296,3 @@ if (this.width > 0) { | ||
} | ||
if (fallbackImgSize != this.width) { | ||
@@ -283,3 +304,5 @@ console.log('Fallback faces have inconsistent widths: ' + fallbackImgSize + ' vs. ' + this.width); | ||
} | ||
loaded++; | ||
if (loaded == 6) { | ||
@@ -291,3 +314,5 @@ fallbackImgSize = this.width; | ||
}; | ||
faceMissing = false; | ||
for (s = 0; s < 6; s++) { | ||
@@ -299,2 +324,3 @@ var faceImg = new Image(); | ||
faceImg.onerror = incLoaded; // ignore missing face to support partial fallback image | ||
if (imageType == 'multires') { | ||
@@ -306,2 +332,3 @@ faceImg.src = encodeURI(path.replace('%s', sides[s]) + '.' + image.extension); | ||
} | ||
fillMissingFaces(fallbackImgSize); | ||
@@ -311,7 +338,11 @@ return; | ||
console.log('Error: no WebGL support detected!'); | ||
throw { type: 'no webgl' }; | ||
throw { | ||
type: 'no webgl' | ||
}; | ||
} | ||
if (imageType == 'cubemap') { | ||
fillMissingFaces(cubeImgWidth); | ||
} | ||
if (image.basePath) { | ||
@@ -322,14 +353,16 @@ image.fullpath = image.basePath + image.path; | ||
} | ||
image.invTileResolution = 1 / image.tileResolution; | ||
var vertices = createCube(); | ||
vtmps = []; | ||
for (s = 0; s < 6; s++) { | ||
vtmps[s] = vertices.slice(s * 12, s * 12 + 12); | ||
vertices = createCube(); | ||
} | ||
} // Make sure image isn't too big | ||
// Make sure image isn't too big | ||
var width = 0, | ||
maxWidth = 0; | ||
if (imageType == 'equirectangular') { | ||
@@ -342,30 +375,35 @@ width = Math.max(image.width, image.height); | ||
} | ||
if (width > maxWidth) { | ||
console.log('Error: The image is too big; it\'s ' + width + 'px wide, ' + 'but this device\'s maximum supported size is ' + maxWidth + 'px.'); | ||
throw { type: 'webgl size error', width: width, maxWidth: maxWidth }; | ||
} | ||
throw { | ||
type: 'webgl size error', | ||
width: width, | ||
maxWidth: maxWidth | ||
}; | ||
} // Store horizon pitch and roll if applicable | ||
// Store horizon pitch and roll if applicable | ||
if (params !== undefined && (params.horizonPitch !== undefined || params.horizonRoll !== undefined)) { | ||
pose = [params.horizonPitch == undefined ? 0 : params.horizonPitch, params.horizonRoll == undefined ? 0 : params.horizonRoll]; | ||
} | ||
} // Set 2d texture binding | ||
// Set 2d texture binding | ||
var glBindType = gl.TEXTURE_2D; | ||
// Create viewport for entire canvas | ||
gl.viewport(0, 0, gl.drawingBufferWidth, gl.drawingBufferHeight); | ||
var glBindType = gl.TEXTURE_2D; // Create viewport for entire canvas | ||
// Create vertex shader | ||
gl.viewport(0, 0, gl.drawingBufferWidth, gl.drawingBufferHeight); // Create vertex shader | ||
vs = gl.createShader(gl.VERTEX_SHADER); | ||
var vertexSrc = v; | ||
if (imageType == 'multires') { | ||
vertexSrc = vMulti; | ||
} | ||
gl.shaderSource(vs, vertexSrc); | ||
gl.compileShader(vs); | ||
gl.compileShader(vs); // Create fragment shader | ||
// Create fragment shader | ||
fs = gl.createShader(gl.FRAGMENT_SHADER); | ||
var fragmentSrc = fragEquirectangular; | ||
if (imageType == 'cubemap') { | ||
@@ -377,33 +415,31 @@ glBindType = gl.TEXTURE_CUBE_MAP; | ||
} | ||
gl.shaderSource(fs, fragmentSrc); | ||
gl.compileShader(fs); | ||
gl.compileShader(fs); // Link WebGL program | ||
// Link WebGL program | ||
program = gl.createProgram(); | ||
gl.attachShader(program, vs); | ||
gl.attachShader(program, fs); | ||
gl.linkProgram(program); | ||
gl.linkProgram(program); // Log errors | ||
// Log errors | ||
if (!gl.getShaderParameter(vs, gl.COMPILE_STATUS)) { | ||
console.log(gl.getShaderInfoLog(vs)); | ||
} | ||
if (!gl.getShaderParameter(fs, gl.COMPILE_STATUS)) { | ||
console.log(gl.getShaderInfoLog(fs)); | ||
} | ||
if (!gl.getProgramParameter(program, gl.LINK_STATUS)) { | ||
console.log(gl.getProgramInfoLog(program)); | ||
} | ||
} // Use WebGL program | ||
// Use WebGL program | ||
gl.useProgram(program); | ||
program.drawInProgress = false; // Set background clear color (does not apply to cubemap/fallback image) | ||
program.drawInProgress = false; | ||
// Set background clear color (does not apply to cubemap/fallback image) | ||
var color = params.backgroundColor ? params.backgroundColor : [0, 0, 0]; | ||
gl.clearColor(color[0], color[1], color[2], 1.0); | ||
gl.clear(gl.COLOR_BUFFER_BIT); | ||
gl.clear(gl.COLOR_BUFFER_BIT); // Look up texture coordinates location | ||
// Look up texture coordinates location | ||
program.texCoordLocation = gl.getAttribLocation(program, 'a_texCoord'); | ||
@@ -417,11 +453,10 @@ gl.enableVertexAttribArray(program.texCoordLocation); | ||
} | ||
gl.bindBuffer(gl.ARRAY_BUFFER, texCoordBuffer); | ||
gl.bufferData(gl.ARRAY_BUFFER, new Float32Array([-1, 1, 1, 1, 1, -1, -1, 1, 1, -1, -1, -1]), gl.STATIC_DRAW); | ||
gl.vertexAttribPointer(program.texCoordLocation, 2, gl.FLOAT, false, 0, 0); | ||
gl.vertexAttribPointer(program.texCoordLocation, 2, gl.FLOAT, false, 0, 0); // Pass aspect ratio | ||
// Pass aspect ratio | ||
program.aspectRatio = gl.getUniformLocation(program, 'u_aspectRatio'); | ||
gl.uniform1f(program.aspectRatio, gl.drawingBufferWidth / gl.drawingBufferHeight); | ||
gl.uniform1f(program.aspectRatio, gl.drawingBufferWidth / gl.drawingBufferHeight); // Locate psi, theta, focal length, horizontal extent, vertical extent, and vertical offset | ||
// Locate psi, theta, focal length, horizontal extent, vertical extent, and vertical offset | ||
program.psi = gl.getUniformLocation(program, 'u_psi'); | ||
@@ -433,20 +468,17 @@ program.theta = gl.getUniformLocation(program, 'u_theta'); | ||
program.vo = gl.getUniformLocation(program, 'u_vo'); | ||
program.rot = gl.getUniformLocation(program, 'u_rot'); | ||
program.rot = gl.getUniformLocation(program, 'u_rot'); // Pass horizontal extent, vertical extent, and vertical offset | ||
// Pass horizontal extent, vertical extent, and vertical offset | ||
gl.uniform1f(program.h, haov / (Math.PI * 2.0)); | ||
gl.uniform1f(program.v, vaov / Math.PI); | ||
gl.uniform1f(program.vo, voffset / Math.PI * 2); | ||
gl.uniform1f(program.vo, voffset / Math.PI * 2); // Set background color | ||
// Set background color | ||
if (imageType == 'equirectangular') { | ||
program.backgroundColor = gl.getUniformLocation(program, 'u_backgroundColor'); | ||
gl.uniform4fv(program.backgroundColor, color.concat([1])); | ||
} | ||
} // Create texture | ||
// Create texture | ||
program.texture = gl.createTexture(); | ||
gl.bindTexture(glBindType, program.texture); | ||
gl.bindTexture(glBindType, program.texture); // Upload images to texture depending on type | ||
// Upload images to texture depending on type | ||
if (imageType == 'cubemap') { | ||
@@ -463,5 +495,5 @@ // Load all six sides of the cube map | ||
gl.texImage2D(glBindType, 0, gl.RGB, gl.RGB, gl.UNSIGNED_BYTE, image); | ||
} | ||
} // Set parameters for rendering any size | ||
// Set parameters for rendering any size | ||
gl.texParameteri(glBindType, gl.TEXTURE_WRAP_S, gl.CLAMP_TO_EDGE); | ||
@@ -474,40 +506,40 @@ gl.texParameteri(glBindType, gl.TEXTURE_WRAP_T, gl.CLAMP_TO_EDGE); | ||
program.vertPosLocation = gl.getAttribLocation(program, 'a_vertCoord'); | ||
gl.enableVertexAttribArray(program.vertPosLocation); | ||
gl.enableVertexAttribArray(program.vertPosLocation); // Create buffers | ||
// Create buffers | ||
if (!cubeVertBuf) { | ||
cubeVertBuf = gl.createBuffer(); | ||
} | ||
if (!cubeVertTexCoordBuf) { | ||
cubeVertTexCoordBuf = gl.createBuffer(); | ||
} | ||
if (!cubeVertIndBuf) { | ||
cubeVertIndBuf = gl.createBuffer(); | ||
} | ||
} // Bind texture coordinate buffer and pass coordinates to WebGL | ||
// Bind texture coordinate buffer and pass coordinates to WebGL | ||
gl.bindBuffer(gl.ARRAY_BUFFER, cubeVertTexCoordBuf); | ||
gl.bufferData(gl.ARRAY_BUFFER, new Float32Array([0, 0, 1, 0, 1, 1, 0, 1]), gl.STATIC_DRAW); | ||
gl.bufferData(gl.ARRAY_BUFFER, new Float32Array([0, 0, 1, 0, 1, 1, 0, 1]), gl.STATIC_DRAW); // Bind square index buffer and pass indicies to WebGL | ||
// Bind square index buffer and pass indicies to WebGL | ||
gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, cubeVertIndBuf); | ||
gl.bufferData(gl.ELEMENT_ARRAY_BUFFER, new Uint16Array([0, 1, 2, 0, 2, 3]), gl.STATIC_DRAW); | ||
gl.bufferData(gl.ELEMENT_ARRAY_BUFFER, new Uint16Array([0, 1, 2, 0, 2, 3]), gl.STATIC_DRAW); // Find uniforms | ||
// Find uniforms | ||
program.perspUniform = gl.getUniformLocation(program, 'u_perspMatrix'); | ||
program.cubeUniform = gl.getUniformLocation(program, 'u_cubeMatrix'); | ||
//program.colorUniform = gl.getUniformLocation(program, 'u_color'); | ||
program.cubeUniform = gl.getUniformLocation(program, 'u_cubeMatrix'); //program.colorUniform = gl.getUniformLocation(program, 'u_color'); | ||
program.level = -1; | ||
program.currentNodes = []; | ||
program.nodeCache = []; | ||
program.nodeCacheTimestamp = 0; | ||
} | ||
} // Check if there was an error | ||
// Check if there was an error | ||
var err = gl.getError(); | ||
if (err !== 0) { | ||
console.log('Error: Something went wrong with WebGL!', err); | ||
throw { type: 'webgl error' }; | ||
throw { | ||
type: 'webgl error' | ||
}; | ||
} | ||
@@ -517,3 +549,2 @@ | ||
}; | ||
/** | ||
@@ -524,2 +555,4 @@ * Destroy renderer. | ||
*/ | ||
this.destroy = function () { | ||
@@ -530,2 +563,3 @@ if (container !== undefined) { | ||
} | ||
if (world !== undefined && container.contains(world)) { | ||
@@ -535,2 +569,3 @@ container.removeChild(world); | ||
} | ||
if (gl) { | ||
@@ -540,2 +575,3 @@ // The spec says this is only supposed to simulate losing the WebGL | ||
var extension = gl.getExtension('WEBGL_lose_context'); | ||
if (extension) { | ||
@@ -546,3 +582,2 @@ extension.loseContext(); | ||
}; | ||
/** | ||
@@ -553,2 +588,4 @@ * Resize renderer (call after resizing container). | ||
*/ | ||
this.resize = function () { | ||
@@ -558,2 +595,3 @@ var pixelRatio = window.devicePixelRatio || 1; | ||
canvas.height = canvas.clientHeight * pixelRatio; | ||
if (gl) { | ||
@@ -563,3 +601,5 @@ if (gl.getError() == 1286) { | ||
} | ||
gl.viewport(0, 0, gl.drawingBufferWidth, gl.drawingBufferHeight); | ||
if (imageType != 'multires') { | ||
@@ -569,6 +609,6 @@ gl.uniform1f(program.aspectRatio, canvas.clientWidth / canvas.clientHeight); | ||
} | ||
}; | ||
// Initialize canvas size | ||
}; // Initialize canvas size | ||
this.resize(); | ||
/** | ||
@@ -579,6 +619,6 @@ * Set renderer horizon pitch and roll. | ||
*/ | ||
this.setPose = function (horizonPitch, horizonRoll) { | ||
pose = [horizonPitch, horizonRoll]; | ||
}; | ||
/** | ||
@@ -595,2 +635,4 @@ * Render new view of panorama. | ||
*/ | ||
this.render = function (pitch, yaw, hfov, params) { | ||
@@ -601,15 +643,16 @@ var focal, | ||
roll = 0; | ||
if (params === undefined) { | ||
params = {}; | ||
} | ||
if (params.roll) { | ||
roll = params.roll; | ||
} | ||
} // Apply pitch and roll transformation if applicable | ||
// Apply pitch and roll transformation if applicable | ||
if (pose !== undefined) { | ||
var horizonPitch = pose[0], | ||
horizonRoll = pose[1]; | ||
horizonRoll = pose[1]; // Calculate new pitch and yaw | ||
// Calculate new pitch and yaw | ||
var orig_pitch = pitch, | ||
@@ -621,19 +664,19 @@ orig_yaw = yaw, | ||
pitch = Math.asin(Math.max(Math.min(z, 1), -1)); | ||
yaw = Math.atan2(y, x); | ||
yaw = Math.atan2(y, x); // Calculate roll | ||
// Calculate roll | ||
var v = [Math.cos(orig_pitch) * (Math.sin(horizonRoll) * Math.sin(horizonPitch) * Math.cos(orig_yaw) - Math.cos(horizonPitch) * Math.sin(orig_yaw)), Math.cos(orig_pitch) * Math.cos(horizonRoll) * Math.cos(orig_yaw), Math.cos(orig_pitch) * (Math.cos(horizonPitch) * Math.sin(horizonRoll) * Math.cos(orig_yaw) + Math.sin(orig_yaw) * Math.sin(horizonPitch))], | ||
w = [-Math.cos(pitch) * Math.sin(yaw), Math.cos(pitch) * Math.cos(yaw)]; | ||
var roll_adj = Math.acos(Math.max(Math.min((v[0] * w[0] + v[1] * w[1]) / (Math.sqrt(v[0] * v[0] + v[1] * v[1] + v[2] * v[2]) * Math.sqrt(w[0] * w[0] + w[1] * w[1])), 1), -1)); | ||
if (v[2] < 0) { | ||
roll_adj = 2 * Math.PI - roll_adj; | ||
} | ||
roll += roll_adj; | ||
} | ||
} // If no WebGL | ||
// If no WebGL | ||
if (!gl && (imageType == 'multires' || imageType == 'cubemap')) { | ||
// Determine face transforms | ||
s = fallbackImgSize / 2; | ||
var transforms = { | ||
@@ -649,14 +692,18 @@ f: 'translate3d(-' + (s + 2) + 'px, -' + (s + 2) + 'px, -' + s + 'px)', | ||
var zoom = focal * canvas.clientWidth / 2 + 'px'; | ||
var transform = 'perspective(' + zoom + ') translateZ(' + zoom + ') rotateX(' + pitch + 'rad) rotateY(' + yaw + 'rad) '; | ||
var transform = 'perspective(' + zoom + ') translateZ(' + zoom + ') rotateX(' + pitch + 'rad) rotateY(' + yaw + 'rad) '; // Apply face transforms | ||
// Apply face transforms | ||
var faces = Object.keys(transforms); | ||
for (i = 0; i < 6; i++) { | ||
var face = world.querySelector('.pnlm-' + faces[i] + 'face'); | ||
if (!face) { | ||
continue; | ||
} // ignore missing face to support partial cubemap/fallback image | ||
face.style.webkitTransform = transform + transforms[faces[i]]; | ||
face.style.transform = transform + transforms[faces[i]]; | ||
} | ||
return; | ||
@@ -668,5 +715,4 @@ } | ||
var vfov = 2 * Math.atan(Math.tan(hfov * 0.5) / (gl.drawingBufferWidth / gl.drawingBufferHeight)); | ||
focal = 1 / Math.tan(vfov * 0.5); | ||
focal = 1 / Math.tan(vfov * 0.5); // Pass psi, theta, roll, and focal length | ||
// Pass psi, theta, roll, and focal length | ||
gl.uniform1f(program.psi, yaw); | ||
@@ -683,14 +729,12 @@ gl.uniform1f(program.theta, pitch); | ||
} | ||
} | ||
} // Draw using current buffer | ||
// Draw using current buffer | ||
gl.drawArrays(gl.TRIANGLES, 0, 6); | ||
} else { | ||
// Create perspective matrix | ||
var perspMatrix = makePersp(hfov, gl.drawingBufferWidth / gl.drawingBufferHeight, 0.1, 100.0); | ||
var perspMatrix = makePersp(hfov, gl.drawingBufferWidth / gl.drawingBufferHeight, 0.1, 100.0); // Find correct zoom level | ||
// Find correct zoom level | ||
checkZoom(hfov); | ||
checkZoom(hfov); // Create rotation matrix | ||
// Create rotation matrix | ||
var matrix = identityMatrix3(); | ||
@@ -700,14 +744,14 @@ matrix = rotateMatrix(matrix, -roll, 'z'); | ||
matrix = rotateMatrix(matrix, yaw, 'y'); | ||
matrix = makeMatrix4(matrix); | ||
matrix = makeMatrix4(matrix); // Set matrix uniforms | ||
// Set matrix uniforms | ||
gl.uniformMatrix4fv(program.perspUniform, false, new Float32Array(transposeMatrix4(perspMatrix))); | ||
gl.uniformMatrix4fv(program.cubeUniform, false, new Float32Array(transposeMatrix4(matrix))); | ||
gl.uniformMatrix4fv(program.cubeUniform, false, new Float32Array(transposeMatrix4(matrix))); // Find current nodes | ||
// Find current nodes | ||
var rotPersp = rotatePersp(perspMatrix, matrix); | ||
program.nodeCache.sort(multiresNodeSort); | ||
if (program.nodeCache.length > 200 && program.nodeCache.length > program.currentNodes.length + 50) { | ||
// Remove older nodes from cache | ||
var removed = program.nodeCache.splice(200, program.nodeCache.length - 200); | ||
for (var i = 0; i < removed.length; i++) { | ||
@@ -718,5 +762,6 @@ // Explicitly delete textures | ||
} | ||
program.currentNodes = []; | ||
var sides = ['f', 'b', 'u', 'd', 'l', 'r']; | ||
var sides = ['f', 'b', 'u', 'd', 'l', 'r']; | ||
for (s = 0; s < 6; s++) { | ||
@@ -727,5 +772,4 @@ var ntmp = new MultiresNode(vtmps[s], sides[s], 1, 0, 0, image.fullpath); | ||
program.currentNodes.sort(multiresNodeRenderSort); | ||
program.currentNodes.sort(multiresNodeRenderSort); // Unqueue any pending requests for nodes that are no longer visible | ||
// Unqueue any pending requests for nodes that are no longer visible | ||
for (i = pendingTextureRequests.length - 1; i >= 0; i--) { | ||
@@ -736,20 +780,19 @@ if (program.currentNodes.indexOf(pendingTextureRequests[i].node) === -1) { | ||
} | ||
} | ||
} // Allow one request to be pending, so that we can create a texture buffer for that in advance of loading actually beginning | ||
// Allow one request to be pending, so that we can create a texture buffer for that in advance of loading actually beginning | ||
if (pendingTextureRequests.length === 0) { | ||
for (i = 0; i < program.currentNodes.length; i++) { | ||
var node = program.currentNodes[i]; | ||
if (!node.texture && !node.textureLoad) { | ||
node.textureLoad = true; | ||
setTimeout(processNextTile, 0, node); // Only process one tile per frame to improve responsiveness | ||
setTimeout(processNextTile, 0, node); | ||
// Only process one tile per frame to improve responsiveness | ||
break; | ||
} | ||
} | ||
} | ||
} // Draw tiles | ||
// Draw tiles | ||
multiresDraw(); | ||
@@ -762,3 +805,2 @@ } | ||
}; | ||
/** | ||
@@ -770,2 +812,4 @@ * Check if images are loading. | ||
*/ | ||
this.isLoading = function () { | ||
@@ -779,5 +823,5 @@ if (gl && imageType == 'multires') { | ||
} | ||
return false; | ||
}; | ||
/** | ||
@@ -789,6 +833,7 @@ * Retrieve renderer's canvas. | ||
*/ | ||
this.getCanvas = function () { | ||
return canvas; | ||
}; | ||
/** | ||
@@ -801,2 +846,4 @@ * Sorting method for multires nodes. | ||
*/ | ||
function multiresNodeSort(a, b) { | ||
@@ -807,10 +854,10 @@ // Base tiles are always first | ||
} | ||
if (b.level == 1 && a.level != 1) { | ||
return 1; | ||
} | ||
} // Higher timestamp first | ||
// Higher timestamp first | ||
return b.timestamp - a.timestamp; | ||
} | ||
/** | ||
@@ -823,2 +870,4 @@ * Sorting method for multires node rendering. | ||
*/ | ||
function multiresNodeRenderSort(a, b) { | ||
@@ -828,8 +877,7 @@ // Lower zoom levels first | ||
return a.level - b.level; | ||
} | ||
} // Lower distance from center first | ||
// Lower distance from center first | ||
return a.diff - b.diff; | ||
} | ||
/** | ||
@@ -839,2 +887,4 @@ * Draws multires nodes. | ||
*/ | ||
function multiresDraw() { | ||
@@ -844,2 +894,3 @@ if (!program.drawInProgress) { | ||
gl.clear(gl.COLOR_BUFFER_BIT); | ||
for (var i = 0; i < program.currentNodes.length; i++) { | ||
@@ -849,21 +900,19 @@ if (program.currentNodes[i].textureLoaded > 1) { | ||
//gl.uniform4f(program.colorUniform, color[0], color[1], color[2], 1.0); | ||
// Bind vertex buffer and pass vertices to WebGL | ||
gl.bindBuffer(gl.ARRAY_BUFFER, cubeVertBuf); | ||
gl.bufferData(gl.ARRAY_BUFFER, new Float32Array(program.currentNodes[i].vertices), gl.STATIC_DRAW); | ||
gl.vertexAttribPointer(program.vertPosLocation, 3, gl.FLOAT, false, 0, 0); | ||
gl.vertexAttribPointer(program.vertPosLocation, 3, gl.FLOAT, false, 0, 0); // Prep for texture | ||
// Prep for texture | ||
gl.bindBuffer(gl.ARRAY_BUFFER, cubeVertTexCoordBuf); | ||
gl.vertexAttribPointer(program.texCoordLocation, 2, gl.FLOAT, false, 0, 0); | ||
gl.vertexAttribPointer(program.texCoordLocation, 2, gl.FLOAT, false, 0, 0); // Bind texture and draw tile | ||
// Bind texture and draw tile | ||
gl.bindTexture(gl.TEXTURE_2D, program.currentNodes[i].texture); // Bind program.currentNodes[i].texture to TEXTURE0 | ||
gl.drawElements(gl.TRIANGLES, 6, gl.UNSIGNED_SHORT, 0); | ||
} | ||
} | ||
program.drawInProgress = false; | ||
} | ||
} | ||
/** | ||
@@ -880,2 +929,4 @@ * Creates new multires node. | ||
*/ | ||
function MultiresNode(vertices, side, level, x, y, path) { | ||
@@ -889,3 +940,2 @@ this.vertices = vertices; | ||
} | ||
/** | ||
@@ -901,2 +951,4 @@ * Test if multires node is visible. If it is, add it to current nodes, | ||
*/ | ||
function testMultiresNode(rotPersp, node, pitch, yaw, hfov) { | ||
@@ -915,6 +967,6 @@ if (checkSquareInView(rotPersp, node.vertices)) { | ||
ydiff = Math.abs(ydiff); | ||
node.diff = Math.acos(Math.sin(pitch) * Math.sin(theta) + Math.cos(pitch) * Math.cos(theta) * Math.cos(ydiff)); | ||
node.diff = Math.acos(Math.sin(pitch) * Math.sin(theta) + Math.cos(pitch) * Math.cos(theta) * Math.cos(ydiff)); // Add node to current nodes and load texture if needed | ||
// Add node to current nodes and load texture if needed | ||
var inCurrent = false; | ||
for (var k = 0; k < program.nodeCache.length; k++) { | ||
@@ -929,2 +981,3 @@ if (program.nodeCache[k].path == node.path) { | ||
} | ||
if (!inCurrent) { | ||
@@ -935,6 +988,6 @@ //node.color = [Math.random(), Math.random(), Math.random()]; | ||
program.nodeCache.push(node); | ||
} | ||
} // TODO: Test error | ||
// Create child nodes | ||
// TODO: Test error | ||
// Create child nodes | ||
if (node.level < program.level) { | ||
@@ -945,12 +998,17 @@ var cubeSize = image.cubeResolution * Math.pow(2, node.level - image.maxLevel); | ||
var lastTileSize = cubeSize * 2 % image.tileResolution; | ||
if (lastTileSize === 0) { | ||
lastTileSize = image.tileResolution; | ||
} | ||
if (doubleTileSize === 0) { | ||
doubleTileSize = image.tileResolution * 2; | ||
} | ||
var f = 0.5; | ||
if (node.x == numTiles || node.y == numTiles) { | ||
f = 1.0 - image.tileResolution / (image.tileResolution + lastTileSize); | ||
} | ||
var i = 1.0 - f; | ||
@@ -964,4 +1022,4 @@ var children = []; | ||
i2 = i, | ||
i3 = i; | ||
// Handle non-symmetric tiles | ||
i3 = i; // Handle non-symmetric tiles | ||
if (lastTileSize < image.tileResolution) { | ||
@@ -971,2 +1029,3 @@ if (node.x == numTiles && node.y != numTiles) { | ||
i2 = 0.5; | ||
if (node.side == 'd' || node.side == 'u') { | ||
@@ -979,2 +1038,3 @@ f3 = 0.5; | ||
i1 = 0.5; | ||
if (node.side == 'l' || node.side == 'r') { | ||
@@ -985,4 +1045,5 @@ f3 = 0.5; | ||
} | ||
} | ||
// Handle small tiles that have fewer than four children | ||
} // Handle small tiles that have fewer than four children | ||
if (doubleTileSize <= image.tileResolution) { | ||
@@ -992,2 +1053,3 @@ if (node.x == numTiles) { | ||
i1 = 1; | ||
if (node.side == 'l' || node.side == 'r') { | ||
@@ -998,5 +1060,7 @@ f3 = 0; | ||
} | ||
if (node.y == numTiles) { | ||
f2 = 0; | ||
i2 = 1; | ||
if (node.side == 'd' || node.side == 'u') { | ||
@@ -1012,2 +1076,3 @@ f3 = 0; | ||
children.push(ntmp); | ||
if (!(node.x == numTiles && doubleTileSize <= image.tileResolution)) { | ||
@@ -1018,2 +1083,3 @@ vtmp = [v[0] * f1 + v[3] * i1, v[1] * f + v[4] * i, v[2] * f3 + v[5] * i3, v[3], v[4], v[5], v[3] * f + v[6] * i, v[4] * f2 + v[7] * i2, v[5] * f3 + v[8] * i3, v[0] * f1 + v[6] * i1, v[1] * f2 + v[7] * i2, v[2] * f3 + v[8] * i3]; | ||
} | ||
if (!(node.x == numTiles && doubleTileSize <= image.tileResolution) && !(node.y == numTiles && doubleTileSize <= image.tileResolution)) { | ||
@@ -1024,2 +1090,3 @@ vtmp = [v[0] * f1 + v[6] * i1, v[1] * f2 + v[7] * i2, v[2] * f3 + v[8] * i3, v[3] * f + v[6] * i, v[4] * f2 + v[7] * i2, v[5] * f3 + v[8] * i3, v[6], v[7], v[8], v[9] * f1 + v[6] * i1, v[10] * f + v[7] * i, v[11] * f3 + v[8] * i3]; | ||
} | ||
if (!(node.y == numTiles && doubleTileSize <= image.tileResolution)) { | ||
@@ -1030,2 +1097,3 @@ vtmp = [v[0] * f + v[9] * i, v[1] * f2 + v[10] * i2, v[2] * f3 + v[11] * i3, v[0] * f1 + v[6] * i1, v[1] * f2 + v[7] * i2, v[2] * f3 + v[8] * i3, v[9] * f1 + v[6] * i1, v[10] * f + v[7] * i, v[11] * f3 + v[8] * i3, v[9], v[10], v[11]]; | ||
} | ||
for (var j = 0; j < children.length; j++) { | ||
@@ -1037,3 +1105,2 @@ testMultiresNode(rotPersp, children[j], pitch, yaw, hfov); | ||
} | ||
/** | ||
@@ -1044,2 +1111,4 @@ * Creates cube vertex array. | ||
*/ | ||
function createCube() { | ||
@@ -1054,3 +1123,2 @@ return [-1, 1, -1, 1, 1, -1, 1, -1, -1, -1, -1, -1, // Front face | ||
} | ||
/** | ||
@@ -1061,6 +1129,7 @@ * Creates 3x3 identity matrix. | ||
*/ | ||
function identityMatrix3() { | ||
return [1, 0, 0, 0, 1, 0, 0, 0, 1]; | ||
} | ||
/** | ||
@@ -1074,11 +1143,16 @@ * Rotates a 3x3 matrix. | ||
*/ | ||
function rotateMatrix(m, angle, axis) { | ||
var s = Math.sin(angle); | ||
var c = Math.cos(angle); | ||
if (axis == 'x') { | ||
return [m[0], c * m[1] + s * m[2], c * m[2] - s * m[1], m[3], c * m[4] + s * m[5], c * m[5] - s * m[4], m[6], c * m[7] + s * m[8], c * m[8] - s * m[7]]; | ||
} | ||
if (axis == 'y') { | ||
return [c * m[0] - s * m[2], m[1], c * m[2] + s * m[0], c * m[3] - s * m[5], m[4], c * m[5] + s * m[3], c * m[6] - s * m[8], m[7], c * m[8] + s * m[6]]; | ||
} | ||
if (axis == 'z') { | ||
@@ -1088,3 +1162,2 @@ return [c * m[0] + s * m[1], c * m[1] - s * m[0], m[2], c * m[3] + s * m[4], c * m[4] - s * m[3], m[5], c * m[6] + s * m[7], c * m[7] - s * m[6], m[8]]; | ||
} | ||
/** | ||
@@ -1096,6 +1169,7 @@ * Turns a 3x3 matrix into a 4x4 matrix. | ||
*/ | ||
function makeMatrix4(m) { | ||
return [m[0], m[1], m[2], 0, m[3], m[4], m[5], 0, m[6], m[7], m[8], 0, 0, 0, 0, 1]; | ||
} | ||
/** | ||
@@ -1107,6 +1181,7 @@ * Transposes a 4x4 matrix. | ||
*/ | ||
function transposeMatrix4(m) { | ||
return [m[0], m[4], m[8], m[12], m[1], m[5], m[9], m[13], m[2], m[6], m[10], m[14], m[3], m[7], m[11], m[15]]; | ||
} | ||
/** | ||
@@ -1121,2 +1196,4 @@ * Creates a perspective matrix. | ||
*/ | ||
function makePersp(hfov, aspect, znear, zfar) { | ||
@@ -1127,3 +1204,2 @@ var fovy = 2 * Math.atan(Math.tan(hfov / 2) * gl.drawingBufferHeight / gl.drawingBufferWidth); | ||
} | ||
/** | ||
@@ -1135,2 +1211,4 @@ * Processes a loaded texture image into a WebGL texture. | ||
*/ | ||
function processLoadedTexture(img, tex) { | ||
@@ -1146,7 +1224,7 @@ gl.bindTexture(gl.TEXTURE_2D, tex); | ||
var pendingTextureRequests = []; | ||
var pendingTextureRequests = []; // Based on http://blog.tojicode.com/2012/03/javascript-memory-optimization-and.html | ||
// Based on http://blog.tojicode.com/2012/03/javascript-memory-optimization-and.html | ||
var loadTexture = function () { | ||
var cacheTop = 4; // Maximum number of concurrents loads | ||
var textureImageCache = {}; | ||
@@ -1160,2 +1238,3 @@ var crossOrigin; | ||
this.image.crossOrigin = crossOrigin ? crossOrigin : 'anonymous'; | ||
var loadFn = function loadFn() { | ||
@@ -1169,8 +1248,12 @@ if (self.image.width > 0 && self.image.height > 0) { | ||
} | ||
releaseTextureImageLoader(self); | ||
}; | ||
this.image.addEventListener('load', loadFn); | ||
this.image.addEventListener('error', loadFn); // ignore missing tile file to support partial image, otherwise retry loop causes high CPU load | ||
}; | ||
} | ||
; | ||
TextureImageLoader.prototype.loadTexture = function (src, texture, callback) { | ||
@@ -1187,4 +1270,6 @@ this.texture = texture; | ||
this.callback = callback; | ||
}; | ||
} | ||
; | ||
function releaseTextureImageLoader(til) { | ||
@@ -1206,2 +1291,3 @@ if (pendingTextureRequests.length) { | ||
var texture = gl.createTexture(); | ||
if (cacheTop) { | ||
@@ -1212,6 +1298,6 @@ textureImageCache[--cacheTop].loadTexture(src, texture, callback); | ||
} | ||
return texture; | ||
}; | ||
}(); | ||
/** | ||
@@ -1222,2 +1308,4 @@ * Loads image and creates texture for a multires node / tile. | ||
*/ | ||
function processNextTile(node) { | ||
@@ -1229,3 +1317,2 @@ loadTexture(node, encodeURI(node.path + '.' + image.extension), function (texture, loaded) { | ||
} | ||
/** | ||
@@ -1236,13 +1323,15 @@ * Finds and applies optimal multires zoom level. | ||
*/ | ||
function checkZoom(hfov) { | ||
// Find optimal level | ||
var newLevel = 1; | ||
while (newLevel < image.maxLevel && gl.drawingBufferWidth > image.tileResolution * Math.pow(2, newLevel - 1) * Math.tan(hfov / 2) * 0.707) { | ||
newLevel++; | ||
} | ||
} // Apply change | ||
// Apply change | ||
program.level = newLevel; | ||
} | ||
/** | ||
@@ -1255,6 +1344,7 @@ * Rotates perspective matrix. | ||
*/ | ||
function rotatePersp(p, r) { | ||
return [p[0] * r[0], p[0] * r[1], p[0] * r[2], 0, p[5] * r[4], p[5] * r[5], p[5] * r[6], 0, p[10] * r[8], p[10] * r[9], p[10] * r[10], p[11], -r[8], -r[9], -r[10], 0]; | ||
} | ||
/** | ||
@@ -1268,6 +1358,7 @@ * Applies rotated perspective matrix to a 3-vector | ||
*/ | ||
function applyRotPerspToVec(m, v) { | ||
return [m[0] * v[0] + m[1] * v[1] + m[2] * v[2], m[4] * v[0] + m[5] * v[1] + m[6] * v[2], m[11] + m[8] * v[0] + m[9] * v[1] + m[10] * v[2], 1 / (m[12] * v[0] + m[13] * v[1] + m[14] * v[2])]; | ||
} | ||
/** | ||
@@ -1281,2 +1372,4 @@ * Checks if a vertex is visible. | ||
*/ | ||
function checkInView(m, v) { | ||
@@ -1292,17 +1385,21 @@ var vpp = applyRotPerspToVec(m, v); | ||
} | ||
if (winX > 1) { | ||
ret[0] = 1; | ||
} | ||
if (winY < -1) { | ||
ret[1] = -1; | ||
} | ||
if (winY > 1) { | ||
ret[1] = 1; | ||
} | ||
if (winZ < -1 || winZ > 1) { | ||
ret[2] = 1; | ||
} | ||
return ret; | ||
} | ||
/** | ||
@@ -1315,2 +1412,4 @@ * Checks if a square (tile) is visible. | ||
*/ | ||
function checkSquareInView(m, v) { | ||
@@ -1322,13 +1421,16 @@ var check1 = checkInView(m, v.slice(0, 3)); | ||
var testX = check1[0] + check2[0] + check3[0] + check4[0]; | ||
if (testX == -4 || testX == 4) { | ||
return false; | ||
} | ||
var testY = check1[1] + check2[1] + check3[1] + check4[1]; | ||
if (testY == -4 || testY == 4) { | ||
return false; | ||
} | ||
var testZ = check1[2] + check2[2] + check3[2] + check4[2]; | ||
return testZ != 4; | ||
} | ||
/** | ||
@@ -1340,2 +1442,4 @@ * On iOS (iPhone 5c, iOS 10.3), this WebGL error occurs when the canvas is | ||
*/ | ||
function handleWebGLError1286() { | ||
@@ -1346,61 +1450,32 @@ console.log('Reducing canvas size due to error 1286!'); | ||
} | ||
} | ||
} // Vertex shader for equirectangular and cube | ||
// Vertex shader for equirectangular and cube | ||
var v = ['attribute vec2 a_texCoord;', 'varying vec2 v_texCoord;', 'void main() {', | ||
// Set position | ||
'gl_Position = vec4(a_texCoord, 0.0, 1.0);', | ||
// Pass the coordinates to the fragment shader | ||
'v_texCoord = a_texCoord;', '}'].join(''); | ||
var v = ['attribute vec2 a_texCoord;', 'varying vec2 v_texCoord;', 'void main() {', // Set position | ||
'gl_Position = vec4(a_texCoord, 0.0, 1.0);', // Pass the coordinates to the fragment shader | ||
'v_texCoord = a_texCoord;', '}'].join(''); // Vertex shader for multires | ||
// Vertex shader for multires | ||
var vMulti = ['attribute vec3 a_vertCoord;', 'attribute vec2 a_texCoord;', 'uniform mat4 u_cubeMatrix;', 'uniform mat4 u_perspMatrix;', 'varying mediump vec2 v_texCoord;', 'void main(void) {', | ||
// Set position | ||
'gl_Position = u_perspMatrix * u_cubeMatrix * vec4(a_vertCoord, 1.0);', | ||
var vMulti = ['attribute vec3 a_vertCoord;', 'attribute vec2 a_texCoord;', 'uniform mat4 u_cubeMatrix;', 'uniform mat4 u_perspMatrix;', 'varying mediump vec2 v_texCoord;', 'void main(void) {', // Set position | ||
'gl_Position = u_perspMatrix * u_cubeMatrix * vec4(a_vertCoord, 1.0);', // Pass the coordinates to the fragment shader | ||
'v_texCoord = a_texCoord;', '}'].join(''); // Fragment shader | ||
// Pass the coordinates to the fragment shader | ||
'v_texCoord = a_texCoord;', '}'].join(''); | ||
var fragEquiCubeBase = ['precision mediump float;', 'uniform float u_aspectRatio;', 'uniform float u_psi;', 'uniform float u_theta;', 'uniform float u_f;', 'uniform float u_h;', 'uniform float u_v;', 'uniform float u_vo;', 'uniform float u_rot;', 'const float PI = 3.14159265358979323846264;', // Texture | ||
'uniform sampler2D u_image;', 'uniform samplerCube u_imageCube;', // Coordinates passed in from vertex shader | ||
'varying vec2 v_texCoord;', // Background color (display for partial panoramas) | ||
'uniform vec4 u_backgroundColor;', 'void main() {', // Map canvas/camera to sphere | ||
'float x = v_texCoord.x * u_aspectRatio;', 'float y = v_texCoord.y;', 'float sinrot = sin(u_rot);', 'float cosrot = cos(u_rot);', 'float rot_x = x * cosrot - y * sinrot;', 'float rot_y = x * sinrot + y * cosrot;', 'float sintheta = sin(u_theta);', 'float costheta = cos(u_theta);', 'float a = u_f * costheta - rot_y * sintheta;', 'float root = sqrt(rot_x * rot_x + a * a);', 'float lambda = atan(rot_x / root, a / root) + u_psi;', 'float phi = atan((rot_y * costheta + u_f * sintheta) / root);'].join('\n'); // Fragment shader | ||
// Fragment shader | ||
var fragEquiCubeBase = ['precision mediump float;', 'uniform float u_aspectRatio;', 'uniform float u_psi;', 'uniform float u_theta;', 'uniform float u_f;', 'uniform float u_h;', 'uniform float u_v;', 'uniform float u_vo;', 'uniform float u_rot;', 'const float PI = 3.14159265358979323846264;', | ||
var fragCube = fragEquiCubeBase + [// Look up color from texture | ||
'float cosphi = cos(phi);', 'gl_FragColor = textureCube(u_imageCube, vec3(cosphi*sin(lambda), sin(phi), cosphi*cos(lambda)));', '}'].join('\n'); // Fragment shader | ||
// Texture | ||
'uniform sampler2D u_image;', 'uniform samplerCube u_imageCube;', | ||
// Coordinates passed in from vertex shader | ||
'varying vec2 v_texCoord;', | ||
// Background color (display for partial panoramas) | ||
'uniform vec4 u_backgroundColor;', 'void main() {', | ||
// Map canvas/camera to sphere | ||
'float x = v_texCoord.x * u_aspectRatio;', 'float y = v_texCoord.y;', 'float sinrot = sin(u_rot);', 'float cosrot = cos(u_rot);', 'float rot_x = x * cosrot - y * sinrot;', 'float rot_y = x * sinrot + y * cosrot;', 'float sintheta = sin(u_theta);', 'float costheta = cos(u_theta);', 'float a = u_f * costheta - rot_y * sintheta;', 'float root = sqrt(rot_x * rot_x + a * a);', 'float lambda = atan(rot_x / root, a / root) + u_psi;', 'float phi = atan((rot_y * costheta + u_f * sintheta) / root);'].join('\n'); | ||
// Fragment shader | ||
var fragCube = fragEquiCubeBase + [ | ||
// Look up color from texture | ||
'float cosphi = cos(phi);', 'gl_FragColor = textureCube(u_imageCube, vec3(cosphi*sin(lambda), sin(phi), cosphi*cos(lambda)));', '}'].join('\n'); | ||
// Fragment shader | ||
var fragEquirectangular = fragEquiCubeBase + [ | ||
// Wrap image | ||
'lambda = mod(lambda + PI, PI * 2.0) - PI;', | ||
// Map texture to sphere | ||
'vec2 coord = vec2(lambda / PI, phi / (PI / 2.0));', | ||
// Look up color from texture | ||
var fragEquirectangular = fragEquiCubeBase + [// Wrap image | ||
'lambda = mod(lambda + PI, PI * 2.0) - PI;', // Map texture to sphere | ||
'vec2 coord = vec2(lambda / PI, phi / (PI / 2.0));', // Look up color from texture | ||
// Map from [-1,1] to [0,1] and flip y-axis | ||
'if(coord.x < -u_h || coord.x > u_h || coord.y < -u_v + u_vo || coord.y > u_v + u_vo)', 'gl_FragColor = u_backgroundColor;', 'else', 'gl_FragColor = texture2D(u_image, vec2((coord.x + u_h) / (u_h * 2.0), (-coord.y + u_v + u_vo) / (u_v * 2.0)));', '}'].join('\n'); | ||
'if(coord.x < -u_h || coord.x > u_h || coord.y < -u_v + u_vo || coord.y > u_v + u_vo)', 'gl_FragColor = u_backgroundColor;', 'else', 'gl_FragColor = texture2D(u_image, vec2((coord.x + u_h) / (u_h * 2.0), (-coord.y + u_v + u_vo) / (u_v * 2.0)));', '}'].join('\n'); // Fragment shader | ||
// Fragment shader | ||
var fragMulti = ['varying mediump vec2 v_texCoord;', 'uniform sampler2D u_sampler;', | ||
//'uniform mediump vec4 u_color;', | ||
'void main(void) {', | ||
// Look up color from texture | ||
'gl_FragColor = texture2D(u_sampler, v_texCoord);', | ||
// 'gl_FragColor = u_color;', | ||
var fragMulti = ['varying mediump vec2 v_texCoord;', 'uniform sampler2D u_sampler;', //'uniform mediump vec4 u_color;', | ||
'void main(void) {', // Look up color from texture | ||
'gl_FragColor = texture2D(u_sampler, v_texCoord);', // 'gl_FragColor = u_color;', | ||
'}'].join(''); | ||
return { | ||
@@ -1407,0 +1482,0 @@ renderer: function renderer(container, image, imagetype, dynamic) { |
@@ -5,12 +5,12 @@ /** | ||
*/ | ||
if (!window.requestAnimationFrame) { | ||
window.requestAnimationFrame = function () { | ||
return window.webkitRequestAnimationFrame || window.mozRequestAnimationFrame || window.oRequestAnimationFrame || window.msRequestAnimationFrame || function ( /* function FrameRequestCallback */callback, /* DOMElement Element */element) { | ||
window.setTimeout(callback, 1000 / 60); | ||
}; | ||
}(); | ||
window.requestAnimationFrame = function () { | ||
return window.webkitRequestAnimationFrame || window.mozRequestAnimationFrame || window.oRequestAnimationFrame || window.msRequestAnimationFrame || function ( | ||
/* function FrameRequestCallback */ | ||
callback, | ||
/* DOMElement Element */ | ||
element) { | ||
window.setTimeout(callback, 1000 / 60); | ||
}; | ||
}(); | ||
} |
@@ -9,42 +9,41 @@ /* | ||
(function (document, videojs, pannellum) { | ||
'use strict'; | ||
'use strict'; | ||
videojs.registerPlugin('pannellum', function (config) { | ||
// Create Pannellum instance | ||
var player = this; | ||
var container = player.el(); | ||
var vid = container.getElementsByTagName('video')[0], | ||
pnlmContainer = document.createElement('div'); | ||
config = config || {}; | ||
config.type = 'equirectangular'; | ||
config.dynamic = true; | ||
config.showZoomCtrl = false; | ||
config.showFullscreenCtrl = false; | ||
config.autoLoad = true; | ||
config.panorama = vid; | ||
pnlmContainer.style.visibility = 'hidden'; | ||
player.pnlmViewer = pannellum.viewer(pnlmContainer, config); | ||
container.insertBefore(pnlmContainer, container.firstChild); | ||
vid.style.display = 'none'; | ||
videojs.registerPlugin('pannellum', function (config) { | ||
// Create Pannellum instance | ||
var player = this; | ||
var container = player.el(); | ||
var vid = container.getElementsByTagName('video')[0], | ||
pnlmContainer = document.createElement('div'); | ||
config = config || {}; | ||
config.type = 'equirectangular'; | ||
config.dynamic = true; | ||
config.showZoomCtrl = false; | ||
config.showFullscreenCtrl = false; | ||
config.autoLoad = true; | ||
config.panorama = vid; | ||
pnlmContainer.style.visibility = 'hidden'; | ||
player.pnlmViewer = pannellum.viewer(pnlmContainer, config); | ||
container.insertBefore(pnlmContainer, container.firstChild); | ||
vid.style.display = 'none'; // Handle update settings | ||
// Handle update settings | ||
player.on('play', function () { | ||
if (vid.readyState > 1) player.pnlmViewer.setUpdate(true); | ||
}); | ||
player.on('canplay', function () { | ||
if (!player.paused()) player.pnlmViewer.setUpdate(true); | ||
}); | ||
player.on('pause', function () { | ||
player.pnlmViewer.setUpdate(false); | ||
}); | ||
player.on('loadeddata', function () { | ||
pnlmContainer.style.visibility = 'visible'; | ||
}); | ||
player.on('seeking', function () { | ||
if (player.paused()) player.pnlmViewer.setUpdate(true); | ||
}); | ||
player.on('seeked', function () { | ||
if (player.paused()) player.pnlmViewer.setUpdate(false); | ||
}); | ||
player.on('play', function () { | ||
if (vid.readyState > 1) player.pnlmViewer.setUpdate(true); | ||
}); | ||
player.on('canplay', function () { | ||
if (!player.paused()) player.pnlmViewer.setUpdate(true); | ||
}); | ||
player.on('pause', function () { | ||
player.pnlmViewer.setUpdate(false); | ||
}); | ||
player.on('loadeddata', function () { | ||
pnlmContainer.style.visibility = 'visible'; | ||
}); | ||
player.on('seeking', function () { | ||
if (player.paused()) player.pnlmViewer.setUpdate(true); | ||
}); | ||
player.on('seeked', function () { | ||
if (player.paused()) player.pnlmViewer.setUpdate(false); | ||
}); | ||
}); | ||
})(document, videojs, pannellum); |
"use strict"; | ||
exports.__esModule = true; | ||
exports["default"] = void 0; | ||
var _class, _temp; | ||
var _propTypes = _interopRequireDefault(require("prop-types")); | ||
var _propTypes = require("prop-types"); | ||
var _react = _interopRequireWildcard(require("react")); | ||
var _propTypes2 = _interopRequireDefault(_propTypes); | ||
var _react = require("react"); | ||
var _react2 = _interopRequireDefault(_react); | ||
require("../pannellum/css/pannellum.css"); | ||
@@ -25,24 +20,30 @@ | ||
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } | ||
function _getRequireWildcardCache(nodeInterop) { if (typeof WeakMap !== "function") return null; var cacheBabelInterop = new WeakMap(); var cacheNodeInterop = new WeakMap(); return (_getRequireWildcardCache = function _getRequireWildcardCache(nodeInterop) { return nodeInterop ? cacheNodeInterop : cacheBabelInterop; })(nodeInterop); } | ||
function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } } | ||
function _interopRequireWildcard(obj, nodeInterop) { if (!nodeInterop && obj && obj.__esModule) { return obj; } if (obj === null || typeof obj !== "object" && typeof obj !== "function") { return { "default": obj }; } var cache = _getRequireWildcardCache(nodeInterop); if (cache && cache.has(obj)) { return cache.get(obj); } var newObj = {}; var hasPropertyDescriptor = Object.defineProperty && Object.getOwnPropertyDescriptor; for (var key in obj) { if (key !== "default" && Object.prototype.hasOwnProperty.call(obj, key)) { var desc = hasPropertyDescriptor ? Object.getOwnPropertyDescriptor(obj, key) : null; if (desc && (desc.get || desc.set)) { Object.defineProperty(newObj, key, desc); } else { newObj[key] = obj[key]; } } } newObj["default"] = obj; if (cache) { cache.set(obj, newObj); } return newObj; } | ||
function _possibleConstructorReturn(self, call) { if (!self) { throw new ReferenceError("this hasn't been initialised - super() hasn't been called"); } return call && (typeof call === "object" || typeof call === "function") ? call : self; } | ||
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { "default": obj }; } | ||
function _inherits(subClass, superClass) { if (typeof superClass !== "function" && superClass !== null) { throw new TypeError("Super expression must either be null or a function, not " + typeof superClass); } subClass.prototype = Object.create(superClass && superClass.prototype, { constructor: { value: subClass, enumerable: false, writable: true, configurable: true } }); if (superClass) Object.setPrototypeOf ? Object.setPrototypeOf(subClass, superClass) : subClass.__proto__ = superClass; } | ||
function _assertThisInitialized(self) { if (self === void 0) { throw new ReferenceError("this hasn't been initialised - super() hasn't been called"); } return self; } | ||
var Pannellum = (_temp = _class = function (_PureComponent) { | ||
_inherits(Pannellum, _PureComponent); | ||
function _inheritsLoose(subClass, superClass) { subClass.prototype = Object.create(superClass.prototype); subClass.prototype.constructor = subClass; _setPrototypeOf(subClass, superClass); } | ||
function _setPrototypeOf(o, p) { _setPrototypeOf = Object.setPrototypeOf || function _setPrototypeOf(o, p) { o.__proto__ = p; return o; }; return _setPrototypeOf(o, p); } | ||
function _defineProperty(obj, key, value) { if (key in obj) { Object.defineProperty(obj, key, { value: value, enumerable: true, configurable: true, writable: true }); } else { obj[key] = value; } return obj; } | ||
var Pannellum = /*#__PURE__*/function (_PureComponent) { | ||
_inheritsLoose(Pannellum, _PureComponent); | ||
function Pannellum(props) { | ||
_classCallCheck(this, Pannellum); | ||
var _this; | ||
var _this = _possibleConstructorReturn(this, _PureComponent.call(this, props)); | ||
_this = _PureComponent.call(this, props) || this; | ||
_this.renderImage = function (state) { | ||
var children = _this.props.children; | ||
// make the array of sub components, even if its one, it become array of one | ||
_defineProperty(_assertThisInitialized(_this), "renderImage", function (state) { | ||
var children = _this.props.children; // make the array of sub components, even if its one, it become array of one | ||
var hotspots = [].concat(children); | ||
var hotspotArray = []; | ||
if (Array.isArray(hotspots)) { | ||
@@ -60,2 +61,3 @@ hotspots.map(function (hotspot) { | ||
}); | ||
case "custom": | ||
@@ -70,4 +72,7 @@ return hotspotArray.push({ | ||
clickHandlerFunc: hotspot.props.handleClick ? hotspot.props.handleClick : _this.handleClickHotspot, | ||
clickHandlerArgs: hotspot.props.handleClickArg ? hotspot.props.handleClickArg : { name: "test" } | ||
clickHandlerArgs: hotspot.props.handleClickArg ? hotspot.props.handleClickArg : { | ||
name: "test" | ||
} | ||
}); | ||
default: | ||
@@ -114,7 +119,5 @@ return []; | ||
}; | ||
Object.keys(jsonConfig).forEach(function (key) { | ||
return jsonConfig[key] === "" && delete jsonConfig[key]; | ||
}); | ||
// this.setState({ jsonConfig }); | ||
}); // this.setState({ jsonConfig }); | ||
@@ -124,24 +127,33 @@ if (state === "update") { | ||
} | ||
_this.panorama = pannellum.viewer(_this.props.id ? _this.props.id : _this.state.id, jsonConfig); | ||
_this.panorama.on("load", _this.props.onLoad); | ||
_this.panorama.on("scenechange", _this.props.onScenechange); | ||
_this.panorama.on("scenechangefadedone", _this.props.onScenechangefadedone); | ||
_this.panorama.on("error", _this.props.onError); | ||
_this.panorama.on("errorcleared", _this.props.onErrorcleared); | ||
_this.panorama.on("mousedown", _this.props.onMousedown); | ||
_this.panorama.on("mouseup", _this.props.onMouseup); | ||
_this.panorama.on("touchstart", _this.props.onTouchstart); | ||
_this.panorama.on("touchend", _this.props.onTouchend); | ||
}; | ||
}); | ||
_this.componentDidMount = function () { | ||
_defineProperty(_assertThisInitialized(_this), "componentDidMount", function () { | ||
_this.renderImage("mount"); | ||
}; | ||
}); | ||
_this.handleClickHotspot = function (e, args) { | ||
_defineProperty(_assertThisInitialized(_this), "handleClickHotspot", function (e, args) { | ||
console.log("hotspot clicked", args.name); | ||
}; | ||
}); | ||
_this.hotspotTooltip = function (hotSpotDiv, args) { | ||
_defineProperty(_assertThisInitialized(_this), "hotspotTooltip", function (hotSpotDiv, args) { | ||
hotSpotDiv.setAttribute("id", "textInfo"); | ||
@@ -159,11 +171,11 @@ var hDiv = document.createElement("div"); | ||
hDiv.appendChild(outDiv); | ||
}; | ||
}); | ||
_this.getViewer = function () { | ||
_defineProperty(_assertThisInitialized(_this), "getViewer", function () { | ||
return _this.panorama; | ||
}; | ||
}); | ||
_this.forceRender = function () { | ||
_defineProperty(_assertThisInitialized(_this), "forceRender", function () { | ||
_this.renderImage("update"); | ||
}; | ||
}); | ||
@@ -176,6 +188,9 @@ _this.state = { | ||
Pannellum.prototype.componentDidUpdate = function componentDidUpdate(prevProps, prevState, snapshot) { | ||
var _proto = Pannellum.prototype; | ||
_proto.componentDidUpdate = function componentDidUpdate(prevProps, prevState, snapshot) { | ||
if (prevProps.image !== this.props.image || prevProps.width !== this.props.width || prevProps.height !== this.props.height || prevProps.compass !== this.props.compass || prevProps.title !== this.props.title || prevProps.author !== this.props.author || prevProps.preview !== this.props.preview || prevProps.previewTitle !== this.props.previewTitle || prevProps.previewAuthor !== this.props.previewAuthor || prevProps.showZoomCtrl !== this.props.showZoomCtrl || prevProps.showFullscreenCtrl !== this.props.showFullscreenCtrl || prevProps.showControls !== this.props.showControls || prevProps.children.length !== this.props.children.length) { | ||
this.renderImage("update"); | ||
} | ||
if (prevProps.maxYaw !== this.props.maxYaw || prevProps.minYaw !== this.props.minYaw || prevProps.maxPitch !== this.props.maxPitch || prevProps.minPitch !== this.props.minPitch || prevProps.maxHfov !== this.props.maxHfov || prevProps.minHfov !== this.props.minHfov) { | ||
@@ -186,8 +201,11 @@ this.panorama.setYawBounds([this.props.minYaw, this.props.maxYaw]); | ||
} | ||
if (prevProps.yaw !== this.props.yaw) { | ||
this.panorama.setYaw(this.props.yaw); | ||
} | ||
if (prevProps.pitch !== this.props.pitch) { | ||
this.panorama.setPitch(this.props.pitch); | ||
} | ||
if (prevProps.hfov !== this.props.hfov) { | ||
@@ -198,9 +216,8 @@ this.panorama.setHfov(this.props.hfov); | ||
Pannellum.prototype.render = function render() { | ||
_proto.render = function render() { | ||
var _this2 = this; | ||
var _props = this.props, | ||
width = _props.width, | ||
height = _props.height; | ||
var _this$props = this.props, | ||
width = _this$props.width, | ||
height = _this$props.height; | ||
var divStyle = { | ||
@@ -210,3 +227,3 @@ width: width, | ||
}; | ||
return _react2.default.createElement("div", { | ||
return /*#__PURE__*/_react["default"].createElement("div", { | ||
id: this.props.id ? this.props.id : this.state.id, | ||
@@ -221,3 +238,5 @@ style: divStyle, | ||
return Pannellum; | ||
}(_react.PureComponent), _class.defaultProps = { | ||
}(_react.PureComponent); | ||
_defineProperty(Pannellum, "defaultProps", { | ||
children: [], | ||
@@ -266,58 +285,62 @@ width: "100%", | ||
onRender: null | ||
}, _temp); | ||
}); | ||
Pannellum.propTypes = process.env.NODE_ENV !== "production" ? { | ||
children: _propTypes2.default.oneOfType([_propTypes2.default.arrayOf(_propTypes2.default.node), _propTypes2.default.node]), | ||
id: _propTypes2.default.string, | ||
width: _propTypes2.default.string, | ||
height: _propTypes2.default.string, | ||
image: _propTypes2.default.string, | ||
haov: _propTypes2.default.number, | ||
vaov: _propTypes2.default.number, | ||
vOffset: _propTypes2.default.number, | ||
yaw: _propTypes2.default.number, | ||
pitch: _propTypes2.default.number, | ||
hfov: _propTypes2.default.number, | ||
minHfov: _propTypes2.default.number, | ||
maxHfov: _propTypes2.default.number, | ||
minPitch: _propTypes2.default.number, | ||
maxPitch: _propTypes2.default.number, | ||
minYaw: _propTypes2.default.number, | ||
maxYaw: _propTypes2.default.number, | ||
autoRotate: _propTypes2.default.number, | ||
compass: _propTypes2.default.bool, | ||
preview: _propTypes2.default.string, | ||
previewTitle: _propTypes2.default.string, | ||
previewAuthor: _propTypes2.default.string, | ||
title: _propTypes2.default.string, | ||
author: _propTypes2.default.string, | ||
autoLoad: _propTypes2.default.bool, | ||
orientationOnByDefault: _propTypes2.default.bool, | ||
showZoomCtrl: _propTypes2.default.bool, | ||
keyboardZoom: _propTypes2.default.bool, | ||
mouseZoom: _propTypes2.default.bool, | ||
draggable: _propTypes2.default.bool, | ||
disableKeyboardCtrl: _propTypes2.default.bool, | ||
showFullscreenCtrl: _propTypes2.default.bool, | ||
showControls: _propTypes2.default.bool, | ||
onLoad: _propTypes2.default.func, | ||
onScenechange: _propTypes2.default.func, | ||
onScenechangefadedone: _propTypes2.default.func, | ||
onError: _propTypes2.default.func, | ||
onErrorcleared: _propTypes2.default.func, | ||
onMousedown: _propTypes2.default.func, | ||
onMouseup: _propTypes2.default.func, | ||
onTouchstart: _propTypes2.default.func, | ||
onTouchend: _propTypes2.default.func, | ||
hotspotDebug: _propTypes2.default.bool, | ||
tooltip: _propTypes2.default.func, | ||
tooltipArg: _propTypes2.default.object, | ||
handleClick: _propTypes2.default.func, | ||
handleClickArg: _propTypes2.default.object, | ||
cssClass: _propTypes2.default.string, | ||
onRender: _propTypes2.default.func | ||
children: _propTypes["default"].oneOfType([_propTypes["default"].arrayOf(_propTypes["default"].node), _propTypes["default"].node]), | ||
id: _propTypes["default"].string, | ||
width: _propTypes["default"].string, | ||
height: _propTypes["default"].string, | ||
image: _propTypes["default"].string, | ||
haov: _propTypes["default"].number, | ||
vaov: _propTypes["default"].number, | ||
vOffset: _propTypes["default"].number, | ||
yaw: _propTypes["default"].number, | ||
pitch: _propTypes["default"].number, | ||
hfov: _propTypes["default"].number, | ||
minHfov: _propTypes["default"].number, | ||
maxHfov: _propTypes["default"].number, | ||
minPitch: _propTypes["default"].number, | ||
maxPitch: _propTypes["default"].number, | ||
minYaw: _propTypes["default"].number, | ||
maxYaw: _propTypes["default"].number, | ||
autoRotate: _propTypes["default"].number, | ||
compass: _propTypes["default"].bool, | ||
preview: _propTypes["default"].string, | ||
previewTitle: _propTypes["default"].string, | ||
previewAuthor: _propTypes["default"].string, | ||
title: _propTypes["default"].string, | ||
author: _propTypes["default"].string, | ||
autoLoad: _propTypes["default"].bool, | ||
orientationOnByDefault: _propTypes["default"].bool, | ||
showZoomCtrl: _propTypes["default"].bool, | ||
keyboardZoom: _propTypes["default"].bool, | ||
mouseZoom: _propTypes["default"].bool, | ||
draggable: _propTypes["default"].bool, | ||
disableKeyboardCtrl: _propTypes["default"].bool, | ||
showFullscreenCtrl: _propTypes["default"].bool, | ||
showControls: _propTypes["default"].bool, | ||
onLoad: _propTypes["default"].func, | ||
onScenechange: _propTypes["default"].func, | ||
onScenechangefadedone: _propTypes["default"].func, | ||
onError: _propTypes["default"].func, | ||
onErrorcleared: _propTypes["default"].func, | ||
onMousedown: _propTypes["default"].func, | ||
onMouseup: _propTypes["default"].func, | ||
onTouchstart: _propTypes["default"].func, | ||
onTouchend: _propTypes["default"].func, | ||
hotspotDebug: _propTypes["default"].bool, | ||
tooltip: _propTypes["default"].func, | ||
tooltipArg: _propTypes["default"].object, | ||
handleClick: _propTypes["default"].func, | ||
handleClickArg: _propTypes["default"].object, | ||
cssClass: _propTypes["default"].string, | ||
onRender: _propTypes["default"].func | ||
} : {}; | ||
Pannellum.Hotspot = function () {}; | ||
Pannellum.Hotspot = function () {}; | ||
exports.default = Pannellum; | ||
module.exports = exports["default"]; | ||
var _default = Pannellum; | ||
exports["default"] = _default; | ||
module.exports = exports.default; |
@@ -1,59 +0,57 @@ | ||
'use strict'; | ||
"use strict"; | ||
exports.__esModule = true; | ||
exports["default"] = void 0; | ||
var _class, _temp; | ||
var _propTypes = _interopRequireDefault(require("prop-types")); | ||
var _propTypes = require('prop-types'); | ||
var _react = _interopRequireWildcard(require("react")); | ||
var _propTypes2 = _interopRequireDefault(_propTypes); | ||
var _video = _interopRequireDefault(require("video.js")); | ||
var _react = require('react'); | ||
require("../pannellum/css/video-js.css"); | ||
var _react2 = _interopRequireDefault(_react); | ||
require("../pannellum/css/pannellum.css"); | ||
var _video = require('video.js'); | ||
require("../pannellum/css/style-textInfo.css"); | ||
var _video2 = _interopRequireDefault(_video); | ||
require("../pannellum/js/libpannellum.js"); | ||
require('../pannellum/css/video-js.css'); | ||
require("../pannellum/js/RequestAnimationFrame"); | ||
require('../pannellum/css/pannellum.css'); | ||
require("../pannellum/js/pannellum.js"); | ||
require('../pannellum/css/style-textInfo.css'); | ||
require("../pannellum/js/videojs-pannellum-plugin"); | ||
require('../pannellum/js/libpannellum.js'); | ||
function _getRequireWildcardCache(nodeInterop) { if (typeof WeakMap !== "function") return null; var cacheBabelInterop = new WeakMap(); var cacheNodeInterop = new WeakMap(); return (_getRequireWildcardCache = function _getRequireWildcardCache(nodeInterop) { return nodeInterop ? cacheNodeInterop : cacheBabelInterop; })(nodeInterop); } | ||
require('../pannellum/js/RequestAnimationFrame'); | ||
function _interopRequireWildcard(obj, nodeInterop) { if (!nodeInterop && obj && obj.__esModule) { return obj; } if (obj === null || typeof obj !== "object" && typeof obj !== "function") { return { "default": obj }; } var cache = _getRequireWildcardCache(nodeInterop); if (cache && cache.has(obj)) { return cache.get(obj); } var newObj = {}; var hasPropertyDescriptor = Object.defineProperty && Object.getOwnPropertyDescriptor; for (var key in obj) { if (key !== "default" && Object.prototype.hasOwnProperty.call(obj, key)) { var desc = hasPropertyDescriptor ? Object.getOwnPropertyDescriptor(obj, key) : null; if (desc && (desc.get || desc.set)) { Object.defineProperty(newObj, key, desc); } else { newObj[key] = obj[key]; } } } newObj["default"] = obj; if (cache) { cache.set(obj, newObj); } return newObj; } | ||
require('../pannellum/js/pannellum.js'); | ||
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { "default": obj }; } | ||
require('../pannellum/js/videojs-pannellum-plugin'); | ||
function _assertThisInitialized(self) { if (self === void 0) { throw new ReferenceError("this hasn't been initialised - super() hasn't been called"); } return self; } | ||
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } | ||
function _inheritsLoose(subClass, superClass) { subClass.prototype = Object.create(superClass.prototype); subClass.prototype.constructor = subClass; _setPrototypeOf(subClass, superClass); } | ||
function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } } | ||
function _setPrototypeOf(o, p) { _setPrototypeOf = Object.setPrototypeOf || function _setPrototypeOf(o, p) { o.__proto__ = p; return o; }; return _setPrototypeOf(o, p); } | ||
function _possibleConstructorReturn(self, call) { if (!self) { throw new ReferenceError("this hasn't been initialised - super() hasn't been called"); } return call && (typeof call === "object" || typeof call === "function") ? call : self; } | ||
function _defineProperty(obj, key, value) { if (key in obj) { Object.defineProperty(obj, key, { value: value, enumerable: true, configurable: true, writable: true }); } else { obj[key] = value; } return obj; } | ||
function _inherits(subClass, superClass) { if (typeof superClass !== "function" && superClass !== null) { throw new TypeError("Super expression must either be null or a function, not " + typeof superClass); } subClass.prototype = Object.create(superClass && superClass.prototype, { constructor: { value: subClass, enumerable: false, writable: true, configurable: true } }); if (superClass) Object.setPrototypeOf ? Object.setPrototypeOf(subClass, superClass) : subClass.__proto__ = superClass; } | ||
var PannellumVideo = /*#__PURE__*/function (_Component) { | ||
_inheritsLoose(PannellumVideo, _Component); | ||
var PannellumVideo = (_temp = _class = function (_Component) { | ||
_inherits(PannellumVideo, _Component); | ||
function PannellumVideo(props) { | ||
_classCallCheck(this, PannellumVideo); | ||
var _this; | ||
var _this = _possibleConstructorReturn(this, _Component.call(this, props)); | ||
_this = _Component.call(this, props) || this; | ||
_this.renderVideo = function (state) { | ||
var children = _this.props.children; | ||
// make the array of sub components, even if its one, it become array of one | ||
_defineProperty(_assertThisInitialized(_this), "renderVideo", function (state) { | ||
var children = _this.props.children; // make the array of sub components, even if its one, it become array of one | ||
var hotspots = [].concat(children); | ||
var hotspotArray = []; | ||
if (Array.isArray(hotspots)) { | ||
hotspots.map(function (hotspot) { | ||
switch (hotspot.props.type) { | ||
case "info": | ||
@@ -68,2 +66,3 @@ return hotspotArray.push({ | ||
}); | ||
case "custom": | ||
@@ -78,4 +77,7 @@ return hotspotArray.push({ | ||
"clickHandlerFunc": hotspot.props.handleClick ? hotspot.props.handleClick : _this.handleClickHotspot, | ||
"clickHandlerArgs": hotspot.props.handleClickArg ? hotspot.props.handleClickArg : { name: "test" } | ||
"clickHandlerArgs": hotspot.props.handleClickArg ? hotspot.props.handleClickArg : { | ||
name: "test" | ||
} | ||
}); | ||
default: | ||
@@ -88,19 +90,22 @@ return []; | ||
if (state === "update") { | ||
_this.video = (0, _video["default"])(_this.videoNode); | ||
var cuurentHS = [].concat(_this.video.pnlmViewer.getConfig().hotSpots); | ||
_this.video = (0, _video2.default)(_this.videoNode); | ||
var cuurentHS = [].concat(_this.video.pnlmViewer.getConfig().hotSpots); | ||
_this.video.pnlmViewer.setYaw(_this.props.yaw); | ||
_this.video.pnlmViewer.setPitch(_this.props.pitch); | ||
_this.video.pnlmViewer.setHfov(_this.props.hfov); | ||
_this.video.pnlmViewer.setHfovBounds([_this.props.minHfov, _this.props.maxHfov]); | ||
//remove all hotspots | ||
_this.video.pnlmViewer.setHfovBounds([_this.props.minHfov, _this.props.maxHfov]); //remove all hotspots | ||
cuurentHS.map(function (hs) { | ||
return _this.video.pnlmViewer.removeHotSpot(hs.id); | ||
}); | ||
// Adding new hotspots | ||
}); // Adding new hotspots | ||
hotspotArray.map(function (hs) { | ||
return _this.video.pnlmViewer.addHotSpot(hs); | ||
}); | ||
// setting new video | ||
}); // setting new video | ||
_this.video.src({ | ||
@@ -110,5 +115,6 @@ type: 'video/mp4', | ||
}); | ||
return _this.video.play(); | ||
} else { | ||
_this.video = (0, _video2.default)(_this.videoNode, { | ||
_this.video = (0, _video["default"])(_this.videoNode, { | ||
loop: _this.props.loop, | ||
@@ -136,16 +142,21 @@ autoplay: _this.props.autoplay, | ||
}); | ||
_this.video.src({ type: 'video/mp4', src: _this.props.video }); | ||
_this.video.src({ | ||
type: 'video/mp4', | ||
src: _this.props.video | ||
}); | ||
_this.video.play(); | ||
} | ||
}; | ||
}); | ||
_this.componentDidMount = function () { | ||
_defineProperty(_assertThisInitialized(_this), "componentDidMount", function () { | ||
_this.renderVideo("mount"); | ||
}; | ||
}); | ||
_this.handleClickHotspot = function (e, args) { | ||
_defineProperty(_assertThisInitialized(_this), "handleClickHotspot", function (e, args) { | ||
console.log("hotspot clicked", args.name); | ||
}; | ||
}); | ||
_this.hotspotTooltip = function (hotSpotDiv, args) { | ||
_defineProperty(_assertThisInitialized(_this), "hotspotTooltip", function (hotSpotDiv, args) { | ||
hotSpotDiv.setAttribute("id", "textInfo"); | ||
@@ -163,7 +174,7 @@ var hDiv = document.createElement('div'); | ||
hDiv.appendChild(outDiv); | ||
}; | ||
}); | ||
_this.getViewer = function () { | ||
_defineProperty(_assertThisInitialized(_this), "getViewer", function () { | ||
return _this.video.pnlmViewer; | ||
}; | ||
}); | ||
@@ -176,3 +187,5 @@ _this.state = { | ||
PannellumVideo.prototype.componentDidUpdate = function componentDidUpdate(prevProps) { | ||
var _proto = PannellumVideo.prototype; | ||
_proto.componentDidUpdate = function componentDidUpdate(prevProps) { | ||
// videojs(this.videoNode).dispose(); | ||
@@ -183,14 +196,13 @@ // this.videoNode.setAttribute("src", this.props.video ); | ||
PannellumVideo.prototype.componentWillUnmount = function componentWillUnmount() { | ||
(0, _video2.default)(this.videoNode).dispose(); | ||
_proto.componentWillUnmount = function componentWillUnmount() { | ||
(0, _video["default"])(this.videoNode).dispose(); | ||
}; | ||
PannellumVideo.prototype.render = function render() { | ||
_proto.render = function render() { | ||
var _this2 = this; | ||
var _props = this.props, | ||
width = _props.width, | ||
height = _props.height, | ||
video = _props.video; | ||
var _this$props = this.props, | ||
width = _this$props.width, | ||
height = _this$props.height, | ||
video = _this$props.video; | ||
var divStyle = { | ||
@@ -200,20 +212,20 @@ width: width, | ||
}; | ||
return _react2.default.createElement( | ||
'div', | ||
{ 'data-vjs-player': true }, | ||
_react2.default.createElement('video', { | ||
id: this.props.id ? this.props.id : this.state.id, | ||
className: 'video-js vjs-default-skin vjs-big-play-centered', | ||
ref: function ref(node) { | ||
return _this2.videoNode = node; | ||
}, | ||
preload: 'none', | ||
crossOrigin: 'anonymous', | ||
style: divStyle | ||
}) | ||
); | ||
return /*#__PURE__*/_react["default"].createElement("div", { | ||
"data-vjs-player": true | ||
}, /*#__PURE__*/_react["default"].createElement("video", { | ||
id: this.props.id ? this.props.id : this.state.id, | ||
className: "video-js vjs-default-skin vjs-big-play-centered", | ||
ref: function ref(node) { | ||
return _this2.videoNode = node; | ||
}, | ||
preload: "none", | ||
crossOrigin: "anonymous", | ||
style: divStyle | ||
})); | ||
}; | ||
return PannellumVideo; | ||
}(_react.Component), _class.defaultProps = { | ||
}(_react.Component); | ||
_defineProperty(PannellumVideo, "defaultProps", { | ||
children: [], | ||
@@ -239,32 +251,34 @@ width: '100%', | ||
muted: true | ||
}, _temp); | ||
}); | ||
PannellumVideo.propTypes = process.env.NODE_ENV !== "production" ? { | ||
children: _propTypes2.default.oneOfType([_propTypes2.default.arrayOf(_propTypes2.default.node), _propTypes2.default.node]), | ||
id: _propTypes2.default.string, | ||
width: _propTypes2.default.string, | ||
height: _propTypes2.default.string, | ||
video: _propTypes2.default.string, | ||
yaw: _propTypes2.default.number, | ||
pitch: _propTypes2.default.number, | ||
hfov: _propTypes2.default.number, | ||
minHfov: _propTypes2.default.number, | ||
maxHfov: _propTypes2.default.number, | ||
minPitch: _propTypes2.default.number, | ||
maxPitch: _propTypes2.default.number, | ||
minYaw: _propTypes2.default.number, | ||
maxYaw: _propTypes2.default.number, | ||
hotspotDebug: _propTypes2.default.bool, | ||
autoRotate: _propTypes2.default.number, | ||
mouseZoom: _propTypes2.default.bool, | ||
loop: _propTypes2.default.bool, | ||
autoplay: _propTypes2.default.bool, | ||
controls: _propTypes2.default.bool, | ||
muted: _propTypes2.default.bool, | ||
tooltip: _propTypes2.default.func, | ||
tooltipArg: _propTypes2.default.object, | ||
handleClick: _propTypes2.default.func, | ||
handleClickArg: _propTypes2.default.object, | ||
cssClass: _propTypes2.default.string | ||
children: _propTypes["default"].oneOfType([_propTypes["default"].arrayOf(_propTypes["default"].node), _propTypes["default"].node]), | ||
id: _propTypes["default"].string, | ||
width: _propTypes["default"].string, | ||
height: _propTypes["default"].string, | ||
video: _propTypes["default"].string, | ||
yaw: _propTypes["default"].number, | ||
pitch: _propTypes["default"].number, | ||
hfov: _propTypes["default"].number, | ||
minHfov: _propTypes["default"].number, | ||
maxHfov: _propTypes["default"].number, | ||
minPitch: _propTypes["default"].number, | ||
maxPitch: _propTypes["default"].number, | ||
minYaw: _propTypes["default"].number, | ||
maxYaw: _propTypes["default"].number, | ||
hotspotDebug: _propTypes["default"].bool, | ||
autoRotate: _propTypes["default"].number, | ||
mouseZoom: _propTypes["default"].bool, | ||
loop: _propTypes["default"].bool, | ||
autoplay: _propTypes["default"].bool, | ||
controls: _propTypes["default"].bool, | ||
muted: _propTypes["default"].bool, | ||
tooltip: _propTypes["default"].func, | ||
tooltipArg: _propTypes["default"].object, | ||
handleClick: _propTypes["default"].func, | ||
handleClickArg: _propTypes["default"].object, | ||
cssClass: _propTypes["default"].string | ||
} : {}; | ||
exports.default = PannellumVideo; | ||
module.exports = exports['default']; | ||
var _default = PannellumVideo; | ||
exports["default"] = _default; | ||
module.exports = exports.default; |
"use strict"; | ||
exports.__esModule = true; | ||
exports.PannellumVideo = exports.Pannellum = undefined; | ||
var _Pannellum = require("./elements/Pannellum"); | ||
var _Pannellum = _interopRequireDefault(require("./elements/Pannellum")); | ||
var _Pannellum2 = _interopRequireDefault(_Pannellum); | ||
exports.Pannellum = _Pannellum["default"]; | ||
var _PannellumVideo = require("./elements/PannellumVideo"); | ||
var _PannellumVideo = _interopRequireDefault(require("./elements/PannellumVideo")); | ||
var _PannellumVideo2 = _interopRequireDefault(_PannellumVideo); | ||
exports.PannellumVideo = _PannellumVideo["default"]; | ||
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } | ||
exports.Pannellum = _Pannellum2.default; | ||
exports.PannellumVideo = _PannellumVideo2.default; | ||
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { "default": obj }; } |
@@ -1,2 +0,2 @@ | ||
'use strict'; | ||
"use strict"; | ||
@@ -25,5 +25,3 @@ /* | ||
*/ | ||
window.libpannellum = function (window, document, undefined) { | ||
/** | ||
@@ -38,3 +36,2 @@ * Creates a new panorama renderer. | ||
container.appendChild(canvas); | ||
var program, gl, vs, fs; | ||
@@ -48,3 +45,2 @@ var fallbackImgSize; | ||
var globalParams; | ||
/** | ||
@@ -68,2 +64,3 @@ * Initialize renderer. | ||
*/ | ||
this.init = function (_image, _imageType, _dynamic, haov, vaov, voffset, callback, params) { | ||
@@ -77,3 +74,5 @@ // Default argument for image type | ||
console.log('Error: invalid image type specified!'); | ||
throw { type: 'config error' }; | ||
throw { | ||
type: 'config error' | ||
}; | ||
} | ||
@@ -84,5 +83,4 @@ | ||
dynamic = _dynamic; | ||
globalParams = params || {}; | ||
globalParams = params || {}; // Clear old data | ||
// Clear old data | ||
if (program) { | ||
@@ -93,2 +91,3 @@ if (vs) { | ||
} | ||
if (fs) { | ||
@@ -98,7 +97,10 @@ gl.detachShader(program, fs); | ||
} | ||
gl.bindBuffer(gl.ARRAY_BUFFER, null); | ||
gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, null); | ||
if (program.texture) { | ||
gl.deleteTexture(program.texture); | ||
} | ||
if (program.nodeCache) { | ||
@@ -109,10 +111,12 @@ for (var i = 0; i < program.nodeCache.length; i++) { | ||
} | ||
gl.deleteProgram(program); | ||
program = undefined; | ||
} | ||
pose = undefined; | ||
var s; | ||
var faceMissing = false; | ||
var cubeImgWidth; | ||
if (imageType == 'cubemap') { | ||
@@ -124,2 +128,3 @@ for (s = 0; s < 6; s++) { | ||
} | ||
if (cubeImgWidth != image[s].width) { | ||
@@ -133,2 +138,3 @@ console.log('Cube faces have inconsistent widths: ' + cubeImgWidth + ' vs. ' + image[s].width); | ||
} | ||
function fillMissingFaces(imgSize) { | ||
@@ -138,2 +144,3 @@ if (faceMissing) { | ||
var nbytes = imgSize * imgSize * 4; // RGB, plus non-functional alpha | ||
var imageArray = new Uint8ClampedArray(nbytes); | ||
@@ -143,4 +150,4 @@ var rgb = params.backgroundColor ? params.backgroundColor : [0, 0, 0]; | ||
rgb[1] *= 255; | ||
rgb[2] *= 255; | ||
// Maybe filling could be done faster, see e.g. https://stackoverflow.com/questions/1295584/most-efficient-way-to-create-a-zero-filled-javascript-array | ||
rgb[2] *= 255; // Maybe filling could be done faster, see e.g. https://stackoverflow.com/questions/1295584/most-efficient-way-to-create-a-zero-filled-javascript-array | ||
for (var i = 0; i < nbytes; i++) { | ||
@@ -151,3 +158,5 @@ imageArray[i++] = rgb[0]; | ||
} | ||
var backgroundSquare = new ImageData(imageArray, imgSize, imgSize); | ||
for (s = 0; s < 6; s++) { | ||
@@ -159,5 +168,3 @@ if (image[s].width == 0) { | ||
} | ||
} | ||
// This awful browser specific test exists because iOS 8/9 and IE 11 | ||
} // This awful browser specific test exists because iOS 8/9 and IE 11 | ||
// don't display non-power-of-two cubemap textures but also don't | ||
@@ -169,13 +176,17 @@ // throw an error (tested on an iPhone 5c / iOS 8.1.3 / iOS 9.2 / | ||
// instead. | ||
if (!(imageType == 'cubemap' && (cubeImgWidth & cubeImgWidth - 1) !== 0 && (navigator.userAgent.toLowerCase().match(/(iphone|ipod|ipad).* os 8_/) || navigator.userAgent.toLowerCase().match(/(iphone|ipod|ipad).* os 9_/) || navigator.userAgent.toLowerCase().match(/(iphone|ipod|ipad).* os 10_/) || navigator.userAgent.match(/Trident.*rv[ :]*11\./)))) { | ||
// Enable WebGL on canvas | ||
if (!gl) { | ||
gl = canvas.getContext('experimental-webgl', { alpha: false, depth: false }); | ||
gl = canvas.getContext('experimental-webgl', { | ||
alpha: false, | ||
depth: false | ||
}); | ||
} | ||
if (gl && gl.getError() == 1286) { | ||
handleWebGLError1286(); | ||
} | ||
} | ||
// If there is no WebGL, fall back to CSS 3D transform renderer. | ||
} // If there is no WebGL, fall back to CSS 3D transform renderer. | ||
// This will discard the image loaded so far and load the fallback image. | ||
@@ -185,2 +196,4 @@ // While browser specific tests are usually frowned upon, the | ||
// (it doesn't work properly in Firefox). | ||
if (!gl && (imageType == 'multires' && image.hasOwnProperty('fallbackPath') || imageType == 'cubemap') && ('WebkitAppearance' in document.documentElement.style || navigator.userAgent.match(/Trident.*rv[ :]*11\./) || navigator.appVersion.indexOf('MSIE 10') !== -1)) { | ||
@@ -190,10 +203,10 @@ // Remove old world if it exists | ||
container.removeChild(world); | ||
} | ||
} // Initialize renderer | ||
// Initialize renderer | ||
world = document.createElement('div'); | ||
world.className = 'pnlm-world'; | ||
world.className = 'pnlm-world'; // Add images | ||
// Add images | ||
var path; | ||
if (image.basePath) { | ||
@@ -204,4 +217,6 @@ path = image.basePath + image.fallbackPath; | ||
} | ||
var sides = ['f', 'r', 'b', 'l', 'u', 'd']; | ||
var loaded = 0; | ||
var onLoad = function onLoad() { | ||
@@ -219,7 +234,7 @@ // Draw image on canvas | ||
var imgData = faceContext.getImageData(0, 0, faceCanvas.width, faceCanvas.height); | ||
var data = imgData.data; | ||
var data = imgData.data; // Duplicate edge pixels | ||
// Duplicate edge pixels | ||
var i; | ||
var j; | ||
for (i = 2; i < faceCanvas.width - 2; i++) { | ||
@@ -231,2 +246,3 @@ for (j = 0; j < 4; j++) { | ||
} | ||
for (i = 2; i < faceCanvas.height - 2; i++) { | ||
@@ -238,2 +254,3 @@ for (j = 0; j < 4; j++) { | ||
} | ||
for (j = 0; j < 4; j++) { | ||
@@ -245,2 +262,3 @@ data[(faceCanvas.width + 1) * 4 + j] = data[(faceCanvas.width * 2 + 2) * 4 + j]; | ||
} | ||
for (i = 1; i < faceCanvas.width - 1; i++) { | ||
@@ -252,2 +270,3 @@ for (j = 0; j < 4; j++) { | ||
} | ||
for (i = 1; i < faceCanvas.height - 1; i++) { | ||
@@ -259,2 +278,3 @@ for (j = 0; j < 4; j++) { | ||
} | ||
for (j = 0; j < 4; j++) { | ||
@@ -265,9 +285,9 @@ data[j] = data[(faceCanvas.width + 1) * 4 + j]; | ||
data[(faceCanvas.width * faceCanvas.height - 1) * 4 + j] = data[(faceCanvas.width * (faceCanvas.height - 1) - 2) * 4 + j]; | ||
} | ||
} // Draw image width duplicated edge pixels on canvas | ||
// Draw image width duplicated edge pixels on canvas | ||
faceContext.putImageData(imgData, 0, 0); | ||
incLoaded.call(this); | ||
}; | ||
var incLoaded = function incLoaded() { | ||
@@ -278,2 +298,3 @@ if (this.width > 0) { | ||
} | ||
if (fallbackImgSize != this.width) { | ||
@@ -285,3 +306,5 @@ console.log('Fallback faces have inconsistent widths: ' + fallbackImgSize + ' vs. ' + this.width); | ||
} | ||
loaded++; | ||
if (loaded == 6) { | ||
@@ -293,3 +316,5 @@ fallbackImgSize = this.width; | ||
}; | ||
faceMissing = false; | ||
for (s = 0; s < 6; s++) { | ||
@@ -301,2 +326,3 @@ var faceImg = new Image(); | ||
faceImg.onerror = incLoaded; // ignore missing face to support partial fallback image | ||
if (imageType == 'multires') { | ||
@@ -308,2 +334,3 @@ faceImg.src = encodeURI(path.replace('%s', sides[s]) + '.' + image.extension); | ||
} | ||
fillMissingFaces(fallbackImgSize); | ||
@@ -313,7 +340,11 @@ return; | ||
console.log('Error: no WebGL support detected!'); | ||
throw { type: 'no webgl' }; | ||
throw { | ||
type: 'no webgl' | ||
}; | ||
} | ||
if (imageType == 'cubemap') { | ||
fillMissingFaces(cubeImgWidth); | ||
} | ||
if (image.basePath) { | ||
@@ -324,14 +355,16 @@ image.fullpath = image.basePath + image.path; | ||
} | ||
image.invTileResolution = 1 / image.tileResolution; | ||
var vertices = createCube(); | ||
vtmps = []; | ||
for (s = 0; s < 6; s++) { | ||
vtmps[s] = vertices.slice(s * 12, s * 12 + 12); | ||
vertices = createCube(); | ||
} | ||
} // Make sure image isn't too big | ||
// Make sure image isn't too big | ||
var width = 0, | ||
maxWidth = 0; | ||
if (imageType == 'equirectangular') { | ||
@@ -344,30 +377,35 @@ width = Math.max(image.width, image.height); | ||
} | ||
if (width > maxWidth) { | ||
console.log('Error: The image is too big; it\'s ' + width + 'px wide, ' + 'but this device\'s maximum supported size is ' + maxWidth + 'px.'); | ||
throw { type: 'webgl size error', width: width, maxWidth: maxWidth }; | ||
} | ||
throw { | ||
type: 'webgl size error', | ||
width: width, | ||
maxWidth: maxWidth | ||
}; | ||
} // Store horizon pitch and roll if applicable | ||
// Store horizon pitch and roll if applicable | ||
if (params !== undefined && (params.horizonPitch !== undefined || params.horizonRoll !== undefined)) { | ||
pose = [params.horizonPitch == undefined ? 0 : params.horizonPitch, params.horizonRoll == undefined ? 0 : params.horizonRoll]; | ||
} | ||
} // Set 2d texture binding | ||
// Set 2d texture binding | ||
var glBindType = gl.TEXTURE_2D; | ||
// Create viewport for entire canvas | ||
gl.viewport(0, 0, gl.drawingBufferWidth, gl.drawingBufferHeight); | ||
var glBindType = gl.TEXTURE_2D; // Create viewport for entire canvas | ||
// Create vertex shader | ||
gl.viewport(0, 0, gl.drawingBufferWidth, gl.drawingBufferHeight); // Create vertex shader | ||
vs = gl.createShader(gl.VERTEX_SHADER); | ||
var vertexSrc = v; | ||
if (imageType == 'multires') { | ||
vertexSrc = vMulti; | ||
} | ||
gl.shaderSource(vs, vertexSrc); | ||
gl.compileShader(vs); | ||
gl.compileShader(vs); // Create fragment shader | ||
// Create fragment shader | ||
fs = gl.createShader(gl.FRAGMENT_SHADER); | ||
var fragmentSrc = fragEquirectangular; | ||
if (imageType == 'cubemap') { | ||
@@ -379,33 +417,31 @@ glBindType = gl.TEXTURE_CUBE_MAP; | ||
} | ||
gl.shaderSource(fs, fragmentSrc); | ||
gl.compileShader(fs); | ||
gl.compileShader(fs); // Link WebGL program | ||
// Link WebGL program | ||
program = gl.createProgram(); | ||
gl.attachShader(program, vs); | ||
gl.attachShader(program, fs); | ||
gl.linkProgram(program); | ||
gl.linkProgram(program); // Log errors | ||
// Log errors | ||
if (!gl.getShaderParameter(vs, gl.COMPILE_STATUS)) { | ||
console.log(gl.getShaderInfoLog(vs)); | ||
} | ||
if (!gl.getShaderParameter(fs, gl.COMPILE_STATUS)) { | ||
console.log(gl.getShaderInfoLog(fs)); | ||
} | ||
if (!gl.getProgramParameter(program, gl.LINK_STATUS)) { | ||
console.log(gl.getProgramInfoLog(program)); | ||
} | ||
} // Use WebGL program | ||
// Use WebGL program | ||
gl.useProgram(program); | ||
program.drawInProgress = false; // Set background clear color (does not apply to cubemap/fallback image) | ||
program.drawInProgress = false; | ||
// Set background clear color (does not apply to cubemap/fallback image) | ||
var color = params.backgroundColor ? params.backgroundColor : [0, 0, 0]; | ||
gl.clearColor(color[0], color[1], color[2], 1.0); | ||
gl.clear(gl.COLOR_BUFFER_BIT); | ||
gl.clear(gl.COLOR_BUFFER_BIT); // Look up texture coordinates location | ||
// Look up texture coordinates location | ||
program.texCoordLocation = gl.getAttribLocation(program, 'a_texCoord'); | ||
@@ -419,11 +455,10 @@ gl.enableVertexAttribArray(program.texCoordLocation); | ||
} | ||
gl.bindBuffer(gl.ARRAY_BUFFER, texCoordBuffer); | ||
gl.bufferData(gl.ARRAY_BUFFER, new Float32Array([-1, 1, 1, 1, 1, -1, -1, 1, 1, -1, -1, -1]), gl.STATIC_DRAW); | ||
gl.vertexAttribPointer(program.texCoordLocation, 2, gl.FLOAT, false, 0, 0); | ||
gl.vertexAttribPointer(program.texCoordLocation, 2, gl.FLOAT, false, 0, 0); // Pass aspect ratio | ||
// Pass aspect ratio | ||
program.aspectRatio = gl.getUniformLocation(program, 'u_aspectRatio'); | ||
gl.uniform1f(program.aspectRatio, gl.drawingBufferWidth / gl.drawingBufferHeight); | ||
gl.uniform1f(program.aspectRatio, gl.drawingBufferWidth / gl.drawingBufferHeight); // Locate psi, theta, focal length, horizontal extent, vertical extent, and vertical offset | ||
// Locate psi, theta, focal length, horizontal extent, vertical extent, and vertical offset | ||
program.psi = gl.getUniformLocation(program, 'u_psi'); | ||
@@ -435,20 +470,17 @@ program.theta = gl.getUniformLocation(program, 'u_theta'); | ||
program.vo = gl.getUniformLocation(program, 'u_vo'); | ||
program.rot = gl.getUniformLocation(program, 'u_rot'); | ||
program.rot = gl.getUniformLocation(program, 'u_rot'); // Pass horizontal extent, vertical extent, and vertical offset | ||
// Pass horizontal extent, vertical extent, and vertical offset | ||
gl.uniform1f(program.h, haov / (Math.PI * 2.0)); | ||
gl.uniform1f(program.v, vaov / Math.PI); | ||
gl.uniform1f(program.vo, voffset / Math.PI * 2); | ||
gl.uniform1f(program.vo, voffset / Math.PI * 2); // Set background color | ||
// Set background color | ||
if (imageType == 'equirectangular') { | ||
program.backgroundColor = gl.getUniformLocation(program, 'u_backgroundColor'); | ||
gl.uniform4fv(program.backgroundColor, color.concat([1])); | ||
} | ||
} // Create texture | ||
// Create texture | ||
program.texture = gl.createTexture(); | ||
gl.bindTexture(glBindType, program.texture); | ||
gl.bindTexture(glBindType, program.texture); // Upload images to texture depending on type | ||
// Upload images to texture depending on type | ||
if (imageType == 'cubemap') { | ||
@@ -465,5 +497,5 @@ // Load all six sides of the cube map | ||
gl.texImage2D(glBindType, 0, gl.RGB, gl.RGB, gl.UNSIGNED_BYTE, image); | ||
} | ||
} // Set parameters for rendering any size | ||
// Set parameters for rendering any size | ||
gl.texParameteri(glBindType, gl.TEXTURE_WRAP_S, gl.CLAMP_TO_EDGE); | ||
@@ -476,40 +508,40 @@ gl.texParameteri(glBindType, gl.TEXTURE_WRAP_T, gl.CLAMP_TO_EDGE); | ||
program.vertPosLocation = gl.getAttribLocation(program, 'a_vertCoord'); | ||
gl.enableVertexAttribArray(program.vertPosLocation); | ||
gl.enableVertexAttribArray(program.vertPosLocation); // Create buffers | ||
// Create buffers | ||
if (!cubeVertBuf) { | ||
cubeVertBuf = gl.createBuffer(); | ||
} | ||
if (!cubeVertTexCoordBuf) { | ||
cubeVertTexCoordBuf = gl.createBuffer(); | ||
} | ||
if (!cubeVertIndBuf) { | ||
cubeVertIndBuf = gl.createBuffer(); | ||
} | ||
} // Bind texture coordinate buffer and pass coordinates to WebGL | ||
// Bind texture coordinate buffer and pass coordinates to WebGL | ||
gl.bindBuffer(gl.ARRAY_BUFFER, cubeVertTexCoordBuf); | ||
gl.bufferData(gl.ARRAY_BUFFER, new Float32Array([0, 0, 1, 0, 1, 1, 0, 1]), gl.STATIC_DRAW); | ||
gl.bufferData(gl.ARRAY_BUFFER, new Float32Array([0, 0, 1, 0, 1, 1, 0, 1]), gl.STATIC_DRAW); // Bind square index buffer and pass indicies to WebGL | ||
// Bind square index buffer and pass indicies to WebGL | ||
gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, cubeVertIndBuf); | ||
gl.bufferData(gl.ELEMENT_ARRAY_BUFFER, new Uint16Array([0, 1, 2, 0, 2, 3]), gl.STATIC_DRAW); | ||
gl.bufferData(gl.ELEMENT_ARRAY_BUFFER, new Uint16Array([0, 1, 2, 0, 2, 3]), gl.STATIC_DRAW); // Find uniforms | ||
// Find uniforms | ||
program.perspUniform = gl.getUniformLocation(program, 'u_perspMatrix'); | ||
program.cubeUniform = gl.getUniformLocation(program, 'u_cubeMatrix'); | ||
//program.colorUniform = gl.getUniformLocation(program, 'u_color'); | ||
program.cubeUniform = gl.getUniformLocation(program, 'u_cubeMatrix'); //program.colorUniform = gl.getUniformLocation(program, 'u_color'); | ||
program.level = -1; | ||
program.currentNodes = []; | ||
program.nodeCache = []; | ||
program.nodeCacheTimestamp = 0; | ||
} | ||
} // Check if there was an error | ||
// Check if there was an error | ||
var err = gl.getError(); | ||
if (err !== 0) { | ||
console.log('Error: Something went wrong with WebGL!', err); | ||
throw { type: 'webgl error' }; | ||
throw { | ||
type: 'webgl error' | ||
}; | ||
} | ||
@@ -519,3 +551,2 @@ | ||
}; | ||
/** | ||
@@ -526,2 +557,4 @@ * Destroy renderer. | ||
*/ | ||
this.destroy = function () { | ||
@@ -532,2 +565,3 @@ if (container !== undefined) { | ||
} | ||
if (world !== undefined && container.contains(world)) { | ||
@@ -537,2 +571,3 @@ container.removeChild(world); | ||
} | ||
if (gl) { | ||
@@ -542,2 +577,3 @@ // The spec says this is only supposed to simulate losing the WebGL | ||
var extension = gl.getExtension('WEBGL_lose_context'); | ||
if (extension) { | ||
@@ -548,3 +584,2 @@ extension.loseContext(); | ||
}; | ||
/** | ||
@@ -555,2 +590,4 @@ * Resize renderer (call after resizing container). | ||
*/ | ||
this.resize = function () { | ||
@@ -560,2 +597,3 @@ var pixelRatio = window.devicePixelRatio || 1; | ||
canvas.height = canvas.clientHeight * pixelRatio; | ||
if (gl) { | ||
@@ -565,3 +603,5 @@ if (gl.getError() == 1286) { | ||
} | ||
gl.viewport(0, 0, gl.drawingBufferWidth, gl.drawingBufferHeight); | ||
if (imageType != 'multires') { | ||
@@ -571,6 +611,6 @@ gl.uniform1f(program.aspectRatio, canvas.clientWidth / canvas.clientHeight); | ||
} | ||
}; | ||
// Initialize canvas size | ||
}; // Initialize canvas size | ||
this.resize(); | ||
/** | ||
@@ -581,6 +621,6 @@ * Set renderer horizon pitch and roll. | ||
*/ | ||
this.setPose = function (horizonPitch, horizonRoll) { | ||
pose = [horizonPitch, horizonRoll]; | ||
}; | ||
/** | ||
@@ -597,2 +637,4 @@ * Render new view of panorama. | ||
*/ | ||
this.render = function (pitch, yaw, hfov, params) { | ||
@@ -603,15 +645,16 @@ var focal, | ||
roll = 0; | ||
if (params === undefined) { | ||
params = {}; | ||
} | ||
if (params.roll) { | ||
roll = params.roll; | ||
} | ||
} // Apply pitch and roll transformation if applicable | ||
// Apply pitch and roll transformation if applicable | ||
if (pose !== undefined) { | ||
var horizonPitch = pose[0], | ||
horizonRoll = pose[1]; | ||
horizonRoll = pose[1]; // Calculate new pitch and yaw | ||
// Calculate new pitch and yaw | ||
var orig_pitch = pitch, | ||
@@ -623,19 +666,19 @@ orig_yaw = yaw, | ||
pitch = Math.asin(Math.max(Math.min(z, 1), -1)); | ||
yaw = Math.atan2(y, x); | ||
yaw = Math.atan2(y, x); // Calculate roll | ||
// Calculate roll | ||
var v = [Math.cos(orig_pitch) * (Math.sin(horizonRoll) * Math.sin(horizonPitch) * Math.cos(orig_yaw) - Math.cos(horizonPitch) * Math.sin(orig_yaw)), Math.cos(orig_pitch) * Math.cos(horizonRoll) * Math.cos(orig_yaw), Math.cos(orig_pitch) * (Math.cos(horizonPitch) * Math.sin(horizonRoll) * Math.cos(orig_yaw) + Math.sin(orig_yaw) * Math.sin(horizonPitch))], | ||
w = [-Math.cos(pitch) * Math.sin(yaw), Math.cos(pitch) * Math.cos(yaw)]; | ||
var roll_adj = Math.acos(Math.max(Math.min((v[0] * w[0] + v[1] * w[1]) / (Math.sqrt(v[0] * v[0] + v[1] * v[1] + v[2] * v[2]) * Math.sqrt(w[0] * w[0] + w[1] * w[1])), 1), -1)); | ||
if (v[2] < 0) { | ||
roll_adj = 2 * Math.PI - roll_adj; | ||
} | ||
roll += roll_adj; | ||
} | ||
} // If no WebGL | ||
// If no WebGL | ||
if (!gl && (imageType == 'multires' || imageType == 'cubemap')) { | ||
// Determine face transforms | ||
s = fallbackImgSize / 2; | ||
var transforms = { | ||
@@ -651,14 +694,18 @@ f: 'translate3d(-' + (s + 2) + 'px, -' + (s + 2) + 'px, -' + s + 'px)', | ||
var zoom = focal * canvas.clientWidth / 2 + 'px'; | ||
var transform = 'perspective(' + zoom + ') translateZ(' + zoom + ') rotateX(' + pitch + 'rad) rotateY(' + yaw + 'rad) '; | ||
var transform = 'perspective(' + zoom + ') translateZ(' + zoom + ') rotateX(' + pitch + 'rad) rotateY(' + yaw + 'rad) '; // Apply face transforms | ||
// Apply face transforms | ||
var faces = Object.keys(transforms); | ||
for (i = 0; i < 6; i++) { | ||
var face = world.querySelector('.pnlm-' + faces[i] + 'face'); | ||
if (!face) { | ||
continue; | ||
} // ignore missing face to support partial cubemap/fallback image | ||
face.style.webkitTransform = transform + transforms[faces[i]]; | ||
face.style.transform = transform + transforms[faces[i]]; | ||
} | ||
return; | ||
@@ -670,5 +717,4 @@ } | ||
var vfov = 2 * Math.atan(Math.tan(hfov * 0.5) / (gl.drawingBufferWidth / gl.drawingBufferHeight)); | ||
focal = 1 / Math.tan(vfov * 0.5); | ||
focal = 1 / Math.tan(vfov * 0.5); // Pass psi, theta, roll, and focal length | ||
// Pass psi, theta, roll, and focal length | ||
gl.uniform1f(program.psi, yaw); | ||
@@ -685,14 +731,12 @@ gl.uniform1f(program.theta, pitch); | ||
} | ||
} | ||
} // Draw using current buffer | ||
// Draw using current buffer | ||
gl.drawArrays(gl.TRIANGLES, 0, 6); | ||
} else { | ||
// Create perspective matrix | ||
var perspMatrix = makePersp(hfov, gl.drawingBufferWidth / gl.drawingBufferHeight, 0.1, 100.0); | ||
var perspMatrix = makePersp(hfov, gl.drawingBufferWidth / gl.drawingBufferHeight, 0.1, 100.0); // Find correct zoom level | ||
// Find correct zoom level | ||
checkZoom(hfov); | ||
checkZoom(hfov); // Create rotation matrix | ||
// Create rotation matrix | ||
var matrix = identityMatrix3(); | ||
@@ -702,14 +746,14 @@ matrix = rotateMatrix(matrix, -roll, 'z'); | ||
matrix = rotateMatrix(matrix, yaw, 'y'); | ||
matrix = makeMatrix4(matrix); | ||
matrix = makeMatrix4(matrix); // Set matrix uniforms | ||
// Set matrix uniforms | ||
gl.uniformMatrix4fv(program.perspUniform, false, new Float32Array(transposeMatrix4(perspMatrix))); | ||
gl.uniformMatrix4fv(program.cubeUniform, false, new Float32Array(transposeMatrix4(matrix))); | ||
gl.uniformMatrix4fv(program.cubeUniform, false, new Float32Array(transposeMatrix4(matrix))); // Find current nodes | ||
// Find current nodes | ||
var rotPersp = rotatePersp(perspMatrix, matrix); | ||
program.nodeCache.sort(multiresNodeSort); | ||
if (program.nodeCache.length > 200 && program.nodeCache.length > program.currentNodes.length + 50) { | ||
// Remove older nodes from cache | ||
var removed = program.nodeCache.splice(200, program.nodeCache.length - 200); | ||
for (var i = 0; i < removed.length; i++) { | ||
@@ -720,5 +764,6 @@ // Explicitly delete textures | ||
} | ||
program.currentNodes = []; | ||
var sides = ['f', 'b', 'u', 'd', 'l', 'r']; | ||
var sides = ['f', 'b', 'u', 'd', 'l', 'r']; | ||
for (s = 0; s < 6; s++) { | ||
@@ -729,5 +774,4 @@ var ntmp = new MultiresNode(vtmps[s], sides[s], 1, 0, 0, image.fullpath); | ||
program.currentNodes.sort(multiresNodeRenderSort); | ||
program.currentNodes.sort(multiresNodeRenderSort); // Unqueue any pending requests for nodes that are no longer visible | ||
// Unqueue any pending requests for nodes that are no longer visible | ||
for (i = pendingTextureRequests.length - 1; i >= 0; i--) { | ||
@@ -738,20 +782,19 @@ if (program.currentNodes.indexOf(pendingTextureRequests[i].node) === -1) { | ||
} | ||
} | ||
} // Allow one request to be pending, so that we can create a texture buffer for that in advance of loading actually beginning | ||
// Allow one request to be pending, so that we can create a texture buffer for that in advance of loading actually beginning | ||
if (pendingTextureRequests.length === 0) { | ||
for (i = 0; i < program.currentNodes.length; i++) { | ||
var node = program.currentNodes[i]; | ||
if (!node.texture && !node.textureLoad) { | ||
node.textureLoad = true; | ||
setTimeout(processNextTile, 0, node); // Only process one tile per frame to improve responsiveness | ||
setTimeout(processNextTile, 0, node); | ||
// Only process one tile per frame to improve responsiveness | ||
break; | ||
} | ||
} | ||
} | ||
} // Draw tiles | ||
// Draw tiles | ||
multiresDraw(); | ||
@@ -764,3 +807,2 @@ } | ||
}; | ||
/** | ||
@@ -772,2 +814,4 @@ * Check if images are loading. | ||
*/ | ||
this.isLoading = function () { | ||
@@ -781,5 +825,5 @@ if (gl && imageType == 'multires') { | ||
} | ||
return false; | ||
}; | ||
/** | ||
@@ -791,6 +835,7 @@ * Retrieve renderer's canvas. | ||
*/ | ||
this.getCanvas = function () { | ||
return canvas; | ||
}; | ||
/** | ||
@@ -803,2 +848,4 @@ * Sorting method for multires nodes. | ||
*/ | ||
function multiresNodeSort(a, b) { | ||
@@ -809,10 +856,10 @@ // Base tiles are always first | ||
} | ||
if (b.level == 1 && a.level != 1) { | ||
return 1; | ||
} | ||
} // Higher timestamp first | ||
// Higher timestamp first | ||
return b.timestamp - a.timestamp; | ||
} | ||
/** | ||
@@ -825,2 +872,4 @@ * Sorting method for multires node rendering. | ||
*/ | ||
function multiresNodeRenderSort(a, b) { | ||
@@ -830,8 +879,7 @@ // Lower zoom levels first | ||
return a.level - b.level; | ||
} | ||
} // Lower distance from center first | ||
// Lower distance from center first | ||
return a.diff - b.diff; | ||
} | ||
/** | ||
@@ -841,2 +889,4 @@ * Draws multires nodes. | ||
*/ | ||
function multiresDraw() { | ||
@@ -846,2 +896,3 @@ if (!program.drawInProgress) { | ||
gl.clear(gl.COLOR_BUFFER_BIT); | ||
for (var i = 0; i < program.currentNodes.length; i++) { | ||
@@ -851,21 +902,19 @@ if (program.currentNodes[i].textureLoaded > 1) { | ||
//gl.uniform4f(program.colorUniform, color[0], color[1], color[2], 1.0); | ||
// Bind vertex buffer and pass vertices to WebGL | ||
gl.bindBuffer(gl.ARRAY_BUFFER, cubeVertBuf); | ||
gl.bufferData(gl.ARRAY_BUFFER, new Float32Array(program.currentNodes[i].vertices), gl.STATIC_DRAW); | ||
gl.vertexAttribPointer(program.vertPosLocation, 3, gl.FLOAT, false, 0, 0); | ||
gl.vertexAttribPointer(program.vertPosLocation, 3, gl.FLOAT, false, 0, 0); // Prep for texture | ||
// Prep for texture | ||
gl.bindBuffer(gl.ARRAY_BUFFER, cubeVertTexCoordBuf); | ||
gl.vertexAttribPointer(program.texCoordLocation, 2, gl.FLOAT, false, 0, 0); | ||
gl.vertexAttribPointer(program.texCoordLocation, 2, gl.FLOAT, false, 0, 0); // Bind texture and draw tile | ||
// Bind texture and draw tile | ||
gl.bindTexture(gl.TEXTURE_2D, program.currentNodes[i].texture); // Bind program.currentNodes[i].texture to TEXTURE0 | ||
gl.drawElements(gl.TRIANGLES, 6, gl.UNSIGNED_SHORT, 0); | ||
} | ||
} | ||
program.drawInProgress = false; | ||
} | ||
} | ||
/** | ||
@@ -882,2 +931,4 @@ * Creates new multires node. | ||
*/ | ||
function MultiresNode(vertices, side, level, x, y, path) { | ||
@@ -891,3 +942,2 @@ this.vertices = vertices; | ||
} | ||
/** | ||
@@ -903,2 +953,4 @@ * Test if multires node is visible. If it is, add it to current nodes, | ||
*/ | ||
function testMultiresNode(rotPersp, node, pitch, yaw, hfov) { | ||
@@ -917,6 +969,6 @@ if (checkSquareInView(rotPersp, node.vertices)) { | ||
ydiff = Math.abs(ydiff); | ||
node.diff = Math.acos(Math.sin(pitch) * Math.sin(theta) + Math.cos(pitch) * Math.cos(theta) * Math.cos(ydiff)); | ||
node.diff = Math.acos(Math.sin(pitch) * Math.sin(theta) + Math.cos(pitch) * Math.cos(theta) * Math.cos(ydiff)); // Add node to current nodes and load texture if needed | ||
// Add node to current nodes and load texture if needed | ||
var inCurrent = false; | ||
for (var k = 0; k < program.nodeCache.length; k++) { | ||
@@ -931,2 +983,3 @@ if (program.nodeCache[k].path == node.path) { | ||
} | ||
if (!inCurrent) { | ||
@@ -937,6 +990,6 @@ //node.color = [Math.random(), Math.random(), Math.random()]; | ||
program.nodeCache.push(node); | ||
} | ||
} // TODO: Test error | ||
// Create child nodes | ||
// TODO: Test error | ||
// Create child nodes | ||
if (node.level < program.level) { | ||
@@ -947,12 +1000,17 @@ var cubeSize = image.cubeResolution * Math.pow(2, node.level - image.maxLevel); | ||
var lastTileSize = cubeSize * 2 % image.tileResolution; | ||
if (lastTileSize === 0) { | ||
lastTileSize = image.tileResolution; | ||
} | ||
if (doubleTileSize === 0) { | ||
doubleTileSize = image.tileResolution * 2; | ||
} | ||
var f = 0.5; | ||
if (node.x == numTiles || node.y == numTiles) { | ||
f = 1.0 - image.tileResolution / (image.tileResolution + lastTileSize); | ||
} | ||
var i = 1.0 - f; | ||
@@ -966,4 +1024,4 @@ var children = []; | ||
i2 = i, | ||
i3 = i; | ||
// Handle non-symmetric tiles | ||
i3 = i; // Handle non-symmetric tiles | ||
if (lastTileSize < image.tileResolution) { | ||
@@ -973,2 +1031,3 @@ if (node.x == numTiles && node.y != numTiles) { | ||
i2 = 0.5; | ||
if (node.side == 'd' || node.side == 'u') { | ||
@@ -981,2 +1040,3 @@ f3 = 0.5; | ||
i1 = 0.5; | ||
if (node.side == 'l' || node.side == 'r') { | ||
@@ -987,4 +1047,5 @@ f3 = 0.5; | ||
} | ||
} | ||
// Handle small tiles that have fewer than four children | ||
} // Handle small tiles that have fewer than four children | ||
if (doubleTileSize <= image.tileResolution) { | ||
@@ -994,2 +1055,3 @@ if (node.x == numTiles) { | ||
i1 = 1; | ||
if (node.side == 'l' || node.side == 'r') { | ||
@@ -1000,5 +1062,7 @@ f3 = 0; | ||
} | ||
if (node.y == numTiles) { | ||
f2 = 0; | ||
i2 = 1; | ||
if (node.side == 'd' || node.side == 'u') { | ||
@@ -1014,2 +1078,3 @@ f3 = 0; | ||
children.push(ntmp); | ||
if (!(node.x == numTiles && doubleTileSize <= image.tileResolution)) { | ||
@@ -1020,2 +1085,3 @@ vtmp = [v[0] * f1 + v[3] * i1, v[1] * f + v[4] * i, v[2] * f3 + v[5] * i3, v[3], v[4], v[5], v[3] * f + v[6] * i, v[4] * f2 + v[7] * i2, v[5] * f3 + v[8] * i3, v[0] * f1 + v[6] * i1, v[1] * f2 + v[7] * i2, v[2] * f3 + v[8] * i3]; | ||
} | ||
if (!(node.x == numTiles && doubleTileSize <= image.tileResolution) && !(node.y == numTiles && doubleTileSize <= image.tileResolution)) { | ||
@@ -1026,2 +1092,3 @@ vtmp = [v[0] * f1 + v[6] * i1, v[1] * f2 + v[7] * i2, v[2] * f3 + v[8] * i3, v[3] * f + v[6] * i, v[4] * f2 + v[7] * i2, v[5] * f3 + v[8] * i3, v[6], v[7], v[8], v[9] * f1 + v[6] * i1, v[10] * f + v[7] * i, v[11] * f3 + v[8] * i3]; | ||
} | ||
if (!(node.y == numTiles && doubleTileSize <= image.tileResolution)) { | ||
@@ -1032,2 +1099,3 @@ vtmp = [v[0] * f + v[9] * i, v[1] * f2 + v[10] * i2, v[2] * f3 + v[11] * i3, v[0] * f1 + v[6] * i1, v[1] * f2 + v[7] * i2, v[2] * f3 + v[8] * i3, v[9] * f1 + v[6] * i1, v[10] * f + v[7] * i, v[11] * f3 + v[8] * i3, v[9], v[10], v[11]]; | ||
} | ||
for (var j = 0; j < children.length; j++) { | ||
@@ -1039,3 +1107,2 @@ testMultiresNode(rotPersp, children[j], pitch, yaw, hfov); | ||
} | ||
/** | ||
@@ -1046,2 +1113,4 @@ * Creates cube vertex array. | ||
*/ | ||
function createCube() { | ||
@@ -1056,3 +1125,2 @@ return [-1, 1, -1, 1, 1, -1, 1, -1, -1, -1, -1, -1, // Front face | ||
} | ||
/** | ||
@@ -1063,6 +1131,7 @@ * Creates 3x3 identity matrix. | ||
*/ | ||
function identityMatrix3() { | ||
return [1, 0, 0, 0, 1, 0, 0, 0, 1]; | ||
} | ||
/** | ||
@@ -1076,11 +1145,16 @@ * Rotates a 3x3 matrix. | ||
*/ | ||
function rotateMatrix(m, angle, axis) { | ||
var s = Math.sin(angle); | ||
var c = Math.cos(angle); | ||
if (axis == 'x') { | ||
return [m[0], c * m[1] + s * m[2], c * m[2] - s * m[1], m[3], c * m[4] + s * m[5], c * m[5] - s * m[4], m[6], c * m[7] + s * m[8], c * m[8] - s * m[7]]; | ||
} | ||
if (axis == 'y') { | ||
return [c * m[0] - s * m[2], m[1], c * m[2] + s * m[0], c * m[3] - s * m[5], m[4], c * m[5] + s * m[3], c * m[6] - s * m[8], m[7], c * m[8] + s * m[6]]; | ||
} | ||
if (axis == 'z') { | ||
@@ -1090,3 +1164,2 @@ return [c * m[0] + s * m[1], c * m[1] - s * m[0], m[2], c * m[3] + s * m[4], c * m[4] - s * m[3], m[5], c * m[6] + s * m[7], c * m[7] - s * m[6], m[8]]; | ||
} | ||
/** | ||
@@ -1098,6 +1171,7 @@ * Turns a 3x3 matrix into a 4x4 matrix. | ||
*/ | ||
function makeMatrix4(m) { | ||
return [m[0], m[1], m[2], 0, m[3], m[4], m[5], 0, m[6], m[7], m[8], 0, 0, 0, 0, 1]; | ||
} | ||
/** | ||
@@ -1109,6 +1183,7 @@ * Transposes a 4x4 matrix. | ||
*/ | ||
function transposeMatrix4(m) { | ||
return [m[0], m[4], m[8], m[12], m[1], m[5], m[9], m[13], m[2], m[6], m[10], m[14], m[3], m[7], m[11], m[15]]; | ||
} | ||
/** | ||
@@ -1123,2 +1198,4 @@ * Creates a perspective matrix. | ||
*/ | ||
function makePersp(hfov, aspect, znear, zfar) { | ||
@@ -1129,3 +1206,2 @@ var fovy = 2 * Math.atan(Math.tan(hfov / 2) * gl.drawingBufferHeight / gl.drawingBufferWidth); | ||
} | ||
/** | ||
@@ -1137,2 +1213,4 @@ * Processes a loaded texture image into a WebGL texture. | ||
*/ | ||
function processLoadedTexture(img, tex) { | ||
@@ -1148,7 +1226,7 @@ gl.bindTexture(gl.TEXTURE_2D, tex); | ||
var pendingTextureRequests = []; | ||
var pendingTextureRequests = []; // Based on http://blog.tojicode.com/2012/03/javascript-memory-optimization-and.html | ||
// Based on http://blog.tojicode.com/2012/03/javascript-memory-optimization-and.html | ||
var loadTexture = function () { | ||
var cacheTop = 4; // Maximum number of concurrents loads | ||
var textureImageCache = {}; | ||
@@ -1162,2 +1240,3 @@ var crossOrigin; | ||
this.image.crossOrigin = crossOrigin ? crossOrigin : 'anonymous'; | ||
var loadFn = function loadFn() { | ||
@@ -1171,8 +1250,12 @@ if (self.image.width > 0 && self.image.height > 0) { | ||
} | ||
releaseTextureImageLoader(self); | ||
}; | ||
this.image.addEventListener('load', loadFn); | ||
this.image.addEventListener('error', loadFn); // ignore missing tile file to support partial image, otherwise retry loop causes high CPU load | ||
}; | ||
} | ||
; | ||
TextureImageLoader.prototype.loadTexture = function (src, texture, callback) { | ||
@@ -1189,4 +1272,6 @@ this.texture = texture; | ||
this.callback = callback; | ||
}; | ||
} | ||
; | ||
function releaseTextureImageLoader(til) { | ||
@@ -1208,2 +1293,3 @@ if (pendingTextureRequests.length) { | ||
var texture = gl.createTexture(); | ||
if (cacheTop) { | ||
@@ -1214,6 +1300,6 @@ textureImageCache[--cacheTop].loadTexture(src, texture, callback); | ||
} | ||
return texture; | ||
}; | ||
}(); | ||
/** | ||
@@ -1224,2 +1310,4 @@ * Loads image and creates texture for a multires node / tile. | ||
*/ | ||
function processNextTile(node) { | ||
@@ -1231,3 +1319,2 @@ loadTexture(node, encodeURI(node.path + '.' + image.extension), function (texture, loaded) { | ||
} | ||
/** | ||
@@ -1238,13 +1325,15 @@ * Finds and applies optimal multires zoom level. | ||
*/ | ||
function checkZoom(hfov) { | ||
// Find optimal level | ||
var newLevel = 1; | ||
while (newLevel < image.maxLevel && gl.drawingBufferWidth > image.tileResolution * Math.pow(2, newLevel - 1) * Math.tan(hfov / 2) * 0.707) { | ||
newLevel++; | ||
} | ||
} // Apply change | ||
// Apply change | ||
program.level = newLevel; | ||
} | ||
/** | ||
@@ -1257,6 +1346,7 @@ * Rotates perspective matrix. | ||
*/ | ||
function rotatePersp(p, r) { | ||
return [p[0] * r[0], p[0] * r[1], p[0] * r[2], 0, p[5] * r[4], p[5] * r[5], p[5] * r[6], 0, p[10] * r[8], p[10] * r[9], p[10] * r[10], p[11], -r[8], -r[9], -r[10], 0]; | ||
} | ||
/** | ||
@@ -1270,6 +1360,7 @@ * Applies rotated perspective matrix to a 3-vector | ||
*/ | ||
function applyRotPerspToVec(m, v) { | ||
return [m[0] * v[0] + m[1] * v[1] + m[2] * v[2], m[4] * v[0] + m[5] * v[1] + m[6] * v[2], m[11] + m[8] * v[0] + m[9] * v[1] + m[10] * v[2], 1 / (m[12] * v[0] + m[13] * v[1] + m[14] * v[2])]; | ||
} | ||
/** | ||
@@ -1283,2 +1374,4 @@ * Checks if a vertex is visible. | ||
*/ | ||
function checkInView(m, v) { | ||
@@ -1294,17 +1387,21 @@ var vpp = applyRotPerspToVec(m, v); | ||
} | ||
if (winX > 1) { | ||
ret[0] = 1; | ||
} | ||
if (winY < -1) { | ||
ret[1] = -1; | ||
} | ||
if (winY > 1) { | ||
ret[1] = 1; | ||
} | ||
if (winZ < -1 || winZ > 1) { | ||
ret[2] = 1; | ||
} | ||
return ret; | ||
} | ||
/** | ||
@@ -1317,2 +1414,4 @@ * Checks if a square (tile) is visible. | ||
*/ | ||
function checkSquareInView(m, v) { | ||
@@ -1324,13 +1423,16 @@ var check1 = checkInView(m, v.slice(0, 3)); | ||
var testX = check1[0] + check2[0] + check3[0] + check4[0]; | ||
if (testX == -4 || testX == 4) { | ||
return false; | ||
} | ||
var testY = check1[1] + check2[1] + check3[1] + check4[1]; | ||
if (testY == -4 || testY == 4) { | ||
return false; | ||
} | ||
var testZ = check1[2] + check2[2] + check3[2] + check4[2]; | ||
return testZ != 4; | ||
} | ||
/** | ||
@@ -1342,2 +1444,4 @@ * On iOS (iPhone 5c, iOS 10.3), this WebGL error occurs when the canvas is | ||
*/ | ||
function handleWebGLError1286() { | ||
@@ -1348,61 +1452,32 @@ console.log('Reducing canvas size due to error 1286!'); | ||
} | ||
} | ||
} // Vertex shader for equirectangular and cube | ||
// Vertex shader for equirectangular and cube | ||
var v = ['attribute vec2 a_texCoord;', 'varying vec2 v_texCoord;', 'void main() {', | ||
// Set position | ||
'gl_Position = vec4(a_texCoord, 0.0, 1.0);', | ||
// Pass the coordinates to the fragment shader | ||
'v_texCoord = a_texCoord;', '}'].join(''); | ||
var v = ['attribute vec2 a_texCoord;', 'varying vec2 v_texCoord;', 'void main() {', // Set position | ||
'gl_Position = vec4(a_texCoord, 0.0, 1.0);', // Pass the coordinates to the fragment shader | ||
'v_texCoord = a_texCoord;', '}'].join(''); // Vertex shader for multires | ||
// Vertex shader for multires | ||
var vMulti = ['attribute vec3 a_vertCoord;', 'attribute vec2 a_texCoord;', 'uniform mat4 u_cubeMatrix;', 'uniform mat4 u_perspMatrix;', 'varying mediump vec2 v_texCoord;', 'void main(void) {', | ||
// Set position | ||
'gl_Position = u_perspMatrix * u_cubeMatrix * vec4(a_vertCoord, 1.0);', | ||
var vMulti = ['attribute vec3 a_vertCoord;', 'attribute vec2 a_texCoord;', 'uniform mat4 u_cubeMatrix;', 'uniform mat4 u_perspMatrix;', 'varying mediump vec2 v_texCoord;', 'void main(void) {', // Set position | ||
'gl_Position = u_perspMatrix * u_cubeMatrix * vec4(a_vertCoord, 1.0);', // Pass the coordinates to the fragment shader | ||
'v_texCoord = a_texCoord;', '}'].join(''); // Fragment shader | ||
// Pass the coordinates to the fragment shader | ||
'v_texCoord = a_texCoord;', '}'].join(''); | ||
var fragEquiCubeBase = ['precision mediump float;', 'uniform float u_aspectRatio;', 'uniform float u_psi;', 'uniform float u_theta;', 'uniform float u_f;', 'uniform float u_h;', 'uniform float u_v;', 'uniform float u_vo;', 'uniform float u_rot;', 'const float PI = 3.14159265358979323846264;', // Texture | ||
'uniform sampler2D u_image;', 'uniform samplerCube u_imageCube;', // Coordinates passed in from vertex shader | ||
'varying vec2 v_texCoord;', // Background color (display for partial panoramas) | ||
'uniform vec4 u_backgroundColor;', 'void main() {', // Map canvas/camera to sphere | ||
'float x = v_texCoord.x * u_aspectRatio;', 'float y = v_texCoord.y;', 'float sinrot = sin(u_rot);', 'float cosrot = cos(u_rot);', 'float rot_x = x * cosrot - y * sinrot;', 'float rot_y = x * sinrot + y * cosrot;', 'float sintheta = sin(u_theta);', 'float costheta = cos(u_theta);', 'float a = u_f * costheta - rot_y * sintheta;', 'float root = sqrt(rot_x * rot_x + a * a);', 'float lambda = atan(rot_x / root, a / root) + u_psi;', 'float phi = atan((rot_y * costheta + u_f * sintheta) / root);'].join('\n'); // Fragment shader | ||
// Fragment shader | ||
var fragEquiCubeBase = ['precision mediump float;', 'uniform float u_aspectRatio;', 'uniform float u_psi;', 'uniform float u_theta;', 'uniform float u_f;', 'uniform float u_h;', 'uniform float u_v;', 'uniform float u_vo;', 'uniform float u_rot;', 'const float PI = 3.14159265358979323846264;', | ||
var fragCube = fragEquiCubeBase + [// Look up color from texture | ||
'float cosphi = cos(phi);', 'gl_FragColor = textureCube(u_imageCube, vec3(cosphi*sin(lambda), sin(phi), cosphi*cos(lambda)));', '}'].join('\n'); // Fragment shader | ||
// Texture | ||
'uniform sampler2D u_image;', 'uniform samplerCube u_imageCube;', | ||
// Coordinates passed in from vertex shader | ||
'varying vec2 v_texCoord;', | ||
// Background color (display for partial panoramas) | ||
'uniform vec4 u_backgroundColor;', 'void main() {', | ||
// Map canvas/camera to sphere | ||
'float x = v_texCoord.x * u_aspectRatio;', 'float y = v_texCoord.y;', 'float sinrot = sin(u_rot);', 'float cosrot = cos(u_rot);', 'float rot_x = x * cosrot - y * sinrot;', 'float rot_y = x * sinrot + y * cosrot;', 'float sintheta = sin(u_theta);', 'float costheta = cos(u_theta);', 'float a = u_f * costheta - rot_y * sintheta;', 'float root = sqrt(rot_x * rot_x + a * a);', 'float lambda = atan(rot_x / root, a / root) + u_psi;', 'float phi = atan((rot_y * costheta + u_f * sintheta) / root);'].join('\n'); | ||
// Fragment shader | ||
var fragCube = fragEquiCubeBase + [ | ||
// Look up color from texture | ||
'float cosphi = cos(phi);', 'gl_FragColor = textureCube(u_imageCube, vec3(cosphi*sin(lambda), sin(phi), cosphi*cos(lambda)));', '}'].join('\n'); | ||
// Fragment shader | ||
var fragEquirectangular = fragEquiCubeBase + [ | ||
// Wrap image | ||
'lambda = mod(lambda + PI, PI * 2.0) - PI;', | ||
// Map texture to sphere | ||
'vec2 coord = vec2(lambda / PI, phi / (PI / 2.0));', | ||
// Look up color from texture | ||
var fragEquirectangular = fragEquiCubeBase + [// Wrap image | ||
'lambda = mod(lambda + PI, PI * 2.0) - PI;', // Map texture to sphere | ||
'vec2 coord = vec2(lambda / PI, phi / (PI / 2.0));', // Look up color from texture | ||
// Map from [-1,1] to [0,1] and flip y-axis | ||
'if(coord.x < -u_h || coord.x > u_h || coord.y < -u_v + u_vo || coord.y > u_v + u_vo)', 'gl_FragColor = u_backgroundColor;', 'else', 'gl_FragColor = texture2D(u_image, vec2((coord.x + u_h) / (u_h * 2.0), (-coord.y + u_v + u_vo) / (u_v * 2.0)));', '}'].join('\n'); | ||
'if(coord.x < -u_h || coord.x > u_h || coord.y < -u_v + u_vo || coord.y > u_v + u_vo)', 'gl_FragColor = u_backgroundColor;', 'else', 'gl_FragColor = texture2D(u_image, vec2((coord.x + u_h) / (u_h * 2.0), (-coord.y + u_v + u_vo) / (u_v * 2.0)));', '}'].join('\n'); // Fragment shader | ||
// Fragment shader | ||
var fragMulti = ['varying mediump vec2 v_texCoord;', 'uniform sampler2D u_sampler;', | ||
//'uniform mediump vec4 u_color;', | ||
'void main(void) {', | ||
// Look up color from texture | ||
'gl_FragColor = texture2D(u_sampler, v_texCoord);', | ||
// 'gl_FragColor = u_color;', | ||
var fragMulti = ['varying mediump vec2 v_texCoord;', 'uniform sampler2D u_sampler;', //'uniform mediump vec4 u_color;', | ||
'void main(void) {', // Look up color from texture | ||
'gl_FragColor = texture2D(u_sampler, v_texCoord);', // 'gl_FragColor = u_color;', | ||
'}'].join(''); | ||
return { | ||
@@ -1409,0 +1484,0 @@ renderer: function renderer(container, image, imagetype, dynamic) { |
@@ -7,12 +7,12 @@ "use strict"; | ||
*/ | ||
if (!window.requestAnimationFrame) { | ||
window.requestAnimationFrame = function () { | ||
return window.webkitRequestAnimationFrame || window.mozRequestAnimationFrame || window.oRequestAnimationFrame || window.msRequestAnimationFrame || function ( /* function FrameRequestCallback */callback, /* DOMElement Element */element) { | ||
window.setTimeout(callback, 1000 / 60); | ||
}; | ||
}(); | ||
window.requestAnimationFrame = function () { | ||
return window.webkitRequestAnimationFrame || window.mozRequestAnimationFrame || window.oRequestAnimationFrame || window.msRequestAnimationFrame || function ( | ||
/* function FrameRequestCallback */ | ||
callback, | ||
/* DOMElement Element */ | ||
element) { | ||
window.setTimeout(callback, 1000 / 60); | ||
}; | ||
}(); | ||
} |
@@ -1,54 +0,52 @@ | ||
'use strict'; | ||
"use strict"; | ||
var _video = require('video.js'); | ||
var _video = _interopRequireDefault(require("video.js")); | ||
var _video2 = _interopRequireDefault(_video); | ||
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { "default": obj }; } | ||
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } | ||
/* | ||
* Video.js plugin for Pannellum | ||
* Copyright (c) 2015-2018 Matthew Petroff | ||
* MIT License | ||
*/ | ||
(function (document, videojs, pannellum) { | ||
'use strict'; | ||
'use strict'; | ||
videojs.registerPlugin('pannellum', function (config) { | ||
// Create Pannellum instance | ||
var player = this; | ||
var container = player.el(); | ||
var vid = container.getElementsByTagName('video')[0], | ||
pnlmContainer = document.createElement('div'); | ||
config = config || {}; | ||
config.type = 'equirectangular'; | ||
config.dynamic = true; | ||
config.showZoomCtrl = false; | ||
config.showFullscreenCtrl = false; | ||
config.autoLoad = true; | ||
config.panorama = vid; | ||
pnlmContainer.style.visibility = 'hidden'; | ||
player.pnlmViewer = pannellum.viewer(pnlmContainer, config); | ||
container.insertBefore(pnlmContainer, container.firstChild); | ||
vid.style.display = 'none'; | ||
videojs.registerPlugin('pannellum', function (config) { | ||
// Create Pannellum instance | ||
var player = this; | ||
var container = player.el(); | ||
var vid = container.getElementsByTagName('video')[0], | ||
pnlmContainer = document.createElement('div'); | ||
config = config || {}; | ||
config.type = 'equirectangular'; | ||
config.dynamic = true; | ||
config.showZoomCtrl = false; | ||
config.showFullscreenCtrl = false; | ||
config.autoLoad = true; | ||
config.panorama = vid; | ||
pnlmContainer.style.visibility = 'hidden'; | ||
player.pnlmViewer = pannellum.viewer(pnlmContainer, config); | ||
container.insertBefore(pnlmContainer, container.firstChild); | ||
vid.style.display = 'none'; // Handle update settings | ||
// Handle update settings | ||
player.on('play', function () { | ||
if (vid.readyState > 1) player.pnlmViewer.setUpdate(true); | ||
}); | ||
player.on('canplay', function () { | ||
if (!player.paused()) player.pnlmViewer.setUpdate(true); | ||
}); | ||
player.on('pause', function () { | ||
player.pnlmViewer.setUpdate(false); | ||
}); | ||
player.on('loadeddata', function () { | ||
pnlmContainer.style.visibility = 'visible'; | ||
}); | ||
player.on('seeking', function () { | ||
if (player.paused()) player.pnlmViewer.setUpdate(true); | ||
}); | ||
player.on('seeked', function () { | ||
if (player.paused()) player.pnlmViewer.setUpdate(false); | ||
}); | ||
player.on('play', function () { | ||
if (vid.readyState > 1) player.pnlmViewer.setUpdate(true); | ||
}); | ||
})(document, _video2.default, pannellum); /* | ||
* Video.js plugin for Pannellum | ||
* Copyright (c) 2015-2018 Matthew Petroff | ||
* MIT License | ||
*/ | ||
player.on('canplay', function () { | ||
if (!player.paused()) player.pnlmViewer.setUpdate(true); | ||
}); | ||
player.on('pause', function () { | ||
player.pnlmViewer.setUpdate(false); | ||
}); | ||
player.on('loadeddata', function () { | ||
pnlmContainer.style.visibility = 'visible'; | ||
}); | ||
player.on('seeking', function () { | ||
if (player.paused()) player.pnlmViewer.setUpdate(true); | ||
}); | ||
player.on('seeked', function () { | ||
if (player.paused()) player.pnlmViewer.setUpdate(false); | ||
}); | ||
}); | ||
})(document, _video["default"], pannellum); |
{ | ||
"name": "pannellum-react", | ||
"version": "1.2.4", | ||
"version": "1.3.3", | ||
"description": "Pannellum React Component", | ||
@@ -36,5 +36,5 @@ "main": "lib/index.js", | ||
"gh-pages": "^1.2.0", | ||
"nwb": "0.21.x", | ||
"react": "^16.4.1", | ||
"react-dom": "^16.4.1" | ||
"nwb": "0.25.2", | ||
"react": "17.0.2", | ||
"react-dom": "17.0.2" | ||
}, | ||
@@ -41,0 +41,0 @@ "author": "farminf<farmin.f@gmail.com>", |
# pannellum-react | ||
[![Travis][build-badge]][build] | ||
[![npm package][npm-badge]][npm] | ||
@@ -10,4 +9,2 @@ | ||
[build-badge]: https://travis-ci.org/farminf/pannellum-react.svg?branch=master | ||
[build]: https://travis-ci.org/farminf/pannellum-react | ||
[npm-badge]: https://img.shields.io/npm/v/pannellum-react.svg | ||
@@ -26,2 +23,8 @@ [npm]: https://www.npmjs.org/package/pannellum-react | ||
or | ||
``` | ||
yarn add pannellum-react | ||
``` | ||
Import pannellum-react in your react component file by | ||
@@ -133,45 +136,45 @@ | ||
| Name | Type | Default | Description | | ||
| ---------------------- | -------- | ----------------------- | ----------------------------------------------------------------------------------------------- | | ||
| id | String | Unique Generated String | If you pass it, it will use it for div id, if not it would be unique string for each component | | ||
| width | String | "100%" | The width of the panorama div | | ||
| height | String | "400px" | The height of the panorama div | | ||
| image | String | "" | The 360 image path | | ||
| haov | Number | 360 | Initial horizontal angle of view | | ||
| vaov | Number | 180 | Initial vertical angle of view | | ||
| vOffsect | Number | 0 | Initial vertical offset angle | | ||
| yaw | Number | 0 | Starting yaw position in degrees | | ||
| pitch | Number | 0 | Starting pitch position in degrees | | ||
| hfov | Number | 100 | Starting horizontal field of view in degrees | | ||
| maxHfov | Number | 150 | Maximum field of view which user can zoom (in degrees) | | ||
| minHfov | Number | 50 | Minimum field of view which user can zoom (in degrees) | | ||
| maxPitch | Number | 90 | Maximum field of view pitch (in degrees) | | ||
| minPitch | Number | -90 | Minimum field of view pitch (in degrees) | | ||
| maxYaw | Number | 180 | Maximum field of view yaw (in degrees) | | ||
| minYaw | Number | -180 | Minimum field of view yaw (in degrees) | | ||
| autoRotate | Number | 0 | rotation speed in degrees per second. Positive is counter-clockwise, and negative is clockwise. | | ||
| compass | Boolean | false | Showing compass if true | | ||
| title | String | "" | Displays as the panorama’s title | | ||
| author | String | "" | Displays as the panorama’s author | | ||
| preview | String | "" | Preview image path to display | | ||
| previewTitle | String | "" | Preview title to display | | ||
| previewAuthor | String | "" | Preview Author to display | | ||
| autoLoad | Boolean | false | Load and dsplay the image automatically if true | | ||
| orientationOnByDefault | Boolean | false | If true Device orientation will work if device supported | | ||
| showZoomCtrl | Boolean | true | The zoom control display on the image | | ||
| keyboardZoom | Boolean | true | Enables zoom control from keyboard if true | | ||
| disableKeyboardCtrl | Boolean | false | Disables control from keyboard if true | | ||
| mouseZoom | Boolean | true | Enables zoom control with mouse if true | | ||
| draggable | Boolean | true | If false, mouse and touch dragging is disabled | | ||
| showFullscreenCtrl | Boolean | true | FullScreen control display | | ||
| showControls | Boolean | true | if False, no control displays | | ||
| onLoad | Function | | Callback function which fires after loading | | ||
| onRender | Function | | Callback function which fires after each render, helpful if you need to react to yaw/pitch/roll/zoom changes | | ||
| onError | Function | | Callback function which fires after error | | ||
| onErrorcleared | Function | | Callback function which calls after clearing the error | | ||
| onMousedown | Function | | Callback function which calls after mouse button press | | ||
| onMouseup | Function | | Callback function which calls after mouse button release | | ||
| onTouchstart | Function | | Callback function which calls after touch starts | | ||
| onTouchend | Function | | Callback function which calls after touch ends | | ||
| hotspotDebug | Boolean | false | For debug pupose (finding correct point for hotspot) | | ||
| Name | Type | Default | Description | | ||
| ---------------------- | -------- | ----------------------- | ------------------------------------------------------------------------------------------------------------ | | ||
| id | String | Unique Generated String | If you pass it, it will use it for div id, if not it would be unique string for each component | | ||
| width | String | "100%" | The width of the panorama div | | ||
| height | String | "400px" | The height of the panorama div | | ||
| image | String | "" | The 360 image path | | ||
| haov | Number | 360 | Initial horizontal angle of view | | ||
| vaov | Number | 180 | Initial vertical angle of view | | ||
| vOffsect | Number | 0 | Initial vertical offset angle | | ||
| yaw | Number | 0 | Starting yaw position in degrees | | ||
| pitch | Number | 0 | Starting pitch position in degrees | | ||
| hfov | Number | 100 | Starting horizontal field of view in degrees | | ||
| maxHfov | Number | 150 | Maximum field of view which user can zoom (in degrees) | | ||
| minHfov | Number | 50 | Minimum field of view which user can zoom (in degrees) | | ||
| maxPitch | Number | 90 | Maximum field of view pitch (in degrees) | | ||
| minPitch | Number | -90 | Minimum field of view pitch (in degrees) | | ||
| maxYaw | Number | 180 | Maximum field of view yaw (in degrees) | | ||
| minYaw | Number | -180 | Minimum field of view yaw (in degrees) | | ||
| autoRotate | Number | 0 | rotation speed in degrees per second. Positive is counter-clockwise, and negative is clockwise. | | ||
| compass | Boolean | false | Showing compass if true | | ||
| title | String | "" | Displays as the panorama’s title | | ||
| author | String | "" | Displays as the panorama’s author | | ||
| preview | String | "" | Preview image path to display | | ||
| previewTitle | String | "" | Preview title to display | | ||
| previewAuthor | String | "" | Preview Author to display | | ||
| autoLoad | Boolean | false | Load and dsplay the image automatically if true | | ||
| orientationOnByDefault | Boolean | false | If true Device orientation will work if device supported | | ||
| showZoomCtrl | Boolean | true | The zoom control display on the image | | ||
| keyboardZoom | Boolean | true | Enables zoom control from keyboard if true | | ||
| disableKeyboardCtrl | Boolean | false | Disables control from keyboard if true | | ||
| mouseZoom | Boolean | true | Enables zoom control with mouse if true | | ||
| draggable | Boolean | true | If false, mouse and touch dragging is disabled | | ||
| showFullscreenCtrl | Boolean | true | FullScreen control display | | ||
| showControls | Boolean | true | if False, no control displays | | ||
| onLoad | Function | | Callback function which fires after loading | | ||
| onRender | Function | | Callback function which fires after each render, helpful if you need to react to yaw/pitch/roll/zoom changes | | ||
| onError | Function | | Callback function which fires after error | | ||
| onErrorcleared | Function | | Callback function which calls after clearing the error | | ||
| onMousedown | Function | | Callback function which calls after mouse button press | | ||
| onMouseup | Function | | Callback function which calls after mouse button release | | ||
| onTouchstart | Function | | Callback function which calls after touch starts | | ||
| onTouchend | Function | | Callback function which calls after touch ends | | ||
| hotspotDebug | Boolean | false | For debug pupose (finding correct point for hotspot) | | ||
@@ -178,0 +181,0 @@ Additionally, by Getting refrence of the component, you can get the pannellum **Viewer** calling `getViewer()` which gives all the available functions of the viewer such as `getPitch`, `setPitch` , `getyaw` and etc. find [here](https://pannellum.org/documentation/api/#viewer) |
Sorry, the diff of this file is too big to display
Sorry, the diff of this file is too big to display
Sorry, the diff of this file is too big to display
Sorry, the diff of this file is too big to display
Sorry, the diff of this file is not supported yet
Uses eval
Supply chain riskPackage uses dynamic code execution (e.g., eval()), which is a dangerous practice. This can prevent the code from running in certain environments and increases the risk that the code may contain exploits or malicious behavior.
Found 1 instance in 1 package
Uses eval
Supply chain riskPackage uses dynamic code execution (e.g., eval()), which is a dangerous practice. This can prevent the code from running in certain environments and increases the risk that the code may contain exploits or malicious behavior.
Found 2 instances in 1 package
6853612
19.72%77549
10.78%328
0.92%1
-50%45
-2.17%