├── .travis.yml ├── dist ├── .gitignore ├── hidpi-canvas.min.js └── hidpi-canvas.js ├── .gitignore ├── .gitmodules ├── test ├── HTMLCanvasElement.html ├── CanvasRenderingContext2D.html ├── HTMLCanvasElementTests.js └── CanvasRenderingContext2DTests.js ├── LICENSE.txt ├── bower.json ├── CHANGELOG ├── src ├── HTMLCanvasElement.js └── CanvasRenderingContext2D.js ├── package.json ├── CONTRIBUTING.md ├── index.html ├── Gruntfile.js └── README.md /.travis.yml: -------------------------------------------------------------------------------- 1 | language: node_js 2 | -------------------------------------------------------------------------------- /dist/.gitignore: -------------------------------------------------------------------------------- 1 | *.zip 2 | *.gz 3 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | /node_modules 2 | npm-debug.log -------------------------------------------------------------------------------- /.gitmodules: -------------------------------------------------------------------------------- 1 | [submodule "test/qunit"] 2 | path = test/qunit 3 | url = https://github.com/jquery/qunit.git 4 | -------------------------------------------------------------------------------- /test/HTMLCanvasElement.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | HTMLCanvasElement Tests 6 | 7 | 8 | 9 |
10 |
11 | 12 |
13 | 14 | 15 | 16 | 17 | 18 | -------------------------------------------------------------------------------- /test/CanvasRenderingContext2D.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CanvasRenderingContext2D Tests 6 | 7 | 8 | 9 |
10 |
11 | 12 |
13 | 14 | 15 | 16 | 17 | 18 | -------------------------------------------------------------------------------- /test/HTMLCanvasElementTests.js: -------------------------------------------------------------------------------- 1 | module('HTMLCanvasElement Tests', { 2 | setup: function() { 3 | window.devicePixelRatio = 2; 4 | } 5 | }); 6 | 7 | test('canvas dimensions scale to device pixel ratio', function() { 8 | var canvas = document.getElementById('test_canvas'), 9 | context; 10 | 11 | canvas.height = 100; 12 | canvas.width = 200; 13 | 14 | context = canvas.getContext('2d'); 15 | 16 | equal(canvas.height, 200); 17 | equal(canvas.width, 400); 18 | 19 | equal(canvas.style.height, '100px'); 20 | equal(canvas.style.width, '200px'); 21 | }); 22 | -------------------------------------------------------------------------------- /LICENSE.txt: -------------------------------------------------------------------------------- 1 | Copyright 2013 Jonathan D. Johnson 2 | 3 | Licensed under the Apache License, Version 2.0 (the "License"); 4 | you may not use this file except in compliance with the License. 5 | You may obtain a copy of the License at 6 | 7 | http://www.apache.org/licenses/LICENSE-2.0 8 | 9 | Unless required by applicable law or agreed to in writing, software 10 | distributed under the License is distributed on an "AS IS" BASIS, 11 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | See the License for the specific language governing permissions and 13 | limitations under the License. 14 | -------------------------------------------------------------------------------- /bower.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "hidpi-canvas", 3 | "version": "1.0.10", 4 | "homepage": "https://github.com/jondavidjohn/hidpi-canvas-polyfill", 5 | "authors": [ 6 | "Jonathan Johnson " 7 | ], 8 | "description": "A JavaScript drop-in module to polyfill consistent and automatic HiDPI Canvas support.", 9 | "keywords": [ 10 | "canvas", 11 | "retina", 12 | "hidpi", 13 | "polyfill" 14 | ], 15 | "main": "dist/hidpi-canvas.js", 16 | "license": "Apache-2.0", 17 | "ignore": [ 18 | "**/.*", 19 | "node_modules", 20 | "bower_components", 21 | "src", 22 | "test", 23 | "tests" 24 | ] 25 | } 26 | -------------------------------------------------------------------------------- /CHANGELOG: -------------------------------------------------------------------------------- 1 | = 1.0.10 2 | * Fixed iOS 10 API deprication (#17) 3 | * Add Travis CI 4 | * Include minified build in release 5 | 6 | = 1.0.9 7 | * True fix for issue with lineWidth handling in stroke (#14) 8 | 9 | = 1.0.8 (broken) 10 | * Fix issue with lineWidth handling in stroke (#14) 11 | 12 | = 1.0.7 13 | * Better fix for pixel ratio being 1 14 | 15 | = 1.0.6 16 | * Performance improvement, early bail if pixel ratio is 1 (#13) 17 | 18 | = 1.0.5 19 | * Correct bower file with "main" entry 20 | * Add `createLinearGradient` support 21 | 22 | = 1.0.3 23 | * Add bower support 24 | * Add built distribution files to the repository 25 | 26 | = 1.0.2 27 | * Fix bug with font scaling with multiple text calls (Issue #4) 28 | * Add a few tests 29 | 30 | = 1.0.1 31 | * Fixed Bug detecting the webkit backingStore 32 | * General code cleanup 33 | 34 | = 1.0.0 35 | * Initial Release 36 | -------------------------------------------------------------------------------- /src/HTMLCanvasElement.js: -------------------------------------------------------------------------------- 1 | (function(prototype) { 2 | prototype.getContext = (function(_super) { 3 | return function(type) { 4 | var backingStore, ratio, 5 | context = _super.call(this, type); 6 | 7 | if (type === '2d') { 8 | 9 | backingStore = context.backingStorePixelRatio || 10 | context.webkitBackingStorePixelRatio || 11 | context.mozBackingStorePixelRatio || 12 | context.msBackingStorePixelRatio || 13 | context.oBackingStorePixelRatio || 14 | context.backingStorePixelRatio || 1; 15 | 16 | ratio = (window.devicePixelRatio || 1) / backingStore; 17 | 18 | if (ratio > 1) { 19 | this.style.height = this.height + 'px'; 20 | this.style.width = this.width + 'px'; 21 | this.width *= ratio; 22 | this.height *= ratio; 23 | } 24 | } 25 | 26 | return context; 27 | }; 28 | })(prototype.getContext); 29 | })(HTMLCanvasElement.prototype); 30 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "hidpi-canvas", 3 | "description": "A JavaScript drop-in module to polyfill consistent and automatic HiDPI Canvas support.", 4 | "version": "1.0.10", 5 | "license": "Apache-2.0", 6 | "homepage": "https://github.com/jondavidjohn/hidpi-canvas-polyfill", 7 | "bugs": "https://github.com/jondavidjohn/hidpi-canvas-polyfill/issues", 8 | "repository": { 9 | "type": "git", 10 | "url": "git@github.com:jondavidjohn/hidpi-canvas-polyfill.git" 11 | }, 12 | "author": "Jonathan D. Johnson (http://jondavidjohn.com)", 13 | "devDependencies": { 14 | "grunt": "0.4.1", 15 | "grunt-cli": "0.1.9", 16 | "grunt-contrib-concat": "0.3.0", 17 | "grunt-contrib-clean": "0.5.0", 18 | "grunt-contrib-compress": "0.5.2", 19 | "grunt-contrib-uglify": "0.2.4", 20 | "grunt-contrib-watch": "0.5.3", 21 | "grunt-contrib-qunit": "0.2.2", 22 | "qunit-assert-canvas": "1.0.1" 23 | }, 24 | "scripts": { 25 | "test": "grunt", 26 | "watch": "grunt watch", 27 | "build": "grunt dist", 28 | "prepublish": "npm run build" 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /test/CanvasRenderingContext2DTests.js: -------------------------------------------------------------------------------- 1 | module('CanvasRenderingContext2D Tests', { 2 | setup: function() { 3 | window.devicePixelRatio = 2; 4 | } 5 | }); 6 | 7 | test('the font size remains unchanged after every text call', function() { 8 | var font_value = '12px Helvetica', 9 | canvas = document.getElementById('test_canvas'), 10 | context = canvas.getContext('2d'); 11 | 12 | context.font = font_value; 13 | 14 | context.fillText("Some Text",10,300); 15 | equal(context.font, font_value); 16 | 17 | context.fillText("Some More Text",10,450); 18 | equal(context.font, font_value); 19 | }); 20 | 21 | test('the lineWidth property remains unchanged after every stroke call', function() { 22 | var line_width_value = 12, 23 | canvas = document.getElementById('test_canvas'), 24 | context = canvas.getContext('2d'); 25 | 26 | context.lineWidth = line_width_value; 27 | 28 | context.moveTo(250,150); 29 | context.arcTo(350,50,350,100,50); 30 | context.stroke(); 31 | equal(context.lineWidth, line_width_value); 32 | 33 | context.moveTo(10,15); 34 | context.arcTo(30,50,30,10,50); 35 | context.stroke(); 36 | equal(context.lineWidth, line_width_value); 37 | }); 38 | -------------------------------------------------------------------------------- /CONTRIBUTING.md: -------------------------------------------------------------------------------- 1 | # How to Contribute 2 | 3 | Yay, you're interested in helping this thing suck less. Good for you! 4 | 5 | Some things you should be familiar with before getting started 6 | 7 | - Unit testing (with [QUnit](http://qunitjs.com)) 8 | - [Grunt](http://gruntjs.org) 9 | - [Node/NPM](https://npmjs.org/) (available via homebrew) 10 | 11 | ## Project Layout 12 | 13 | - `src/` - Coffeescript Source files 14 | - `dist/` - Compiled, Concatinated, and Minified 15 | - `test/` - Unit Testing Resources 16 | 17 | 18 | ## Development 19 | 20 | Once you have npm installed, clone the repository (with `--recursive` to also clone all submodules) and install all dependencies 21 | 22 | git clone git@.....hidpi-canvas-polyfill.git --recursive 23 | cd hidpi-canvas-polyfill 24 | npm install 25 | 26 | Then to build a distribution run 27 | 28 | npm run build 29 | 30 | This will generate the compiled (and minified) sourc in your `dist/` directory 31 | along with a distributable zip archive. 32 | 33 | Any time you change any of the `src/**/*.js` files you'll 34 | need to re-run this command. 35 | 36 | You can also use 37 | 38 | npm run watch 39 | 40 | to automatically reconcat the unminified file everytime you 41 | change any of the `src/**/*.js` files. 42 | 43 | ## Testing 44 | 45 | ### Writing Tests 46 | 47 | The `test/` directory mirrors the `src/` directory for test organization, make 48 | sure to organize and produce tests that fit the patterns present. 49 | 50 | ### Running Tests 51 | 52 | npm test 53 | 54 | ## On Contribution 55 | 56 | ### Be a Chameleon 57 | 58 | Try your best to follow the present code formatting and patterns in place. 59 | 60 | ### Pull Requests 61 | 62 | **Make sure to send pull requests to develop.** 63 | 64 | Good Pull Requests include: 65 | 66 | - A clear explaination of the problem (or enhancement) 67 | - Clean commit history (squash where it makes sense) 68 | - Relevant Tests (either updated and/or new) 69 | 70 | # TODO 71 | 72 | A few things it currently lacks that I'd like to see improved 73 | 74 | - More complete canvas context method coverage. 75 | - Figure out how to test this stuff. 76 | -------------------------------------------------------------------------------- /dist/hidpi-canvas.min.js: -------------------------------------------------------------------------------- 1 | /** 2 | * HiDPI Canvas Polyfill (1.0.10) 3 | * 4 | * Author: Jonathan D. Johnson (http://jondavidjohn.com) 5 | * Homepage: https://github.com/jondavidjohn/hidpi-canvas-polyfill 6 | * Issue Tracker: https://github.com/jondavidjohn/hidpi-canvas-polyfill/issues 7 | * License: Apache-2.0 8 | */ 9 | !function(a){var b=function(){var a=document.createElement("canvas"),b=a.getContext("2d"),c=b.backingStorePixelRatio||b.webkitBackingStorePixelRatio||b.mozBackingStorePixelRatio||b.msBackingStorePixelRatio||b.oBackingStorePixelRatio||b.backingStorePixelRatio||1;return(window.devicePixelRatio||1)/c}(),c=function(a,b){for(var c in a)a.hasOwnProperty(c)&&b(a[c],c)},d={fillRect:"all",clearRect:"all",strokeRect:"all",moveTo:"all",lineTo:"all",arc:[0,1,2],arcTo:"all",bezierCurveTo:"all",isPointinPath:"all",isPointinStroke:"all",quadraticCurveTo:"all",rect:"all",translate:"all",createRadialGradient:"all",createLinearGradient:"all"};1!==b&&(c(d,function(c,d){a[d]=function(a){return function(){var d,e,f=Array.prototype.slice.call(arguments);if("all"===c)f=f.map(function(a){return a*b});else if(Array.isArray(c))for(d=0,e=c.length;e>d;d++)f[c[d]]*=b;return a.apply(this,f)}}(a[d])}),a.stroke=function(a){return function(){this.lineWidth*=b,a.apply(this,arguments),this.lineWidth/=b}}(a.stroke),a.fillText=function(a){return function(){var c=Array.prototype.slice.call(arguments);c[1]*=b,c[2]*=b,this.font=this.font.replace(/(\d+)(px|em|rem|pt)/g,function(a,c,d){return c*b+d}),a.apply(this,c),this.font=this.font.replace(/(\d+)(px|em|rem|pt)/g,function(a,c,d){return c/b+d})}}(a.fillText),a.strokeText=function(a){return function(){var c=Array.prototype.slice.call(arguments);c[1]*=b,c[2]*=b,this.font=this.font.replace(/(\d+)(px|em|rem|pt)/g,function(a,c,d){return c*b+d}),a.apply(this,c),this.font=this.font.replace(/(\d+)(px|em|rem|pt)/g,function(a,c,d){return c/b+d})}}(a.strokeText))}(CanvasRenderingContext2D.prototype),function(a){a.getContext=function(a){return function(b){var c,d,e=a.call(this,b);return"2d"===b&&(c=e.backingStorePixelRatio||e.webkitBackingStorePixelRatio||e.mozBackingStorePixelRatio||e.msBackingStorePixelRatio||e.oBackingStorePixelRatio||e.backingStorePixelRatio||1,d=(window.devicePixelRatio||1)/c,d>1&&(this.style.height=this.height+"px",this.style.width=this.width+"px",this.width*=d,this.height*=d)),e}}(a.getContext)}(HTMLCanvasElement.prototype); -------------------------------------------------------------------------------- /index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | HiDPI Canvas Example 6 | 11 | 12 | 13 | 14 | 15 | 83 | 84 | -------------------------------------------------------------------------------- /Gruntfile.js: -------------------------------------------------------------------------------- 1 | module.exports = function (grunt) { 2 | grunt.initConfig({ 3 | pkg: grunt.file.readJSON('package.json'), 4 | 5 | clean: [ 6 | 'lib/**/*', 7 | 'dist/**/*', 8 | '!lib/.gitignore', 9 | '!dist/.gitignore', 10 | ], 11 | 12 | concat: { 13 | options: { 14 | banner: '/**\n' 15 | + ' * HiDPI Canvas Polyfill (<%= pkg.version %>)\n' 16 | + ' *\n' 17 | + ' * Author: <%= pkg.author %>\n' 18 | + ' * Homepage: <%= pkg.homepage %>\n' 19 | + ' * Issue Tracker: <%= pkg.bugs %>\n' 20 | + ' * License: <%= pkg.license %>\n' 21 | + '*/\n', 22 | separator: ';' 23 | }, 24 | dist: { 25 | src: ['src/**/*.js'], 26 | dest: 'dist/hidpi-canvas.js' 27 | } 28 | }, 29 | 30 | uglify: { 31 | options: { 32 | banner: '<%= concat.options.banner %>' 33 | }, 34 | dist: { 35 | files: { 36 | 'dist/hidpi-canvas.min.js': ['<%= concat.dist.dest %>'] 37 | } 38 | } 39 | }, 40 | 41 | compress: { 42 | main:{ 43 | options: { 44 | mode: 'gzip' 45 | }, 46 | expand: true, 47 | cwd: 'dist', 48 | src: ['*.js'], 49 | dest: 'dist/' 50 | }, 51 | dist: { 52 | options: { 53 | archive: 'dist/hidpi-canvas-<%= pkg.version %>.zip', 54 | level: 9 55 | }, 56 | files: [ 57 | { 58 | src: [ 59 | 'LICENSE.txt', 60 | 'README.md', 61 | 'CHANGELOG' 62 | ] 63 | }, 64 | { 65 | expand: true, 66 | cwd: 'dist/', 67 | src: [ 68 | '*.js', 69 | '*.js.gz' 70 | ] 71 | } 72 | ] 73 | }, 74 | }, 75 | 76 | qunit: { 77 | files: [ 78 | 'test/CanvasRenderingContext2D.html', 79 | 'test/HTMLCanvasElement.html' 80 | ] 81 | }, 82 | 83 | watch: { 84 | files: ['<%= concat.dist.src %>'], 85 | tasks: ['clean', 'concat:dist'] 86 | } 87 | }); 88 | 89 | // Load Package Tasks 90 | grunt.loadNpmTasks('grunt-contrib-clean'); 91 | grunt.loadNpmTasks('grunt-contrib-concat'); 92 | grunt.loadNpmTasks('grunt-contrib-uglify'); 93 | grunt.loadNpmTasks('grunt-contrib-compress'); 94 | grunt.loadNpmTasks('grunt-contrib-qunit'); 95 | grunt.loadNpmTasks('grunt-contrib-watch'); 96 | 97 | // Define Custom Tasks 98 | grunt.registerTask('test', ['qunit']); 99 | grunt.registerTask('default', ['clean', 'concat:dist', 'test']); 100 | grunt.registerTask('dist', ['default', 'uglify:dist', 'compress', 'compress:dist']); 101 | }; 102 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | --- 2 |

3 |

Do you use webpack?

4 |

5 |

6 | Wish your team made reducing the size of your webpack builds a priority? Want to know how the changes you're making impact your asset profile for every pull request? 7 |

8 |

9 | Check it out at packtracker.io. 10 |

11 | 12 | --- 13 | 14 | # HiDPI Canvas Polyfill 15 | 16 | [![Build Status](https://travis-ci.org/jondavidjohn/hidpi-canvas-polyfill.svg?branch=master)](https://travis-ci.org/jondavidjohn/hidpi-canvas-polyfill) 17 | 18 | This is a drop-in polyfill to scale canvas appropriately to maintain sharpness 19 | in browsers that currently do not provide the appropriately scaled backing 20 | store to do this automatically. 21 | 22 | As of this writing Safari is the only browser that accounts for this. 23 | 24 | The goal of this drop-in is to make this behavior consistent accross all browsers, 25 | without having to modify any of your canvas code. 26 | 27 | ## Scope 28 | 29 | Currently this plugin handles most general cross browser drawing functions, but 30 | feel free to send Pull Requests as you find functions you need supported. 31 | 32 | If the function simply needs all or some of its arguments multiplied by the ratio, 33 | it should simply require you to add it to the `ratioArgs` object, following the proper 34 | pattern. 35 | 36 | It currently leaves images alone, so to retinize images on your canvas, simply 37 | duplicate the getPixelRatio function in your code and divide your image dimensions 38 | by the provided ratio. 39 | 40 | ```js 41 | var getPixelRatio = function(context) { 42 | var backingStore = context.backingStorePixelRatio || 43 | context.webkitBackingStorePixelRatio || 44 | context.mozBackingStorePixelRatio || 45 | context.msBackingStorePixelRatio || 46 | context.oBackingStorePixelRatio || 47 | context.backingStorePixelRatio || 1; 48 | 49 | return (window.devicePixelRatio || 1) / backingStore; 50 | }; 51 | ``` 52 | 53 | ## Usage 54 | 55 | To use this module, simply include it before any of your canvas code 56 | 57 | ```html 58 | ... 59 | 60 | 61 | ... 62 | ``` 63 | 64 | ### Bower 65 | 66 | This module is also installable via [bower](http://bower.io/) 67 | 68 | bower install hidpi-canvas 69 | 70 | ## TODO 71 | 72 | - More Complete context function coverage 73 | - Figure out how to write tests for this type of thing 74 | 75 | ## Development 76 | 77 | See [CONTRIBUTING.md](https://github.com/jondavidjohn/hidpi-canvas-polyfill/blob/develop/CONTRIBUTING.md) 78 | 79 | -------------------------------------------------------------------------------- /src/CanvasRenderingContext2D.js: -------------------------------------------------------------------------------- 1 | (function(prototype) { 2 | 3 | var pixelRatio = (function() { 4 | var canvas = document.createElement('canvas'), 5 | context = canvas.getContext('2d'), 6 | backingStore = context.backingStorePixelRatio || 7 | context.webkitBackingStorePixelRatio || 8 | context.mozBackingStorePixelRatio || 9 | context.msBackingStorePixelRatio || 10 | context.oBackingStorePixelRatio || 11 | context.backingStorePixelRatio || 1; 12 | 13 | return (window.devicePixelRatio || 1) / backingStore; 14 | })(), 15 | 16 | forEach = function(obj, func) { 17 | for (var p in obj) { 18 | if (obj.hasOwnProperty(p)) { 19 | func(obj[p], p); 20 | } 21 | } 22 | }, 23 | 24 | ratioArgs = { 25 | 'fillRect': 'all', 26 | 'clearRect': 'all', 27 | 'strokeRect': 'all', 28 | 'moveTo': 'all', 29 | 'lineTo': 'all', 30 | 'arc': [0,1,2], 31 | 'arcTo': 'all', 32 | 'bezierCurveTo': 'all', 33 | 'isPointinPath': 'all', 34 | 'isPointinStroke': 'all', 35 | 'quadraticCurveTo': 'all', 36 | 'rect': 'all', 37 | 'translate': 'all', 38 | 'createRadialGradient': 'all', 39 | 'createLinearGradient': 'all' 40 | }; 41 | 42 | if (pixelRatio === 1) return; 43 | 44 | forEach(ratioArgs, function(value, key) { 45 | prototype[key] = (function(_super) { 46 | return function() { 47 | var i, len, 48 | args = Array.prototype.slice.call(arguments); 49 | 50 | if (value === 'all') { 51 | args = args.map(function(a) { 52 | return a * pixelRatio; 53 | }); 54 | } 55 | else if (Array.isArray(value)) { 56 | for (i = 0, len = value.length; i < len; i++) { 57 | args[value[i]] *= pixelRatio; 58 | } 59 | } 60 | 61 | return _super.apply(this, args); 62 | }; 63 | })(prototype[key]); 64 | }); 65 | 66 | // Stroke lineWidth adjustment 67 | prototype.stroke = (function(_super) { 68 | return function() { 69 | this.lineWidth *= pixelRatio; 70 | _super.apply(this, arguments); 71 | this.lineWidth /= pixelRatio; 72 | }; 73 | })(prototype.stroke); 74 | 75 | // Text 76 | // 77 | prototype.fillText = (function(_super) { 78 | return function() { 79 | var args = Array.prototype.slice.call(arguments); 80 | 81 | args[1] *= pixelRatio; // x 82 | args[2] *= pixelRatio; // y 83 | 84 | this.font = this.font.replace( 85 | /(\d+)(px|em|rem|pt)/g, 86 | function(w, m, u) { 87 | return (m * pixelRatio) + u; 88 | } 89 | ); 90 | 91 | _super.apply(this, args); 92 | 93 | this.font = this.font.replace( 94 | /(\d+)(px|em|rem|pt)/g, 95 | function(w, m, u) { 96 | return (m / pixelRatio) + u; 97 | } 98 | ); 99 | }; 100 | })(prototype.fillText); 101 | 102 | prototype.strokeText = (function(_super) { 103 | return function() { 104 | var args = Array.prototype.slice.call(arguments); 105 | 106 | args[1] *= pixelRatio; // x 107 | args[2] *= pixelRatio; // y 108 | 109 | this.font = this.font.replace( 110 | /(\d+)(px|em|rem|pt)/g, 111 | function(w, m, u) { 112 | return (m * pixelRatio) + u; 113 | } 114 | ); 115 | 116 | _super.apply(this, args); 117 | 118 | this.font = this.font.replace( 119 | /(\d+)(px|em|rem|pt)/g, 120 | function(w, m, u) { 121 | return (m / pixelRatio) + u; 122 | } 123 | ); 124 | }; 125 | })(prototype.strokeText); 126 | })(CanvasRenderingContext2D.prototype); 127 | -------------------------------------------------------------------------------- /dist/hidpi-canvas.js: -------------------------------------------------------------------------------- 1 | /** 2 | * HiDPI Canvas Polyfill (1.0.10) 3 | * 4 | * Author: Jonathan D. Johnson (http://jondavidjohn.com) 5 | * Homepage: https://github.com/jondavidjohn/hidpi-canvas-polyfill 6 | * Issue Tracker: https://github.com/jondavidjohn/hidpi-canvas-polyfill/issues 7 | * License: Apache-2.0 8 | */ 9 | (function(prototype) { 10 | 11 | var pixelRatio = (function() { 12 | var canvas = document.createElement('canvas'), 13 | context = canvas.getContext('2d'), 14 | backingStore = context.backingStorePixelRatio || 15 | context.webkitBackingStorePixelRatio || 16 | context.mozBackingStorePixelRatio || 17 | context.msBackingStorePixelRatio || 18 | context.oBackingStorePixelRatio || 19 | context.backingStorePixelRatio || 1; 20 | 21 | return (window.devicePixelRatio || 1) / backingStore; 22 | })(), 23 | 24 | forEach = function(obj, func) { 25 | for (var p in obj) { 26 | if (obj.hasOwnProperty(p)) { 27 | func(obj[p], p); 28 | } 29 | } 30 | }, 31 | 32 | ratioArgs = { 33 | 'fillRect': 'all', 34 | 'clearRect': 'all', 35 | 'strokeRect': 'all', 36 | 'moveTo': 'all', 37 | 'lineTo': 'all', 38 | 'arc': [0,1,2], 39 | 'arcTo': 'all', 40 | 'bezierCurveTo': 'all', 41 | 'isPointinPath': 'all', 42 | 'isPointinStroke': 'all', 43 | 'quadraticCurveTo': 'all', 44 | 'rect': 'all', 45 | 'translate': 'all', 46 | 'createRadialGradient': 'all', 47 | 'createLinearGradient': 'all' 48 | }; 49 | 50 | if (pixelRatio === 1) return; 51 | 52 | forEach(ratioArgs, function(value, key) { 53 | prototype[key] = (function(_super) { 54 | return function() { 55 | var i, len, 56 | args = Array.prototype.slice.call(arguments); 57 | 58 | if (value === 'all') { 59 | args = args.map(function(a) { 60 | return a * pixelRatio; 61 | }); 62 | } 63 | else if (Array.isArray(value)) { 64 | for (i = 0, len = value.length; i < len; i++) { 65 | args[value[i]] *= pixelRatio; 66 | } 67 | } 68 | 69 | return _super.apply(this, args); 70 | }; 71 | })(prototype[key]); 72 | }); 73 | 74 | // Stroke lineWidth adjustment 75 | prototype.stroke = (function(_super) { 76 | return function() { 77 | this.lineWidth *= pixelRatio; 78 | _super.apply(this, arguments); 79 | this.lineWidth /= pixelRatio; 80 | }; 81 | })(prototype.stroke); 82 | 83 | // Text 84 | // 85 | prototype.fillText = (function(_super) { 86 | return function() { 87 | var args = Array.prototype.slice.call(arguments); 88 | 89 | args[1] *= pixelRatio; // x 90 | args[2] *= pixelRatio; // y 91 | 92 | this.font = this.font.replace( 93 | /(\d+)(px|em|rem|pt)/g, 94 | function(w, m, u) { 95 | return (m * pixelRatio) + u; 96 | } 97 | ); 98 | 99 | _super.apply(this, args); 100 | 101 | this.font = this.font.replace( 102 | /(\d+)(px|em|rem|pt)/g, 103 | function(w, m, u) { 104 | return (m / pixelRatio) + u; 105 | } 106 | ); 107 | }; 108 | })(prototype.fillText); 109 | 110 | prototype.strokeText = (function(_super) { 111 | return function() { 112 | var args = Array.prototype.slice.call(arguments); 113 | 114 | args[1] *= pixelRatio; // x 115 | args[2] *= pixelRatio; // y 116 | 117 | this.font = this.font.replace( 118 | /(\d+)(px|em|rem|pt)/g, 119 | function(w, m, u) { 120 | return (m * pixelRatio) + u; 121 | } 122 | ); 123 | 124 | _super.apply(this, args); 125 | 126 | this.font = this.font.replace( 127 | /(\d+)(px|em|rem|pt)/g, 128 | function(w, m, u) { 129 | return (m / pixelRatio) + u; 130 | } 131 | ); 132 | }; 133 | })(prototype.strokeText); 134 | })(CanvasRenderingContext2D.prototype); 135 | ;(function(prototype) { 136 | prototype.getContext = (function(_super) { 137 | return function(type) { 138 | var backingStore, ratio, 139 | context = _super.call(this, type); 140 | 141 | if (type === '2d') { 142 | 143 | backingStore = context.backingStorePixelRatio || 144 | context.webkitBackingStorePixelRatio || 145 | context.mozBackingStorePixelRatio || 146 | context.msBackingStorePixelRatio || 147 | context.oBackingStorePixelRatio || 148 | context.backingStorePixelRatio || 1; 149 | 150 | ratio = (window.devicePixelRatio || 1) / backingStore; 151 | 152 | if (ratio > 1) { 153 | this.style.height = this.height + 'px'; 154 | this.style.width = this.width + 'px'; 155 | this.width *= ratio; 156 | this.height *= ratio; 157 | } 158 | } 159 | 160 | return context; 161 | }; 162 | })(prototype.getContext); 163 | })(HTMLCanvasElement.prototype); 164 | --------------------------------------------------------------------------------