/*! * ___ ___ _____ ______ __ __ _____ ______ __ __ * | \/ |/ _ \ / __ \| \ | |_ _| ___| \ / | * | | / \ | | \__| \| | | | | |__ \ \/ / * | |\/| | |_| | | ___ | | | | __| \ / * | | | | _ | \_/ | |\ |_| |_| | | | * |__| |__|__| |__|\____/|_|__| \__|_____|__| |__| * * jquery.magnify - v1.4.2 * a jquery plugin to view images just like in windows * https://github.com/nzbin/magnify#readme * * 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 functions */ /** * [getimgsrc] * @param {[object]} el [description] */ function getimgsrc(el) { // get data-src as image src at first var src = $(el).attr('data-src') ? $(el).attr('data-src') : $(el).attr('href'); return src; } /** * [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} success [callbacks] * @param {function} error [callbacks] */ function preloadimg(src, success, error) { var img = new image(); img.onload = function () { success(img); }; img.onerror = function () { error(img); }; img.src = src; } /** * [requestfullscreen] * @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] */ 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; } /** * [hasscrollbar] * @return {[boolean]} [description] */ function hasscrollbar() { return document.body.scrollheight > (window.innerheight || document.documentelement.clientheight); } /** * [getscrollbarwidth] * @return {[number]} [description] */ function getscrollbarwidth() { var scrolldiv = document.createelement('div'); scrolldiv.style.csstext = 'width: 99px; height: 99px; overflow: scroll; position: absolute; top: -9999px;'; document.body.appendchild(scrolldiv); var scrollbarwidth = scrolldiv.offsetwidth - scrolldiv.clientwidth; document.body.removechild(scrolldiv); return scrollbarwidth; } /** * [setgrabcursor] * @param {[object]} imagedata [description] * @param {[object]} stagedata [description] * @param {[object]} stage [description] * @param {[boolean]} isrotate [description] */ function setgrabcursor(imagedata, stagedata, stage, isrotated) { var imagewidth = !isrotated ? imagedata.w : imagedata.h, imageheight = !isrotated ? imagedata.h : imagedata.w; if (imageheight > stagedata.h || imagewidth > stagedata.w) { stage.addclass('is-grab'); } if (imageheight <= stagedata.h && imagewidth <= stagedata.w) { stage.removeclass('is-grab'); } } /** * [supporttouch] * @return {[boolean]} [description] */ function supporttouch() { return !!(('ontouchstart' in window) || window.documenttouch && document instanceof documenttouch); } /** * [isie8] * @return {[boolean]} [description] */ function isie8() { return (navigator.appname == 'microsoft internet explorer' && navigator.appversion.indexof('msie 8.0') > 0) || (navigator.appname == 'microsoft internet explorer' && navigator.appversion.indexof('msie 7.0') > 0); } /** * private static constants */ var $w = $(window), $d = $(document), click_event = 'click', resize_event = 'resize', keydown_event = 'keydown', wheel_event = 'wheel mousewheel dommousescroll', touch_start_event = supporttouch() ? 'touchstart' : 'mousedown', touch_move_event = supporttouch() ? 'touchmove' : 'mousemove', touch_end_event = supporttouch() ? 'touchend' : 'mouseup', ns = 'magnify', event_ns = '.' + ns, // plugin default options defaults = { // enable modal to drag draggable: true, // enable modal to resize resizable: true, // enable image to move movable: true, // enable keyboard navigation keyboard: true, // shows the title title: true, // min width of modal modalwidth: 320, // min height of modal modalheight: 320, // enable the page content fixed fixedcontent: true, // disable the modal size fixed fixedmodalsize: false, // disable the image viewer maximized on init initmaximized: false, // threshold of modal to browser window gapthreshold: 0.02, // threshold of image ratio ratiothreshold: 0.1, // min ratio of image when zoom out minratio: 0.05, // max ratio of image when zoom in maxratio: 16, // toolbar options in header headtoolbar: [ 'maximize', 'close' ], // toolbar options in footer foottoolbar: [ 'zoomin', 'zoomout', 'prev', 'fullscreen', 'next', 'actualsize', 'rotateright' ], // customize button icon icons: { minimize: '\ \ ', maximize: '\ \ ', close: '\ \ ', zoomin: '\ \ ', zoomout: '\ \ ', prev: '\ \ ', next: '\ \ ', fullscreen: '\ \ ', actualsize: '\ \ ', rotateleft: '\ \ ', rotateright: '\ \ ' }, // customize language of button title i18n: { minimize: 'minimize', maximize: 'maximize', close: 'close', zoomin: 'zoom-in(+)', zoomout: 'zoom-out(-)', prev: 'prev(←)', next: 'next(→)', fullscreen: 'fullscreen', actualsize: 'actual-size(ctrl+alt+0)', rotateleft: 'rotate-left(ctrl+,)', rotateright: 'rotate-right(ctrl+.)' }, // enable multiple instances multiinstances: true, // init trigger event initevent: 'click', // enable animation initanimation: true, // disable modal position fixed when change images fixedmodalpos: false, // modal z-index zindex: 1090, // selector of drag handler draghandle: false, // callback events callbacks: { beforeopen: $.noop, opened: $.noop, beforeclose: $.noop, closed: $.noop, beforechange: $.noop, changed: $.noop }, // load the image progressively progressiveloading: true }, public_vars = { // image moving flag ismoving: false, // modal resizing flag isresizing: false, // modal z-index setting zindex: defaults.zindex }; // jquery element of calling plugin var jqel = null; /** * magnify class */ var magnify = function (el, options) { var self = this; this.options = $.extend(true, {}, defaults, options); if (options && $.isarray(options.foottoolbar)) { this.options.foottoolbar = options.foottoolbar; } if (options && $.isarray(options.headtoolbar)) { this.options.headtoolbar = options.headtoolbar; } // store element of clicked this.$el = $(el); // as we have multiple instances, // so every instance has following variables. // modal open flag this.isopened = false; // modal maximize flag this.ismaximized = false; // image rotate 90*(2n+1) flag this.isrotated = false; // image rotate angle this.rotateangle = 0; // if modal do resize this.isdoresize = false; // store image data in every instance this.imagedata = {}; // store modal data in every instance this.modaldata = { width: null, height: null, left: null, top: null }; this.init(el, self.options); }; /** * mangify prototype */ magnify.prototype = { init: function (el, opts) { // get image src var imgsrc = 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.open(); this.loadimg(imgsrc); // draggable & movable & resizable if (opts.draggable) { this.draggable(this.$magnify, this.draghandle, '.magnify-button'); } if (opts.movable) { this.movable(this.$stage, isie8() ? '.magnify-image' : this.$image); } if (opts.resizable) { this.resizable( this.$magnify, this.$stage, isie8() ? '.magnify-image' : this.$image, opts.modalwidth, opts.modalheight); } }, _creatbtns: function (toolbar, btns) { var btnsstr = ''; $.each(toolbar, function (index, item) { btnsstr += btns[item]; }); return btnsstr; }, _creattitle: function () { return (this.options.title ? '
' : ''); }, creatdom: function () { var btnstpl = { minimize: '', maximize: '', close: '', zoomin: '', zoomout: '', prev: '', next: '', fullscreen: '', actualsize: '', rotateleft: '', rotateright: '' }; // magnify base html var magnifyhtml = '
\
\
' + this._creatbtns(this.options.headtoolbar, btnstpl) + '\
' + this._creattitle() + '\
\
\ \
\ \
'; return magnifyhtml; }, 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.$header = $magnify.find('.magnify-header'); this.$headtoolbar = $magnify.find('.magnify-head-toolbar'); this.$footer = $magnify.find('.magnify-footer'); this.$foottoolbar = $magnify.find('.magnify-foot-toolbar'); this.$stage = $magnify.find('.magnify-stage'); this.$title = $magnify.find('.magnify-title'); this.$image = $magnify.find('.magnify-image'); this.$close = $magnify.find('.magnify-button-close'); this.$maximize = $magnify.find('.magnify-button-maximize'); this.$minimize = $magnify.find('.magnify-button-minimize'); 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'); // add class before image loaded this.$stage.addclass('stage-ready'); this.$image.addclass('image-ready'); // reset modal z-index with multiple instances this.$magnify.css('z-index', public_vars['zindex']); // set handle element of draggable if (!this.options.draghandle || this.options.draghandle === '.magnify-modal') { this.draghandle = this.$magnify; } else { this.draghandle = this.$magnify.find(this.options.draghandle); } }, open: function () { if (!this.options.multiinstances) { $('.magnify-modal').eq(0).remove(); } // fixed modal position bug if (!$('.magnify-modal').length && this.options.fixedcontent) { $('html').css({ 'overflow': 'hidden' }); if (hasscrollbar()) { var scrollbarwidth = getscrollbarwidth(); if (scrollbarwidth) { $('html').css({ 'padding-right': scrollbarwidth }); } } } this.build(); this._triggerhook('beforeopen', this.$el); // add magnify to dom $('body').append(this.$magnify); this.addevents(); this.setmodalpos(this.$magnify); this._triggerhook('opened', this.$el); }, close: function (el) { this._triggerhook('beforeclose', this.$el); // remove instance this.$magnify.remove(); this.isopened = false; this.ismaximized = false; this.isrotated = false; this.rotateangle = 0; var zeromodal = !$('.magnify-modal').length; // fixed modal position bug if (zeromodal && this.options.fixedcontent) { $('html').css({ 'overflow': '', 'padding-right': '' }); } // reset zindex after close if (zeromodal && this.options.multiinstances) { public_vars['zindex'] = this.options.zindex; } // off events if (!$('.magnify-modal').length) { $d.off(keydown_event + event_ns); $w.off(resize_event + event_ns); } this._triggerhook('closed', this.$el); }, setmodalpos: function (modal) { var winwidth = $w.width(), winheight = $w.height(), scrollleft = $d.scrollleft(), scrolltop = $d.scrolltop(); var modalwidth = this.options.modalwidth, modalheight = this.options.modalheight; // set modal maximized when init if (this.options.initmaximized) { modal.addclass('magnify-maximize'); modal.css({ width: '100%', height: '100%', left: 0, top: 0 }); this.isopened = true; this.ismaximized = true; } else { // make the modal in windows center modal.css({ width: modalwidth, height: modalheight, left: (winwidth - modalwidth) / 2 + scrollleft + 'px', top: (winheight - modalheight) / 2 + scrolltop + 'px' }); } }, setmodalsize: function (img) { var self = this, 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 + parsefloat(stagecss.left) + parsefloat(stagecss.right) + parsefloat(stagecss.borderleft) + parsefloat(stagecss.borderright), modalheight = img.height + parsefloat(stagecss.top) + parsefloat(stagecss.bottom) + parsefloat(stagecss.bordertop) + parsefloat(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.round(minwidth); minheight = this.options.fixedmodalsize ? this.options.modalheight : math.round(minheight); var modalcssobj = { width: minwidth + 'px', height: minheight + 'px', left: (winwidth - minwidth) / 2 + scrollleft + 'px', top: (winheight - minheight) / 2 + scrolltop + 'px' }; // add modal init animation if (this.options.initanimation) { this.$magnify.animate(modalcssobj, function () { self.setimagesize(img); }); } else { this.$magnify.css(modalcssobj); this.setimagesize(img); } this.isopened = true; }, getimagescaletostage: function(stagewidth, stageheight) { var scale = 1; if (!this.isrotated) { scale = math.min(stagewidth / this.img.width, stageheight / this.img.height, 1); } else { scale = math.min(stagewidth / this.img.height, stageheight / this.img.width, 1); } return scale; }, setimagesize: function (img) { var $image = isie8() ? this.$stage.find('.magnify-image') : this.$image; var stagedata = { w: this.$stage.width(), h: this.$stage.height() }; var scale = this.getimagescaletostage( stagedata.w, stagedata.h ); $image.css({ width: math.ceil(img.width * scale) + 'px', height: math.ceil(img.height * scale) + 'px', left: (stagedata.w - math.ceil(img.width * scale)) / 2 + 'px', top: (stagedata.h - math.ceil(img.height * scale)) / 2 + 'px' }); if (isie8()) { $image.find('group').css({ width: math.floor(img.width * scale) + 'px', height: math.floor(img.height * scale) + 'px' }); } // store image initial data $.extend(this.imagedata, { initwidth: img.width * scale, initheight: img.height * scale, initleft: (stagedata.w - img.width * scale) / 2, inittop: (stagedata.h - img.height * scale) / 2, width: img.width * scale, height: img.height * scale, left: (stagedata.w - img.width * scale) / 2, top: (stagedata.h - img.height * scale) / 2 }); // set grab cursor setgrabcursor( { w: $image.width(), h: $image.height() }, { w: this.$stage.width(), h: this.$stage.height() }, this.$stage, this.isrotated ); // remove class must when image setting end this.$stage.removeclass('stage-ready'); this.$image.removeclass('image-ready'); // loader end this.$magnify.find('.magnify-loader').remove(); // add image init animation if (this.options.initanimation && !this.options.progressiveloading) { $image.fadein(); } }, loadimg: function (imgsrc, fn, err) { var self = this; var loaderhtml = '
'; // loader start this.$magnify.append(loaderhtml); // add class before image loaded this.$stage.addclass('stage-ready'); this.$image.addclass('image-ready'); // reset image this.$image.removeattr('style').attr('src', ''); this.isrotated = false; this.rotateangle = 0; if (this.options.initanimation && !this.options.progressiveloading) { this.$image.hide(); } if (isie8()) { this.$stage.html(''); } else { this.$image.attr('src', imgsrc); } preloadimg(imgsrc, function (img) { // store htmlimageelement self.img = img; // store original data self.imagedata = { originalwidth: img.width, originalheight: img.height }; if (self.ismaximized || (self.isopened && self.options.fixedmodalpos)) { self.setimagesize(img); } else { self.setmodalsize(img); } // callback of image loaded successfully if(fn){ fn.call(); } }, function () { // loader end self.$magnify.find('.magnify-loader').remove(); // callback of image loading failed if(err){ err.call(); } }); if (this.options.title) { this.setimgtitle(imgsrc); } }, getimggroup: function (list, imgsrc) { var self = this; self.groupdata = []; $(list).each(function (index, item) { var src = 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.html(caption); }, jump: function (step) { this._triggerhook('beforechange', this.groupindex); this.groupindex = this.groupindex + step; this.jumpto(this.groupindex); }, jumpto: function (index) { var self = this; 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, function () { self._triggerhook('changed', index); }, function () { self._triggerhook('changed', index); }); }, 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 relative to stage var pointer = { x: e.originalevent.clientx - this.$stage.offset().left + $d.scrollleft(), y: e.originalevent.clienty - this.$stage.offset().top + $d.scrolltop() }; this.zoom(ratio, pointer, e); }, zoom: function (ratio, origin, e) { this.$image = isie8() ? this.$stage.find('.magnify-image') : this.$image; // zoom out ratio & zoom in ratio ratio = ratio < 0 ? (1 / (1 - ratio)) : (1 + ratio); // image ratio ratio = this.$image.width() / this.imagedata.originalwidth * ratio; // fixed digital error // if (ratio > 0.95 && ratio < 1.05) { // ratio = 1; // } if (ratio > this.options.maxratio || ratio < this.options.minratio) { return; } this.zoomto(ratio, origin, e); }, zoomto: function (ratio, origin, e) { var $image = isie8() ? this.$stage.find('.magnify-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; // δ is the difference between image new width and new height var δ = !this.isrotated ? 0 : (newwidth - newheight) / 2, imgnewwidth = !this.isrotated ? newwidth : newheight, imgnewheight = !this.isrotated ? newheight : newwidth; var offsetx = stagedata.w - newwidth, offsety = stagedata.h - newheight; // zoom out & zoom in condition // it's important and it takes me a lot of time to get it // the conditions with image rotate 90 degree drive me crazy alomst! if (imgnewheight <= stagedata.h) { newtop = (stagedata.h - newheight) / 2; } else { newtop = newtop > δ ? δ : (newtop > (offsety - δ) ? newtop : (offsety - δ)); } if (imgnewwidth <= stagedata.w) { newleft = (stagedata.w - newwidth) / 2; } else { newleft = newleft > -δ ? -δ : (newleft > (offsetx + δ) ? newleft : (offsetx + δ)); } // if the image scale get to the critical point if (math.abs(this.imagedata.initwidth - newwidth) < this.imagedata.initwidth * 0.05) { this.setimagesize(this.img); } else { $image.css({ width: math.round(newwidth) + 'px', height: math.round(newheight) + 'px', left: math.round(newleft) + 'px', top: math.round(newtop) + 'px' }); if (isie8()) { $image.find('group').css({ width: math.ceil(newwidth) + 'px', height: math.ceil(newheight) + 'px' }); } // set grab cursor setgrabcursor( { w: math.round(imgnewwidth), h: math.round(imgnewheight) }, { w: stagedata.w, h: stagedata.h }, this.$stage ); } // update image initial data $.extend(this.imagedata, { width: newwidth, height: newheight, left: newleft, top: newtop }); }, rotate: function (angle) { this.rotateangle = this.rotateangle + angle; if ((this.rotateangle / 90) % 2 === 0) { this.isrotated = false; } else { this.isrotated = true; } this.rotateto(this.rotateangle); }, rotateto: function (angle) { var self = this, $image = isie8() ? this.$stage.find('.magnify-image') : this.$image; // depend on jqueryrotate.js $image.rotate({ angle: angle }); this.setimagesize({ width: this.imagedata.originalwidth, height: this.imagedata.originalheight }); // remove grab cursor when rotate this.$stage.removeclass('is-grab'); }, resize: function () { var self = this; var resizehandler = throttle(function () { if (self.isopened) { if (self.ismaximized) { self.setimagesize({ width: self.imagedata.originalwidth, height: self.imagedata.originalheight }); } else { self.setmodalsize({ width: self.imagedata.originalwidth, height: self.imagedata.originalheight }); } } }, 500); return resizehandler; }, maximize: function () { var self = this; 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: 0, top: 0 }); this.ismaximized = true; } else { this.$magnify.removeclass('magnify-maximize'); this.$magnify.css({ width: this.modaldata.width ? this.modaldata.width : this.options.modalwidth, height: this.modaldata.height ? this.modaldata.height : this.options.modalheight, left: this.modaldata.left ? this.modaldata.left : ($w.width() - this.options.modalwidth) / 2 + $d.scrollleft(), top: this.modaldata.top ? this.modaldata.top : ($w.height() - this.options.modalheight) / 2 + $d.scrolltop() }); this.ismaximized = false; } this.setimagesize({ width: this.imagedata.originalwidth, height: this.imagedata.originalheight }); }, fullscreen: function () { requestfullscreen(this.$magnify[0]); }, keydown: function (e) { 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: } }, addevents: function () { var self = this; this.$close.off(click_event + event_ns).on(click_event + event_ns, function (e) { self.close(); }); this.$stage.off(wheel_event + event_ns).on(wheel_event + event_ns, function (e) { self.wheel(e); }); this.$zoomin.off(click_event + event_ns).on(click_event + event_ns, function (e) { self.zoom( self.options.ratiothreshold * 3, { x: self.$stage.width() / 2, y: self.$stage.height() / 2 }, e ); }); this.$zoomout.off(click_event + event_ns).on(click_event + event_ns, function (e) { self.zoom( -self.options.ratiothreshold * 3, { x: self.$stage.width() / 2, y: self.$stage.height() / 2 }, e ); }); this.$actualsize.off(click_event + event_ns).on(click_event + event_ns, function (e) { self.zoomto( 1, { x: self.$stage.width() / 2, y: self.$stage.height() / 2 }, e ); }); this.$prev.off(click_event + event_ns).on(click_event + event_ns, function () { self.jump(-1); }); this.$fullscreen.off(click_event + event_ns).on(click_event + event_ns, function () { self.fullscreen(); }); this.$next.off(click_event + event_ns).on(click_event + event_ns, function () { self.jump(1); }); this.$rotateleft.off(click_event + event_ns).on(click_event + event_ns, function () { self.rotate(-90); }); this.$rotateright.off(click_event + event_ns).on(click_event + event_ns, function () { self.rotate(90); }); this.$maximize.off(click_event + event_ns).on(click_event + event_ns, function () { self.maximize(); }); $d.off(keydown_event + event_ns).on(keydown_event + event_ns, function (e) { self.keydown(e); }); $w.on(resize_event + event_ns, self.resize()); }, _triggerhook: function (e, data) { if (this.options.callbacks[e]) { this.options.callbacks[e].apply(this, $.isarray(data) ? data : [data]); } } }; /** * jquery plugin */ $.fn.magnify = function (options) { jqel = $(this); // convert a numeric string into a number for (var key in options) { if (typeof (options[key]) === 'string' && !isnan(options[key])) { options[key] = parsefloat(options[key]); } } // get init event, 'click' or 'dblclick' var opts = $.extend(true, {}, defaults, options); // we should get zindex of options before plugin's init. public_vars['zindex'] = opts.zindex; if (typeof options === 'string') { // $(this).data('magnify')[options](); } else { if (opts.initevent === 'dblclick') { jqel.off('click' + event_ns).on('click' + event_ns, function (e) { e.preventdefault(); // this will stop triggering data-api event e.stoppropagation(); }); } jqel.off(opts.initevent + event_ns).on(opts.initevent + event_ns, function (e) { e.preventdefault(); // this will stop triggering data-api event e.stoppropagation(); $(this).data('magnify', new magnify(this, options)); }); } return jqel; }; /** * magnify data-api */ $d.on(click_event + event_ns, '[data-magnify]', function (e) { jqel = $('[data-magnify]'); e.preventdefault(); $(this).data('magnify', new magnify(this, defaults)); }); /** * [draggable] * @param {[object]} modal [the modal element] * @param {[object]} draghandle [the handle element when dragging] * @param {[object]} dragcancel [the cancel element when dragging] */ var draggable = function (modal, draghandle, dragcancel) { var self = this; var isdragging = false; var startx = 0, starty = 0, left = 0, top = 0; var dragstart = function (e) { var e = e || window.event; // must be removed // e.preventdefault(); if (self.options.multiinstances) { modal.css('z-index', ++public_vars['zindex']); } // get clicked button var elemcancel = $(e.target).closest(dragcancel); // stop modal moving when click buttons if (elemcancel.length) { return true; } isdragging = true; startx = e.type === 'touchstart' ? e.originalevent.targettouches[0].pagex : e.clientx; starty = e.type === 'touchstart' ? e.originalevent.targettouches[0].pagey : e.clienty; left = $(modal).offset().left; top = $(modal).offset().top; $d.on(touch_move_event + event_ns, dragmove) .on(touch_end_event + event_ns, dragend); }; var dragmove = function (e) { var e = e || window.event; e.preventdefault(); if (isdragging && !public_vars['ismoving'] && !public_vars['isresizing'] && !self.ismaximized) { var endx = e.type === 'touchmove' ? e.originalevent.targettouches[0].pagex : e.clientx, endy = e.type === 'touchmove' ? e.originalevent.targettouches[0].pagey : e.clienty, relativex = endx - startx, relativey = endy - starty; $(modal).css({ left: relativex + left + 'px', top: relativey + top + 'px' }); } }; var dragend = function (e) { $d.off(touch_move_event + event_ns, dragmove) .off(touch_end_event + event_ns, dragend); isdragging = false; }; $(draghandle).on(touch_start_event + event_ns, dragstart); }; // add to magnify prototype $.extend(magnify.prototype, { draggable: draggable }); /** * -------------------------------------- * 1.no movable * 2.vertical movable * 3.horizontal movable * 4.vertical & horizontal movable * -------------------------------------- * * [image movable] * @param {[object]} stage [the stage element] * @param {[object]} image [the image element] */ var movable = function (stage, image) { 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 $image = isie8() ? $(stage).find(image) : $(image); var imagewidth = $image.width(), imageheight = $image.height(), stagewidth = $(stage).width(), stageheight = $(stage).height(); startx = e.type === 'touchstart' ? e.originalevent.targettouches[0].pagex : e.clientx; starty = e.type === 'touchstart' ? e.originalevent.targettouches[0].pagey : 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); // modal can be dragging if image is smaller to stage isdragging = (widthdiff > 0 || heightdiff > 0) ? true : false; public_vars['ismoving'] = (widthdiff > 0 || heightdiff > 0) ? true : false; // reclac the element position when mousedown // fixed the issue of stage with a border left = $image.position().left - (isie8() ? 0 : δ); top = $image.position().top + (isie8() ? 0 : δ); // add grabbing cursor if (stage.hasclass('is-grab')) { $('html,body,.magnify-modal,.magnify-stage,.magnify-button,.magnify-resizable-handle').addclass('is-grabbing'); } $d.on(touch_move_event + event_ns, dragmove) .on(touch_end_event + event_ns, dragend); }; var dragmove = function (e) { var e = e || window.event; e.preventdefault(); var $image = isie8() ? $(stage).find(image) : $(image); if (isdragging) { var endx = e.type === 'touchmove' ? e.originalevent.targettouches[0].pagex : e.clientx, endy = e.type === 'touchmove' ? e.originalevent.targettouches[0].pagey : 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 }); } }; var dragend = function (e) { $d.off(touch_move_event + event_ns, dragmove) .off(touch_end_event + event_ns, dragend); isdragging = false; public_vars['ismoving'] = false; // remove grabbing cursor $('html,body,.magnify-modal,.magnify-stage,.magnify-button,.magnify-resizable-handle').removeclass('is-grabbing'); }; $(stage).on(touch_start_event + event_ns, dragstart); }; // add to magnify prototype $.extend(magnify.prototype, { movable: movable }); /** * ------------------------------ * 1.modal resizable * 2.keep image in stage center * 3.other image limitations * ------------------------------ * * [resizable] * @param {[object]} modal [the modal element] * @param {[object]} stage [the stage element] * @param {[object]} image [the image element] * @param {[number]} minwidth [the option of modalwidth] * @param {[number]} minheight [the option of modalheight] */ var resizable = function (modal, stage, image, minwidth, minheight) { var self = this; var resizablehandlee = $('
'), resizablehandlew = $('
'), resizablehandles = $('
'), resizablehandlen = $('
'), resizablehandlese = $('
'), resizablehandlesw = $('
'), resizablehandlene = $('
'), resizablehandlenw = $('
'); 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 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 }, // δ is the difference between image width and height δ = 0, imgwidth = 0, imgheight = 0, 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) { var $image = isie8() ? $(stage).find(image) : $(image); // in modern browser, the width and height of image won't change after rotated. // but its position top and left will get values from the image rotated. // in ie8 browser, due to the type of rotating, all the value will be the same. var imgposleft = isie8() ? ($image.position().left + δ) : $image.position().left, imgpostop = isie8() ? ($image.position().top - δ) : $image.position().top; // 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 = (widthdiff > 0 ? imgposleft : (imgposleft < 0 ? imgposleft : 0)) - δ, imgtop = (heightdiff > 0 ? imgpostop : (imgpostop < 0 ? imgpostop : 0)) + δ, imgleft2 = (widthdiff2 > 0 ? imgposleft : (imgposleft < 0 ? imgposleft : 0)) - δ, imgtop2 = (heightdiff2 > 0 ? imgpostop : (imgpostop < 0 ? imgpostop : 0)) + δ; 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') : (imgleft2 > widthdiff2 ? (imgleft2 + 'px') : (widthdiff2 + 'px')) }, 'n': { top: heightdiff2 >= δ ? ((heightdiff2 + δ) / 2 + 'px') : (imgtop2 > heightdiff2 ? (imgtop2 + 'px') : (heightdiff2 + 'px')) }, 'nw': { top: heightdiff2 >= δ ? ((heightdiff2 + δ) / 2 + 'px') : (imgtop2 > heightdiff2 ? (imgtop2 + 'px') : (heightdiff2 + 'px')), left: widthdiff2 >= -δ ? ((widthdiff2 - δ) / 2 + 'px') : (imgleft2 > widthdiff2 ? (imgleft2 + 'px') : (widthdiff2 + 'px')) }, 'ne': { top: heightdiff2 >= δ ? ((heightdiff2 + δ) / 2 + 'px') : (imgtop2 > heightdiff2 ? (imgtop2 + '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') : (imgleft2 > widthdiff2 ? (imgleft2 + 'px') : (widthdiff2 + 'px')) } }; return opts[dir]; }; var dragstart = function (dir, e) { var e = e || window.event; e.preventdefault(); var $image = isie8() ? $(stage).find(image) : $(image); isdragging = true; public_vars['isresizing'] = true; startx = e.type === 'touchstart' ? e.originalevent.targettouches[0].pagex : e.clientx; starty = e.type === 'touchstart' ? e.originalevent.targettouches[0].pagey : 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 }; // δ is the difference between image width and height δ = !self.isrotated ? 0 : (imagedata.w - imagedata.h) / 2; imgwidth = !self.isrotated ? imagedata.w : imagedata.h; imgheight = !self.isrotated ? imagedata.h : imagedata.w; direction = dir; // add resizable cursor $('html,body,.magnify-modal,.magnify-stage,.magnify-button').css('cursor', dir + '-resize'); $d.on(touch_move_event + event_ns, dragmove) .on(touch_end_event + event_ns, dragend); }; var dragmove = function (e) { var e = e || window.event; e.preventdefault(); var $image = isie8() ? $(stage).find(image) : $(image); if (isdragging && !self.ismaximized) { var endx = e.type === 'touchmove' ? e.originalevent.targettouches[0].pagex : e.clientx, endy = e.type === 'touchmove' ? e.originalevent.targettouches[0].pagey : e.clienty, relativex = endx - startx, relativey = endy - starty; var modalopts = getmodalopts(direction, relativex, relativey); $(modal).css(modalopts); var imageopts = getimageopts(direction, relativex, relativey); $image.css(imageopts); self.isdoresize = true; } }; var dragend = function (e) { $d.off(touch_move_event + event_ns, dragmove) .off(touch_end_event + event_ns, dragend); // set grab cursor if (public_vars['isresizing']) { setgrabcursor( { w: imgwidth, h: imgheight }, { w: $(stage).width(), h: $(stage).height() }, stage ); } isdragging = false; public_vars['isresizing'] = false; // remove resizable cursor $('html,body,.magnify-modal,.magnify-stage,.magnify-button').css('cursor', ''); // update image initial data var scale = self.getimagescaletostage( $(stage).width(), $(stage).height() ); $.extend(self.imagedata, { initwidth: self.img.width * scale, initheight: self.img.height * scale, initleft: ($(stage).width() - self.img.width * scale) / 2, inittop: ($(stage).height() - self.img.height * scale) / 2 }); }; $.each(resizablehandles, function (dir, handle) { handle.on(touch_start_event + event_ns, function (e) { dragstart(dir, e); }); }); }; // add to magnify prototype $.extend(magnify.prototype, { resizable: resizable }); }); // version: 2.3 last update: 11.07.2013 /* * licensed under the mit license: http://www.opensource.org/licenses/mit-license.php * * made by wilq32, wilq32@gmail.com, wroclaw, poland, 01.2009 * website: http://jqueryrotate.com */ (function($) { var supportedcss, supportedcssorigin, styles = document.getelementsbytagname('head')[0].style, tocheck = 'transformproperty webkittransform otransform mstransform moztransform'.split(' '); for (var a = 0; a < tocheck.length; a++) if (styles[tocheck[a]] !== undefined) { supportedcss = tocheck[a]; } if (supportedcss) { supportedcssorigin = supportedcss.replace(/[tt]ransform/, 'transformorigin'); if (supportedcssorigin[0] == 't') supportedcssorigin[0] = 't'; } // bad eval to preven google closure to remove it from code o_o eval('ie = "v"=="\v"'); jquery.fn.extend({ rotate: function(parameters) { if (this.length === 0 || typeof parameters == 'undefined') return; if (typeof parameters == 'number') parameters = { angle: parameters }; var returned = []; for (var i = 0, i0 = this.length; i < i0; i++) { var element = this.get(i); if (!element.wilq32 || !element.wilq32.photoeffect) { var paramclone = $.extend(true, {}, parameters); var newrotobject = new wilq32.photoeffect(element, paramclone)._rootobj; returned.push($(newrotobject)); } else { element.wilq32.photoeffect._handlerotation(parameters); } } return returned; }, getrotateangle: function() { var ret = [0]; for (var i = 0, i0 = this.length; i < i0; i++) { var element = this.get(i); if (element.wilq32 && element.wilq32.photoeffect) { ret[i] = element.wilq32.photoeffect._angle; } } return ret; }, stoprotate: function() { for (var i = 0, i0 = this.length; i < i0; i++) { var element = this.get(i); if (element.wilq32 && element.wilq32.photoeffect) { cleartimeout(element.wilq32.photoeffect._timer); } } } }); // library agnostic interface wilq32 = window.wilq32 || {}; wilq32.photoeffect = (function() { if (supportedcss) { return function(img, parameters) { img.wilq32 = { photoeffect: this }; this._img = this._rootobj = this._eventobj = img; this._handlerotation(parameters); }; } else { return function(img, parameters) { this._img = img; this._onloaddelegate = [parameters]; this._rootobj = document.createelement('span'); this._rootobj.style.display = 'inline-block'; this._rootobj.wilq32 = { photoeffect: this }; img.parentnode.insertbefore(this._rootobj, img); if (img.complete) { this._loader(); } else { var self = this; // todo: remove jquery dependency jquery(this._img).bind('load', function() { self._loader(); }); } }; } })(); wilq32.photoeffect.prototype = { _setupparameters: function(parameters) { this._parameters = this._parameters || {}; if (typeof this._angle !== 'number') { this._angle = 0; } if (typeof parameters.angle === 'number') { this._angle = parameters.angle; } this._parameters.animateto = (typeof parameters.animateto === 'number') ? (parameters.animateto) : (this._angle); this._parameters.step = parameters.step || this._parameters.step || null; this._parameters.easing = parameters.easing || this._parameters.easing || this._defaulteasing; this._parameters.duration = 'duration' in parameters ? parameters.duration : parameters.duration || this._parameters.duration || 1000; this._parameters.callback = parameters.callback || this._parameters.callback || this._emptyfunction; this._parameters.center = parameters.center || this._parameters.center || ['50%', '50%']; if (typeof this._parameters.center[0] == 'string') { this._rotationcenterx = (parseint(this._parameters.center[0], 10) / 100) * this._imgwidth * this._aspectw; } else { this._rotationcenterx = this._parameters.center[0]; } if (typeof this._parameters.center[1] == 'string') { this._rotationcentery = (parseint(this._parameters.center[1], 10) / 100) * this._imgheight * this._aspecth; } else { this._rotationcentery = this._parameters.center[1]; } if (parameters.bind && parameters.bind != this._parameters.bind) { this._bindevents(parameters.bind); } }, _emptyfunction: function() {}, _defaulteasing: function(x, t, b, c, d) { return -c * ((t = t / d - 1) * t * t * t - 1) + b; }, _handlerotation: function(parameters, dontcheck) { if (!supportedcss && !this._img.complete && !dontcheck) { this._onloaddelegate.push(parameters); return; } this._setupparameters(parameters); if (this._angle == this._parameters.animateto) { this._rotate(this._angle); } else { this._animatestart(); } }, _bindevents: function(events) { if (events && this._eventobj) { // unbinding previous events if (this._parameters.bind) { var oldevents = this._parameters.bind; for (var a in oldevents) if (oldevents.hasownproperty(a)) // todo: remove jquery dependency jquery(this._eventobj).unbind(a, oldevents[a]); } this._parameters.bind = events; for (var a in events) if (events.hasownproperty(a)) // todo: remove jquery dependency jquery(this._eventobj).bind(a, events[a]); } }, _loader: (function() { if (ie) return function() { var width = this._img.width; var height = this._img.height; this._imgwidth = width; this._imgheight = height; this._img.parentnode.removechild(this._img); this._vimage = this.createvmlnode('image'); this._vimage.src = this._img.src; this._vimage.style.height = height + 'px'; this._vimage.style.width = width + 'px'; this._vimage.style.position = 'absolute'; // fixes ie problem - its only rendered if its on absolute position! this._vimage.style.top = '0px'; this._vimage.style.left = '0px'; this._aspectw = this._aspecth = 1; /* group minifying a small 1px precision problem when rotating object */ this._container = this.createvmlnode('group'); this._container.style.width = width; this._container.style.height = height; this._container.style.position = 'absolute'; this._container.style.top = '0px'; this._container.style.left = '0px'; this._container.setattribute('coordsize', width - 1 + ',' + (height - 1)); // this -1, -1 trying to fix ugly problem with small displacement on ie this._container.appendchild(this._vimage); this._rootobj.appendchild(this._container); this._rootobj.style.position = 'relative'; // fixes ie problem this._rootobj.style.width = width + 'px'; this._rootobj.style.height = height + 'px'; this._rootobj.setattribute('id', this._img.getattribute('id')); this._rootobj.classname = this._img.classname; this._eventobj = this._rootobj; var parameters; while (parameters = this._onloaddelegate.shift()) { this._handlerotation(parameters, true); } }; else return function() { this._rootobj.setattribute('id', this._img.getattribute('id')); this._rootobj.classname = this._img.classname; this._imgwidth = this._img.naturalwidth; this._imgheight = this._img.naturalheight; var _widthmax = math.sqrt((this._imgheight) * (this._imgheight) + (this._imgwidth) * (this._imgwidth)); this._width = _widthmax * 3; this._height = _widthmax * 3; this._aspectw = this._img.offsetwidth / this._img.naturalwidth; this._aspecth = this._img.offsetheight / this._img.naturalheight; this._img.parentnode.removechild(this._img); this._canvas = document.createelement('canvas'); this._canvas.setattribute('width', this._width); this._canvas.style.position = 'relative'; this._canvas.style.left = -this._img.height * this._aspectw + 'px'; this._canvas.style.top = -this._img.width * this._aspecth + 'px'; this._canvas.wilq32 = this._rootobj.wilq32; this._rootobj.appendchild(this._canvas); this._rootobj.style.width = this._img.width * this._aspectw + 'px'; this._rootobj.style.height = this._img.height * this._aspecth + 'px'; this._eventobj = this._canvas; this._cnv = this._canvas.getcontext('2d'); var parameters; while (parameters = this._onloaddelegate.shift()) { this._handlerotation(parameters, true); } }; })(), _animatestart: function() { if (this._timer) { cleartimeout(this._timer); } this._animatestarttime = +new date; this._animatestartangle = this._angle; this._animate(); }, _animate: function() { var actualtime = +new date; var checkend = actualtime - this._animatestarttime > this._parameters.duration; // todo: bug for animatedgif for static rotation ? (to test) if (checkend && !this._parameters.animatedgif) { cleartimeout(this._timer); } else { if (this._canvas || this._vimage || this._img) { var angle = this._parameters.easing(0, actualtime - this._animatestarttime, this._animatestartangle, this._parameters.animateto - this._animatestartangle, this._parameters.duration); this._rotate((~~(angle * 10)) / 10); } if (this._parameters.step) { this._parameters.step(this._angle); } var self = this; this._timer = settimeout(function() { self._animate.call(self); }, 10); } // to fix bug that prevents using recursive function in callback i moved this function to back if (this._parameters.callback && checkend) { this._angle = this._parameters.animateto; this._rotate(this._angle); this._parameters.callback.call(this._rootobj); } }, _rotate: (function() { var rad = math.pi / 180; if (ie) return function(angle) { this._angle = angle; this._container.style.rotation = (angle % 360) + 'deg'; this._vimage.style.top = -(this._rotationcentery - this._imgheight / 2) + 'px'; this._vimage.style.left = -(this._rotationcenterx - this._imgwidth / 2) + 'px'; this._container.style.top = this._rotationcentery - this._imgheight / 2 + 'px'; this._container.style.left = this._rotationcenterx - this._imgwidth / 2 + 'px'; }; else if (supportedcss) return function(angle) { this._angle = angle; this._img.style[supportedcss] = 'rotate(' + (angle % 360) + 'deg)'; this._img.style[supportedcssorigin] = this._parameters.center.join(' '); }; else return function(angle) { this._angle = angle; angle = (angle % 360) * rad; // clear canvas this._canvas.width = this._width; //+this._widthadd; this._canvas.height = this._height; //+this._heightadd; // remember: all drawings are read from backwards.. so first function is translate, then rotate, then translate, translate.. this._cnv.translate(this._imgwidth * this._aspectw, this._imgheight * this._aspecth); // at least center image on screen this._cnv.translate(this._rotationcenterx, this._rotationcentery); // we move image back to its orginal this._cnv.rotate(angle); // rotate image this._cnv.translate(-this._rotationcenterx, -this._rotationcentery); // move image to its center, so we can rotate around its center this._cnv.scale(this._aspectw, this._aspecth); // scale - if needed ;) this._cnv.drawimage(this._img, 0, 0); // first - we draw image }; })() }; if (ie) { wilq32.photoeffect.prototype.createvmlnode = (function() { document.createstylesheet().addrule('.rvml', 'behavior:url(#default#vml)'); try { !document.namespaces.rvml && document.namespaces.add('rvml', 'urn:schemas-microsoft-com:vml'); return function(tagname) { return document.createelement(''); }; } catch (e) { return function(tagname) { return document.createelement('<' + tagname + ' xmlns="urn:schemas-microsoft.com:vml" class="rvml">'); }; } })(); } })(jquery);