diff --git a/index.js b/index.js new file mode 100644 index 0000000..14f7eb7 --- /dev/null +++ b/index.js @@ -0,0 +1 @@ +module.exports = require('./wheelzoom'); diff --git a/package.json b/package.json index 4e28154..73420d8 100644 --- a/package.json +++ b/package.json @@ -1,23 +1,19 @@ { - "name": "wheelzoom", - "description": "Zoom IMG elements on mousewheel or touchpad scroll.", - "version": "3.1.3", - "keywords": [ - "zoom", - "images", - "ui" - ], - "author": { - "name": "Jack Moore", - "url": "http://www.jacklmoore.com", - "email": "hello@jacklmoore.com" - }, - "main": "wheelzoom.js", - "license": "MIT", - "homepage": "http://www.jacklmoore.com/wheelzoom", - "demo": "http://www.jacklmoore.com/wheelzoom", - "repository": { - "type": "git", - "url": "http://github.com/jackmoore/wheelzoom.git" - } + "name": "wheelzoom", + "description": "Zoom IMG elements on mousewheel or touchpad scroll.", + "version": "3.1.4", + "keywords": ["zoom", "images", "ui"], + "author": { + "name": "Jack Moore", + "url": "http://www.jacklmoore.com", + "email": "hello@jacklmoore.com" + }, + "main": "index.js", + "license": "MIT", + "homepage": "http://www.jacklmoore.com/wheelzoom", + "demo": "http://www.jacklmoore.com/wheelzoom", + "repository": { + "type": "git", + "url": "http://github.com/jackmoore/wheelzoom.git" + } } diff --git a/readme.md b/readme.md index b4a4e15..51e6fa8 100644 --- a/readme.md +++ b/readme.md @@ -1,70 +1,93 @@ # Wheelzoom -A small script for zooming IMG elements with the mousewheel/trackpad. Wheelzoom works by replacing the img element's src with a transparent image, then using the original src as a background image, which can be sized and positioned. Wheelzoom is dependency free, doesn't add any extra elements to the DOM, or change the positioning of the IMG element. +A small script for zooming IMG elements with the mousewheel/trackpad. Wheelzoom works by replacing the img element's src with a transparent image, then using the original src as a background image, which can be sized and positioned. Wheelzoom is dependency free, doesn't add any extra elements to the DOM, or change the positioning of the IMG element. ## Usage: -````javascript + +```javascript wheelzoom(document.querySelectorAll('img')); // or -wheelzoom(document.querySelectorAll('img'), {zoom:0.05}); +wheelzoom(document.querySelectorAll('img'), {zoom: 0.05}); // zoom sets the zoom percent. -```` +``` ## License + [MIT License](http://opensource.org/licenses/MIT) ## Supported Browsers: + Chrome, Safari, Opera, FireFox 17+, IE9+. ## Changelog: +##### v.3.1.4 - 2018/05/15 + +* Support module.exports and AMD + ##### v.3.1.3 - 2018/01/31 + * Added 'initialZoom' option. Resolves #32 ##### v.3.1.2 - 2017/04/20 + * Added package.json & added to NPM. ##### v.3.1.0 - 2017/04/10 + * Added 'maxZoom' option for maximum zoom level. ##### v.3.0.4 - 2015/12/15 + * Automatically account for changes to the img src, to avoid requiring manually calling destroy and reapply. ##### v.3.0.3 - 2015/09/05 -* Fixed zoom positioning issue in Firefox. Fixes #17 -* Fixed error when calling destroy in Firefox. Fixes #16 -* Removed debugging statement. Fixes #15 + +* Fixed zoom positioning issue in Firefox. Fixes #17 +* Fixed error when calling destroy in Firefox. Fixes #16 +* Removed debugging statement. Fixes #15 ##### v.3.0.2 - 2015/09/05 + * Fixed lint warnings and bug introduced in 3.0.1 ##### v.3.0.1 - 2015/09/05 + * Fixed issue with src URLs that contain single quotes. Fixes #13. ##### v.3.0.0 - 2014/10/14 + * Removed jQuery dependency * Added 'wheelzoom.destroy' event for removing changes that wheelzoom has made to an element. ##### v.2.0.1 - 2014/9/9 -* Merged bugfix to wrap background-image path in quotes. Ref #8. + +* Merged bugfix to wrap background-image path in quotes. Ref #8. ##### v.2.0.0 - 2014/4/17 + * Simplified by dropping support for having border and padding on the img element. Borders and/or padding should be applied to the parent element, rather than the img element. ##### v.1.1.3 - 2014/4/13 + * Minor code improvement. ##### v.1.1.2 - 2013/1/31 + * Fixed bug with unzoom trigger. ##### v1.1.1 - 2013/1/29 -* Added trigger to unzoom image: -````javascript - $('#example').trigger('wheelzoom.reset') -```` + +* Added trigger to unzoom image: + +```javascript +$('#example').trigger('wheelzoom.reset'); +``` ##### v1.1.0 - 2012/11/28 + * Added dragging. ##### v1.0 - 2012/11/26 + * Initial release. diff --git a/wheelzoom.js b/wheelzoom.js index 596bf94..651b288 100644 --- a/wheelzoom.js +++ b/wheelzoom.js @@ -1,206 +1,224 @@ /*! - Wheelzoom 3.1.3 - license: MIT - http://www.jacklmoore.com/wheelzoom + Wheelzoom 3.1.4 + license: MIT + http://www.jacklmoore.com/wheelzoom */ -window.wheelzoom = (function(){ - var defaults = { - zoom: 0.10, - maxZoom: false, - initialZoom: 1, - }; - - var canvas = document.createElement('canvas'); - - var main = function(img, options){ - if (!img || !img.nodeName || img.nodeName !== 'IMG') { return; } - - var settings = {}; - var width; - var height; - var bgWidth; - var bgHeight; - var bgPosX; - var bgPosY; - var previousEvent; - var cachedDataUrl; - - function setSrcToBackground(img) { - img.style.backgroundImage = 'url("'+img.src+'")'; - img.style.backgroundRepeat = 'no-repeat'; - canvas.width = img.naturalWidth; - canvas.height = img.naturalHeight; - cachedDataUrl = canvas.toDataURL(); - img.src = cachedDataUrl; - } - - function updateBgStyle() { - if (bgPosX > 0) { - bgPosX = 0; - } else if (bgPosX < width - bgWidth) { - bgPosX = width - bgWidth; - } - - if (bgPosY > 0) { - bgPosY = 0; - } else if (bgPosY < height - bgHeight) { - bgPosY = height - bgHeight; - } - - img.style.backgroundSize = bgWidth+'px '+bgHeight+'px'; - img.style.backgroundPosition = bgPosX+'px '+bgPosY+'px'; - } - - function reset() { - bgWidth = width; - bgHeight = height; - bgPosX = bgPosY = 0; - updateBgStyle(); - } - - function onwheel(e) { - var deltaY = 0; - - e.preventDefault(); - - if (e.deltaY) { // FireFox 17+ (IE9+, Chrome 31+?) - deltaY = e.deltaY; - } else if (e.wheelDelta) { - deltaY = -e.wheelDelta; - } - - // As far as I know, there is no good cross-browser way to get the cursor position relative to the event target. - // We have to calculate the target element's position relative to the document, and subtrack that from the - // cursor's position relative to the document. - var rect = img.getBoundingClientRect(); - var offsetX = e.pageX - rect.left - window.pageXOffset; - var offsetY = e.pageY - rect.top - window.pageYOffset; - - // Record the offset between the bg edge and cursor: - var bgCursorX = offsetX - bgPosX; - var bgCursorY = offsetY - bgPosY; - - // Use the previous offset to get the percent offset between the bg edge and cursor: - var bgRatioX = bgCursorX/bgWidth; - var bgRatioY = bgCursorY/bgHeight; - - // Update the bg size: - if (deltaY < 0) { - bgWidth += bgWidth*settings.zoom; - bgHeight += bgHeight*settings.zoom; - } else { - bgWidth -= bgWidth*settings.zoom; - bgHeight -= bgHeight*settings.zoom; - } - - if (settings.maxZoom) { - bgWidth = Math.min(width*settings.maxZoom, bgWidth); - bgHeight = Math.min(height*settings.maxZoom, bgHeight); - } - - // Take the percent offset and apply it to the new size: - bgPosX = offsetX - (bgWidth * bgRatioX); - bgPosY = offsetY - (bgHeight * bgRatioY); - - // Prevent zooming out beyond the starting size - if (bgWidth <= width || bgHeight <= height) { - reset(); - } else { - updateBgStyle(); - } - } - - function drag(e) { - e.preventDefault(); - bgPosX += (e.pageX - previousEvent.pageX); - bgPosY += (e.pageY - previousEvent.pageY); - previousEvent = e; - updateBgStyle(); - } - - function removeDrag() { - document.removeEventListener('mouseup', removeDrag); - document.removeEventListener('mousemove', drag); - } - - // Make the background draggable - function draggable(e) { - e.preventDefault(); - previousEvent = e; - document.addEventListener('mousemove', drag); - document.addEventListener('mouseup', removeDrag); - } - - function load() { - var initial = Math.max(settings.initialZoom, 1); - - if (img.src === cachedDataUrl) return; - - var computedStyle = window.getComputedStyle(img, null); - - width = parseInt(computedStyle.width, 10); - height = parseInt(computedStyle.height, 10); - bgWidth = width * initial; - bgHeight = height * initial; - bgPosX = -(bgWidth - width)/2; - bgPosY = -(bgHeight - height)/2;; - - setSrcToBackground(img); - - img.style.backgroundSize = bgWidth+'px '+bgHeight+'px'; - img.style.backgroundPosition = bgPosX+'px '+bgPosY+'px'; - img.addEventListener('wheelzoom.reset', reset); - - img.addEventListener('wheel', onwheel); - img.addEventListener('mousedown', draggable); - } - - var destroy = function (originalProperties) { - img.removeEventListener('wheelzoom.destroy', destroy); - img.removeEventListener('wheelzoom.reset', reset); - img.removeEventListener('load', load); - img.removeEventListener('mouseup', removeDrag); - img.removeEventListener('mousemove', drag); - img.removeEventListener('mousedown', draggable); - img.removeEventListener('wheel', onwheel); - - img.style.backgroundImage = originalProperties.backgroundImage; - img.style.backgroundRepeat = originalProperties.backgroundRepeat; - img.src = originalProperties.src; - }.bind(null, { - backgroundImage: img.style.backgroundImage, - backgroundRepeat: img.style.backgroundRepeat, - src: img.src - }); - - img.addEventListener('wheelzoom.destroy', destroy); - - options = options || {}; - - Object.keys(defaults).forEach(function(key){ - settings[key] = options[key] !== undefined ? options[key] : defaults[key]; - }); - - if (img.complete) { - load(); - } - - img.addEventListener('load', load); - }; - - // Do nothing in IE8 - if (typeof window.getComputedStyle !== 'function') { - return function(elements) { - return elements; - }; - } else { - return function(elements, options) { - if (elements && elements.length) { - Array.prototype.forEach.call(elements, main, options); - } else if (elements && elements.nodeName) { - main(elements, options); - } - return elements; - }; - } -}()); \ No newline at end of file +(function() { + var wheelzoom = (function() { + var defaults = { + zoom: 0.1, + maxZoom: false, + initialZoom: 1, + }; + + var canvas = document.createElement('canvas'); + + var main = function(img, options) { + if (!img || !img.nodeName || img.nodeName !== 'IMG') { + return; + } + + var settings = {}; + var width; + var height; + var bgWidth; + var bgHeight; + var bgPosX; + var bgPosY; + var previousEvent; + var cachedDataUrl; + + function setSrcToBackground(img) { + img.style.backgroundImage = 'url("' + img.src + '")'; + img.style.backgroundRepeat = 'no-repeat'; + canvas.width = img.naturalWidth; + canvas.height = img.naturalHeight; + cachedDataUrl = canvas.toDataURL(); + img.src = cachedDataUrl; + } + + function updateBgStyle() { + if (bgPosX > 0) { + bgPosX = 0; + } else if (bgPosX < width - bgWidth) { + bgPosX = width - bgWidth; + } + + if (bgPosY > 0) { + bgPosY = 0; + } else if (bgPosY < height - bgHeight) { + bgPosY = height - bgHeight; + } + + img.style.backgroundSize = bgWidth + 'px ' + bgHeight + 'px'; + img.style.backgroundPosition = bgPosX + 'px ' + bgPosY + 'px'; + } + + function reset() { + bgWidth = width; + bgHeight = height; + bgPosX = bgPosY = 0; + updateBgStyle(); + } + + function onwheel(e) { + var deltaY = 0; + + e.preventDefault(); + + if (e.deltaY) { + // FireFox 17+ (IE9+, Chrome 31+?) + deltaY = e.deltaY; + } else if (e.wheelDelta) { + deltaY = -e.wheelDelta; + } + + // As far as I know, there is no good cross-browser way to get the cursor position relative to the event target. + // We have to calculate the target element's position relative to the document, and subtrack that from the + // cursor's position relative to the document. + var rect = img.getBoundingClientRect(); + var offsetX = e.pageX - rect.left - window.pageXOffset; + var offsetY = e.pageY - rect.top - window.pageYOffset; + + // Record the offset between the bg edge and cursor: + var bgCursorX = offsetX - bgPosX; + var bgCursorY = offsetY - bgPosY; + + // Use the previous offset to get the percent offset between the bg edge and cursor: + var bgRatioX = bgCursorX / bgWidth; + var bgRatioY = bgCursorY / bgHeight; + + // Update the bg size: + if (deltaY < 0) { + bgWidth += bgWidth * settings.zoom; + bgHeight += bgHeight * settings.zoom; + } else { + bgWidth -= bgWidth * settings.zoom; + bgHeight -= bgHeight * settings.zoom; + } + + if (settings.maxZoom) { + bgWidth = Math.min(width * settings.maxZoom, bgWidth); + bgHeight = Math.min(height * settings.maxZoom, bgHeight); + } + + // Take the percent offset and apply it to the new size: + bgPosX = offsetX - bgWidth * bgRatioX; + bgPosY = offsetY - bgHeight * bgRatioY; + + // Prevent zooming out beyond the starting size + if (bgWidth <= width || bgHeight <= height) { + reset(); + } else { + updateBgStyle(); + } + } + + function drag(e) { + e.preventDefault(); + bgPosX += e.pageX - previousEvent.pageX; + bgPosY += e.pageY - previousEvent.pageY; + previousEvent = e; + updateBgStyle(); + } + + function removeDrag() { + document.removeEventListener('mouseup', removeDrag); + document.removeEventListener('mousemove', drag); + } + + // Make the background draggable + function draggable(e) { + e.preventDefault(); + previousEvent = e; + document.addEventListener('mousemove', drag); + document.addEventListener('mouseup', removeDrag); + } + + function load() { + var initial = Math.max(settings.initialZoom, 1); + + if (img.src === cachedDataUrl) return; + + var computedStyle = window.getComputedStyle(img, null); + + width = parseInt(computedStyle.width, 10); + height = parseInt(computedStyle.height, 10); + bgWidth = width * initial; + bgHeight = height * initial; + bgPosX = -(bgWidth - width) / 2; + bgPosY = -(bgHeight - height) / 2; + + setSrcToBackground(img); + + img.style.backgroundSize = bgWidth + 'px ' + bgHeight + 'px'; + img.style.backgroundPosition = bgPosX + 'px ' + bgPosY + 'px'; + img.addEventListener('wheelzoom.reset', reset); + + img.addEventListener('wheel', onwheel); + img.addEventListener('mousedown', draggable); + } + + var destroy = function(originalProperties) { + img.removeEventListener('wheelzoom.destroy', destroy); + img.removeEventListener('wheelzoom.reset', reset); + img.removeEventListener('load', load); + img.removeEventListener('mouseup', removeDrag); + img.removeEventListener('mousemove', drag); + img.removeEventListener('mousedown', draggable); + img.removeEventListener('wheel', onwheel); + + img.style.backgroundImage = originalProperties.backgroundImage; + img.style.backgroundRepeat = originalProperties.backgroundRepeat; + img.src = originalProperties.src; + }.bind(null, { + backgroundImage: img.style.backgroundImage, + backgroundRepeat: img.style.backgroundRepeat, + src: img.src, + }); + + img.addEventListener('wheelzoom.destroy', destroy); + + options = options || {}; + + Object.keys(defaults).forEach(function(key) { + settings[key] = + options[key] !== undefined ? options[key] : defaults[key]; + }); + + if (img.complete) { + load(); + } + + img.addEventListener('load', load); + }; + + // Do nothing in IE8 + if (typeof window.getComputedStyle !== 'function') { + return function(elements) { + return elements; + }; + } else { + return function(elements, options) { + if (elements && elements.length) { + Array.prototype.forEach.call(elements, main, options); + } else if (elements && elements.nodeName) { + main(elements, options); + } + return elements; + }; + } + })(); + + if (typeof module !== 'undefined' && typeof module.exports !== 'undefined') { + module.exports = wheelzoom; + } else { + if (typeof define === 'function' && define.amd) { + define([], function() { + return wheelzoom; + }); + } else { + window.wheelzoom = wheelzoom; + } + } +})();