计量单位转换库

时间:2009-05-14 20:33:33

标签: javascript

根据用户首选的度量单位设置,抽象出客户端度量单位转换的最佳/最优雅方法是什么?

例如,假设用户A的首选度量单位是“metric”,而用户B的首选项是“imperial”。

现在我可以说我已计算出以平方米为单位的面积。当我去显示值时,我需要为每个用户使用不同的转换因子(例如,“1米= 1.09361码”)。或者说我已计算mL中的流体量。用户B的视图将使用转换“236.588237 mL = 1 US cup”进行计算。

是否有一个现有的javascript库,这里的任何人都知道处理这些简单的UOM转换?

8 个答案:

答案 0 :(得分:40)

这是一个小小的脚本,我只是为了它而扔在一起。它处理克,字节,米和升的所有SI转换,并且我还添加了盎司和磅作为非SI单位的示例。要添加更多内容,您需要:

  1. 将基本类型添加到“SI”或
  2. 后面的项目的“单位”列表中
  3. 为不符合SI
  4. 的项目添加转化率

    用法:

    $u(1, 'g').as('kg').val(); // converts one gram to kg
    

    您可以使用.val()获取值,使用.toString()获取字符串表示,或通过.debug()获取完整详细信息

    (function () {
        var table = {};
    
        window.unitConverter = function (value, unit) {
            this.value = value;
            if (unit) {
                this.currentUnit = unit;
            }
        };
        unitConverter.prototype.as = function (targetUnit) {
            this.targetUnit = targetUnit;
            return this;
        };
        unitConverter.prototype.is = function (currentUnit) {
            this.currentUnit = currentUnit;
            return this;
        };
    
        unitConverter.prototype.val = function () {
            // first, convert from the current value to the base unit
            var target = table[this.targetUnit];
            var current = table[this.currentUnit];
            if (target.base != current.base) {
                throw new Error('Incompatible units; cannot convert from "' + this.currentUnit + '" to "' + this.targetUnit + '"');
            }
    
            return this.value * (current.multiplier / target.multiplier);
        };
        unitConverter.prototype.toString = function () {
            return this.val() + ' ' + this.targetUnit;
        };
        unitConverter.prototype.debug = function () {
            return this.value + ' ' + this.currentUnit + ' is ' + this.val() + ' ' + this.targetUnit;
        };
        unitConverter.addUnit = function (baseUnit, actualUnit, multiplier) {
            table[actualUnit] = { base: baseUnit, actual: actualUnit, multiplier: multiplier };
        };
    
        var prefixes = ['Y', 'Z', 'E', 'P', 'T', 'G', 'M', 'k', 'h', 'da', '', 'd', 'c', 'm', 'u', 'n', 'p', 'f', 'a', 'z', 'y'];
        var factors = [24, 21, 18, 15, 12, 9, 6, 3, 2, 1, 0, -1, -2, -3, -6, -9, -12, -15, -18, -21, -24];
        // SI units only, that follow the mg/kg/dg/cg type of format
        var units = ['g', 'b', 'l', 'm'];
    
        for (var j = 0; j < units.length; j++) {
            var base = units[j];
            for (var i = 0; i < prefixes.length; i++) {
                unitConverter.addUnit(base, prefixes[i] + base, Math.pow(10, factors[i]));
            }
        }
    
        // we use the SI gram unit as the base; this allows
        // us to convert between SI and English units
        unitConverter.addUnit('g', 'ounce', 28.3495231);
        unitConverter.addUnit('g', 'oz', 28.3495231);
        unitConverter.addUnit('g', 'pound', 453.59237);
        unitConverter.addUnit('g', 'lb', 453.59237);
    
    
        window.$u = function (value, unit) {
            var u = new window.unitConverter(value, unit);
            return u;
        };
    })();
    
    console.log($u(1, 'g').as('kg').debug());  
    console.log($u(1, 'kg').as('g').debug());
    console.log($u(1, 'g').as('mg').debug());
    console.log($u(1, 'mg').as('g').debug());
    console.log($u(1, 'mg').as('kg').debug());
    
    console.log($u(1, 'g').as('oz').debug());
    console.log($u(1, 'g').as('lb').debug());
    
    console.log($u(1, 'oz').as('lb').debug());
    
    console.log($u(1, 'lb').as('g').debug());
    
    // this last one throws an exception since you can't convert liters to mg
    console.log($u(1, 'l').as('mg').debug());
    

    我已将此移至Github上的小型回购中,因此如果有人想要改进/增强,他们可以这样做: https://github.com/jerodvenemafm/jsunitconverter

答案 1 :(得分:9)

您可以将这个Ruby Units端口查看为Javascript:

https://github.com/gentooboontoo/js-quantities

答案 2 :(得分:5)

受到许多关于这个主题的帖子的启发以及MomentJs的简单性和小巧性,我已经开始研究这个问题了:

MeasurementJs

它尚未包含所有上述转化,但您可以轻松扩展DEFINITIONS数组和MeasurementJs.Units.*对象,以实现您喜欢的任何转换。

答案 3 :(得分:3)

我会把它留在这里......

转换几乎所有英制/标准距离/长度

的简单JS方法
;;if (!window.hasOwnProperty('convertImperialMetric')) {
    function convertImperialMetric () {
        var metrics = convertImperialMetric.metrics,
            imperials = convertImperialMetric.imperials,
            args = arguments,
            conversionTypes = { imperial: 'imperial', metric: 'metric' },
            toFixed = false, toFixedX = 2,
            intX, typImp, typMet, conType = 'metric',
            $ret;

        conversionTypes.i = conversionTypes.imp = conversionTypes.imperial;
        conversionTypes.m = conversionTypes.met = conversionTypes.metric;

        function setVarz(c) {
            for (i in c) {
                var a = c[i];
                switch (typeof a) {
                    case "boolean":
                        toFixed = a;
                        break;
                    case "number":
                        void 0 == intX ? intX = a : toFixedX = a;
                        break;
                    case "string":
                        isNaN(parseFloat(a)) || void 0 != intX ? imperials.hasOwnProperty(a) ? typImp = a : metrics.hasOwnProperty(a) ? typMet = a : conversionTypes.hasOwnProperty(a) && (conType = conversionTypes[a]) : intX = parseFloat(a);
                        break;
                    case "object":
                        if (a instanceof Array) setVarz.apply(this, [a]);
                        else if (a instanceof Object)
                            for (h in a) {
                                var b = a[h];
                                conversionTypes.hasOwnProperty(h) ? conType = conversionTypes[h] : imperials.hasOwnProperty(h) ? (typImp =
                                    h, void 0 != intX || isNaN(parseFloat(b)) || (intX = parseFloat(b))) : metrics.hasOwnProperty(h) ? (typMet = h, void 0 != intX || isNaN(parseFloat(b)) || (intX = parseFloat(b))) : setVarz.apply(this, [
                                    [b]
                                ])
                            }
                }
            }
        };
        setVarz(args);

        if (!isNaN(parseFloat(intX)) && imperials.hasOwnProperty(typImp) && metrics.hasOwnProperty(typMet) && conversionTypes.hasOwnProperty(conType)) {
            if (conType == 'metric') {
                var inches = intX * imperials[typImp],
                    centimeters = inches * 2.54;
                $ret = centimeters * metrics[typMet];
            }
            else if (conType == 'imperial') {
                var centimeters = intX / metrics[typMet],
                    inches = centimeters / 2.54;
                $ret = inches / imperials[typImp];
            }
        }

        return toFixed ? parseFloat($ret.toFixed(toFixedX)) : $ret;
    }

    convertImperialMetric.imperials = {
        inches: 1,
        feet: 12,
        yards: 36,
        miles: 63360,
        nautical: 72913.4
    };

    convertImperialMetric.metrics = {
        yocto: 10000000000000000000000,
        zepto: 10000000000000000000,
        atto: 10000000000000000,
        femto: 10000000000000,
        pico: 10000000000,
        nano: 10000000,
        micro: 10000,
        milli: 10,
        centi: 1,
        deci: .1,
        meter: .01,
        deka: .001,
        hecto: .0001,
        kilo: .00001,
        mega: .00000001,
        giga: .00000000001,
        tera: .00000000000001,
        peta: .00000000000000001,
        exa: .00000000000000000001,
        zetta: .00000000000000000000001,
        yotta: .00000000000000000000000001
    };
}

示例用法:

convertImperialMetric(12, 'inches', 'centi');   //  Results in: 30.48
convertImperialMetric(30.48, 'centi', 'inches', 'i');   //  Results in: 12
convertImperialMetric('1200000', 'inches', 'kilo'); //  Results in: 30.480000000000004
convertImperialMetric('1200000', 'inches', 'kilo', true);   //  Results in: 30.48
convertImperialMetric('1200000', 'inches', 'kilo', true, 1);    //  Results in: 30.5
convertImperialMetric([ 12, 'inches', 'centi' ]);   //  Results in: 30.48
convertImperialMetric([ '12', 'inches', 'centi' ]); //  Results in: 30.48
convertImperialMetric({ inches: 12, anyVariableName: 'centi' });    //  Results in: 30.48
convertImperialMetric({ inches: '12', anyVariableName: 'centi' });  //  Results in: 30.48
convertImperialMetric({ inches: 12, centi: 'anyValue' });   //  Results in: 30.48
convertImperialMetric({ inches: '12', centi: 'anyValue' }); //  Results in: 30.48
convertImperialMetric({ inches: '12', to: 'centi', type: 'metric', toFixed: true, toFX: 1 });   //  Results in: 30.5
convertImperialMetric({ feet: 1 }, 'centi');    //  Results in: 30.48
convertImperialMetric({ centi: '30.48' }, 'inches', 'imperial');    //  Results in: 12
convertImperialMetric({ meter: '.3048' }, 'inches', 'imperial');    //  Results in: 12

jsFiddle / jsFiddle/show

答案 4 :(得分:2)

正在转换多少个不同的单位?这听起来好像你正在编写我正在使用的特定应用程序,因为你只需要几种不同类型的转换(面积,体积等)

如果就是这种情况,那么只需要为您需要的转换查找转换并将它们编码为自己的类就可能更快。加载一个完整的JavaScript库只是为了执行一些特定的乘法可能是过度的。

答案 5 :(得分:2)

一种流行的实用程序,可让您在不同单位之间进行转换:convert-units

用法示例,将英制英寸转换为公制厘米:

var convert = require('convert-units')
convert(1).from('in').to('cm') // 2.54 

安装:

npm install convert-units

答案 6 :(得分:1)

这是一个可扩展和简洁的东西,可以构建一个查找表,因此性能应该很好。

core = {};
core.mixin = function (dst, src) { if (src) for (var i in src) dst[i] = src[i]; return dst; }

function UnitConverter(meter) {
    var feetPerMeter = 3.2808399, feetPerMile = 5280;
    this.meter = core.mixin({ km: 1000, mi: feetPerMile / feetPerMeter, ft: 1 / feetPerMeter, m: 1 }, meter);
    var t = [], i = 0;
    for (t[i++] in this.meter);
    this.table = [];
    for (i = 0; i < t.length; i++)
        for (j = 0; j < t.length; j++) {
            var key1 = t[i], key2 = t[(i + j + 1) % t.length];
            this.table[key1 + "/" + key2] = this.meter[key2] / this.meter[key1];
        }
};

with(UnitConverter) {
    prototype = new Object();
    prototype.convert = function () {
        switch (arguments.length) {
        case 1:
            return this.table[arguments[0]];
        case 2:
            return arguments[0] * this.table[arguments[1]];
        case 3:
            return arguments[0] * this.meter[arguments[1]] / this.meter[arguments[2]];
        }
        return Number.NaN;
    }
}

<强>用法

Number.converter = new UnitConverter({ nm: 1852 }); // extent to include nautical miles
Number.units = Number.converter.table;
var km = 1;
var mi = km * Number.units["mi/km"];
var m = Number.converter.convert(mi, "mi", "m");
var ft = Number.converter.convert(m, "ft/m");
m = Number.converter.convert(ft, "ft", "m");
ft = m / Number.converter.convert("m/ft");
km = ft * Number.units["km/ft"];
nm = Number.converter.convert(km, "km", "nm");

答案 7 :(得分:1)

图书馆&#34;衡量&#34;在单位类型(体积,质量等)之间进行转换,并支持多个单位系统(美国,英制,公制)

// volume
measure('1 teaspoon').teaspoons() // 1
measure('1 1/2 tsp.').teaspoons() // 1.5
measure('2 cups and 1 pint').quarts() // 1

// mass
measure('1 pound').ounces() // 16
measure('1 1/2 oz.').ounces() // 1.5

// operations
measure('1 teaspoon').add('1 teaspoon').teaspoons();
measure('6 1/2 teaspoon').divide(2).teaspoons(); // 3.25

https://github.com/dubbs/measure