├── .gitignore ├── .npmignore ├── LICENSE.md ├── package.json ├── test.js ├── README.md └── convert-length.js /.gitignore: -------------------------------------------------------------------------------- 1 | bower_components 2 | node_modules 3 | *.log 4 | .DS_Store 5 | bundle.js 6 | -------------------------------------------------------------------------------- /.npmignore: -------------------------------------------------------------------------------- 1 | bower_components 2 | node_modules 3 | *.log 4 | .DS_Store 5 | bundle.js 6 | test 7 | test.js 8 | demo/ 9 | .npmignore 10 | LICENSE.md -------------------------------------------------------------------------------- /LICENSE.md: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | Copyright (c) 2017 Matt DesLauriers 3 | 4 | Permission is hereby granted, free of charge, to any person obtaining a copy 5 | of this software and associated documentation files (the "Software"), to deal 6 | in the Software without restriction, including without limitation the rights 7 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 8 | copies of the Software, and to permit persons to whom the Software is 9 | furnished to do so, subject to the following conditions: 10 | 11 | The above copyright notice and this permission notice shall be included in all 12 | copies or substantial portions of the Software. 13 | 14 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 15 | EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 16 | MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. 17 | IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, 18 | DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR 19 | OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE 20 | OR OTHER DEALINGS IN THE SOFTWARE. 21 | 22 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "convert-length", 3 | "version": "1.0.1", 4 | "description": "Converts a distance unit (e.g. m) to another (e.g. cm)", 5 | "main": "./convert-length.js", 6 | "license": "MIT", 7 | "author": { 8 | "name": "Matt DesLauriers", 9 | "email": "dave.des@gmail.com", 10 | "url": "https://github.com/mattdesl" 11 | }, 12 | "dependencies": { 13 | "defined": "^1.0.0" 14 | }, 15 | "devDependencies": { 16 | "tape": "^4.9.1" 17 | }, 18 | "scripts": { 19 | "test": "node test.js" 20 | }, 21 | "keywords": [ 22 | "distance", 23 | "length", 24 | "px", 25 | "conversion", 26 | "convert", 27 | "converts", 28 | "from", 29 | "to", 30 | "unit", 31 | "units", 32 | "m", 33 | "cm", 34 | "mm", 35 | "meter", 36 | "meters", 37 | "inches", 38 | "in", 39 | "centimeter", 40 | "millimetre", 41 | "centimetre", 42 | "metre", 43 | "metres", 44 | "inch", 45 | "millimeter" 46 | ], 47 | "repository": { 48 | "type": "git", 49 | "url": "git://github.com/mattdesl/convert-length.git" 50 | }, 51 | "homepage": "https://github.com/mattdesl/convert-length", 52 | "bugs": { 53 | "url": "https://github.com/mattdesl/convert-length/issues" 54 | } 55 | } 56 | -------------------------------------------------------------------------------- /test.js: -------------------------------------------------------------------------------- 1 | const tape = require('tape'); 2 | const convert = require('./'); 3 | 4 | const convertWithPrecision = (a, b, c, precision = 4, opt = {}) => { 5 | return convert(a, b, c, Object.assign({}, opt, { precision })); 6 | }; 7 | 8 | tape('test px to physical', t => { 9 | t.equal(convert(1, 'in', 'px'), 96); 10 | t.equal(convert(1, 'px', 'in'), 1 / 96); 11 | t.equal(convert(4, 'in', 'px'), 384); 12 | t.equal(convert(1, 'in', 'px', { pixelsPerInch: 72 }), 72); 13 | t.equal(convert(6, 'cm', 'px'), 227); 14 | t.equal(convert(10, 'mm', 'px'), 38); 15 | t.equal(convert(10, 'mm', 'px', { pixelsPerInch: 72 }), 28); 16 | t.equal(convert(10, 'px', 'mm', { precision: 2 }), 2.65); 17 | t.equal(convert(11, 'px', 'in', { precision: 3 }), 0.115); 18 | t.end(); 19 | }); 20 | 21 | tape('test basic conversion functions', t => { 22 | t.equal(convert(1, 'm', 'm'), 1); 23 | t.equal(convert(1, 'cm', 'm'), 0.01); 24 | t.equal(convert(1, 'mm', 'm'), 0.001); 25 | t.equal(convert(1, 'm', 'cm'), 100); 26 | t.equal(convert(1, 'm', 'mm'), 1000); 27 | t.equal(convertWithPrecision(1, 'm', 'ft'), 3.2808); 28 | t.equal(convert(1, 'ft', 'in'), 12); 29 | t.equal(convert(1, 'in', 'ft'), 1 / 12); 30 | t.equal(convertWithPrecision(1, 'm', 'ft'), 3.2808); 31 | t.equal(convertWithPrecision(1, 'm', 'ft'), 3.2808); 32 | t.equal(convertWithPrecision(1, 'm', 'in'), 39.3701); 33 | t.equal(convert(1, 'in', 'm'), 0.0254); 34 | t.equal(convert(1, 'cm', 'm'), 0.01); 35 | t.equal(convert(1, 'm', 'cm'), 100); 36 | t.equal(convert(72, 'pt', 'in'), 1); 37 | t.equal(convert(1, 'in', 'pt'), 72); 38 | t.equal(convert(1, 'in', 'pc'), 6); 39 | t.equal(convert(6, 'pc', 'in'), 1); 40 | t.equal(convert(6, 'pc', 'pc'), 6); 41 | t.equal(convert(6, 'in', 'in'), 6); 42 | t.end(); 43 | }); 44 | 45 | tape('test API and errors', t => { 46 | t.throws(() => convert(2, 'gold', 'foo')); 47 | t.throws(() => convert(NaN, 'px', 'in')); 48 | t.throws(() => convert(25)); 49 | t.deepEqual(convert.units, [ 'mm', 'cm', 'm', 'pc', 'pt', 'in', 'ft', 'px' ]); 50 | t.end(); 51 | }); 52 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # convert-length 2 | 3 | A simple utility to convert from physical lengths (meters, inches, etc) to pixels and back, based on the CSS spec. Supports converting to and from the following units: 4 | 5 | - `mm` (millimeters) 6 | - `cm` (centimeters) 7 | - `m` (meters) 8 | - `pc` (pica, or 1 / 6 of an inch) 9 | - `pt` (point, or 1 / 72 of an inch) 10 | - `in` (inch) 11 | - `ft` (feet, or 12 inches) 12 | - `px` (pixels) 13 | 14 | Example: 15 | 16 | ```js 17 | const convert = require('convert-length'); 18 | 19 | // Convert 10 inches to meters 20 | const result = convert(10, 'in', 'm') 21 | // -> 0.254 22 | 23 | // Convert A4 print (210 x 297 mm) to pixels @ 300 PPI 24 | const result = [ 210, 297 ].map(n => { 25 | return convert(n, 'mm', 'px', { pixelsPerInch: 300 }) 26 | }); 27 | // -> [ 2480, 3508 ] 28 | ``` 29 | 30 | Pixels are computed based on the specified `pixelsPerInch` setting (default 96), as per the CSS spec. 31 | 32 | ## Install 33 | 34 | Use [npm](https://npmjs.com/) to install and use this. Should work with browserify, Webpack, etc. 35 | 36 | ```sh 37 | npm install convert-length 38 | ``` 39 | 40 | ## Usage 41 | 42 | ### `result = convert(value, fromUnit, toUnit, [options])` 43 | 44 | Converts the `value` number from the `fromUnit` unit string (e.g. `"in"`) to the `toUnit` unit string. The unit strings are case insensitive. 45 | 46 | Options can be: 47 | 48 | - `pixelsPerInch` (default 96) the number of pixels in one inch, used when converting to and from `"px"` units 49 | - `precision` if specified, the value will be rounded to the Nth decimal. e.g. A precision of `3` will round to `0.001`. If not specified, the result will not be rounded. 50 | - `roundPixel` (default true) If enabled, when converting to a `"px"` unit the return value will be rounded to a whole pixel. If disabled, the conversion will instead round to the specified Nth `precision` decimal (or no rounding if `precision` is not specified). 51 | 52 | ### `convert.units` 53 | 54 | The list of supported units for this module, equivalent to: 55 | 56 | ```js 57 | [ 'mm', 'cm', 'm', 'pc', 'pt', 'in', 'ft', 'px' ] 58 | ``` 59 | 60 | ## See Also 61 | 62 | This module was inspired by [measures](https://www.npmjs.com/package/measures) and [convert-units](https://www.npmjs.com/package/convert-units), but I wanted something dead-simple for the browser, without all the extra features, and that supports pixels in the same way CSS and Photoshop handle their conversions. 63 | 64 | ## License 65 | 66 | MIT, see [LICENSE.md](http://github.com/mattdesl/convert-length/blob/master/LICENSE.md) for details. 67 | -------------------------------------------------------------------------------- /convert-length.js: -------------------------------------------------------------------------------- 1 | var defined = require('defined'); 2 | var units = [ 'mm', 'cm', 'm', 'pc', 'pt', 'in', 'ft', 'px' ]; 3 | 4 | var conversions = { 5 | // metric 6 | m: { 7 | system: 'metric', 8 | factor: 1 9 | }, 10 | cm: { 11 | system: 'metric', 12 | factor: 1 / 100 13 | }, 14 | mm: { 15 | system: 'metric', 16 | factor: 1 / 1000 17 | }, 18 | // imperial 19 | pt: { 20 | system: 'imperial', 21 | factor: 1 / 72 22 | }, 23 | pc: { 24 | system: 'imperial', 25 | factor: 1 / 6 26 | }, 27 | in: { 28 | system: 'imperial', 29 | factor: 1 30 | }, 31 | ft: { 32 | system: 'imperial', 33 | factor: 12 34 | } 35 | }; 36 | 37 | const anchors = { 38 | metric: { 39 | unit: 'm', 40 | ratio: 1 / 0.0254 41 | }, 42 | imperial: { 43 | unit: 'in', 44 | ratio: 0.0254 45 | } 46 | }; 47 | 48 | function round (value, decimals) { 49 | return Number(Math.round(value + 'e' + decimals) + 'e-' + decimals); 50 | } 51 | 52 | function convertDistance (value, fromUnit, toUnit, opts) { 53 | if (typeof value !== 'number' || !isFinite(value)) throw new Error('Value must be a finite number'); 54 | if (!fromUnit || !toUnit) throw new Error('Must specify from and to units'); 55 | 56 | opts = opts || {}; 57 | var pixelsPerInch = defined(opts.pixelsPerInch, 96); 58 | var precision = opts.precision; 59 | var roundPixel = opts.roundPixel !== false; 60 | 61 | fromUnit = fromUnit.toLowerCase(); 62 | toUnit = toUnit.toLowerCase(); 63 | 64 | if (units.indexOf(fromUnit) === -1) throw new Error('Invalid from unit "' + fromUnit + '", must be one of: ' + units.join(', ')); 65 | if (units.indexOf(toUnit) === -1) throw new Error('Invalid from unit "' + toUnit + '", must be one of: ' + units.join(', ')); 66 | 67 | if (fromUnit === toUnit) { 68 | // We don't need to convert from A to B since they are the same already 69 | return value; 70 | } 71 | 72 | var toFactor = 1; 73 | var fromFactor = 1; 74 | var isToPixel = false; 75 | 76 | if (fromUnit === 'px') { 77 | fromFactor = 1 / pixelsPerInch; 78 | fromUnit = 'in'; 79 | } 80 | if (toUnit === 'px') { 81 | isToPixel = true; 82 | toFactor = pixelsPerInch; 83 | toUnit = 'in'; 84 | } 85 | 86 | var fromUnitData = conversions[fromUnit]; 87 | var toUnitData = conversions[toUnit]; 88 | 89 | // source to anchor inside source's system 90 | var anchor = value * fromUnitData.factor * fromFactor; 91 | 92 | // if systems differ, convert one to another 93 | if (fromUnitData.system !== toUnitData.system) { 94 | // regular 'm' to 'in' and so forth 95 | anchor *= anchors[fromUnitData.system].ratio; 96 | } 97 | 98 | var result = anchor / toUnitData.factor * toFactor; 99 | if (isToPixel && roundPixel) { 100 | result = Math.round(result); 101 | } else if (typeof precision === 'number' && isFinite(precision)) { 102 | result = round(result, precision); 103 | } 104 | return result; 105 | } 106 | 107 | module.exports = convertDistance; 108 | module.exports.units = units; 109 | --------------------------------------------------------------------------------