Refactor Format literal to Formatter class that keeps precision stored.

This commit is contained in:
Jürg Lehni 2013-04-09 17:32:19 -07:00
parent 8da8f116d1
commit fbe8a558bd
13 changed files with 116 additions and 107 deletions

View file

@ -120,11 +120,11 @@ var Matrix = this.Matrix = Base.extend(/** @lends Matrix# */{
* @return {String} A string representation of this transform.
*/
toString: function() {
var format = Format.number;
return '[[' + [format(this._a), format(this._b),
format(this._tx)].join(', ') + '], ['
+ [format(this._c), format(this._d),
format(this._ty)].join(', ') + ']]';
var f = Formatter.instance;
return '[[' + [f.number(this._a), f.number(this._b),
f.number(this._tx)].join(', ') + '], ['
+ [f.number(this._c), f.number(this._d),
f.number(this._ty)].join(', ') + ']]';
},
/**

View file

@ -224,18 +224,16 @@ var Point = this.Point = Base.extend(/** @lends Point# */{
* @return {String} A string representation of the point.
*/
toString: function() {
var format = Format.number;
return '{ x: ' + format(this.x) + ', y: ' + format(this.y) + ' }';
var f = Formatter.instance;
return '{ x: ' + f.number(this.x) + ', y: ' + f.number(this.y) + ' }';
},
_serialize: function(options) {
var format = Format.number,
precision = options.precision;
// For speed reasons, we directly call Format.number() here with
// precision, instead of converting array through Base.serialize() which
// makes a copy.
return [format(this.x, precision),
format(this.y, precision)];
var f = options.formatter;
// For speed reasons, we directly call formatter.number() here, instead
// of converting array through Base.serialize() which makes a copy.
return [f.number(this.x),
f.number(this.y)];
},
/**

View file

@ -210,22 +210,21 @@ var Rectangle = this.Rectangle = Base.extend(/** @lends Rectangle# */{
* @return {String} A string representation of this rectangle.
*/
toString: function() {
var format = Format.number;
return '{ x: ' + format(this.x)
+ ', y: ' + format(this.y)
+ ', width: ' + format(this.width)
+ ', height: ' + format(this.height)
var f = Formatter.instance;
return '{ x: ' + f.number(this.x)
+ ', y: ' + f.number(this.y)
+ ', width: ' + f.number(this.width)
+ ', height: ' + f.number(this.height)
+ ' }';
},
_serialize: function(options) {
var format = Format.number,
precision = options.precision;
var f = options.formatter;
// See Point#_serialize()
return [format(this.x, precision),
format(this.y, precision),
format(this.width, precision),
format(this.height, precision)];
return [f.number(this.x),
f.number(this.y),
f.number(this.width),
f.number(this.height)];
},
/**
@ -846,6 +845,8 @@ var LinkedRectangle = Rectangle.extend({
};
}, /** @lends Rectangle# */{
/**
* {@grouptitle Item Bounds}
*
* Specifies whether an item's bounds are selected and will also
* mark the item as selected.
*

View file

@ -171,17 +171,16 @@ var Size = this.Size = Base.extend(/** @lends Size# */{
* @return {String} A string representation of the size.
*/
toString: function() {
var format = Format.number;
return '{ width: ' + format(this.width)
+ ', height: ' + format(this.height) + ' }';
var f = Formatter.instance;
return '{ width: ' + f.number(this.width)
+ ', height: ' + f.number(this.height) + ' }';
},
_serialize: function(options) {
var format = Format.number,
precision = options.precision;
var f = options.formatter;
// See Point#_serialize()
return [format(this.width, precision),
format(this.height, precision)];
return [f.number(this.width),
f.number(this.height)];
},
/**

View file

@ -44,7 +44,7 @@ this.Base = Base.inject(/** @lends Base# */{
if (!/^_/.test(key)) {
var type = typeof value;
this.push(key + ': ' + (type === 'number'
? Format.number(value)
? Formatter.instance.number(value)
: type === 'string' ? "'" + value + "'" : value));
}
}, []).join(', ') + ' }';
@ -270,9 +270,11 @@ this.Base = Base.inject(/** @lends Base# */{
*/
serialize: function(obj, options, compact, dictionary) {
options = options || {};
var root = !dictionary,
res;
if (root) {
options.formatter = new Formatter(options.precision);
// Create a simple dictionary object that handles all the
// storing and retrieving of dictionary definitions and
// references, e.g. for symbols and gradients. Items that want
@ -325,7 +327,7 @@ this.Base = Base.inject(/** @lends Base# */{
res[i] = Base.serialize(obj[i], options, compact,
dictionary);
} else if (typeof obj === 'number') {
res = Format.number(obj, options.precision);
res = options.formatter.number(obj, options.precision);
} else {
res = obj;
}

View file

@ -107,7 +107,7 @@ var paper = new function() {
/*#*/ include('tool/Tool.js');
/*#*/ } // options.browser
/*#*/ include('util/Format.js');
/*#*/ include('util/Formatter.js');
/*#*/ include('util/CanvasProvider.js');
/*#*/ include('util/Numerical.js');
/*#*/ include('util/BlendMode.js');

View file

@ -223,7 +223,8 @@ var CurveLocation = this.CurveLocation = Base.extend(/** @lends CurveLocation# *
*/
toString: function() {
var parts = [],
point = this.getPoint();
point = this.getPoint(),
f = Formatter.instance;
if (point)
parts.push('point: ' + point);
var index = this.getIndex();
@ -231,9 +232,9 @@ var CurveLocation = this.CurveLocation = Base.extend(/** @lends CurveLocation# *
parts.push('index: ' + index);
var parameter = this.getParameter();
if (parameter != null)
parts.push('parameter: ' + Format.number(parameter));
parts.push('parameter: ' + f.number(parameter));
if (this._distance != null)
parts.push('distance: ' + Format.number(this._distance));
parts.push('distance: ' + f.number(this._distance));
return '{ ' + parts.join(', ') + ' }';
}
});

View file

@ -206,8 +206,8 @@ var Path = this.Path = PathItem.extend(/** @lends Path# */{
getPathData: function(/* precision */) {
var segments = this._segments,
style = this._style,
format = Format.point,
precision = arguments[0],
f = Formatter.instance,
parts = [];
// TODO: Add support for H/V and/or relative commands, where appropriate
@ -220,21 +220,21 @@ var Path = this.Path = PathItem.extend(/** @lends Path# */{
if (handle1.isZero() && handle2.isZero()) {
if (!skipLine) {
// L = absolute lineto: moving to a point with drawing
parts.push('L' + format(point2, precision));
parts.push('L' + f.point(point2, precision));
}
} else {
// c = relative curveto: handle1, handle2 + end - start,
// end - start
var end = point2.subtract(point1);
parts.push('c' + format(handle1, precision)
+ ' ' + format(end.add(handle2), precision)
+ ' ' + format(end, precision));
parts.push('c' + f.point(handle1, precision)
+ ' ' + f.point(end.add(handle2), precision)
+ ' ' + f.point(end, precision));
}
}
if (segments.length === 0)
return '';
parts.push('M' + format(segments[0]._point));
parts.push('M' + f.point(segments[0]._point));
for (i = 0, l = segments.length - 1; i < l; i++)
addCurve(segments[i], segments[i + 1], false);
// We only need to draw the connecting curve if it is not a line, and if

View file

@ -688,15 +688,15 @@ var Color = this.Color = Base.extend(new function() {
var properties = types[this._type],
parts = [],
isGradient = this._type === 'gradient',
format = Format.number;
f = Formatter.instance;
for (var i = 0, l = properties.length; i < l; i++) {
var value = this._components[i];
if (value != null)
parts.push(properties[i] + ': '
+ (isGradient ? value : format(value)));
+ (isGradient ? value : f.number(value)));
}
if (this._alpha != null)
parts.push('alpha: ' + format(this._alpha));
parts.push('alpha: ' + f.number(this._alpha));
return '{ ' + parts.join(', ') + ' }';
},

View file

@ -15,8 +15,7 @@
* Paper.js DOM to a SVG DOM.
*/
new function() {
// Shortcut to Format.number
var format = Format.number,
var formatter = Formatter.instance,
namespaces = {
href: 'http://www.w3.org/1999/xlink'
};
@ -26,7 +25,7 @@ new function() {
var val = attrs[key],
namespace = namespaces[key];
if (typeof val === 'number')
val = format(val);
val = formatter.number(val);
if (namespace) {
node.setAttributeNS(namespace, key, val);
} else {
@ -72,11 +71,11 @@ new function() {
angle = decomposed.rotation,
scale = decomposed.scaling;
if (trans && !trans.isZero())
parts.push('translate(' + Format.point(trans) + ')');
parts.push('translate(' + formatter.point(trans) + ')');
if (!Numerical.isZero(scale.x - 1) || !Numerical.isZero(scale.y - 1))
parts.push('scale(' + Format.point(scale) +')');
parts.push('scale(' + formatter.point(scale) +')');
if (angle)
parts.push('rotate(' + format(angle) + ')');
parts.push('rotate(' + formatter.number(angle) + ')');
attrs.transform = parts.join(' ');
} else {
attrs.transform = 'matrix(' + matrix.getValues().join(',') + ')';
@ -223,7 +222,7 @@ new function() {
case 'polygon':
var parts = [];
for(i = 0, l = segments.length; i < l; i++)
parts.push(Format.point(segments[i]._point));
parts.push(formatter.point(segments[i]._point));
attrs = {
points: parts.join(' ')
};
@ -296,8 +295,8 @@ new function() {
break;
}
if (angle) {
attrs.transform = 'rotate(' + format(angle) + ','
+ Format.point(center) + ')';
attrs.transform = 'rotate(' + formatter.number(angle) + ','
+ formatter.point(center) + ')';
// Tell applyStyle() that to transform the gradient the other way
item._gradientMatrix = new Matrix().rotate(-angle, center);
}
@ -320,7 +319,7 @@ new function() {
bounds = definition.getBounds();
if (!symbolNode) {
symbolNode = createElement('symbol', {
viewBox: Format.rectangle(bounds)
viewBox: formatter.rectangle(bounds)
});
symbolNode.appendChild(exportSvg(definition));
setDefinition(symbol, symbolNode);
@ -328,8 +327,8 @@ new function() {
attrs.href = '#' + symbolNode.id;
attrs.x += bounds.x;
attrs.y += bounds.y;
attrs.width = format(bounds.width);
attrs.height = format(bounds.height);
attrs.width = formatter.number(bounds.width);
attrs.height = formatter.number(bounds.height);
return createElement('use', attrs);
}
@ -431,7 +430,7 @@ new function() {
: entry.type === 'array'
? value.join(',')
: entry.type === 'number'
? format(value)
? formatter.number(value)
: value;
}
});

View file

@ -1,44 +0,0 @@
/**
* @name Format
* @namespace
* @private
*/
var Format = new function() {
// Cache for precision values, linking prec -> Math.pow(10, prec)
var precisions = {};
function number(val, prec) {
prec = prec
? precisions[prec] || (precisions[prec] = Math.pow(10, prec))
: 100000; // Default is 5
return Math.round(val * prec) / prec;
}
function point(val, prec, separator) {
return number(val.x, prec) + (separator || ',') + number(val.y, prec);
}
function size(val, prec, separator) {
return number(val.width, prec) + (separator || ',')
+ number(val.height, prec);
}
function rectangle(val, prec, separator) {
return point(val, prec, separator) + (separator || ',')
+ size(val, prec, separator);
}
return {
/**
* Utility function for rendering numbers as strings at a precision of
* up to the amount of fractional digits.
*
* @param {Number} num the number to be converted to a string
* @param {Number} [precision=5] the amount of fractional digits.
*/
number: number,
point: point,
size: size,
rectangle: rectangle
};
};

51
src/util/Formatter.js Normal file
View file

@ -0,0 +1,51 @@
/*
* Paper.js - The Swiss Army Knife of Vector Graphics Scripting.
* http://paperjs.org/
*
* Copyright (c) 2011 - 2013, Juerg Lehni & Jonathan Puckey
* http://lehni.org/ & http://jonathanpuckey.com/
*
* Distributed under the MIT license. See LICENSE file for details.
*
* All rights reserved.
*/
/**
* @name Formatter
* @private
*/
var Formatter = Base.extend({
/**
* @param {Number} [precision=5] the amount of fractional digits.
*/
initialize: function(precision) {
this.precision = precision || 5;
this.multiplier = Math.pow(10, this.precision);
},
/**
* Utility function for rendering numbers as strings at a precision of
* up to the amount of fractional digits.
*
* @param {Number} num the number to be converted to a string
*/
number: function(val) {
return Math.round(val * this.multiplier) / this.multiplier;
},
point: function(val, separator) {
return this.number(val.x) + (separator || ',') + this.number(val.y);
},
size: function(val, separator) {
return this.number(val.width) + (separator || ',')
+ this.number(val.height);
},
rectangle: function(val, separator) {
return this.point(val, separator) + (separator || ',')
+ this.size(val, separator);
}
});
Formatter.instance = new Formatter(5);

View file

@ -60,14 +60,16 @@ function asyncTest(testName, expected) {
}
function compareNumbers(number1, number2, message, precision) {
equals(Format.number(number1, precision),
Format.number(number2, precision), message);
var formatter = new Formatter(precision);
equals(formatter.number(number1, precision),
formatter.number(number2, precision), message);
}
function compareArrays(array1, array2, message, precision) {
var formatter = new Formatter(precision);
function format(array) {
return Base.each(array, function(value, index) {
this[index] = Format.number(value, precision);
this[index] = formatter.number(value, precision);
}, []).toString();
}
equals(format(array1), format(array2), message);