var Node = require(“./node”),
unitConversions = require("../data/unit-conversions"), Unit = require("./unit"), Color = require("./color");
// // A number with a unit // var Dimension = function (value, unit) {
this.value = parseFloat(value); this.unit = (unit && unit instanceof Unit) ? unit : new Unit(unit ? [unit] : undefined);
};
Dimension.prototype = new Node(); Dimension.prototype.type = “Dimension”; Dimension.prototype.accept = function (visitor) {
this.unit = visitor.visit(this.unit);
}; Dimension.prototype.eval = function (context) {
return this;
}; Dimension.prototype.toColor = function () {
return new Color([this.value, this.value, this.value]);
}; Dimension.prototype.genCSS = function (context, output) {
if ((context && context.strictUnits) && !this.unit.isSingular()) { throw new Error("Multiple units in dimension. Correct the units or use the unit function. Bad unit: " + this.unit.toString()); } var value = this.fround(context, this.value), strValue = String(value); if (value !== 0 && value < 0.000001 && value > -0.000001) { // would be output 1e-6 etc. strValue = value.toFixed(20).replace(/0+$/, ""); } if (context && context.compress) { // Zero values doesn't need a unit if (value === 0 && this.unit.isLength()) { output.add(strValue); return; } // Float values doesn't need a leading zero if (value > 0 && value < 1) { strValue = (strValue).substr(1); } } output.add(strValue); this.unit.genCSS(context, output);
};
// In an operation between two Dimensions, // we default to the first Dimension's unit, // so `1px + 2` will yield `3px`. Dimension.prototype.operate = function (context, op, other) {
/*jshint noempty:false */ var value = this._operate(context, op, this.value, other.value), unit = this.unit.clone(); if (op === '+' || op === '-') { if (unit.numerator.length === 0 && unit.denominator.length === 0) { unit = other.unit.clone(); if (this.unit.backupUnit) { unit.backupUnit = this.unit.backupUnit; } } else if (other.unit.numerator.length === 0 && unit.denominator.length === 0) { // do nothing } else { other = other.convertTo(this.unit.usedUnits()); if (context.strictUnits && other.unit.toString() !== unit.toString()) { throw new Error("Incompatible units. Change the units or use the unit function. Bad units: '" + unit.toString() + "' and '" + other.unit.toString() + "'."); } value = this._operate(context, op, this.value, other.value); } } else if (op === '*') { unit.numerator = unit.numerator.concat(other.unit.numerator).sort(); unit.denominator = unit.denominator.concat(other.unit.denominator).sort(); unit.cancel(); } else if (op === '/') { unit.numerator = unit.numerator.concat(other.unit.denominator).sort(); unit.denominator = unit.denominator.concat(other.unit.numerator).sort(); unit.cancel(); } return new Dimension(value, unit);
}; Dimension.prototype.compare = function (other) {
var a, b; if (!(other instanceof Dimension)) { return undefined; } if (this.unit.isEmpty() || other.unit.isEmpty()) { a = this; b = other; } else { a = this.unify(); b = other.unify(); if (a.unit.compare(b.unit) !== 0) { return undefined; } } return Node.numericCompare(a.value, b.value);
}; Dimension.prototype.unify = function () {
return this.convertTo({ length: 'px', duration: 's', angle: 'rad' });
}; Dimension.prototype.convertTo = function (conversions) {
var value = this.value, unit = this.unit.clone(), i, groupName, group, targetUnit, derivedConversions = {}, applyUnit; if (typeof conversions === 'string') { for (i in unitConversions) { if (unitConversions[i].hasOwnProperty(conversions)) { derivedConversions = {}; derivedConversions[i] = conversions; } } conversions = derivedConversions; } applyUnit = function (atomicUnit, denominator) { /* jshint loopfunc:true */ if (group.hasOwnProperty(atomicUnit)) { if (denominator) { value = value / (group[atomicUnit] / group[targetUnit]); } else { value = value * (group[atomicUnit] / group[targetUnit]); } return targetUnit; } return atomicUnit; }; for (groupName in conversions) { if (conversions.hasOwnProperty(groupName)) { targetUnit = conversions[groupName]; group = unitConversions[groupName]; unit.map(applyUnit); } } unit.cancel(); return new Dimension(value, unit);
}; module.exports = Dimension;