1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453 |
- /**
- * ___ ___ _____ ______ __ __ _____ ______ __ __
- * | \/ |/ _ \ / __ \| \ | |_ _| ___| \ / |
- * | | / \ | | \__| \| | | | | |__ \ \/ /
- * | |\/| | |_| | | ___ | | | | __| \ /
- * | | | | _ | \_/ | |\ |_| |_| | | |
- * |__| |__|__| |__|\____/|_|__| \__|_____|__| |__|
- *
- * jquery.magnify.js v0.1.0
- *
- * A jQuery plugin to view images just like in windows
- *
- * Copyright (c) 2017 nzbin
- *
- * Released under the MIT License
- *
- *
- */
- ;
- (function(factory) {
- if (typeof define === 'function' && define.amd) {
- // AMD. Register as anonymous module.
- define(['jquery'], factory);
- } else if (typeof exports === 'object') {
- // Node / CommonJS
- factory(require('jquery'));
- } else {
- // Browser globals.
- factory(jQuery);
- }
- })(function($) {
- 'use strict';
- /**
- * Private vars
- */
- var $W = $(window),
- $D = $(document),
- // plugin default options
- defaults = {
- draggable: true,
- resizable: true,
- movable: true,
- keyboard: true,
- title: true,
- modalWidth: 320,
- modalHeight: 320,
- fixedContent: false,
- fixedModalSize: false,
- initMaximized: false,
- gapThreshold: 0.02,
- ratioThreshold: 0.1,
- minRatio: 0.1,
- maxRatio: 16,
- toolbar: ['zoomIn', 'zoomOut', 'prev', 'fullscreen', 'next', 'actualSize', 'rotateRight'],
- icons: {
- maximize: 'fa fa-window-maximize',
- close: 'fa fa-close',
- zoomIn: 'fa fa-search-plus',
- zoomOut: 'fa fa-search-minus',
- prev: 'fa fa-arrow-left',
- next: 'fa fa-arrow-right',
- fullscreen: 'fa fa-photo',
- actualSize: 'fa fa-arrows-alt',
- rotateLeft: 'fa fa-rotate-left',
- rotateRight: 'fa fa-rotate-right'
- },
- lang: 'en',
- i18n: {},
- // beforeOpen:$.noop,
- // afterOpen:$.noop,
- // beforeClose:$.noop,
- // afterClose:$.noop
- },
- // jquery element of calling plugin
- jqEl = null,
- // image moving flag
- isMoving = false,
- // modal resizing flag
- isResizing = false,
- // modal open flag
- isOpened = false,
- // modal maximize flag
- isMaximized = false,
- // image rotate 90*(2n+1) flag
- isRotated = false,
- // image rotate angle
- rotateAngle = 0;
- /**
- * Magnify Class
- */
- var Magnify = function (el, options) {
- var self = this;
- this.options = $.extend(true, {}, defaults, options);
- if (options && $.isArray(options.toolbar)) {
- this.options.toolbar = options.toolbar;
- }
- this.init(el, self.options);
- this.isOpened = false;
- this.isMaximized = false;
- this.isRotated = false;
- this.rotateAngle = 0;
- // Store image data in every instance
- // this.imageData = {};
- }
- /**
- * Mangify prototype
- */
- Magnify.prototype = {
- init: function (el, options) {
- this.open();
- // Get image src
- var imgSrc = this.getImgSrc(el);
- // Get image group
- this.groupName = null;
- var currentGroupName = $(el).attr('data-group'),
- groupList = $D.find('[data-group="' + currentGroupName + '"]');
- if (currentGroupName !== undefined) {
- this.groupName = currentGroupName;
- this.getImgGroup(groupList, imgSrc);
- } else {
- this.getImgGroup(jqEl.not('[data-group]'), imgSrc);
- }
- this.loadImg(imgSrc);
- },
- creatBtns: function (btns) {
- var footerBtnsStr = '';
- $.each(this.options.toolbar, function (index, item) {
- footerBtnsStr += btns[item];
- });
- return footerBtnsStr;
- },
- creatDOM: function () {
- var btnsTpl = {
- maximize: '<button class="magnify-button magnify-button-maximize" title="maximize">\
- <i class="' + this.options.icons.maximize + '" aria-hidden="true"></i>\
- </button>',
- close: '<button class="magnify-button magnify-button-close" title="close">\
- <i class="' + this.options.icons.close + '" aria-hidden="true"></i>\
- </button>',
- zoomIn: '<button class="magnify-button magnify-button-zoom-in" title="zoom-in">\
- <i class="' + this.options.icons.zoomIn + '" aria-hidden="true"></i>\
- </button>',
- zoomOut: '<button class="magnify-button magnify-button-zoom-out" title="zoom-out">\
- <i class="' + this.options.icons.zoomOut + '" aria-hidden="true"></i>\
- </button>',
- prev: '<button class="magnify-button magnify-button-prev" title="prev">\
- <i class="' + this.options.icons.prev + '" aria-hidden="true"></i>\
- </button>',
- next: '<button class="magnify-button magnify-button-next" title="next">\
- <i class="' + this.options.icons.next + '" aria-hidden="true"></i>\
- </button>',
- fullscreen: '<button class="magnify-button magnify-button-fullscreen" title="fullscreen">\
- <i class="' + this.options.icons.fullscreen + '" aria-hidden="true"></i>\
- </button>',
- actualSize: '<button class="magnify-button magnify-button-actual-size" title="actual-size">\
- <i class="' + this.options.icons.actualSize + '" aria-hidden="true"></i>\
- </button>',
- rotateLeft: '<button class="magnify-button magnify-button-rotate-left" title="rotate-left">\
- <i class="' + this.options.icons.rotateLeft + '" aria-hidden="true"></i>\
- </button>',
- rotateRight: '<button class="magnify-button magnify-button-rotate-right" title="rotate-right">\
- <i class="' + this.options.icons.rotateRight + '" aria-hidden="true"></i>\
- </button>'
- }
- // magnify base HTML
- var magnifyHTML = '<div class="magnify-modal">\
- <div class="magnify-header">\
- <div class="magnify-title"></div>\
- <div class="magnify-toolbar">' + btnsTpl.maximize + btnsTpl.close + '</div>\
- </div>\
- <div class="magnify-stage">\
- <img src="" alt="" title="">\
- </div>\
- <div class="magnify-footer">\
- <div class="magnify-toolbar">' + this.creatBtns(btnsTpl) + '</div>\
- </div>\
- </div>';
- return magnifyHTML;
- },
- open: function () {
- // Fixed modal position bug
- if (!$('.magnify-modal').length) {
- $('html').css('overflow', 'hidden');
- }
- this.isOpened = isOpened = true;
- this.build();
- this.addEvent();
- this.resize();
- },
- build: function () {
- // Create magnify HTML string
- var magnifyHTML = this.creatDOM();
- // Make magnify HTML string to jQuery element
- var $magnify = $(magnifyHTML);
- // Get all magnify element
- this.$magnify = $magnify;
- this.$stage = $magnify.find('.magnify-stage');
- this.$title = $magnify.find('.magnify-title');
- this.$image = $magnify.find('.magnify-stage img');
- this.$close = $magnify.find('.magnify-button-close');
- this.$maximize = $magnify.find('.magnify-button-maximize');
- this.$zoomIn = $magnify.find('.magnify-button-zoom-in');
- this.$zoomOut = $magnify.find('.magnify-button-zoom-out');
- this.$actualSize = $magnify.find('.magnify-button-actual-size');
- this.$fullscreen = $magnify.find('.magnify-button-fullscreen');
- this.$rotateLeft = $magnify.find('.magnify-button-rotate-left');
- this.$rotateRight = $magnify.find('.magnify-button-rotate-right');
- this.$prev = $magnify.find('.magnify-button-prev');
- this.$next = $magnify.find('.magnify-button-next');
- $('body').append($magnify);
- this.setModalPos($magnify);
- // draggable & movable & resizable
- if (this.options.draggable) {
- this.draggable($magnify);
- }
- if (this.options.movable) {
- this.movable(this.$image, this.$stage);
- }
- if (this.options.resizable) {
- this.resizable($magnify, this.$stage, this.$image, this.options.modalWidth, this.options.modalHeight);
- }
- },
- close: function (el) {
- // off events
- // Remove instance
- this.$magnify.remove();
- this.isMaximized = false;
- this.isRotated = false;
- this.rotateAngle = rotateAngle = 0;
- this.isOpened = isOpened = false;
- // Fixed modal position bug
- if (!$('.magnify-modal').length) {
- $('html').css('overflow', 'auto');
- }
- },
- setModalPos: function (modal) {
- var winWidth = $W.width(),
- winHeight = $W.height(),
- scrollLeft = $D.scrollLeft(),
- scrollTop = $D.scrollTop();
- var modalWidth = modal.width(),
- modalHeight = modal.height();
- // Make the modal in windows center
- modal.css({
- left: (winWidth - modalWidth) / 2 + scrollLeft + 'px',
- top: (winHeight - modalHeight) / 2 + scrollTop + 'px'
- });
- },
- setModalSize: function (img) {
- var winWidth = $W.width(),
- winHeight = $W.height(),
- scrollLeft = $D.scrollLeft(),
- scrollTop = $D.scrollTop();
- // stage css value
- var stageCSS = {
- left: this.$stage.css('left'),
- right: this.$stage.css('right'),
- top: this.$stage.css('top'),
- bottom: this.$stage.css('bottom'),
- borderLeft: this.$stage.css('border-left-width'),
- borderRight: this.$stage.css('border-right-width'),
- borderTop: this.$stage.css('border-top-width'),
- borderBottom: this.$stage.css('border-bottom-width'),
- };
- // Modal size should calc with stage css value
- var modalWidth = img.width + getNumFromCSSValue(stageCSS.left) + getNumFromCSSValue(stageCSS.right) +
- getNumFromCSSValue(stageCSS.borderLeft) + getNumFromCSSValue(stageCSS.borderRight),
- modalHeight = img.height + getNumFromCSSValue(stageCSS.top) + getNumFromCSSValue(stageCSS.bottom) +
- getNumFromCSSValue(stageCSS.borderTop) + getNumFromCSSValue(stageCSS.borderBottom);
- var gapThreshold = (this.options.gapThreshold > 0 ? this.options.gapThreshold : 0) + 1,
- // modal scale to window
- scale = Math.min(winWidth / (modalWidth * gapThreshold), winHeight / (modalHeight * gapThreshold), 1);
- var minWidth = Math.max(modalWidth * scale, this.options.modalWidth),
- minHeight = Math.max(modalHeight * scale, this.options.modalHeight);
- minWidth = this.options.fixedModalSize ? this.options.modalWidth : Math.ceil(minWidth);
- minHeight = this.options.fixedModalSize ? this.options.modalHeight : Math.ceil(minHeight);
- this.$magnify.css({
- width: minWidth + 'px',
- height: minHeight + 'px',
- left: (winWidth - minWidth) / 2 + scrollLeft + 'px',
- top: (winHeight - minHeight) / 2 + scrollTop + 'px'
- });
- this.setImageSize(img);
- },
- setImageSize: function (img) {
- var stageData = {
- w: this.$stage.width(),
- h: this.$stage.height()
- }
- // image scale to stage
- var scale = 1;
- if (!this.isRotated) {
- scale = Math.min(stageData.w / img.width, stageData.h / img.height, 1);
- } else {
- scale = Math.min(stageData.w / img.height, stageData.h / img.width, 1);
- }
- this.$image.css({
- width: Math.ceil(img.width * scale) + 'px',
- height: Math.ceil(img.height * scale) + 'px',
- left: (stageData.w - img.width * scale) / 2 + 'px',
- top: (stageData.h - img.height * scale) / 2 + 'px'
- });
- // Store image initial data
- $.extend(this.imageData, {
- width: img.width * scale,
- height: img.height * scale,
- left: (stageData.w - img.width * scale) / 2,
- top: (stageData.h - img.height * scale) / 2
- });
- },
- loadImg: function (imgSrc) {
- var self = this;
- this.$image.attr('src', imgSrc);
- preloadImg(imgSrc, function (img) {
- // Store original data
- self.imageData = {
- originalWidth: img.width,
- originalHeight: img.height
- }
- if (self.isMaximized) {
- self.setImageSize(img);
- } else {
- self.setModalSize(img);
- }
- });
- if (this.options.title) {
- this.setImgTitle(imgSrc);
- }
- },
- getImgGroup: function (list, imgSrc) {
- var self = this;
- self.groupData = [];
- $(list).each(function (index, item) {
- var src = self.getImgSrc(this);
- self.groupData.push({
- src: src,
- caption: $(this).attr('data-caption')
- });
- // Get image index
- if (imgSrc === src) {
- self.groupIndex = index
- }
- });
- },
- setImgTitle: function (url) {
- var index = this.groupIndex,
- caption = this.groupData[index].caption,
- caption = caption ? caption : getImageNameFromUrl(url);
- this.$title.text(caption);
- },
- getImgSrc: function (el) {
- // Get data-src as image src at first
- var src = $(el).attr('data-src') ? $(el).attr('data-src') : $(el).attr('href');
- return src;
- },
- jump: function (index) {
- this.groupIndex = this.groupIndex + index;
- this.jumpTo(this.groupIndex);
- },
- jumpTo: function (index) {
- index = index % this.groupData.length;
- if (index >= 0) {
- index = index % this.groupData.length;
- } else if (index < 0) {
- index = (this.groupData.length + index) % this.groupData.length;
- }
- this.groupIndex = index;
- this.loadImg(this.groupData[index].src);
- },
- wheel: function (e) {
- e.preventDefault();
- var delta = 1;
- if (e.originalEvent.deltaY) {
- delta = e.originalEvent.deltaY > 0 ? 1 : -1;
- } else if (e.originalEvent.wheelDelta) {
- delta = -e.originalEvent.wheelDelta / 120;
- } else if (e.originalEvent.detail) {
- delta = e.originalEvent.detail > 0 ? 1 : -1;
- }
- // ratio threshold
- var ratio = -delta * this.options.ratioThreshold;
- // mouse point position
- var pointer = {
- x: e.originalEvent.clientX - this.$stage.offset().left,
- y: e.originalEvent.clientY - this.$stage.offset().top
- }
- this.zoom(ratio, pointer, e);
- },
- zoom: function (ratio, origin, e) {
- // zoom out & zoom in
- ratio = ratio < 0 ? (1 / (1 - ratio)) : (1 + ratio);
- if (ratio > 0.95 && ratio < 1.05) {
- ratio = 1;
- }
- ratio = this.$image.width() / this.imageData.originalWidth * ratio;
- // min image size
- ratio = Math.max(ratio, this.options.minRatio);
- // max image size
- ratio = Math.min(ratio, this.options.maxRatio);
- this.zoomTo(ratio, origin, e);
- },
- zoomTo: function (ratio, origin, e) {
- var $image = this.$image,
- $stage = this.$stage,
- imgData = {
- w: this.imageData.width,
- h: this.imageData.height,
- x: this.imageData.left,
- y: this.imageData.top
- };
- // image stage position
- // We will use it to calc the relative position of image
- var stageData = {
- w: $stage.width(),
- h: $stage.height(),
- x: $stage.offset().left,
- y: $stage.offset().top
- }
- var newWidth = this.imageData.originalWidth * ratio,
- newHeight = this.imageData.originalHeight * ratio,
- // Think about it for a while ~~~
- newLeft = origin.x - (origin.x - imgData.x) / imgData.w * newWidth,
- newTop = origin.y - (origin.y - imgData.y) / imgData.h * newHeight;
- var offsetX = stageData.w - newWidth,
- offsetY = stageData.h - newHeight,
- // Get the offsets when image rotate 90 deg
- offsetX2 = stageData.w - (newWidth + newHeight) / 2,
- offsetY2 = stageData.h - (newWidth + newHeight) / 2;
- // zoom out & zoom in condition
- // It's important and it takes me a lot of time to get it
- if (!this.isRotated) {
- if (newHeight <= stageData.h) {
- newTop = (stageData.h - newHeight) / 2;
- } else {
- newTop = newTop > 0 ? 0 : (newTop > offsetY ? newTop : offsetY);
- }
- if (newWidth <= stageData.w) {
- newLeft = (stageData.w - newWidth) / 2;
- } else {
- newLeft = newLeft > 0 ? 0 : (newLeft > offsetX ? newLeft : offsetX);
- }
- } else {
- // The conditions bellow drive me crazy alomst!
- if (newWidth <= stageData.h) {
- newTop = (stageData.h - newHeight) / 2;
- } else {
- newTop = newTop > (newWidth - newHeight) / 2 ? (newWidth - newHeight) / 2 : (newTop > offsetY2 ? newTop : offsetY2);
- }
- if (newHeight <= stageData.w) {
- newLeft = (stageData.w - newWidth) / 2;
- } else {
- newLeft = newLeft > (newHeight - newWidth) / 2 ? (newHeight - newWidth) / 2 : (newLeft > offsetX2 ? newLeft : offsetX2);
- }
- }
- $image.css({
- width: Math.ceil(newWidth) + 'px',
- height: Math.ceil(newHeight) + 'px',
- left: newLeft + 'px',
- top: newTop + 'px'
- });
- // Update image initial data
- $.extend(this.imageData, {
- width: newWidth,
- height: newHeight,
- left: newLeft,
- top: newTop
- });
- },
- rotate: function (angle) {
- this.rotateAngle = rotateAngle = rotateAngle + angle;
- if ((rotateAngle / 90) % 2 === 0) {
- this.isRotated = false;
- } else {
- this.isRotated = true;
- }
- this.rotateTo(rotateAngle);
- },
- rotateTo: function (angle) {
- var self = this;
- this.$image.css({
- transform: 'rotate(' + angle + 'deg)'
- });
- this.setImageSize({ width: this.imageData.originalWidth, height: this.imageData.originalHeight });
- },
- resize: function () {
- var self = this;
- var resizeHandler = throttle(function(){
- if (isOpened) {
- if (!self.isMaximized) {
- self.setModalSize({ width: self.imageData.originalWidth, height: self.imageData.originalHeight });
- }
- self.setImageSize({ width: self.imageData.originalWidth, height: self.imageData.originalHeight });
- }
- }, 500);
- $W.off('resize').on('resize', resizeHandler);
- },
- maximize: function () {
- var self = this;
- var scrollLeft = $D.scrollLeft(),
- scrollTop = $D.scrollTop();
- if (!this.isMaximized) {
- // Store modal data before maximize
- this.modalData = {
- width: this.$magnify.width(),
- height: this.$magnify.height(),
- left: this.$magnify.offset().left,
- top: this.$magnify.offset().top
- }
- this.$magnify.addClass('magnify-maximize');
- this.$magnify.css({
- width: '100%',
- height: '100%',
- left: scrollLeft,
- top: scrollTop
- });
- this.isMaximized = true;
- } else {
- this.$magnify.removeClass('magnify-maximize');
- this.$magnify.css({
- width: this.modalData.width,
- height: this.modalData.height,
- left: this.modalData.left,
- top: this.modalData.top
- });
- this.isMaximized = false;
- }
- this.setImageSize({ width: this.imageData.originalWidth, height: this.imageData.originalHeight });
- },
- fullscreen: function () {
- requestFullscreen(this.$magnify[0]);
- },
- keydown: function (e) {
- e.preventDefault();
- var self = this;
- if (!this.options.keyboard) {
- return false;
- }
- var keyCode = e.keyCode || e.which || e.charCode,
- ctrlKey = e.ctrlKey || e.metaKey,
- altKey = e.altKey || e.metaKey;
- switch (keyCode) {
- // ←
- case 37:
- self.jump(-1);
- break;
- // →
- case 39:
- self.jump(1);
- break;
- // +
- case 187:
- self.zoom(self.options.ratioThreshold * 3, { x: self.$stage.width() / 2, y: self.$stage.height() / 2 }, e);
- break;
- // -
- case 189:
- self.zoom(-self.options.ratioThreshold * 3, { x: self.$stage.width() / 2, y: self.$stage.height() / 2 }, e);
- break;
- // + Firefox
- case 61:
- self.zoom(self.options.ratioThreshold * 3, { x: self.$stage.width() / 2, y: self.$stage.height() / 2 }, e);
- break;
- // - Firefox
- case 173:
- self.zoom(-self.options.ratioThreshold * 3, { x: self.$stage.width() / 2, y: self.$stage.height() / 2 }, e);
- break;
- // ctrl + alt + 0
- case 48:
- if (ctrlKey && altKey) {
- self.zoomTo(1, { x: self.$stage.width() / 2, y: self.$stage.height() / 2 }, e);
- }
- break;
- // ctrl + ,
- case 188:
- if (ctrlKey) {
- self.rotate(-90);
- }
- break;
- // ctrl + .
- case 190:
- if (ctrlKey) {
- self.rotate(90);
- }
- break;
- default:
- }
- },
- addEvent: function () {
- var self = this;
- this.$close.off('click').on('click', function (e) {
- self.close();
- });
- this.$stage.off('wheel mousewheel DOMMouseScroll').on('wheel mousewheel DOMMouseScroll', function (e) {
- self.wheel(e);
- });
- this.$zoomIn.off('click').on('click', function (e) {
- self.zoom(self.options.ratioThreshold * 3, { x: self.$stage.width() / 2, y: self.$stage.height() / 2 }, e);
- });
- this.$zoomOut.off('click').on('click', function (e) {
- self.zoom(-self.options.ratioThreshold * 3, { x: self.$stage.width() / 2, y: self.$stage.height() / 2 }, e);
- });
- this.$actualSize.off('click').on('click', function (e) {
- self.zoomTo(1, { x: self.$stage.width() / 2, y: self.$stage.height() / 2 }, e);
- });
- this.$prev.off('click').on('click', function () {
- self.jump(-1);
- });
- this.$fullscreen.off('click').on('click', function () {
- self.fullscreen();
- });
- this.$next.off('click').on('click', function () {
- self.jump(1);
- });
- this.$rotateLeft.off('click').on('click', function () {
- self.rotate(-90);
- });
- this.$rotateRight.off('click').on('click', function () {
- self.rotate(90);
- });
- this.$maximize.off('click').on('click', function () {
- self.maximize();
- });
- $D.off('keydown').on('keydown', function (e) {
- self.keydown(e);
- });
- }
- }
- /**
- * Public static functions
- */
- $.magnify = {
- instance: Magnify.prototype
- }
- $.fn.magnify = function (options) {
- jqEl = $(this);
- if (typeof options === 'string') {
- // $(this).data('magnify')[options]();
- } else {
- jqEl.off('click.magnify').on('click.magnify', function (e) {
- if (e.isDefaultPrevented()) {
- return;
- }
- e.preventDefault();
- $(this).data('magnify', new Magnify(this, options));
- });
- }
- return jqEl;
- }
- /**
- * MAGNIFY DATA-API
- */
- $D.on('click.magnify', '[data-magnify]', function (e) {
- jqEl = $('[data-magnify]');
- if (e.isDefaultPrevented()) {
- return;
- }
- e.preventDefault();
- $(this).data('magnify', new Magnify(this, {}));
- });
- /**
- * draggable
- */
- // modal draggable
- var draggable = function(modal) {
- var self = this;
- var isDragging = false;
- var startX = 0,
- startY = 0,
- left = 0,
- top = 0;
- var dragStart = function(e) {
- var e = e || window.event;
- e.preventDefault();
- // Get clicked button
- var elemCancel = $(e.target).closest('.magnify-button');
- // Stop modal moving when click buttons
- if(elemCancel.length){
- return true;
- }
- isDragging = true;
- startX = e.clientX;
- startY = e.clientY;
- left = $(modal).offset().left;
- top = $(modal).offset().top;
- }
- var dragMove = function(e) {
- var e = e || window.event;
- e.preventDefault();
- if (isDragging && !isMoving && !isResizing && !self.isMaximized) {
- var endX = e.clientX,
- endY = e.clientY,
- relativeX = endX - startX,
- relativeY = endY - startY;
- $(modal).css({
- left: relativeX + left + 'px',
- top: relativeY + top + 'px'
- });
- }
- return false;
- }
- var dragEnd = function(e) {
- isDragging = false;
- }
- $(modal).on('mousedown', dragStart);
- $D.on('mousemove', dragMove);
- $D.on('mouseup', dragEnd);
- }
- // Add to Magnify Prototype
- $.extend(Magnify.prototype, {
- draggable: draggable
- });
- /**
- * image movable
- * --------------------------------------
- * 1.no movable
- * 2.vertical movable
- * 3.horizontal movable
- * 4.vertical & horizontal movable
- * --------------------------------------
- */
- var movable = function(image, stage) {
- var self = this;
- var isDragging = false;
- var startX = 0,
- startY = 0,
- left = 0,
- top = 0,
- widthDiff = 0,
- heightDiff = 0,
- δ = 0;
- var dragStart = function(e) {
- var e = e || window.event;
- e.preventDefault();
- var imageWidth = $(image).width(),
- imageHeight = $(image).height(),
- stageWidth = $(stage).width(),
- stageHeight = $(stage).height();
- isDragging = true;
- isMoving = true;
- startX = e.clientX;
- startY = e.clientY;
- // δ is the difference between image width and height
- δ = !self.isRotated ? 0 : (imageWidth - imageHeight) / 2;
- // Width or height difference can be use to limit image right or top position
- widthDiff = !self.isRotated ? (imageWidth - stageWidth) : (imageHeight - stageWidth);
- heightDiff = !self.isRotated ? (imageHeight - stageHeight) : (imageWidth - stageHeight);
- // Reclac the element position when mousedown
- // Fixed the issue of stage with a border
- left = $(image).position().left - δ;
- top = $(image).position().top + δ;
- }
- var dragMove = function(e) {
- var e = e || window.event;
- e.preventDefault();
- if (isDragging) {
- var endX = e.clientX,
- endY = e.clientY,
- relativeX = endX - startX,
- relativeY = endY - startY,
- newLeft = relativeX + left,
- newTop = relativeY + top;
- // vertical limit
- if (heightDiff > 0) {
- if ((relativeY + top) > δ) {
- newTop = δ;
- } else if ((relativeY + top) < -heightDiff + δ) {
- newTop = -heightDiff + δ;
- }
- } else {
- newTop = top;
- }
- // horizontal limit
- if (widthDiff > 0) {
- if ((relativeX + left) > -δ) {
- newLeft = -δ;
- } else if ((relativeX + left) < -widthDiff - δ) {
- newLeft = -widthDiff - δ;
- }
- } else {
- newLeft = left;
- }
- $(image).css({
- left: newLeft + 'px',
- top: newTop + 'px',
- });
- // Update image initial data
- $.extend(self.imageData, {
- left: newLeft,
- top: newTop
- });
- }
- return false;
- }
- var dragEnd = function(e) {
- isDragging = false;
- isMoving = false;
- }
- $(image).on('mousedown', dragStart);
- $D.on('mousemove', dragMove);
- $D.on('mouseup', dragEnd);
- }
- // Add to Magnify Prototype
- $.extend(Magnify.prototype, {
- movable: movable
- });
- /**
- * resizable
- * ------------------------------
- * 1.modal resizable
- * 2.keep image in stage center
- * ------------------------------
- */
- var resizable = function(modal, stage, image, minWidth, minHeight) {
- var self = this;
- var resizableHandleE = $('<div class="resizable-handle resizable-handle-e"></div>'),
- resizableHandleW = $('<div class="resizable-handle resizable-handle-w"></div>'),
- resizableHandleS = $('<div class="resizable-handle resizable-handle-s"></div>'),
- resizableHandleN = $('<div class="resizable-handle resizable-handle-n"></div>'),
- resizableHandleSE = $('<div class="resizable-handle resizable-handle-se"></div>'),
- resizableHandleSW = $('<div class="resizable-handle resizable-handle-sw"></div>'),
- resizableHandleNE = $('<div class="resizable-handle resizable-handle-ne"></div>'),
- resizableHandleNW = $('<div class="resizable-handle resizable-handle-nw"></div>');
- var resizableHandles = {
- 'e': resizableHandleE,
- 's': resizableHandleS,
- 'se': resizableHandleSE,
- 'n': resizableHandleN,
- 'w': resizableHandleW,
- 'nw': resizableHandleNW,
- 'ne': resizableHandleNE,
- 'sw': resizableHandleSW,
- }
- $(modal).append(
- resizableHandleE, resizableHandleW, resizableHandleS, resizableHandleN, resizableHandleSE, resizableHandleSW, resizableHandleNE, resizableHandleNW
- );
- var isDragging = false;
- var draggingLimit = false;
- var startX = 0,
- startY = 0,
- modalData = {
- w: 0,
- h: 0,
- l: 0,
- t: 0
- },
- stageData = {
- w: 0,
- h: 0,
- l: 0,
- t: 0
- },
- imageData = {
- w: 0,
- h: 0,
- l: 0,
- t: 0
- };
- var direction = '';
- // modal CSS options
- var getModalOpts = function(dir, offsetX, offsetY) {
- // Modal should not move when its width to the minwidth
- var modalLeft = (-offsetX + modalData.w) > minWidth ? (offsetX + modalData.l) : (modalData.l + modalData.w - minWidth),
- modalTop = (-offsetY + modalData.h) > minHeight ? (offsetY + modalData.t) : (modalData.t + modalData.h - minHeight);
- var opts = {
- 'e': {
- width: Math.max((offsetX + modalData.w), minWidth) + 'px',
- },
- 's': {
- height: Math.max((offsetY + modalData.h), minHeight) + 'px'
- },
- 'se': {
- width: Math.max((offsetX + modalData.w), minWidth) + 'px',
- height: Math.max((offsetY + modalData.h), minHeight) + 'px'
- },
- 'w': {
- width: Math.max((-offsetX + modalData.w), minWidth) + 'px',
- left: modalLeft + 'px'
- },
- 'n': {
- height: Math.max((-offsetY + modalData.h), minHeight) + 'px',
- top: modalTop + 'px'
- },
- 'nw': {
- width: Math.max((-offsetX + modalData.w), minWidth) + 'px',
- height: Math.max((-offsetY + modalData.h), minHeight) + 'px',
- top: modalTop + 'px',
- left: modalLeft + 'px'
- },
- 'ne': {
- width: Math.max((offsetX + modalData.w), minWidth) + 'px',
- height: Math.max((-offsetY + modalData.h), minHeight) + 'px',
- top: modalTop + 'px'
- },
- 'sw': {
- width: Math.max((-offsetX + modalData.w), minWidth) + 'px',
- height: Math.max((offsetY + modalData.h), minHeight) + 'px',
- left: modalLeft + 'px'
- }
- };
- return opts[dir];
- }
- // image CSS options
- var getImageOpts = function(dir, offsetX, offsetY) {
- // δ is the difference between image width and height
- var δ = !self.isRotated ? 0 : (imageData.w - imageData.h) / 2,
- imgWidth = !self.isRotated ? imageData.w : imageData.h,
- imgHeight = !self.isRotated ? imageData.h : imageData.w;
- // Image should not move when modal width to the min width
- // The minwidth is modal width, so we should clac the stage minwidth
- var widthDiff = (offsetX + modalData.w) > minWidth ? (stageData.w - imgWidth + offsetX - δ) : (minWidth - (modalData.w - stageData.w) - imgWidth - δ),
- heightDiff = (offsetY + modalData.h) > minHeight ? (stageData.h - imgHeight + offsetY + δ) : (minHeight - (modalData.h - stageData.h) - imgHeight + δ),
- widthDiff2 = (-offsetX + modalData.w) > minWidth ? (stageData.w - imgWidth - offsetX - δ) : (minWidth - (modalData.w - stageData.w) - imgWidth - δ),
- heightDiff2 = (-offsetY + modalData.h) > minHeight ? (stageData.h - imgHeight - offsetY + δ) : (minHeight - (modalData.h - stageData.h) - imgHeight + δ);
- // Get image position in dragging
- var imgLeft = $(image).position().left - δ,
- imgTop = $(image).position().top + δ;
- var opts = {
- 'e': {
- left: widthDiff >= -δ ? ((widthDiff - δ) / 2 + 'px') : (imgLeft > widthDiff ? (imgLeft + 'px') : (widthDiff + 'px'))
- },
- 's': {
- top: heightDiff >= δ ? ((heightDiff + δ) / 2 + 'px') : (imgTop > heightDiff ? (imgTop + 'px') : (heightDiff + 'px'))
- },
- 'se': {
- top: heightDiff >= δ ? ((heightDiff + δ) / 2 + 'px') : (imgTop > heightDiff ? (imgTop + 'px') : (heightDiff + 'px')),
- left: widthDiff >= -δ ? ((widthDiff - δ) / 2 + 'px') : (imgLeft > widthDiff ? (imgLeft + 'px') : (widthDiff + 'px'))
- },
- 'w': {
- left: widthDiff2 >= -δ ? ((widthDiff2 - δ) / 2 + 'px') : (imgLeft > widthDiff2 ? (imgLeft + 'px') : (widthDiff2 + 'px'))
- },
- 'n': {
- top: heightDiff2 >= δ ? ((heightDiff2 + δ) / 2 + 'px') : (imgTop > heightDiff2 ? (imgTop + 'px') : (heightDiff2 + 'px'))
- },
- 'nw': {
- top: heightDiff2 >= δ ? ((heightDiff2 + δ) / 2 + 'px') : (imgTop > heightDiff2 ? (imgTop + 'px') : (heightDiff2 + 'px')),
- left: widthDiff2 >= -δ ? ((widthDiff2 - δ) / 2 + 'px') : (imgLeft > widthDiff2 ? (imgLeft + 'px') : (widthDiff2 + 'px'))
- },
- 'ne': {
- top: heightDiff2 >= δ ? ((heightDiff2 + δ) / 2 + 'px') : (imgTop > heightDiff2 ? (imgTop + 'px') : (heightDiff2 + 'px')),
- left: widthDiff >= -δ ? ((widthDiff - δ) / 2 + 'px') : (imgLeft > widthDiff ? (imgLeft + 'px') : (widthDiff + 'px'))
- },
- 'sw': {
- top: heightDiff >= δ ? ((heightDiff + δ) / 2 + 'px') : (imgTop > heightDiff ? (imgTop + 'px') : (heightDiff + 'px')),
- left: widthDiff2 >= -δ ? ((widthDiff2 - δ) / 2 + 'px') : (imgLeft > widthDiff2 ? (imgLeft + 'px') : (widthDiff2 + 'px'))
- }
- };
- return opts[dir];
- }
- var dragStart = function(dir, e) {
- var e = e || window.event;
- e.preventDefault();
- isDragging = true;
- isResizing = true;
- startX = e.clientX;
- startY = e.clientY;
- // Reclac the modal data when mousedown
- modalData = {
- w: $(modal).width(),
- h: $(modal).height(),
- l: $(modal).offset().left,
- t: $(modal).offset().top
- };
- stageData = {
- w: $(stage).width(),
- h: $(stage).height(),
- l: $(stage).offset().left,
- t: $(stage).offset().top
- };
- imageData = {
- w: $(image).width(),
- h: $(image).height(),
- l: $(image).position().left,
- t: $(image).position().top
- };
- direction = dir;
- }
- var dragMove = function(e) {
- var e = e || window.event;
- e.preventDefault();
- if (isDragging && !self.isMaximized) {
- var endX = e.clientX,
- endY = e.clientY,
- relativeX = endX - startX,
- relativeY = endY - startY;
- var modalOpts = getModalOpts(direction, relativeX, relativeY);
- $(modal).css(modalOpts);
- // Limit dragging speed to prevent drag too fast
- // ?
- // if (draggingLimit) {
- // return false;
- // }
- // draggingLimit = true;
- // setTimeout(function() {
- // draggingLimit = false;
- // }, 50);
- var imageOpts = getImageOpts(direction, relativeX, relativeY);
- $(image).css(imageOpts);
- }
- return false;
- }
- var dragEnd = function(e) {
- isDragging = false;
- isResizing = false;
- }
- $.each(resizableHandles, function(dir, handle) {
- handle.on('mousedown', function(e) {
- dragStart(dir, e);
- });
- });
- $D.on('mousemove', dragMove);
- $D.on('mouseup', dragEnd);
- }
- // Add to Magnify Prototype
- $.extend(Magnify.prototype, {
- resizable: resizable
- });
- /**
- * Private functions
- */
- /**
- * [throttle]
- * @param {Function} fn [description]
- * @param {[Number]} delay [description]
- * @return {Function} [description]
- */
- function throttle(fn, delay) {
- var timer = null;
- return function() {
- var context = this,
- args = arguments;
- clearTimeout(timer);
- timer = setTimeout(function() {
- fn.apply(context, args);
- }, delay);
- };
- };
- /**
- * [preloadImg]
- * @param {[String]} src [image src]
- * @param {Function} fn [callbacks]
- */
- function preloadImg(src, fn) {
- var img = new Image();
- if (!!window.ActiveXObject) {
- img.onreadystatechange = function() {
- if (this.readyState == 'complete') {
- fn(img);
- }
- }
- } else {
- img.onload = function() {
- fn(img);
- }
- }
- img.src = src;
- }
- /**
- * [requestFullscreen description]
- * @param {[type]} element [description]
- */
- function requestFullscreen(element) {
- if (element.requestFullscreen) {
- element.requestFullscreen();
- } else if (element.mozRequestFullScreen) {
- element.mozRequestFullScreen();
- } else if (element.webkitRequestFullscreen) {
- element.webkitRequestFullscreen();
- } else if (element.msRequestFullscreen) {
- element.msRequestFullscreen();
- }
- }
- /**
- * [exitFullscreen description]
- */
- function exitFullscreen() {
- if (document.exitFullscreen) {
- document.exitFullscreen();
- } else if (document.mozCancelFullScreen) {
- document.mozCancelFullScreen();
- } else if (document.webkitExitFullscreen) {
- document.webkitExitFullscreen();
- }
- }
- /**
- * [getImageNameFromUrl]
- * @param {[String]} url [description]
- * @return {[String]} [description]
- */
- function getImageNameFromUrl(url) {
- var reg = /^.*?\/*([^/?]*)\.[a-z]+(\?.+|$)/ig,
- txt = url.replace(reg, '$1');
- return txt;
- }
- /**
- * [getNumFromCSSValue description]
- * @param {[type]} value [description]
- * @return {[type]} [description]
- */
- function getNumFromCSSValue(value) {
- var reg = /\d+/g,
- arr = value.match(reg),
- num = parseFloat(arr[0]);
- return num;
- }
- });
|