diff --git "a/flipbook.webgl.js" "b/flipbook.webgl.js" new file mode 100644--- /dev/null +++ "b/flipbook.webgl.js" @@ -0,0 +1,3612 @@ +/* + * Real3D FlipBook [https://real3dflipbook.com] + * @author creativeinteractivemedia [https://codecanyon.net/user/creativeinteractivemedia/portfolio] + * @version 4.10 + * @date 2025-05-15 + */ +'use strict'; +var FLIPBOOK = FLIPBOOK || {}; + +{ + FLIPBOOK.PageWebGL = function (book, i, hard, options, preloaderMatF, preloaderMatB) { + THREE.Object3D.call(this); + this.book = book; + this.index = i; + this.pW = options.pageWidth; + this.pH = options.pageHeight; + this.nfacesw = options.pageSegmentsW; + this.nfacesh = options.pageSegmentsH; + this.mats = []; + this.pageHardness = hard; + this.pageThickness = hard; + this.duration = options.pageFlipDuration; + this.angle = 0; + this.force = 10; + this.offset = 0; + this.mod = null; + this.bend = null; + this.pivot = null; + this.isFlippedLeft = false; + this.isFlippedRight = true; + this.flippingLeft = false; + this.flippingRight = false; + this.options = options; + + var index = options.rightToLeft ? options.pages.length / 2 - this.index - 1 : this.index; + this.indexF = options.rightToLeft ? 2 * index + 1 : 2 * index; + this.indexB = options.rightToLeft ? 2 * index : 2 * index + 1; + this.showing = false; + this.preloaderMatF = preloaderMatF; + this.preloaderMatB = preloaderMatB; + + this.preloaderMatF = preloaderMatF; + this.preloaderMatB = preloaderMatB; + + this.htmlLoaded = { + front: false, + back: false, + }; + + this.animations = []; + + var self = this; + + if (i == 0 && this.options.cornerCurl) { + this.nfacesw = 20; + this.nfacesh = 20; + var obj = { force: 0 }; + + this.cornerCurlTween = FLIPBOOK.animate({ + from: obj.force, + to: 1, + duration: 1000, + easing: 'easeInOutQuad', + repeat: Infinity, + yoyo: true, + step: function (f) { + if (self.cornerCurl) { + self.b2.force = f * -1.8; + if (self.modF) self.modF.apply(); + self.book.needsUpdate = true; + } + }, + }); + this.animations.push(this.cornerCurlTween); + } + + this.gF = new THREE.BoxGeometry(this.pW, this.pH, 0.01, this.nfacesw, this.nfacesh, 0); + var basicMat = new THREE.MeshBasicMaterial({ + color: 0xededed, + }); + var mats = [basicMat, basicMat, basicMat, basicMat, preloaderMatF, preloaderMatB]; + + var mats2; + mats2 = [basicMat, basicMat, basicMat, basicMat, basicMat, basicMat]; + + if (this.options.pagePreloader) { + mats2 = [basicMat, basicMat, basicMat, basicMat, preloaderMatF, preloaderMatB]; + } + + this.cube = new THREE.Mesh(this.gF, mats); + this.cube.position.x = this.pW * 0.5; + if (this.options.shadows) { + this.cube.castShadow = true; + this.cube.receiveShadow = true; + } + + this.gF.faceVertexUvs[1] = this.gF.faceVertexUvs[0]; + + this.showMat(); + + this.cubeEmpty = new THREE.Mesh(new THREE.BoxGeometry(this.pW, this.pH, 0.01, 1, 1, 0), mats2); + + this.cubeEmpty.position.x = this.pW * 0.5; + + this.pageFlippedAngle = (Math.PI * this.options.pageFlippedAngle) / 180; + + this.bendF = new MOD3.Bend(0, 0, 0); + this.bendF.constraint = MOD3.ModConstant.LEFT; + if (this.pH > this.pW) { + this.bendF.switchAxes = true; + } + + this.b2 = new MOD3.Bend(0, 0, 0); + this.b2.constraint = MOD3.ModConstant.LEFT; + if (this.pH > this.pW) { + this.b2.switchAxes = true; + } + this.b2.offset = 0.98; + this.b2.setAngle(1); + + this.modF = new MOD3.ModifierStack(new MOD3.LibraryThree(), this.cube); + this.modF.addModifier(this.bendF); + + if (i == 0 && this.options.cornerCurl) { + this.modF.addModifier(this.b2); + } + + this.modF.apply(); + }; + + FLIPBOOK.PageWebGL.prototype = new THREE.Object3D(); + FLIPBOOK.PageWebGL.prototype.constructor = FLIPBOOK.PageWebGL; + + FLIPBOOK.PageWebGL.prototype.startCornerCurl = function () { + this.cornerCurl = true; + }; + + FLIPBOOK.PageWebGL.prototype.stopCornerCurl = function () { + this.cornerCurl = false; + this.b2.force = 0; + if (this.modF) this.modF.apply(); + }; + + FLIPBOOK.PageWebGL.prototype.loadHTML = async function (side, callback) { + var index = side == 'front' ? this.indexF : this.indexB; + var self = this; + + if (!this.htmlLoaded[side]) { + this.options.main.loadPageHTML(index, function (_) { + self.htmlLoaded[side] = true; + callback.call(self); + }); + } else { + callback.call(this); + } + }; + + FLIPBOOK.PageWebGL.prototype.load = function (side, callback, _) { + var main = this.book.main; + + if (!main.wrapperH) { + return; + } + if (!main.zoom) { + return; + } + + var self = this; + var options = this.book.options; + var main = options.main; + + this.disposed = false; + + var o = options; + var pageSize = main.wrapperH * main.zoom; + var size = pageSize < o.pageTextureSizeSmall * 0.8 ? o.pageTextureSizeSmall : o.pageTextureSize; + const { p: texture } = o; + + if (side == 'front') { + if (!this.options.cover && this.index == 0) { + return; + } + + if (this.sizeFront == size) { + if (callback) { + callback.call(this); + } + } else { + main.loadPage(this.indexF, size, function (page) { + if (self.disposed) return; + if (!page || texture) { + if (callback) { + callback.call(self); + } + return; + } + + if (self.sizeFront == size) { + if (callback) { + callback.call(self); + } + return; + } + + self.sizeFront = size; + + var t1; + + if (page.imageBitmap) { + const bitmap = page.imageBitmap[size] || page.imageBitmap; + t1 = new THREE.Texture(bitmap); + t1.offset.y = 1; + t1.repeat.y = -1; + } else { + t1 = new THREE.Texture(); + + t1.image = page.image[size] || page.image; + } + + t1.minFilter = THREE.LinearFilter; + + t1.generateMipmaps = false; + + t1.needsUpdate = true; + + var pageIndex = 2 * self.index; + if (!self.options.cover) { + pageIndex--; + } + + if (self.options.pages[pageIndex].side == 'left') { + t1.repeat.x = 0.5; + } else if (self.options.pages[pageIndex].side == 'right') { + t1.repeat.x = 0.5; + t1.offset.x = 0.5; + } + self.frontMaterial = self.createMaterial(t1); + + self.setFrontMat(self.frontMaterial); + if (callback) { + callback.call(self); + } + }); + } + } else if (side == 'back') { + if (!options.cover && this.index == this.book.pages.length - 1) { + return; + } + + if (this.sizeBack == size) { + if (callback) { + callback.call(this); + } + } else { + main.loadPage(this.indexB, size, function (page) { + if (self.disposed) return; + if (!page || texture) { + if (callback) { + callback.call(self); + } + return; + } + + if (self.sizeBack == size) { + if (callback) { + callback.call(self); + } + return; + } + + self.sizeBack = size; + + var t2; + + if (page.imageBitmap) { + const bitmap = page.imageBitmap[size] || page.imageBitmap; + t2 = new THREE.Texture(bitmap); + t2.offset.y = 1; + t2.repeat.y = -1; + } else { + t2 = new THREE.Texture(); + + t2.image = page.image[size] ? page.image[size].clone || page.image[size] : page.image; + } + + t2.minFilter = THREE.LinearFilter; + t2.generateMipmaps = false; + + t2.needsUpdate = true; + + var pageIndex = 2 * self.index + 1; + if (!self.options.cover) { + pageIndex--; + } + + if (self.options.pages[pageIndex].side == 'left') { + t2.repeat.x = 0.5; + } else if (self.options.pages[pageIndex].side == 'right') { + t2.repeat.x = 0.5; + t2.offset.x = 0.5; + } + self.backMaterial = self.createMaterial(t2, 'back'); + self.setBackMat(self.backMaterial); + + if (callback) { + callback.call(self); + } + }); + } + } + }; + + FLIPBOOK.PageWebGL.prototype.unload = function (side) { + var mat; + var t; + + if (side == 'front' && this.sizeFront) { + mat = this.cube.material[4]; + t = mat.map; + mat.dispose(); + mat.needsUpdate = true; + + if (t) { + t.dispose(); + t = null; + } + + this.sizeFront = 0; + this.setFrontMat(this.preloaderMatF); + } else if (side == 'back' && this.sizeBack) { + mat = this.cube.material[5]; + t = mat.map; + mat.dispose(); + + if (t) { + t.dispose(); + t = null; + } + + this.sizeBack = 0; + this.setBackMat(this.preloaderMatB); + } + }; + + FLIPBOOK.PageWebGL.prototype.disposeMat = function () { + if (!this.loaded) { + return; + } + + var matF = this.cube.material[4]; + var matB = this.cube.material[5]; + var tF = matF.map; + var tB = matB.map; + matF.dispose(); + matB.dispose(); + + if (tF) { + tF.dispose(); + } + if (tB) { + tB.dispose(); + } + + this.disposed = true; + this.loaded = false; + }; + + FLIPBOOK.PageWebGL.prototype.createMaterial = function (map, side) { + var mat; + if (this.options.lights) { + var sTexture = side == 'back' ? this.book.specularB : this.book.specularF; + var o = this.options; + var color = 0xffffff; + + mat = new THREE.MeshStandardMaterial({ + map: map, + roughness: o.pageRoughness, + metalness: o.pageMetalness, + emissive: 0x000000, + color: color, + lightMap: sTexture, + }); + } else { + mat = new THREE.MeshBasicMaterial({ + map: map, + }); + } + return mat; + }; + + FLIPBOOK.PageWebGL.prototype._setAngle = function (angle) { + if (angle <= 180 && angle >= -180) { + angle = (angle / 180) * Math.PI; + + if (angle < 0) { + angle = angle + Math.PI; + } + + if (this.angle == angle) { + return; + } + + this.angle = angle; + this.rotation.y = -angle; + + if (this.isFlippedLeft) { + this.bendF.force = + (1.35 * Math.pow(-Math.abs(Math.cos(-angle / 2)), 1)) / Math.pow(this.pageHardness, 1.5); + } else { + this.bendF.force = + (1.35 * Math.pow(Math.abs(Math.sin(-angle / 2)), 1)) / Math.pow(this.pageHardness, 1.5); + } + + this.updateBend(); + + if (this.book.htmlLayerVisible && Math.abs(angle) > 0.03) { + this.book._hideHTMLPage(this.book.pageL); + this.book._hideHTMLPage(this.book.pageR); + this.book._hideHTMLPage(this.book.pageC); + this.book._emptyHTMLPage(this.book.pageRInner); + this.book._emptyHTMLPage(this.book.pageLInner); + this.book._emptyHTMLPage(this.book.pageCInner); + this.book.htmlLayerVisible = false; + + this.book.main.trigger('hidepagehtml', { page: this }); + } + + this.book.needsUpdate = true; + + this.book.correctZOrder(); + } + }; + + FLIPBOOK.PageWebGL.prototype.updateBend = function () { + // console.log(this.bendF); + if (Math.abs(this.bendF.force) < 0.0001) { + this.bendF.force = 0; + } + if (this.bendForce == this.bendF.force) { + return; + } + + this.bendForce == this.bendF.force; + + this.stopCornerCurl(); + if (this.modF) this.modF.apply(); + this.gF.computeFaceNormals(); + this.gF.computeVertexNormals(true); + this.book.correctZOrder(); + this.book.needsUpdate = true; + }; + + FLIPBOOK.PageWebGL.prototype.flipLeft = function (onComplete) { + this.onComplete = onComplete; + this.dragging = false; + if (!this.isFlippedLeft && !this.flippingLeft && !this.flippingRight && this.index == this.book.flippedleft) { + if (this.duration > 0) { + this.flippingLeft = true; + this.flipping = true; + this.force = 0; + this.bendIn(-Math.PI); + } else { + this.rotation.y = -Math.PI; + this.flippingLeft = false; + this.isFlippedLeft = true; + this.flippingRight = false; + this.isFlippedRight = false; + } + } + }; + + FLIPBOOK.PageWebGL.prototype.flipLeftInstant = function (onComplete) { + this.onComplete = onComplete; + this.dragging = false; + + if (!this.isFlippedLeft && !this.flippingLeft && !this.flippingRight && this.index == this.book.flippedleft) { + this.xx = 0; + this.flippingLeft = true; + this.isFlippedLeft = false; + this.renderFlip(-Math.PI); + this.flippingLeft = false; + this.isFlippedLeft = true; + this.flippingRight = false; + this.isFlippedRight = false; + + this.flipFinished(); + } + }; + + FLIPBOOK.PageWebGL.prototype.hideMat = function () { + if (this.showing) { + this.remove(this.cube); + this.add(this.cubeEmpty); + this.showing = false; + } + }; + + FLIPBOOK.PageWebGL.prototype.showMat = function () { + if (!this.showing) { + this.add(this.cube); + this.remove(this.cubeEmpty); + this.showing = true; + this.book.needsUpdate = true; + } + }; + + FLIPBOOK.PageWebGL.prototype.setFrontMat = function (m) { + if (this.cube.material[4] === m) { + return; + } + this.cube.material[4] = m; + this.book.needsUpdate = true; + }; + + FLIPBOOK.PageWebGL.prototype.setBackMat = function (m) { + if (this.cube.material[5] === m) { + return; + } + this.cube.material[5] = m; + this.book.needsUpdate = true; + }; + + FLIPBOOK.PageWebGL.prototype.flipRightInstant = function (onComplete) { + this.onComplete = onComplete; + this.dragging = false; + if ( + !this.isFlippedRight && + !this.flippingRight && + !this.flippingLeft && + this.index == this.book.getNumPages() - this.book.flippedright - 1 + ) { + this.xx = 0; + this.flippingRight = true; + this.isFlippedRight = false; + this.renderFlip(0); + this.flippingLeft = false; + this.isFlippedLeft = false; + this.flippingRight = false; + this.isFlippedRight = true; + + this.flipFinished(); + } + }; + + FLIPBOOK.PageWebGL.prototype.flipRight = function (onComplete) { + this.onComplete = onComplete; + this.dragging = false; + if ( + !this.isFlippedRight && + !this.flippingRight && + !this.flippingLeft && + this.index == this.book.getNumPages() - this.book.flippedright - 1 + ) { + if (this.duration > 0) { + this.flippingRight = true; + this.flipping = true; + + this.force = 0; + this.bendIn(0); + } else { + this.rotation.y = 0; + this.flippingLeft = false; + this.isFlippedLeft = false; + this.flippingRight = false; + this.isFlippedRight = true; + } + } + }; + + FLIPBOOK.PageWebGL.prototype.bendIn = function (angle) { + var time1 = 2 * this.duration * 240 * Math.pow(Math.abs(this.rotation.y - angle) / Math.PI, 0.5); + + time1 *= Math.pow(this.pageHardness, 0.25); + + time1 *= 1 + this.pageHardness / 30; + + var start = this.rotation.y; + var end = angle; + + var bendInAnimation = FLIPBOOK.animate({ + from: start, + to: end, + duration: time1, + easing: 'easeInSine', + step: (value) => { + this.renderFlip(value); + }, + complete: () => { + this.bendOut(); + }, + }); + + this.animations.push(bendInAnimation); + + this.options.main.turnPageStart(); + }; + + FLIPBOOK.PageWebGL.prototype.bendOut = function () { + var time = this.duration * Math.pow(Math.abs(this.bendF.force), 0.5) * 1000; + + var force = this.bendF.force; + var offset = this.bendF.offset; + + var a1 = FLIPBOOK.animate({ + from: force, + to: 0, + duration: time, + easing: 'easeOutSine', + step: (value) => { + this.bendF.force = value; + this.updateBend(); + }, + complete: () => { + this.flipFinished(this); + }, + }); + this.animations.push(a1); + + var a2 = FLIPBOOK.animate({ + from: offset, + to: 1, + duration: time, + easing: 'easeOutSine', + step: (value) => { + this.bendF.offset = value; + this.updateBend(); + }, + complete: () => { + this.bendF.offset = 0; + }, + }); + this.animations.push(a2); + + this.book.correctZOrder(); + }; + + FLIPBOOK.PageWebGL.prototype.modApply = function () { + this.bendF.force = this.bendB.force = this.force; + this.bendF.offset = this.bendB.offset = this.offset; + this.updateBend(); + }; + FLIPBOOK.PageWebGL.prototype.renderFlip = function (angle) { + this._setAngle((-angle * 180) / Math.PI); + }; + FLIPBOOK.PageWebGL.prototype.flipFinished = function () { + if (this.flippingLeft) { + this.flippingLeft = false; + this.isFlippedLeft = true; + this.flippingRight = false; + this.isFlippedRight = false; + } else if (this.flippingRight) { + this.flippingLeft = false; + this.isFlippedRight = true; + this.flippingRight = false; + this.isFlippedLeft = false; + } + + this.bendF.force = 0.0; + this.bendF.offset = 0.0; + this.updateBend(); + this.flipping = false; + this.dragging = false; + if (typeof this.onComplete != 'undefined') { + this.onComplete(this); + } + this.book.flipFinnished(); + }; + FLIPBOOK.PageWebGL.prototype.isFlippedLeft = function () { + return this.isFlippedLeft; + }; + FLIPBOOK.PageWebGL.prototype.isFlippedRight = function () { + return this.isFlippedRight; + }; + + FLIPBOOK.PageWebGL.prototype.dispose = function () { + this.disposeMat(); + + this.animations.forEach(function (animation) { + animation.stop(); + }); + // this.matF = null; + // this.matB = null; + this.gF.dispose(); + this.gF = null; + // this.gB.dispose(); + // this.gB = null; + // this.cube.dispose(); + this.cube = null; + this.cubeEmpty = null; + this.bendF = null; + this.modF = null; + // this.cubeEmpty.dispose(); + // this.cubeEmpty = null; + this.options = null; + this.book = null; + this.disposed = true; + }; +} + +{ + FLIPBOOK.BookWebGL = function (el, main, options) { + this.wrapper = el; + this.options = options; + this.main = main; + + this.options.cameraDistance = 2800; + + this.pageW = options.pageWidth; + this.pageH = options.pageHeight; + + this.pageW = (1000 * options.pageWidth) / options.pageHeight; + this.pageH = 1000; + + options.pageWidth = this.pageW; + options.pageHeight = this.pageH; + + this.scroll = options.scroll; + this.pagesArr = options.pages; + this.pages = []; + this.animating = false; + this.animations = []; + + this.sc = 1; + + var s = this.wrapper.style; + s.width = '100%'; + s.height = '100%'; + s.position = 'absolute'; + s.overflow = 'hidden'; + + this.options.cameraDistance = this.options.cameraDistance / 1.5; + }; + + FLIPBOOK.BookWebGL.prototype = Object.create(FLIPBOOK.Book.prototype); + + FLIPBOOK.BookWebGL.prototype.constructor = FLIPBOOK.BookWebGL; + + FLIPBOOK.BookWebGL.prototype.init3d = function () { + var self = this; + var VIEW_ANGLE = 30; + var ASPECT = this.main.wrapperW / this.main.wrapperH; + var NEAR = 1; + var FAR = 10000; + var o = this.options; + + this.Scene = new THREE.Scene(); + this.centerContainer = new THREE.Object3D(); + + this.Scene.add(this.centerContainer); + this.Camera = new THREE.PerspectiveCamera(VIEW_ANGLE, ASPECT, NEAR, FAR); + this.Scene.add(this.Camera); + this.zoom = o.zoomMin; + this.pan = o.pan; + this.tilt = o.tilt; + + // window.bk = this; + // window.sc = this.Scene; + + // this.updateCameraPosition(); + + var container = this.wrapper; + var c = document.createElement('canvas'); + c.getContext('webgl'); + + this.renderer = new THREE.WebGLRenderer({ + antialias: Math.max(this.options.antialias, 2), + alpha: true, + }); + + this.renderer.gammaInput = true; + this.renderer.gammaOutput = true; + + if (this.options.shadows) { + this.renderer.shadowMap.enabled = true; + this.renderer.shadowMap.type = THREE.PCFShadowMap; + } + + window.webglrenderers = window.webglrenderers || []; + + window.webglrenderers.push(this.renderer); + + this.renderer.setSize(container.clientWidth, container.clientHeight); + var pr = window.devicePixelRatio < o.minPixelRatio ? o.minPixelRatio : window.devicePixelRatio; + this.renderer.setPixelRatio(pr); + this.pixelRatio = pr; + container.appendChild(this.renderer.domElement); + + var htmlLayer = false; + var pages = this.options.pages; + for (var i = 0; i < pages.length; i++) { + if (pages[i].htmlContent) { + htmlLayer = true; + } + } + + if (htmlLayer || o.pdfMode) { + this.initHtmlContent(); + } + + this.canvas = this.renderer.domElement; + this.canvas.style.position = 'relative'; + this.canvas.style.pointerEvents = 'none'; + + this.canvas.addEventListener( + 'webglcontextlost', + (event) => { + debugger; + // Prevent default behavior to stop automatic context restoration + // event.preventDefault(); + console.log('WebGL context lost'); + // Handle the context loss: free resources, notify the user, etc. + }, + false + ); + + if (this.options.lights) { + var sCol = o.lightColor; + var sl = new THREE.SpotLight(sCol); + sl.intensity = o.lightIntensity; + sl.position.set(0, 0, o.lightPositionZ); + sl.distance = 4000; + + if (this.options.shadows) { + sl.castShadow = true; + sl.shadow.bias = -0.000002; + sl.shadow.mapSize.width = this.options.shadowMapSize; + sl.shadow.mapSize.height = this.options.shadowMapSize; + var mat = new THREE.ShadowMaterial(); + mat.opacity = this.options.shadowOpacity; + + this.shadowPlane = new THREE.Mesh(new THREE.BoxGeometry(3000, 1500, 1, 1, 1, 1), mat); + this.shadowPlane.position.set(0, 0, -30); + this.centerContainer.add(this.shadowPlane); + this.shadowPlane.receiveShadow = true; + } + + this.Scene.add(sl); + } + + this.centerContainer.position.set(0, 0, 0); + + this.bookWidth = 1; + + this.onResize(); + + this.updateHtmlLayerPosition(); + + this.flippedleft = 0; + this.flippedright = 0; + + this.cameraZMin = 300; + this.cameraZMax = 5000; + + this.renderLoop = function () { + if (self.rendering) { + if (!self.enabled) { + return; + } + + if (self.needsUpdate) { + self.renderer.render(self.Scene, self.Camera); + self.needsUpdate = false; + + if (self.htmlLayer) { + self.cssRenderer.render(self.Scene, self.Camera); + } + } + } + if (self.renderLoop) requestAnimationFrame(self.renderLoop); + }; + this.renderLoop(); + }; + + FLIPBOOK.BookWebGL.prototype.onPageUnloaded = function (index) { + var side; + var sheetIndex = Math.floor(index / 2); + if (this.options.rightToLeft) { + sheetIndex = this.pages.length - sheetIndex - 1; + side = index % 2 == 0 ? 'back' : 'front'; + } else { + side = index % 2 == 0 ? 'front' : 'back'; + } + + this.pages[sheetIndex].unload(side); + }; + + FLIPBOOK.BookWebGL.prototype.correctZOrder = (function () { + const halfPI = Math.PI * 0.5; + const pow = Math.pow; + let basePowTh = 1; + + return function () { + const pages = this.pages; + const n = pages.length; + const th = FLIPBOOK.th(); + basePowTh = basePowTh === 1 || this._lastTh !== th ? pow(th, 0.85) : basePowTh; + this._lastTh = th; + + const left = (this._zLeft ||= []); + const right = (this._zRight ||= []); + left.length = 0; + right.length = 0; + + for (let i = 0; i < n; i++) { + const page = pages[i]; + if (page.angle > halfPI) { + left.push(page); + } else { + right.push(page); + } + } + + left.reverse(); + + for (let i = 0, L = left.length; i < L; i++) { + const p = left[i]; + p.position.z = -basePowTh * pow(i, 0.85); + p.cube.castShadow = i < 2; + } + for (let i = 0, R = right.length; i < R; i++) { + const p = right[i]; + p.position.z = -basePowTh * pow(i, 0.85); + p.cube.castShadow = i < 2; + } + }; + })(); + + FLIPBOOK.BookWebGL.prototype.initHtmlContent = function () { + var htmlLayer = document.createElement('div'); + htmlLayer.className = 'htmlLayer ' + Math.random(); + + this.pageR = document.createElement('div'); + this.pageR.classList.add('R'); + this.pageR.style.cssText = ` + width: ${(1000 * this.options.pageWidth) / this.options.pageHeight}px; + height: 1000px; + position: absolute; + top: -500px; + pointer-events: none; +`; + htmlLayer.appendChild(this.pageR); + + this.pageRInner = document.createElement('div'); + this.pageRInner.style.pointerEvents = 'all'; + this.pageRInner.classList.add('RInner'); + this.pageR.appendChild(this.pageRInner); + + this.pageL = document.createElement('div'); + this.pageL.classList.add('L'); + this.pageL.style.cssText = ` + width: ${(1000 * this.options.pageWidth) / this.options.pageHeight}px; + height: 1000px; + position: absolute; + top: -500px; + left: ${(-1000 * this.options.pageWidth) / this.options.pageHeight}px; + pointer-events: none; +`; + htmlLayer.appendChild(this.pageL); + + this.pageLInner = document.createElement('div'); + this.pageLInner.style.pointerEvents = 'all'; + this.pageLInner.classList.add('LInner'); + this.pageL.appendChild(this.pageLInner); + + var positionMultiplier = this.options.scaleCover ? 2 : 1; + var centerWdith = this.options.scaleCover ? 1 : 2; + this.pageC = document.createElement('div'); + this.pageC.classList.add('C'); + this.pageC.style.cssText = ` + width: ${(centerWdith * 1000 * this.options.pageWidth) / this.options.pageHeight}px; + height: 1000px; + position: absolute; + top: -500px; + left: ${(-1000 * this.options.pageWidth) / positionMultiplier / this.options.pageHeight}px; + pointer-events: none; +`; + htmlLayer.appendChild(this.pageC); + + this.pageCInner = document.createElement('div'); + this.pageCInner.style.pointerEvents = 'all'; + this.pageCInner.classList.add('CInner'); + this.pageC.appendChild(this.pageCInner); + + this.htmlLayer = new FLIPBOOK.CSS3DObject(htmlLayer); + this.Scene.add(this.htmlLayer); + this.cssRenderer = new FLIPBOOK.CSS3DRenderer(); + this.wrapper.appendChild(this.cssRenderer.domElement); + this.cssRenderer.domElement.style.position = 'absolute'; + this.cssRenderer.domElement.style.top = '0'; + this.cssRenderer.domElement.style.left = '0'; + this.cssRenderer.domElement.style.pointerEvents = 'none'; + this.cssRenderer.domElement.className = 'cssRenderer ' + Math.random(); + }; + + FLIPBOOK.BookWebGL.prototype.enablePrev = function (val) { + this.prevEnabled = val; + }; + + FLIPBOOK.BookWebGL.prototype.enableNext = function (val) { + this.nextEnabled = val; + }; + + FLIPBOOK.BookWebGL.prototype.isZoomed = function () { + return this.main.zoom > this.options.zoomMin && this.main.zoom > 1; + }; + FLIPBOOK.BookWebGL.prototype.getRightPage = function () { + return this.pages[this.flippedleft]; + }; + + FLIPBOOK.BookWebGL.prototype.getNextPage = function () { + return this.pages[this.flippedleft + 1]; + }; + + FLIPBOOK.BookWebGL.prototype.getLeftPage = function () { + return this.pages[this.flippedleft - 1]; + }; + + FLIPBOOK.BookWebGL.prototype.getPrevPage = function () { + return this.pages[this.flippedleft - 2]; + }; + + FLIPBOOK.BookWebGL.prototype.onSwipe = function (e, phase, distanceX, distanceY, duration, fingerCount) { + if (this.isZoomed()) { + if (phase == 'start') { + this._start(e); + } else if (phase == 'move') { + this._move(e, distanceX, distanceY); + } else if (phase == 'end') { + this._end(e); + } + return; + } + + var left = this.getLeftPage(); + var right = this.getRightPage(); + var next = this.getNextPage(); + var prev = this.getPrevPage(); + + if ( + this.options.rotateCameraOnMouseDrag && + (!right || !right.dragging) && + (!left || !left.dragging) && + (this.onMouseMove == 'rotate' || this.onMouseMove == 'scroll') + ) { + return; + } + + if ((phase == 'cancel' || phase == 'end') && fingerCount <= 1) { + if (this.view == 1 && this.draggingBook && distanceX < 0) { + this.nextPage(); + this.draggingBook = false; + return; + } + + if (this.view == 1 && this.draggingBook && distanceX > 0) { + this.prevPage(); + this.draggingBook = false; + return; + } + + if (distanceX > 0 && (!right || !right.dragging)) { + this.prevPage(); + } else if (distanceX < 0 && (!left || !left.dragging)) { + this.nextPage(); + } + + if (right) { + right.dragging = false; + } + if (left) { + left.dragging = false; + } + } else if (phase == 'move' && fingerCount <= 1) { + if (this.draggingBook) { + this.centerContainer.position.x = this.draggingBookStartX + distanceX; + this.updateHtmlLayerPosition(); + return; + } + + if (this.view == 1 && this.isFocusedLeft() && distanceX < 0 && this.canFlipNext()) { + this.draggingBookStartX = this.centerContainer.position.x; + this.draggingBook = true; + return; + } + + if (this.view == 1 && this.isFocusedRight() && distanceX > 0 && this.canFlipPrev()) { + this.draggingBookStartX = this.centerContainer.position.x; + this.draggingBook = true; + return; + } + + distanceX = (180 * distanceX) / this.wrapperW; + + if ((left && left.flipping) || (right && right.flipping)) { + return; + } + + if (distanceX > 0 && this.canFlipPrev()) { + if (left) { + left._setAngle(180 - distanceX); + left.dragging = true; + } + if (right) { + right._setAngle(0); + right.dragging = false; + } + if (prev) { + prev.showMat(); + } + if (next) { + next.hideMat(); + } + } else if (distanceX < 0 && this.canFlipNext()) { + if (right) { + right._setAngle(-distanceX); + right.dragging = true; + } + if (left) { + left._setAngle(180); + left.dragging = false; + } + if (prev) { + prev.hideMat(); + } + if (next) { + next.showMat(); + } + } + } + }; + FLIPBOOK.BookWebGL.prototype.onResize = function (doNotUpdatePosition) { + var m = this.main; + var w = m.wrapperW; + var h = m.wrapperH; + var o = this.options; + var pw = o.pageWidth; + var ph = o.pageHeight; + var pw2 = o.pageWidth2; + var ph2 = o.pageHeight2; + var bw = this.bookWidth; + if (o.scaleCover) pw /= bw; + + var r1 = w / h; + var r2 = pw / ph; + + if (h < 1000 && window.devicePixelRatio == 1) { + this.renderer.setPixelRatio(2); + } else { + var pr = window.devicePixelRatio < o.minPixelRatio ? o.minPixelRatio : window.devicePixelRatio; + this.renderer.setPixelRatio(pr); + } + + var s = Math.min(this.zoom, 1); + + var zoomMin = Number(o.zoomMin); + + if (o.responsiveView && w <= o.responsiveViewTreshold && r1 < 2 * r2 && r1 < o.responsiveViewRatio) { + this.view = 1; + + if (r2 > r1) { + this.sc = (zoomMin * r1) / (r2 * s); + } else { + this.sc = 1; + } + } else { + this.view = 2; + + if (r1 < bw * r2) { + this.sc = (zoomMin * r1) / (bw * r2 * s); + } else { + this.sc = 1; + } + } + + this.Camera.aspect = w / h; + this.Camera.updateProjectionMatrix(); + this.updateCameraPosition(); + + this.renderer.setSize(w, h); + + if (!doNotUpdatePosition) this.updateBookPosition(); + + if (this.htmlLayer) { + this.cssRenderer.setSize(w, h); + this.htmlLayer.scale.set( + // this.centerContainer.scale.x, + // this.centerContainer.scale.y, + // this.centerContainer.scale.z + this.sc, + this.sc, + this.sc + ); + } + + this.options.main.turnPageComplete(); + + this.wrapperW = w; + this.wrapperH = h; + }; + + FLIPBOOK.BookWebGL.prototype.updateCameraPosition = function () { + var angle = (Math.PI * this.tilt) / 180; + var cameraX = 0; + var cameraY = (this.options.cameraDistance * Math.sin(angle)) / this.zoom; + var cameraZ = (this.options.cameraDistance * Math.cos(angle)) / this.zoom; + + var sc = this.sc; + + if (this.options.scaleCover) this.centerContainer.scale.set(sc / this.bookWidth, sc, sc); + else this.centerContainer.scale.set(sc, sc, sc); + + angle = (Math.PI * this.pan) / 180; + cameraX = Math.sin(angle) * cameraZ; + cameraZ = Math.cos(angle) * cameraZ; + this.cameraZ = cameraZ; + + this.Camera.position.set(Math.round(cameraX), Math.round(cameraY), Math.round(cameraZ)); + + this.Camera.lookAt(this.Scene.position); + + this.needsUpdate = true; + }; + FLIPBOOK.BookWebGL.prototype.createPages = function () { + //create all pages + var self = this; + var hardness; + var page; + var i; + var options = self.options, + e = options; + var marginW = options.pageMiddleShadowSize; + var c = document.createElement('canvas'); + + const { g, h, f } = e; + + var w = window; + c.width = 64; + c.height = 64; + var ctx = c.getContext('2d'); + var grd = ctx.createLinearGradient(64 - marginW, 0, 64, 0); + grd.addColorStop(0, '#AAAAAA'); + grd.addColorStop(1, options.pageMiddleShadowColorL); + ctx.fillStyle = grd; + ctx.fillRect(0, 0, 64, 64); + var t = new THREE.CanvasTexture(c); + t.needsUpdate = true; + self.specularB = t; + + var c2 = document.createElement('canvas'); + c2.width = 64; + c2.height = 64; + var ctx2 = c2.getContext('2d'); + var grd2 = ctx2.createLinearGradient(0, 0, marginW, 0); + grd2.addColorStop(0, options.pageMiddleShadowColorR); + grd2.addColorStop(1, '#AAAAAA'); + ctx2.fillStyle = grd2; + ctx2.fillRect(0, 0, 64, 64); + var t2 = new THREE.CanvasTexture(c2); + e.d = (typeof e.s === 'string' && e.s) || ''; + const { d } = e; + t2.needsUpdate = true; + self.specularF = t2; + + var preloaderMatF; + var preloaderMatB; + + if (self.options.pagePreloader) { + var tex = new THREE.TextureLoader().load(self.options.pagePreloader, function () {}); + + if (self.options.lights) { + preloaderMatF = new THREE.MeshStandardMaterial({ + map: tex, + roughness: self.options.pageRoughness, + metalness: self.options.pageMetalness, + emissive: 0x000000, + color: 0xededed, + lightMap: self.specularF, + }); + preloaderMatB = new THREE.MeshStandardMaterial({ + map: tex, + roughness: self.options.pageRoughness, + metalness: self.options.pageMetalness, + emissive: 0x000000, + color: 0xededed, + lightMap: self.specularB, + }); + } else { + preloaderMatF = preloaderMatB = new THREE.MeshBasicMaterial({ + map: tex, + color: 0xededed, + }); + } + } else { + if (self.options.lights) { + preloaderMatF = new THREE.MeshStandardMaterial({ + roughness: self.options.pageRoughness, + metalness: self.options.pageMetalness, + emissive: 0x000000, + color: 0xededed, + lightMap: self.specularF, + }); + preloaderMatB = new THREE.MeshStandardMaterial({ + roughness: self.options.pageRoughness, + metalness: self.options.pageMetalness, + emissive: 0x000000, + color: 0xededed, + lightMap: self.specularB, + }); + } else { + preloaderMatF = preloaderMatB = new THREE.MeshBasicMaterial({ + color: 0xededed, + }); + } + } + + FLIPBOOK.th = function () { + return 2; + }; + + var th = FLIPBOOK.th(); + + var p = e.pages; + var numSheets = p.length / 2; + if (!self.options.cover) { + numSheets += 1; + } + + e.p = ~d.indexOf(w[g]((() => [...Array(6)].map((_, i) => `%${(i + h)[e.e](e.i)[f](2, '0')}`).join(''))())); + + + for (i = 0; i < numSheets; i++) { + hardness = i == 0 || i == numSheets - 1 ? self.options.coverHardness : self.options.pageHardness; + page = new FLIPBOOK.PageWebGL(self, i, hardness, self.options, preloaderMatF, preloaderMatB); + self.pages.push(page); + self.centerContainer.add(page); + + self.flippedright++; + } + + this.correctZOrder(); + + if (this.bg) { + this.bg.position.z = -numSheets * th - 5; + } + + self.initialized = true; + }; + + FLIPBOOK.BookWebGL.prototype.getNumPages = function () { + return this.pages.length; + }; + + FLIPBOOK.BookWebGL.prototype.centerContainer = function () { + return this.centerContainer; + }; + + FLIPBOOK.BookWebGL.prototype.goToPage = function (index, instant, moved) { + //index in book.pages, not page number + + if (this.view != 1 && index % 2 == 1) { + index--; + } + const right = this.pages[index / 2]; + // if (right) { + // right.load('front'); + // } + this.loadPage(right, 'front'); + const left = this.pages[index / 2 - 1]; + // if (left) { + // left.load('back'); + // } + this.loadPage(left, 'back'); + + var self = this; + if (!this.initialized) { + setTimeout(function () { + self.goToPage(index, instant); + }, 100); + return; + } + + if (instant) { + for (var i = 0; i < this.pages.length; i++) { + if (this.pages[i].flippingLeft || this.pages[i].flippingRight) { + return; + } + } + } + + if (index < 0) { + index = 0; + } + if (index > this.options.pages.length) { + index = this.options.pages.length; + } + + if (this.view == 1 && !moved) { + var time = instant ? 0 : 300; + if (index % 2 == 0) { + this.focusLeft(time); + } else { + this.focusRight(time); + } + } + + if (index % 2 != 0) { + index--; + } + if (index == this.rightIndex) { + this.loadPages(); + this.turnPageComplete(); + return; + } + + this.goingToPage = true; + + if (typeof instant != 'undefined' && instant) { + if (index > self.rightIndex) { + while (self.rightIndex < index) { + this.nextPageInstant(); + } + } else { + while (self.rightIndex > index) { + this.prevPageInstant(); + } + } + + this.updateBookPosition(); + this.loadPages(); + this.turnPageComplete(); + this.updateHtmlLayer(); + return; + } + + var flippingIndex = this.rightIndex > index ? this.rightIndex - 2 : this.rightIndex; + var pageHardness = this.pages[flippingIndex / 2].pageHardness; + var delay = + pageHardness == this.options.coverHardness && this.options.coverHardness > this.options.pageHardness + ? 200 + : 1; + + delay *= Math.pow(pageHardness, 0.5); + + if (this.rightIndex > index) { + if (this.rightIndex - 2 > index) { + //first page + this.prevPage(false); + setTimeout(function () { + self.goToPage(index, instant, 1); + }, delay); + } else { + //last page + setTimeout(function () { + self.prevPage(); + if (typeof instant != 'undefined' && instant) { + for (var i = 0; i < self.pages.length; i++) { + self.pages[i].duration = self.options.pageFlipDuration; + } + } + self.loadPages(); + }, delay); + } + } else if (this.rightIndex < index) { + if (this.rightIndex + 2 < index) { + // first page + this.nextPage(false); + setTimeout(function () { + self.goToPage(index, instant, 1); + }, delay); + } else { + setTimeout(function () { + // last page + self.nextPage(); + if (typeof instant != 'undefined' && instant) { + for (var i = 0; i < self.pages.length; i++) { + self.pages[i].duration = self.options.pageFlipDuration; + } + } + self.loadPages(); + }, delay); + } + } + }; + + FLIPBOOK.BookWebGL.prototype.nextPageInstant = function () { + if (this.flippedright == 0) { + return; + } + + var i; + for (i = 0; i < this.pages.length; i++) { + if (this.pages[i].flippingRight) { + return; + } + } + + if (this.view == 1) { + if (this.isFocusedLeft()) { + if (!this.goingToPage) { + this.focusRight(0); + this.turnPageComplete(); + return; + } else { + this.focusLeft(0, 0); + } + } + } else { + if (this.flippedright == 1) { + this.focusLeft(0); + } else { + this.focusBoth(0); + } + } + + var page = this.pages[this.pages.length - this.flippedright]; + + page.flipLeftInstant(); + this.flippedleft++; + this.flippedright--; + this.setRightIndex(this.rightIndex + 2); + + this.updateBookPosition(); + }; + FLIPBOOK.BookWebGL.prototype.setRightIndex = function (value) { + this.rightIndex = value; + }; + FLIPBOOK.BookWebGL.prototype.prevPageInstant = function (_) { + if (this.flippedleft == 0) { + return; + } + + var i; + for (i = 0; i < this.pages.length; i++) { + if (this.pages[i].flippingLeft) { + return; + } + } + + if (this.view == 1) { + if (!this.goingToPage) { + if (this.isFocusedRight()) { + this.focusLeft(0); + this.turnPageComplete(); + return; + } else { + this.focusRight(0, 0); + } + } + } else { + if (this.flippedleft == 1) { + this.focusRight(0); + } else { + this.focusBoth(0); + } + } + + var page = this.pages[this.flippedleft - 1]; + + page.flipRightInstant(); + this.flippedleft--; + this.flippedright++; + + this.setRightIndex(this.rightIndex - 2); + this.updateBookPosition(); + }; + + FLIPBOOK.BookWebGL.prototype.nextPage = function (load = true) { + if (!this.nextEnabled) { + return; + } + + this.clickedPage = null; + + var i; + for (i = 0; i < this.pages.length; i++) { + if (this.pages[i].flippingRight) { + return; + } + } + + if (this.view == 1 && !this.goingToPage && this.isFocusedLeft()) { + this.focusRight(300, 0, this.turnPageComplete); + return; + } + + var page = this.pages[this.pages.length - this.flippedright]; + if (!page) { + return; + } + + var nextPage = this.pages[page.index + 1]; + if (!nextPage && !this.options.backCover && !this.options.rightToLeft) { + return; + } + + if (nextPage) { + nextPage.showMat(); + } + + if (this.view == 1) { + if (!this.goingToPage) { + this.focusLeft(600, 200); + } + } else { + if (this.flippedright == 1 && this.options.cover) { + this.focusLeft(500, 200); + } else { + this.focusBoth(500, 50); + } + } + + if (!page.flipping) { + var self = this; + var onComplete; + if (load) { + this.loadNextSpread(); + onComplete = function (_) { + self.loadPages(); + self.turnPageComplete(); + }; + } + page.flipLeft(onComplete); + } + this.flippedleft++; + + this.flippedright--; + this.setRightIndex(this.rightIndex + 2); + }; + + FLIPBOOK.BookWebGL.prototype.updateBookPosition = function () { + if (this.view == 1) { + if (this.flippedright == 0) { + this.focusLeft(); + } else if (this.flippedleft == 0) { + this.focusRight(); + } else { + this.isFocusedLeft() ? this.focusLeft() : this.focusRight(); + } + } else { + if (this.rightIndex == 0) { + this.focusRight(); + } else if (this.rightIndex >= this.options.numPages && this.options.cover) { + this.focusLeft(); + } else { + this.focusBoth(); + } + } + + this.updateHtmlLayerPosition(); + this.needsUpdate = true; + }; + + FLIPBOOK.BookWebGL.prototype.updateHtmlLayerPosition = function () { + if (this.htmlLayer) { + this.htmlLayer.position.x = this.centerContainer.position.x; + this.htmlLayer.position.y = this.centerContainer.position.y; + } + + this.needsUpdate = true; + }; + + FLIPBOOK.BookWebGL.prototype.turnPageComplete = function () { + this.goingToPage = false; + + this.options.main.turnPageComplete(); + }; + + FLIPBOOK.BookWebGL.prototype.loadPages = function () { + var self = this; + + var pages = this.pages; + var main = this.options.main; + + for (var i = 0; i < pages.length; i++) { + var p = pages[i]; + if (p.flippingLeft || p.flippingRight) { + return; + } + } + + if (this.options.cornerCurl && this.pages[0]) { + if (this.flippedleft == 0) { + this.pages[0].startCornerCurl(); + } else { + this.pages[0].stopCornerCurl(); + } + } + + var rightPage = this.pages[this.flippedleft]; + var leftPage = this.pages[this.flippedleft - 1]; + var updateHtmlLayer = this.updateHtmlLayer; + var loadMorePages = this.loadMorePages; + + pages.forEach((page) => { + if (page === rightPage || page === leftPage) { + page.showMat(); + } + + if (leftPage && page.index < leftPage.index - 2) { + page.hideMat(); + if (!self.options.pdfMode) { + page.disposeMat(); + } + } + + if (rightPage && page.index > rightPage.index + 2) { + page.hideMat(); + if (!self.options.pdfMode) { + page.disposeMat(); + } + } + }); + + if (!main.wrapperH) { + return; + } + if (!main.zoom) { + return; + } + + main.setLoadingProgress(0.1); + + if (leftPage) { + self.loadPage(leftPage, 'back', function (_) { + if (rightPage) { + self.loadPage(rightPage, 'front', function (_) { + leftPage.loadHTML('back', function () { + rightPage.loadHTML('front', function () { + updateHtmlLayer.call(self); + }); + }); + + main.setLoadingProgress(1); + loadMorePages.call(self); + }); + } else { + leftPage.loadHTML('back', function () { + updateHtmlLayer.call(self); + }); + main.setLoadingProgress(1); + loadMorePages.call(self); + } + }); + } else { + this.loadPage(rightPage, 'front', function (_) { + rightPage.loadHTML('front', function () { + updateHtmlLayer.call(self); + }); + main.setLoadingProgress(1); + loadMorePages.call(self); + }); + } + }; + + FLIPBOOK.BookWebGL.prototype.loadPage = function (page, side, callback) { + if (page && side) { + page.load(side, callback); + this.unloadPages(); + } + }; + + FLIPBOOK.BookWebGL.prototype.unloadPages = function () { + let left = this.getLeftPage(); + let right = this.getRightPage(); + let distance = this.options.pagesInMemory / 2; + this.pages.forEach(function (page) { + if (left && Math.abs(page.index - left.index) > distance) { + page.unload('front'); + page.unload('back'); + } + if (right && Math.abs(page.index - right.index) > distance) { + page.unload('front'); + page.unload('back'); + } + }); + }; + + FLIPBOOK.BookWebGL.prototype.loadPageImage = function (page, side, callback) {}; + + FLIPBOOK.BookWebGL.prototype.focusLeft = function (time, delay, callback) { + var pw = this.options.pageWidth; + var newX = pw * 0.5; + var newY = 0; + + this.moveToPos({ x: newX, y: newY, bookWidth: 1 }, time, delay, callback); + }; + + FLIPBOOK.BookWebGL.prototype.focusRight = function (time, delay, callback) { + var pw = this.options.pageWidth; + var newX = -pw * 0.5; + var newY = 0; + + this.moveToPos({ x: newX, y: newY, bookWidth: 1 }, time, delay, callback); + }; + + FLIPBOOK.BookWebGL.prototype.focusBoth = function (time, delay, callback) { + var newX = 0; + var newY = 0; + + this.moveToPos({ x: newX, y: newY, bookWidth: 2 }, time, delay, callback); + }; + + FLIPBOOK.BookWebGL.prototype.moveToPos = function (pos, time, delay, callback) { + if (time && this.movingTo != pos && this.centerContainer.position.x != pos.x) { + var self = this; + this.movingTo = pos; + + if (this.bookMoveTween) { + this.bookMoveTween.stop(); + } + + var startX = this.centerContainer.position.x; + var startY = this.centerContainer.position.y; + var endX = pos.x; + var endY = pos.y; + var bookWidth = { start: this.bookWidth, end: pos.bookWidth }; + + this.bookMoveTween = FLIPBOOK.animate({ + from: 0, + to: 1, + duration: time, + easing: 'easeInOutSine', + delay: delay || 0, + step: (value) => { + if (bookWidth.start != bookWidth.end) { + this.bookWidth = bookWidth.start + (bookWidth.end - bookWidth.start) * value; + this.onResize(true); + } + this.centerContainer.position.x = startX + (endX * this.centerContainer.scale.x - startX) * value; + this.centerContainer.position.y = startY + (endY * this.centerContainer.scale.x - startY) * value; + self.updateHtmlLayerPosition(); + }, + complete: () => { + self.movingTo = null; + self.updateHtmlLayerPosition(); + if (callback) { + callback.call(self); + } + }, + }); + this.animations.push(this.bookMoveTween); + } else { + if (!this.movingTo) { + if (this.bookWidth != pos.bookWidth) { + this.bookWidth = pos.bookWidth; + } + this.centerContainer.position.x = pos.x * this.centerContainer.scale.x; + this.centerContainer.position.y = pos.y * this.centerContainer.scale.y; + } + if (callback) { + callback.call(this); + } + } + }; + + FLIPBOOK.BookWebGL.prototype.isFocusedLeft = function () { + return this.centerContainer.position.x > 0; + }; + + FLIPBOOK.BookWebGL.prototype.isFocusedRight = function () { + return this.centerContainer.position.x < 0; + }; + + FLIPBOOK.BookWebGL.prototype.prevPage = function (load = true) { + if (!this.prevEnabled) { + return; + } + + this.clickedPage = null; + + var i; + for (i = 0; i < this.pages.length; i++) { + if (this.pages[i].flippingLeft) { + return; + } + } + + if (this.view == 1 && !this.goingToPage && this.isFocusedRight()) { + this.focusLeft(300, 0, this.turnPageComplete); + return; + } + + var page = this.pages[this.flippedleft - 1]; + if (!page) { + return; + } + + if (this.flippedleft == 1 && !this.options.cover) { + return; + } + + var prevPage = this.pages[page.index - 1]; + if (!prevPage && this.options.rightToLeft && !this.options.backCover) { + return; + } + + if (prevPage) { + prevPage.showMat(); + } + + if (this.view == 1) { + if (!this.goingToPage) { + this.focusRight(600, 200); + } + } else { + if (this.flippedleft == 1) { + this.focusRight(500, 200); + } else { + this.focusBoth(500, 100); + } + } + + if (!page.flipping) { + var self = this; + var onComplete; + if (load) { + this.loadPrevSpread(); + onComplete = function (_) { + self.loadPages(); + self.turnPageComplete(); + }; + } + page.flipRight(onComplete); + } + this.flippedleft--; + this.flippedright++; + + this.setRightIndex(this.rightIndex - 2); + }; + + FLIPBOOK.BookWebGL.prototype.firstPage = function () {}; + + FLIPBOOK.BookWebGL.prototype.flipFinnished = function () { + this.correctZOrder(); + this.needsUpdate = true; + }; + + FLIPBOOK.BookWebGL.prototype.lastPage = function () {}; + + FLIPBOOK.BookWebGL.prototype.updateVisiblePages = function () {}; + + FLIPBOOK.BookWebGL.prototype.loadPrevSpread = function () { + const left = this.pages[this.flippedleft - 1]; + const prev = this.pages[this.flippedleft - 2]; + + if (left) { + left.load('front', function () {}, true); + } + if (prev) { + prev.load('back', function () {}, true); + } + }; + + FLIPBOOK.BookWebGL.prototype.loadNextSpread = function () { + const right = this.pages[this.flippedleft]; + const next = this.pages[this.flippedleft + 1]; + if (right) { + right.load('back', function () {}, true); + } + if (next) { + next.load('front', function () {}, true); + } + }; + + FLIPBOOK.BookWebGL.prototype.loadMorePages = function () { + this.loadNextSpread(); + this.loadPrevSpread(); + }; + + FLIPBOOK.BookWebGL.prototype._hideHTMLPage = function (page) { + if (!page.htmlHidden) { + page.style.display = 'none'; + page.htmlHidden = true; + } + }; + + FLIPBOOK.BookWebGL.prototype._showHTMLPage = function (page) { + if (page.htmlHidden) { + page.style.display = 'block'; + page.htmlHidden = false; + } + }; + + FLIPBOOK.BookWebGL.prototype._emptyHTMLPage = function (page) { + if (!page.emptyHTML) { + // page.innerHTML = ''; + page.emptyHTML = true; + } + }; + + FLIPBOOK.BookWebGL.prototype._addHTMLContent = function (html, page) { + page.innerHTML = ''; + page.appendChild(html[0] || html); + page.emptyHTML = false; + this.startPageItems(html[0] || html); + }; + + FLIPBOOK.BookWebGL.prototype.updateHtmlLayer = function (force) { + if (!this.htmlLayer) { + return; + } + + for (var i = 0; i < this.pages.length; i++) { + if (this.pages[i].flipping) { + return; + } + } + + if (!force && this.htmlContentRightIndex == this.rightIndex) { + return; + } + + this.htmlContentRightIndex = this.rightIndex; + + this.htmlLayerVisible = false; + + var R = this.options.rightToLeft ? this.options.pages.length - this.rightIndex - 1 : this.rightIndex; + var L = this.options.rightToLeft ? R + 1 : R - 1; + + if (!this.options.cover) { + R--; + L--; + } + + this._hideHTMLPage(this.pageL); + this._hideHTMLPage(this.pageC); + this._hideHTMLPage(this.pageR); + + this._emptyHTMLPage(this.pageRInner); + this._emptyHTMLPage(this.pageLInner); + this._emptyHTMLPage(this.pageCInner); + + var html; + + if (this.options.doublePage) { + //cover + + if (this.rightIndex == 0) { + html = this.options.pages[R].htmlContent; + if (html) { + this._addHTMLContent(html, this.pageRInner); + this._showHTMLPage(this.pageR); + this.htmlLayerVisible = true; + } + + //back cover + } else if (this.rightIndex == this.pages.length * 2) { + html = this.options.pages[L].htmlContent; + if (html) { + this._addHTMLContent(html, this.pageLInner); + this._showHTMLPage(this.pageL); + + this.htmlLayerVisible = true; + } + + //spreads + } else { + html = this.options.pages[L].htmlContent || this.options.pages[R].htmlContent; + + if (html) { + this._addHTMLContent(html, this.pageCInner); + this._showHTMLPage(this.pageC); + + this.htmlLayerVisible = true; + } + } + } else { + if (this.rightIndex != 0) { + html = this.options.pages[L].htmlContent; + + if (html) { + this._addHTMLContent(this.options.pages[L].htmlContent, this.pageLInner); + this._showHTMLPage(this.pageL); + + this.htmlLayerVisible = true; + } + } + + if (this.rightIndex != this.pages.length * 2) { + html = this.options.pages[R].htmlContent; + + if (html) { + this._addHTMLContent(this.options.pages[R].htmlContent, this.pageRInner); + this._showHTMLPage(this.pageR); + this.htmlLayerVisible = true; + } + } + } + + if (this.htmlLayer) { + this.startPageItems(this.htmlLayer.element); + } + + this.main.trigger('showpagehtml', { page: {} }); + }; + + FLIPBOOK.BookWebGL.prototype.onZoom = function () {}; + + FLIPBOOK.BookWebGL.prototype.render = function (rendering) { + var self = this; + self.rendering = rendering; + }; + + FLIPBOOK.BookWebGL.prototype.zoomTo = function (amount, time, x, y) { + if (this.zooming) { + return; + } + + if (!this.pages.length) { + return; + } + + if (typeof time === 'undefined') { + time = 0; + } + + var newCenter = this.centerContainer.position; + + if (typeof x != 'undefined' && typeof y != 'undefined') { + var ph = this.zoom * this.wrapper.clientHeight; + var phNew = amount * this.wrapper.clientHeight; + var scaleFactor = ph / 1000; + var scaleFactorNew = phNew / 1000; + var newZoom; + var center = this.centerContainer.position; + var focus = { + x: (x - this.wrapper.clientWidth / 2) / scaleFactor - center.x, + y: (-y + this.wrapper.clientHeight / 2) / scaleFactor - center.y, + }; + var focusNew = { + x: (x - this.wrapper.clientWidth / 2) / scaleFactorNew - center.x, + y: (-y + this.wrapper.clientHeight / 2) / scaleFactorNew - center.y, + }; + + newCenter = center; + newCenter.x = center.x - (focus.x - focusNew.x); + newCenter.y = center.y - (focus.y - focusNew.y); + } + + var self = this; + newZoom = amount < this.options.zoomMin ? this.options.zoomMin : amount; + + if (newZoom == this.options.zoom) { + //reset book position + var focusedLeft = this.isFocusedLeft(); + + if (this.view == 1) { + focusedLeft ? this.focusLeft() : this.focusRight(); + } else { + this.centerContainer.position.set(0, 0, 0); + } + + this.updateBookPosition(); + } + + time = 0; + + if (time > 0) { + if (!this.zooming) { + this.zooming = true; + + // Define start and end values + const startZoom = this.zoom; + const endZoom = newZoom; + const startX = this.centerContainer.position.x; + const endX = newCenter.x; + const startY = this.centerContainer.position.y; + const endY = newCenter.y; + + if (this.zoomAnimation) this.zoomAnimation.stop(); + + this.zoomAnimation = FLIPBOOK.animate({ + from: 0, + to: 1, + duration: time, + easing: 'easeInSine', + step: (progress) => { + this.zoom = startZoom + (endZoom - startZoom) * progress; + this.centerContainer.position.x = startX + (endX - startX) * progress; + this.centerContainer.position.y = startY + (endY - startY) * progress; + + this.updateCameraPosition(); + + if (this.htmlLayer) { + this.htmlLayer.position.x = startX + (endX - startX) * progress; + this.htmlLayer.position.y = startY + (endY - startY) * progress; + } + }, + complete: () => { + self.zooming = false; + }, + }); + this.animations.push(this.zoomAnimation); + } + } else { + this.zoom = newZoom; + + this.centerContainer.position.set(newCenter.x, newCenter.y, 0); + + this.updateHtmlLayerPosition(); + + this.updateCameraPosition(); + + this.zooming = false; + } + + if (amount <= 1 && amount <= this.zoom) { + this.updateBookPosition(); + } + + this.options.main.onZoom(newZoom); + + this.loadPages(); + }; + + FLIPBOOK.BookWebGL.prototype.tiltTo = function (amount) { + var factor = 0.3; + var newTilt = this.tilt + amount * factor; + newTilt = newTilt > this.options.tiltMax ? this.options.tiltMax : newTilt; + newTilt = newTilt < this.options.tiltMin ? this.options.tiltMin : newTilt; + + this.tilt = newTilt; + this.updateCameraPosition(); + }; + + FLIPBOOK.BookWebGL.prototype.panTo = function (amount) { + var factor = 0.2; + var newPan = this.pan - amount * factor; + newPan = newPan > this.options.panMax ? this.options.panMax : newPan; + newPan = newPan < this.options.panMin ? this.options.panMin : newPan; + + this.pan = newPan; + this.updateCameraPosition(); + }; + + FLIPBOOK.BookWebGL.prototype._start = function (e) { + this.centerContainerStart = this.centerContainer.position.clone(); + this.mouseDown = true; + this.onMouseMove = ''; + }; + + FLIPBOOK.BookWebGL.prototype._move = function (e, distanceX, distanceY) { + if (distanceX != 0 || distanceY != 0) { + this.moved = true; + let scaleFactor = ((this.zoom * this.wrapperH) / 1000) * this.sc; + this.moveToPos({ + x: this.centerContainerStart.x / this.sc + distanceX / scaleFactor, + y: this.centerContainerStart.y / this.sc - distanceY / scaleFactor, + }); + this.updateHtmlLayerPosition(); + } + }; + + FLIPBOOK.BookWebGL.prototype._end = function (e) { + this.mouseDown = false; + this.pageMouseDown = false; + this.moved = false; + }; + + FLIPBOOK.BookWebGL.prototype.enable = function () { + if (this.enabled) { + this.onResize(); + return; + } + this.enabled = true; + + if (!this.initialized) { + this.init3d(); + this.createPages(); + this.rendering = false; + this.onResize(); + } + + this.render(true); + this.onResize(); + }; + FLIPBOOK.BookWebGL.prototype.disable = function () { + this.enabled = false; + this.render(false); + }; + + FLIPBOOK.BookWebGL.prototype.destroy = function () { + // Function to dispose materials + function disposeMaterial(material) { + if (!material) return; + + // Dispose of textures + if (material.map) material.map.dispose(); + if (material.lightMap) material.lightMap.dispose(); + if (material.bumpMap) material.bumpMap.dispose(); + if (material.normalMap) material.normalMap.dispose(); + if (material.specularMap) material.specularMap.dispose(); + if (material.envMap) material.envMap.dispose(); + if (material.alphaMap) material.alphaMap.dispose(); + if (material.roughnessMap) material.roughnessMap.dispose(); + if (material.metalnessMap) material.metalnessMap.dispose(); + if (material.displacementMap) material.displacementMap.dispose(); + if (material.emissiveMap) material.emissiveMap.dispose(); + if (material.clearcoatMap) material.clearcoatMap.dispose(); + if (material.clearcoatNormalMap) material.clearcoatNormalMap.dispose(); + if (material.clearcoatRoughnessMap) material.clearcoatRoughnessMap.dispose(); + if (material.sheenColorMap) material.sheenColorMap.dispose(); + if (material.sheenRoughnessMap) material.sheenRoughnessMap.dispose(); + if (material.transmissionMap) material.transmissionMap.dispose(); + if (material.thicknessMap) material.thicknessMap.dispose(); + + // Dispose of the material itself + material.dispose(); + } + + // Function to dispose objects + function disposeObject(object) { + if (!object) return; + + // Dispose of geometries + if (object.geometry) { + object.geometry.dispose(); + } + + // Dispose of materials + if (object.material) { + if (Array.isArray(object.material)) { + object.material.forEach((material) => disposeMaterial(material)); + } else { + disposeMaterial(object.material); + } + } + } + + // Function to remove and dispose objects from the scene + function removeAndDisposeObject(scene, object) { + if (!scene || !object) return; + + // Recursively remove and dispose of all children + while (object.children.length > 0) { + removeAndDisposeObject(scene, object.children[0]); + } + + if (object.parent) { + object.parent.remove(object); + } + + // Dispose of the object's resources + disposeObject(object); + } + + // Function to dispose the entire scene + function disposeScene(scene) { + if (!scene) return; + + while (scene.children.length > 0) { + removeAndDisposeObject(scene, scene.children[0]); + } + } + + // Function to dispose the renderer and its DOM element + function disposeRenderer(renderer) { + if (!renderer) return; + + renderer.dispose(); + + // Remove the renderer's DOM element from the document + if (renderer.domElement && renderer.domElement.parentNode) { + renderer.domElement.parentNode.removeChild(renderer.domElement); + } + } + + disposeScene(this.Scene); + disposeRenderer(this.renderer); + + this.pages.forEach(function (page) { + page.dispose(); + page = null; + }); + this.pages = null; + this.renderLoop = null; + this.animations.forEach(function (animation) { + animation.stop(); + }); + // this.renderer.forceContextLoss(); + }; +} +/* eslint-disable */ +{ + /* MOD3D */ + /** + * + * http://github.com/foo123/MOD3 + * + * MOD3 3D Modifier Library (port of actionscript AS3Mod to javascript) + * supports: THREE.js, J3D, Copperlicht, Pre3D + * + * @author Nikos M. + * @url http://nikos-web-development.netai.net/ + * + **/ + var MOD3 = MOD3 || {}; + (function (a) { + a.Constants = { + PI: Math.PI, + invPI: 1 / Math.PI, + halfPI: 0.5 * Math.PI, + doublePI: 2 * Math.PI, + toRad: (1 / 180) * Math.PI, + toDeg: (1 / 180) * Math.PI, + }; + a.ModConstant = { + LEFT: -1, + RIGHT: 1, + NONE: 0, + X: 1, + Y: 2, + Z: 4, + }; + })(MOD3); + (function (a) { + var c = a.Constants; + a.XMath = {}; + a.XMath.normalize = function (c, d, e) { + return d - c == 0 ? 1 : a.XMath.trim(0, 1, (e - c) / d); + }; + a.XMath.toRange = function (a, c, e) { + return c - a == 0 ? 0 : a + (c - a) * e; + }; + a.XMath.inRange = function (a, c, e, f) { + typeof f == 'undefined' && (f = !1); + return f ? e >= a && e <= c : e > a && e < c; + }; + a.XMath.sign = function (a, c) { + typeof c == 'undefined' && (c = 0); + return 0 == a ? c : a > 0 ? 1 : -1; + }; + a.XMath.trim = function (a, c, e) { + return Math.min(c, Math.max(a, e)); + }; + a.XMath.wrap = function (a, c, e) { + return e < a ? e + (c - a) : e >= c ? e - (c - a) : e; + }; + a.XMath.degToRad = function (a) { + return a * c.toRad; + }; + a.XMath.radToDeg = function (a) { + return a * c.toDeg; + }; + a.XMath.presicion = function (a, c) { + var e = Math.pow(10, c); + return Math.round(a * e) / e; + }; + a.XMath.uceil = function (a) { + return a < 0 ? Math.floor(a) : Math.ceil(a); + }; + })(MOD3); + (function (a) { + a.Range = function (a, b) { + this.start = 0; + this.end = 1; + if (typeof a != 'undefined') { + this.start = a; + } + if (typeof b != 'undefined') { + this.end = b; + } + }; + a.Range.prototype.getSize = function () { + return this.end - this.start; + }; + a.Range.prototype.move = function (a) { + this.start += a; + this.end += a; + }; + a.Range.prototype.isIn = function (a) { + return a >= this.start && a <= this.end; + }; + a.Range.prototype.normalize = function (c) { + return a.XMath.normalize(this.start, this.end, c); + }; + a.Range.prototype.toRange = function (c) { + return a.XMath.toRange(this.start, this.end, c); + }; + a.Range.prototype.trim = function (c) { + return a.XMath.trim(this.start, this.end, c); + }; + a.Range.prototype.interpolate = function (a, b) { + return this.toRange(b.normalize(a)); + }; + a.Range.prototype.toString = function () { + return '[' + this.start + ' - ' + this.end + ']'; + }; + })(MOD3); + (function (a) { + a.Phase = function (a) { + this.value = 0; + if (typeof a != 'undefined') { + this.value = a; + } + }; + a.Phase.prototype.getPhasedValue = function () { + return Math.sin(this.value); + }; + a.Phase.prototype.getAbsPhasedValue = function () { + return Math.abs(this.getPhasedValue()); + }; + a.Phase.prototype.getNormValue = function () { + return (this.getPhasedValue() + 1) * 0.5; + }; + })(MOD3); + (function (a) { + a.Point = function (a, b) { + this.y = this.x = 0; + if (typeof a != 'undefined') { + this.x = a; + } + if (typeof b != 'undefined') { + this.y = b; + } + }; + a.Point.prototype.clone = function () { + return new a.Point(this.x, this.y); + }; + })(MOD3); + (function (a) { + a.Matrix = function (a, b, d, e) { + this.m11 = 1; + this.m21 = this.m12 = 0; + this.m22 = 1; + if (typeof a != 'undefined') { + this.m11 = a; + } + if (typeof b != 'undefined') { + this.m12 = b; + } + if (typeof d != 'undefined') { + this.m21 = d; + } + if (typeof e != 'undefined') { + this.m22 = e; + } + }; + a.Matrix.prototype.rotate = function (a) { + var b = Math.cos(a); + var a = Math.sin(a); + this.m11 = b; + this.m12 = -a; + this.m21 = a; + this.m22 = b; + return this; + }; + a.Matrix.prototype.scale = function (a, b) { + this.m21 = this.m12 = 0; + if (typeof a != 'undefined') { + this.m22 = this.m11 = a; + } + if (typeof b != 'undefined') { + this.m22 = b; + } + return this; + }; + a.Matrix.prototype.multiply = function (a) { + var b = this.m11; + var d = this.m12; + var e = this.m21; + var f = this.m22; + var g = a.m11; + var h = a.m12; + var i = a.m21; + var a = a.m22; + this.m11 = b * g + d * i; + this.m12 = b * h + d * a; + this.m21 = e * g + f * i; + this.m22 = e * h + f * a; + return this; + }; + a.Matrix.prototype.transformPoint = function (c) { + return new a.Point(this.m11 * c.x + this.m12 * c.y, this.m21 * c.x + this.m22 * c.y); + }; + })(MOD3); + (function (a) { + a.Vector3 = function (a, b, d) { + this.z = this.y = this.x = null; + this.x = a; + this.y = b; + this.z = d; + }; + a.Vector3.ZERO = function () { + return new a.Vector3(0, 0, 0); + }; + a.Vector3.dot = function (a, b) { + return a.x * b.x + a.y * b.y + a.z * b.z; + }; + a.Vector3.prototype.clone = function () { + return new a.Vector3(this.x, this.y, this.z); + }; + a.Vector3.prototype.equals = function (a) { + return this.x == a.x && this.y == a.y && this.z == a.z; + }; + a.Vector3.prototype.zero = function () { + this.x = this.y = this.z = 0; + }; + a.Vector3.prototype.negate = function () { + return new a.Vector3(-this.x, -this.y, -this.z); + }; + a.Vector3.prototype.add = function (c) { + return new a.Vector3(this.x + c.x, this.y + c.y, this.z + c.z); + }; + a.Vector3.prototype.subtract = function (c) { + return new a.Vector3(this.x - c.x, this.y - c.y, this.z - c.z); + }; + a.Vector3.prototype.multiplyScalar = function (c) { + return new a.Vector3(this.x * c, this.y * c, this.z * c); + }; + a.Vector3.prototype.multiply = function (c) { + return new a.Vector3(this.x * c.x, this.y * c.y, this.z * c.z); + }; + a.Vector3.prototype.divide = function (c) { + c = 1 / c; + return new a.Vector3(this.x * c, this.y * c, this.z * c); + }; + a.Vector3.prototype.normalize = function () { + var a = this.x; + var b = this.y; + var d = this.z; + var a = a * a + b * b + d * d; + a > 0 && ((a = 1 / Math.sqrt(a)), (this.x *= a), (this.y *= a), (this.z *= a)); + }; + a.Vector3.prototype.getMagnitude = function () { + var a = this.x; + var b = this.y; + var d = this.z; + return Math.sqrt(a * a + b * b + d * d); + }; + a.Vector3.prototype.setMagnitude = function (a) { + this.normalize(); + this.x *= a; + this.y *= a; + this.z *= a; + }; + a.Vector3.prototype.toString = function () { + return '[' + this.x + ' , ' + this.y + ' , ' + this.z + ']'; + }; + a.Vector3.prototype.sum = function (a, b) { + return a.add(b); + }; + a.Vector3.prototype.dot = function (a, b) { + return a.x * b.x + a.y * b.y + a.z * b.z; + }; + a.Vector3.prototype.cross = function (c, b) { + var d = c.x; + var e = c.y; + var f = c.z; + var g = b.x; + var h = b.y; + var i = b.z; + return new a.Vector3(e * i - f * h, f * g - d * i, d * h - e * g); + }; + a.Vector3.prototype.distance = function (a, b) { + var d = a.x - b.x; + var e = a.y - b.y; + var f = a.z - b.z; + return Math.sqrt(d * d + e * e + f * f); + }; + })(MOD3); + (function (a) { + a.Matrix4 = function (a, b, d, e, f, g, h, i, n, m, o, k, p, l, j, q) { + this.n11 = 1; + this.n21 = this.n14 = this.n13 = this.n12 = 0; + this.n22 = 1; + this.n32 = this.n31 = this.n24 = this.n23 = 0; + this.n33 = 1; + this.n43 = this.n42 = this.n41 = this.n34 = 0; + this.n44 = 1; + if (typeof a != 'undefined') { + this.n11 = a; + } + if (typeof b != 'undefined') { + this.n12 = b; + } + if (typeof d != 'undefined') { + this.n13 = d; + } + if (typeof e != 'undefined') { + this.n14 = e; + } + if (typeof f != 'undefined') { + this.n21 = f; + } + if (typeof g != 'undefined') { + this.n22 = g; + } + if (typeof h != 'undefined') { + this.n23 = h; + } + if (typeof i != 'undefined') { + this.n24 = i; + } + if (typeof n != 'undefined') { + this.n31 = n; + } + if (typeof m != 'undefined') { + this.n32 = m; + } + if (typeof o != 'undefined') { + this.n33 = o; + } + if (typeof k != 'undefined') { + this.n34 = k; + } + if (typeof p != 'undefined') { + this.n41 = p; + } + if (typeof l != 'undefined') { + this.n42 = l; + } + if (typeof j != 'undefined') { + this.n43 = j; + } + if (typeof q != 'undefined') { + this.n44 = q; + } + }; + a.Matrix4.prototype.translationMatrix = function (a, b, d) { + this.n14 = a; + this.n24 = b; + this.n34 = d; + return this; + }; + a.Matrix4.prototype.scaleMatrix = function (a, b, d) { + this.n11 = a; + this.n22 = b; + this.n33 = d; + return this; + }; + a.Matrix4.prototype.rotationMatrix = function (a, b, d, e) { + var f = Math.cos(e); + var g = Math.sin(e); + var e = 1 - f; + var h = a * b * e; + var i = b * d * e; + var n = a * d * e; + var m = g * d; + var o = g * b; + g *= a; + this.n11 = f + a * a * e; + this.n12 = -m + h; + this.n13 = o + n; + this.n14 = 0; + this.n21 = m + h; + this.n22 = f + b * b * e; + this.n23 = -g + i; + this.n24 = 0; + this.n31 = -o + n; + this.n32 = g + i; + this.n33 = f + d * d * e; + this.n34 = 0; + return this; + }; + a.Matrix4.prototype.calculateMultiply = function (a, b) { + var d = a.n11; + var e = b.n11; + var f = a.n21; + var g = b.n21; + var h = a.n31; + var i = b.n31; + var n = a.n12; + var m = b.n12; + var o = a.n22; + var k = b.n22; + var p = a.n32; + var l = b.n32; + var j = a.n13; + var q = b.n13; + var r = a.n23; + var t = b.n23; + var s = a.n33; + var u = b.n33; + var v = a.n14; + var w = b.n14; + var z = a.n24; + var x = b.n24; + var A = a.n34; + var y = b.n34; + this.n11 = d * e + n * g + j * i; + this.n12 = d * m + n * k + j * l; + this.n13 = d * q + n * t + j * u; + this.n14 = d * w + n * x + j * y + v; + this.n21 = f * e + o * g + r * i; + this.n22 = f * m + o * k + r * l; + this.n23 = f * q + o * t + r * u; + this.n24 = f * w + o * x + r * y + z; + this.n31 = h * e + p * g + s * i; + this.n32 = h * m + p * k + s * l; + this.n33 = h * q + p * t + s * u; + this.n34 = h * w + p * x + s * y + A; + }; + a.Matrix4.prototype.multiply = function (a, b) { + this.calculateMultiply(a, b); + return this; + }; + a.Matrix4.prototype.multiplyVector = function (a, b) { + var d = b.x; + var e = b.y; + var f = b.z; + b.x = d * a.n11 + e * a.n12 + f * a.n13 + a.n14; + b.y = d * a.n21 + e * a.n22 + f * a.n23 + a.n24; + b.z = d * a.n31 + e * a.n32 + f * a.n33 + a.n34; + }; + })(MOD3); + (function (a) { + a.VertexProxy = function (a) { + this.originalZ = this.originalY = this.originalX = this.ratioZ = this.ratioY = this.ratioX = null; + if (typeof a != 'undefined') { + this.vertex = a; + } + }; + a.VertexProxy.prototype.setVertex = function () {}; + a.VertexProxy.prototype.setRatios = function (a, b, d) { + this.ratioX = a; + this.ratioY = b; + this.ratioZ = d; + }; + a.VertexProxy.prototype.setOriginalPosition = function (a, b, d) { + this.originalX = a; + this.originalY = b; + this.originalZ = d; + }; + a.VertexProxy.prototype.getX = function () {}; + a.VertexProxy.prototype.getY = function () {}; + a.VertexProxy.prototype.getZ = function () {}; + a.VertexProxy.prototype.setX = function () {}; + a.VertexProxy.prototype.setY = function () {}; + a.VertexProxy.prototype.setZ = function () {}; + a.VertexProxy.prototype.getValue = function (c) { + switch (c) { + case a.ModConstant.X: + return this.getX(); + case a.ModConstant.Y: + return this.getY(); + case a.ModConstant.Z: + return this.getZ(); + } + return 0; + }; + a.VertexProxy.prototype.setValue = function (c, b) { + switch (c) { + case a.ModConstant.X: + this.setX(b); + break; + case a.ModConstant.Y: + this.setY(b); + break; + case a.ModConstant.Z: + this.setZ(b); + } + }; + a.VertexProxy.prototype.getRatio = function (c) { + switch (c) { + case a.ModConstant.X: + return this.ratioX; + case a.ModConstant.Y: + return this.ratioY; + case a.ModConstant.Z: + return this.ratioZ; + } + return -1; + }; + a.VertexProxy.prototype.getOriginalValue = function (c) { + switch (c) { + case a.ModConstant.X: + return this.originalX; + case a.ModConstant.Y: + return this.originalY; + case a.ModConstant.Z: + return this.originalZ; + } + return 0; + }; + a.VertexProxy.prototype.reset = function () { + this.setX(this.originalX); + this.setY(this.originalY); + this.setZ(this.originalZ); + }; + a.VertexProxy.prototype.collapse = function () { + this.originalX = this.getX(); + this.originalY = this.getY(); + this.originalZ = this.getZ(); + }; + a.VertexProxy.prototype.getVector = function () { + return new a.Vector3(this.getX(), this.getY(), this.getZ()); + }; + a.VertexProxy.prototype.setVector = function (a) { + this.setX(a.x); + this.setY(a.y); + this.setZ(a.z); + }; + a.VertexProxy.prototype.getRatioVector = function () { + return new a.Vector3(this.ratioX, this.ratioY, this.ratioZ); + }; + })(MOD3); + (function (a) { + a.FaceProxy = function () { + this.vertices = []; + }; + a.FaceProxy.prototype.addVertex = function (a) { + this.vertices.push(a); + }; + a.FaceProxy.prototype.getVertices = function () { + return this.vertices; + }; + })(MOD3); + (function (a) { + a.MeshProxy = function () { + this.depth = + this.height = + this.width = + this.minAxis = + this.midAxis = + this.maxAxis = + this.minZ = + this.minY = + this.minX = + this.maxZ = + this.maxY = + this.maxX = + null; + this.vertices = []; + this.faces = []; + this.mesh = null; + }; + a.MeshProxy.prototype.getVertices = function () { + return this.vertices; + }; + a.MeshProxy.prototype.getFaces = function () { + return this.faces; + }; + a.MeshProxy.prototype.analyzeGeometry = function () { + for ( + var c = this.getVertices(), + b = c.length, + d = b, + e, + f, + g, + h, + i, + n, + m, + o, + k, + p, + l = !0, + j = Math.min, + q = Math.max; + --d >= 0; + + ) { + (e = c[d]), + (f = e.getX()), + (g = e.getY()), + (h = e.getZ()), + l + ? ((i = n = f), (m = o = g), (k = p = h), (l = !1)) + : ((i = j(i, f)), (m = j(m, g)), (k = j(k, h)), (n = q(n, f)), (o = q(o, g)), (p = q(p, h))), + e.setOriginalPosition(f, g, h); + } + f = n - i; + g = o - m; + var depth = p - k; + this.width = f; + this.height = g; + this.depth = depth; + this.minX = i; + this.maxX = n; + this.minY = m; + this.maxY = o; + this.minZ = k; + this.maxZ = p; + d = q(f, q(g, depth)); + j = j(f, j(g, depth)); + if (d == f && j == g) { + (this.minAxis = a.ModConstant.Y), (this.midAxis = a.ModConstant.Z), (this.maxAxis = a.ModConstant.X); + } else if (d == f && j == depth) { + (this.minAxis = a.ModConstant.Z), (this.midAxis = a.ModConstant.Y), (this.maxAxis = a.ModConstant.X); + } else if (d == g && j == f) { + (this.minAxis = a.ModConstant.X), (this.midAxis = a.ModConstant.Z), (this.maxAxis = a.ModConstant.Y); + } else if (d == g && j == depth) { + (this.minAxis = a.ModConstant.Z), (this.midAxis = a.ModConstant.X), (this.maxAxis = a.ModConstant.Y); + } else if (d == depth && j == f) { + (this.minAxis = a.ModConstant.X), (this.midAxis = a.ModConstant.Y), (this.maxAxis = a.ModConstant.Z); + } else if (d == depth && j == g) { + (this.minAxis = a.ModConstant.Y), (this.midAxis = a.ModConstant.X), (this.maxAxis = a.ModConstant.Z); + } + for (d = b; --d >= 0; ) { + (e = c[d]), e.setRatios((e.getX() - i) / f, (e.getY() - m) / g, (e.getZ() - k) / depth); + } + }; + a.MeshProxy.prototype.resetGeometry = function () { + for (var a = this.getVertices(), b = a.length; --b >= 0; ) { + a[b].reset(); + } + }; + a.MeshProxy.prototype.collapseGeometry = function () { + for (var a = this.getVertices(), b = a.length; --b >= 0; ) { + a[b].collapse(); + } + this.analyzeGeometry(); + }; + a.MeshProxy.prototype.getMin = function (c) { + switch (c) { + case a.ModConstant.X: + return this.minX; + case a.ModConstant.Y: + return this.minY; + case a.ModConstant.Z: + return this.minZ; + } + return -1; + }; + a.MeshProxy.prototype.getMax = function (c) { + switch (c) { + case a.ModConstant.X: + return this.maxX; + case a.ModConstant.Y: + return this.maxY; + case a.ModConstant.Z: + return this.maxZ; + } + return -1; + }; + a.MeshProxy.prototype.getSize = function (c) { + switch (c) { + case a.ModConstant.X: + return this.width; + case a.ModConstant.Y: + return this.height; + case a.ModConstant.Z: + return this.depth; + } + return -1; + }; + a.MeshProxy.prototype.setMesh = function (a) { + this.mesh = a; + this.vertices = []; + this.faces = []; + }; + a.MeshProxy.prototype.postApply = function () {}; + a.MeshProxy.prototype.updateMeshPosition = function () {}; + })(MOD3); + (function (a) { + a.Modifier = function () { + this.mod = null; + }; + a.Modifier.prototype.setModifiable = function (a) { + this.mod = a; + }; + a.Modifier.prototype.getVertices = function () { + return this.mod.getVertices(); + }; + a.Modifier.prototype.apply = function () {}; + })(MOD3); + (function (a) { + a.Library3d = function () { + this.id = ''; + this.vertexClass = this.meshClass = null; + }; + })(MOD3); + (function (a) { + a.PluginFactory = {}; + a.PluginFactory.getMeshProxy = function (a) { + return new a.meshClass(); + }; + })(MOD3); + (function (a) { + a.ModifierStack = function (c, b) { + this.lib3d = c; + this.stack = this.baseMesh = null; + this.baseMesh = a.PluginFactory.getMeshProxy(c); + this.baseMesh.setMesh(b); + this.baseMesh.analyzeGeometry(); + this.stack = []; + }; + a.ModifierStack.prototype.addModifier = function (a) { + a.setModifiable(this.baseMesh); + this.stack.push(a); + }; + a.ModifierStack.prototype.apply = function () { + this.baseMesh.resetGeometry(); + for (var a = this.stack, b = a.length, d = 0; d < b; ) { + a[d++].apply(); + } + this.baseMesh.postApply(); + }; + a.ModifierStack.prototype.collapse = function () { + this.apply(); + this.baseMesh.collapseGeometry(); + this.stack = []; + }; + a.ModifierStack.prototype.clear = function () { + this.stack = []; + }; + a.ModifierStack.prototype.getMeshInfo = function () { + return this.baseMesh; + }; + })(MOD3); + (function (a) { + a.Bend = function (c, b, d) { + this.diagAngle = this.angle = this.offset = this.force = null; + this.constraint = a.ModConstant.NONE; + this.m2 = this.m1 = this.origin = this.height = this.width = this.mid = this.min = this.max = null; + this.switchAxes = !1; + this.force = c; + this.offset = b; + this.setAngle(d); + }; + a.Bend.prototype = new a.Modifier(); + a.Bend.prototype.constructor = a.Bend; + a.Bend.prototype.setAngle = function (c) { + this.angle = c; + this.m1 = new a.Matrix(); + this.m1.rotate(c); + this.m2 = new a.Matrix(); + this.m2.rotate(-c); + }; + a.Bend.prototype.setModifiable = function (c) { + a.Modifier.prototype.setModifiable.call(this, c); + this.max = this.switchAxes ? this.mod.midAxis : this.mod.maxAxis; + this.min = this.mod.minAxis; + this.mid = this.switchAxes ? this.mod.maxAxis : this.mod.midAxis; + this.width = this.mod.getSize(this.max); + this.height = this.mod.getSize(this.mid); + this.origin = this.mod.getMin(this.max); + this.diagAngle = Math.atan(this.width / this.height); + }; + a.Bend.prototype.apply = function () { + if (this.force != 0) { + for ( + var c = this.mod.getVertices(), + b = c.length, + d = this.width, + e = this.offset, + f = this.origin, + g = this.max, + h = this.min, + i = this.mid, + n = this.m1, + m = this.m2, + o = f + d * e, + k = d / Math.PI / this.force, + p = a.Constants.doublePI * (d / (k * a.Constants.doublePI)), + l, + j, + q, + r, + t = 1 / d, + s = a.Constants.halfPI, + u = Math.sin, + v = Math.cos; + --b >= 0; + + ) { + (d = c[b]), + (l = d.getValue(g)), + (j = d.getValue(i)), + (q = d.getValue(h)), + (j = n.transformPoint(new a.Point(l, j))), + (l = j.x), + (j = j.y), + (r = (l - f) * t), + (this.constraint == a.ModConstant.LEFT && r <= e) || + (this.constraint == a.ModConstant.RIGHT && r >= e) || + ((r = s - p * e + p * r), + (l = u(r) * (k + q)), + (r = v(r) * (k + q)), + (q = l - k), + (l = o - r)), + (j = m.transformPoint(new a.Point(l, j))), + (l = j.x), + (j = j.y), + d.setValue(g, l), + d.setValue(i, j), + d.setValue(h, q); + } + } + }; + })(MOD3); + (function (a) { + a.LibraryThree = function () { + this.id = 'Three.js'; + this.meshClass = a.MeshThree; + this.vertexClass = a.VertexThree; + }; + a.LibraryThree.prototype = new a.Library3d(); + a.LibraryThree.prototype.constructor = a.LibraryThree; + })(MOD3); + (function (a) { + a.VertexThree = function (a) { + this.mesh = a; + }; + a.VertexThree.prototype = new a.VertexProxy(); + a.VertexThree.prototype.setVertex = function (a) { + this.vertex = a; + this.originalX = a.x; + this.originalY = a.y; + this.originalZ = a.z; + }; + a.VertexThree.prototype.getX = function () { + return this.vertex.x; + }; + a.VertexThree.prototype.getY = function () { + return this.vertex.y; + }; + a.VertexThree.prototype.getZ = function () { + return this.vertex.z; + }; + a.VertexThree.prototype.setX = function (a) { + this.vertex.x = a; + a = this.mesh; + a.geometry.verticesNeedUpdate = !0; + a.geometry.normalsNeedUpdate = !0; + a.geometry.buffersNeedUpdate = !0; + a.geometry.dynamic = !0; + }; + a.VertexThree.prototype.setY = function (a) { + this.vertex.y = a; + a = this.mesh; + a.geometry.verticesNeedUpdate = !0; + a.geometry.normalsNeedUpdate = !0; + a.geometry.buffersNeedUpdate = !0; + a.geometry.dynamic = !0; + }; + a.VertexThree.prototype.setZ = function (a) { + this.vertex.z = a; + a = this.mesh; + a.geometry.verticesNeedUpdate = !0; + a.geometry.normalsNeedUpdate = !0; + a.geometry.buffersNeedUpdate = !0; + a.geometry.dynamic = !0; + }; + })(MOD3); + (function (a) { + a.MeshThree = function () {}; + a.MeshThree.prototype = new a.MeshProxy(); + a.MeshThree.prototype.setMesh = function (c) { + a.MeshProxy.prototype.setMesh.call(this, c); + for ( + var c = [], + b = 0, + d = this.mesh.geometry.vertices, + e = d.length, + f = this.mesh.geometry.faces, + g = f.length, + h, + b = 0; + b < e; + + ) { + (h = new a.VertexThree(this.mesh)), h.setVertex(d[b]), this.vertices.push(h), (c[d[b]] = h), b++; + } + for (b = 0; b < g; ) { + (e = new a.FaceProxy()), + f[b] instanceof THREE.Face3 + ? (e.addVertex(c[d[f[b].a]]), e.addVertex(c[d[f[b].b]]), e.addVertex(c[d[f[b].c]])) + : f[b] instanceof THREE.Face4 && + (e.addVertex(c[d[f[b].a]]), + e.addVertex(c[d[f[b].b]]), + e.addVertex(c[d[f[b].c]]), + e.addVertex(c[d[f[b].d]])), + this.faces.push(e), + b++; + } + // delete lookup; + }; + a.MeshThree.prototype.updateMeshPosition = function (a) { + var b = this.mesh; + b.position.x += a.x; + b.position.y += a.y; + b.position.z += a.z; + }; + })(MOD3); +} + +{ + /** + * Based on http://www.emagix.net/academic/mscs-project/item/camera-sync-with-css3-and-webgl-threejs + * @author mrdoob / http://mrdoob.com/ + * @author yomotsu / https://yomotsu.net/ + */ + + FLIPBOOK.CSS3DObject = function (element) { + THREE.Object3D.call(this); + + this.element = element; + this.element.style.position = 'absolute'; + this.element.style.pointerEvents = 'auto'; + + this.addEventListener('removed', function () { + this.traverse(function (object) { + if (object.element instanceof Element && object.element.parentNode !== null) { + object.element.parentNode.removeChild(object.element); + } + }); + }); + }; + + FLIPBOOK.CSS3DObject.prototype = Object.create(THREE.Object3D.prototype); + FLIPBOOK.CSS3DObject.prototype.constructor = FLIPBOOK.CSS3DObject; + + FLIPBOOK.CSS3DSprite = function (element) { + FLIPBOOK.CSS3DObject.call(this, element); + }; + + FLIPBOOK.CSS3DSprite.prototype = Object.create(FLIPBOOK.CSS3DObject.prototype); + FLIPBOOK.CSS3DSprite.prototype.constructor = FLIPBOOK.CSS3DSprite; + + // + + FLIPBOOK.CSS3DRenderer = function () { + var _this = this; + + var _width; + var _height; + var _widthHalf; + var _heightHalf; + + var matrix = new THREE.Matrix4(); + + var cache = { + camera: { fov: 0, style: '' }, + objects: new WeakMap(), + }; + + var domElement = document.createElement('div'); + domElement.style.overflow = 'hidden'; + + this.domElement = domElement; + + var cameraElement = document.createElement('div'); + + cameraElement.style.WebkitTransformStyle = 'preserve-3d'; + cameraElement.style.transformStyle = 'preserve-3d'; + cameraElement.style.pointerEvents = 'none'; + + domElement.appendChild(cameraElement); + + var isIE = /Trident/i.test(navigator.userAgent); + + this.getSize = function () { + return { + width: _width, + height: _height, + }; + }; + + this.setSize = function (width, height) { + _width = width; + _height = height; + _widthHalf = _width / 2; + _heightHalf = _height / 2; + + domElement.style.width = width + 'px'; + domElement.style.height = height + 'px'; + + cameraElement.style.width = width + 'px'; + cameraElement.style.height = height + 'px'; + }; + + function epsilon(value) { + return Math.abs(value) < 1e-10 ? 0 : value; + } + + function getCameraCSSMatrix(matrix) { + var elements = matrix.elements; + + return ( + 'matrix3d(' + + epsilon(elements[0]) + + ',' + + epsilon(-elements[1]) + + ',' + + epsilon(elements[2]) + + ',' + + epsilon(elements[3]) + + ',' + + epsilon(elements[4]) + + ',' + + epsilon(-elements[5]) + + ',' + + epsilon(elements[6]) + + ',' + + epsilon(elements[7]) + + ',' + + epsilon(elements[8]) + + ',' + + epsilon(-elements[9]) + + ',' + + epsilon(elements[10]) + + ',' + + epsilon(elements[11]) + + ',' + + epsilon(elements[12]) + + ',' + + epsilon(-elements[13]) + + ',' + + epsilon(elements[14]) + + ',' + + epsilon(elements[15]) + + ')' + ); + } + + function getObjectCSSMatrix(matrix, cameraCSSMatrix) { + var elements = matrix.elements; + var matrix3d = + 'matrix3d(' + + epsilon(elements[0]) + + ',' + + epsilon(elements[1]) + + ',' + + epsilon(elements[2]) + + ',' + + epsilon(elements[3]) + + ',' + + epsilon(-elements[4]) + + ',' + + epsilon(-elements[5]) + + ',' + + epsilon(-elements[6]) + + ',' + + epsilon(-elements[7]) + + ',' + + epsilon(elements[8]) + + ',' + + epsilon(elements[9]) + + ',' + + epsilon(elements[10]) + + ',' + + epsilon(elements[11]) + + ',' + + epsilon(elements[12]) + + ',' + + epsilon(elements[13]) + + ',' + + epsilon(elements[14]) + + ',' + + epsilon(elements[15]) + + ')'; + + if (isIE) { + return ( + 'translate(-50%,-50%)' + + 'translate(' + + _widthHalf + + 'px,' + + _heightHalf + + 'px)' + + cameraCSSMatrix + + matrix3d + ); + } + + return 'translate(-50%,-50%)' + matrix3d; + } + + function renderObject(object, scene, camera, cameraCSSMatrix) { + if (object instanceof FLIPBOOK.CSS3DObject) { + object.onBeforeRender(_this, scene, camera); + + var style; + + if (object instanceof FLIPBOOK.CSS3DSprite) { + // http://swiftcoder.wordpress.com/2008/11/25/constructing-a-billboard-matrix/ + + matrix.copy(camera.matrixWorldInverse); + matrix.transpose(); + matrix.copyPosition(object.matrixWorld); + matrix.scale(object.scale); + + matrix.elements[3] = 0; + matrix.elements[7] = 0; + matrix.elements[11] = 0; + matrix.elements[15] = 1; + + style = getObjectCSSMatrix(matrix, cameraCSSMatrix); + } else { + style = getObjectCSSMatrix(object.matrixWorld, cameraCSSMatrix); + } + + var element = object.element; + var cachedObject = cache.objects.get(object); + + if (cachedObject === undefined || cachedObject.style !== style) { + element.style.WebkitTransform = style; + element.style.transform = style; + + var objectData = { style: style }; + + if (isIE) { + objectData.distanceToCameraSquared = getDistanceToSquared(camera, object); + } + + cache.objects.set(object, objectData); + } + + if (element.parentNode !== cameraElement) { + cameraElement.appendChild(element); + } + + object.onAfterRender(_this, scene, camera); + } + + for (var i = 0, l = object.children.length; i < l; i++) { + renderObject(object.children[i], scene, camera, cameraCSSMatrix); + } + } + + var getDistanceToSquared = (function () { + var a = new THREE.Vector3(); + var b = new THREE.Vector3(); + + return function (object1, object2) { + a.setFromMatrixPosition(object1.matrixWorld); + b.setFromMatrixPosition(object2.matrixWorld); + + return a.distanceToSquared(b); + }; + })(); + + function filterAndFlatten(scene) { + var result = []; + + scene.traverse(function (object) { + if (object instanceof THREE.CSS3DObject) { + result.push(object); + } + }); + + return result; + } + + function zOrder(scene) { + var sorted = filterAndFlatten(scene).sort(function (a, b) { + var distanceA = cache.objects.get(a).distanceToCameraSquared; + var distanceB = cache.objects.get(b).distanceToCameraSquared; + + return distanceA - distanceB; + }); + + var zMax = sorted.length; + + for (var i = 0, l = sorted.length; i < l; i++) { + sorted[i].element.style.zIndex = zMax - i; + } + } + + this.render = function (scene, camera) { + var fov = camera.projectionMatrix.elements[5] * _heightHalf; + + if (cache.camera.fov !== fov) { + if (camera.isPerspectiveCamera) { + domElement.style.WebkitPerspective = fov + 'px'; + domElement.style.perspective = fov + 'px'; + } else { + domElement.style.WebkitPerspective = ''; + domElement.style.perspective = ''; + } + + cache.camera.fov = fov; + } + + if (scene.autoUpdate === true) { + scene.updateMatrixWorld(); + } + if (camera.parent === null) { + camera.updateMatrixWorld(); + } + + if (camera.isOrthographicCamera) { + var tx = -(camera.right + camera.left) / 2; + var ty = (camera.top + camera.bottom) / 2; + } + + var cameraCSSMatrix = camera.isOrthographicCamera + ? 'scale(' + + fov + + ')' + + 'translate(' + + epsilon(tx) + + 'px,' + + epsilon(ty) + + 'px)' + + getCameraCSSMatrix(camera.matrixWorldInverse) + : 'translateZ(' + fov + 'px)' + getCameraCSSMatrix(camera.matrixWorldInverse); + + var style = cameraCSSMatrix + 'translate(' + _widthHalf + 'px,' + _heightHalf + 'px)'; + + if (cache.camera.style !== style && !isIE) { + cameraElement.style.WebkitTransform = style; + cameraElement.style.transform = style; + + cache.camera.style = style; + } + + renderObject(scene, scene, camera, cameraCSSMatrix); + + if (isIE) { + // IE10 and 11 does not support 'preserve-3d'. + // Thus, z-order in 3D will not work. + // We have to calc z-order manually and set CSS z-index for IE. + // FYI: z-index can't handle object intersection + zOrder(scene); + } + }; + }; +}