/* * jquery.zoomooz-core.js, part of: * http://janne.aukia.com/zoomooz * * Version history: * 1.04 fixed examples, iphone tuneups, transform offset fix * 1.03 added closeclick, code structuring * 1.02 bug fix on endcallback resetting for native animation * 1.01 declarative syntax and fixes * 0.92 working scrolling * 0.91 simplifying code base and scrolling for non-body zoom roots * 0.90 fixing margin on first body child * 0.89 support for jquery 1.7 * 0.88 fixed a bug with 90 deg rotations * 0.87 fixed a bug with settings and a couple of demos * 0.86 fixed a bug with non-body zoom root * 0.85 basic IE9 support * 0.81 basic support for scrolling * 0.80 refactored position code to a separate file * 0.72 fixed a bug with skew in Webkit * 0.71 fixed bugs with FF4 * 0.70 support for non-body zoom root * 0.69 better settings management * 0.68 root element tuning * 0.67 adjustable zoom origin (not fully working yet) * 0.65 zoom origin to center * 0.63 basic Opera support * 0.61 refactored to use CSSMatrix classes * 0.51 initial public version * * LICENCE INFORMATION: * * Copyright (c) 2010 Janne Aukia (janne.aukia.com) * Dual licensed under the MIT (MIT-LICENSE.txt) * and GPL Version 2 (GPL-LICENSE.txt) licenses. * * LICENCE INFORMATION FOR DERIVED FUNCTIONS: * * Function computeTotalTransformation based * on jquery.fn.offset, copyright John Resig, 2010 * (MIT and GPL Version 2). * */ /*jslint sub: true */ (function($) { "use strict"; //**********************************// //*** Variables ***// //**********************************// var helpers = $.zoomooz.helpers; var animationSettings = ["duration", "easing", "nativeanimation"]; //**********************************// //*** Static setup ***// //**********************************// setupCssStyles(); //**********************************// //*** jQuery functions ***// //**********************************// if(!$.zoomooz) { $.zoomooz = {}; } /* this can be used for setting the default settings for zoomooz explicitly. */ $.zoomooz.setup = function(settings) { $.zoomooz.defaultSettings = jQuery.extend(constructDefaultSettings(), settings); }; /* returns the zooming settings of a particular element. used by zoomTarget. */ $.fn.zoomSettings = function(settings) { var retValue; this.each(function() { var $elem = $(this); retValue = setupElementSettings($elem, settings); }); return retValue; } /* the main zooming method. */ $.fn.zoomTo = function(settings, skipElementSettings) { this.each(function() { var $this = $(this); if(!skipElementSettings) { settings = $this.zoomSettings(settings); } zoomTo($this, settings); if(settings.debug) { if($("#debug").length===0) { $(settings.root).append('
'); } else { $("#debug").html(""); } showDebug($this,settings); } else { if($("#debug").length!==0) { $("#debug").html(""); } } }); return this; }; //**********************************// //*** Setup functions ***// //**********************************// function setupElementSettings($elem, baseSettings) { var settings = jQuery.extend({}, baseSettings); if(!$.zoomooz.defaultSettings) { $.zoomooz.setup(); } var defaultSettings = $.zoomooz.defaultSettings; var elementSettings = jQuery.extend({},settings); for(var key in defaultSettings) { if (defaultSettings.hasOwnProperty(key) && !elementSettings[key]) { elementSettings[key] = $elem.data(key); } } // FIXME: it would be better, that the animationSettings // would come from the jquery.zoomooz-anim file somehow for(var i=0;i
'; $("#debug").append(label); } //**********************************// //*** Calculating element ***// //*** total transformation ***// //**********************************// /* Based on: * jQuery.fn.offset */ function computeTotalTransformation(input, transformationRootElement) { var elem = input[0]; if( !elem || !elem.ownerDocument ) { return null; } var totalTransformation = new PureCSSMatrix(); var trans; if ( elem === elem.ownerDocument.body ) { var bOffset = jQuery.offset.bodyOffset( elem ); trans = new PureCSSMatrix(); trans = trans.translate(bOffset.left, bOffset.top); totalTransformation = totalTransformation.multiply(trans); return totalTransformation; } var support; if(jQuery.offset.initialize) { jQuery.offset.initialize(); support = { fixedPosition:jQuery.offset.supportsFixedPosition, doesNotAddBorder:jQuery.offset.doesNotAddBorder, doesAddBorderForTableAndCells:jQuery.support.doesAddBorderForTableAndCells, subtractsBorderForOverflowNotVisible:jQuery.offset.subtractsBorderForOverflowNotVisible } } else { support = jQuery.support; } var offsetParent = elem.offsetParent; var doc = elem.ownerDocument; var computedStyle; var docElem = doc.documentElement; var body = doc.body; var root = transformationRootElement[0]; var defaultView = doc.defaultView; var prevComputedStyle; if(defaultView) { prevComputedStyle = defaultView.getComputedStyle( elem, null ); } else { prevComputedStyle = elem.currentStyle; } /* function offsetParentInsideRoot($elem, $root) { // FIXME: // wondering, should this be $root.closest() // or $root.parent().closest... var $viewport = $root.parent(); var $offsetParent = $elem.offsetParent(); return ($viewport[0]==$offsetParent[0]) || $viewport.closest($offsetParent).length==0; } console.log("inside root",offsetParentInsideRoot(input, transformationRootElement)); */ var top = elem.offsetTop; var left = elem.offsetLeft; var transformation = constructTransformation().translate(left,top); transformation = transformation.multiply(constructTransformation(elem)); totalTransformation = transformation.multiply((totalTransformation)); // loop from node down to root while ( (elem = elem.parentNode) && elem !== root) { top = 0; left = 0; if ( support.fixedPosition && prevComputedStyle.position === "fixed" ) { break; } computedStyle = defaultView ? defaultView.getComputedStyle(elem, null) : elem.currentStyle; top -= elem.scrollTop; left -= elem.scrollLeft; if ( elem === offsetParent ) { top += elem.offsetTop; left += elem.offsetLeft; if ( support.doesNotAddBorder && !(support.doesAddBorderForTableAndCells && /^t(able|d|h)$/i.test(elem.nodeName)) ) { top += parseFloat( computedStyle.borderTopWidth ) || 0; left += parseFloat( computedStyle.borderLeftWidth ) || 0; } offsetParent = elem.offsetParent; } if ( support.subtractsBorderForOverflowNotVisible && computedStyle.overflow !== "visible" ) { top += parseFloat( computedStyle.borderTopWidth ) || 0; left += parseFloat( computedStyle.borderLeftWidth ) || 0; } prevComputedStyle = computedStyle; if(elem.offsetParent==root) { top -= parseFloat($(elem.offsetParent).css("margin-top")) || 0; left -= parseFloat($(elem.offsetParent).css("margin-left")) || 0; } transformation = constructTransformation().translate(left,top); transformation = transformation.multiply(constructTransformation(elem)); totalTransformation = transformation.multiply(totalTransformation); } top = 0; left = 0; // fixme: should disable these for non-body roots? if ( prevComputedStyle.position === "relative" || prevComputedStyle.position === "static" ) { top += body.offsetTop; left += body.offsetLeft; } if ( support.fixedPosition && prevComputedStyle.position === "fixed" ) { top += Math.max( docElem.scrollTop, body.scrollTop ); left += Math.max( docElem.scrollLeft, body.scrollLeft ); } var itertrans = (new PureCSSMatrix()).translate(left,top); totalTransformation = totalTransformation.multiply(itertrans); return totalTransformation; } //**********************************// //*** Helpers ***// //**********************************// function printFixedNumber(x) { return Number(x).toFixed(6); } function constructTransformation(elem) { var rawTrans = helpers.getElementTransform(elem); if(!rawTrans) { return new PureCSSMatrix(); } else { return new PureCSSMatrix(rawTrans); } } })(jQuery);