diff --git a/README.md b/README.md index 8d868ca2..cbbea431 100644 --- a/README.md +++ b/README.md @@ -62,11 +62,11 @@ Under project folder: `yarn watch` -Now open up `index.html` and play around with it! +Open up `index.html` and play around with it! ## Test -Open up `test.html` for browser testing. +Open up `test.html` for browser testing (keep your cursor away from the browser window). ## Methods @@ -103,8 +103,8 @@ Takes an options object. Available options: | enableGrab | Boolean | true | To be able to grab and drag the image for extra zoom-in. | | preloadImage | Boolean | true | Preload images with attribute `data-original`. | | transitionDuration | Number | 0.4 | Transition duration in seconds. [More](https://developer.mozilla.org/en-US/docs/Web/CSS/transition-duration) | -| transitionTimingFunction | String | 'cubic-bezier(.4,0,0,1)' | Transition timing function. [More](https://developer.mozilla.org/en-US/docs/Web/CSS/single-transition-timing-function) | -| bgColor | String | '#fff' | Overlay background color. | +| transitionTimingFunction | String | 'cubic-bezier(0.4, 0, 0, 1)' | Transition timing function. [More](https://developer.mozilla.org/en-US/docs/Web/CSS/single-transition-timing-function) | +| bgColor | String | 'rgb(255, 255, 255)' | Overlay background color. | | bgOpacity | Number | 1 | Overlay background capacity. | | scaleBase | Number | 1.0 | The base scale factor for zooming. By default scale to fit the window. | | scaleExtra | Number | 0.5 | The extra scale factor when grabbing the image. | diff --git a/bower.json b/bower.json index 800f3eba..768a76e0 100644 --- a/bower.json +++ b/bower.json @@ -1,6 +1,6 @@ { "name": "zooming", - "version": "0.6.3", + "version": "0.6.4", "homepage": "https://github.com/kingdido999/zooming", "authors": [ "Desmond Ding " diff --git a/build/zooming.js b/build/zooming.js index a3c6ec8a..6b360e69 100644 --- a/build/zooming.js +++ b/build/zooming.js @@ -7,26 +7,6 @@ // webkit prefix var prefix = 'WebkitAppearance' in document.documentElement.style ? '-webkit-' : ''; -var options = { - defaultZoomable: 'img[data-action="zoom"]', - enableGrab: true, - preloadImage: true, - transitionDuration: 0.4, - transitionTimingFunction: 'cubic-bezier(.4,0,0,1)', - bgColor: '#fff', - bgOpacity: 1, - scaleBase: 1.0, - scaleExtra: 0.5, - scrollThreshold: 40, - onOpen: null, - onClose: null, - onRelease: null, - onBeforeOpen: null, - onBeforeClose: null, - onBeforeGrab: null, - onBeforeRelease: null -}; - var sniffTransition = function sniffTransition(el) { var ret = {}; var trans = ['webkitTransition', 'transition', 'mozTransition']; @@ -98,9 +78,28 @@ var preloadImage = function preloadImage(url) { return new Image().src = url; }; +var options = { + defaultZoomable: 'img[data-action="zoom"]', + enableGrab: true, + preloadImage: true, + transitionDuration: 0.4, + transitionTimingFunction: 'cubic-bezier(0.4, 0, 0, 1)', + bgColor: 'rgb(255, 255, 255)', + bgOpacity: 1, + scaleBase: 1.0, + scaleExtra: 0.5, + scrollThreshold: 40, + onOpen: null, + onClose: null, + onRelease: null, + onBeforeOpen: null, + onBeforeClose: null, + onBeforeGrab: null, + onBeforeRelease: null +}; + var _this = undefined; -// elements var body = document.body; var overlay = document.createElement('div'); var target = void 0; @@ -287,9 +286,10 @@ var eventHandler = { // init ------------------------------------------------------------------------ +overlay.setAttribute('id', 'zoom-overlay'); setStyle$1(overlay, { zIndex: 998, - background: options.bgColor, + backgroundColor: options.bgColor, position: 'fixed', top: 0, left: 0, diff --git a/build/zooming.js.map b/build/zooming.js.map index d931f0ba..ce42745e 100644 --- a/build/zooming.js.map +++ b/build/zooming.js.map @@ -1 +1 @@ -{"version":3,"file":null,"sources":["../src/helpers.js","../src/zooming.js"],"sourcesContent":["// webkit prefix\nconst prefix = 'WebkitAppearance' in document.documentElement.style ? '-webkit-' : ''\n\nconst options = {\n defaultZoomable: 'img[data-action=\"zoom\"]',\n enableGrab: true,\n preloadImage: true,\n transitionDuration: 0.4,\n transitionTimingFunction: 'cubic-bezier(.4,0,0,1)',\n bgColor: '#fff',\n bgOpacity: 1,\n scaleBase: 1.0,\n scaleExtra: 0.5,\n scrollThreshold: 40,\n onOpen: null,\n onClose: null,\n onRelease: null,\n onBeforeOpen: null,\n onBeforeClose: null,\n onBeforeGrab: null,\n onBeforeRelease: null\n}\n\nconst sniffTransition = (el) => {\n let ret = {}\n const trans = ['webkitTransition', 'transition', 'mozTransition']\n const tform = ['webkitTransform', 'transform', 'mozTransform']\n const end = {\n 'transition' : 'transitionend',\n 'mozTransition' : 'transitionend',\n 'webkitTransition' : 'webkitTransitionEnd'\n }\n\n trans.some(prop => {\n if (el.style[prop] !== undefined) {\n ret.transitionProp = prop\n ret.transEndEvent = end[prop]\n return true\n }\n })\n\n tform.some(prop => {\n if (el.style[prop] !== undefined) {\n ret.transformProp = prop\n ret.transformCssProp = prop.replace(/(.*)Transform/, '-$1-transform')\n return true\n }\n })\n\n return ret\n}\n\nconst checkTrans = (transitionProp, transformProp) => {\n return function setStyle(el, styles, remember) {\n let value\n if (styles.transition) {\n value = styles.transition\n delete styles.transition\n styles[transitionProp] = value\n }\n if (styles.transform) {\n value = styles.transform\n delete styles.transform\n styles[transformProp] = value\n }\n\n let s = el.style\n let original = {}\n\n for (let key in styles) {\n if (remember) original[key] = s[key] || ''\n s[key] = styles[key]\n }\n\n return original\n }\n}\n\nconst toggleListeners = (el, types, handler, add = true) => {\n types.forEach(t => {\n if (add) {\n el.addEventListener(t, handler[t])\n } else {\n el.removeEventListener(t, handler[t])\n }\n })\n}\n\nconst preloadImage = (url) => (new Image()).src = url\n\nexport {\n prefix,\n options,\n sniffTransition,\n checkTrans,\n toggleListeners,\n preloadImage\n}\n","import { prefix, options, sniffTransition, checkTrans, toggleListeners, preloadImage } from './helpers'\n\n// elements\nconst body = document.body\nconst overlay = document.createElement('div')\nlet target, parent\n\n// state\nlet shown = false // image is open\nlet lock = false // image is in transform\nlet released = true // mouse/finger is not pressing down\nlet multitouch = false\nlet lastScrollPosition = null\nlet translate, scale, srcThumbnail, pressTimer, dynamicScaleExtra\n\n// style\nconst style = {\n close: null,\n open: null\n}\n\nconst trans = sniffTransition(overlay)\nconst transformCssProp = trans.transformCssProp\nconst transEndEvent = trans.transEndEvent\nconst setStyleHelper = checkTrans(trans.transitionProp, trans.transformProp)\n\nconst PRESS_DELAY = 200\nconst TOUCH_SCALE_FACTOR = 2\nconst GRAB_EVENT_TYPES = [\n 'mousedown', 'mousemove', 'mouseup',\n 'touchstart', 'touchmove', 'touchend'\n]\n\n// helpers ---------------------------------------------------------------------\n\nconst setStyle = (el, styles, remember) => {\n return setStyleHelper(el, styles, remember)\n}\n\nconst calculateTransform = () => {\n const imgRect = target.getBoundingClientRect()\n const [imgHalfWidth, imgHalfHeight] = [imgRect.width / 2, imgRect.height / 2]\n\n const imgCenter = {\n x: imgRect.left + imgHalfWidth,\n y: imgRect.top + imgHalfHeight\n }\n\n const windowCenter = {\n x: window.innerWidth / 2,\n y: window.innerHeight / 2\n }\n\n // The distance between image edge and window edge\n const distFromImageEdgeToWindowEdge = {\n x: windowCenter.x - imgHalfWidth,\n y: windowCenter.y - imgHalfHeight\n }\n\n const scaleHorizontally = distFromImageEdgeToWindowEdge.x / imgHalfWidth\n const scaleVertically = distFromImageEdgeToWindowEdge.y / imgHalfHeight\n\n // The vector to translate image to the window center\n translate = {\n x: windowCenter.x - imgCenter.x,\n y: windowCenter.y - imgCenter.y\n }\n\n // The additional scale is based on the smaller value of\n // scaling horizontally and scaling vertically\n scale = options.scaleBase + Math.min(scaleHorizontally, scaleVertically)\n\n return `translate(${translate.x}px, ${translate.y}px) scale(${scale})`\n}\n\nconst processTouches = (touches, cb) => {\n const total = touches.length\n const firstTouch = touches[0]\n\n let i = touches.length\n let [xs, ys] = [0, 0]\n\n // keep track of the min and max of touch positions\n let min = { x: firstTouch.clientX, y: firstTouch.clientY }\n let max = { x: firstTouch.clientX, y: firstTouch.clientY }\n\n multitouch = total > 1\n\n while (i--) {\n const t = touches[i]\n const [x, y] = [t.clientX, t.clientY]\n xs += x\n ys += y\n\n if (multitouch) {\n if (x < min.x) min.x = x\n else if (x > max.x) max.x = x\n\n if (y < min.y) min.y = y\n else if (y > max.y) max.y = y\n }\n }\n\n if (multitouch) {\n // change scaleExtra dynamically\n const [distX, distY] = [max.x - min.x, max.y - min.y]\n if (distX > distY) dynamicScaleExtra = (distX / window.innerWidth) * TOUCH_SCALE_FACTOR\n else dynamicScaleExtra = (distY / window.innerHeight) * TOUCH_SCALE_FACTOR\n }\n\n cb(xs / total, ys / total)\n}\n\nconst eventHandler = {\n\n scroll: function () {\n const scrollTop = window.pageYOffset ||\n (document.documentElement || body.parentNode || body).scrollTop\n\n if (lastScrollPosition === null) lastScrollPosition = scrollTop\n\n const deltaY = lastScrollPosition - scrollTop\n\n if (Math.abs(deltaY) >= options.scrollThreshold) {\n lastScrollPosition = null\n api.close()\n }\n },\n\n keydown: function (e) {\n const code = e.key || e.code\n if (code === 'Escape' || e.keyCode === 27) api.close()\n },\n\n mousedown: function (e) {\n e.preventDefault()\n\n pressTimer = setTimeout(function () {\n api.grab(e.clientX, e.clientY, true)\n }, PRESS_DELAY)\n },\n\n mousemove: function (e) {\n if (released) return\n api.grab(e.clientX, e.clientY)\n },\n\n mouseup: function () {\n clearTimeout(pressTimer)\n },\n\n touchstart: function (e) {\n e.preventDefault()\n\n pressTimer = setTimeout(() => {\n processTouches(e.touches, (x, y) => api.grab(x, y, true))\n }, PRESS_DELAY)\n },\n\n touchmove: function (e) {\n if (released) return\n processTouches(e.touches, (x, y) => api.grab(x, y))\n },\n\n touchend: function (e) {\n if (e.targetTouches.length > 0) return\n clearTimeout(pressTimer)\n\n if (released) {\n api.close()\n } else {\n api.release()\n }\n }\n}\n\n// init ------------------------------------------------------------------------\n\nsetStyle(overlay, {\n zIndex: 998,\n background: options.bgColor,\n position: 'fixed',\n top: 0,\n left: 0,\n right: 0,\n bottom: 0,\n opacity: 0,\n transition: `opacity\n ${options.transitionDuration}s\n ${options.transitionTimingFunction}`\n})\n\noverlay.addEventListener('click', () => api.close())\ndocument.addEventListener('DOMContentLoaded', () => api.listen(options.defaultZoomable))\n\n// API -------------------------------------------------------------------------\n\nconst api = {\n\n listen: (el) => {\n if (typeof el === 'string') {\n let els = document.querySelectorAll(el), i = els.length\n\n while (i--) {\n api.listen(els[i])\n }\n\n return this\n }\n\n if (el.tagName !== 'IMG') return\n\n el.style.cursor = `${prefix}zoom-in`\n\n el.addEventListener('click', (e) => {\n e.preventDefault()\n\n if (shown) {\n if (released) {\n api.close()\n } else {\n api.release()\n }\n } else {\n api.open(el)\n }\n })\n\n if (options.preloadImage && el.hasAttribute('data-original')) {\n preloadImage(el.getAttribute('data-original'))\n }\n\n return this\n },\n\n config: (opts) => {\n if (!opts) return options\n\n for (let key in opts) {\n options[key] = opts[key]\n }\n\n setStyle(overlay, {\n backgroundColor: options.bgColor,\n transition: `opacity\n ${options.transitionDuration}s\n ${options.transitionTimingFunction}`\n })\n\n return this\n },\n\n open: (el, cb = options.onOpen) => {\n if (shown || lock) return\n\n target = typeof el === 'string'\n ? document.querySelector(el)\n : el\n\n if (target.tagName !== 'IMG') return\n\n // onBeforeOpen event\n if (options.onBeforeOpen) options.onBeforeOpen(target)\n\n shown = true\n lock = true\n parent = target.parentNode\n\n // force layout update\n target.offsetWidth\n\n style.open = {\n position: 'relative',\n zIndex: 999,\n cursor: `${prefix}${options.enableGrab ? 'grab' : 'zoom-out'}`,\n transition: `${transformCssProp}\n ${options.transitionDuration}s\n ${options.transitionTimingFunction}`,\n transform: calculateTransform()\n }\n\n // trigger transition\n style.close = setStyle(target, style.open, true)\n\n parent.appendChild(overlay)\n setTimeout(() => overlay.style.opacity = options.bgOpacity, 30)\n\n document.addEventListener('scroll', eventHandler.scroll)\n document.addEventListener('keydown', eventHandler.keydown)\n\n target.addEventListener(transEndEvent, function onEnd () {\n target.removeEventListener(transEndEvent, onEnd)\n\n if (options.enableGrab) toggleListeners(target, GRAB_EVENT_TYPES, eventHandler, true)\n\n lock = false\n\n // upgrade source if possible\n if (target.hasAttribute('data-original')) {\n srcThumbnail = target.getAttribute('src')\n target.setAttribute('src', target.getAttribute('data-original'))\n }\n\n if (cb) cb(target)\n })\n\n return this\n },\n\n close: (cb = options.onClose) => {\n if (!shown || lock) return\n lock = true\n\n // onBeforeClose event\n if (options.onBeforeClose) options.onBeforeClose(target)\n\n // force layout update\n target.offsetWidth\n\n overlay.style.opacity = 0\n setStyle(target, { transform: 'none' })\n\n document.removeEventListener('scroll', eventHandler.scroll)\n document.removeEventListener('keydown', eventHandler.keydown)\n\n target.addEventListener(transEndEvent, function onEnd () {\n target.removeEventListener(transEndEvent, onEnd)\n\n if (options.enableGrab) toggleListeners(target, GRAB_EVENT_TYPES, eventHandler, false)\n\n shown = false\n lock = false\n\n // downgrade source if possible\n if (target.hasAttribute('data-original')) {\n target.setAttribute('src', srcThumbnail)\n }\n\n setStyle(target, style.close)\n parent.removeChild(overlay)\n\n if (cb) cb(target)\n })\n\n return this\n },\n\n grab: (x, y, start, cb) => {\n if (!shown || lock) return\n released = false\n\n // onBeforeGrab event\n if (options.onBeforeGrab) options.onBeforeGrab(target)\n\n const [dx, dy] = [window.innerWidth / 2 - x, window.innerHeight / 2 - y]\n const scaleExtra = multitouch ? dynamicScaleExtra : options.scaleExtra\n const transform = target.style.transform\n .replace(/translate\\(.*?\\)/i, `translate(${translate.x + dx}px, ${translate.y + dy}px)`)\n .replace(/scale\\([0-9|\\.]*\\)/i, `scale(${scale + scaleExtra})`)\n\n setStyle(target, {\n cursor: 'move',\n transition: `${transformCssProp} ${start\n ? options.transitionDuration + 's ' + options.transitionTimingFunction\n : 'ease'}`,\n transform: transform\n })\n\n target.addEventListener(transEndEvent, function onEnd () {\n target.removeEventListener(transEndEvent, onEnd)\n if (cb) cb(target)\n })\n },\n\n release: (cb = options.onRelease) => {\n if (!shown || lock) return\n lock = true\n\n // onBeforeRelease event\n if (options.onBeforeRelease) options.onBeforeRelease(target)\n\n setStyle(target, style.open)\n\n target.addEventListener(transEndEvent, function onEnd () {\n target.removeEventListener(transEndEvent, onEnd)\n\n lock = false\n released = true\n\n if (cb) cb(target)\n })\n\n return this\n }\n}\n\nexport default api\n"],"names":["prefix","document","documentElement","style","options","sniffTransition","el","ret","trans","tform","end","some","prop","undefined","transitionProp","transEndEvent","transformProp","transformCssProp","replace","checkTrans","setStyle","styles","remember","value","transition","transform","s","original","key","toggleListeners","types","handler","add","forEach","addEventListener","t","removeEventListener","preloadImage","url","Image","src","body","overlay","createElement","target","parent","shown","lock","released","multitouch","lastScrollPosition","translate","scale","srcThumbnail","pressTimer","dynamicScaleExtra","setStyleHelper","PRESS_DELAY","TOUCH_SCALE_FACTOR","GRAB_EVENT_TYPES","calculateTransform","imgRect","getBoundingClientRect","imgHalfWidth","width","imgHalfHeight","height","imgCenter","left","top","windowCenter","window","innerWidth","innerHeight","distFromImageEdgeToWindowEdge","x","y","scaleHorizontally","scaleVertically","scaleBase","Math","min","processTouches","touches","cb","total","length","firstTouch","i","xs","ys","clientX","clientY","max","distX","distY","eventHandler","scrollTop","pageYOffset","parentNode","deltaY","abs","scrollThreshold","close","e","code","keyCode","api","preventDefault","setTimeout","grab","targetTouches","release","bgColor","transitionDuration","transitionTimingFunction","listen","defaultZoomable","els","querySelectorAll","tagName","cursor","open","hasAttribute","getAttribute","opts","onOpen","querySelector","onBeforeOpen","offsetWidth","enableGrab","appendChild","opacity","bgOpacity","scroll","keydown","onEnd","setAttribute","onClose","onBeforeClose","removeChild","start","onBeforeGrab","dx","dy","scaleExtra","onRelease","onBeforeRelease"],"mappings":"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"} \ No newline at end of file +{"version":3,"file":null,"sources":["../src/helpers.js","../src/options.js","../src/zooming.js"],"sourcesContent":["// webkit prefix\nconst prefix = 'WebkitAppearance' in document.documentElement.style ? '-webkit-' : ''\n\nconst sniffTransition = (el) => {\n let ret = {}\n const trans = ['webkitTransition', 'transition', 'mozTransition']\n const tform = ['webkitTransform', 'transform', 'mozTransform']\n const end = {\n 'transition' : 'transitionend',\n 'mozTransition' : 'transitionend',\n 'webkitTransition' : 'webkitTransitionEnd'\n }\n\n trans.some(prop => {\n if (el.style[prop] !== undefined) {\n ret.transitionProp = prop\n ret.transEndEvent = end[prop]\n return true\n }\n })\n\n tform.some(prop => {\n if (el.style[prop] !== undefined) {\n ret.transformProp = prop\n ret.transformCssProp = prop.replace(/(.*)Transform/, '-$1-transform')\n return true\n }\n })\n\n return ret\n}\n\nconst checkTrans = (transitionProp, transformProp) => {\n return function setStyle(el, styles, remember) {\n let value\n if (styles.transition) {\n value = styles.transition\n delete styles.transition\n styles[transitionProp] = value\n }\n if (styles.transform) {\n value = styles.transform\n delete styles.transform\n styles[transformProp] = value\n }\n\n let s = el.style\n let original = {}\n\n for (let key in styles) {\n if (remember) original[key] = s[key] || ''\n s[key] = styles[key]\n }\n\n return original\n }\n}\n\nconst toggleListeners = (el, types, handler, add = true) => {\n types.forEach(t => {\n if (add) {\n el.addEventListener(t, handler[t])\n } else {\n el.removeEventListener(t, handler[t])\n }\n })\n}\n\nconst preloadImage = (url) => (new Image()).src = url\n\nexport {\n prefix,\n sniffTransition,\n checkTrans,\n toggleListeners,\n preloadImage\n}\n","export const options = {\n defaultZoomable: 'img[data-action=\"zoom\"]',\n enableGrab: true,\n preloadImage: true,\n transitionDuration: 0.4,\n transitionTimingFunction: 'cubic-bezier(0.4, 0, 0, 1)',\n bgColor: 'rgb(255, 255, 255)',\n bgOpacity: 1,\n scaleBase: 1.0,\n scaleExtra: 0.5,\n scrollThreshold: 40,\n onOpen: null,\n onClose: null,\n onRelease: null,\n onBeforeOpen: null,\n onBeforeClose: null,\n onBeforeGrab: null,\n onBeforeRelease: null\n}\n","import { prefix, sniffTransition, checkTrans, toggleListeners, preloadImage } from './helpers'\nimport { options } from './options'\n\n// elements\nconst body = document.body\nconst overlay = document.createElement('div')\nlet target, parent\n\n// state\nlet shown = false // image is open\nlet lock = false // image is in transform\nlet released = true // mouse/finger is not pressing down\nlet multitouch = false\nlet lastScrollPosition = null\nlet translate, scale, srcThumbnail, pressTimer, dynamicScaleExtra\n\n// style\nconst style = {\n close: null,\n open: null\n}\n\nconst trans = sniffTransition(overlay)\nconst transformCssProp = trans.transformCssProp\nconst transEndEvent = trans.transEndEvent\nconst setStyleHelper = checkTrans(trans.transitionProp, trans.transformProp)\n\nconst PRESS_DELAY = 200\nconst TOUCH_SCALE_FACTOR = 2\nconst GRAB_EVENT_TYPES = [\n 'mousedown', 'mousemove', 'mouseup',\n 'touchstart', 'touchmove', 'touchend'\n]\n\n// helpers ---------------------------------------------------------------------\n\nconst setStyle = (el, styles, remember) => {\n return setStyleHelper(el, styles, remember)\n}\n\nconst calculateTransform = () => {\n const imgRect = target.getBoundingClientRect()\n const [imgHalfWidth, imgHalfHeight] = [imgRect.width / 2, imgRect.height / 2]\n\n const imgCenter = {\n x: imgRect.left + imgHalfWidth,\n y: imgRect.top + imgHalfHeight\n }\n\n const windowCenter = {\n x: window.innerWidth / 2,\n y: window.innerHeight / 2\n }\n\n // The distance between image edge and window edge\n const distFromImageEdgeToWindowEdge = {\n x: windowCenter.x - imgHalfWidth,\n y: windowCenter.y - imgHalfHeight\n }\n\n const scaleHorizontally = distFromImageEdgeToWindowEdge.x / imgHalfWidth\n const scaleVertically = distFromImageEdgeToWindowEdge.y / imgHalfHeight\n\n // The vector to translate image to the window center\n translate = {\n x: windowCenter.x - imgCenter.x,\n y: windowCenter.y - imgCenter.y\n }\n\n // The additional scale is based on the smaller value of\n // scaling horizontally and scaling vertically\n scale = options.scaleBase + Math.min(scaleHorizontally, scaleVertically)\n\n return `translate(${translate.x}px, ${translate.y}px) scale(${scale})`\n}\n\nconst processTouches = (touches, cb) => {\n const total = touches.length\n const firstTouch = touches[0]\n\n let i = touches.length\n let [xs, ys] = [0, 0]\n\n // keep track of the min and max of touch positions\n let min = { x: firstTouch.clientX, y: firstTouch.clientY }\n let max = { x: firstTouch.clientX, y: firstTouch.clientY }\n\n multitouch = total > 1\n\n while (i--) {\n const t = touches[i]\n const [x, y] = [t.clientX, t.clientY]\n xs += x\n ys += y\n\n if (multitouch) {\n if (x < min.x) min.x = x\n else if (x > max.x) max.x = x\n\n if (y < min.y) min.y = y\n else if (y > max.y) max.y = y\n }\n }\n\n if (multitouch) {\n // change scaleExtra dynamically\n const [distX, distY] = [max.x - min.x, max.y - min.y]\n if (distX > distY) dynamicScaleExtra = (distX / window.innerWidth) * TOUCH_SCALE_FACTOR\n else dynamicScaleExtra = (distY / window.innerHeight) * TOUCH_SCALE_FACTOR\n }\n\n cb(xs / total, ys / total)\n}\n\nconst eventHandler = {\n\n scroll: function () {\n const scrollTop = window.pageYOffset ||\n (document.documentElement || body.parentNode || body).scrollTop\n\n if (lastScrollPosition === null) lastScrollPosition = scrollTop\n\n const deltaY = lastScrollPosition - scrollTop\n\n if (Math.abs(deltaY) >= options.scrollThreshold) {\n lastScrollPosition = null\n api.close()\n }\n },\n\n keydown: function (e) {\n const code = e.key || e.code\n if (code === 'Escape' || e.keyCode === 27) api.close()\n },\n\n mousedown: function (e) {\n e.preventDefault()\n\n pressTimer = setTimeout(function () {\n api.grab(e.clientX, e.clientY, true)\n }, PRESS_DELAY)\n },\n\n mousemove: function (e) {\n if (released) return\n api.grab(e.clientX, e.clientY)\n },\n\n mouseup: function () {\n clearTimeout(pressTimer)\n },\n\n touchstart: function (e) {\n e.preventDefault()\n\n pressTimer = setTimeout(() => {\n processTouches(e.touches, (x, y) => api.grab(x, y, true))\n }, PRESS_DELAY)\n },\n\n touchmove: function (e) {\n if (released) return\n processTouches(e.touches, (x, y) => api.grab(x, y))\n },\n\n touchend: function (e) {\n if (e.targetTouches.length > 0) return\n clearTimeout(pressTimer)\n\n if (released) {\n api.close()\n } else {\n api.release()\n }\n }\n}\n\n// init ------------------------------------------------------------------------\n\noverlay.setAttribute('id', 'zoom-overlay')\nsetStyle(overlay, {\n zIndex: 998,\n backgroundColor: options.bgColor,\n position: 'fixed',\n top: 0,\n left: 0,\n right: 0,\n bottom: 0,\n opacity: 0,\n transition: `opacity\n ${options.transitionDuration}s\n ${options.transitionTimingFunction}`\n})\n\noverlay.addEventListener('click', () => api.close())\ndocument.addEventListener('DOMContentLoaded', () => api.listen(options.defaultZoomable))\n\n// API -------------------------------------------------------------------------\n\nconst api = {\n\n listen: (el) => {\n if (typeof el === 'string') {\n let els = document.querySelectorAll(el), i = els.length\n\n while (i--) {\n api.listen(els[i])\n }\n\n return this\n }\n\n if (el.tagName !== 'IMG') return\n\n el.style.cursor = `${prefix}zoom-in`\n\n el.addEventListener('click', (e) => {\n e.preventDefault()\n\n if (shown) {\n if (released) {\n api.close()\n } else {\n api.release()\n }\n } else {\n api.open(el)\n }\n })\n\n if (options.preloadImage && el.hasAttribute('data-original')) {\n preloadImage(el.getAttribute('data-original'))\n }\n\n return this\n },\n\n config: (opts) => {\n if (!opts) return options\n\n for (let key in opts) {\n options[key] = opts[key]\n }\n\n setStyle(overlay, {\n backgroundColor: options.bgColor,\n transition: `opacity\n ${options.transitionDuration}s\n ${options.transitionTimingFunction}`\n })\n\n return this\n },\n\n open: (el, cb = options.onOpen) => {\n if (shown || lock) return\n\n target = typeof el === 'string'\n ? document.querySelector(el)\n : el\n\n if (target.tagName !== 'IMG') return\n\n // onBeforeOpen event\n if (options.onBeforeOpen) options.onBeforeOpen(target)\n\n shown = true\n lock = true\n parent = target.parentNode\n\n // force layout update\n target.offsetWidth\n\n style.open = {\n position: 'relative',\n zIndex: 999,\n cursor: `${prefix}${options.enableGrab ? 'grab' : 'zoom-out'}`,\n transition: `${transformCssProp}\n ${options.transitionDuration}s\n ${options.transitionTimingFunction}`,\n transform: calculateTransform()\n }\n\n // trigger transition\n style.close = setStyle(target, style.open, true)\n\n parent.appendChild(overlay)\n setTimeout(() => overlay.style.opacity = options.bgOpacity, 30)\n\n document.addEventListener('scroll', eventHandler.scroll)\n document.addEventListener('keydown', eventHandler.keydown)\n\n target.addEventListener(transEndEvent, function onEnd () {\n target.removeEventListener(transEndEvent, onEnd)\n\n if (options.enableGrab) toggleListeners(target, GRAB_EVENT_TYPES, eventHandler, true)\n\n lock = false\n\n // upgrade source if possible\n if (target.hasAttribute('data-original')) {\n srcThumbnail = target.getAttribute('src')\n target.setAttribute('src', target.getAttribute('data-original'))\n }\n\n if (cb) cb(target)\n })\n\n return this\n },\n\n close: (cb = options.onClose) => {\n if (!shown || lock) return\n lock = true\n\n // onBeforeClose event\n if (options.onBeforeClose) options.onBeforeClose(target)\n\n // force layout update\n target.offsetWidth\n\n overlay.style.opacity = 0\n setStyle(target, { transform: 'none' })\n\n document.removeEventListener('scroll', eventHandler.scroll)\n document.removeEventListener('keydown', eventHandler.keydown)\n\n target.addEventListener(transEndEvent, function onEnd () {\n target.removeEventListener(transEndEvent, onEnd)\n\n if (options.enableGrab) toggleListeners(target, GRAB_EVENT_TYPES, eventHandler, false)\n\n shown = false\n lock = false\n\n // downgrade source if possible\n if (target.hasAttribute('data-original')) {\n target.setAttribute('src', srcThumbnail)\n }\n\n setStyle(target, style.close)\n parent.removeChild(overlay)\n\n if (cb) cb(target)\n })\n\n return this\n },\n\n grab: (x, y, start, cb) => {\n if (!shown || lock) return\n released = false\n\n // onBeforeGrab event\n if (options.onBeforeGrab) options.onBeforeGrab(target)\n\n const [dx, dy] = [window.innerWidth / 2 - x, window.innerHeight / 2 - y]\n const scaleExtra = multitouch ? dynamicScaleExtra : options.scaleExtra\n const transform = target.style.transform\n .replace(/translate\\(.*?\\)/i, `translate(${translate.x + dx}px, ${translate.y + dy}px)`)\n .replace(/scale\\([0-9|\\.]*\\)/i, `scale(${scale + scaleExtra})`)\n\n setStyle(target, {\n cursor: 'move',\n transition: `${transformCssProp} ${start\n ? options.transitionDuration + 's ' + options.transitionTimingFunction\n : 'ease'}`,\n transform: transform\n })\n\n target.addEventListener(transEndEvent, function onEnd () {\n target.removeEventListener(transEndEvent, onEnd)\n if (cb) cb(target)\n })\n },\n\n release: (cb = options.onRelease) => {\n if (!shown || lock) return\n lock = true\n\n // onBeforeRelease event\n if (options.onBeforeRelease) options.onBeforeRelease(target)\n\n setStyle(target, style.open)\n\n target.addEventListener(transEndEvent, function onEnd () {\n target.removeEventListener(transEndEvent, onEnd)\n\n lock = false\n released = true\n\n if (cb) cb(target)\n })\n\n return this\n }\n}\n\nexport default api\n"],"names":["prefix","document","documentElement","style","sniffTransition","el","ret","trans","tform","end","some","prop","undefined","transitionProp","transEndEvent","transformProp","transformCssProp","replace","checkTrans","setStyle","styles","remember","value","transition","transform","s","original","key","toggleListeners","types","handler","add","forEach","addEventListener","t","removeEventListener","preloadImage","url","Image","src","options","body","overlay","createElement","target","parent","shown","lock","released","multitouch","lastScrollPosition","translate","scale","srcThumbnail","pressTimer","dynamicScaleExtra","setStyleHelper","PRESS_DELAY","TOUCH_SCALE_FACTOR","GRAB_EVENT_TYPES","calculateTransform","imgRect","getBoundingClientRect","imgHalfWidth","width","imgHalfHeight","height","imgCenter","left","top","windowCenter","window","innerWidth","innerHeight","distFromImageEdgeToWindowEdge","x","y","scaleHorizontally","scaleVertically","scaleBase","Math","min","processTouches","touches","cb","total","length","firstTouch","i","xs","ys","clientX","clientY","max","distX","distY","eventHandler","scrollTop","pageYOffset","parentNode","deltaY","abs","scrollThreshold","close","e","code","keyCode","api","preventDefault","setTimeout","grab","targetTouches","release","setAttribute","bgColor","transitionDuration","transitionTimingFunction","listen","defaultZoomable","els","querySelectorAll","tagName","cursor","open","hasAttribute","getAttribute","opts","onOpen","querySelector","onBeforeOpen","offsetWidth","enableGrab","appendChild","opacity","bgOpacity","scroll","keydown","onEnd","onClose","onBeforeClose","removeChild","start","onBeforeGrab","dx","dy","scaleExtra","onRelease","onBeforeRelease"],"mappings":"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"} \ No newline at end of file diff --git a/build/zooming.min.js b/build/zooming.min.js index 80e340b9..76730a2c 100644 --- a/build/zooming.min.js +++ b/build/zooming.min.js @@ -1,2 +1,2 @@ -!function(n,e){"object"==typeof exports&&"undefined"!=typeof module?module.exports=e():"function"==typeof define&&define.amd?define(e):n.Zooming=e()}(this,function(){"use strict";var n="WebkitAppearance"in document.documentElement.style?"-webkit-":"",e={defaultZoomable:'img[data-action="zoom"]',enableGrab:!0,preloadImage:!0,transitionDuration:.4,transitionTimingFunction:"cubic-bezier(.4,0,0,1)",bgColor:"#fff",bgOpacity:1,scaleBase:1,scaleExtra:.5,scrollThreshold:40,onOpen:null,onClose:null,onRelease:null,onBeforeOpen:null,onBeforeClose:null,onBeforeGrab:null,onBeforeRelease:null},t=function(n){var e={},t=["webkitTransition","transition","mozTransition"],o=["webkitTransform","transform","mozTransform"],r={transition:"transitionend",mozTransition:"transitionend",webkitTransition:"webkitTransitionEnd"};return t.some(function(t){if(void 0!==n.style[t])return e.transitionProp=t,e.transEndEvent=r[t],!0}),o.some(function(t){if(void 0!==n.style[t])return e.transformProp=t,e.transformCssProp=t.replace(/(.*)Transform/,"-$1-transform"),!0}),e},o=function(n,e){return function(t,o,r){var i=void 0;o.transition&&(i=o.transition,delete o.transition,o[n]=i),o.transform&&(i=o.transform,delete o.transform,o[e]=i);var a=t.style,s={};for(var l in o)r&&(s[l]=a[l]||""),a[l]=o[l];return s}},r=function(n,e,t){var o=!(arguments.length>3&&void 0!==arguments[3])||arguments[3];e.forEach(function(e){o?n.addEventListener(e,t[e]):n.removeEventListener(e,t[e])})},i=function(n){return(new Image).src=n},a=void 0,s=document.body,l=document.createElement("div"),u=void 0,c=void 0,d=!1,f=!1,m=!0,v=!1,p=null,g=void 0,y=void 0,b=void 0,h=void 0,x=void 0,E={close:null,open:null},w=t(l),T=w.transformCssProp,L=w.transEndEvent,k=o(w.transitionProp,w.transformProp),C=200,B=2,A=["mousedown","mousemove","mouseup","touchstart","touchmove","touchend"],z=function(n,e,t){return k(n,e,t)},D=function(){var n=u.getBoundingClientRect(),t=n.width/2,o=n.height/2,r={x:n.left+t,y:n.top+o},i={x:window.innerWidth/2,y:window.innerHeight/2},a={x:i.x-t,y:i.y-o},s=a.x/t,l=a.y/o;return g={x:i.x-r.x,y:i.y-r.y},y=e.scaleBase+Math.min(s,l),"translate("+g.x+"px, "+g.y+"px) scale("+y+")"},G=function(n,e){var t=n.length,o=n[0],r=n.length,i=0,a=0,s={x:o.clientX,y:o.clientY},l={x:o.clientX,y:o.clientY};for(v=t>1;r--;){var u=n[r],c=[u.clientX,u.clientY],d=c[0],f=c[1];i+=d,a+=f,v&&(dl.x&&(l.x=d),fl.y&&(l.y=f))}if(v){var m=l.x-s.x,p=l.y-s.y;x=m>p?m/window.innerWidth*B:p/window.innerHeight*B}e(i/t,a/t)},O={scroll:function(){var n=window.pageYOffset||(document.documentElement||s.parentNode||s).scrollTop;null===p&&(p=n);var t=p-n;Math.abs(t)>=e.scrollThreshold&&(p=null,I.close())},keydown:function(n){var e=n.key||n.code;"Escape"!==e&&27!==n.keyCode||I.close()},mousedown:function(n){n.preventDefault(),h=setTimeout(function(){I.grab(n.clientX,n.clientY,!0)},C)},mousemove:function(n){m||I.grab(n.clientX,n.clientY)},mouseup:function(){clearTimeout(h)},touchstart:function(n){n.preventDefault(),h=setTimeout(function(){G(n.touches,function(n,e){return I.grab(n,e,!0)})},C)},touchmove:function(n){m||G(n.touches,function(n,e){return I.grab(n,e)})},touchend:function(n){n.targetTouches.length>0||(clearTimeout(h),m?I.close():I.release())}};z(l,{zIndex:998,background:e.bgColor,position:"fixed",top:0,left:0,right:0,bottom:0,opacity:0,transition:"opacity\n "+e.transitionDuration+"s\n "+e.transitionTimingFunction}),l.addEventListener("click",function(){return I.close()}),document.addEventListener("DOMContentLoaded",function(){return I.listen(e.defaultZoomable)});var I={listen:function(t){if("string"==typeof t){for(var o=document.querySelectorAll(t),r=o.length;r--;)I.listen(o[r]);return a}if("IMG"===t.tagName)return t.style.cursor=n+"zoom-in",t.addEventListener("click",function(n){n.preventDefault(),d?m?I.close():I.release():I.open(t)}),e.preloadImage&&t.hasAttribute("data-original")&&i(t.getAttribute("data-original")),a},config:function(n){if(!n)return e;for(var t in n)e[t]=n[t];return z(l,{backgroundColor:e.bgColor,transition:"opacity\n "+e.transitionDuration+"s\n "+e.transitionTimingFunction}),a},open:function(t){var o=arguments.length>1&&void 0!==arguments[1]?arguments[1]:e.onOpen;if(!d&&!f&&(u="string"==typeof t?document.querySelector(t):t,"IMG"===u.tagName))return e.onBeforeOpen&&e.onBeforeOpen(u),d=!0,f=!0,c=u.parentNode,u.offsetWidth,E.open={position:"relative",zIndex:999,cursor:""+n+(e.enableGrab?"grab":"zoom-out"),transition:T+"\n "+e.transitionDuration+"s\n "+e.transitionTimingFunction,transform:D()},E.close=z(u,E.open,!0),c.appendChild(l),setTimeout(function(){return l.style.opacity=e.bgOpacity},30),document.addEventListener("scroll",O.scroll),document.addEventListener("keydown",O.keydown),u.addEventListener(L,function n(){u.removeEventListener(L,n),e.enableGrab&&r(u,A,O,!0),f=!1,u.hasAttribute("data-original")&&(b=u.getAttribute("src"),u.setAttribute("src",u.getAttribute("data-original"))),o&&o(u)}),a},close:function(){var n=arguments.length>0&&void 0!==arguments[0]?arguments[0]:e.onClose;if(d&&!f)return f=!0,e.onBeforeClose&&e.onBeforeClose(u),u.offsetWidth,l.style.opacity=0,z(u,{transform:"none"}),document.removeEventListener("scroll",O.scroll),document.removeEventListener("keydown",O.keydown),u.addEventListener(L,function t(){u.removeEventListener(L,t),e.enableGrab&&r(u,A,O,!1),d=!1,f=!1,u.hasAttribute("data-original")&&u.setAttribute("src",b),z(u,E.close),c.removeChild(l),n&&n(u)}),a},grab:function(n,t,o,r){if(d&&!f){m=!1,e.onBeforeGrab&&e.onBeforeGrab(u);var i=window.innerWidth/2-n,a=window.innerHeight/2-t,s=v?x:e.scaleExtra,l=u.style.transform.replace(/translate\(.*?\)/i,"translate("+(g.x+i)+"px, "+(g.y+a)+"px)").replace(/scale\([0-9|\.]*\)/i,"scale("+(y+s)+")");z(u,{cursor:"move",transition:T+" "+(o?e.transitionDuration+"s "+e.transitionTimingFunction:"ease"),transform:l}),u.addEventListener(L,function n(){u.removeEventListener(L,n),r&&r(u)})}},release:function(){var n=arguments.length>0&&void 0!==arguments[0]?arguments[0]:e.onRelease;if(d&&!f)return f=!0,e.onBeforeRelease&&e.onBeforeRelease(u),z(u,E.open),u.addEventListener(L,function e(){u.removeEventListener(L,e),f=!1,m=!0,n&&n(u)}),a}};return I}); +!function(n,e){"object"==typeof exports&&"undefined"!=typeof module?module.exports=e():"function"==typeof define&&define.amd?define(e):n.Zooming=e()}(this,function(){"use strict";var n="WebkitAppearance"in document.documentElement.style?"-webkit-":"",e=function(n){var e={},t=["webkitTransition","transition","mozTransition"],o=["webkitTransform","transform","mozTransform"],r={transition:"transitionend",mozTransition:"transitionend",webkitTransition:"webkitTransitionEnd"};return t.some(function(t){if(void 0!==n.style[t])return e.transitionProp=t,e.transEndEvent=r[t],!0}),o.some(function(t){if(void 0!==n.style[t])return e.transformProp=t,e.transformCssProp=t.replace(/(.*)Transform/,"-$1-transform"),!0}),e},t=function(n,e){return function(t,o,r){var i=void 0;o.transition&&(i=o.transition,delete o.transition,o[n]=i),o.transform&&(i=o.transform,delete o.transform,o[e]=i);var a=t.style,s={};for(var l in o)r&&(s[l]=a[l]||""),a[l]=o[l];return s}},o=function(n,e,t){var o=!(arguments.length>3&&void 0!==arguments[3])||arguments[3];e.forEach(function(e){o?n.addEventListener(e,t[e]):n.removeEventListener(e,t[e])})},r=function(n){return(new Image).src=n},i={defaultZoomable:'img[data-action="zoom"]',enableGrab:!0,preloadImage:!0,transitionDuration:.4,transitionTimingFunction:"cubic-bezier(0.4, 0, 0, 1)",bgColor:"rgb(255, 255, 255)",bgOpacity:1,scaleBase:1,scaleExtra:.5,scrollThreshold:40,onOpen:null,onClose:null,onRelease:null,onBeforeOpen:null,onBeforeClose:null,onBeforeGrab:null,onBeforeRelease:null},a=void 0,s=document.body,l=document.createElement("div"),u=void 0,c=void 0,d=!1,f=!1,m=!0,v=!1,p=null,g=void 0,y=void 0,b=void 0,h=void 0,x=void 0,E={close:null,open:null},w=e(l),T=w.transformCssProp,L=w.transEndEvent,k=t(w.transitionProp,w.transformProp),C=200,B=2,A=["mousedown","mousemove","mouseup","touchstart","touchmove","touchend"],z=function(n,e,t){return k(n,e,t)},D=function(){var n=u.getBoundingClientRect(),e=n.width/2,t=n.height/2,o={x:n.left+e,y:n.top+t},r={x:window.innerWidth/2,y:window.innerHeight/2},a={x:r.x-e,y:r.y-t},s=a.x/e,l=a.y/t;return g={x:r.x-o.x,y:r.y-o.y},y=i.scaleBase+Math.min(s,l),"translate("+g.x+"px, "+g.y+"px) scale("+y+")"},G=function(n,e){var t=n.length,o=n[0],r=n.length,i=0,a=0,s={x:o.clientX,y:o.clientY},l={x:o.clientX,y:o.clientY};for(v=t>1;r--;){var u=n[r],c=[u.clientX,u.clientY],d=c[0],f=c[1];i+=d,a+=f,v&&(dl.x&&(l.x=d),fl.y&&(l.y=f))}if(v){var m=l.x-s.x,p=l.y-s.y;x=m>p?m/window.innerWidth*B:p/window.innerHeight*B}e(i/t,a/t)},O={scroll:function(){var n=window.pageYOffset||(document.documentElement||s.parentNode||s).scrollTop;null===p&&(p=n);var e=p-n;Math.abs(e)>=i.scrollThreshold&&(p=null,I.close())},keydown:function(n){var e=n.key||n.code;"Escape"!==e&&27!==n.keyCode||I.close()},mousedown:function(n){n.preventDefault(),h=setTimeout(function(){I.grab(n.clientX,n.clientY,!0)},C)},mousemove:function(n){m||I.grab(n.clientX,n.clientY)},mouseup:function(){clearTimeout(h)},touchstart:function(n){n.preventDefault(),h=setTimeout(function(){G(n.touches,function(n,e){return I.grab(n,e,!0)})},C)},touchmove:function(n){m||G(n.touches,function(n,e){return I.grab(n,e)})},touchend:function(n){n.targetTouches.length>0||(clearTimeout(h),m?I.close():I.release())}};l.setAttribute("id","zoom-overlay"),z(l,{zIndex:998,backgroundColor:i.bgColor,position:"fixed",top:0,left:0,right:0,bottom:0,opacity:0,transition:"opacity\n "+i.transitionDuration+"s\n "+i.transitionTimingFunction}),l.addEventListener("click",function(){return I.close()}),document.addEventListener("DOMContentLoaded",function(){return I.listen(i.defaultZoomable)});var I={listen:function(e){if("string"==typeof e){for(var t=document.querySelectorAll(e),o=t.length;o--;)I.listen(t[o]);return a}if("IMG"===e.tagName)return e.style.cursor=n+"zoom-in",e.addEventListener("click",function(n){n.preventDefault(),d?m?I.close():I.release():I.open(e)}),i.preloadImage&&e.hasAttribute("data-original")&&r(e.getAttribute("data-original")),a},config:function(n){if(!n)return i;for(var e in n)i[e]=n[e];return z(l,{backgroundColor:i.bgColor,transition:"opacity\n "+i.transitionDuration+"s\n "+i.transitionTimingFunction}),a},open:function(e){var t=arguments.length>1&&void 0!==arguments[1]?arguments[1]:i.onOpen;if(!d&&!f&&(u="string"==typeof e?document.querySelector(e):e,"IMG"===u.tagName))return i.onBeforeOpen&&i.onBeforeOpen(u),d=!0,f=!0,c=u.parentNode,u.offsetWidth,E.open={position:"relative",zIndex:999,cursor:""+n+(i.enableGrab?"grab":"zoom-out"),transition:T+"\n "+i.transitionDuration+"s\n "+i.transitionTimingFunction,transform:D()},E.close=z(u,E.open,!0),c.appendChild(l),setTimeout(function(){return l.style.opacity=i.bgOpacity},30),document.addEventListener("scroll",O.scroll),document.addEventListener("keydown",O.keydown),u.addEventListener(L,function n(){u.removeEventListener(L,n),i.enableGrab&&o(u,A,O,!0),f=!1,u.hasAttribute("data-original")&&(b=u.getAttribute("src"),u.setAttribute("src",u.getAttribute("data-original"))),t&&t(u)}),a},close:function(){var n=arguments.length>0&&void 0!==arguments[0]?arguments[0]:i.onClose;if(d&&!f)return f=!0,i.onBeforeClose&&i.onBeforeClose(u),u.offsetWidth,l.style.opacity=0,z(u,{transform:"none"}),document.removeEventListener("scroll",O.scroll),document.removeEventListener("keydown",O.keydown),u.addEventListener(L,function e(){u.removeEventListener(L,e),i.enableGrab&&o(u,A,O,!1),d=!1,f=!1,u.hasAttribute("data-original")&&u.setAttribute("src",b),z(u,E.close),c.removeChild(l),n&&n(u)}),a},grab:function(n,e,t,o){if(d&&!f){m=!1,i.onBeforeGrab&&i.onBeforeGrab(u);var r=window.innerWidth/2-n,a=window.innerHeight/2-e,s=v?x:i.scaleExtra,l=u.style.transform.replace(/translate\(.*?\)/i,"translate("+(g.x+r)+"px, "+(g.y+a)+"px)").replace(/scale\([0-9|\.]*\)/i,"scale("+(y+s)+")");z(u,{cursor:"move",transition:T+" "+(t?i.transitionDuration+"s "+i.transitionTimingFunction:"ease"),transform:l}),u.addEventListener(L,function n(){u.removeEventListener(L,n),o&&o(u)})}},release:function(){var n=arguments.length>0&&void 0!==arguments[0]?arguments[0]:i.onRelease;if(d&&!f)return f=!0,i.onBeforeRelease&&i.onBeforeRelease(u),z(u,E.open),u.addEventListener(L,function e(){u.removeEventListener(L,e),f=!1,m=!0,n&&n(u)}),a}};return I}); //# sourceMappingURL=zooming.min.js.map diff --git a/build/zooming.min.js.map b/build/zooming.min.js.map index f81138b8..c3ac9dca 100644 --- a/build/zooming.min.js.map +++ b/build/zooming.min.js.map @@ -1 +1 @@ -{"version":3,"file":null,"sources":["../src/helpers.js","../src/zooming.js"],"sourcesContent":["// webkit prefix\nconst prefix = 'WebkitAppearance' in document.documentElement.style ? '-webkit-' : ''\n\nconst options = {\n defaultZoomable: 'img[data-action=\"zoom\"]',\n enableGrab: true,\n preloadImage: true,\n transitionDuration: 0.4,\n transitionTimingFunction: 'cubic-bezier(.4,0,0,1)',\n bgColor: '#fff',\n bgOpacity: 1,\n scaleBase: 1.0,\n scaleExtra: 0.5,\n scrollThreshold: 40,\n onOpen: null,\n onClose: null,\n onRelease: null,\n onBeforeOpen: null,\n onBeforeClose: null,\n onBeforeGrab: null,\n onBeforeRelease: null\n}\n\nconst sniffTransition = (el) => {\n let ret = {}\n const trans = ['webkitTransition', 'transition', 'mozTransition']\n const tform = ['webkitTransform', 'transform', 'mozTransform']\n const end = {\n 'transition' : 'transitionend',\n 'mozTransition' : 'transitionend',\n 'webkitTransition' : 'webkitTransitionEnd'\n }\n\n trans.some(prop => {\n if (el.style[prop] !== undefined) {\n ret.transitionProp = prop\n ret.transEndEvent = end[prop]\n return true\n }\n })\n\n tform.some(prop => {\n if (el.style[prop] !== undefined) {\n ret.transformProp = prop\n ret.transformCssProp = prop.replace(/(.*)Transform/, '-$1-transform')\n return true\n }\n })\n\n return ret\n}\n\nconst checkTrans = (transitionProp, transformProp) => {\n return function setStyle(el, styles, remember) {\n let value\n if (styles.transition) {\n value = styles.transition\n delete styles.transition\n styles[transitionProp] = value\n }\n if (styles.transform) {\n value = styles.transform\n delete styles.transform\n styles[transformProp] = value\n }\n\n let s = el.style\n let original = {}\n\n for (let key in styles) {\n if (remember) original[key] = s[key] || ''\n s[key] = styles[key]\n }\n\n return original\n }\n}\n\nconst toggleListeners = (el, types, handler, add = true) => {\n types.forEach(t => {\n if (add) {\n el.addEventListener(t, handler[t])\n } else {\n el.removeEventListener(t, handler[t])\n }\n })\n}\n\nconst preloadImage = (url) => (new Image()).src = url\n\nexport {\n prefix,\n options,\n sniffTransition,\n checkTrans,\n toggleListeners,\n preloadImage\n}\n","import { prefix, options, sniffTransition, checkTrans, toggleListeners, preloadImage } from './helpers'\n\n// elements\nconst body = document.body\nconst overlay = document.createElement('div')\nlet target, parent\n\n// state\nlet shown = false // image is open\nlet lock = false // image is in transform\nlet released = true // mouse/finger is not pressing down\nlet multitouch = false\nlet lastScrollPosition = null\nlet translate, scale, srcThumbnail, pressTimer, dynamicScaleExtra\n\n// style\nconst style = {\n close: null,\n open: null\n}\n\nconst trans = sniffTransition(overlay)\nconst transformCssProp = trans.transformCssProp\nconst transEndEvent = trans.transEndEvent\nconst setStyleHelper = checkTrans(trans.transitionProp, trans.transformProp)\n\nconst PRESS_DELAY = 200\nconst TOUCH_SCALE_FACTOR = 2\nconst GRAB_EVENT_TYPES = [\n 'mousedown', 'mousemove', 'mouseup',\n 'touchstart', 'touchmove', 'touchend'\n]\n\n// helpers ---------------------------------------------------------------------\n\nconst setStyle = (el, styles, remember) => {\n return setStyleHelper(el, styles, remember)\n}\n\nconst calculateTransform = () => {\n const imgRect = target.getBoundingClientRect()\n const [imgHalfWidth, imgHalfHeight] = [imgRect.width / 2, imgRect.height / 2]\n\n const imgCenter = {\n x: imgRect.left + imgHalfWidth,\n y: imgRect.top + imgHalfHeight\n }\n\n const windowCenter = {\n x: window.innerWidth / 2,\n y: window.innerHeight / 2\n }\n\n // The distance between image edge and window edge\n const distFromImageEdgeToWindowEdge = {\n x: windowCenter.x - imgHalfWidth,\n y: windowCenter.y - imgHalfHeight\n }\n\n const scaleHorizontally = distFromImageEdgeToWindowEdge.x / imgHalfWidth\n const scaleVertically = distFromImageEdgeToWindowEdge.y / imgHalfHeight\n\n // The vector to translate image to the window center\n translate = {\n x: windowCenter.x - imgCenter.x,\n y: windowCenter.y - imgCenter.y\n }\n\n // The additional scale is based on the smaller value of\n // scaling horizontally and scaling vertically\n scale = options.scaleBase + Math.min(scaleHorizontally, scaleVertically)\n\n return `translate(${translate.x}px, ${translate.y}px) scale(${scale})`\n}\n\nconst processTouches = (touches, cb) => {\n const total = touches.length\n const firstTouch = touches[0]\n\n let i = touches.length\n let [xs, ys] = [0, 0]\n\n // keep track of the min and max of touch positions\n let min = { x: firstTouch.clientX, y: firstTouch.clientY }\n let max = { x: firstTouch.clientX, y: firstTouch.clientY }\n\n multitouch = total > 1\n\n while (i--) {\n const t = touches[i]\n const [x, y] = [t.clientX, t.clientY]\n xs += x\n ys += y\n\n if (multitouch) {\n if (x < min.x) min.x = x\n else if (x > max.x) max.x = x\n\n if (y < min.y) min.y = y\n else if (y > max.y) max.y = y\n }\n }\n\n if (multitouch) {\n // change scaleExtra dynamically\n const [distX, distY] = [max.x - min.x, max.y - min.y]\n if (distX > distY) dynamicScaleExtra = (distX / window.innerWidth) * TOUCH_SCALE_FACTOR\n else dynamicScaleExtra = (distY / window.innerHeight) * TOUCH_SCALE_FACTOR\n }\n\n cb(xs / total, ys / total)\n}\n\nconst eventHandler = {\n\n scroll: function () {\n const scrollTop = window.pageYOffset ||\n (document.documentElement || body.parentNode || body).scrollTop\n\n if (lastScrollPosition === null) lastScrollPosition = scrollTop\n\n const deltaY = lastScrollPosition - scrollTop\n\n if (Math.abs(deltaY) >= options.scrollThreshold) {\n lastScrollPosition = null\n api.close()\n }\n },\n\n keydown: function (e) {\n const code = e.key || e.code\n if (code === 'Escape' || e.keyCode === 27) api.close()\n },\n\n mousedown: function (e) {\n e.preventDefault()\n\n pressTimer = setTimeout(function () {\n api.grab(e.clientX, e.clientY, true)\n }, PRESS_DELAY)\n },\n\n mousemove: function (e) {\n if (released) return\n api.grab(e.clientX, e.clientY)\n },\n\n mouseup: function () {\n clearTimeout(pressTimer)\n },\n\n touchstart: function (e) {\n e.preventDefault()\n\n pressTimer = setTimeout(() => {\n processTouches(e.touches, (x, y) => api.grab(x, y, true))\n }, PRESS_DELAY)\n },\n\n touchmove: function (e) {\n if (released) return\n processTouches(e.touches, (x, y) => api.grab(x, y))\n },\n\n touchend: function (e) {\n if (e.targetTouches.length > 0) return\n clearTimeout(pressTimer)\n\n if (released) {\n api.close()\n } else {\n api.release()\n }\n }\n}\n\n// init ------------------------------------------------------------------------\n\nsetStyle(overlay, {\n zIndex: 998,\n background: options.bgColor,\n position: 'fixed',\n top: 0,\n left: 0,\n right: 0,\n bottom: 0,\n opacity: 0,\n transition: `opacity\n ${options.transitionDuration}s\n ${options.transitionTimingFunction}`\n})\n\noverlay.addEventListener('click', () => api.close())\ndocument.addEventListener('DOMContentLoaded', () => api.listen(options.defaultZoomable))\n\n// API -------------------------------------------------------------------------\n\nconst api = {\n\n listen: (el) => {\n if (typeof el === 'string') {\n let els = document.querySelectorAll(el), i = els.length\n\n while (i--) {\n api.listen(els[i])\n }\n\n return this\n }\n\n if (el.tagName !== 'IMG') return\n\n el.style.cursor = `${prefix}zoom-in`\n\n el.addEventListener('click', (e) => {\n e.preventDefault()\n\n if (shown) {\n if (released) {\n api.close()\n } else {\n api.release()\n }\n } else {\n api.open(el)\n }\n })\n\n if (options.preloadImage && el.hasAttribute('data-original')) {\n preloadImage(el.getAttribute('data-original'))\n }\n\n return this\n },\n\n config: (opts) => {\n if (!opts) return options\n\n for (let key in opts) {\n options[key] = opts[key]\n }\n\n setStyle(overlay, {\n backgroundColor: options.bgColor,\n transition: `opacity\n ${options.transitionDuration}s\n ${options.transitionTimingFunction}`\n })\n\n return this\n },\n\n open: (el, cb = options.onOpen) => {\n if (shown || lock) return\n\n target = typeof el === 'string'\n ? document.querySelector(el)\n : el\n\n if (target.tagName !== 'IMG') return\n\n // onBeforeOpen event\n if (options.onBeforeOpen) options.onBeforeOpen(target)\n\n shown = true\n lock = true\n parent = target.parentNode\n\n // force layout update\n target.offsetWidth\n\n style.open = {\n position: 'relative',\n zIndex: 999,\n cursor: `${prefix}${options.enableGrab ? 'grab' : 'zoom-out'}`,\n transition: `${transformCssProp}\n ${options.transitionDuration}s\n ${options.transitionTimingFunction}`,\n transform: calculateTransform()\n }\n\n // trigger transition\n style.close = setStyle(target, style.open, true)\n\n parent.appendChild(overlay)\n setTimeout(() => overlay.style.opacity = options.bgOpacity, 30)\n\n document.addEventListener('scroll', eventHandler.scroll)\n document.addEventListener('keydown', eventHandler.keydown)\n\n target.addEventListener(transEndEvent, function onEnd () {\n target.removeEventListener(transEndEvent, onEnd)\n\n if (options.enableGrab) toggleListeners(target, GRAB_EVENT_TYPES, eventHandler, true)\n\n lock = false\n\n // upgrade source if possible\n if (target.hasAttribute('data-original')) {\n srcThumbnail = target.getAttribute('src')\n target.setAttribute('src', target.getAttribute('data-original'))\n }\n\n if (cb) cb(target)\n })\n\n return this\n },\n\n close: (cb = options.onClose) => {\n if (!shown || lock) return\n lock = true\n\n // onBeforeClose event\n if (options.onBeforeClose) options.onBeforeClose(target)\n\n // force layout update\n target.offsetWidth\n\n overlay.style.opacity = 0\n setStyle(target, { transform: 'none' })\n\n document.removeEventListener('scroll', eventHandler.scroll)\n document.removeEventListener('keydown', eventHandler.keydown)\n\n target.addEventListener(transEndEvent, function onEnd () {\n target.removeEventListener(transEndEvent, onEnd)\n\n if (options.enableGrab) toggleListeners(target, GRAB_EVENT_TYPES, eventHandler, false)\n\n shown = false\n lock = false\n\n // downgrade source if possible\n if (target.hasAttribute('data-original')) {\n target.setAttribute('src', srcThumbnail)\n }\n\n setStyle(target, style.close)\n parent.removeChild(overlay)\n\n if (cb) cb(target)\n })\n\n return this\n },\n\n grab: (x, y, start, cb) => {\n if (!shown || lock) return\n released = false\n\n // onBeforeGrab event\n if (options.onBeforeGrab) options.onBeforeGrab(target)\n\n const [dx, dy] = [window.innerWidth / 2 - x, window.innerHeight / 2 - y]\n const scaleExtra = multitouch ? dynamicScaleExtra : options.scaleExtra\n const transform = target.style.transform\n .replace(/translate\\(.*?\\)/i, `translate(${translate.x + dx}px, ${translate.y + dy}px)`)\n .replace(/scale\\([0-9|\\.]*\\)/i, `scale(${scale + scaleExtra})`)\n\n setStyle(target, {\n cursor: 'move',\n transition: `${transformCssProp} ${start\n ? options.transitionDuration + 's ' + options.transitionTimingFunction\n : 'ease'}`,\n transform: transform\n })\n\n target.addEventListener(transEndEvent, function onEnd () {\n target.removeEventListener(transEndEvent, onEnd)\n if (cb) cb(target)\n })\n },\n\n release: (cb = options.onRelease) => {\n if (!shown || lock) return\n lock = true\n\n // onBeforeRelease event\n if (options.onBeforeRelease) options.onBeforeRelease(target)\n\n setStyle(target, style.open)\n\n target.addEventListener(transEndEvent, function onEnd () {\n target.removeEventListener(transEndEvent, onEnd)\n\n lock = false\n released = true\n\n if (cb) cb(target)\n })\n\n return this\n }\n}\n\nexport default api\n"],"names":["prefix","document","documentElement","style","options","sniffTransition","el","ret","trans","tform","end","some","undefined","prop","transitionProp","transEndEvent","transformProp","transformCssProp","replace","checkTrans","styles","remember","value","transition","transform","s","original","key","toggleListeners","types","handler","add","forEach","addEventListener","t","removeEventListener","preloadImage","url","Image","src","body","overlay","createElement","target","parent","shown","lock","released","multitouch","lastScrollPosition","translate","scale","srcThumbnail","pressTimer","dynamicScaleExtra","setStyleHelper","PRESS_DELAY","TOUCH_SCALE_FACTOR","GRAB_EVENT_TYPES","setStyle","calculateTransform","imgRect","getBoundingClientRect","imgHalfWidth","width","imgHalfHeight","height","imgCenter","left","top","windowCenter","window","innerWidth","innerHeight","distFromImageEdgeToWindowEdge","x","y","scaleHorizontally","scaleVertically","scaleBase","Math","min","processTouches","touches","cb","total","length","firstTouch","i","xs","ys","clientX","clientY","max","distX","distY","eventHandler","scrollTop","pageYOffset","parentNode","deltaY","abs","scrollThreshold","close","e","code","keyCode","api","preventDefault","setTimeout","grab","targetTouches","release","bgColor","transitionDuration","transitionTimingFunction","listen","defaultZoomable","els","querySelectorAll","tagName","cursor","open","hasAttribute","getAttribute","opts","onOpen","querySelector","onBeforeOpen","offsetWidth","enableGrab","appendChild","opacity","bgOpacity","scroll","keydown","onEnd","setAttribute","onClose","onBeforeClose","removeChild","start","onBeforeGrab","dx","dy","scaleExtra","onRelease","onBeforeRelease"],"mappings":"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"} \ No newline at end of file +{"version":3,"file":null,"sources":["../src/helpers.js","../src/options.js","../src/zooming.js"],"sourcesContent":["// webkit prefix\nconst prefix = 'WebkitAppearance' in document.documentElement.style ? '-webkit-' : ''\n\nconst sniffTransition = (el) => {\n let ret = {}\n const trans = ['webkitTransition', 'transition', 'mozTransition']\n const tform = ['webkitTransform', 'transform', 'mozTransform']\n const end = {\n 'transition' : 'transitionend',\n 'mozTransition' : 'transitionend',\n 'webkitTransition' : 'webkitTransitionEnd'\n }\n\n trans.some(prop => {\n if (el.style[prop] !== undefined) {\n ret.transitionProp = prop\n ret.transEndEvent = end[prop]\n return true\n }\n })\n\n tform.some(prop => {\n if (el.style[prop] !== undefined) {\n ret.transformProp = prop\n ret.transformCssProp = prop.replace(/(.*)Transform/, '-$1-transform')\n return true\n }\n })\n\n return ret\n}\n\nconst checkTrans = (transitionProp, transformProp) => {\n return function setStyle(el, styles, remember) {\n let value\n if (styles.transition) {\n value = styles.transition\n delete styles.transition\n styles[transitionProp] = value\n }\n if (styles.transform) {\n value = styles.transform\n delete styles.transform\n styles[transformProp] = value\n }\n\n let s = el.style\n let original = {}\n\n for (let key in styles) {\n if (remember) original[key] = s[key] || ''\n s[key] = styles[key]\n }\n\n return original\n }\n}\n\nconst toggleListeners = (el, types, handler, add = true) => {\n types.forEach(t => {\n if (add) {\n el.addEventListener(t, handler[t])\n } else {\n el.removeEventListener(t, handler[t])\n }\n })\n}\n\nconst preloadImage = (url) => (new Image()).src = url\n\nexport {\n prefix,\n sniffTransition,\n checkTrans,\n toggleListeners,\n preloadImage\n}\n","export const options = {\n defaultZoomable: 'img[data-action=\"zoom\"]',\n enableGrab: true,\n preloadImage: true,\n transitionDuration: 0.4,\n transitionTimingFunction: 'cubic-bezier(0.4, 0, 0, 1)',\n bgColor: 'rgb(255, 255, 255)',\n bgOpacity: 1,\n scaleBase: 1.0,\n scaleExtra: 0.5,\n scrollThreshold: 40,\n onOpen: null,\n onClose: null,\n onRelease: null,\n onBeforeOpen: null,\n onBeforeClose: null,\n onBeforeGrab: null,\n onBeforeRelease: null\n}\n","import { prefix, sniffTransition, checkTrans, toggleListeners, preloadImage } from './helpers'\nimport { options } from './options'\n\n// elements\nconst body = document.body\nconst overlay = document.createElement('div')\nlet target, parent\n\n// state\nlet shown = false // image is open\nlet lock = false // image is in transform\nlet released = true // mouse/finger is not pressing down\nlet multitouch = false\nlet lastScrollPosition = null\nlet translate, scale, srcThumbnail, pressTimer, dynamicScaleExtra\n\n// style\nconst style = {\n close: null,\n open: null\n}\n\nconst trans = sniffTransition(overlay)\nconst transformCssProp = trans.transformCssProp\nconst transEndEvent = trans.transEndEvent\nconst setStyleHelper = checkTrans(trans.transitionProp, trans.transformProp)\n\nconst PRESS_DELAY = 200\nconst TOUCH_SCALE_FACTOR = 2\nconst GRAB_EVENT_TYPES = [\n 'mousedown', 'mousemove', 'mouseup',\n 'touchstart', 'touchmove', 'touchend'\n]\n\n// helpers ---------------------------------------------------------------------\n\nconst setStyle = (el, styles, remember) => {\n return setStyleHelper(el, styles, remember)\n}\n\nconst calculateTransform = () => {\n const imgRect = target.getBoundingClientRect()\n const [imgHalfWidth, imgHalfHeight] = [imgRect.width / 2, imgRect.height / 2]\n\n const imgCenter = {\n x: imgRect.left + imgHalfWidth,\n y: imgRect.top + imgHalfHeight\n }\n\n const windowCenter = {\n x: window.innerWidth / 2,\n y: window.innerHeight / 2\n }\n\n // The distance between image edge and window edge\n const distFromImageEdgeToWindowEdge = {\n x: windowCenter.x - imgHalfWidth,\n y: windowCenter.y - imgHalfHeight\n }\n\n const scaleHorizontally = distFromImageEdgeToWindowEdge.x / imgHalfWidth\n const scaleVertically = distFromImageEdgeToWindowEdge.y / imgHalfHeight\n\n // The vector to translate image to the window center\n translate = {\n x: windowCenter.x - imgCenter.x,\n y: windowCenter.y - imgCenter.y\n }\n\n // The additional scale is based on the smaller value of\n // scaling horizontally and scaling vertically\n scale = options.scaleBase + Math.min(scaleHorizontally, scaleVertically)\n\n return `translate(${translate.x}px, ${translate.y}px) scale(${scale})`\n}\n\nconst processTouches = (touches, cb) => {\n const total = touches.length\n const firstTouch = touches[0]\n\n let i = touches.length\n let [xs, ys] = [0, 0]\n\n // keep track of the min and max of touch positions\n let min = { x: firstTouch.clientX, y: firstTouch.clientY }\n let max = { x: firstTouch.clientX, y: firstTouch.clientY }\n\n multitouch = total > 1\n\n while (i--) {\n const t = touches[i]\n const [x, y] = [t.clientX, t.clientY]\n xs += x\n ys += y\n\n if (multitouch) {\n if (x < min.x) min.x = x\n else if (x > max.x) max.x = x\n\n if (y < min.y) min.y = y\n else if (y > max.y) max.y = y\n }\n }\n\n if (multitouch) {\n // change scaleExtra dynamically\n const [distX, distY] = [max.x - min.x, max.y - min.y]\n if (distX > distY) dynamicScaleExtra = (distX / window.innerWidth) * TOUCH_SCALE_FACTOR\n else dynamicScaleExtra = (distY / window.innerHeight) * TOUCH_SCALE_FACTOR\n }\n\n cb(xs / total, ys / total)\n}\n\nconst eventHandler = {\n\n scroll: function () {\n const scrollTop = window.pageYOffset ||\n (document.documentElement || body.parentNode || body).scrollTop\n\n if (lastScrollPosition === null) lastScrollPosition = scrollTop\n\n const deltaY = lastScrollPosition - scrollTop\n\n if (Math.abs(deltaY) >= options.scrollThreshold) {\n lastScrollPosition = null\n api.close()\n }\n },\n\n keydown: function (e) {\n const code = e.key || e.code\n if (code === 'Escape' || e.keyCode === 27) api.close()\n },\n\n mousedown: function (e) {\n e.preventDefault()\n\n pressTimer = setTimeout(function () {\n api.grab(e.clientX, e.clientY, true)\n }, PRESS_DELAY)\n },\n\n mousemove: function (e) {\n if (released) return\n api.grab(e.clientX, e.clientY)\n },\n\n mouseup: function () {\n clearTimeout(pressTimer)\n },\n\n touchstart: function (e) {\n e.preventDefault()\n\n pressTimer = setTimeout(() => {\n processTouches(e.touches, (x, y) => api.grab(x, y, true))\n }, PRESS_DELAY)\n },\n\n touchmove: function (e) {\n if (released) return\n processTouches(e.touches, (x, y) => api.grab(x, y))\n },\n\n touchend: function (e) {\n if (e.targetTouches.length > 0) return\n clearTimeout(pressTimer)\n\n if (released) {\n api.close()\n } else {\n api.release()\n }\n }\n}\n\n// init ------------------------------------------------------------------------\n\noverlay.setAttribute('id', 'zoom-overlay')\nsetStyle(overlay, {\n zIndex: 998,\n backgroundColor: options.bgColor,\n position: 'fixed',\n top: 0,\n left: 0,\n right: 0,\n bottom: 0,\n opacity: 0,\n transition: `opacity\n ${options.transitionDuration}s\n ${options.transitionTimingFunction}`\n})\n\noverlay.addEventListener('click', () => api.close())\ndocument.addEventListener('DOMContentLoaded', () => api.listen(options.defaultZoomable))\n\n// API -------------------------------------------------------------------------\n\nconst api = {\n\n listen: (el) => {\n if (typeof el === 'string') {\n let els = document.querySelectorAll(el), i = els.length\n\n while (i--) {\n api.listen(els[i])\n }\n\n return this\n }\n\n if (el.tagName !== 'IMG') return\n\n el.style.cursor = `${prefix}zoom-in`\n\n el.addEventListener('click', (e) => {\n e.preventDefault()\n\n if (shown) {\n if (released) {\n api.close()\n } else {\n api.release()\n }\n } else {\n api.open(el)\n }\n })\n\n if (options.preloadImage && el.hasAttribute('data-original')) {\n preloadImage(el.getAttribute('data-original'))\n }\n\n return this\n },\n\n config: (opts) => {\n if (!opts) return options\n\n for (let key in opts) {\n options[key] = opts[key]\n }\n\n setStyle(overlay, {\n backgroundColor: options.bgColor,\n transition: `opacity\n ${options.transitionDuration}s\n ${options.transitionTimingFunction}`\n })\n\n return this\n },\n\n open: (el, cb = options.onOpen) => {\n if (shown || lock) return\n\n target = typeof el === 'string'\n ? document.querySelector(el)\n : el\n\n if (target.tagName !== 'IMG') return\n\n // onBeforeOpen event\n if (options.onBeforeOpen) options.onBeforeOpen(target)\n\n shown = true\n lock = true\n parent = target.parentNode\n\n // force layout update\n target.offsetWidth\n\n style.open = {\n position: 'relative',\n zIndex: 999,\n cursor: `${prefix}${options.enableGrab ? 'grab' : 'zoom-out'}`,\n transition: `${transformCssProp}\n ${options.transitionDuration}s\n ${options.transitionTimingFunction}`,\n transform: calculateTransform()\n }\n\n // trigger transition\n style.close = setStyle(target, style.open, true)\n\n parent.appendChild(overlay)\n setTimeout(() => overlay.style.opacity = options.bgOpacity, 30)\n\n document.addEventListener('scroll', eventHandler.scroll)\n document.addEventListener('keydown', eventHandler.keydown)\n\n target.addEventListener(transEndEvent, function onEnd () {\n target.removeEventListener(transEndEvent, onEnd)\n\n if (options.enableGrab) toggleListeners(target, GRAB_EVENT_TYPES, eventHandler, true)\n\n lock = false\n\n // upgrade source if possible\n if (target.hasAttribute('data-original')) {\n srcThumbnail = target.getAttribute('src')\n target.setAttribute('src', target.getAttribute('data-original'))\n }\n\n if (cb) cb(target)\n })\n\n return this\n },\n\n close: (cb = options.onClose) => {\n if (!shown || lock) return\n lock = true\n\n // onBeforeClose event\n if (options.onBeforeClose) options.onBeforeClose(target)\n\n // force layout update\n target.offsetWidth\n\n overlay.style.opacity = 0\n setStyle(target, { transform: 'none' })\n\n document.removeEventListener('scroll', eventHandler.scroll)\n document.removeEventListener('keydown', eventHandler.keydown)\n\n target.addEventListener(transEndEvent, function onEnd () {\n target.removeEventListener(transEndEvent, onEnd)\n\n if (options.enableGrab) toggleListeners(target, GRAB_EVENT_TYPES, eventHandler, false)\n\n shown = false\n lock = false\n\n // downgrade source if possible\n if (target.hasAttribute('data-original')) {\n target.setAttribute('src', srcThumbnail)\n }\n\n setStyle(target, style.close)\n parent.removeChild(overlay)\n\n if (cb) cb(target)\n })\n\n return this\n },\n\n grab: (x, y, start, cb) => {\n if (!shown || lock) return\n released = false\n\n // onBeforeGrab event\n if (options.onBeforeGrab) options.onBeforeGrab(target)\n\n const [dx, dy] = [window.innerWidth / 2 - x, window.innerHeight / 2 - y]\n const scaleExtra = multitouch ? dynamicScaleExtra : options.scaleExtra\n const transform = target.style.transform\n .replace(/translate\\(.*?\\)/i, `translate(${translate.x + dx}px, ${translate.y + dy}px)`)\n .replace(/scale\\([0-9|\\.]*\\)/i, `scale(${scale + scaleExtra})`)\n\n setStyle(target, {\n cursor: 'move',\n transition: `${transformCssProp} ${start\n ? options.transitionDuration + 's ' + options.transitionTimingFunction\n : 'ease'}`,\n transform: transform\n })\n\n target.addEventListener(transEndEvent, function onEnd () {\n target.removeEventListener(transEndEvent, onEnd)\n if (cb) cb(target)\n })\n },\n\n release: (cb = options.onRelease) => {\n if (!shown || lock) return\n lock = true\n\n // onBeforeRelease event\n if (options.onBeforeRelease) options.onBeforeRelease(target)\n\n setStyle(target, style.open)\n\n target.addEventListener(transEndEvent, function onEnd () {\n target.removeEventListener(transEndEvent, onEnd)\n\n lock = false\n released = true\n\n if (cb) cb(target)\n })\n\n return this\n }\n}\n\nexport default api\n"],"names":["prefix","document","documentElement","style","sniffTransition","el","ret","trans","tform","end","some","undefined","prop","transitionProp","transEndEvent","transformProp","transformCssProp","replace","checkTrans","styles","remember","value","transition","transform","s","original","key","toggleListeners","types","handler","add","forEach","addEventListener","t","removeEventListener","preloadImage","url","Image","src","options","body","overlay","createElement","target","parent","shown","lock","released","multitouch","lastScrollPosition","translate","scale","srcThumbnail","pressTimer","dynamicScaleExtra","setStyleHelper","PRESS_DELAY","TOUCH_SCALE_FACTOR","GRAB_EVENT_TYPES","setStyle","calculateTransform","imgRect","getBoundingClientRect","imgHalfWidth","width","imgHalfHeight","height","imgCenter","left","top","windowCenter","window","innerWidth","innerHeight","distFromImageEdgeToWindowEdge","x","y","scaleHorizontally","scaleVertically","scaleBase","Math","min","processTouches","touches","cb","total","length","firstTouch","i","xs","ys","clientX","clientY","max","distX","distY","eventHandler","scrollTop","pageYOffset","parentNode","deltaY","abs","scrollThreshold","close","e","code","keyCode","api","preventDefault","setTimeout","grab","targetTouches","release","setAttribute","bgColor","transitionDuration","transitionTimingFunction","listen","defaultZoomable","els","querySelectorAll","tagName","cursor","open","hasAttribute","getAttribute","opts","onOpen","querySelector","onBeforeOpen","offsetWidth","enableGrab","appendChild","opacity","bgOpacity","scroll","keydown","onEnd","onClose","onBeforeClose","removeChild","start","onBeforeGrab","dx","dy","scaleExtra","onRelease","onBeforeRelease"],"mappings":"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"} \ No newline at end of file diff --git a/package.json b/package.json index 22ac2eea..effe5d94 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "zooming", - "version": "0.6.3", + "version": "0.6.4", "description": "Image zoom that makes sense.", "main": "src/zooming.js", "repository": { diff --git a/src/helpers.js b/src/helpers.js index 43e5343c..13ca5ec1 100644 --- a/src/helpers.js +++ b/src/helpers.js @@ -1,26 +1,6 @@ // webkit prefix const prefix = 'WebkitAppearance' in document.documentElement.style ? '-webkit-' : '' -const options = { - defaultZoomable: 'img[data-action="zoom"]', - enableGrab: true, - preloadImage: true, - transitionDuration: 0.4, - transitionTimingFunction: 'cubic-bezier(.4,0,0,1)', - bgColor: '#fff', - bgOpacity: 1, - scaleBase: 1.0, - scaleExtra: 0.5, - scrollThreshold: 40, - onOpen: null, - onClose: null, - onRelease: null, - onBeforeOpen: null, - onBeforeClose: null, - onBeforeGrab: null, - onBeforeRelease: null -} - const sniffTransition = (el) => { let ret = {} const trans = ['webkitTransition', 'transition', 'mozTransition'] @@ -90,7 +70,6 @@ const preloadImage = (url) => (new Image()).src = url export { prefix, - options, sniffTransition, checkTrans, toggleListeners, diff --git a/src/options.js b/src/options.js new file mode 100644 index 00000000..ffe48db3 --- /dev/null +++ b/src/options.js @@ -0,0 +1,19 @@ +export const options = { + defaultZoomable: 'img[data-action="zoom"]', + enableGrab: true, + preloadImage: true, + transitionDuration: 0.4, + transitionTimingFunction: 'cubic-bezier(0.4, 0, 0, 1)', + bgColor: 'rgb(255, 255, 255)', + bgOpacity: 1, + scaleBase: 1.0, + scaleExtra: 0.5, + scrollThreshold: 40, + onOpen: null, + onClose: null, + onRelease: null, + onBeforeOpen: null, + onBeforeClose: null, + onBeforeGrab: null, + onBeforeRelease: null +} diff --git a/src/zooming.js b/src/zooming.js index 5a5976d2..f7aef84f 100644 --- a/src/zooming.js +++ b/src/zooming.js @@ -1,4 +1,5 @@ -import { prefix, options, sniffTransition, checkTrans, toggleListeners, preloadImage } from './helpers' +import { prefix, sniffTransition, checkTrans, toggleListeners, preloadImage } from './helpers' +import { options } from './options' // elements const body = document.body @@ -176,9 +177,10 @@ const eventHandler = { // init ------------------------------------------------------------------------ +overlay.setAttribute('id', 'zoom-overlay') setStyle(overlay, { zIndex: 998, - background: options.bgColor, + backgroundColor: options.bgColor, position: 'fixed', top: 0, left: 0, diff --git a/test/test.js b/test/test.js index 1b933612..29a7d166 100644 --- a/test/test.js +++ b/test/test.js @@ -4,10 +4,11 @@ var expect = chai.expect var should = chai.should() var prefix = 'WebkitAppearance' in document.documentElement.style ? '-webkit-' : '' -var options = Zooming.config() +var defaultOpts = Object.assign({}, Zooming.config()) describe('API', function() { - var els = document.querySelectorAll('img[data-action="zoom"]') + var els = document.querySelectorAll(defaultOpts.defaultZoomable) + var el = els[0] var i = els.length describe('listen()', function() { @@ -19,19 +20,66 @@ describe('API', function() { }) }) - describe('open()', function() { - var el = els[0] + describe('config()', function() { + var opts = { + defaultZoomable: 'img[data-action="open"]', + enableGrab: false, + preloadImage: false, + transitionDuration: 0.2, + transitionTimingFunction: 'ease', + bgColor: '#000', + bgOpacity: 0.8, + scaleBase: 0.8, + scaleExtra: 0.3, + scrollThreshold: 50, + onOpen: function() { return 'onOpen' }, + onClose: function() { return 'onClose' }, + onRelease: function() { return 'onRelease' }, + onBeforeOpen: function() { return 'onBeforeOpen' }, + onBeforeClose: function() { return 'onBeforeClose' }, + onBeforeGrab: function() { return 'onBeforeGrab' }, + onBeforeRelease: function() { return 'onBeforeRelease' } + } + + before(function() { + Zooming.config(opts) + }) + it('should update options correctly', function() { + expect(Zooming.config()).to.deep.equal(opts) + }) + + after(function() { + Zooming.config(defaultOpts) + }) + }) + + describe('open()', function() { it('should open up the image', function(done) { Zooming.open(el, function(target) { expect(target.style.position).to.equal('relative') expect(target.style.zIndex).to.equal('999') - expect(target.style.cursor).to.equal(prefix + (options.enableGrab ? 'grab': 'zoom-out')) + expect(target.style.cursor).to.equal(prefix + (defaultOpts.enableGrab ? 'grab': 'zoom-out')) expect(target.style.transition).to.not.be.empty expect(target.style.transform).to.not.be.empty done() }) }) + + it('should insert the overlay', function() { + var overlay = el.parentNode.lastChild + var style = overlay.style + expect(overlay.getAttribute('id')).to.equal('zoom-overlay') + expect(style.zIndex).to.equal('998') + expect(style.backgroundColor).to.equal(defaultOpts.bgColor) + expect(style.position).to.equal('fixed') + expect(style.top).to.equal('0px') + expect(style.left).to.equal('0px') + expect(style.right).to.equal('0px') + expect(style.bottom).to.equal('0px') + expect(style.opacity).to.equal(defaultOpts.bgOpacity.toString()) + expect(style.transition).to.not.be.empty + }) }) describe('grab()', function() { @@ -53,7 +101,7 @@ describe('API', function() { Zooming.release(function(target) { expect(target.style.position).to.equal('relative') expect(target.style.zIndex).to.equal('999') - expect(target.style.cursor).to.equal(prefix + (options.enableGrab ? 'grab': 'zoom-out')) + expect(target.style.cursor).to.equal(prefix + (defaultOpts.enableGrab ? 'grab': 'zoom-out')) expect(target.style.transition).to.not.be.empty expect(target.style.transform).to.not.be.empty done() @@ -72,5 +120,10 @@ describe('API', function() { done() }) }) + + it('should remove the overlay', function() { + var overlay = document.querySelector('#zoom-overlay') + expect(overlay).to.not.exist + }) }) })