UNPKG

flipbook-vue

Version:

3D page flip effect for Vue.js

1,434 lines (1,363 loc) 50.5 kB
/*! * @license * flipbook-vue v1.0.0-beta.4 * Copyright © 2023 Takeshi Sone. * Released under the MIT License. */ (function (vue) { 'use strict'; /*! @license Rematrix v0.7.2 Copyright 2021 Julian Lloyd. Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ function format(source) { if (source && source.constructor === Array) { var values = source .filter(function (value) { return typeof value === 'number'; }) .filter(function (value) { return !isNaN(value); }); if (source.length === 6 && values.length === 6) { var matrix = identity(); matrix[0] = values[0]; matrix[1] = values[1]; matrix[4] = values[2]; matrix[5] = values[3]; matrix[12] = values[4]; matrix[13] = values[5]; return matrix } else if (source.length === 16 && values.length === 16) { return source } } throw new TypeError('Expected a `number[]` with length 6 or 16.') } function identity() { var matrix = []; for (var i = 0; i < 16; i++) { i % 5 == 0 ? matrix.push(1) : matrix.push(0); } return matrix } function multiply(matrixA, matrixB) { var fma = format(matrixA); var fmb = format(matrixB); var product = []; for (var i = 0; i < 4; i++) { var row = [fma[i], fma[i + 4], fma[i + 8], fma[i + 12]]; for (var j = 0; j < 4; j++) { var k = j * 4; var col = [fmb[k], fmb[k + 1], fmb[k + 2], fmb[k + 3]]; var result = row[0] * col[0] + row[1] * col[1] + row[2] * col[2] + row[3] * col[3]; product[i + k] = result; } } return product } function perspective(distance) { var matrix = identity(); matrix[11] = -1 / distance; return matrix } function rotateY(angle) { var theta = (Math.PI / 180) * angle; var matrix = identity(); matrix[0] = matrix[10] = Math.cos(theta); matrix[2] = matrix[8] = Math.sin(theta); matrix[2] *= -1; return matrix } function toString(source) { return ("matrix3d(" + (format(source).join(', ')) + ")") } function translate(distanceX, distanceY) { var matrix = identity(); matrix[12] = distanceX; if (distanceY) { matrix[13] = distanceY; } return matrix } function translate3d(distanceX, distanceY, distanceZ) { var matrix = identity(); if (distanceX !== undefined && distanceY !== undefined && distanceZ !== undefined) { matrix[12] = distanceX; matrix[13] = distanceY; matrix[14] = distanceZ; } return matrix } var Matrix = /*@__PURE__*/(function () { function Matrix(arg) { if (arg) { if (arg.m) { this.m = [].concat( arg.m ); } else { this.m = [].concat( arg ); } } else { this.m = identity(); } } Matrix.prototype.clone = function clone () { return new Matrix(this); }; Matrix.prototype.multiply = function multiply$1 (m) { return this.m = multiply(this.m, m); }; Matrix.prototype.perspective = function perspective$1 (d) { return this.multiply(perspective(d)); }; Matrix.prototype.transformX = function transformX (x) { return (x * this.m[0] + this.m[12]) / (x * this.m[3] + this.m[15]); }; Matrix.prototype.translate = function translate$1 (x, y) { return this.multiply(translate(x, y)); }; Matrix.prototype.translate3d = function translate3d$1 (x, y, z) { return this.multiply(translate3d(x, y, z)); }; Matrix.prototype.rotateY = function rotateY$1 (deg) { return this.multiply(rotateY(deg)); }; Matrix.prototype.toString = function toString$1 () { return toString(this.m); }; return Matrix; }()); var spinner = "data:image/svg+xml,%3C%3Fxml%20version%3D%221.0%22%3F%3E%3Csvg%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20width%3D%22500%22%20height%3D%22500%22%20viewBox%3D%220%200%20500%20500%22%20fill%3D%22transparent%22%20style%3D%22background-color%3A%20%23fff%22%3E%20%20%3Ccircle%20%20%20%20cx%3D%22250%22%20%20%20%20cy%3D%22250%22%20%20%20%20r%3D%2248%22%20%20%20%20stroke%3D%22%23333%22%20%20%20%20stroke-width%3D%222%22%20%20%20%20stroke-dasharray%3D%22271%2030%22%20%20%3E%20%20%20%20%3CanimateTransform%20%20%20%20%20%20attributeName%3D%22transform%22%20%20%20%20%20%20attributeType%3D%22XML%22%20%20%20%20%20%20type%3D%22rotate%22%20%20%20%20%20%20from%3D%220%20250%20250%22%20%20%20%20%20%20to%3D%22360%20250%20250%22%20%20%20%20%20%20dur%3D%221s%22%20%20%20%20%20%20repeatCount%3D%22indefinite%22%20%20%20%20%2F%3E%20%20%3C%2Fcircle%3E%3C%2Fsvg%3E"; var easeIn, easeInOut, easeOut; easeIn = function(x) { return Math.pow(x, 2); }; easeOut = function(x) { return 1 - easeIn(1 - x); }; easeInOut = function(x) { if (x < 0.5) { return easeIn(x * 2) / 2; } else { return 0.5 + easeOut((x - 0.5) * 2) / 2; } }; var script = { props: { pages: { type: Array, required: true }, pagesHiRes: { type: Array, default: function() { return []; } }, flipDuration: { type: Number, default: 1000 }, zoomDuration: { type: Number, default: 500 }, zooms: { type: Array, default: function() { return [1, 2, 4]; } }, perspective: { type: Number, default: 2400 }, nPolygons: { type: Number, default: 10 }, ambient: { type: Number, default: 0.4 }, gloss: { type: Number, default: 0.6 }, swipeMin: { type: Number, default: 3 }, singlePage: { type: Boolean, default: false }, forwardDirection: { validator: function(val) { return val === 'right' || val === 'left'; }, default: 'right' }, centering: { type: Boolean, default: true }, startPage: { type: Number, default: null }, loadingImage: { type: String, default: spinner }, clickToZoom: { type: Boolean, default: true }, dragToFlip: { type: Boolean, default: true }, wheel: { type: String, default: 'scroll' } }, data: function() { return { viewWidth: 0, viewHeight: 0, imageWidth: null, imageHeight: null, displayedPages: 1, nImageLoad: 0, nImageLoadTrigger: 0, imageLoadCallback: null, currentPage: 0, firstPage: 0, secondPage: 1, zoomIndex: 0, zoom: 1, zooming: false, touchStartX: null, touchStartY: null, maxMove: 0, activeCursor: null, hasTouchEvents: false, hasPointerEvents: false, minX: 2e308, maxX: -2e308, preloadedImages: {}, flip: { progress: 0, direction: null, frontImage: null, backImage: null, auto: false, opacity: 1 }, currentCenterOffset: null, animatingCenter: false, startScrollLeft: 0, startScrollTop: 0, scrollLeft: 0, scrollTop: 0, loadedImages: {} }; }, computed: { IE: function() { return typeof navigator !== 'undefined' && /Trident/.test(navigator.userAgent); }, canFlipLeft: function() { if (this.forwardDirection === 'left') { return this.canGoForward; } else { return this.canGoBack; } }, canFlipRight: function() { if (this.forwardDirection === 'right') { return this.canGoForward; } else { return this.canGoBack; } }, canZoomIn: function() { return !this.zooming && this.zoomIndex < this.zooms_.length - 1; }, canZoomOut: function() { return !this.zooming && this.zoomIndex > 0; }, numPages: function() { if (this.pages[0] === null) { return this.pages.length - 1; } else { return this.pages.length; } }, page: function() { if (this.pages[0] !== null) { return this.currentPage + 1; } else { return Math.max(1, this.currentPage); } }, zooms_: function() { return this.zooms || [1]; }, canGoForward: function() { return !this.flip.direction && this.currentPage < this.pages.length - this.displayedPages; }, canGoBack: function() { return !this.flip.direction && this.currentPage >= this.displayedPages && !(this.displayedPages === 1 && !this.pageUrl(this.firstPage - 1)); }, leftPage: function() { if (this.forwardDirection === 'right' || this.displayedPages === 1) { return this.firstPage; } else { return this.secondPage; } }, rightPage: function() { if (this.forwardDirection === 'left') { return this.firstPage; } else { return this.secondPage; } }, showLeftPage: function() { return this.pageUrl(this.leftPage); }, showRightPage: function() { return this.pageUrl(this.rightPage) && this.displayedPages === 2; }, cursor: function() { if (this.activeCursor) { return this.activeCursor; } else if (this.IE) { return 'auto'; } else if (this.clickToZoom && this.canZoomIn) { return 'zoom-in'; } else if (this.clickToZoom && this.canZoomOut) { return 'zoom-out'; } else if (this.dragToFlip) { return 'grab'; } else { return 'auto'; } }, pageScale: function() { var scale, vw, xScale, yScale; vw = this.viewWidth / this.displayedPages; xScale = vw / this.imageWidth; yScale = this.viewHeight / this.imageHeight; scale = xScale < yScale ? xScale : yScale; if (scale < 1) { return scale; } else { return 1; } }, pageWidth: function() { return Math.round(this.imageWidth * this.pageScale); }, pageHeight: function() { return Math.round(this.imageHeight * this.pageScale); }, xMargin: function() { return (this.viewWidth - this.pageWidth * this.displayedPages) / 2; }, yMargin: function() { return (this.viewHeight - this.pageHeight) / 2; }, polygonWidth: function() { var w; w = this.pageWidth / this.nPolygons; w = Math.ceil(w + 1 / this.zoom); return w + 'px'; }, polygonHeight: function() { return this.pageHeight + 'px'; }, polygonBgSize: function() { return ((this.pageWidth) + "px " + (this.pageHeight) + "px"); }, polygonArray: function() { return this.makePolygonArray('front').concat(this.makePolygonArray('back')); }, boundingLeft: function() { var x; if (this.displayedPages === 1) { return this.xMargin; } else { x = this.pageUrl(this.leftPage) ? this.xMargin : this.viewWidth / 2; if (x < this.minX) { return x; } else { return this.minX; } } }, boundingRight: function() { var x; if (this.displayedPages === 1) { return this.viewWidth - this.xMargin; } else { x = this.pageUrl(this.rightPage) ? this.viewWidth - this.xMargin : this.viewWidth / 2; if (x > this.maxX) { return x; } else { return this.maxX; } } }, centerOffset: function() { var retval; retval = this.centering ? Math.round(this.viewWidth / 2 - (this.boundingLeft + this.boundingRight) / 2) : 0; if (this.currentCenterOffset === null && this.imageWidth !== null) { this.currentCenterOffset = retval; } return retval; }, centerOffsetSmoothed: function() { return Math.round(this.currentCenterOffset); }, dragToScroll: function() { return !this.hasTouchEvents; }, scrollLeftMin: function() { var w; w = (this.boundingRight - this.boundingLeft) * this.zoom; if (w < this.viewWidth) { return (this.boundingLeft + this.centerOffsetSmoothed) * this.zoom - (this.viewWidth - w) / 2; } else { return (this.boundingLeft + this.centerOffsetSmoothed) * this.zoom; } }, scrollLeftMax: function() { var w; w = (this.boundingRight - this.boundingLeft) * this.zoom; if (w < this.viewWidth) { return (this.boundingLeft + this.centerOffsetSmoothed) * this.zoom - (this.viewWidth - w) / 2; } else { return (this.boundingRight + this.centerOffsetSmoothed) * this.zoom - this.viewWidth; } }, scrollTopMin: function() { var h; h = this.pageHeight * this.zoom; if (h < this.viewHeight) { return this.yMargin * this.zoom - (this.viewHeight - h) / 2; } else { return this.yMargin * this.zoom; } }, scrollTopMax: function() { var h; h = this.pageHeight * this.zoom; if (h < this.viewHeight) { return this.yMargin * this.zoom - (this.viewHeight - h) / 2; } else { return (this.yMargin + this.pageHeight) * this.zoom - this.viewHeight; } }, scrollLeftLimited: function() { return Math.min(this.scrollLeftMax, Math.max(this.scrollLeftMin, this.scrollLeft)); }, scrollTopLimited: function() { return Math.min(this.scrollTopMax, Math.max(this.scrollTopMin, this.scrollTop)); } }, mounted: function() { window.addEventListener('resize', this.onResize, { passive: true }); this.onResize(); this.zoom = this.zooms_[0]; return this.goToPage(this.startPage); }, beforeDestroy: function() { return window.removeEventListener('resize', this.onResize, { passive: true }); }, methods: { onResize: function() { var viewport; viewport = this.$refs.viewport; if (!viewport) { return; } this.viewWidth = viewport.clientWidth; this.viewHeight = viewport.clientHeight; this.displayedPages = this.viewWidth > this.viewHeight && !this.singlePage ? 2 : 1; if (this.displayedPages === 2) { this.currentPage &= ~1; } this.fixFirstPage(); this.minX = 2e308; return this.maxX = -2e308; }, fixFirstPage: function() { if (this.displayedPages === 1 && this.currentPage === 0 && this.pages.length && !this.pageUrl(0)) { return this.currentPage++; } }, pageUrl: function(page, hiRes) { if ( hiRes === void 0 ) hiRes = false; var url; if (hiRes && this.zoom > 1 && !this.zooming) { url = this.pagesHiRes[page]; if (url) { return url; } } return this.pages[page] || null; }, pageUrlLoading: function(page, hiRes) { if ( hiRes === void 0 ) hiRes = false; var url; url = this.pageUrl(page, hiRes); if (hiRes && this.zoom > 1 && !this.zooming) { // High-res image doesn't use 'loading' return url; } return url && this.loadImage(url); }, flipLeft: function() { if (!this.canFlipLeft) { return; } return this.flipStart('left', true); }, flipRight: function() { if (!this.canFlipRight) { return; } return this.flipStart('right', true); }, makePolygonArray: function(face) { var bgPos, dRadian, dRotate, direction, i, image, j, lighting, m, originRight, pageMatrix, pageRotation, pageX, polygonWidth, progress, rad, radian, radius, ref, results, rotate, theta, x, x0, x1, z; if (!this.flip.direction) { return []; } progress = this.flip.progress; direction = this.flip.direction; if (this.displayedPages === 1 && direction !== this.forwardDirection) { progress = 1 - progress; direction = this.forwardDirection; } this.flip.opacity = this.displayedPages === 1 && progress > .7 ? 1 - (progress - .7) / .3 : 1; image = face === 'front' ? this.flip.frontImage : this.flip.backImage; polygonWidth = this.pageWidth / this.nPolygons; pageX = this.xMargin; originRight = false; if (this.displayedPages === 1) { if (this.forwardDirection === 'right') { if (face === 'back') { originRight = true; pageX = this.xMargin - this.pageWidth; } } else { if (direction === 'left') { if (face === 'back') { pageX = this.pageWidth - this.xMargin; } else { originRight = true; } } else { if (face === 'front') { pageX = this.pageWidth - this.xMargin; } else { originRight = true; } } } } else { if (direction === 'left') { if (face === 'back') { pageX = this.viewWidth / 2; } else { originRight = true; } } else { if (face === 'front') { pageX = this.viewWidth / 2; } else { originRight = true; } } } pageMatrix = new Matrix(); pageMatrix.translate(this.viewWidth / 2); pageMatrix.perspective(this.perspective); pageMatrix.translate(-this.viewWidth / 2); pageMatrix.translate(pageX, this.yMargin); pageRotation = 0; if (progress > 0.5) { pageRotation = -(progress - 0.5) * 2 * 180; } if (direction === 'left') { pageRotation = -pageRotation; } if (face === 'back') { pageRotation += 180; } if (pageRotation) { if (originRight) { pageMatrix.translate(this.pageWidth); } pageMatrix.rotateY(pageRotation); if (originRight) { pageMatrix.translate(-this.pageWidth); } } if (progress < 0.5) { theta = progress * 2 * Math.PI; } else { theta = (1 - (progress - 0.5) * 2) * Math.PI; } if (theta === 0) { theta = 1e-9; } radius = this.pageWidth / theta; radian = 0; dRadian = theta / this.nPolygons; rotate = dRadian / 2 / Math.PI * 180; dRotate = dRadian / Math.PI * 180; if (originRight) { rotate = -theta / Math.PI * 180 + dRotate / 2; } if (face === 'back') { rotate = -rotate; dRotate = -dRotate; } this.minX = 2e308; this.maxX = -2e308; results = []; for (i = j = 0, ref = this.nPolygons; (0 <= ref ? j < ref : j > ref); i = 0 <= ref ? ++j : --j) { bgPos = (i / (this.nPolygons - 1) * 100) + "% 0px"; m = pageMatrix.clone(); rad = originRight ? theta - radian : radian; x = Math.sin(rad) * radius; if (originRight) { x = this.pageWidth - x; } z = (1 - Math.cos(rad)) * radius; if (face === 'back') { z = -z; } m.translate3d(x, 0, z); m.rotateY(-rotate); x0 = m.transformX(0); x1 = m.transformX(polygonWidth); this.maxX = Math.max(Math.max(x0, x1), this.maxX); this.minX = Math.min(Math.min(x0, x1), this.minX); lighting = this.computeLighting(pageRotation - rotate, dRotate); radian += dRadian; rotate += dRotate; results.push([face + i, image, lighting, bgPos, m.toString(), Math.abs(Math.round(z))]); } return results; }, computeLighting: function(rot, dRotate) { var DEG, POW, blackness, diffuse, gradients, lightingPoints, specular; gradients = []; lightingPoints = [-0.5, -0.25, 0, 0.25, 0.5]; if (this.ambient < 1) { blackness = 1 - this.ambient; diffuse = lightingPoints.map(function (d) { return (1 - Math.cos((rot - dRotate * d) / 180 * Math.PI)) * blackness; }); gradients.push(("linear-gradient(to right,\n rgba(0, 0, 0, " + (diffuse[0]) + "),\n rgba(0, 0, 0, " + (diffuse[1]) + ") 25%,\n rgba(0, 0, 0, " + (diffuse[2]) + ") 50%,\n rgba(0, 0, 0, " + (diffuse[3]) + ") 75%,\n rgba(0, 0, 0, " + (diffuse[4]) + "))")); } if (this.gloss > 0 && !this.IE) { DEG = 30; POW = 200; specular = lightingPoints.map(function (d) { return Math.max(Math.pow( Math.cos((rot + DEG - dRotate * d) / 180 * Math.PI), POW ), Math.pow( Math.cos((rot - DEG - dRotate * d) / 180 * Math.PI), POW )); }); gradients.push(("linear-gradient(to right,\n rgba(255, 255, 255, " + (specular[0] * this.gloss) + "),\n rgba(255, 255, 255, " + (specular[1] * this.gloss) + ") 25%,\n rgba(255, 255, 255, " + (specular[2] * this.gloss) + ") 50%,\n rgba(255, 255, 255, " + (specular[3] * this.gloss) + ") 75%,\n rgba(255, 255, 255, " + (specular[4] * this.gloss) + "))")); } return gradients.join(','); }, flipStart: function(direction, auto) { var this$1$1 = this; if (direction !== this.forwardDirection) { if (this.displayedPages === 1) { this.flip.frontImage = this.pageUrl(this.currentPage - 1); this.flip.backImage = null; } else { this.flip.frontImage = this.pageUrl(this.firstPage); this.flip.backImage = this.pageUrl(this.currentPage - this.displayedPages + 1); } } else { if (this.displayedPages === 1) { this.flip.frontImage = this.pageUrl(this.currentPage); this.flip.backImage = null; } else { this.flip.frontImage = this.pageUrl(this.secondPage); this.flip.backImage = this.pageUrl(this.currentPage + this.displayedPages); } } this.flip.direction = direction; this.flip.progress = 0; return requestAnimationFrame(function () { return requestAnimationFrame(function () { if (this$1$1.flip.direction !== this$1$1.forwardDirection) { if (this$1$1.displayedPages === 2) { this$1$1.firstPage = this$1$1.currentPage - this$1$1.displayedPages; } } else { if (this$1$1.displayedPages === 1) { this$1$1.firstPage = this$1$1.currentPage + this$1$1.displayedPages; } else { this$1$1.secondPage = this$1$1.currentPage + 1 + this$1$1.displayedPages; } } if (auto) { return this$1$1.flipAuto(true); } }); }); }, flipAuto: function(ease) { var this$1$1 = this; var animate, duration, startRatio, t0; t0 = Date.now(); duration = this.flipDuration * (1 - this.flip.progress); startRatio = this.flip.progress; this.flip.auto = true; this.$emit(("flip-" + (this.flip.direction) + "-start"), this.page); animate = function () { return requestAnimationFrame(function () { var ratio, t; t = Date.now() - t0; ratio = startRatio + t / duration; if (ratio > 1) { ratio = 1; } this$1$1.flip.progress = ease ? easeInOut(ratio) : ratio; if (ratio < 1) { return animate(); } else { if (this$1$1.flip.direction !== this$1$1.forwardDirection) { this$1$1.currentPage -= this$1$1.displayedPages; } else { this$1$1.currentPage += this$1$1.displayedPages; } this$1$1.$emit(("flip-" + (this$1$1.flip.direction) + "-end"), this$1$1.page); if (this$1$1.displayedPages === 1 && this$1$1.flip.direction === this$1$1.forwardDirection) { this$1$1.flip.direction = null; } else { this$1$1.onImageLoad(1, function () { return this$1$1.flip.direction = null; }); } return this$1$1.flip.auto = false; } }); }; return animate(); }, flipRevert: function() { var this$1$1 = this; var animate, duration, startRatio, t0; t0 = Date.now(); duration = this.flipDuration * this.flip.progress; startRatio = this.flip.progress; this.flip.auto = true; animate = function () { return requestAnimationFrame(function () { var ratio, t; t = Date.now() - t0; ratio = startRatio - startRatio * t / duration; if (ratio < 0) { ratio = 0; } this$1$1.flip.progress = ratio; if (ratio > 0) { return animate(); } else { this$1$1.firstPage = this$1$1.currentPage; this$1$1.secondPage = this$1$1.currentPage + 1; if (this$1$1.displayedPages === 1 && this$1$1.flip.direction !== this$1$1.forwardDirection) { this$1$1.flip.direction = null; } else { this$1$1.onImageLoad(1, function () { return this$1$1.flip.direction = null; }); } return this$1$1.flip.auto = false; } }); }; return animate(); }, onImageLoad: function(trigger, cb) { this.nImageLoad = 0; this.nImageLoadTrigger = trigger; return this.imageLoadCallback = cb; }, didLoadImage: function(ev) { if (this.imageWidth === null) { this.imageWidth = (ev.target || ev.path[0]).naturalWidth; this.imageHeight = (ev.target || ev.path[0]).naturalHeight; this.preloadImages(); } if (!this.imageLoadCallback) { return; } if (++this.nImageLoad >= this.nImageLoadTrigger) { this.imageLoadCallback(); return this.imageLoadCallback = null; } }, zoomIn: function(zoomAt) { if ( zoomAt === void 0 ) zoomAt = null; if (!this.canZoomIn) { return; } this.zoomIndex += 1; return this.zoomTo(this.zooms_[this.zoomIndex], zoomAt); }, zoomOut: function(zoomAt) { if ( zoomAt === void 0 ) zoomAt = null; if (!this.canZoomOut) { return; } this.zoomIndex -= 1; return this.zoomTo(this.zooms_[this.zoomIndex], zoomAt); }, zoomTo: function(zoom, zoomAt) { var this$1$1 = this; if ( zoomAt === void 0 ) zoomAt = null; var animate, containerFixedX, containerFixedY, end, endX, endY, fixedX, fixedY, rect, start, startX, startY, t0, viewport; viewport = this.$refs.viewport; if (zoomAt) { rect = viewport.getBoundingClientRect(); fixedX = zoomAt.pageX - rect.left; fixedY = zoomAt.pageY - rect.top; } else { fixedX = viewport.clientWidth / 2; fixedY = viewport.clientHeight / 2; } start = this.zoom; end = zoom; startX = viewport.scrollLeft; startY = viewport.scrollTop; containerFixedX = fixedX + startX; containerFixedY = fixedY + startY; endX = containerFixedX / start * end - fixedX; endY = containerFixedY / start * end - fixedY; t0 = Date.now(); this.zooming = true; this.$emit('zoom-start', zoom); animate = function () { return requestAnimationFrame(function () { var ratio, t; t = Date.now() - t0; ratio = t / this$1$1.zoomDuration; if (ratio > 1 || this$1$1.IE) { ratio = 1; } ratio = easeInOut(ratio); this$1$1.zoom = start + (end - start) * ratio; this$1$1.scrollLeft = startX + (endX - startX) * ratio; this$1$1.scrollTop = startY + (endY - startY) * ratio; if (t < this$1$1.zoomDuration) { return animate(); } else { this$1$1.$emit('zoom-end', zoom); this$1$1.zooming = false; this$1$1.zoom = zoom; this$1$1.scrollLeft = endX; return this$1$1.scrollTop = endY; } }); }; animate(); if (end > 1) { return this.preloadImages(true); } }, zoomAt: function(zoomAt) { this.zoomIndex = (this.zoomIndex + 1) % this.zooms_.length; return this.zoomTo(this.zooms_[this.zoomIndex], zoomAt); }, swipeStart: function(touch) { this.touchStartX = touch.pageX; this.touchStartY = touch.pageY; this.maxMove = 0; if (this.zoom <= 1) { if (this.dragToFlip) { return this.activeCursor = 'grab'; } } else { this.startScrollLeft = this.$refs.viewport.scrollLeft; this.startScrollTop = this.$refs.viewport.scrollTop; return this.activeCursor = 'all-scroll'; } }, swipeMove: function(touch) { var x, y; if (this.touchStartX == null) { return; } x = touch.pageX - this.touchStartX; y = touch.pageY - this.touchStartY; this.maxMove = Math.max(this.maxMove, Math.abs(x)); this.maxMove = Math.max(this.maxMove, Math.abs(y)); if (this.zoom > 1) { if (this.dragToScroll) { this.dragScroll(x, y); } return; } if (!this.dragToFlip) { return; } if (Math.abs(y) > Math.abs(x)) { return; } this.activeCursor = 'grabbing'; if (x > 0) { if (this.flip.direction === null && this.canFlipLeft && x >= this.swipeMin) { this.flipStart('left', false); } if (this.flip.direction === 'left') { this.flip.progress = x / this.pageWidth; if (this.flip.progress > 1) { this.flip.progress = 1; } } } else { if (this.flip.direction === null && this.canFlipRight && x <= -this.swipeMin) { this.flipStart('right', false); } if (this.flip.direction === 'right') { this.flip.progress = -x / this.pageWidth; if (this.flip.progress > 1) { this.flip.progress = 1; } } } return true; }, swipeEnd: function(touch) { if (this.touchStartX == null) { return; } if (this.clickToZoom && this.maxMove < this.swipeMin) { this.zoomAt(touch); } if (this.flip.direction !== null && !this.flip.auto) { if (this.flip.progress > 1 / 4) { this.flipAuto(false); } else { this.flipRevert(); } } this.touchStartX = null; return this.activeCursor = null; }, onTouchStart: function(ev) { this.hasTouchEvents = true; return this.swipeStart(ev.changedTouches[0]); }, onTouchMove: function(ev) { if (this.swipeMove(ev.changedTouches[0])) { if (ev.cancelable) { return ev.preventDefault(); } } }, onTouchEnd: function(ev) { return this.swipeEnd(ev.changedTouches[0]); }, onPointerDown: function(ev) { this.hasPointerEvents = true; if (this.hasTouchEvents) { return; } if (ev.which && ev.which !== 1) { // Ignore right-click return; } this.swipeStart(ev); try { return ev.target.setPointerCapture(ev.pointerId); } catch (error) { } }, onPointerMove: function(ev) { if (!this.hasTouchEvents) { return this.swipeMove(ev); } }, onPointerUp: function(ev) { if (this.hasTouchEvents) { return; } this.swipeEnd(ev); try { return ev.target.releasePointerCapture(ev.pointerId); } catch (error) { } }, onMouseDown: function(ev) { if (this.hasTouchEvents || this.hasPointerEvents) { return; } if (ev.which && ev.which !== 1) { // Ignore right-click return; } return this.swipeStart(ev); }, onMouseMove: function(ev) { if (!(this.hasTouchEvents || this.hasPointerEvents)) { return this.swipeMove(ev); } }, onMouseUp: function(ev) { if (!(this.hasTouchEvents || this.hasPointerEvents)) { return this.swipeEnd(ev); } }, dragScroll: function(x, y) { this.scrollLeft = this.startScrollLeft - x; return this.scrollTop = this.startScrollTop - y; }, onWheel: function(ev) { if (this.wheel === 'scroll' && this.zoom > 1 && this.dragToScroll) { this.scrollLeft = this.$refs.viewport.scrollLeft + ev.deltaX; this.scrollTop = this.$refs.viewport.scrollTop + ev.deltaY; if (ev.cancelable) { ev.preventDefault(); } } if (this.wheel === 'zoom') { if (ev.deltaY >= 100) { this.zoomOut(ev); return ev.preventDefault(); } else if (ev.deltaY <= -100) { this.zoomIn(ev); return ev.preventDefault(); } } }, preloadImages: function(hiRes) { if ( hiRes === void 0 ) hiRes = false; var i, j, k, ref, ref1, ref2, ref3, src; for (i = j = ref = this.currentPage - 3, ref1 = this.currentPage + 3; (ref <= ref1 ? j <= ref1 : j >= ref1); i = ref <= ref1 ? ++j : --j) { this.pageUrlLoading(i); // this preloads image } if (hiRes) { for (i = k = ref2 = this.currentPage, ref3 = this.currentPage + this.displayedPages; (ref2 <= ref3 ? k < ref3 : k > ref3); i = ref2 <= ref3 ? ++k : --k) { src = this.pagesHiRes[i]; if (src) { (new Image()).src = src; } } } }, goToPage: function(p) { if (p === null || p === this.page) { return; } if (this.pages[0] === null) { if (this.displayedPages === 2 && p === 1) { this.currentPage = 0; } else { this.currentPage = p; } } else { this.currentPage = p - 1; } this.minX = 2e308; this.maxX = -2e308; return this.currentCenterOffset = this.centerOffset; }, loadImage: function(url) { var this$1$1 = this; var img; if (this.imageWidth === null) { // First loaded image defines the image width and height. // So it must be true image, not 'loading' image. return url; } else { if (this.loadedImages[url]) { return url; } else { img = new Image(); img.onload = function () { if (this$1$1.$set) { return this$1$1.$set(this$1$1.loadedImages, url, true); } else { return this$1$1.loadedImages[url] = true; } }; img.src = url; return this.loadingImage; } } } }, watch: { currentPage: function() { this.firstPage = this.currentPage; this.secondPage = this.currentPage + 1; return this.preloadImages(); }, centerOffset: function() { var this$1$1 = this; var animate; if (this.animatingCenter) { return; } animate = function () { return requestAnimationFrame(function () { var diff, rate; rate = 0.1; diff = this$1$1.centerOffset - this$1$1.currentCenterOffset; if (Math.abs(diff) < 0.5) { this$1$1.currentCenterOffset = this$1$1.centerOffset; return this$1$1.animatingCenter = false; } else { this$1$1.currentCenterOffset += diff * rate; return animate(); } }); }; this.animatingCenter = true; return animate(); }, scrollLeftLimited: function(val) { var this$1$1 = this; if (this.IE) { return requestAnimationFrame(function () { return this$1$1.$refs.viewport.scrollLeft = val; }); } else { return this.$refs.viewport.scrollLeft = val; } }, scrollTopLimited: function(val) { var this$1$1 = this; if (this.IE) { return requestAnimationFrame(function () { return this$1$1.$refs.viewport.scrollTop = val; }); } else { return this.$refs.viewport.scrollTop = val; } }, pages: function(after, before) { this.fixFirstPage(); if (!(before != null ? before.length : void 0) && (after != null ? after.length : void 0)) { if (this.startPage > 1 && after[0] === null) { return this.currentPage++; } } }, startPage: function(p) { return this.goToPage(p); } } }; var _hoisted_1 = ["src"]; var _hoisted_2 = ["src"]; function render(_ctx, _cache) { return (vue.openBlock(), vue.createElementBlock("div", null, [ vue.renderSlot(_ctx.$slots, "default", vue.normalizeProps(vue.guardReactiveProps({ canFlipLeft: _ctx.canFlipLeft, canFlipRight: _ctx.canFlipRight, canZoomIn: _ctx.canZoomIn, canZoomOut: _ctx.canZoomOut, page: _ctx.page, numPages: _ctx.numPages, flipLeft: _ctx.flipLeft, flipRight: _ctx.flipRight, zoomIn: _ctx.zoomIn, zoomOut: _ctx.zoomOut, }))), vue.createElementVNode("div", { class: vue.normalizeClass(["viewport", { zoom: _ctx.zooming || _ctx.zoom > 1, 'drag-to-scroll': _ctx.dragToScroll, }]), ref: "viewport", style: vue.normalizeStyle({ cursor: _ctx.cursor == 'grabbing' ? 'grabbing' : 'auto' }), onTouchmove: _cache[7] || (_cache[7] = function () { var args = [], len = arguments.length; while ( len-- ) args[ len ] = arguments[ len ]; return (_ctx.onTouchMove && _ctx.onTouchMove.apply(_ctx, args)); }), onPointermove: _cache[8] || (_cache[8] = function () { var args = [], len = arguments.length; while ( len-- ) args[ len ] = arguments[ len ]; return (_ctx.onPointerMove && _ctx.onPointerMove.apply(_ctx, args)); }), onMousemove: _cache[9] || (_cache[9] = function () { var args = [], len = arguments.length; while ( len-- ) args[ len ] = arguments[ len ]; return (_ctx.onMouseMove && _ctx.onMouseMove.apply(_ctx, args)); }), onTouchend: _cache[10] || (_cache[10] = function () { var args = [], len = arguments.length; while ( len-- ) args[ len ] = arguments[ len ]; return (_ctx.onTouchEnd && _ctx.onTouchEnd.apply(_ctx, args)); }), onTouchcancel: _cache[11] || (_cache[11] = function () { var args = [], len = arguments.length; while ( len-- ) args[ len ] = arguments[ len ]; return (_ctx.onTouchEnd && _ctx.onTouchEnd.apply(_ctx, args)); }), onPointerup: _cache[12] || (_cache[12] = function () { var args = [], len = arguments.length; while ( len-- ) args[ len ] = arguments[ len ]; return (_ctx.onPointerUp && _ctx.onPointerUp.apply(_ctx, args)); }), onPointercancel: _cache[13] || (_cache[13] = function () { var args = [], len = arguments.length; while ( len-- ) args[ len ] = arguments[ len ]; return (_ctx.onPointerUp && _ctx.onPointerUp.apply(_ctx, args)); }), onMouseup: _cache[14] || (_cache[14] = function () { var args = [], len = arguments.length; while ( len-- ) args[ len ] = arguments[ len ]; return (_ctx.onMouseUp && _ctx.onMouseUp.apply(_ctx, args)); }), onWheel: _cache[15] || (_cache[15] = function () { var args = [], len = arguments.length; while ( len-- ) args[ len ] = arguments[ len ]; return (_ctx.onWheel && _ctx.onWheel.apply(_ctx, args)); }) }, [ vue.createElementVNode("div", { class: "flipbook-container", style: vue.normalizeStyle({ transform: ("scale(" + (_ctx.zoom) + ")") }) }, [ vue.createElementVNode("div", { class: "click-to-flip left", style: vue.normalizeStyle({ cursor: _ctx.canFlipLeft ? 'pointer' : 'auto' }), onClick: _cache[0] || (_cache[0] = function () { var args = [], len = arguments.length; while ( len-- ) args[ len ] = arguments[ len ]; return (_ctx.flipLeft && _ctx.flipLeft.apply(_ctx, args)); }) }, null, 4 /* STYLE */), vue.createElementVNode("div", { class: "click-to-flip right", style: vue.normalizeStyle({ cursor: _ctx.canFlipRight ? 'pointer' : 'auto' }), onClick: _cache[1] || (_cache[1] = function () { var args = [], len = arguments.length; while ( len-- ) args[ len ] = arguments[ len ]; return (_ctx.flipRight && _ctx.flipRight.apply(_ctx, args)); }) }, null, 4 /* STYLE */), vue.createElementVNode("div", { style: vue.normalizeStyle({ transform: ("translateX(" + (_ctx.centerOffsetSmoothed) + "px)") }) }, [ (_ctx.showLeftPage) ? (vue.openBlock(), vue.createElementBlock("img", { key: 0, class: "page fixed", style: vue.normalizeStyle({ width: _ctx.pageWidth + 'px', height: _ctx.pageHeight + 'px', left: _ctx.xMargin + 'px', top: _ctx.yMargin + 'px', }), src: _ctx.pageUrlLoading(_ctx.leftPage, true), onLoad: _cache[2] || (_cache[2] = function ($event) { return (_ctx.didLoadImage($event)); }) }, null, 44 /* STYLE, PROPS, HYDRATE_EVENTS */, _hoisted_1)) : vue.createCommentVNode("v-if", true), (_ctx.showRightPage) ? (vue.openBlock(), vue.createElementBlock("img", { key: 1, class: "page fixed", style: vue.normalizeStyle({ width: _ctx.pageWidth + 'px', height: _ctx.pageHeight + 'px', left: _ctx.viewWidth / 2 + 'px', top: _ctx.yMargin + 'px', }), src: _ctx.pageUrlLoading(_ctx.rightPage, true), onLoad: _cache[3] || (_cache[3] = function ($event) { return (_ctx.didLoadImage($event)); }) }, null, 44 /* STYLE, PROPS, HYDRATE_EVENTS */, _hoisted_2)) : vue.createCommentVNode("v-if", true), vue.createElementVNode("div", { style: vue.normalizeStyle({ opacity: _ctx.flip.opacity }) }, [ (vue.openBlock(true), vue.createElementBlock(vue.Fragment, null, vue.renderList(_ctx.polygonArray, function (ref) { var key = ref[0]; var bgImage = ref[1]; var lighting = ref[2]; var bgPos = ref[3]; var transform = ref[4]; var z = ref[5]; return (vue.openBlock(), vue.createElementBlock("div", { class: vue.normalizeClass(["polygon", { blank: !bgImage }]), key: key, style: vue.normalizeStyle({ backgroundImage: bgImage && ("url(" + (_ctx.loadImage(bgImage)) + ")"), backgroundSize: _ctx.polygonBgSize, backgroundPosition: bgPos, width: _ctx.polygonWidth, height: _ctx.polygonHeight, transform: transform, zIndex: z, }) }, [ vue.withDirectives(vue.createElementVNode("div", { class: "lighting", style: vue.normalizeStyle({ backgroundImage: lighting }) }, null, 4 /* STYLE */), [ [vue.vShow, lighting.length] ]) ], 6 /* CLASS, STYLE */)) }), 128 /* KEYED_FRAGMENT */)) ], 4 /* STYLE */), vue.createElementVNode("div", { class: "bounding-box", style: vue.normalizeStyle({ left: _ctx.boundingLeft + 'px', top: _ctx.yMargin + 'px', width: _ctx.boundingRight - _ctx.boundingLeft + 'px', height: _ctx.pageHeight + 'px', cursor: _ctx.cursor, }), onTouchstart: _cache[4] || (_cache[4] = function () { var args = [], len = arguments.length; while ( len-- ) args[ len ] = arguments[ len ]; return (_ctx.onTouchStart && _ctx.onTouchStart.apply(_ctx, args)); }), onPointerdown: _cache[5] || (_cache[5] = function () { var args = [], len = arguments.length; while ( len-- ) args[ len ] = arguments[ len ]; return (_ctx.onPointerDown && _ctx.onPointerDown.apply(_ctx, args)); }), onMousedown: _cache[6] || (_cache[6] = function () { var args = [], len = arguments.length; while ( len-- ) args[ len ] = arguments[ len ]; return (_ctx.onMouseDown && _ctx.onMouseDown.apply(_ctx, args)); }) }, null, 36 /* STYLE, HYDRATE_EVENTS */) ], 4 /* STYLE */) ], 4 /* STYLE */) ], 38 /* CLASS, STYLE, HYDRATE_EVENTS */) ])) } var e=[],t=[];function n(n,r){if(n&&"undefined"!=typeof document){var a,s=!0===r.prepend?"prepend":"append",d=!0===r.singleTag,i="string"==typeof r.container?document.querySelector(r.container):document.getElementsByTagName("head")[0];if(d){var u=e.indexOf(i);-1===u&&(u=e.push(i)-1,t[u]={}),a=t[u]&&t[u][s]?t[u][s]:t[u][s]=c();}else { a=c(); }65279===n.charCodeAt(0)&&(n=n.substring(1)),a.styleSheet?a.styleSheet.cssText+=n:a.appendChild(document.createTextNode(n));}function c(){var e=document.createElement("style");if(e.setAttribute("type","text/css"),r.attributes){ for(var t=Object.keys(r.attributes),n=0;n<t.length;n++){ e.setAttribute(t[n],r.attributes[t[n]]); } }var a="prepend"===s?"afterbegin":"beforeend";return i.insertAdjacentElement(a,e),e}} var css = ".viewport[data-v-5c04eecf]{-webkit-overflow-scrolling:touch;height:100%;width:100%}.viewport.zoom[data-v-5c04eecf]{overflow:scroll}.viewport.zoom.drag-to-scroll[data-v-5c04eecf]{overflow:hidden}.flipbook-container[data-v-5c04eecf]{height:100%;position:relative;-webkit-transform-origin:top left;transform-origin:top left;-webkit-user-select:none;user-select:none;width:100%}.click-to-flip[data-v-5c04eecf]{height:100%;position:absolute;top:0;-webkit-user-select:none;user-select:none;width:50%}.click-to-flip.left[data-v-5c04eecf]{left:0}.click-to-flip.right[data-v-5c04eecf]{right:0}.bounding-box[data-v-5c04eecf]{position:absolute;-webkit-user-select:none;user-select:none}.page[data-v-5c04eecf],.polygon[data-v-5c04eecf]{-webkit-backface-visibility:hidden;backface-visibility:hidden;position:absolute}.polygon[data-v-5c04eecf]{background-repeat:no-repeat;left:0;top:0;-webkit-transform-origin:center left;transform-orig