From fbe8a558bdbfa5ac24f977cf35c3f1adad57f073 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C3=BCrg=20Lehni?= Date: Tue, 9 Apr 2013 17:32:19 -0700 Subject: [PATCH] Refactor Format literal to Formatter class that keeps precision stored. --- src/basic/Matrix.js | 10 ++++---- src/basic/Point.js | 16 ++++++------ src/basic/Rectangle.js | 23 +++++++++--------- src/basic/Size.js | 13 +++++----- src/core/Base.js | 6 +++-- src/paper.js | 2 +- src/path/CurveLocation.js | 7 +++--- src/path/Path.js | 12 ++++----- src/style/Color.js | 6 ++--- src/svg/SvgExport.js | 25 +++++++++---------- src/util/Format.js | 44 --------------------------------- src/util/Formatter.js | 51 +++++++++++++++++++++++++++++++++++++++ test/lib/helpers.js | 8 +++--- 13 files changed, 116 insertions(+), 107 deletions(-) delete mode 100644 src/util/Format.js create mode 100644 src/util/Formatter.js diff --git a/src/basic/Matrix.js b/src/basic/Matrix.js index 06656a24..0a0a57b0 100644 --- a/src/basic/Matrix.js +++ b/src/basic/Matrix.js @@ -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(', ') + ']]'; }, /** diff --git a/src/basic/Point.js b/src/basic/Point.js index 608f001c..a23b534a 100644 --- a/src/basic/Point.js +++ b/src/basic/Point.js @@ -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)]; }, /** diff --git a/src/basic/Rectangle.js b/src/basic/Rectangle.js index ab5775bc..0c55b058 100644 --- a/src/basic/Rectangle.js +++ b/src/basic/Rectangle.js @@ -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. * diff --git a/src/basic/Size.js b/src/basic/Size.js index 9fede338..9cb8fec2 100644 --- a/src/basic/Size.js +++ b/src/basic/Size.js @@ -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)]; }, /** diff --git a/src/core/Base.js b/src/core/Base.js index 17661475..398b8d13 100644 --- a/src/core/Base.js +++ b/src/core/Base.js @@ -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; } diff --git a/src/paper.js b/src/paper.js index c9be52d5..64b3ef7c 100644 --- a/src/paper.js +++ b/src/paper.js @@ -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'); diff --git a/src/path/CurveLocation.js b/src/path/CurveLocation.js index 7a702a22..da599ba1 100644 --- a/src/path/CurveLocation.js +++ b/src/path/CurveLocation.js @@ -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(', ') + ' }'; } }); diff --git a/src/path/Path.js b/src/path/Path.js index fee49120..90941c3d 100644 --- a/src/path/Path.js +++ b/src/path/Path.js @@ -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 diff --git a/src/style/Color.js b/src/style/Color.js index 7786010d..541f72c9 100644 --- a/src/style/Color.js +++ b/src/style/Color.js @@ -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(', ') + ' }'; }, diff --git a/src/svg/SvgExport.js b/src/svg/SvgExport.js index 693e7f06..b5a2f775 100644 --- a/src/svg/SvgExport.js +++ b/src/svg/SvgExport.js @@ -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; } }); diff --git a/src/util/Format.js b/src/util/Format.js deleted file mode 100644 index 7451d2a2..00000000 --- a/src/util/Format.js +++ /dev/null @@ -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 - }; -}; diff --git a/src/util/Formatter.js b/src/util/Formatter.js new file mode 100644 index 00000000..d9261d1a --- /dev/null +++ b/src/util/Formatter.js @@ -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); \ No newline at end of file diff --git a/test/lib/helpers.js b/test/lib/helpers.js index cf8c983f..dcbe5e79 100644 --- a/test/lib/helpers.js +++ b/test/lib/helpers.js @@ -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);