Repository: tombigel/detect-zoom Branch: master Commit: b94c09c04855 Files: 5 Total size: 16.2 KB Directory structure: gitextract_6v6dismt/ ├── .gitignore ├── Makefile ├── README.md ├── detect-zoom.js └── package.json ================================================ FILE CONTENTS ================================================ ================================================ FILE: .gitignore ================================================ # Compiled Python files *.pyc # Folder view configuration files .DS_Store Desktop.ini # Thumbnail cache files ._* Thumbs.db # Files that might appear on external disks .Spotlight-V100 .Trashes # IntelliJ *.iml *.ipr *.iws .idea # npm node_modules ================================================ FILE: Makefile ================================================ UGLIFY=./node_modules/uglify-js/bin/uglifyjs detect-zoom.min.js: detect-zoom.js $(UGLIFY) detect-zoom.js -c > detect-zoom.min.js ================================================ FILE: README.md ================================================ Cross Browser Zoom and Pixel Ratio Detector ====== ------ ### READ THIS: Detect-zoom is currently unusable for desktop Last update: Aug 7 2013 **In the past few months both Mozilla and Google made some changes to their browsers that make it almost impossible to do what detect-zoom is here to do:** #### Firefox On *Firefox 18* Mozilla changes the `devicePixelRatio` value on manual zoom (cmd/ctrl +/-), making it impossible to know whether the browser is in zoom mode or is it a retina device, ignoring what the word DEVICE represents. I personally believe someone there refuses to admit this is a mistake and revert this decision. #### Chrome On *Chrome 27* (Meaning WebKit and Blink) `webkitTextSizeAdjust` was deprecated on desktops versions of the browser. This was the only bullet proof way to detect zoom in desktop chrome that I am aware of. There are couple of other ways, but they don't cover all the bases - one uses SVG but is not working in iFrames, the other uses window.inner/outerWidth and is not working when there is a sidebar or the DevTools are open on the side. ### Other Known issues: * In some multi-monitor enviroments where each monitor has a different 'pixel aspect ratio' windows that span accross both monitors might return false pixelAspectRatio values. What is this for? ------ Detecting the browser zoom level and device pixel ratio relative to the zoom level. It can be used to show higher-resolution `canvas` or `img` when necessary, to warn users that your site's layout will be broken in their current zoom level, and much more. Personally I'm maintaining it to use Detect-zoom in [Wix.com](http://wix.com)'s editor to warn users that their browser is in zoom mode before saving important changes to their website. What happend to @yonran? ------ Don't worry, he is well. As of January 2013 [@yonran](https://github.com/yonran) stopped maintaining his source of detect-zoom, and transferred the repository to me. If you are looking to update previous versions note that there were some breaking changes * **Major Changes from the latest yonran version:** * `DetectZoom` object name changed to `detectZoom` * `DetectZoom.ratio()` is no longer publicly accessible * Supported browsers: IE8+, FF4+, modern Webkit, mobile Webkit, Opera 11.1+ * *IE6, IE7, FF 3.6 and Opera 10.x are no longer supported* * Added support to be loaded as an AMD and CommonJS module Live Example ------ See the Live Example section in http://tombigel.github.com/detect-zoom/ Usage ------ **Detect-zoom has only two public functions:** * `zoom()` Returns the zoom level of the user's browser using Javascript. * `device()` Returns the device pixel ratio multiplied by the zoom level (Read [more about devicePixelRatio](http://www.quirksmode.org/blog/archives/2012/07/more_about_devi.html) at QuirksMode) ```html ``` **AMD Usage** ```javascript require(['detect-zoom'], function(detectZoom){ var zoom = detectZoom.zoom(); }); ``` **Installing with NPM** ```bash > npm install detect-zoom ``` Changelog ------ 2013/4/01 * Changed WebKit detection from deprecated webkitTextSizeAdjust to webkitMarquee * Changed WebKitMobile detection from unreliable 'ontouchstart' event (can be triggered on desktops too) to 'orientation' property that is hopefully more reliable * Minor version bump to 1.0.4 2013/3/29 * Added package.json (thanks [@TCampaigne](https://github.com/TCampaigne)) * Some documentation fixes * Added detect-zoom to npm package manager (again, thanks [@TCampaigne](https://github.com/TCampaigne)) 2013/2/25 * Fixed a missing 'else' between ie8 and ie10 detection * Minor version bump to 1.0.2 2013/2/15 * Added a fix for IE10 Metro (or whatever MS calls it these days..) by [@stefanvanburen](https://github.com/stefanvanburen) * Minor version bump to 1.0.1 * Added minimized version 2013/2/05 * Merged a pull request that fixed zoom on IE being returned X100 (thanks [@kreymerman](https://github.com/kreymerman)) * Refactored the code some more, changed some function names * Browser dependent main function is created only on initialization (thanks [@jsmaker](https://github.com/jsmaker)) * _Open Issue: Firefox returns `zoom` and `devicePixelRatio` the same. Still looking for a solution here._ * Started versioning - this is version 1.0.0 2013/1/27 * Added a fix to Mozilla's (Broken as I see it - https://bugzilla.mozilla.org/show_bug.cgi?id=809788) implementation of window.devicePixel starting Firefox 18 2013/1/26 * Repository moved here * Refactored most of the code * Removed support for older browsers * Added support for AMD and CommonJS Help Needed ------ ***Detect-zoom is not complete, many parts of the code are 6 to 12 months old and I'm still reviewing them I need help testing different browsers, finding better ways to measure zoom on problematic browsers (ahm.. Firefox.. ahm) patches are more than welcome.*** License ------ Detect-zoom is dual-licensed under the [WTFPL](http://www.wtfpl.net/about/) and [MIT](http://opensource.org/licenses/MIT) license, at the recipient's choice. ================================================ FILE: detect-zoom.js ================================================ /* Detect-zoom * ----------- * Cross Browser Zoom and Pixel Ratio Detector * Version 1.0.4 | Apr 1 2013 * dual-licensed under the WTFPL and MIT license * Maintained by https://github/tombigel * Original developer https://github.com/yonran */ //AMD and CommonJS initialization copied from https://github.com/zohararad/audio5js (function (root, ns, factory) { "use strict"; if (typeof (module) !== 'undefined' && module.exports) { // CommonJS module.exports = factory(ns, root); } else if (typeof (define) === 'function' && define.amd) { // AMD define("detect-zoom", function () { return factory(ns, root); }); } else { root[ns] = factory(ns, root); } }(window, 'detectZoom', function () { /** * Use devicePixelRatio if supported by the browser * @return {Number} * @private */ var devicePixelRatio = function () { return window.devicePixelRatio || 1; }; /** * Fallback function to set default values * @return {Object} * @private */ var fallback = function () { return { zoom: 1, devicePxPerCssPx: 1 }; }; /** * IE 8 and 9: no trick needed! * TODO: Test on IE10 and Windows 8 RT * @return {Object} * @private **/ var ie8 = function () { var zoom = Math.round((screen.deviceXDPI / screen.logicalXDPI) * 100) / 100; return { zoom: zoom, devicePxPerCssPx: zoom * devicePixelRatio() }; }; /** * For IE10 we need to change our technique again... * thanks https://github.com/stefanvanburen * @return {Object} * @private */ var ie10 = function () { var zoom = Math.round((document.documentElement.offsetHeight / window.innerHeight) * 100) / 100; return { zoom: zoom, devicePxPerCssPx: zoom * devicePixelRatio() }; }; /** * For chrome * */ var chrome = function() { var zoom = Math.round(((window.outerWidth) / window.innerWidth)*100) / 100; return { zoom: zoom, devicePxPerCssPx: zoom * devicePixelRatio() }; } /** * For safari (same as chrome) * */ var safari= function() { var zoom = Math.round(((document.documentElement.clientWidth) / window.innerWidth)*100) / 100; return { zoom: zoom, devicePxPerCssPx: zoom * devicePixelRatio() }; } /** * Mobile WebKit * the trick: window.innerWIdth is in CSS pixels, while * screen.width and screen.height are in system pixels. * And there are no scrollbars to mess up the measurement. * @return {Object} * @private */ var webkitMobile = function () { var deviceWidth = (Math.abs(window.orientation) == 90) ? screen.height : screen.width; var zoom = deviceWidth / window.innerWidth; return { zoom: zoom, devicePxPerCssPx: zoom * devicePixelRatio() }; }; /** * Desktop Webkit * the trick: an element's clientHeight is in CSS pixels, while you can * set its line-height in system pixels using font-size and * -webkit-text-size-adjust:none. * device-pixel-ratio: http://www.webkit.org/blog/55/high-dpi-web-sites/ * * Previous trick (used before http://trac.webkit.org/changeset/100847): * documentElement.scrollWidth is in CSS pixels, while * document.width was in system pixels. Note that this is the * layout width of the document, which is slightly different from viewport * because document width does not include scrollbars and might be wider * due to big elements. * @return {Object} * @private */ var webkit = function () { var important = function (str) { return str.replace(/;/g, " !important;"); }; var div = document.createElement('div'); div.innerHTML = "1
2
3
4
5
6
7
8
9
0"; div.setAttribute('style', important('font: 100px/1em sans-serif; -webkit-text-size-adjust: none; text-size-adjust: none; height: auto; width: 1em; padding: 0; overflow: visible;')); // The container exists so that the div will be laid out in its own flow // while not impacting the layout, viewport size, or display of the // webpage as a whole. // Add !important and relevant CSS rule resets // so that other rules cannot affect the results. var container = document.createElement('div'); container.setAttribute('style', important('width:0; height:0; overflow:hidden; visibility:hidden; position: absolute;')); container.appendChild(div); document.body.appendChild(container); var zoom = 1000 / div.clientHeight; zoom = Math.round(zoom * 100) / 100; document.body.removeChild(container); return{ zoom: zoom, devicePxPerCssPx: zoom * devicePixelRatio() }; }; /** * no real trick; device-pixel-ratio is the ratio of device dpi / css dpi. * (Note that this is a different interpretation than Webkit's device * pixel ratio, which is the ratio device dpi / system dpi). * * Also, for Mozilla, there is no difference between the zoom factor and the device ratio. * * @return {Object} * @private */ var firefox4 = function () { var zoom = mediaQueryBinarySearch('min--moz-device-pixel-ratio', '', 0, 10, 20, 0.0001); zoom = Math.round(zoom * 100) / 100; return { zoom: zoom, devicePxPerCssPx: zoom }; }; /** * Firefox 18.x * Mozilla added support for devicePixelRatio to Firefox 18, * but it is affected by the zoom level, so, like in older * Firefox we can't tell if we are in zoom mode or in a device * with a different pixel ratio * @return {Object} * @private */ var firefox18 = function () { return { zoom: firefox4().zoom, devicePxPerCssPx: devicePixelRatio() }; }; /** * works starting Opera 11.11 * the trick: outerWidth is the viewport width including scrollbars in * system px, while innerWidth is the viewport width including scrollbars * in CSS px * @return {Object} * @private */ var opera11 = function () { var zoom = window.top.outerWidth / window.top.innerWidth; zoom = Math.round(zoom * 100) / 100; return { zoom: zoom, devicePxPerCssPx: zoom * devicePixelRatio() }; }; /** * Use a binary search through media queries to find zoom level in Firefox * @param property * @param unit * @param a * @param b * @param maxIter * @param epsilon * @return {Number} */ var mediaQueryBinarySearch = function (property, unit, a, b, maxIter, epsilon) { var matchMedia; var head, style, div; if (window.matchMedia) { matchMedia = window.matchMedia; } else { head = document.getElementsByTagName('head')[0]; style = document.createElement('style'); head.appendChild(style); div = document.createElement('div'); div.className = 'mediaQueryBinarySearch'; div.style.display = 'none'; document.body.appendChild(div); matchMedia = function (query) { style.sheet.insertRule('@media ' + query + '{.mediaQueryBinarySearch ' + '{text-decoration: underline} }', 0); var matched = getComputedStyle(div, null).textDecoration == 'underline'; style.sheet.deleteRule(0); return {matches: matched}; }; } var ratio = binarySearch(a, b, maxIter); if (div) { head.removeChild(style); document.body.removeChild(div); } return ratio; function binarySearch(a, b, maxIter) { var mid = (a + b) / 2; if (maxIter <= 0 || b - a < epsilon) { return mid; } var query = "(" + property + ":" + mid + unit + ")"; if (matchMedia(query).matches) { return binarySearch(mid, b, maxIter - 1); } else { return binarySearch(a, mid, maxIter - 1); } } }; /** * Generate detection function * @private */ var detectFunction = (function () { var func = fallback; //IE8+ if (!isNaN(screen.logicalXDPI) && !isNaN(screen.systemXDPI)) { func = ie8; } // IE10+ / Touch else if (window.navigator.msMaxTouchPoints) { func = ie10; } //chrome else if(!!window.chrome && !(!!window.opera || navigator.userAgent.indexOf(' Opera') >= 0)){ func = chrome; } //safari else if(Object.prototype.toString.call(window.HTMLElement).indexOf('Constructor') > 0){ func = safari; } //Mobile Webkit else if ('orientation' in window && 'webkitRequestAnimationFrame' in window) { func = webkitMobile; } //WebKit else if ('webkitRequestAnimationFrame' in window) { func = webkit; } //Opera else if (navigator.userAgent.indexOf('Opera') >= 0) { func = opera11; } //Last one is Firefox //FF 18.x else if (window.devicePixelRatio) { func = firefox18; } //FF 4.0 - 17.x else if (firefox4().zoom > 0.001) { func = firefox4; } return func; }()); return ({ /** * Ratios.zoom shorthand * @return {Number} Zoom level */ zoom: function () { return detectFunction().zoom; }, /** * Ratios.devicePxPerCssPx shorthand * @return {Number} devicePxPerCssPx level */ device: function () { return detectFunction().devicePxPerCssPx; } }); })); ================================================ FILE: package.json ================================================ { "name": "detect-zoom", "version": "1.0.4", "description": "Cross Browser Zoom and Pixel Ratio Detector", "main": "detect-zoom.js", "scripts": { "test": "echo \"Error: no test specified\" && exit 1" }, "repository": { "type": "git", "url": "git://github.com/tombigel/detect-zoom.git" }, "keywords": [ "browser", "zoom", "compatibility", "pixel", "ratio", "retina" ], "author": "Yonathan Randolph", "contributors": [ "Tom Bigelajzen " ], "license": "MIT", "readmeFilename": "README.md", "gitHead": "6eaf3107a6913a4f7b93665ba6d5bc16cdf0f3ab", "devDependencies": { "uglify-js": "~3.6.6" } }