Created
October 31, 2013 06:46
-
-
Save rickdog/7245244 to your computer and use it in GitHub Desktop.
zoom
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| /*! | |
| * zoom.js 0.2 | |
| * http://lab.hakim.se/zoom-js | |
| * MIT licensed | |
| * | |
| * Copyright (C) 2011-2012 Hakim El Hattab, http://hakim.se | |
| */ | |
| var zoom = (function(){ | |
| // The current zoom level (scale) | |
| var level = 1; | |
| // The current mouse position, used for panning | |
| var mouseX = 0, | |
| mouseY = 0; | |
| // Timeout before pan is activated | |
| var panEngageTimeout = -1, | |
| panUpdateInterval = -1; | |
| // Check for transform support so that we can fallback otherwise | |
| var supportsTransforms = 'WebkitTransform' in document.body.style || | |
| 'MozTransform' in document.body.style || | |
| 'msTransform' in document.body.style || | |
| 'OTransform' in document.body.style || | |
| 'transform' in document.body.style; | |
| if( supportsTransforms ) { | |
| // The easing that will be applied when we zoom in/out | |
| document.body.style.transition = 'transform 0.8s ease'; | |
| document.body.style.OTransition = '-o-transform 0.8s ease'; | |
| document.body.style.msTransition = '-ms-transform 0.8s ease'; | |
| document.body.style.MozTransition = '-moz-transform 0.8s ease'; | |
| document.body.style.WebkitTransition = '-webkit-transform 0.8s ease'; | |
| } | |
| // Zoom out if the user hits escape | |
| document.addEventListener( 'keyup', function( event ) { | |
| if( level !== 1 && event.keyCode === 27 ) { | |
| zoom.out(); | |
| } | |
| } ); | |
| // Monitor mouse movement for panning | |
| document.addEventListener( 'mousemove', function( event ) { | |
| if( level !== 1 ) { | |
| mouseX = event.clientX; | |
| mouseY = event.clientY; | |
| } | |
| } ); | |
| /** | |
| * Applies the CSS required to zoom in, prioritizes use of CSS3 | |
| * transforms but falls back on zoom for IE. | |
| * | |
| * @param {Number} pageOffsetX | |
| * @param {Number} pageOffsetY | |
| * @param {Number} elementOffsetX | |
| * @param {Number} elementOffsetY | |
| * @param {Number} scale | |
| */ | |
| function magnify( pageOffsetX, pageOffsetY, elementOffsetX, elementOffsetY, scale ) { | |
| if( supportsTransforms ) { | |
| var origin = pageOffsetX +'px '+ pageOffsetY +'px', | |
| transform = 'translate('+ -elementOffsetX +'px,'+ -elementOffsetY +'px) scale('+ scale +')'; | |
| document.body.style.transformOrigin = origin; | |
| document.body.style.OTransformOrigin = origin; | |
| document.body.style.msTransformOrigin = origin; | |
| document.body.style.MozTransformOrigin = origin; | |
| document.body.style.WebkitTransformOrigin = origin; | |
| document.body.style.transform = transform; | |
| document.body.style.OTransform = transform; | |
| document.body.style.msTransform = transform; | |
| document.body.style.MozTransform = transform; | |
| document.body.style.WebkitTransform = transform; | |
| } | |
| else { | |
| // Reset all values | |
| if( scale === 1 ) { | |
| document.body.style.position = ''; | |
| document.body.style.left = ''; | |
| document.body.style.top = ''; | |
| document.body.style.width = ''; | |
| document.body.style.height = ''; | |
| document.body.style.zoom = ''; | |
| } | |
| // Apply scale | |
| else { | |
| document.body.style.position = 'relative'; | |
| document.body.style.left = ( - ( pageOffsetX + elementOffsetX ) / scale ) + 'px'; | |
| document.body.style.top = ( - ( pageOffsetY + elementOffsetY ) / scale ) + 'px'; | |
| document.body.style.width = ( scale * 100 ) + '%'; | |
| document.body.style.height = ( scale * 100 ) + '%'; | |
| document.body.style.zoom = scale; | |
| } | |
| } | |
| level = scale; | |
| } | |
| /** | |
| * Pan the document when the mosue cursor approaches the edges | |
| * of the window. | |
| */ | |
| function pan() { | |
| var range = 0.12, | |
| rangeX = window.innerWidth * range, | |
| rangeY = window.innerHeight * range, | |
| scrollOffset = getScrollOffset(); | |
| // Up | |
| if( mouseY < rangeY ) { | |
| window.scroll( scrollOffset.x, scrollOffset.y - ( 1 - ( mouseY / rangeY ) ) * ( 14 / level ) ); | |
| } | |
| // Down | |
| else if( mouseY > window.innerHeight - rangeY ) { | |
| window.scroll( scrollOffset.x, scrollOffset.y + ( 1 - ( window.innerHeight - mouseY ) / rangeY ) * ( 14 / level ) ); | |
| } | |
| // Left | |
| if( mouseX < rangeX ) { | |
| window.scroll( scrollOffset.x - ( 1 - ( mouseX / rangeX ) ) * ( 14 / level ), scrollOffset.y ); | |
| } | |
| // Right | |
| else if( mouseX > window.innerWidth - rangeX ) { | |
| window.scroll( scrollOffset.x + ( 1 - ( window.innerWidth - mouseX ) / rangeX ) * ( 14 / level ), scrollOffset.y ); | |
| } | |
| } | |
| function getScrollOffset() { | |
| return { | |
| x: window.scrollX !== undefined ? window.scrollX : window.pageXOffset, | |
| y: window.scrollY !== undefined ? window.scrollY : window.pageXYffset | |
| } | |
| } | |
| return { | |
| /** | |
| * Zooms in on either a rectangle or HTML element. | |
| * | |
| * @param {Object} options | |
| * - element: HTML element to zoom in on | |
| * OR | |
| * - x/y: coordinates in non-transformed space to zoom in on | |
| * - width/height: the portion of the screen to zoom in on | |
| * - scale: can be used instead of width/height to explicitly set scale | |
| */ | |
| to: function( options ) { | |
| // Due to an implementation limitation we can't zoom in | |
| // to another element without zooming out first | |
| if( level !== 1 ) { | |
| zoom.out(); | |
| } | |
| else { | |
| options.x = options.x || 0; | |
| options.y = options.y || 0; | |
| // If an element is set, that takes precedence | |
| if( !!options.element ) { | |
| // Space around the zoomed in element to leave on screen | |
| var padding = 20; | |
| options.width = options.element.getBoundingClientRect().width + ( padding * 2 ); | |
| options.height = options.element.getBoundingClientRect().height + ( padding * 2 ); | |
| options.x = options.element.getBoundingClientRect().left - padding; | |
| options.y = options.element.getBoundingClientRect().top - padding; | |
| } | |
| // If width/height values are set, calculate scale from those values | |
| if( options.width !== undefined && options.height !== undefined ) { | |
| options.scale = Math.max( Math.min( window.innerWidth / options.width, window.innerHeight / options.height ), 1 ); | |
| } | |
| if( options.scale > 1 ) { | |
| options.x *= options.scale; | |
| options.y *= options.scale; | |
| var scrollOffset = getScrollOffset(); | |
| magnify( scrollOffset.x, scrollOffset.y, options.x, options.y, options.scale ); | |
| if( options.pan !== false ) { | |
| // Wait with engaging panning as it may conflict with the | |
| // zoom transition | |
| panEngageTimeout = setTimeout( function() { | |
| panUpdateInterval = setInterval( pan, 1000 / 60 ); | |
| }, 800 ); | |
| } | |
| } | |
| } | |
| }, | |
| /** | |
| * Resets the document zoom state to its default. | |
| */ | |
| out: function() { | |
| clearTimeout( panEngageTimeout ); | |
| clearInterval( panUpdateInterval ); | |
| var scrollOffset = getScrollOffset(); | |
| magnify( scrollOffset.x, scrollOffset.y, 0, 0, 1 ); | |
| level = 1; | |
| }, | |
| // Alias | |
| magnify: function( options ) { this.to( options ) }, | |
| reset: function() { this.out() }, | |
| zoomLevel: function() { | |
| return level; | |
| } | |
| } | |
| })(); | |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment