diff --git a/dist/all.js b/dist/all.js index 8660150a..d64056c7 100644 --- a/dist/all.js +++ b/dist/all.js @@ -2,7 +2,18 @@ var fabric = fabric || { version: 0.1 }; +/** + * Wrapper around `console.log` (when available) + * @method log + * @param {Any} Values to log + */ fabric.log = function() { }; + +/** + * Wrapper around `console.warn` (when available) + * @method warn + * @param {Any} Values to log as a warning + */ fabric.warn = function() { }; if (typeof console !== 'undefined') { @@ -432,6 +443,7 @@ replace(/(?:^|:|,)(?:\s*\[)+/g, ''))) { slice = Array.prototype.slice, apply = Function.prototype.apply; + /** @namespace */ fabric.util = { }; (function() { @@ -1240,6 +1252,8 @@ fabric.util.animate = animate; })(this); (function(){ + /** @name fabric */ + var fabric = this.fabric || (this.fabric = { }), extend = fabric.util.object.extend, capitalize = fabric.util.string.capitalize, @@ -1258,8 +1272,12 @@ fabric.util.animate = animate; }; /** - * Returns an object of attributes' name/value, given element and an array of attribute names - * Parses parent "g" nodes recursively upwards + * Returns an object of attributes' name/value, given element and an array of attribute names; + * Parses parent "g" nodes recursively upwards. + * + * @static + * @memberOf fabric + * @method parseAttributes * @param {DOMElement} element Element to parse * @param {Array} attributes Array of attributes to parse * @return {Object} object containing parsed attributes' names/values @@ -1305,7 +1323,9 @@ fabric.util.animate = animate; /** * @static - * @method fabric.parseTransformAttribute + * @function + * @memberOf fabric + * @method parseTransformAttribute * @param attributeValue {String} string containing attribute value * @return {Array} array of 6 elements representing transformation matrix */ @@ -1429,7 +1449,8 @@ fabric.util.animate = animate; /** * @static - * @method fabric.parsePointsAttribute + * @memberOf fabric + * @method parsePointsAttribute * @param points {String} points attribute string * @return {Array} array of points */ @@ -1463,9 +1484,10 @@ fabric.util.animate = animate; /** * @static - * @method fabric.parseStyleAttribute - * @param element {SVGElement} element to parse - * @return {Object} objects with values parsed from style attribute of an element + * @memberOf fabric + * @method parseStyleAttribute + * @param {SVGElement} element Element to parse + * @return {Object} Objects with values parsed from style attribute of an element */ function parseStyleAttribute(element) { var oStyle = { }, @@ -1495,10 +1517,11 @@ fabric.util.animate = animate; /** * @static - * @method fabric.parseElements - * @param elements {Array} array of elements to parse - * @param options {Object} options object - * @return {Array} array of corresponding instances (transformed from SVG elements) + * @memberOf fabric + * @method parseElements + * @param {Array} elements Array of elements to parse + * @param {Object} options Options object + * @return {Array} Array of corresponding instances (transformed from SVG elements) */ function parseElements(elements, options) { var _elements = elements.map(function(el) { @@ -1520,12 +1543,13 @@ fabric.util.animate = animate; /** * @static - * @method fabric.parseSVGDocument - * @param doc {SVGDocument} SVG document to parse - * @param callback {Function} callback to call when parsing is finished. - * Callback is being passed array of elements (parsed from a document) + * @function + * @memberOf fabric + * @method parseSVGDocument + * @param {SVGDocument} doc SVG document to parse + * @param {Function} callback Callback to call when parsing is finished; It's being passed an array of elements (parsed from a document). */ - fabric.parseSVGDocument = (function(){ + fabric.parseSVGDocument = (function() { var reAllowedSVGTagNames = /^(path|circle|polygon|polyline|ellipse|rect|line)$/; @@ -1613,106 +1637,178 @@ fabric.util.animate = animate; return; } + fabric.Point = Point; + + /** + * @name Point + * @memberOf fabric + * @constructor + * @param {Number} x + * @param {Number} y + * @return {fabric.Point} thisArg + */ function Point(x, y) { if (arguments.length > 0) { this.init(x, y); } } - Point.prototype = { + Point.prototype = /** @scope fabric.Point.prototype */ { + constructor: Point, + + /** + * @method init + * @param {Number} x + * @param {Number} y + */ init: function (x, y) { this.x = x; this.y = y; }, + + /** + * @method add + * @param {fabric.Point} that + * @return {fabric.Point} new Point instance with added values + */ add: function (that) { return new Point(this.x + that.x, this.y + that.y); }, + + /** + * @method addEquals + * @param {fabric.Point} that + * @return {fabric.Point} thisArg + */ addEquals: function (that) { this.x += that.x; this.y += that.y; return this; }, + + /** + * @method scalarAdd + * @param {Number} scalar + * @return {fabric.Point} new Point with added value + */ scalarAdd: function (scalar) { return new Point(this.x + scalar, this.y + scalar); }, + + /** + * @method scalarAddEquals + * @param {Number} scalar + * @param {fabric.Point} thisArg + */ scalarAddEquals: function (scalar) { this.x += scalar; this.y += scalar; return this; }, + + /** + * @method subtract + * @param {fabric.Point} that + * @return {fabric.Point} new Point object with subtracted values + */ subtract: function (that) { return new Point(this.x - that.x, this.y - that.y); }, + + /** + * @method subtractEquals + * @param {fabric.Point} that + * @return {fabric.Point} thisArg + */ subtractEquals: function (that) { this.x -= that.x; this.y -= that.y; return this; }, + scalarSubtract: function (scalar) { return new Point(this.x - scalar, this.y - scalar); }, + scalarSubtractEquals: function (scalar) { this.x -= scalar; this.y -= scalar; return this; }, + multiply: function (scalar) { return new Point(this.x * scalar, this.y * scalar); }, + multiplyEquals: function (scalar) { this.x *= scalar; this.y *= scalar; return this; }, + divide: function (scalar) { return new Point(this.x / scalar, this.y / scalar); }, + divideEquals: function (scalar) { this.x /= scalar; this.y /= scalar; return this; }, + eq: function (that) { return (this.x == that.x && this.y == that.y); }, + lt: function (that) { return (this.x < that.x && this.y < that.y); }, + lte: function (that) { return (this.x <= that.x && this.y <= that.y); }, + gt: function (that) { return (this.x > that.x && this.y > that.y); }, + gte: function (that) { return (this.x >= that.x && this.y >= that.y); }, + lerp: function (that, t) { return new Point(this.x + (that.x - this.x) * t, this.y + (that.y - this.y) * t); }, + distanceFrom: function (that) { var dx = this.x - that.x, dy = this.y - that.y; return Math.sqrt(dx * dx + dy * dy); }, + min: function (that) { return new Point(Math.min(this.x, that.x), Math.min(this.y, that.y)); }, + max: function (that) { return new Point(Math.max(this.x, that.x), Math.max(this.y, that.y)); }, + toString: function () { return this.x + "," + this.y; }, + setXY: function (x, y) { this.x = x; this.y = y; }, + setFromPoint: function (that) { this.x = that.x; this.y = that.y; }, + swap: function (that) { var x = this.x, y = this.y; @@ -1723,8 +1819,6 @@ fabric.util.animate = animate; } }; - fabric.Point = Point; - })(); (function() { @@ -1739,24 +1833,51 @@ fabric.util.animate = animate; return; } + /** + * @class Intersection + * @memberOf fabric + */ function Intersection(status) { if (arguments.length > 0) { this.init(status); } } - Intersection.prototype.init = function (status) { - this.status = status; - this.points = []; - }; - Intersection.prototype.appendPoint = function (point) { - this.points.push(point); - }; - Intersection.prototype.appendPoints = function (points) { - this.points = this.points.concat(points); + fabric.Intersection = Intersection; + + fabric.Intersection.prototype = /** @scope fabric.Intersection.prototype */ { + + /** + * @method init + * @param {String} status + */ + init: function (status) { + this.status = status; + this.points = []; + }, + + /** + * @method appendPoint + * @param {String} status + */ + appendPoint: function (point) { + this.points.push(point); + }, + + /** + * @method appendPoints + * @param {String} status + */ + appendPoints: function (points) { + this.points = this.points.concat(points); + } }; - Intersection.intersectLineLine = function (a1, a2, b1, b2) { + /** + * @static + * @method intersectLineLine + */ + fabric.Intersection.intersectLineLine = function (a1, a2, b1, b2) { var result, ua_t = (b2.x - b1.x) * (a1.y - b1.y) - (b2.y - b1.y) * (a1.x - b1.x), ub_t = (a2.x - a1.x) * (a1.y - b1.y) - (a2.y - a1.y) * (a1.x - b1.x), @@ -1783,7 +1904,10 @@ fabric.util.animate = animate; return result; }; - Intersection.intersectLinePolygon = function(a1,a2,points){ + /** + * @method intersectLinePolygon + */ + fabric.Intersection.intersectLinePolygon = function(a1,a2,points){ var result = new Intersection("No Intersection"), length = points.length; @@ -1800,7 +1924,10 @@ fabric.util.animate = animate; return result; }; - Intersection.intersectPolygonPolygon = function (points1, points2) { + /** + * @method intersectPolygonPolygon + */ + fabric.Intersection.intersectPolygonPolygon = function (points1, points2) { var result = new Intersection("No Intersection"), length = points1.length; @@ -1817,7 +1944,10 @@ fabric.util.animate = animate; return result; }; - Intersection.intersectPolygonRectangle = function (points, r1, r2) { + /** + * @method intersectPolygonRectangle + */ + fabric.Intersection.intersectPolygonRectangle = function (points, r1, r2) { var min = r1.min(r2), max = r1.max(r2), topRight = new fabric.Point(max.x, min.y), @@ -1838,8 +1968,6 @@ fabric.util.animate = animate; return result; }; - fabric.Intersection = Intersection; - })(); (function() { @@ -1851,10 +1979,12 @@ fabric.util.animate = animate; return; } - fabric.Color = Color; - /** - * @constructor + * The purpose of fabric.Color is to abstract and encapsulate common color operations; + * fabric.Color is a constructor and creates instances of fabric.Color objects. + * + * @class Color + * @memberOf fabric * @param {String} color (optional) in hex or rgb(a) format */ function Color(color) { @@ -1866,173 +1996,191 @@ fabric.util.animate = animate; } } - /** - * @private - * @method _tryParsingColor - */ - Color.prototype._tryParsingColor = function(color) { - var source = Color.sourceFromHex(color); - if (!source) { - source = Color.sourceFromRgb(color); - } - if (source) { + fabric.Color = Color; + + fabric.Color.prototype = /** @scope fabric.Color.prototype */ { + + /** + * @private + * @method _tryParsingColor + */ + _tryParsingColor: function(color) { + var source = Color.sourceFromHex(color); + if (!source) { + source = Color.sourceFromRgb(color); + } + if (source) { + this.setSource(source); + } + }, + + /** + * Returns source of this color (where source is an array representation; ex: [200, 200, 100, 1]) + * @method getSource + * @return {Array} + */ + getSource: function() { + return this._source; + }, + + /** + * Sets source of this color (where source is an array representation; ex: [200, 200, 100, 1]) + * @method setSource + * @param {Array} source + */ + setSource: function(source) { + this._source = source; + }, + + /** + * Returns color represenation in RGB format + * @method toRgb + * @return {String} ex: rgb(0-255,0-255,0-255) + */ + toRgb: function() { + var source = this.getSource(); + return 'rgb(' + source[0] + ',' + source[1] + ',' + source[2] + ')'; + }, + + /** + * Returns color represenation in RGBA format + * @method toRgba + * @return {String} ex: rgba(0-255,0-255,0-255,0-1) + */ + toRgba: function() { + var source = this.getSource(); + return 'rgba(' + source[0] + ',' + source[1] + ',' + source[2] + ',' + source[3] + ')'; + }, + + /** + * Returns color represenation in HEX format + * @method toHex + * @return {String} ex: FF5555 + */ + toHex: function() { + var source = this.getSource(); + + var r = source[0].toString(16); + r = (r.length == 1) ? ('0' + r) : r; + + var g = source[1].toString(16); + g = (g.length == 1) ? ('0' + g) : g; + + var b = source[2].toString(16); + b = (b.length == 1) ? ('0' + b) : b; + + return r.toUpperCase() + g.toUpperCase() + b.toUpperCase(); + }, + + /** + * Gets value of alpha channel for this color + * @method getAlpha + * @return {Number} 0-1 + */ + getAlpha: function() { + return this.getSource()[3]; + }, + + /** + * Sets value of alpha channel for this color + * @method setAlpha + * @param {Number} 0-1 + * @return {fabric.Color} thisArg + */ + setAlpha: function(alpha) { + var source = this.getSource(); + source[3] = alpha; this.setSource(source); + return this; + }, + + /** + * Transforms color to its grayscale representation + * @method toGrayscale + * @return {fabric.Color} thisArg + */ + toGrayscale: function() { + var source = this.getSource(), + average = parseInt((source[0] * 0.3 + source[1] * 0.59 + source[2] * 0.11).toFixed(0), 10), + currentAlpha = source[3]; + this.setSource([average, average, average, currentAlpha]); + return this; + }, + + /** + * Transforms color to its black and white representation + * @method toGrayscale + * @return {fabric.Color} thisArg + */ + toBlackWhite: function(threshold) { + var source = this.getSource(), + average = (source[0] * 0.3 + source[1] * 0.59 + source[2] * 0.11).toFixed(0), + currentAlpha = source[3], + threshold = threshold || 127; + + average = (Number(average) < Number(threshold)) ? 0 : 255; + this.setSource([average, average, average, currentAlpha]); + return this; + }, + + /** + * Overlays color with another color + * @method overlayWith + * @param {String|fabric.Color} otherColor + * @return {fabric.Color} thisArg + */ + overlayWith: function(otherColor) { + if (!(otherColor instanceof Color)) { + otherColor = new Color(otherColor); + } + + var result = [], + alpha = this.getAlpha(), + otherAlpha = 0.5, + source = this.getSource(), + otherSource = otherColor.getSource(); + + for (var i = 0; i < 3; i++) { + result.push(Math.round((source[i] * (1 - otherAlpha)) + (otherSource[i] * otherAlpha))); + } + + result[4] = alpha; + this.setSource(result); + return this; } - } - - /** - * @method getSource - * @return {Array} - */ - Color.prototype.getSource = function() { - return this._source; - }; - - /** - * @method setSource - * @param {Array} source - */ - Color.prototype.setSource = function(source) { - this._source = source; - }; - - /** - * @method toRgb - * @return {String} ex: rgb(0-255,0-255,0-255) - */ - Color.prototype.toRgb = function() { - var source = this.getSource(); - return 'rgb(' + source[0] + ',' + source[1] + ',' + source[2] + ')'; - }; - - /** - * @method toRgba - * @return {String} ex: rgba(0-255,0-255,0-255,0-1) - */ - Color.prototype.toRgba = function() { - var source = this.getSource(); - return 'rgba(' + source[0] + ',' + source[1] + ',' + source[2] + ',' + source[3] + ')'; - }; - - /** - * @method toHex - * @return {String} ex: FF5555 - */ - Color.prototype.toHex = function() { - var source = this.getSource(); - - var r = source[0].toString(16); - r = (r.length == 1) ? ('0' + r) : r; - - var g = source[1].toString(16); - g = (g.length == 1) ? ('0' + g) : g; - - var b = source[2].toString(16); - b = (b.length == 1) ? ('0' + b) : b; - - return r.toUpperCase() + g.toUpperCase() + b.toUpperCase(); - }; - - /** - * @method getAlpha - * @return {Number} 0-1 - */ - Color.prototype.getAlpha = function() { - return this.getSource()[3]; - }; - - /** - * @method setAlpha - * @param {Number} 0-1 - * @return {Color} thisArg - */ - Color.prototype.setAlpha = function(alpha) { - var source = this.getSource(); - source[3] = alpha; - this.setSource(source); - return this; - }; - - /** - * Transforms color to its grayscale representation - * @method toGrayscale - * @return {Color} thisArg - */ - Color.prototype.toGrayscale = function() { - var source = this.getSource(), - average = parseInt((source[0] * 0.3 + source[1] * 0.59 + source[2] * 0.11).toFixed(0), 10), - currentAlpha = source[3]; - this.setSource([average, average, average, currentAlpha]); - return this; - }; - - /** - * Transforms color to its black and white representation - * @method toGrayscale - * @return {Color} thisArg - */ - Color.prototype.toBlackWhite = function(threshold) { - var source = this.getSource(), - average = (source[0] * 0.3 + source[1] * 0.59 + source[2] * 0.11).toFixed(0), - currentAlpha = source[3], - threshold = threshold || 127; - - average = (Number(average) < Number(threshold)) ? 0 : 255; - this.setSource([average, average, average, currentAlpha]); - return this; - }; - - /** - * Overlays color with another color - * @method overlayWith - * @param {Color} otherColor - * @return {Color} thisArg - */ - Color.prototype.overlayWith = function(otherColor) { - otherColor = new Color(otherColor); - - var result = [], - alpha = this.getAlpha(), - otherAlpha = 0.5, - source = this.getSource(), - otherSource = otherColor.getSource(); - - for (var i = 0; i < 3; i++) { - result.push(Math.round((source[i] * (1 - otherAlpha)) + (otherSource[i] * otherAlpha))); - } - - result[4] = alpha; - this.setSource(result); - return this; }; /** + * Regex matching color in RGB or RGBA formats (ex: rgb(0, 0, 0), rgb(255, 100, 10, 0.5), rgb(1,1,1)) * @static - * @field reRGBa + * @field */ - Color.reRGBa = /^rgba?\((\d{1,3})\s*,\s*(\d{1,3})\s*,\s*(\d{1,3})(?:\s*,\s*(\d+(?:\.\d+)?))?\)$/; + fabric.Color.reRGBa = /^rgba?\((\d{1,3})\s*,\s*(\d{1,3})\s*,\s*(\d{1,3})(?:\s*,\s*(\d+(?:\.\d+)?))?\)$/; /** + * Regex matching color in HEX format (ex: #FF5555, 010155, aff) * @static - * @field reHex + * @field */ - Color.reHex = /^#?([0-9a-f]{6}|[0-9a-f]{3})$/i; + fabric.Color.reHex = /^#?([0-9a-f]{6}|[0-9a-f]{3})$/i; /** + * Returns new color object, when given a color in RGB format * @method fromRgb * @param {String} color ex: rgb(0-255,0-255,0-255) - * @return {Color} + * @return {fabric.Color} */ - Color.fromRgb = function(color) { + fabric.Color.fromRgb = function(color) { return Color.fromSource(Color.sourceFromRgb(color)); }; /** + * Returns array represenatation (ex: [100, 100, 200, 1]) of a color that's in RGB or RGBA format * @method sourceFromRgb * @param {String} color ex: rgb(0-255,0-255,0-255) * @return {Array} source */ - Color.sourceFromRgb = function(color) { + fabric.Color.sourceFromRgb = function(color) { var match = color.match(Color.reRGBa); if (match) { return [ @@ -2045,28 +2193,33 @@ fabric.util.animate = animate; }; /** + * Returns new color object, when given a color in RGBA format * @static + * @function * @method fromRgba - * @return {Color} + * @param {String} color + * @return {fabric.Color} */ - Color.fromRgba = Color.fromRgb; + fabric.Color.fromRgba = Color.fromRgb; /** + * Returns new color object, when given a color in HEX format * @static * @method fromHex - * @return {Color} + * @return {fabric.Color} */ - Color.fromHex = function(color) { + fabric.Color.fromHex = function(color) { return Color.fromSource(Color.sourceFromHex(color)); }; /** + * Returns array represenatation (ex: [100, 100, 200, 1]) of a color that's in HEX format * @static * @method sourceFromHex - * @param {String} ex: FF5555 + * @param {String} color ex: FF5555 * @return {Array} source */ - Color.sourceFromHex = function(color) { + fabric.Color.sourceFromHex = function(color) { if (color.match(Color.reHex)) { var value = color.slice(color.indexOf('#') + 1), isShortNotation = (value.length === 3), @@ -2084,11 +2237,12 @@ fabric.util.animate = animate; }; /** + * Returns new color object, when given color in array representation (ex: [200, 100, 100, 0.5]) * @static * @method fromSource - * @return {Color} + * @return {fabric.Color} */ - Color.fromSource = function(source) { + fabric.Color.fromSource = function(source) { var oColor = new Color(); oColor.setSource(source); return oColor; @@ -2273,9 +2427,11 @@ fabric.util.animate = animate; * @return {fabric.Element} thisArg * @chainable */ - setOverlayImage: function (url, callback) { + setOverlayImage: function (url, callback) { // TODO (kangax): test callback if (url) { var _this = this, img = new Image(); + + /** @ignore */ img.onload = function () { _this.overlayImage = img; if (callback) { @@ -2289,13 +2445,13 @@ fabric.util.animate = animate; }, /** - * canvas class's initialization method. This method is automatically - * called by constructor, and sets up all DOM references for - * pre-existing markup, and creates required markup if it is not + * Canvas class' initialization method; This method is automatically + * called by constructor, sets up all DOM references for + * pre-existing markup, and creates required markup if it is not. * already present. * @method _initElement - * @param canvasEl {HTMLElement|String} canvasEl canvas element - * + * @param {HTMLElement|String} canvasEl Canvas element + * @throws {CANVAS_INIT_ERROR} If canvas can not be initialized */ _initElement: function (canvasEl) { var el = fabric.util.getById(canvasEl); @@ -3762,6 +3918,8 @@ fabric.util.animate = animate; } else { var imgEl = new Image(); + + /** @ignore */ imgEl.onload = function () { imgEl.onload = null; @@ -3782,6 +3940,11 @@ fabric.util.animate = animate; } })(), + /** + * @method loadSVGFromURL + * @param {String} url + * @param {Function} callback + */ loadSVGFromURL: function (url, callback) { var _this = this; @@ -3980,7 +4143,7 @@ fabric.util.animate = animate; }, /** - * Removes an active object + * Removes currently active object * @method removeActiveObject * @return {fabric.Element} thisArg * @chainable @@ -3994,9 +4157,9 @@ fabric.util.animate = animate; }, /** - * Sets current group to a speicified one + * Sets active group to a speicified one * @method setActiveGroup - * @param group {fabric.Group} group to set as a current one + * @param {fabric.Group} group Group to set as a current one * @return {fabric.Element} thisArg * @chainable */ @@ -4006,7 +4169,7 @@ fabric.util.animate = animate; }, /** - * Returns current group + * Returns currently active group * @method getActiveGroup * @return {fabric.Group} Current group */ @@ -4015,7 +4178,7 @@ fabric.util.animate = animate; }, /** - * Removes current group + * Removes currently active group * @method removeActiveGroup * @return {fabric.Element} thisArg */ @@ -4028,6 +4191,7 @@ fabric.util.animate = animate; }, /** + * Returns object at specified index * @method item * @param {Number} index * @return {fabric.Object} @@ -4222,11 +4386,6 @@ fabric.util.animate = animate; (function(){ var global = this, - - /** - * @name Canvas - * @namespace - */ fabric = global.fabric || (global.fabric = { }), extend = fabric.util.object.extend, clone = fabric.util.object.clone, @@ -4241,12 +4400,14 @@ fabric.util.animate = animate; /** * @class Object - * @memberOf Canvas + * @memberOf fabric */ - fabric.Object = fabric.util.createClass({ + fabric.Object = fabric.util.createClass(/** @scope fabric.Object.prototype */ { + /** @property */ type: 'object', + /** @property */ includeDefaultValues: true, /** @@ -4269,16 +4430,13 @@ fabric.util.animate = animate; */ MIN_SCALE_LIMIT: 0.1, - /** - * @field - */ + /** @property */ stateProperties: ('top left width height scaleX scaleY flipX flipY ' + 'theta angle opacity cornersize fill overlayFill stroke ' + 'strokeWidth fillRule borderScaleFactor transformMatrix').split(' '), - /** - * @field - */ + + /** @property */ options: { top: 0, left: 0, @@ -4305,6 +4463,10 @@ fabric.util.animate = animate; transformMatrix: null }, + /** + * @method callSuper + * @param {String} methodName + */ callSuper: function(methodName) { var fn = this.constructor.superclass.prototype[methodName]; return (arguments.length > 1) @@ -4313,8 +4475,9 @@ fabric.util.animate = animate; }, /** - * @constructs - * @param options {Object} options + * Constructor + * @method initialize + * @param {Object} [options] Options object */ initialize: function(options) { this.setOptions(options); @@ -4324,6 +4487,10 @@ fabric.util.animate = animate; this.saveState(); }, + /** + * @method setOptions + * @param {Object} [options] + */ setOptions: function(options) { this.options = extend(this._getOptions(), options); }, @@ -4836,17 +5003,20 @@ fabric.util.animate = animate; cloneAsImage: function(callback) { if (fabric.Image) { var i = new Image(); + + /** @ignore */ i.onload = function() { if (callback) { callback(new fabric.Image(i), orig); } i = i.onload = null; - } + }; + var orig = { angle: this.get('angle'), flipX: this.get('flipX'), flipY: this.get('flipY') - } + }; this.set('angle', 0).set('flipX', false).set('flipY', false); i.src = this.toDataURL(); @@ -5443,25 +5613,31 @@ fabric.util.animate = animate; fabric.Object.prototype.rotate = fabric.Object.prototype.setAngle; })(); -(function(){ +(function() { var fabric = this.fabric || (this.fabric = { }), extend = fabric.util.object.extend; if (fabric.Line) { + fabric.warn('fabric.Line is already defined'); return; } - fabric.Line = fabric.util.createClass(fabric.Object, { + /** + * @class Line + * @extends fabric.Object + */ + fabric.Line = fabric.util.createClass(fabric.Object, /** @scope fabric.Line.prototype */ { + /** @property */ type: 'line', /** - * @constructor + * Constructor * @method initialize - * @param points {Array} array of points - * @param options {Object} options object - * @return {Object} thisArg + * @param {Array} points Array of points + * @param {Object} [options] Options object + * @return {fabric.Line} thisArg */ initialize: function(points, options) { if (!points) { @@ -5484,7 +5660,7 @@ fabric.util.animate = animate; /** * @private * @method _render - * @param ctx {CanvasRenderingContext2D} context to render on + * @param {CanvasRenderingContext2D} ctx Context to render on */ _render: function(ctx) { ctx.beginPath(); @@ -5507,6 +5683,7 @@ fabric.util.animate = animate; }, /** + * Returns object representation of an instance * @methd toObject * @return {Object} */ @@ -5520,14 +5697,17 @@ fabric.util.animate = animate; } }); + /** + * @see http://www.w3.org/TR/SVG/shapes.html#LineElement + */ fabric.Element.ATTRIBUTE_NAMES = 'x1 y1 x2 y2 stroke stroke-width transform'.split(' '); /** * @static * @method fabric.Line.fromElement - * @param element {SVGElement} element to parse - * @param options {Object} options object - * @return {Object} instance of fabric.Line + * @param {SVGElement} element Element to parse + * @param {Object} [options] Options object + * @return {fabric.Line} instance of fabric.Line */ fabric.Line.fromElement = function(element, options) { var parsedAttributes = fabric.parseAttributes(element, fabric.Element.ATTRIBUTE_NAMES); @@ -5543,8 +5723,8 @@ fabric.util.animate = animate; /** * @static * @method fabric.Line.fromObject - * @param object {Object} object to create an instance from - * @return {Object} instance of fabric.Line + * @param {Object} object Object to create an instance from + * @return {fabric.Line} instance of fabric.Line */ fabric.Line.fromObject = function(object) { var points = [object.x1, object.y1, object.x2, object.y2]; @@ -5563,15 +5743,16 @@ fabric.util.animate = animate; return; } - fabric.Circle = fabric.util.createClass(fabric.Object, /** @lends fabric.Circle.prototype */ { + /** + * @class Circle + * @extends fabric.Object + */ + fabric.Circle = fabric.util.createClass(fabric.Object, /** @scope fabric.Circle.prototype */ { - /** - * @field - */ + /** @property */ type: 'circle', /** - * @constructs * @method initialize * @param options {Object} options object * @return {Object} thisArg @@ -5626,11 +5807,14 @@ fabric.util.animate = animate; }); /** + * List of attribute names to account for when parsing SVG element (used by `fabric.Circle.fromElement`) + * @static * @see: http://www.w3.org/TR/SVG/shapes.html#CircleElement */ fabric.Circle.ATTRIBUTE_NAMES = 'cx cy r fill fill-opacity stroke stroke-width transform'.split(' '); /** + * Returns fabric.Circle instance from an SVG element * @static * @method fabric.Circle.fromElement * @param element {SVGElement} element to parse @@ -5661,30 +5845,36 @@ fabric.util.animate = animate; } /** + * Returns fabric.Circle instance from an object representation * @static * @method fabric.Circle.fromObject - * @param object {Object} object to create an instance from - * @return {Object} instance of fabric.Circle + * @param {Object} object Object to create an instance from + * @return {Object} Instance of fabric.Circle */ fabric.Circle.fromObject = function(object) { return new fabric.Circle(object); } })(); -(function(){ +(function() { var fabric = this.fabric || (this.fabric = { }); - if (fabric.Triangle) return; + if (fabric.Triangle) { + fabric.warn('fabric.Triangle is already defined'); + return; + } - fabric.Triangle = fabric.util.createClass(fabric.Object, { + /** + * @class Triangle + * @extends fabric.Object + */ + fabric.Triangle = fabric.util.createClass(fabric.Object, /** @scope fabric.Triangle.prototype */ { - /** - * @field - */ + /** @property */ type: 'triangle', /** - * @constructs + * Constructor * @method initialize * @param options {Object} options object * @return {Object} thisArg @@ -5701,7 +5891,7 @@ fabric.util.animate = animate; /** * @private * @method _render - * @param ctx {CanvasRenderingContext2D} context to render on + * @param ctx {CanvasRenderingContext2D} Context to render on */ _render: function(ctx) { var widthBy2 = this.width / 2, @@ -5732,6 +5922,7 @@ fabric.util.animate = animate; }); /** + * Returns fabric.Triangle instance from an object representation * @static * @method Canvas.Trangle.fromObject * @param object {Object} object to create an instance from @@ -5753,14 +5944,19 @@ fabric.util.animate = animate; return; } - fabric.Ellipse = fabric.util.createClass(fabric.Object, { + /** + * @class Ellipse + * @extends fabric.Object + */ + fabric.Ellipse = fabric.util.createClass(fabric.Object, /** @scope fabric.Ellipse.prototype */ { + /** @property */ type: 'ellipse', /** - * @constructor + * Constructor * @method initialize - * @param options {Object} options object + * @param {Object} [options] Options object * @return {Object} thisArg */ initialize: function(options) { @@ -5828,11 +6024,12 @@ fabric.util.animate = animate; fabric.Ellipse.ATTRIBUTE_NAMES = 'cx cy rx ry fill fill-opacity stroke stroke-width transform'.split(' '); /** + * Returns fabric.Ellipse instance from an SVG element * @static * @method fabric.Ellipse.fromElement - * @param element {SVGElement} element to parse - * @param options {Object} options object - * @return {Object} instance of fabric.Ellipse + * @param {SVGElement} element Element to parse + * @param {Object} [options] Options object + * @return {fabric.Ellipse} */ fabric.Ellipse.fromElement = function(element, options) { options || (options = { }); @@ -5847,21 +6044,23 @@ fabric.util.animate = animate; }; /** + * Returns fabric.Ellipse instance from an object representation * @static * @method fabric.Ellipse.fromObject - * @param object {Object} object to create an instance from - * @return {Object} instance of fabric.Ellipse + * @param {Object} object Object to create an instance from + * @return {fabric.Ellipse} */ fabric.Ellipse.fromObject = function(object) { return new fabric.Ellipse(object); } })(); -(function(){ +(function() { var fabric = this.fabric || (this.fabric = { }); if (fabric.Rect) { + console.warn('fabric.Rect is already defined'); return; } @@ -5869,17 +6068,19 @@ fabric.util.animate = animate; * @class Rect * @extends fabric.Object */ - fabric.Rect = fabric.util.createClass(fabric.Object, /** @lends fabric.Rect.prototype */ { + fabric.Rect = fabric.util.createClass(fabric.Object, /** @scope fabric.Rect.prototype */ { + /** @property */ type: 'rect', + /** @property */ options: { rx: 0, ry: 0 }, /** - * @constructs + * Constructor * @method initialize * @param options {Object} options object * @return {Object} thisArg @@ -5970,7 +6171,7 @@ fabric.util.animate = animate; * @method fabric.Rect.fromElement * @param element {SVGElement} element to parse * @param options {Object} options object - * @return {Object} instance of fabric.Rect + * @return {fabric.Rect} instance of fabric.Rect */ fabric.Rect.fromElement = function(element, options) { if (!element) { @@ -5997,7 +6198,7 @@ fabric.util.animate = animate; }; })(); -(function(){ +(function() { var fabric = this.fabric || (this.fabric = { }); @@ -6006,15 +6207,20 @@ fabric.util.animate = animate; return; } - fabric.Polyline = fabric.util.createClass(fabric.Object, { + /** + * @class Polyline + * @extends fabric.Object + */ + fabric.Polyline = fabric.util.createClass(fabric.Object, /** @scope fabric.Polyline.prototype */ { + /** @property */ type: 'polyline', /** - * @constructor + * Constructor * @method initialize - * @param points {Array} array of points - * @param options {Object} options object + * @param {Array} points array of points + * @param {Object} [options] Options object * @return {Object} thisArg */ initialize: function(points, options) { @@ -6035,7 +6241,7 @@ fabric.util.animate = animate; /** * Returns object representation of an instance * @method toObject - * @return {Object} object representation of an instance + * @return {Object} Object representation of an instance */ toObject: function() { return fabric.Polygon.prototype.toObject.call(this); @@ -6044,7 +6250,7 @@ fabric.util.animate = animate; /** * @private * @method _render - * @param ctx {CanvasRenderingContext2D} context to render on + * @param {CanvasRenderingContext2D} ctx Context to render on */ _render: function(ctx) { var point; @@ -6062,6 +6268,7 @@ fabric.util.animate = animate; }, /** + * Returns complexity of an instance * @method complexity * @return {Number} complexity */ @@ -6070,13 +6277,19 @@ fabric.util.animate = animate; } }); + /** + * List of attribute names to account for when parsing SVG element (used by `fabric.Polyline.fromElement`) + * @static + * @see: http://www.w3.org/TR/SVG/shapes.html#PolylineElement + */ var ATTRIBUTE_NAMES = 'fill fill-opacity stroke stroke-width transform'.split(' '); /** + * Returns fabric.Polyline instance from an SVG element * @static * @method fabric.Polyline.fromElement - * @param element {SVGElement} element to parse - * @param options {Object} options object + * @param {SVGElement} element Element to parse + * @param {Object} [options] Options object * @return {Object} instance of fabric.Polyline */ fabric.Polyline.fromElement = function(element, options) { @@ -6097,18 +6310,20 @@ fabric.util.animate = animate; }; /** + * Returns fabric.Polyline instance from an object representation * @static * @method fabric.Polyline.fromObject - * @param object {Object} object to create an instance from - * @return {Object} instance of fabric.Polyline + * @param {Object} [object] Object to create an instance from + * @return {fabric.Polyline} */ fabric.Polyline.fromObject = function(object) { var points = object.points; return new fabric.Polyline(points, object); - } + }; + })(); -(function(){ +(function() { var fabric = this.fabric || (this.fabric = { }), extend = fabric.util.object.extend, @@ -6123,16 +6338,21 @@ fabric.util.animate = animate; function byX(p) { return p.x; } function byY(p) { return p.y; } - fabric.Polygon = fabric.util.createClass(fabric.Object, { + /** + * @class Polygon + * @extends fabric.Object + */ + fabric.Polygon = fabric.util.createClass(fabric.Object, /** @scope fabric.Polygon.prototype */ { + /** @property */ type: 'polygon', /** - * @constructor + * Constructor * @method initialize - * @param points {Array} array of points - * @param options {Object} options object - * @return thisArg + * @param {Array} points Array of points + * @param {Object} options Options object + * @return {fabric.Polygon} thisArg */ initialize: function(points, options) { options = options || { }; @@ -6201,14 +6421,20 @@ fabric.util.animate = animate; } }); + /** + * List of attribute names to account for when parsing SVG element (used by `fabric.Polygon.fromElement`) + * @static + * @see: http://www.w3.org/TR/SVG/shapes.html#PolygonElement + */ fabric.Polygon.ATTRIBUTE_NAMES = 'fill fill-opacity stroke stroke-width transform'.split(' '); /** + * Returns fabric.Polygon instance from an SVG element * @static * @method fabric.Polygon.fromElement - * @param element {SVGElement} element to parse - * @param options {Object} options object - * @return {Object} instance of fabric.Polygon + * @param {SVGElement} element Element to parse + * @param {Object} options Options object + * @return {fabric.Polygon} */ fabric.Polygon.fromElement = function(element, options) { if (!element) { @@ -6228,10 +6454,11 @@ fabric.util.animate = animate; }; /** + * Returns fabric.Polygon instance from an object representation * @static * @method fabric.Polygon.fromObject - * @param object {Object} object to create an instance from - * @return {Object} instance of fabric.Polygon + * @param {Object} object Object to create an instance from + * @return {fabric.Polygon} */ fabric.Polygon.fromObject = function(object) { return new fabric.Polygon(object.points, object); @@ -6255,15 +6482,40 @@ fabric.util.animate = animate; return; } - fabric.Path = fabric.util.createClass(fabric.Object, { + /** + * @private + */ + function getX(item) { + if (item[0] === 'H') { + return item[1]; + } + return item[item.length - 2]; + } + /** + * @private + */ + function getY(item) { + if (item[0] === 'V') { + return item[1]; + } + return item[item.length - 1]; + } + + /** + * @class Path + * @extends fabric.Object + */ + fabric.Path = fabric.util.createClass(fabric.Object, /** @scope fabric.Path.prototype */ { + + /** @property */ type: 'path', /** - * @constructor - * @param path {Array | String} path data - * (i.e. sequence of coordinates and corresponding "command" tokens) - * @param options {Object} options object + * Constructor + * @method initialize + * @param {Array|String} path Path data (sequence of coordinates and corresponding "command" tokens) + * @param {Object} [options] Options object */ initialize: function(path, options) { options = options || { }; @@ -6573,6 +6825,11 @@ fabric.util.animate = animate; return o; }, + /** + * Returns number representation of an instance complexity + * @method complexity + * @return {Number} complexity + */ complexity: function() { return this.path.length; }, @@ -6595,6 +6852,9 @@ fabric.util.animate = animate; return result; }, + /** + * @method _parseDimensions + */ _parseDimensions: function() { var aX = [], aY = [], @@ -6603,18 +6863,7 @@ fabric.util.animate = animate; isLowerCase = false, x, y; - function getX(item) { - if (item[0] === 'H') { - return item[1]; - } - return item[item.length - 2]; - } - function getY(item) { - if (item[0] === 'V') { - return item[1]; - } - return item[item.length - 1]; - } + this.path.forEach(function(item, i) { if (item[0] !== 'H') { previousX = (i === 0) ? getX(item) : getX(this.path[i-1]); @@ -6710,11 +6959,25 @@ fabric.util.animate = animate; return; } - fabric.PathGroup = fabric.util.createClass(fabric.Path, { + /** + * @class PathGroup + * @extends fabric.Path + */ + fabric.PathGroup = fabric.util.createClass(fabric.Path, /** @scope fabric.PathGroup.prototype */ { + /** @property */ type: 'path-group', + + /** @property */ forceFillOverwrite: false, + /** + * Constructor + * @method initialize + * @param {Array} paths + * @param {Object} [options] Options object + * @return {fabric.PathGroup} thisArg + */ initialize: function(paths, options) { options = options || { }; @@ -6915,16 +7178,20 @@ fabric.util.animate = animate; return; } - fabric.Group = fabric.util.createClass(fabric.Object, { + /** + * @class Group + * @extends fabric.Object + */ + fabric.Group = fabric.util.createClass(fabric.Object, /** @scope fabric.Group.prototype */ { - /** - * @property type - */ + /** @property */ type: 'group', /** - * @constructor + * Constructor + * @method initialized * @param {Object} objects Group objects + * @param {Object} [options] Options object * @return {Object} thisArg */ initialize: function(objects, options) { @@ -6973,6 +7240,7 @@ fabric.util.animate = animate; }, /** + * Returns string represenation of a group * @method toString * @return {String} */ @@ -6981,6 +7249,7 @@ fabric.util.animate = animate; }, /** + * Returns an array of all objects in this group * @method getObjects * @return {Array} group objects */ @@ -6989,10 +7258,10 @@ fabric.util.animate = animate; }, /** - * Adds an object to a group. Recalculates group's dimension, position. + * Adds an object to a group; Then recalculates group's dimension, position. * @method add * @param {Object} object - * @return {Object} thisArg + * @return {fabric.Group} thisArg * @chainable */ add: function(object) { @@ -7005,9 +7274,9 @@ fabric.util.animate = animate; }, /** - * Removes an object from a group. Recalculates group's dimension, position. + * Removes an object from a group; Then recalculates group's dimension, position. * @param {Object} object - * @return {Object} thisArg + * @return {fabric.Group} thisArg * @chainable */ remove: function(object) { @@ -7020,7 +7289,7 @@ fabric.util.animate = animate; }, /** - * Returns a size of a group (i.e. length of an array containing its objects) + * Returns a size of a group (i.e: length of an array containing its objects) * @return {Number} Group size */ size: function() { @@ -7031,8 +7300,8 @@ fabric.util.animate = animate; * Sets property to a given value * @method set * @param {String} name - * @param {Object | Function} value - * @return {Object} thisArg + * @param {Object|Function} value + * @return {fabric.Group} thisArg * @chainable */ set: function(name, value) { @@ -7058,7 +7327,7 @@ fabric.util.animate = animate; * Returns true if a group contains an object * @method contains * @param {Object} object Object to check against - * @return {Boolean} true if group contains an object + * @return {Boolean} `true` if group contains an object */ contains: function(object) { return this.objects.indexOf(object) > -1; @@ -7078,7 +7347,7 @@ fabric.util.animate = animate; /** * Renders instance on a given context * @method render - * @param ctx {CanvasRenderingContext2D} context to render instance on + * @param {CanvasRenderingContext2D} ctx context to render instance on */ render: function(ctx) { ctx.save(); @@ -7099,6 +7368,7 @@ fabric.util.animate = animate; }, /** + * Returns object from the group at the specified index * @method item * @param index {Number} index of item to get * @return {fabric.Object} @@ -7108,6 +7378,7 @@ fabric.util.animate = animate; }, /** + * Returns complexity of an instance * @method complexity * @return {Number} complexity */ @@ -7119,7 +7390,7 @@ fabric.util.animate = animate; }, /** - * Retores original state of each of group objects + * Retores original state of each of group objects (original state is that which was before group was created). * @private * @method _restoreObjectsState * @return {fabric.Group} thisArg @@ -7131,9 +7402,11 @@ fabric.util.animate = animate; }, /** + * Restores original state of a specified object in group * @private * @method _restoreObjectState * @param {fabric.Object} object + * @return {fabric.Group} thisArg */ _restoreObjectState: function(object) { @@ -7162,6 +7435,7 @@ fabric.util.animate = animate; }, /** + * Destroys a group (restoring state of its objects) * @method destroy * @return {fabric.Group} thisArg * @chainable @@ -7181,6 +7455,10 @@ fabric.util.animate = animate; return this; }, + /** + * @method hasMoved + * @return {Boolean} true if an object was moved (since fabric.Group#saveCoords was called) + */ hasMoved: function() { return this._originalLeft !== this.get('left') || this._originalTop !== this.get('top'); @@ -7210,6 +7488,7 @@ fabric.util.animate = animate; }, /** + * Activates (makes active) all group objects * @method setActive * @param {Boolean} value `true` to activate object, `false` otherwise * @return {fabric.Group} thisArg @@ -7231,9 +7510,9 @@ fabric.util.animate = animate; * Callback is invoked in a context of Global Object (e.g. `window`) * when no `context` argument is given * - * @param {Object} context a.k.a. thisObject + * @param {Object} context Context (aka thisObject) * - * @return {fabric.Group} + * @return {fabric.Group} thisArg * @chainable */ forEachObject: function(callback, context) { @@ -7336,7 +7615,7 @@ fabric.util.animate = animate; })(); -(function(){ +(function() { var fabric = this.fabric || (this.fabric = { }), extend = fabric.util.object.extend, @@ -7351,8 +7630,13 @@ fabric.util.animate = animate; return; } - fabric.Text = fabric.util.createClass(fabric.Object, { + /** + * @class Text + * @extends fabric.Object + */ + fabric.Text = fabric.util.createClass(fabric.Object, /** @scope fabric.Text.prototype */ { + /** @property */ options: { top: 10, left: 10, @@ -7362,8 +7646,16 @@ fabric.util.animate = animate; path: null }, + /** @property */ type: 'text', + /** + * Constructor + * @method initialize + * @param {String} text + * @param {Object} [options] + * @return {fabric.Text} thisArg + */ initialize: function(text, options) { this.originalState = { }; this.initStateProperties(); @@ -7375,6 +7667,9 @@ fabric.util.animate = animate; this.setCoords(); }, + /** + * @method initStateProperties + */ initStateProperties: function() { var o; if ((o = this.constructor) && @@ -7387,11 +7682,21 @@ fabric.util.animate = animate; } }, + /** + * Returns string representation of an instance + * @method toString + * @return {String} String representation of text object + */ toString: function() { return '#'; }, + /** + * @private + * @method _render + * @param {CanvasRenderingContext2D} ctx Context to render on + */ _render: function(context) { var o = Cufon.textOptions || (Cufon.textOptions = { }); @@ -7413,6 +7718,10 @@ fabric.util.animate = animate; this.height = o.height; }, + /** + * @private + * @method _initDummyElement + */ _initDummyElement: function() { var el = document.createElement('div'); el.innerHTML = this.text; @@ -7428,6 +7737,10 @@ fabric.util.animate = animate; return el; }, + /** + * @method render + * @param ctx {CanvasRenderingContext2D} context to render on + */ render: function(context) { context.save(); this._render(context); @@ -7440,7 +7753,7 @@ fabric.util.animate = animate; /** * @method toObject - * @return {Object} object representation of an instance + * @return {Object} Object representation of text object */ toObject: function() { return extend(this.callSuper('toObject'), { @@ -7484,9 +7797,11 @@ fabric.util.animate = animate; }, /** + * Sets text of an instance, and updates its coordinates * @method setText * @param {String} value * @return {fabric.Text} thisArg + * @chainable */ setText: function(value) { this.set('text', value); @@ -7494,6 +7809,14 @@ fabric.util.animate = animate; return this; }, + /** + * Sets specified property to a specified value + * @method set + * @param {String} name + * @param {Any} value + * @return {fabric.Text} thisArg + * @chainable + */ set: function(name, value) { this[name] = value; if (name === 'fontfamily') { @@ -7504,6 +7827,7 @@ fabric.util.animate = animate; }); /** + * Returns fabric.Text instance from an object representation * @static * @method fromObject * @param {Object} object to create an instance from @@ -7542,22 +7866,34 @@ fabric.util.animate = animate; return; } + /** + * @class Image + * @extends fabric.Object + */ + fabric.Image = fabric.util.createClass(fabric.Object, /** @scope fabric.Image.prototype */ { - fabric.Image = fabric.util.createClass(fabric.Object, { - + /** @property */ maxwidth: null, + + /** @property */ maxheight: null, + + /** @property */ active: false, + /** @property */ bordervisibility: false, + + /** @property */ cornervisibility: false, + /** @property */ type: 'image', __isGrayscaled: false, /** - * @constructor + * Constructor * @param {HTMLImageElement | String} element Image element * @param {Object} options optional */ @@ -7568,6 +7904,7 @@ fabric.util.animate = animate; }, /** + * Returns image element which this instance if based on * @method getElement * @return {HTMLImageElement} image element */ @@ -7576,8 +7913,11 @@ fabric.util.animate = animate; }, /** + * Sets image element for this instance to a specified one * @method setElement + * @param {HTMLImageElement} element * @return {fabric.Image} thisArg + * @chainable */ setElement: function(element) { this._element = element; @@ -7585,12 +7925,12 @@ fabric.util.animate = animate; }, /** - * Method that resizes an image depending on whether maxwidth and maxheight are set up. + * Resizes an image depending on whether maxwidth and maxheight are set up; * Width and height have to mantain the same proportion in the final image as it was in the initial one. * @method getNormalizedSize * @param {Object} oImg - * @param {Number} maxwidth maximum width of the image in px - * @param {Number} maxheight maximum height of the image in px + * @param {Number} maxwidth maximum width of the image (in px) + * @param {Number} maxheight maximum height of the image (in px) */ getNormalizedSize: function(oImg, maxwidth, maxheight) { if (maxheight && maxwidth && (oImg.width > oImg.height && (oImg.width / oImg.height) < (maxwidth / maxheight))) { @@ -7617,6 +7957,7 @@ fabric.util.animate = animate; }, /** + * Returns original size of an image * @method getOriginalSize * @return {Object} object with "width" and "height" properties */ @@ -7629,24 +7970,29 @@ fabric.util.animate = animate; }, /** + * Sets border visibility * @method setBorderVisibility - * @param showBorder {Boolean} when true, border is being set visible + * @param {Boolean} visible When true, border is set to be visible */ - setBorderVisibility: function(showBorder) { + setBorderVisibility: function(visible) { this._resetWidthHeight(); this._adjustWidthHeightToBorders(showBorder); this.setCoords(); }, /** + * Sets corner visibility * @method setCornersVisibility + * @param {Boolean} visible When true, corners are set to be visible */ setCornersVisibility: function(visible) { this.cornervisibility = !!visible; }, /** + * Renders image on a specified context * @method render + * @param {CanvasRenderingContext2D} ctx Context to render on */ render: function(ctx, noTransform) { ctx.save(); @@ -7662,8 +8008,9 @@ fabric.util.animate = animate; }, /** + * Returns object representation of an instance * @method toObject - * @return {Object} object representation of an instance + * @return {Object} Object representation of an instance */ toObject: function() { return extend(this.callSuper('toObject'), { @@ -7672,30 +8019,34 @@ fabric.util.animate = animate; }, /** + * Returns source of an image * @method getSrc - * @return {String} source of an image + * @return {String} Source of an image */ getSrc: function() { return this.getElement().src; }, /** + * Returns string representation of an instance * @method toString - * @return {String} string representation of an instance + * @return {String} String representation of an instance */ toString: function() { return '#'; }, /** + * Returns a clone of an instance * @mthod clone - * @param {Function} callback + * @param {Function} callback Callback is invoked with a clone as a first argument */ clone: function(callback) { this.constructor.fromObject(this.toObject(), callback); }, /** + * Makes image grayscale * @mthod toGrayscale * @param {Function} callback */ @@ -7716,6 +8067,7 @@ fabric.util.animate = animate; canvasEl.getContext('2d').drawImage(imgEl, 0, 0); fabric.Element.toGrayscale(canvasEl); + /** @ignore */ replacement.onload = function() { _this.setElement(replacement); callback && callback(); @@ -7811,26 +8163,29 @@ fabric.util.animate = animate; this.height = (this.getElement().height || 0) + sidesBorderWidth; }, + /** + * Returns complexity of an instance + * @method complexity + * @return {Number} complexity + */ complexity: function() { return 1; } }); /** - * Constant for the default CSS class name that represents a Canvas - * @property fabric.Image.CSS_CANVAS + * Default CSS class name for canvas * @static - * @final * @type String */ fabric.Image.CSS_CANVAS = "canvas-img"; /** * Creates an instance of fabric.Image from its object representation + * @static * @method fromObject * @param object {Object} * @param callback {Function} optional - * @static */ fabric.Image.fromObject = function(object, callback) { var img = document.createElement('img'), @@ -7842,6 +8197,8 @@ fabric.util.animate = animate; if (object.height) { img.height = object.height; } + + /** @ignore */ img.onload = function() { if (callback) { callback(new fabric.Image(img, object)); @@ -7853,14 +8210,16 @@ fabric.util.animate = animate; /** * Creates an instance of fabric.Image from an URL string - * @method fromURL - * @param url {String} - * @param callback {Function} optional - * @param imgOptions {Object} optional * @static + * @method fromURL + * @param {String} url URL to create an image from + * @param {Function} [callback] Callback to invoke when image is created (newly created image is passed as a first argument) + * @param {Object} [imgOptions] Options object */ fabric.Image.fromURL = function(url, callback, imgOptions) { var img = document.createElement('img'); + + /** @ignore */ img.onload = function() { if (callback) { callback(new fabric.Image(img, imgOptions)); diff --git a/dist/all.min.js b/dist/all.min.js index 77374de8..c38367cf 100644 --- a/dist/all.min.js +++ b/dist/all.min.js @@ -1,167 +1,168 @@ var fabric=fabric||{version:0.1};fabric.log=function(){};fabric.warn=function(){};if(typeof console!=="undefined"){if(typeof console.log!=="undefined"&&console.log.apply)fabric.log=function(){return console.log.apply(console,arguments)};if(typeof console.warn!=="undefined"&&console.warn.apply)fabric.warn=function(){return console.warn.apply(console,arguments)}}if(!this.JSON)this.JSON={}; -(function(){function h(g){return g<10?"0"+g:g}function p(g){o.lastIndex=0;return o.test(g)?'"'+g.replace(o,function(m){var q=a[m];return typeof q==="string"?q:"\\u"+("0000"+m.charCodeAt(0).toString(16)).slice(-4)})+'"':'"'+g+'"'}function e(g,m){var q,r,u,v,A=d,w,s=m[g];if(s&&typeof s==="object"&&typeof s.toJSON==="function")s=s.toJSON(g);if(typeof b==="function")s=b.call(m,g,s);switch(typeof s){case "string":return p(s);case "number":return isFinite(s)?String(s):"null";case "boolean":case "null":return String(s); -case "object":if(!s)return"null";d+=c;w=[];if(Object.prototype.toString.apply(s)==="[object Array]"){v=s.length;for(q=0;q>>0;c=Number(c)||0;c=Math[c<0?"ceil":"floor"](c);if(c<0)c+=a;for(;c>>0;a>>0;b>>0;a>>0;a>>0;g>>0,a=0,b;if(arguments.length>1)b=arguments[1];else{do{if(a in this){b=this[a++];break}if(++a>=c)throw new TypeError;}while(1)}for(;a=b)b=d[a][c]}else for(;a--;)if(d[a]>=b)b=d[a];return b}};e.util.object={extend:h,clone:function(d){return h({},d)}};if(!String.prototype.trim)String.prototype.trim=function(){return this.replace(/^[\s\xA0]+/, -"").replace(/[\s\xA0]+$/,"")};e.util.string={camelize:function(d){return d.replace(/-+(.)?/g,function(c,a){return a?a.toUpperCase():""})},capitalize:function(d){return d.charAt(0).toUpperCase()+d.slice(1).toLowerCase()}};if(!Function.prototype.bind)Function.prototype.bind=function(d){var c=this,a=l.call(arguments,1);return a.length?function(){return o.call(c,d,a.concat(l.call(arguments)))}:function(){return o.call(c,d,arguments)}};(function(){function d(){}var c;c=function(){for(var a in{toString:1})if(a=== -"toString")return false;return true}()?function(a,b){if(b.toString!==Object.prototype.toString)a.prototype.toString=b.toString;if(b.valueOf!==Object.prototype.valueOf)a.prototype.valueOf=b.valueOf;for(var g in b)a.prototype[g]=b[g]}:function(a,b){for(var g in b)a.prototype[g]=b[g]};e.util.createClass=function(){function a(){this.initialize.apply(this,arguments)}var b=null,g=l.call(arguments,0);if(typeof g[0]==="function")b=g.shift();a.superclass=b;a.subclasses=[];if(b){d.prototype=b.prototype;a.prototype= -new d;b.subclasses.push(a)}b=0;for(var m=g.length;b=0.9999?"":"alpha(opacity="+m*100+")";q.filter=q.filter.replace(a,m)}else q.filter+=" alpha(opacity="+m*100+")";return g};e.util.setStyle=function(g,m){var q=g.style;if(typeof m==="string"){g.style.cssText+=";"+m;return m.indexOf("opacity")>-1?b(g,m.match(/opacity:\s*(\d?\.?\d*)/)[1]): -g}for(var r in m)if(r==="opacity")b(g,m[r]);else q[r==="float"||r==="cssFloat"?typeof q.styleFloat==="undefined"?"cssFloat":"styleFloat":r]=m[r];return g}})();(function(){var d=document.documentElement.style,c="userSelect"in d?"userSelect":"MozUserSelect"in d?"MozUserSelect":"WebkitUserSelect"in d?"WebkitUserSelect":"KhtmlUserSelect"in d?"KhtmlUserSelect":"";e.util.makeElementUnselectable=function(a){if(typeof a.onselectstart!=="undefined")a.onselectstart=e.util.falseFunction;if(c)a.style[c]="none"; -else if(typeof a.unselectable=="string")a.unselectable="on";return a}})();(function(){function d(a,b){c.load(a);b()}e.util.getScript=function(a,b){var g=document.getElementsByTagName("head")[0],m=document.createElement("script"),q=true;m.type="text/javascript";m.setAttribute("runat","server");m.onload=m.onreadystatechange=function(r){if(q)if(!(typeof this.readyState=="string"&&this.readyState!=="loaded"&&this.readyState!=="complete")){q=false;b(r||window.event);m=m.onload=m.onreadystatechange=null}}; -m.src=a;g.appendChild(m)};var c=this.Jaxer;if(c&&c.load)e.util.getScript=d})();e.util.getById=function(d){return typeof d==="string"?document.getElementById(d):d};e.util.toArray=function(d){for(var c=[],a=d.length;a--;)c[a]=d[a];return c};e.util.makeElement=p;e.util.addClass=function(d,c){if((" "+d.className+" ").indexOf(" "+c+" ")===-1)d.className+=(d.className?" ":"")+c};e.util.wrapElement=function(d,c,a){if(typeof c==="string")c=p(c,a);d.parentNode&&d.parentNode.replaceChild(c,d);c.appendChild(d); -return c};e.util.getElementOffset=function(d){var c=0,a=0;do{c+=d.offsetTop||0;a+=d.offsetLeft||0;d=d.offsetParent}while(d);return{left:a,top:c}};e.util.animate=function(d){d||(d={});var c=+new Date,a=d.duration||500,b=c+a,g,m,q=d.onChange||function(){},r=d.easing||function(s){return-Math.cos(s*Math.PI)/2+0.5},u="startValue"in d?d.startValue:0,v="endValue"in d?d.endValue:100,A=u>v;d.onStart&&d.onStart();var w=setInterval(function(){g=+new Date;m=g>b?1:(g-c)/a;q(A?u-(u-v)*r(m):u+(v-u)*r(m));if(g>b){clearInterval(w); -d.onComplete&&d.onComplete()}},10)};(function(){function d(){}var c=function(){for(var a=[function(){return new ActiveXObject("Microsoft.XMLHTTP")},function(){return new ActiveXObject("Msxml2.XMLHTTP")},function(){return new ActiveXObject("Msxml2.XMLHTTP.3.0")},function(){return new XMLHttpRequest}],b=a.length;b--;)try{if(a[b]())return a[b]}catch(g){}}();e.util.request=function(a,b){b||(b={});var g=b.method?b.method.toUpperCase():"GET",m=b.onComplete||function(){},q=c(),r;q.onreadystatechange=function(){if(q.readyState=== -4){m(q);q.onreadystatechange=d}};if(g==="GET"){r=null;if(typeof b.parameters=="string")a=a+(/\?/.test(a)?"&":"?")+b.parameters}q.open(g,a,true);if(g==="POST"||g==="PUT")q.setRequestHeader("Content-Type","application/x-www-form-urlencoded");q.send(r);return q}})()})(this); -(function(){var h=this.fabric||(this.fabric={}),p=h.util.object.extend,e=h.util.string.capitalize,l=h.util.object.clone,o={cx:"left",x:"left",cy:"top",y:"top",r:"radius","fill-opacity":"opacity","fill-rule":"fillRule","stroke-width":"strokeWidth",transform:"transformMatrix"};h.parseTransformAttribute=function(){function d(q,r){var u=r[0];q[0]=Math.cos(u);q[1]=Math.sin(u);q[2]=-Math.sin(u);q[3]=Math.cos(u)}function c(q,r){var u=r.length===2?r[1]:r[0];q[0]=r[0];q[3]=u}function a(q,r){q[4]=r[0];if(r.length=== -2)q[5]=r[1]}var b=[1,0,0,1,0,0],g=RegExp("^\\s*(?:(?:(?:(?:(matrix)\\s*\\(\\s*((?:[-+]?\\d+(?:\\.\\d+)?(?:e[-+]?\\d+)?))(?:\\s+,?\\s*|,\\s*)((?:[-+]?\\d+(?:\\.\\d+)?(?:e[-+]?\\d+)?))(?:\\s+,?\\s*|,\\s*)((?:[-+]?\\d+(?:\\.\\d+)?(?:e[-+]?\\d+)?))(?:\\s+,?\\s*|,\\s*)((?:[-+]?\\d+(?:\\.\\d+)?(?:e[-+]?\\d+)?))(?:\\s+,?\\s*|,\\s*)((?:[-+]?\\d+(?:\\.\\d+)?(?:e[-+]?\\d+)?))(?:\\s+,?\\s*|,\\s*)((?:[-+]?\\d+(?:\\.\\d+)?(?:e[-+]?\\d+)?))\\s*\\))|(?:(translate)\\s*\\(\\s*((?:[-+]?\\d+(?:\\.\\d+)?(?:e[-+]?\\d+)?))(?:(?:\\s+,?\\s*|,\\s*)((?:[-+]?\\d+(?:\\.\\d+)?(?:e[-+]?\\d+)?)))?\\s*\\))|(?:(scale)\\s*\\(\\s*((?:[-+]?\\d+(?:\\.\\d+)?(?:e[-+]?\\d+)?))(?:(?:\\s+,?\\s*|,\\s*)((?:[-+]?\\d+(?:\\.\\d+)?(?:e[-+]?\\d+)?)))?\\s*\\))|(?:(rotate)\\s*\\(\\s*((?:[-+]?\\d+(?:\\.\\d+)?(?:e[-+]?\\d+)?))(?:(?:\\s+,?\\s*|,\\s*)((?:[-+]?\\d+(?:\\.\\d+)?(?:e[-+]?\\d+)?))(?:\\s+,?\\s*|,\\s*)((?:[-+]?\\d+(?:\\.\\d+)?(?:e[-+]?\\d+)?)))?\\s*\\))|(?:(skewX)\\s*\\(\\s*((?:[-+]?\\d+(?:\\.\\d+)?(?:e[-+]?\\d+)?))\\s*\\))|(?:(skewY)\\s*\\(\\s*((?:[-+]?\\d+(?:\\.\\d+)?(?:e[-+]?\\d+)?))\\s*\\)))(?:(?:\\s+,?\\s*|,\\s*)(?:(?:(matrix)\\s*\\(\\s*((?:[-+]?\\d+(?:\\.\\d+)?(?:e[-+]?\\d+)?))(?:\\s+,?\\s*|,\\s*)((?:[-+]?\\d+(?:\\.\\d+)?(?:e[-+]?\\d+)?))(?:\\s+,?\\s*|,\\s*)((?:[-+]?\\d+(?:\\.\\d+)?(?:e[-+]?\\d+)?))(?:\\s+,?\\s*|,\\s*)((?:[-+]?\\d+(?:\\.\\d+)?(?:e[-+]?\\d+)?))(?:\\s+,?\\s*|,\\s*)((?:[-+]?\\d+(?:\\.\\d+)?(?:e[-+]?\\d+)?))(?:\\s+,?\\s*|,\\s*)((?:[-+]?\\d+(?:\\.\\d+)?(?:e[-+]?\\d+)?))\\s*\\))|(?:(translate)\\s*\\(\\s*((?:[-+]?\\d+(?:\\.\\d+)?(?:e[-+]?\\d+)?))(?:(?:\\s+,?\\s*|,\\s*)((?:[-+]?\\d+(?:\\.\\d+)?(?:e[-+]?\\d+)?)))?\\s*\\))|(?:(scale)\\s*\\(\\s*((?:[-+]?\\d+(?:\\.\\d+)?(?:e[-+]?\\d+)?))(?:(?:\\s+,?\\s*|,\\s*)((?:[-+]?\\d+(?:\\.\\d+)?(?:e[-+]?\\d+)?)))?\\s*\\))|(?:(rotate)\\s*\\(\\s*((?:[-+]?\\d+(?:\\.\\d+)?(?:e[-+]?\\d+)?))(?:(?:\\s+,?\\s*|,\\s*)((?:[-+]?\\d+(?:\\.\\d+)?(?:e[-+]?\\d+)?))(?:\\s+,?\\s*|,\\s*)((?:[-+]?\\d+(?:\\.\\d+)?(?:e[-+]?\\d+)?)))?\\s*\\))|(?:(skewX)\\s*\\(\\s*((?:[-+]?\\d+(?:\\.\\d+)?(?:e[-+]?\\d+)?))\\s*\\))|(?:(skewY)\\s*\\(\\s*((?:[-+]?\\d+(?:\\.\\d+)?(?:e[-+]?\\d+)?))\\s*\\))))*)?)\\s*$"), +(function(){function l(d){return d<10?"0"+d:d}function n(d){p.lastIndex=0;return p.test(d)?'"'+d.replace(p,function(m){var q=a[m];return typeof q==="string"?q:"\\u"+("0000"+m.charCodeAt(0).toString(16)).slice(-4)})+'"':'"'+d+'"'}function c(d,m){var q,r,v,w,x=g,s,t=m[d];if(t&&typeof t==="object"&&typeof t.toJSON==="function")t=t.toJSON(d);if(typeof b==="function")t=b.call(m,d,t);switch(typeof t){case "string":return n(t);case "number":return isFinite(t)?String(t):"null";case "boolean":case "null":return String(t); +case "object":if(!t)return"null";g+=f;s=[];if(Object.prototype.toString.apply(t)==="[object Array]"){w=t.length;for(q=0;q>>0;f=Number(f)||0;f=Math[f<0?"ceil":"floor"](f);if(f<0)f+=a;for(;f>>0;a>>0;b>>0;a>>0;a>>0;d>>0,a=0,b;if(arguments.length>1)b=arguments[1];else{do{if(a in this){b=this[a++];break}if(++a>=f)throw new TypeError;}while(1)}for(;a=b)b=g[a][f]}else for(;a--;)if(g[a]>=b)b=g[a];return b}};c.util.object={extend:l,clone:function(g){return l({},g)}};if(!String.prototype.trim)String.prototype.trim=function(){return this.replace(/^[\s\xA0]+/, +"").replace(/[\s\xA0]+$/,"")};c.util.string={camelize:function(g){return g.replace(/-+(.)?/g,function(f,a){return a?a.toUpperCase():""})},capitalize:function(g){return g.charAt(0).toUpperCase()+g.slice(1).toLowerCase()}};if(!Function.prototype.bind)Function.prototype.bind=function(g){var f=this,a=k.call(arguments,1);return a.length?function(){return p.call(f,g,a.concat(k.call(arguments)))}:function(){return p.call(f,g,arguments)}};(function(){function g(){}var f;f=function(){for(var a in{toString:1})if(a=== +"toString")return false;return true}()?function(a,b){if(b.toString!==Object.prototype.toString)a.prototype.toString=b.toString;if(b.valueOf!==Object.prototype.valueOf)a.prototype.valueOf=b.valueOf;for(var d in b)a.prototype[d]=b[d]}:function(a,b){for(var d in b)a.prototype[d]=b[d]};c.util.createClass=function(){function a(){this.initialize.apply(this,arguments)}var b=null,d=k.call(arguments,0);if(typeof d[0]==="function")b=d.shift();a.superclass=b;a.subclasses=[];if(b){g.prototype=b.prototype;a.prototype= +new g;b.subclasses.push(a)}b=0;for(var m=d.length;b=0.9999?"":"alpha(opacity="+m*100+")";q.filter=q.filter.replace(a,m)}else q.filter+=" alpha(opacity="+m*100+")";return d};c.util.setStyle=function(d,m){var q=d.style;if(typeof m==="string"){d.style.cssText+=";"+m;return m.indexOf("opacity")>-1?b(d,m.match(/opacity:\s*(\d?\.?\d*)/)[1]): +d}for(var r in m)if(r==="opacity")b(d,m[r]);else q[r==="float"||r==="cssFloat"?typeof q.styleFloat==="undefined"?"cssFloat":"styleFloat":r]=m[r];return d}})();(function(){var g=document.documentElement.style,f="userSelect"in g?"userSelect":"MozUserSelect"in g?"MozUserSelect":"WebkitUserSelect"in g?"WebkitUserSelect":"KhtmlUserSelect"in g?"KhtmlUserSelect":"";c.util.makeElementUnselectable=function(a){if(typeof a.onselectstart!=="undefined")a.onselectstart=c.util.falseFunction;if(f)a.style[f]="none"; +else if(typeof a.unselectable=="string")a.unselectable="on";return a}})();(function(){function g(a,b){f.load(a);b()}c.util.getScript=function(a,b){var d=document.getElementsByTagName("head")[0],m=document.createElement("script"),q=true;m.type="text/javascript";m.setAttribute("runat","server");m.onload=m.onreadystatechange=function(r){if(q)if(!(typeof this.readyState=="string"&&this.readyState!=="loaded"&&this.readyState!=="complete")){q=false;b(r||window.event);m=m.onload=m.onreadystatechange=null}}; +m.src=a;d.appendChild(m)};var f=this.Jaxer;if(f&&f.load)c.util.getScript=g})();c.util.getById=function(g){return typeof g==="string"?document.getElementById(g):g};c.util.toArray=function(g){for(var f=[],a=g.length;a--;)f[a]=g[a];return f};c.util.makeElement=n;c.util.addClass=function(g,f){if((" "+g.className+" ").indexOf(" "+f+" ")===-1)g.className+=(g.className?" ":"")+f};c.util.wrapElement=function(g,f,a){if(typeof f==="string")f=n(f,a);g.parentNode&&g.parentNode.replaceChild(f,g);f.appendChild(g); +return f};c.util.getElementOffset=function(g){var f=0,a=0;do{f+=g.offsetTop||0;a+=g.offsetLeft||0;g=g.offsetParent}while(g);return{left:a,top:f}};c.util.animate=function(g){g||(g={});var f=+new Date,a=g.duration||500,b=f+a,d,m,q=g.onChange||function(){},r=g.easing||function(t){return-Math.cos(t*Math.PI)/2+0.5},v="startValue"in g?g.startValue:0,w="endValue"in g?g.endValue:100,x=v>w;g.onStart&&g.onStart();var s=setInterval(function(){d=+new Date;m=d>b?1:(d-f)/a;q(x?v-(v-w)*r(m):v+(w-v)*r(m));if(d>b){clearInterval(s); +g.onComplete&&g.onComplete()}},10)};(function(){function g(){}var f=function(){for(var a=[function(){return new ActiveXObject("Microsoft.XMLHTTP")},function(){return new ActiveXObject("Msxml2.XMLHTTP")},function(){return new ActiveXObject("Msxml2.XMLHTTP.3.0")},function(){return new XMLHttpRequest}],b=a.length;b--;)try{if(a[b]())return a[b]}catch(d){}}();c.util.request=function(a,b){b||(b={});var d=b.method?b.method.toUpperCase():"GET",m=b.onComplete||function(){},q=f(),r;q.onreadystatechange=function(){if(q.readyState=== +4){m(q);q.onreadystatechange=g}};if(d==="GET"){r=null;if(typeof b.parameters=="string")a=a+(/\?/.test(a)?"&":"?")+b.parameters}q.open(d,a,true);if(d==="POST"||d==="PUT")q.setRequestHeader("Content-Type","application/x-www-form-urlencoded");q.send(r);return q}})()})(this); +(function(){var l=this.fabric||(this.fabric={}),n=l.util.object.extend,c=l.util.string.capitalize,k=l.util.object.clone,p={cx:"left",x:"left",cy:"top",y:"top",r:"radius","fill-opacity":"opacity","fill-rule":"fillRule","stroke-width":"strokeWidth",transform:"transformMatrix"};l.parseTransformAttribute=function(){function g(q,r){var v=r[0];q[0]=Math.cos(v);q[1]=Math.sin(v);q[2]=-Math.sin(v);q[3]=Math.cos(v)}function f(q,r){var v=r.length===2?r[1]:r[0];q[0]=r[0];q[3]=v}function a(q,r){q[4]=r[0];if(r.length=== +2)q[5]=r[1]}var b=[1,0,0,1,0,0],d=RegExp("^\\s*(?:(?:(?:(?:(matrix)\\s*\\(\\s*((?:[-+]?\\d+(?:\\.\\d+)?(?:e[-+]?\\d+)?))(?:\\s+,?\\s*|,\\s*)((?:[-+]?\\d+(?:\\.\\d+)?(?:e[-+]?\\d+)?))(?:\\s+,?\\s*|,\\s*)((?:[-+]?\\d+(?:\\.\\d+)?(?:e[-+]?\\d+)?))(?:\\s+,?\\s*|,\\s*)((?:[-+]?\\d+(?:\\.\\d+)?(?:e[-+]?\\d+)?))(?:\\s+,?\\s*|,\\s*)((?:[-+]?\\d+(?:\\.\\d+)?(?:e[-+]?\\d+)?))(?:\\s+,?\\s*|,\\s*)((?:[-+]?\\d+(?:\\.\\d+)?(?:e[-+]?\\d+)?))\\s*\\))|(?:(translate)\\s*\\(\\s*((?:[-+]?\\d+(?:\\.\\d+)?(?:e[-+]?\\d+)?))(?:(?:\\s+,?\\s*|,\\s*)((?:[-+]?\\d+(?:\\.\\d+)?(?:e[-+]?\\d+)?)))?\\s*\\))|(?:(scale)\\s*\\(\\s*((?:[-+]?\\d+(?:\\.\\d+)?(?:e[-+]?\\d+)?))(?:(?:\\s+,?\\s*|,\\s*)((?:[-+]?\\d+(?:\\.\\d+)?(?:e[-+]?\\d+)?)))?\\s*\\))|(?:(rotate)\\s*\\(\\s*((?:[-+]?\\d+(?:\\.\\d+)?(?:e[-+]?\\d+)?))(?:(?:\\s+,?\\s*|,\\s*)((?:[-+]?\\d+(?:\\.\\d+)?(?:e[-+]?\\d+)?))(?:\\s+,?\\s*|,\\s*)((?:[-+]?\\d+(?:\\.\\d+)?(?:e[-+]?\\d+)?)))?\\s*\\))|(?:(skewX)\\s*\\(\\s*((?:[-+]?\\d+(?:\\.\\d+)?(?:e[-+]?\\d+)?))\\s*\\))|(?:(skewY)\\s*\\(\\s*((?:[-+]?\\d+(?:\\.\\d+)?(?:e[-+]?\\d+)?))\\s*\\)))(?:(?:\\s+,?\\s*|,\\s*)(?:(?:(matrix)\\s*\\(\\s*((?:[-+]?\\d+(?:\\.\\d+)?(?:e[-+]?\\d+)?))(?:\\s+,?\\s*|,\\s*)((?:[-+]?\\d+(?:\\.\\d+)?(?:e[-+]?\\d+)?))(?:\\s+,?\\s*|,\\s*)((?:[-+]?\\d+(?:\\.\\d+)?(?:e[-+]?\\d+)?))(?:\\s+,?\\s*|,\\s*)((?:[-+]?\\d+(?:\\.\\d+)?(?:e[-+]?\\d+)?))(?:\\s+,?\\s*|,\\s*)((?:[-+]?\\d+(?:\\.\\d+)?(?:e[-+]?\\d+)?))(?:\\s+,?\\s*|,\\s*)((?:[-+]?\\d+(?:\\.\\d+)?(?:e[-+]?\\d+)?))\\s*\\))|(?:(translate)\\s*\\(\\s*((?:[-+]?\\d+(?:\\.\\d+)?(?:e[-+]?\\d+)?))(?:(?:\\s+,?\\s*|,\\s*)((?:[-+]?\\d+(?:\\.\\d+)?(?:e[-+]?\\d+)?)))?\\s*\\))|(?:(scale)\\s*\\(\\s*((?:[-+]?\\d+(?:\\.\\d+)?(?:e[-+]?\\d+)?))(?:(?:\\s+,?\\s*|,\\s*)((?:[-+]?\\d+(?:\\.\\d+)?(?:e[-+]?\\d+)?)))?\\s*\\))|(?:(rotate)\\s*\\(\\s*((?:[-+]?\\d+(?:\\.\\d+)?(?:e[-+]?\\d+)?))(?:(?:\\s+,?\\s*|,\\s*)((?:[-+]?\\d+(?:\\.\\d+)?(?:e[-+]?\\d+)?))(?:\\s+,?\\s*|,\\s*)((?:[-+]?\\d+(?:\\.\\d+)?(?:e[-+]?\\d+)?)))?\\s*\\))|(?:(skewX)\\s*\\(\\s*((?:[-+]?\\d+(?:\\.\\d+)?(?:e[-+]?\\d+)?))\\s*\\))|(?:(skewY)\\s*\\(\\s*((?:[-+]?\\d+(?:\\.\\d+)?(?:e[-+]?\\d+)?))\\s*\\))))*)?)\\s*$"), m=RegExp("(?:(?:(matrix)\\s*\\(\\s*((?:[-+]?\\d+(?:\\.\\d+)?(?:e[-+]?\\d+)?))(?:\\s+,?\\s*|,\\s*)((?:[-+]?\\d+(?:\\.\\d+)?(?:e[-+]?\\d+)?))(?:\\s+,?\\s*|,\\s*)((?:[-+]?\\d+(?:\\.\\d+)?(?:e[-+]?\\d+)?))(?:\\s+,?\\s*|,\\s*)((?:[-+]?\\d+(?:\\.\\d+)?(?:e[-+]?\\d+)?))(?:\\s+,?\\s*|,\\s*)((?:[-+]?\\d+(?:\\.\\d+)?(?:e[-+]?\\d+)?))(?:\\s+,?\\s*|,\\s*)((?:[-+]?\\d+(?:\\.\\d+)?(?:e[-+]?\\d+)?))\\s*\\))|(?:(translate)\\s*\\(\\s*((?:[-+]?\\d+(?:\\.\\d+)?(?:e[-+]?\\d+)?))(?:(?:\\s+,?\\s*|,\\s*)((?:[-+]?\\d+(?:\\.\\d+)?(?:e[-+]?\\d+)?)))?\\s*\\))|(?:(scale)\\s*\\(\\s*((?:[-+]?\\d+(?:\\.\\d+)?(?:e[-+]?\\d+)?))(?:(?:\\s+,?\\s*|,\\s*)((?:[-+]?\\d+(?:\\.\\d+)?(?:e[-+]?\\d+)?)))?\\s*\\))|(?:(rotate)\\s*\\(\\s*((?:[-+]?\\d+(?:\\.\\d+)?(?:e[-+]?\\d+)?))(?:(?:\\s+,?\\s*|,\\s*)((?:[-+]?\\d+(?:\\.\\d+)?(?:e[-+]?\\d+)?))(?:\\s+,?\\s*|,\\s*)((?:[-+]?\\d+(?:\\.\\d+)?(?:e[-+]?\\d+)?)))?\\s*\\))|(?:(skewX)\\s*\\(\\s*((?:[-+]?\\d+(?:\\.\\d+)?(?:e[-+]?\\d+)?))\\s*\\))|(?:(skewY)\\s*\\(\\s*((?:[-+]?\\d+(?:\\.\\d+)?(?:e[-+]?\\d+)?))\\s*\\)))"); -return function(q){var r=b.concat();if(!q||q&&!g.test(q))return r;q.replace(m,function(u){var v=RegExp("(?:(?:(matrix)\\s*\\(\\s*((?:[-+]?\\d+(?:\\.\\d+)?(?:e[-+]?\\d+)?))(?:\\s+,?\\s*|,\\s*)((?:[-+]?\\d+(?:\\.\\d+)?(?:e[-+]?\\d+)?))(?:\\s+,?\\s*|,\\s*)((?:[-+]?\\d+(?:\\.\\d+)?(?:e[-+]?\\d+)?))(?:\\s+,?\\s*|,\\s*)((?:[-+]?\\d+(?:\\.\\d+)?(?:e[-+]?\\d+)?))(?:\\s+,?\\s*|,\\s*)((?:[-+]?\\d+(?:\\.\\d+)?(?:e[-+]?\\d+)?))(?:\\s+,?\\s*|,\\s*)((?:[-+]?\\d+(?:\\.\\d+)?(?:e[-+]?\\d+)?))\\s*\\))|(?:(translate)\\s*\\(\\s*((?:[-+]?\\d+(?:\\.\\d+)?(?:e[-+]?\\d+)?))(?:(?:\\s+,?\\s*|,\\s*)((?:[-+]?\\d+(?:\\.\\d+)?(?:e[-+]?\\d+)?)))?\\s*\\))|(?:(scale)\\s*\\(\\s*((?:[-+]?\\d+(?:\\.\\d+)?(?:e[-+]?\\d+)?))(?:(?:\\s+,?\\s*|,\\s*)((?:[-+]?\\d+(?:\\.\\d+)?(?:e[-+]?\\d+)?)))?\\s*\\))|(?:(rotate)\\s*\\(\\s*((?:[-+]?\\d+(?:\\.\\d+)?(?:e[-+]?\\d+)?))(?:(?:\\s+,?\\s*|,\\s*)((?:[-+]?\\d+(?:\\.\\d+)?(?:e[-+]?\\d+)?))(?:\\s+,?\\s*|,\\s*)((?:[-+]?\\d+(?:\\.\\d+)?(?:e[-+]?\\d+)?)))?\\s*\\))|(?:(skewX)\\s*\\(\\s*((?:[-+]?\\d+(?:\\.\\d+)?(?:e[-+]?\\d+)?))\\s*\\))|(?:(skewY)\\s*\\(\\s*((?:[-+]?\\d+(?:\\.\\d+)?(?:e[-+]?\\d+)?))\\s*\\)))").exec(u).filter(function(A){return A!== -""&&A!=null});u=v[1];v=v.slice(2).map(parseFloat);switch(u){case "translate":a(r,v);break;case "rotate":d(r,v);break;case "scale":c(r,v);break;case "skewX":r[2]=v[0];break;case "skewY":r[1]=v[0];break;case "matrix":r=v;break}});return r}}();h.parseSVGDocument=function(){var d=/^(path|circle|polygon|polyline|ellipse|rect|line)$/,c=RegExp("^\\s*((?:[-+]?\\d+(?:\\.\\d+)?(?:e[-+]?\\d+)?)+)\\s*,?\\s*((?:[-+]?\\d+(?:\\.\\d+)?(?:e[-+]?\\d+)?)+)\\s*,?\\s*((?:[-+]?\\d+(?:\\.\\d+)?(?:e[-+]?\\d+)?)+)\\s*,?\\s*((?:[-+]?\\d+(?:\\.\\d+)?(?:e[-+]?\\d+)?)+)\\s*$"); -return function(a,b){if(a){var g=h.util.toArray(a.getElementsByTagName("*")).filter(function(A){var w;if(w=d.test(A.tagName)){a:{for(A=A;A&&(A=A.parentNode);)if(A.nodeName==="pattern"){A=true;break a}A=false}w=!A}return w});if(!(!g||g&&!g.length)){var m=a.getAttribute("viewBox"),q=a.getAttribute("width"),r=a.getAttribute("height"),u=null,v=null;if(m&&(m=m.match(c))){parseInt(m[1],10);parseInt(m[2],10);u=parseInt(m[3],10);v=parseInt(m[4],10)}u=q?parseFloat(q):u;v=r?parseFloat(r):v;m={width:u,height:v}; -g=h.parseElements(g,l(m));!g||g&&!g.length||b&&b(g,m)}}}}();p(h,{parseAttributes:function(d,c){if(d){var a,b,g={};if(d.parentNode&&/^g$/i.test(d.parentNode.nodeName))g=h.parseAttributes(d.parentNode,c);var m=c.reduce(function(q,r){a=d.getAttribute(r);b=parseFloat(a);if(a){if((r==="fill"||r==="stroke")&&a==="none")a="";if(r==="fill-rule")a=a==="evenodd"?"destination-over":a;if(r==="transform")a=h.parseTransformAttribute(a);if(r in o)r=o[r];q[r]=isNaN(b)?a:b}return q},{});m=p(h.parseStyleAttribute(d), -m);return p(g,m)}},parseElements:function(d,c){var a=d.map(function(b){var g=h[e(b.tagName)];if(g&&g.fromElement)try{return g.fromElement(b,c)}catch(m){h.log(m.message||m)}});return a=a.filter(function(b){return b!=null})},parseStyleAttribute:function(d){var c={};if(d=d.getAttribute("style"))if(typeof d=="string"){d=d.split(";");d.pop();c=d.reduce(function(b,g){var m=g.split(":"),q=m[0].trim();m=m[1].trim();b[q]=m;return b},{})}else for(var a in d)if(typeof d[a]!=="undefined")c[a]=d[a];return c}, -parsePointsAttribute:function(d){if(!d)return null;d=d.trim();var c=d.indexOf(",")>-1;d=d.split(/\s+/);var a=[];if(c){c=0;for(var b=d.length;c0&&this.init(e,l)}var p=this.fabric||(this.fabric={});if(p.Point)p.warn("fabric.Point is already defined");else{h.prototype={constructor:h,init:function(e,l){this.x=e;this.y=l},add:function(e){return new h(this.x+e.x,this.y+e.y)},addEquals:function(e){this.x+=e.x;this.y+=e.y;return this},scalarAdd:function(e){return new h(this.x+e,this.y+e)},scalarAddEquals:function(e){this.x+=e;this.y+=e;return this},subtract:function(e){return new h(this.x-e.x,this.y- -e.y)},subtractEquals:function(e){this.x-=e.x;this.y-=e.y;return this},scalarSubtract:function(e){return new h(this.x-e,this.y-e)},scalarSubtractEquals:function(e){this.x-=e;this.y-=e;return this},multiply:function(e){return new h(this.x*e,this.y*e)},multiplyEquals:function(e){this.x*=e;this.y*=e;return this},divide:function(e){return new h(this.x/e,this.y/e)},divideEquals:function(e){this.x/=e;this.y/=e;return this},eq:function(e){return this.x==e.x&&this.y==e.y},lt:function(e){return this.xe.x&&this.y>e.y},gte:function(e){return this.x>=e.x&&this.y>=e.y},lerp:function(e,l){return new h(this.x+(e.x-this.x)*l,this.y+(e.y-this.y)*l)},distanceFrom:function(e){var l=this.x-e.x;e=this.y-e.y;return Math.sqrt(l*l+e*e)},min:function(e){return new h(Math.min(this.x,e.x),Math.min(this.y,e.y))},max:function(e){return new h(Math.max(this.x,e.x),Math.max(this.y,e.y))},toString:function(){return this.x+","+this.y}, -setXY:function(e,l){this.x=e;this.y=l},setFromPoint:function(e){this.x=e.x;this.y=e.y},swap:function(e){var l=this.x,o=this.y;this.x=e.x;this.y=e.y;e.x=l;e.y=o}};p.Point=h}})(); -(function(){function h(e){arguments.length>0&&this.init(e)}var p=this.fabric||(this.fabric={});if(p.Intersection)p.warn("fabric.Intersection is already defined");else{h.prototype.init=function(e){this.status=e;this.points=[]};h.prototype.appendPoint=function(e){this.points.push(e)};h.prototype.appendPoints=function(e){this.points=this.points.concat(e)};h.intersectLineLine=function(e,l,o,d){var c,a=(d.x-o.x)*(e.y-o.y)-(d.y-o.y)*(e.x-o.x);c=(l.x-e.x)*(e.y-o.y)-(l.y-e.y)*(e.x-o.x);o=(d.y-o.y)*(l.x-e.x)- -(d.x-o.x)*(l.y-e.y);if(o!=0){a=a/o;c=c/o;if(0<=a&&a<=1&&0<=c&&c<=1){c=new h("Intersection");c.points.push(new p.Point(e.x+a*(l.x-e.x),e.y+a*(l.y-e.y)))}else c=new h("No Intersection")}else c=a==0||c==0?new h("Coincident"):new h("Parallel");return c};h.intersectLinePolygon=function(e,l,o){for(var d=new h("No Intersection"),c=o.length,a=0;a0)d.status="Intersection";return d};h.intersectPolygonPolygon= -function(e,l){for(var o=new h("No Intersection"),d=e.length,c=0;c0)o.status="Intersection";return o};h.intersectPolygonRectangle=function(e,l,o){var d=l.min(o),c=l.max(o);o=new p.Point(c.x,d.y);var a=new p.Point(d.x,c.y);l=h.intersectLinePolygon(d,o,e);o=h.intersectLinePolygon(o,c,e);c=h.intersectLinePolygon(c,a,e);e=h.intersectLinePolygon(a,d,e);d=new h("No Intersection");d.appendPoints(l.points); -d.appendPoints(o.points);d.appendPoints(c.points);d.appendPoints(e.points);if(d.points.length>0)d.status="Intersection";return d};p.Intersection=h}})(); -(function(){function h(e){e?this._tryParsingColor(e):this.setSource([0,0,0,1])}var p=this.fabric||(this.fabric={});if(p.Color)p.warn("fabric.Color is already defined.");else{p.Color=h;h.prototype._tryParsingColor=function(e){var l=h.sourceFromHex(e);l||(l=h.sourceFromRgb(e));l&&this.setSource(l)};h.prototype.getSource=function(){return this._source};h.prototype.setSource=function(e){this._source=e};h.prototype.toRgb=function(){var e=this.getSource();return"rgb("+e[0]+","+e[1]+","+e[2]+")"};h.prototype.toRgba= -function(){var e=this.getSource();return"rgba("+e[0]+","+e[1]+","+e[2]+","+e[3]+")"};h.prototype.toHex=function(){var e=this.getSource(),l=e[0].toString(16);l=l.length==1?"0"+l:l;var o=e[1].toString(16);o=o.length==1?"0"+o:o;e=e[2].toString(16);e=e.length==1?"0"+e:e;return l.toUpperCase()+o.toUpperCase()+e.toUpperCase()};h.prototype.getAlpha=function(){return this.getSource()[3]};h.prototype.setAlpha=function(e){var l=this.getSource();l[3]=e;this.setSource(l);return this};h.prototype.toGrayscale= -function(){var e=this.getSource(),l=parseInt((e[0]*0.3+e[1]*0.59+e[2]*0.11).toFixed(0),10);this.setSource([l,l,l,e[3]]);return this};h.prototype.toBlackWhite=function(e){var l=this.getSource(),o=(l[0]*0.3+l[1]*0.59+l[2]*0.11).toFixed(0);l=l[3];e=e||127;o=Number(o)0?0:-k),f.ey-(n>0?0:-n),t,x);this.contextTop.lineWidth=this.selectionLineWidth;this.contextTop.strokeStyle=this.selectionBorderColor;this.contextTop.strokeRect(f.ex+0.5-(k>0?0:t),f.ey+0.5-(n>0?0:x),t,x)},_findSelectedObjects:function(){var f=[],k=this._groupSelector.ex,n=this._groupSelector.ey,t=k+this._groupSelector.left,x=n+this._groupSelector.top,y=new fabric.Point(s(k,t),s(n,x));n=new fabric.Point(C(k,t),C(n,x));t=0;for(x=this._objects.length;t1){f=new fabric.Group(f);this.setActiveGroup(f);f.saveCoords();d("group:selected",{target:f})}this.renderAll()},add:function(){this._objects.push.apply(this._objects,arguments);this.renderAll();return this},insertAt:function(f,k){this._objects.splice(k,0,f);this.renderAll();return this},getObjects:function(){return this._objects},getContext:function(){return this.contextTop}, -clearContext:function(f){f.clearRect(0,0,this._config.width,this._config.height);return this},clear:function(){this._objects.length=0;this.clearContext(this.contextTop);this.clearContext(this.contextContainer);this.renderAll();return this},renderAll:function(f){var k=this._config.width,n=this._config.height,t=f?this.contextTop:this.contextContainer;this.clearContext(this.contextTop);f||this.clearContext(t);t.fillStyle=this.backgroundColor;t.fillRect(0,0,k,n);f=this._objects.length;k=this.getActiveGroup(); -n=new Date;if(f)for(var x=0;x1?new fabric.PathGroup(F,D):F[0];F.setSourcePath(H);if(!(F instanceof fabric.PathGroup)){e(F,D);typeof D.angle!=="undefined"&&F.setAngle(D.angle)}n(F,G)})}, -this)}catch(B){fabric.log(B.message)}},loadImageFromURL:function(){var f={};return function(k,n){function t(){var B=p.getElementById(f[k]);B.width&&B.height?n(new fabric.Image(B)):setTimeout(t,50)}var x=this;if(f[k])t();else{var y=new Image;y.onload=function(){y.onload=null;x._resizeImageToFit(y);var B=new fabric.Image(y);n(B)};y.className="canvas-img-clone";y.src=k;if(this.shouldCacheImages)f[k]=Element.identify(y);p.body.appendChild(y)}}}(),loadSVGFromURL:function(f,k){function n(y){if(y=y.responseXML)(y= -y.documentElement)&&fabric.parseSVGDocument(y,function(B,D){x.cache.set(f,{objects:B.invoke("toObject"),options:D});k(B,D)})}function t(){fabric.log("ERROR!")}var x=this;f=f.replace(/^\n\s*/,"").replace(/\?.*$/,"").trim();this.cache.has(f,function(y){if(y)x.cache.get(f,function(B){B=x._enlivenCachedObject(B);k(B.objects,B.options)});else new Ajax.Request(f,{method:"get",onComplete:n,onFailure:t})})},_enlivenCachedObject:function(f){var k=f.objects;f=f.options;k=k.map(function(n){return fabric[l(n.type)].fromObject(n)}); -return{objects:k,options:f}},remove:function(f){b(this._objects,f);this.renderAll();return f},fxRemove:function(f,k){var n=this;f.fxRemove({onChange:this.renderAll.bind(this),onComplete:function(){n.remove(f);typeof k==="function"&&k()}});return this},sendToBack:function(f){b(this._objects,f);this._objects.unshift(f);return this.renderAll()},bringToFront:function(f){b(this._objects,f);this._objects.push(f);return this.renderAll()},sendBackwards:function(f){var k=this._objects.indexOf(f),n=k;if(k!== -0){for(k=k-1;k>=0;--k)if(f.intersectsWithObject(this._objects[k])){n=k;break}b(this._objects,f);this._objects.splice(n,0,f)}return this.renderAll()},bringForward:function(f){var k=this.getObjects(),n=k.indexOf(f),t=n;if(n!==k.length-1){n=n+1;for(var x=this._objects.length;n"};e(fabric.Element,{EMPTY_JSON:'{"objects": [], "background": "white"}',toGrayscale:function(f){var k=f.getContext("2d");f=k.getImageData(0,0,f.width,f.height);var n=f.data,t=f.width,x=f.height,y,B;for(i=0;i1?b.apply(this,c.call(arguments,1)):b.call(this)}, -initialize:function(a){this.setOptions(a);this._importProperties();this.originalState={};this.setCoords();this.saveState()},setOptions:function(a){this.options=p(this._getOptions(),a)},_getOptions:function(){return p(e(this._getSuperOptions()),this.options)},_getSuperOptions:function(){var a=this.constructor;if(a)if(a=a.superclass)if((a=a.prototype)&&typeof a._getOptions=="function")return a._getOptions();return{}},_importProperties:function(){this.stateProperties.forEach(function(a){a==="angle"? -this.setAngle(this.options[a]):this[a]=this.options[a]},this)},transform:function(a){a.globalAlpha=this.opacity;a.translate(this.left,this.top);a.rotate(this.theta);a.scale(this.scaleX*(this.flipX?-1:1),this.scaleY*(this.flipY?-1:1))},toObject:function(){var a={type:this.type,left:l(this.left,this.NUM_FRACTION_DIGITS),top:l(this.top,this.NUM_FRACTION_DIGITS),width:l(this.width,this.NUM_FRACTION_DIGITS),height:l(this.height,this.NUM_FRACTION_DIGITS),fill:this.fill,overlayFill:this.overlayFill,stroke:this.stroke, -strokeWidth:this.strokeWidth,scaleX:l(this.scaleX,this.NUM_FRACTION_DIGITS),scaleY:l(this.scaleY,this.NUM_FRACTION_DIGITS),angle:l(this.getAngle(),this.NUM_FRACTION_DIGITS),flipX:this.flipX,flipY:this.flipY,opacity:l(this.opacity,this.NUM_FRACTION_DIGITS)};this.includeDefaultValues||(a=this._removeDefaultValues(a));return a},toDatalessObject:function(){return this.toObject()},_removeDefaultValues:function(a){var b=h.Object.prototype.options;this.stateProperties.forEach(function(g){a[g]===b[g]&&delete a[g]}); -return a},isActive:function(){return!!this.active},setActive:function(a){this.active=!!a;return this},toString:function(){return"#"},set:function(a,b){if((a==="scaleX"||a==="scaleY")&&b-1;g=g.split(/\s+/);var a=[];if(f){f=0;for(var b=g.length;f0&&this.init(c,k)}var n=this.fabric||(this.fabric={});if(n.Point)n.warn("fabric.Point is already defined");else{n.Point=l;l.prototype={constructor:l,init:function(c,k){this.x=c;this.y=k},add:function(c){return new l(this.x+c.x,this.y+c.y)},addEquals:function(c){this.x+=c.x;this.y+=c.y;return this},scalarAdd:function(c){return new l(this.x+c,this.y+c)},scalarAddEquals:function(c){this.x+=c;this.y+=c;return this},subtract:function(c){return new l(this.x- +c.x,this.y-c.y)},subtractEquals:function(c){this.x-=c.x;this.y-=c.y;return this},scalarSubtract:function(c){return new l(this.x-c,this.y-c)},scalarSubtractEquals:function(c){this.x-=c;this.y-=c;return this},multiply:function(c){return new l(this.x*c,this.y*c)},multiplyEquals:function(c){this.x*=c;this.y*=c;return this},divide:function(c){return new l(this.x/c,this.y/c)},divideEquals:function(c){this.x/=c;this.y/=c;return this},eq:function(c){return this.x==c.x&&this.y==c.y},lt:function(c){return this.x< +c.x&&this.yc.x&&this.y>c.y},gte:function(c){return this.x>=c.x&&this.y>=c.y},lerp:function(c,k){return new l(this.x+(c.x-this.x)*k,this.y+(c.y-this.y)*k)},distanceFrom:function(c){var k=this.x-c.x;c=this.y-c.y;return Math.sqrt(k*k+c*c)},min:function(c){return new l(Math.min(this.x,c.x),Math.min(this.y,c.y))},max:function(c){return new l(Math.max(this.x,c.x),Math.max(this.y,c.y))},toString:function(){return this.x+ +","+this.y},setXY:function(c,k){this.x=c;this.y=k},setFromPoint:function(c){this.x=c.x;this.y=c.y},swap:function(c){var k=this.x,p=this.y;this.x=c.x;this.y=c.y;c.x=k;c.y=p}}}})(); +(function(){function l(c){arguments.length>0&&this.init(c)}var n=this.fabric||(this.fabric={});if(n.Intersection)n.warn("fabric.Intersection is already defined");else{n.Intersection=l;n.Intersection.prototype={init:function(c){this.status=c;this.points=[]},appendPoint:function(c){this.points.push(c)},appendPoints:function(c){this.points=this.points.concat(c)}};n.Intersection.intersectLineLine=function(c,k,p,g){var f,a=(g.x-p.x)*(c.y-p.y)-(g.y-p.y)*(c.x-p.x);f=(k.x-c.x)*(c.y-p.y)-(k.y-c.y)*(c.x-p.x); +p=(g.y-p.y)*(k.x-c.x)-(g.x-p.x)*(k.y-c.y);if(p!=0){a=a/p;f=f/p;if(0<=a&&a<=1&&0<=f&&f<=1){f=new l("Intersection");f.points.push(new n.Point(c.x+a*(k.x-c.x),c.y+a*(k.y-c.y)))}else f=new l("No Intersection")}else f=a==0||f==0?new l("Coincident"):new l("Parallel");return f};n.Intersection.intersectLinePolygon=function(c,k,p){for(var g=new l("No Intersection"),f=p.length,a=0;a0)g.status="Intersection";return g}; +n.Intersection.intersectPolygonPolygon=function(c,k){for(var p=new l("No Intersection"),g=c.length,f=0;f0)p.status="Intersection";return p};n.Intersection.intersectPolygonRectangle=function(c,k,p){var g=k.min(p),f=k.max(p);p=new n.Point(f.x,g.y);var a=new n.Point(g.x,f.y);k=l.intersectLinePolygon(g,p,c);p=l.intersectLinePolygon(p,f,c);f=l.intersectLinePolygon(f,a,c);c=l.intersectLinePolygon(a,g,c); +g=new l("No Intersection");g.appendPoints(k.points);g.appendPoints(p.points);g.appendPoints(f.points);g.appendPoints(c.points);if(g.points.length>0)g.status="Intersection";return g}}})(); +(function(){function l(c){c?this._tryParsingColor(c):this.setSource([0,0,0,1])}var n=this.fabric||(this.fabric={});if(n.Color)n.warn("fabric.Color is already defined.");else{n.Color=l;n.Color.prototype={_tryParsingColor:function(c){var k=l.sourceFromHex(c);k||(k=l.sourceFromRgb(c));k&&this.setSource(k)},getSource:function(){return this._source},setSource:function(c){this._source=c},toRgb:function(){var c=this.getSource();return"rgb("+c[0]+","+c[1]+","+c[2]+")"},toRgba:function(){var c=this.getSource(); +return"rgba("+c[0]+","+c[1]+","+c[2]+","+c[3]+")"},toHex:function(){var c=this.getSource(),k=c[0].toString(16);k=k.length==1?"0"+k:k;var p=c[1].toString(16);p=p.length==1?"0"+p:p;c=c[2].toString(16);c=c.length==1?"0"+c:c;return k.toUpperCase()+p.toUpperCase()+c.toUpperCase()},getAlpha:function(){return this.getSource()[3]},setAlpha:function(c){var k=this.getSource();k[3]=c;this.setSource(k);return this},toGrayscale:function(){var c=this.getSource(),k=parseInt((c[0]*0.3+c[1]*0.59+c[2]*0.11).toFixed(0), +10);this.setSource([k,k,k,c[3]]);return this},toBlackWhite:function(c){var k=this.getSource(),p=(k[0]*0.3+k[1]*0.59+k[2]*0.11).toFixed(0);k=k[3];c=c||127;p=Number(p)0?0:-h),e.ey-(o>0?0:-o),u,y);this.contextTop.lineWidth=this.selectionLineWidth;this.contextTop.strokeStyle=this.selectionBorderColor;this.contextTop.strokeRect(e.ex+0.5-(h>0?0:u),e.ey+0.5-(o>0?0:y),u,y)},_findSelectedObjects:function(){var e=[],h=this._groupSelector.ex,o=this._groupSelector.ey,u=h+this._groupSelector.left,y=o+this._groupSelector.top,z=new fabric.Point(t(h,u),t(o,y));o=new fabric.Point(B(h,u),B(o,y));u=0;for(y=this._objects.length;u1){e=new fabric.Group(e);this.setActiveGroup(e);e.saveCoords();g("group:selected",{target:e})}this.renderAll()},add:function(){this._objects.push.apply(this._objects,arguments);this.renderAll();return this},insertAt:function(e,h){this._objects.splice(h,0,e);this.renderAll();return this},getObjects:function(){return this._objects},getContext:function(){return this.contextTop}, +clearContext:function(e){e.clearRect(0,0,this._config.width,this._config.height);return this},clear:function(){this._objects.length=0;this.clearContext(this.contextTop);this.clearContext(this.contextContainer);this.renderAll();return this},renderAll:function(e){var h=this._config.width,o=this._config.height,u=e?this.contextTop:this.contextContainer;this.clearContext(this.contextTop);e||this.clearContext(u);u.fillStyle=this.backgroundColor;u.fillRect(0,0,h,o);e=this._objects.length;h=this.getActiveGroup(); +o=new Date;if(e)for(var y=0;y1?new fabric.PathGroup(F,D):F[0];F.setSourcePath(H);if(!(F instanceof fabric.PathGroup)){c(F,D);typeof D.angle!=="undefined"&&F.setAngle(D.angle)}o(F,G)})}, +this)}catch(C){fabric.log(C.message)}},loadImageFromURL:function(){var e={};return function(h,o){function u(){var C=n.getElementById(e[h]);C.width&&C.height?o(new fabric.Image(C)):setTimeout(u,50)}var y=this;if(e[h])u();else{var z=new Image;z.onload=function(){z.onload=null;y._resizeImageToFit(z);var C=new fabric.Image(z);o(C)};z.className="canvas-img-clone";z.src=h;if(this.shouldCacheImages)e[h]=Element.identify(z);n.body.appendChild(z)}}}(),loadSVGFromURL:function(e,h){function o(z){if(z=z.responseXML)(z= +z.documentElement)&&fabric.parseSVGDocument(z,function(C,D){y.cache.set(e,{objects:C.invoke("toObject"),options:D});h(C,D)})}function u(){fabric.log("ERROR!")}var y=this;e=e.replace(/^\n\s*/,"").replace(/\?.*$/,"").trim();this.cache.has(e,function(z){if(z)y.cache.get(e,function(C){C=y._enlivenCachedObject(C);h(C.objects,C.options)});else new Ajax.Request(e,{method:"get",onComplete:o,onFailure:u})})},_enlivenCachedObject:function(e){var h=e.objects;e=e.options;h=h.map(function(o){return fabric[k(o.type)].fromObject(o)}); +return{objects:h,options:e}},remove:function(e){b(this._objects,e);this.renderAll();return e},fxRemove:function(e,h){var o=this;e.fxRemove({onChange:this.renderAll.bind(this),onComplete:function(){o.remove(e);typeof h==="function"&&h()}});return this},sendToBack:function(e){b(this._objects,e);this._objects.unshift(e);return this.renderAll()},bringToFront:function(e){b(this._objects,e);this._objects.push(e);return this.renderAll()},sendBackwards:function(e){var h=this._objects.indexOf(e),o=h;if(h!== +0){for(h=h-1;h>=0;--h)if(e.intersectsWithObject(this._objects[h])){o=h;break}b(this._objects,e);this._objects.splice(o,0,e)}return this.renderAll()},bringForward:function(e){var h=this.getObjects(),o=h.indexOf(e),u=o;if(o!==h.length-1){o=o+1;for(var y=this._objects.length;o"};c(fabric.Element,{EMPTY_JSON:'{"objects": [], "background": "white"}',toGrayscale:function(e){var h=e.getContext("2d");e=h.getImageData(0,0,e.width,e.height);var o=e.data,u=e.width,y=e.height,z,C;for(i=0;i1?b.apply(this,f.call(arguments,1)):b.call(this)}, +initialize:function(a){this.setOptions(a);this._importProperties();this.originalState={};this.setCoords();this.saveState()},setOptions:function(a){this.options=n(this._getOptions(),a)},_getOptions:function(){return n(c(this._getSuperOptions()),this.options)},_getSuperOptions:function(){var a=this.constructor;if(a)if(a=a.superclass)if((a=a.prototype)&&typeof a._getOptions=="function")return a._getOptions();return{}},_importProperties:function(){this.stateProperties.forEach(function(a){a==="angle"? +this.setAngle(this.options[a]):this[a]=this.options[a]},this)},transform:function(a){a.globalAlpha=this.opacity;a.translate(this.left,this.top);a.rotate(this.theta);a.scale(this.scaleX*(this.flipX?-1:1),this.scaleY*(this.flipY?-1:1))},toObject:function(){var a={type:this.type,left:k(this.left,this.NUM_FRACTION_DIGITS),top:k(this.top,this.NUM_FRACTION_DIGITS),width:k(this.width,this.NUM_FRACTION_DIGITS),height:k(this.height,this.NUM_FRACTION_DIGITS),fill:this.fill,overlayFill:this.overlayFill,stroke:this.stroke, +strokeWidth:this.strokeWidth,scaleX:k(this.scaleX,this.NUM_FRACTION_DIGITS),scaleY:k(this.scaleY,this.NUM_FRACTION_DIGITS),angle:k(this.getAngle(),this.NUM_FRACTION_DIGITS),flipX:this.flipX,flipY:this.flipY,opacity:k(this.opacity,this.NUM_FRACTION_DIGITS)};this.includeDefaultValues||(a=this._removeDefaultValues(a));return a},toDatalessObject:function(){return this.toObject()},_removeDefaultValues:function(a){var b=l.Object.prototype.options;this.stateProperties.forEach(function(d){a[d]===b[d]&&delete a[d]}); +return a},isActive:function(){return!!this.active},setActive:function(a){this.active=!!a;return this},toString:function(){return"#"},set:function(a,b){if((a==="scaleX"||a==="scaleY")&&ba.x&&q.xa.y&&r.y=b&&r.d.y>=b)){if(r.o.x==r.d.x&&r.o.x>=a)m=r.o.x;else{m=(r.d.y-r.o.y)/(r.d.x-r.o.x);q=b-0*a;r=r.o.y-m*r.o.x;m=-(q-r)/(0-m)}if(m>=a)u+=1;if(u==2)break}}return u},_getImageLines:function(a){return{topline:{o:a.tl,d:a.tr},rightline:{o:a.tr,d:a.br},bottomline:{o:a.br,d:a.bl},leftline:{o:a.bl,d:a.tl}}},_setCornerCoords:function(){var a=this.oCoords,b=this.theta,g=this.cornersize*Math.cos(b),m=this.cornersize*Math.sin(b);b=this.cornersize/2;var q=b-m;a.tl.x-=q;a.tl.y-= -b;a.tl.corner={tl:{x:a.tl.x,y:a.tl.y},tr:{x:a.tl.x+g,y:a.tl.y+m},bl:{x:a.tl.x-m,y:a.tl.y+g}};a.tl.corner.br={x:a.tl.corner.tr.x-m,y:a.tl.corner.tr.y+g};a.tl.x+=q;a.tl.y+=b;a.tr.x+=b;a.tr.y-=b;a.tr.corner={tl:{x:a.tr.x-g,y:a.tr.y-m},tr:{x:a.tr.x,y:a.tr.y},br:{x:a.tr.x-m,y:a.tr.y+g}};a.tr.corner.bl={x:a.tr.corner.tl.x-m,y:a.tr.corner.tl.y+g};a.tr.x-=b;a.tr.y+=b;a.bl.x-=b;a.bl.y+=b;a.bl.corner={tl:{x:a.bl.x+m,y:a.bl.y-g},bl:{x:a.bl.x,y:a.bl.y},br:{x:a.bl.x+g,y:a.bl.y+m}};a.bl.corner.tr={x:a.bl.corner.br.x+ -m,y:a.bl.corner.br.y-g};a.bl.x+=b;a.bl.y-=b;a.br.x+=b;a.br.y+=b;a.br.corner={tr:{x:a.br.x+m,y:a.br.y-g},bl:{x:a.br.x-g,y:a.br.y-m},br:{x:a.br.x,y:a.br.y}};a.br.corner.tl={x:a.br.corner.bl.x+m,y:a.br.corner.bl.y-g};a.br.x-=b;a.br.y-=b;a.ml.x-=b;a.ml.y-=b;a.ml.corner={tl:{x:a.ml.x,y:a.ml.y},tr:{x:a.ml.x+g,y:a.ml.y+m},bl:{x:a.ml.x-m,y:a.ml.y+g}};a.ml.corner.br={x:a.ml.corner.tr.x-m,y:a.ml.corner.tr.y+g};a.ml.x+=b;a.ml.y+=b;a.mt.x-=b;a.mt.y-=b;a.mt.corner={tl:{x:a.mt.x,y:a.mt.y},tr:{x:a.mt.x+g,y:a.mt.y+ -m},bl:{x:a.mt.x-m,y:a.mt.y+g}};a.mt.corner.br={x:a.mt.corner.tr.x-m,y:a.mt.corner.tr.y+g};a.mt.x+=b;a.mt.y+=b;a.mr.x-=b;a.mr.y-=b;a.mr.corner={tl:{x:a.mr.x,y:a.mr.y},tr:{x:a.mr.x+g,y:a.mr.y+m},bl:{x:a.mr.x-m,y:a.mr.y+g}};a.mr.corner.br={x:a.mr.corner.tr.x-m,y:a.mr.corner.tr.y+g};a.mr.x+=b;a.mr.y+=b;a.mb.x-=b;a.mb.y-=b;a.mb.corner={tl:{x:a.mb.x,y:a.mb.y},tr:{x:a.mb.x+g,y:a.mb.y+m},bl:{x:a.mb.x-m,y:a.mb.y+g}};a.mb.corner.br={x:a.mb.corner.tr.x-m,y:a.mb.corner.tr.y+g};a.mb.x+=b;a.mb.y+=b;a=a.mb.corner; -a.tl.x-=b;a.tl.y-=b;a.tr.x-=b;a.tr.y-=b;a.br.x-=b;a.br.y-=b;a.bl.x-=b;a.bl.y-=b},toGrayscale:function(){var a=this.get("fill");a&&this.set("overlayFill",(new h.Color(a)).toGrayscale().toRgb());return this},complexity:function(){return 0},getCenter:function(){return{x:this.get("left")+this.width/2,y:this.get("top")+this.height/2}},straighten:function(){this.setAngle(this._getAngleValueForStraighten());return this},fxStraighten:function(a){a=a||{};var b=function(){},g=a.onComplete||b,m=a.onChange|| -b,q=this;h.util.animate({startValue:this.get("angle"),endValue:this._getAngleValueForStraighten(),duration:this.FX_DURATION,onChange:function(r){q.setAngle(r);m()},onComplete:function(){q.setCoords();g()},onStart:function(){q.setActive(false)}});return this},fxRemove:function(a){a||(a={});var b=function(){},g=a.onComplete||b,m=a.onChange||b,q=this;h.util.animate({startValue:this.get("opacity"),endValue:0,duration:this.FX_DURATION,onChange:function(r){q.set("opacity",r);m()},onComplete:g,onStart:function(){q.setActive(false)}}); -return this},_getAngleValueForStraighten:function(){var a=this.get("angle");if(a>-225&&a<=-135)return-180;else if(a>-135&&a<=-45)return-90;else if(a>-45&&a<=45)return 0;else if(a>45&&a<=135)return 90;else if(a>135&&a<=225)return 180;else if(a>225&&a<=315)return 270;else if(a>315)return 360;return 0},toJSON:function(){return this.toObject()}});h.Object.prototype.rotate=h.Object.prototype.setAngle}})(); -(function(){var h=this.fabric||(this.fabric={}),p=h.util.object.extend;if(!h.Line){h.Line=h.util.createClass(h.Object,{type:"line",initialize:function(e,l){e||(e=[0,0,0,0]);this.callSuper("initialize",l);this.set("x1",e[0]);this.set("y1",e[1]);this.set("x2",e[2]);this.set("y2",e[3]);this.set("width",this.x2-this.x1);this.set("height",this.y2-this.y1);this.set("left",this.x1+this.width/2);this.set("top",this.y1+this.height/2)},_render:function(e){e.beginPath();e.moveTo(-this.width/2,-this.height/2); -e.lineTo(this.width/2,this.height/2);var l=e.strokeStyle;e.strokeStyle=e.fillStyle;e.stroke();e.strokeStyle=l},complexity:function(){return 1},toObject:function(){return p(this.callSuper("toObject"),{x1:this.get("x1"),y1:this.get("y1"),x2:this.get("x2"),y2:this.get("y2")})}});h.Element.ATTRIBUTE_NAMES="x1 y1 x2 y2 stroke stroke-width transform".split(" ");h.Line.fromElement=function(e,l){var o=h.parseAttributes(e,h.Element.ATTRIBUTE_NAMES);return new h.Line([o.x1||0,o.y1||0,o.x2||0,o.y2||0],p(o,l))}; -h.Line.fromObject=function(e){return new h.Line([e.x1,e.y1,e.x2,e.y2],e)}}})(); -(function(){var h=this.fabric||(this.fabric={}),p=Math.PI*2,e=h.util.object.extend;if(h.Circle)h.warn("fabric.Circle is already defined.");else{h.Circle=h.util.createClass(h.Object,{type:"circle",initialize:function(l){l=l||{};this.set("radius",l.radius||0);this.callSuper("initialize",l);l=this.get("radius")*2*this.get("scaleX");this.set("width",l).set("height",l)},toObject:function(){return e(this.callSuper("toObject"),{radius:this.get("radius")})},_render:function(l,o){l.beginPath();l.arc(o?this.left: -0,o?this.top:0,this.radius,0,p,false);l.closePath();this.fill&&l.fill();this.stroke&&l.stroke()},complexity:function(){return 1}});h.Circle.ATTRIBUTE_NAMES="cx cy r fill fill-opacity stroke stroke-width transform".split(" ");h.Circle.fromElement=function(l,o){o||(o={});var d=h.parseAttributes(l,h.Circle.ATTRIBUTE_NAMES);if(!("radius"in d&&d.radius>0))throw Error("value of `r` attribute is required and can not be negative");if("left"in d)d.left-=o.width/2||0;if("top"in d)d.top-=o.height/2||0;return new h.Circle(e(d, -o))};h.Circle.fromObject=function(l){return new h.Circle(l)}}})(); -(function(){var h=this.fabric||(this.fabric={});if(!h.Triangle){h.Triangle=h.util.createClass(h.Object,{type:"triangle",initialize:function(p){p=p||{};this.callSuper("initialize",p);this.set("width",p.width||100).set("height",p.height||100)},_render:function(p){var e=this.width/2,l=this.height/2;p.beginPath();p.moveTo(-e,l);p.lineTo(0,-l);p.lineTo(e,l);p.closePath();this.fill&&p.fill();this.stroke&&p.stroke()},complexity:function(){return 1}});h.Triangle.fromObject=function(p){return new h.Triangle(p)}}})(); -(function(){var h=this.fabric||(this.fabric={}),p=Math.PI*2,e=h.util.object.extend;if(h.Ellipse)h.warn("fabric.Ellipse is already defined.");else{h.Ellipse=h.util.createClass(h.Object,{type:"ellipse",initialize:function(l){l=l||{};this.callSuper("initialize",l);this.set("rx",l.rx||0);this.set("ry",l.ry||0);this.set("width",this.get("rx")*2);this.set("height",this.get("ry")*2)},toObject:function(){return e(this.callSuper("toObject"),{rx:this.get("rx"),ry:this.get("ry")})},render:function(l,o){if(!(this.rx=== -0||this.ry===0))return this.callSuper("render",l,o)},_render:function(l,o){l.beginPath();l.save();l.transform(1,0,0,this.ry/this.rx,0,0);l.arc(o?this.left:0,o?this.top:0,this.rx,0,p,false);l.restore();this.stroke&&l.stroke();this.fill&&l.fill()},complexity:function(){return 1}});h.Ellipse.ATTRIBUTE_NAMES="cx cy rx ry fill fill-opacity stroke stroke-width transform".split(" ");h.Ellipse.fromElement=function(l,o){o||(o={});var d=h.parseAttributes(l,h.Ellipse.ATTRIBUTE_NAMES);if("left"in d)d.left-=o.width/ -2||0;if("top"in d)d.top-=o.height/2||0;return new h.Ellipse(e(d,o))};h.Ellipse.fromObject=function(l){return new h.Ellipse(l)}}})(); -(function(){var h=this.fabric||(this.fabric={});if(!h.Rect){h.Rect=h.util.createClass(h.Object,{type:"rect",options:{rx:0,ry:0},initialize:function(p){this.callSuper("initialize",p);this._initRxRy()},_initRxRy:function(){if(this.options.rx&&!this.options.ry)this.options.ry=this.options.rx;else if(this.options.ry&&!this.options.rx)this.options.rx=this.options.ry},_render:function(p){var e=this.options.rx||0,l=this.options.ry||0,o=-this.width/2,d=-this.height/2,c=this.width,a=this.height;p.beginPath(); -p.moveTo(o+e,d);p.lineTo(o+c-e,d);p.bezierCurveTo(o+c,d,o+c,d+l,o+c,d+l);p.lineTo(o+c,d+a-l);p.bezierCurveTo(o+c,d+a,o+c-e,d+a,o+c-e,d+a);p.lineTo(o+e,d+a);p.bezierCurveTo(o,d+a,o,d+a-l,o,d+a-l);p.lineTo(o,d+l);p.bezierCurveTo(o,d,o+e,d,o+e,d);p.closePath();this.fill&&p.fill();this.stroke&&p.stroke()},_normalizeLeftTopProperties:function(p){p.left&&this.set("left",p.left+this.getWidth()/2);p.top&&this.set("top",p.top+this.getHeight()/2);return this},complexity:function(){return 1}});h.Rect.ATTRIBUTE_NAMES= -"x y width height rx ry fill fill-opacity stroke stroke-width transform".split(" ");h.Rect.fromElement=function(p,e){if(!p)return null;var l=h.parseAttributes(p,h.Rect.ATTRIBUTE_NAMES);l=l;l.left=l.left||0;l.top=l.top||0;l=l;var o=new h.Rect(h.util.object.extend(e||{},l));o._normalizeLeftTopProperties(l);return o};h.Rect.fromObject=function(p){return new h.Rect(p)}}})(); -(function(){var h=this.fabric||(this.fabric={});if(h.Polyline)h.warn("fabric.Polyline is already defined");else{h.Polyline=h.util.createClass(h.Object,{type:"polyline",initialize:function(e,l){l=l||{};this.set("points",e);this.callSuper("initialize",l);this._calcDimensions()},_calcDimensions:function(){return h.Polygon.prototype._calcDimensions.call(this)},toObject:function(){return h.Polygon.prototype.toObject.call(this)},_render:function(e){var l;e.beginPath();for(var o=0,d=this.points.length;o< -d;o++){l=this.points[o];e.lineTo(l.x,l.y)}this.fill&&e.fill();this.stroke&&e.stroke()},complexity:function(){return this.get("points").length}});var p="fill fill-opacity stroke stroke-width transform".split(" ");h.Polyline.fromElement=function(e,l){if(!e)return null;l||(l={});for(var o=h.parsePointsAttribute(e.getAttribute("points")),d=h.parseAttributes(e,p),c=0,a=o.length;c"},toObject:function(){var d=l(this.callSuper("toObject"),{path:this.path});if(this.sourcePath)d.sourcePath=this.sourcePath;if(this.transformMatrix)d.transformMatrix=this.transformMatrix;return d},toDatalessObject:function(){var d=this.toObject();if(this.sourcePath)d.path=this.sourcePath;delete d.sourcePath;return d},complexity:function(){return this.path.length},set:function(d,c){return this.callSuper("set",d,c)},_parsePath:function(){for(var d= -[],c,a,b=0,g=this.path.length;b"},isSameColor:function(){var a=this.getObjects()[0].get("fill");return this.getObjects().every(function(b){return b.get("fill")===a})},complexity:function(){return this.paths.reduce(function(a,b){return a+(b&&b.complexity?b.complexity():0)},0)},toGrayscale:function(){for(var a=this.paths.length;a--;)this.paths[a].toGrayscale();return this},getObjects:function(){return this.paths}});h.PathGroup.fromObject=function(a){for(var b=a.paths, -g=0,m=b.length;g"},getObjects:function(){return this.objects},add:function(c){this._restoreObjectsState();this.objects.push(c);c.setActive(true);this._calcBounds();this._updateObjectsCoords();return this},remove:function(c){this._restoreObjectsState(); -d(this.objects,c);c.setActive(false);this._calcBounds();this._updateObjectsCoords();return this},size:function(){return this.getObjects().length},set:function(c,a){if(typeof a=="function")this.set(c,a(this[c]));else if(c==="fill"||c==="opacity"){var b=this.objects.length;for(this[c]=a;b--;)this.objects[b].set(c,a)}else this[c]=a;return this},contains:function(c){return this.objects.indexOf(c)>-1},toObject:function(){return p(this.callSuper("toObject"),{objects:o(this.objects,"clone")})},render:function(c){c.save(); -this.transform(c);for(var a=Math.max(this.scaleX,this.scaleY),b=0,g;g=this.objects[b];b++){var m=g.borderScaleFactor;g.borderScaleFactor=a;g.render(c);g.borderScaleFactor=m}this.hideBorders||this.drawBorders(c);this.hideCorners||this.drawCorners(c);c.restore();this.setCoords()},item:function(c){return this.getObjects()[c]},complexity:function(){return this.getObjects().reduce(function(c,a){c+=typeof a.complexity=="function"?a.complexity():0;return c},0)},_restoreObjectsState:function(){this.objects.forEach(this._restoreObjectState, -this);return this},_restoreObjectState:function(c){var a=this.get("left"),b=this.get("top"),g=this.getAngle()*(Math.PI/180);c.get("originalLeft");c.get("originalTop");var m=Math.cos(g)*c.get("top")+Math.sin(g)*c.get("left");g=-Math.sin(g)*c.get("top")+Math.cos(g)*c.get("left");c.setAngle(c.getAngle()+this.getAngle());c.set("left",a+g*this.get("scaleX"));c.set("top",b+m*this.get("scaleY"));c.set("scaleX",c.get("scaleX")*this.get("scaleX"));c.set("scaleY",c.get("scaleY")*this.get("scaleY"));c.setCoords(); -c.hideCorners=false;c.setActive(false);c.setCoords();return this},destroy:function(){return this._restoreObjectsState()},saveCoords:function(){this._originalLeft=this.get("left");this._originalTop=this.get("top");return this},hasMoved:function(){return this._originalLeft!==this.get("left")||this._originalTop!==this.get("top")},setObjectsCoords:function(){this.forEachObject(function(c){c.setCoords()});return this},activateAllObjects:function(){return this.setActive(true)},setActive:function(c){this.forEachObject(function(a){a.setActive(c)}); -return this},forEachObject:function(c,a){for(var b=this.getObjects(),g=b.length;g--;)c.call(a,b[g],g,b);return this},_setOpacityIfSame:function(){var c=this.getObjects(),a=c[0]?c[0].get("opacity"):1;if(c.every(function(b){return b.get("opacity")===a}))this.opacity=a},_calcBounds:function(){var c=[],a=[],b,g;g=0;for(var m=this.objects.length;gc.x&&m-bc.y},toGrayscale:function(){for(var c=this.objects.length;c--;)this.objects[c].toGrayscale()}});h.Group.fromObject=function(c){return new h.Group(c.objects,c)}}})(); -(function(){var h=this.fabric||(this.fabric={}),p=h.util.object.extend,e=h.util.object.clone;if(h.Text)h.warn("fabric.Text is already defined");else if(h.Object){h.Text=h.util.createClass(h.Object,{options:{top:10,left:10,fontsize:20,fontweight:100,fontfamily:"Modernist_One_400",path:null},type:"text",initialize:function(l,o){this.originalState={};this.initStateProperties();this.text=l;this.setOptions(o);p(this,this.options);this.theta=this.angle*(Math.PI/180);this.width=this.getWidth();this.setCoords()}, -initStateProperties:function(){var l;if((l=this.constructor)&&(l=l.superclass)&&(l=l.prototype)&&(l=l.stateProperties)&&l.clone){this.stateProperties=l.clone();this.stateProperties.push("fontfamily","fontweight","path")}},toString:function(){return"#"},_render:function(l){var o=Cufon.textOptions||(Cufon.textOptions={});o.left=this.left;o.top=this.top;o.context=l;o.color=this.fill;var d=this._initDummyElement(); -this.transform(l);Cufon.replaceElement(d,{separate:"none",fontFamily:this.fontfamily});this.width=o.width;this.height=o.height},_initDummyElement:function(){var l=document.createElement("div");l.innerHTML=this.text;l.style.fontSize="40px";l.style.fontWeight="400";l.style.fontStyle="normal";l.style.letterSpacing="normal";l.style.color="#000000";l.style.fontWeight="600";l.style.fontFamily="Verdana";return l},render:function(l){l.save();this._render(l);if(this.active){this.drawBorders(l);this.drawCorners(l)}l.restore()}, -toObject:function(){return p(this.callSuper("toObject"),{text:this.text,fontsize:this.fontsize,fontweight:this.fontweight,fontfamily:this.fontfamily,path:this.path})},setColor:function(l){this.set("fill",l);return this},setFontsize:function(l){this.set("fontsize",l);this.setCoords();return this},getText:function(){return this.text},setText:function(l){this.set("text",l);this.setCoords();return this},set:function(l,o){this[l]=o;if(l==="fontfamily")this.path=this.path.replace(/(.*?)([^\/]*)(\.font\.js)/, -"$1"+o+"$3");return this}});h.Text.fromObject=function(l){return new h.Text(l.text,e(l))};h.Text.fromElement=function(){}}else h.warn("fabric.Text requires fabric.Object")})(); -(function(){var h=fabric.util.object.extend;if(!this.fabric)this.fabric={};if(this.fabric.Image)fabric.warn("fabric.Image is already defined.");else if(fabric.Object){fabric.Image=fabric.util.createClass(fabric.Object,{maxwidth:null,maxheight:null,active:false,bordervisibility:false,cornervisibility:false,type:"image",__isGrayscaled:false,initialize:function(p,e){this.callSuper("initialize",e);this._initElement(p);this._initConfig(e||{})},getElement:function(){return this._element},setElement:function(p){this._element= -p;return this},getNormalizedSize:function(p,e,l){if(l&&e&&p.width>p.height&&p.width/p.heightp.width||p.height>l)){normalizedWidth=~~(p.width*l/p.height);normalizedHeight=l}else if(e&&e'},clone:function(p){this.constructor.fromObject(this.toObject(),p)},toGrayscale:function(p){if(!this.__isGrayscaled){var e=this.getElement(),l=document.createElement("canvas"),o=document.createElement("img"),d=this;l.width=e.width;l.height=e.height;l.getContext("2d").drawImage(e,0,0);fabric.Element.toGrayscale(l);o.onload=function(){d.setElement(o);p&&p();o.onload=l=e=imageData=null};o.width=e.width;o.height=e.height;o.src=l.toDataURL("image/png");this.__isGrayscaled=true;return this}}, -_render:function(p){var e=this.getOriginalSize();p.drawImage(this.getElement(),-e.width/2,-e.height/2,e.width,e.height)},_adjustWidthHeightToBorders:function(p){if(p){this.currentBorder=this.borderwidth;this.width+=2*this.currentBorder;this.height+=2*this.currentBorder}else this.currentBorder=0},_resetWidthHeight:function(){var p=this.getElement();this.set("width",p.width);this.set("height",p.height)},_initElement:function(p){this.setElement(fabric.util.getById(p));fabric.util.addClass(this.getElement(), -fabric.Image.CSS_CANVAS)},_initConfig:function(p){this.setOptions(p);this._setBorder();this._setWidthHeight(p)},_setBorder:function(){this.currentBorder=this.bordervisibility?this.borderwidth:0},_setWidthHeight:function(){var p=2*this.currentBorder;this.width=(this.getElement().width||0)+p;this.height=(this.getElement().height||0)+p},complexity:function(){return 1}});fabric.Image.CSS_CANVAS="canvas-img";fabric.Image.fromObject=function(p,e){var l=document.createElement("img"),o=p.src;if(p.width)l.width= -p.width;if(p.height)l.height=p.height;l.onload=function(){e&&e(new fabric.Image(l,p));l=l.onload=null};l.src=o};fabric.Image.fromURL=function(p,e,l){var o=document.createElement("img");o.onload=function(){e&&e(new fabric.Image(o,l));o=o.onload=null};o.src=p}}else fabric.warn("fabric.Object is required for fabric.Image initialization")})(); +2,2)+Math.pow(this.currentHeight/2,2));this._angle=Math.atan(this.currentHeight/this.currentWidth);var a=Math.cos(this._angle+this.theta)*this._hypotenuse,b=Math.sin(this._angle+this.theta)*this._hypotenuse,d=this.theta,m=Math.sin(d);d=Math.cos(d);a={x:this.left-a,y:this.top-b};b={x:a.x+this.currentWidth*d,y:a.y+this.currentWidth*m};var q={x:a.x-this.currentHeight*m,y:a.y+this.currentHeight*d};this.oCoords={tl:a,tr:b,br:{x:b.x-this.currentHeight*m,y:b.y+this.currentHeight*d},bl:q,ml:{x:a.x-this.currentHeight/ +2*m,y:a.y+this.currentHeight/2*d},mt:{x:a.x+this.currentWidth/2*d,y:a.y+this.currentWidth/2*m},mr:{x:b.x-this.currentHeight/2*m,y:b.y+this.currentHeight/2*d},mb:{x:q.x+this.currentWidth/2*d,y:q.y+this.currentWidth/2*m}};this._setCornerCoords();return this},drawBorders:function(a){var b=this.options,d=b.padding,m=d*2;a.save();a.globalAlpha=this.isMoving?b.borderOpacityWhenMoving:1;a.strokeStyle=b.borderColor;b=1/(this.scaleXa.x&&q.xa.y&&r.y=b&&r.d.y>=b)){if(r.o.x==r.d.x&&r.o.x>=a)m=r.o.x;else{m=(r.d.y-r.o.y)/(r.d.x-r.o.x);q=b-0*a;r=r.o.y-m*r.o.x;m=-(q-r)/(0-m)}if(m>=a)v+=1;if(v==2)break}}return v},_getImageLines:function(a){return{topline:{o:a.tl,d:a.tr},rightline:{o:a.tr,d:a.br},bottomline:{o:a.br,d:a.bl},leftline:{o:a.bl,d:a.tl}}},_setCornerCoords:function(){var a=this.oCoords,b=this.theta,d=this.cornersize*Math.cos(b),m=this.cornersize*Math.sin(b);b=this.cornersize/2;var q=b-m;a.tl.x-=q;a.tl.y-= +b;a.tl.corner={tl:{x:a.tl.x,y:a.tl.y},tr:{x:a.tl.x+d,y:a.tl.y+m},bl:{x:a.tl.x-m,y:a.tl.y+d}};a.tl.corner.br={x:a.tl.corner.tr.x-m,y:a.tl.corner.tr.y+d};a.tl.x+=q;a.tl.y+=b;a.tr.x+=b;a.tr.y-=b;a.tr.corner={tl:{x:a.tr.x-d,y:a.tr.y-m},tr:{x:a.tr.x,y:a.tr.y},br:{x:a.tr.x-m,y:a.tr.y+d}};a.tr.corner.bl={x:a.tr.corner.tl.x-m,y:a.tr.corner.tl.y+d};a.tr.x-=b;a.tr.y+=b;a.bl.x-=b;a.bl.y+=b;a.bl.corner={tl:{x:a.bl.x+m,y:a.bl.y-d},bl:{x:a.bl.x,y:a.bl.y},br:{x:a.bl.x+d,y:a.bl.y+m}};a.bl.corner.tr={x:a.bl.corner.br.x+ +m,y:a.bl.corner.br.y-d};a.bl.x+=b;a.bl.y-=b;a.br.x+=b;a.br.y+=b;a.br.corner={tr:{x:a.br.x+m,y:a.br.y-d},bl:{x:a.br.x-d,y:a.br.y-m},br:{x:a.br.x,y:a.br.y}};a.br.corner.tl={x:a.br.corner.bl.x+m,y:a.br.corner.bl.y-d};a.br.x-=b;a.br.y-=b;a.ml.x-=b;a.ml.y-=b;a.ml.corner={tl:{x:a.ml.x,y:a.ml.y},tr:{x:a.ml.x+d,y:a.ml.y+m},bl:{x:a.ml.x-m,y:a.ml.y+d}};a.ml.corner.br={x:a.ml.corner.tr.x-m,y:a.ml.corner.tr.y+d};a.ml.x+=b;a.ml.y+=b;a.mt.x-=b;a.mt.y-=b;a.mt.corner={tl:{x:a.mt.x,y:a.mt.y},tr:{x:a.mt.x+d,y:a.mt.y+ +m},bl:{x:a.mt.x-m,y:a.mt.y+d}};a.mt.corner.br={x:a.mt.corner.tr.x-m,y:a.mt.corner.tr.y+d};a.mt.x+=b;a.mt.y+=b;a.mr.x-=b;a.mr.y-=b;a.mr.corner={tl:{x:a.mr.x,y:a.mr.y},tr:{x:a.mr.x+d,y:a.mr.y+m},bl:{x:a.mr.x-m,y:a.mr.y+d}};a.mr.corner.br={x:a.mr.corner.tr.x-m,y:a.mr.corner.tr.y+d};a.mr.x+=b;a.mr.y+=b;a.mb.x-=b;a.mb.y-=b;a.mb.corner={tl:{x:a.mb.x,y:a.mb.y},tr:{x:a.mb.x+d,y:a.mb.y+m},bl:{x:a.mb.x-m,y:a.mb.y+d}};a.mb.corner.br={x:a.mb.corner.tr.x-m,y:a.mb.corner.tr.y+d};a.mb.x+=b;a.mb.y+=b;a=a.mb.corner; +a.tl.x-=b;a.tl.y-=b;a.tr.x-=b;a.tr.y-=b;a.br.x-=b;a.br.y-=b;a.bl.x-=b;a.bl.y-=b},toGrayscale:function(){var a=this.get("fill");a&&this.set("overlayFill",(new l.Color(a)).toGrayscale().toRgb());return this},complexity:function(){return 0},getCenter:function(){return{x:this.get("left")+this.width/2,y:this.get("top")+this.height/2}},straighten:function(){this.setAngle(this._getAngleValueForStraighten());return this},fxStraighten:function(a){a=a||{};var b=function(){},d=a.onComplete||b,m=a.onChange|| +b,q=this;l.util.animate({startValue:this.get("angle"),endValue:this._getAngleValueForStraighten(),duration:this.FX_DURATION,onChange:function(r){q.setAngle(r);m()},onComplete:function(){q.setCoords();d()},onStart:function(){q.setActive(false)}});return this},fxRemove:function(a){a||(a={});var b=function(){},d=a.onComplete||b,m=a.onChange||b,q=this;l.util.animate({startValue:this.get("opacity"),endValue:0,duration:this.FX_DURATION,onChange:function(r){q.set("opacity",r);m()},onComplete:d,onStart:function(){q.setActive(false)}}); +return this},_getAngleValueForStraighten:function(){var a=this.get("angle");if(a>-225&&a<=-135)return-180;else if(a>-135&&a<=-45)return-90;else if(a>-45&&a<=45)return 0;else if(a>45&&a<=135)return 90;else if(a>135&&a<=225)return 180;else if(a>225&&a<=315)return 270;else if(a>315)return 360;return 0},toJSON:function(){return this.toObject()}});l.Object.prototype.rotate=l.Object.prototype.setAngle}})(); +(function(){var l=this.fabric||(this.fabric={}),n=l.util.object.extend;if(l.Line)l.warn("fabric.Line is already defined");else{l.Line=l.util.createClass(l.Object,{type:"line",initialize:function(c,k){c||(c=[0,0,0,0]);this.callSuper("initialize",k);this.set("x1",c[0]);this.set("y1",c[1]);this.set("x2",c[2]);this.set("y2",c[3]);this.set("width",this.x2-this.x1);this.set("height",this.y2-this.y1);this.set("left",this.x1+this.width/2);this.set("top",this.y1+this.height/2)},_render:function(c){c.beginPath(); +c.moveTo(-this.width/2,-this.height/2);c.lineTo(this.width/2,this.height/2);var k=c.strokeStyle;c.strokeStyle=c.fillStyle;c.stroke();c.strokeStyle=k},complexity:function(){return 1},toObject:function(){return n(this.callSuper("toObject"),{x1:this.get("x1"),y1:this.get("y1"),x2:this.get("x2"),y2:this.get("y2")})}});l.Element.ATTRIBUTE_NAMES="x1 y1 x2 y2 stroke stroke-width transform".split(" ");l.Line.fromElement=function(c,k){var p=l.parseAttributes(c,l.Element.ATTRIBUTE_NAMES);return new l.Line([p.x1|| +0,p.y1||0,p.x2||0,p.y2||0],n(p,k))};l.Line.fromObject=function(c){return new l.Line([c.x1,c.y1,c.x2,c.y2],c)}}})(); +(function(){var l=this.fabric||(this.fabric={}),n=Math.PI*2,c=l.util.object.extend;if(l.Circle)l.warn("fabric.Circle is already defined.");else{l.Circle=l.util.createClass(l.Object,{type:"circle",initialize:function(k){k=k||{};this.set("radius",k.radius||0);this.callSuper("initialize",k);k=this.get("radius")*2*this.get("scaleX");this.set("width",k).set("height",k)},toObject:function(){return c(this.callSuper("toObject"),{radius:this.get("radius")})},_render:function(k,p){k.beginPath();k.arc(p?this.left: +0,p?this.top:0,this.radius,0,n,false);k.closePath();this.fill&&k.fill();this.stroke&&k.stroke()},complexity:function(){return 1}});l.Circle.ATTRIBUTE_NAMES="cx cy r fill fill-opacity stroke stroke-width transform".split(" ");l.Circle.fromElement=function(k,p){p||(p={});var g=l.parseAttributes(k,l.Circle.ATTRIBUTE_NAMES);if(!("radius"in g&&g.radius>0))throw Error("value of `r` attribute is required and can not be negative");if("left"in g)g.left-=p.width/2||0;if("top"in g)g.top-=p.height/2||0;return new l.Circle(c(g, +p))};l.Circle.fromObject=function(k){return new l.Circle(k)}}})(); +(function(){var l=this.fabric||(this.fabric={});if(l.Triangle)l.warn("fabric.Triangle is already defined");else{l.Triangle=l.util.createClass(l.Object,{type:"triangle",initialize:function(n){n=n||{};this.callSuper("initialize",n);this.set("width",n.width||100).set("height",n.height||100)},_render:function(n){var c=this.width/2,k=this.height/2;n.beginPath();n.moveTo(-c,k);n.lineTo(0,-k);n.lineTo(c,k);n.closePath();this.fill&&n.fill();this.stroke&&n.stroke()},complexity:function(){return 1}});l.Triangle.fromObject= +function(n){return new l.Triangle(n)}}})(); +(function(){var l=this.fabric||(this.fabric={}),n=Math.PI*2,c=l.util.object.extend;if(l.Ellipse)l.warn("fabric.Ellipse is already defined.");else{l.Ellipse=l.util.createClass(l.Object,{type:"ellipse",initialize:function(k){k=k||{};this.callSuper("initialize",k);this.set("rx",k.rx||0);this.set("ry",k.ry||0);this.set("width",this.get("rx")*2);this.set("height",this.get("ry")*2)},toObject:function(){return c(this.callSuper("toObject"),{rx:this.get("rx"),ry:this.get("ry")})},render:function(k,p){if(!(this.rx=== +0||this.ry===0))return this.callSuper("render",k,p)},_render:function(k,p){k.beginPath();k.save();k.transform(1,0,0,this.ry/this.rx,0,0);k.arc(p?this.left:0,p?this.top:0,this.rx,0,n,false);k.restore();this.stroke&&k.stroke();this.fill&&k.fill()},complexity:function(){return 1}});l.Ellipse.ATTRIBUTE_NAMES="cx cy rx ry fill fill-opacity stroke stroke-width transform".split(" ");l.Ellipse.fromElement=function(k,p){p||(p={});var g=l.parseAttributes(k,l.Ellipse.ATTRIBUTE_NAMES);if("left"in g)g.left-=p.width/ +2||0;if("top"in g)g.top-=p.height/2||0;return new l.Ellipse(c(g,p))};l.Ellipse.fromObject=function(k){return new l.Ellipse(k)}}})(); +(function(){var l=this.fabric||(this.fabric={});if(l.Rect)console.warn("fabric.Rect is already defined");else{l.Rect=l.util.createClass(l.Object,{type:"rect",options:{rx:0,ry:0},initialize:function(n){this.callSuper("initialize",n);this._initRxRy()},_initRxRy:function(){if(this.options.rx&&!this.options.ry)this.options.ry=this.options.rx;else if(this.options.ry&&!this.options.rx)this.options.rx=this.options.ry},_render:function(n){var c=this.options.rx||0,k=this.options.ry||0,p=-this.width/2,g=-this.height/ +2,f=this.width,a=this.height;n.beginPath();n.moveTo(p+c,g);n.lineTo(p+f-c,g);n.bezierCurveTo(p+f,g,p+f,g+k,p+f,g+k);n.lineTo(p+f,g+a-k);n.bezierCurveTo(p+f,g+a,p+f-c,g+a,p+f-c,g+a);n.lineTo(p+c,g+a);n.bezierCurveTo(p,g+a,p,g+a-k,p,g+a-k);n.lineTo(p,g+k);n.bezierCurveTo(p,g,p+c,g,p+c,g);n.closePath();this.fill&&n.fill();this.stroke&&n.stroke()},_normalizeLeftTopProperties:function(n){n.left&&this.set("left",n.left+this.getWidth()/2);n.top&&this.set("top",n.top+this.getHeight()/2);return this},complexity:function(){return 1}}); +l.Rect.ATTRIBUTE_NAMES="x y width height rx ry fill fill-opacity stroke stroke-width transform".split(" ");l.Rect.fromElement=function(n,c){if(!n)return null;var k=l.parseAttributes(n,l.Rect.ATTRIBUTE_NAMES);k=k;k.left=k.left||0;k.top=k.top||0;k=k;var p=new l.Rect(l.util.object.extend(c||{},k));p._normalizeLeftTopProperties(k);return p};l.Rect.fromObject=function(n){return new l.Rect(n)}}})(); +(function(){var l=this.fabric||(this.fabric={});if(l.Polyline)l.warn("fabric.Polyline is already defined");else{l.Polyline=l.util.createClass(l.Object,{type:"polyline",initialize:function(c,k){k=k||{};this.set("points",c);this.callSuper("initialize",k);this._calcDimensions()},_calcDimensions:function(){return l.Polygon.prototype._calcDimensions.call(this)},toObject:function(){return l.Polygon.prototype.toObject.call(this)},_render:function(c){var k;c.beginPath();for(var p=0,g=this.points.length;p< +g;p++){k=this.points[p];c.lineTo(k.x,k.y)}this.fill&&c.fill();this.stroke&&c.stroke()},complexity:function(){return this.get("points").length}});var n="fill fill-opacity stroke stroke-width transform".split(" ");l.Polyline.fromElement=function(c,k){if(!c)return null;k||(k={});for(var p=l.parsePointsAttribute(c.getAttribute("points")),g=l.parseAttributes(c,n),f=0,a=p.length;f"},toObject:function(){var a=g(this.callSuper("toObject"),{path:this.path});if(this.sourcePath)a.sourcePath=this.sourcePath;if(this.transformMatrix)a.transformMatrix=this.transformMatrix;return a},toDatalessObject:function(){var a=this.toObject();if(this.sourcePath)a.path= +this.sourcePath;delete a.sourcePath;return a},complexity:function(){return this.path.length},set:function(a,b){return this.callSuper("set",a,b)},_parsePath:function(){for(var a=[],b,d,m=0,q=this.path.length;m"},isSameColor:function(){var a=this.getObjects()[0].get("fill");return this.getObjects().every(function(b){return b.get("fill")===a})},complexity:function(){return this.paths.reduce(function(a,b){return a+(b&&b.complexity?b.complexity():0)},0)},toGrayscale:function(){for(var a=this.paths.length;a--;)this.paths[a].toGrayscale();return this},getObjects:function(){return this.paths}});l.PathGroup.fromObject=function(a){for(var b=a.paths, +d=0,m=b.length;d"},getObjects:function(){return this.objects},add:function(f){this._restoreObjectsState();this.objects.push(f);f.setActive(true);this._calcBounds();this._updateObjectsCoords();return this},remove:function(f){this._restoreObjectsState(); +g(this.objects,f);f.setActive(false);this._calcBounds();this._updateObjectsCoords();return this},size:function(){return this.getObjects().length},set:function(f,a){if(typeof a=="function")this.set(f,a(this[f]));else if(f==="fill"||f==="opacity"){var b=this.objects.length;for(this[f]=a;b--;)this.objects[b].set(f,a)}else this[f]=a;return this},contains:function(f){return this.objects.indexOf(f)>-1},toObject:function(){return n(this.callSuper("toObject"),{objects:p(this.objects,"clone")})},render:function(f){f.save(); +this.transform(f);for(var a=Math.max(this.scaleX,this.scaleY),b=0,d;d=this.objects[b];b++){var m=d.borderScaleFactor;d.borderScaleFactor=a;d.render(f);d.borderScaleFactor=m}this.hideBorders||this.drawBorders(f);this.hideCorners||this.drawCorners(f);f.restore();this.setCoords()},item:function(f){return this.getObjects()[f]},complexity:function(){return this.getObjects().reduce(function(f,a){f+=typeof a.complexity=="function"?a.complexity():0;return f},0)},_restoreObjectsState:function(){this.objects.forEach(this._restoreObjectState, +this);return this},_restoreObjectState:function(f){var a=this.get("left"),b=this.get("top"),d=this.getAngle()*(Math.PI/180);f.get("originalLeft");f.get("originalTop");var m=Math.cos(d)*f.get("top")+Math.sin(d)*f.get("left");d=-Math.sin(d)*f.get("top")+Math.cos(d)*f.get("left");f.setAngle(f.getAngle()+this.getAngle());f.set("left",a+d*this.get("scaleX"));f.set("top",b+m*this.get("scaleY"));f.set("scaleX",f.get("scaleX")*this.get("scaleX"));f.set("scaleY",f.get("scaleY")*this.get("scaleY"));f.setCoords(); +f.hideCorners=false;f.setActive(false);f.setCoords();return this},destroy:function(){return this._restoreObjectsState()},saveCoords:function(){this._originalLeft=this.get("left");this._originalTop=this.get("top");return this},hasMoved:function(){return this._originalLeft!==this.get("left")||this._originalTop!==this.get("top")},setObjectsCoords:function(){this.forEachObject(function(f){f.setCoords()});return this},activateAllObjects:function(){return this.setActive(true)},setActive:function(f){this.forEachObject(function(a){a.setActive(f)}); +return this},forEachObject:function(f,a){for(var b=this.getObjects(),d=b.length;d--;)f.call(a,b[d],d,b);return this},_setOpacityIfSame:function(){var f=this.getObjects(),a=f[0]?f[0].get("opacity"):1;if(f.every(function(b){return b.get("opacity")===a}))this.opacity=a},_calcBounds:function(){var f=[],a=[],b,d;d=0;for(var m=this.objects.length;df.x&&m-bf.y},toGrayscale:function(){for(var f=this.objects.length;f--;)this.objects[f].toGrayscale()}});l.Group.fromObject=function(f){return new l.Group(f.objects,f)}}})(); +(function(){var l=this.fabric||(this.fabric={}),n=l.util.object.extend,c=l.util.object.clone;if(l.Text)l.warn("fabric.Text is already defined");else if(l.Object){l.Text=l.util.createClass(l.Object,{options:{top:10,left:10,fontsize:20,fontweight:100,fontfamily:"Modernist_One_400",path:null},type:"text",initialize:function(k,p){this.originalState={};this.initStateProperties();this.text=k;this.setOptions(p);n(this,this.options);this.theta=this.angle*(Math.PI/180);this.width=this.getWidth();this.setCoords()}, +initStateProperties:function(){var k;if((k=this.constructor)&&(k=k.superclass)&&(k=k.prototype)&&(k=k.stateProperties)&&k.clone){this.stateProperties=k.clone();this.stateProperties.push("fontfamily","fontweight","path")}},toString:function(){return"#"},_render:function(k){var p=Cufon.textOptions||(Cufon.textOptions={});p.left=this.left;p.top=this.top;p.context=k;p.color=this.fill;var g=this._initDummyElement(); +this.transform(k);Cufon.replaceElement(g,{separate:"none",fontFamily:this.fontfamily});this.width=p.width;this.height=p.height},_initDummyElement:function(){var k=document.createElement("div");k.innerHTML=this.text;k.style.fontSize="40px";k.style.fontWeight="400";k.style.fontStyle="normal";k.style.letterSpacing="normal";k.style.color="#000000";k.style.fontWeight="600";k.style.fontFamily="Verdana";return k},render:function(k){k.save();this._render(k);if(this.active){this.drawBorders(k);this.drawCorners(k)}k.restore()}, +toObject:function(){return n(this.callSuper("toObject"),{text:this.text,fontsize:this.fontsize,fontweight:this.fontweight,fontfamily:this.fontfamily,path:this.path})},setColor:function(k){this.set("fill",k);return this},setFontsize:function(k){this.set("fontsize",k);this.setCoords();return this},getText:function(){return this.text},setText:function(k){this.set("text",k);this.setCoords();return this},set:function(k,p){this[k]=p;if(k==="fontfamily")this.path=this.path.replace(/(.*?)([^\/]*)(\.font\.js)/, +"$1"+p+"$3");return this}});l.Text.fromObject=function(k){return new l.Text(k.text,c(k))};l.Text.fromElement=function(){}}else l.warn("fabric.Text requires fabric.Object")})(); +(function(){var l=fabric.util.object.extend;if(!this.fabric)this.fabric={};if(this.fabric.Image)fabric.warn("fabric.Image is already defined.");else if(fabric.Object){fabric.Image=fabric.util.createClass(fabric.Object,{maxwidth:null,maxheight:null,active:false,bordervisibility:false,cornervisibility:false,type:"image",__isGrayscaled:false,initialize:function(n,c){this.callSuper("initialize",c);this._initElement(n);this._initConfig(c||{})},getElement:function(){return this._element},setElement:function(n){this._element= +n;return this},getNormalizedSize:function(n,c,k){if(k&&c&&n.width>n.height&&n.width/n.heightn.width||n.height>k)){normalizedWidth=~~(n.width*k/n.height);normalizedHeight=k}else if(c&&c'},clone:function(n){this.constructor.fromObject(this.toObject(),n)},toGrayscale:function(n){if(!this.__isGrayscaled){var c=this.getElement(),k=document.createElement("canvas"),p=document.createElement("img"),g=this;k.width=c.width;k.height=c.height;k.getContext("2d").drawImage(c,0,0);fabric.Element.toGrayscale(k);p.onload=function(){g.setElement(p);n&&n();p.onload=k=c=imageData=null};p.width=c.width;p.height=c.height;p.src=k.toDataURL("image/png"); +this.__isGrayscaled=true;return this}},_render:function(n){var c=this.getOriginalSize();n.drawImage(this.getElement(),-c.width/2,-c.height/2,c.width,c.height)},_adjustWidthHeightToBorders:function(n){if(n){this.currentBorder=this.borderwidth;this.width+=2*this.currentBorder;this.height+=2*this.currentBorder}else this.currentBorder=0},_resetWidthHeight:function(){var n=this.getElement();this.set("width",n.width);this.set("height",n.height)},_initElement:function(n){this.setElement(fabric.util.getById(n)); +fabric.util.addClass(this.getElement(),fabric.Image.CSS_CANVAS)},_initConfig:function(n){this.setOptions(n);this._setBorder();this._setWidthHeight(n)},_setBorder:function(){this.currentBorder=this.bordervisibility?this.borderwidth:0},_setWidthHeight:function(){var n=2*this.currentBorder;this.width=(this.getElement().width||0)+n;this.height=(this.getElement().height||0)+n},complexity:function(){return 1}});fabric.Image.CSS_CANVAS="canvas-img";fabric.Image.fromObject=function(n,c){var k=document.createElement("img"), +p=n.src;if(n.width)k.width=n.width;if(n.height)k.height=n.height;k.onload=function(){c&&c(new fabric.Image(k,n));k=k.onload=null};k.src=p};fabric.Image.fromURL=function(n,c,k){var p=document.createElement("img");p.onload=function(){c&&c(new fabric.Image(p,k));p=p.onload=null};p.src=n}}else fabric.warn("fabric.Object is required for fabric.Image initialization")})(); diff --git a/fabric.js b/fabric.js index 4dc0d4b8..ef1712ec 100644 --- a/fabric.js +++ b/fabric.js @@ -2,7 +2,18 @@ var fabric = fabric || { version: 0.1 }; +/** + * Wrapper around `console.log` (when available) + * @method log + * @param {Any} Values to log + */ fabric.log = function() { }; + +/** + * Wrapper around `console.warn` (when available) + * @method warn + * @param {Any} Values to log as a warning + */ fabric.warn = function() { }; if (typeof console !== 'undefined') { diff --git a/src/circle.class.js b/src/circle.class.js index 6ae61b69..d2f968bd 100644 --- a/src/circle.class.js +++ b/src/circle.class.js @@ -10,16 +10,17 @@ fabric.warn('fabric.Circle is already defined.'); return; } - - fabric.Circle = fabric.util.createClass(fabric.Object, /** @lends fabric.Circle.prototype */ { + + /** + * @class Circle + * @extends fabric.Object + */ + fabric.Circle = fabric.util.createClass(fabric.Object, /** @scope fabric.Circle.prototype */ { - /** - * @field - */ + /** @property */ type: 'circle', /** - * @constructs * @method initialize * @param options {Object} options object * @return {Object} thisArg @@ -74,11 +75,14 @@ }); /** + * List of attribute names to account for when parsing SVG element (used by `fabric.Circle.fromElement`) + * @static * @see: http://www.w3.org/TR/SVG/shapes.html#CircleElement */ fabric.Circle.ATTRIBUTE_NAMES = 'cx cy r fill fill-opacity stroke stroke-width transform'.split(' '); /** + * Returns fabric.Circle instance from an SVG element * @static * @method fabric.Circle.fromElement * @param element {SVGElement} element to parse @@ -109,10 +113,11 @@ } /** + * Returns fabric.Circle instance from an object representation * @static * @method fabric.Circle.fromObject - * @param object {Object} object to create an instance from - * @return {Object} instance of fabric.Circle + * @param {Object} object Object to create an instance from + * @return {Object} Instance of fabric.Circle */ fabric.Circle.fromObject = function(object) { return new fabric.Circle(object); diff --git a/src/color.class.js b/src/color.class.js index dc0b1252..b0f2de32 100644 --- a/src/color.class.js +++ b/src/color.class.js @@ -7,10 +7,12 @@ return; } - fabric.Color = Color; - /** - * @constructor + * The purpose of fabric.Color is to abstract and encapsulate common color operations; + * fabric.Color is a constructor and creates instances of fabric.Color objects. + * + * @class Color + * @memberOf fabric * @param {String} color (optional) in hex or rgb(a) format */ function Color(color) { @@ -22,173 +24,191 @@ } } - /** - * @private - * @method _tryParsingColor - */ - Color.prototype._tryParsingColor = function(color) { - var source = Color.sourceFromHex(color); - if (!source) { - source = Color.sourceFromRgb(color); - } - if (source) { + fabric.Color = Color; + + fabric.Color.prototype = /** @scope fabric.Color.prototype */ { + + /** + * @private + * @method _tryParsingColor + */ + _tryParsingColor: function(color) { + var source = Color.sourceFromHex(color); + if (!source) { + source = Color.sourceFromRgb(color); + } + if (source) { + this.setSource(source); + } + }, + + /** + * Returns source of this color (where source is an array representation; ex: [200, 200, 100, 1]) + * @method getSource + * @return {Array} + */ + getSource: function() { + return this._source; + }, + + /** + * Sets source of this color (where source is an array representation; ex: [200, 200, 100, 1]) + * @method setSource + * @param {Array} source + */ + setSource: function(source) { + this._source = source; + }, + + /** + * Returns color represenation in RGB format + * @method toRgb + * @return {String} ex: rgb(0-255,0-255,0-255) + */ + toRgb: function() { + var source = this.getSource(); + return 'rgb(' + source[0] + ',' + source[1] + ',' + source[2] + ')'; + }, + + /** + * Returns color represenation in RGBA format + * @method toRgba + * @return {String} ex: rgba(0-255,0-255,0-255,0-1) + */ + toRgba: function() { + var source = this.getSource(); + return 'rgba(' + source[0] + ',' + source[1] + ',' + source[2] + ',' + source[3] + ')'; + }, + + /** + * Returns color represenation in HEX format + * @method toHex + * @return {String} ex: FF5555 + */ + toHex: function() { + var source = this.getSource(); + + var r = source[0].toString(16); + r = (r.length == 1) ? ('0' + r) : r; + + var g = source[1].toString(16); + g = (g.length == 1) ? ('0' + g) : g; + + var b = source[2].toString(16); + b = (b.length == 1) ? ('0' + b) : b; + + return r.toUpperCase() + g.toUpperCase() + b.toUpperCase(); + }, + + /** + * Gets value of alpha channel for this color + * @method getAlpha + * @return {Number} 0-1 + */ + getAlpha: function() { + return this.getSource()[3]; + }, + + /** + * Sets value of alpha channel for this color + * @method setAlpha + * @param {Number} 0-1 + * @return {fabric.Color} thisArg + */ + setAlpha: function(alpha) { + var source = this.getSource(); + source[3] = alpha; this.setSource(source); + return this; + }, + + /** + * Transforms color to its grayscale representation + * @method toGrayscale + * @return {fabric.Color} thisArg + */ + toGrayscale: function() { + var source = this.getSource(), + average = parseInt((source[0] * 0.3 + source[1] * 0.59 + source[2] * 0.11).toFixed(0), 10), + currentAlpha = source[3]; + this.setSource([average, average, average, currentAlpha]); + return this; + }, + + /** + * Transforms color to its black and white representation + * @method toGrayscale + * @return {fabric.Color} thisArg + */ + toBlackWhite: function(threshold) { + var source = this.getSource(), + average = (source[0] * 0.3 + source[1] * 0.59 + source[2] * 0.11).toFixed(0), + currentAlpha = source[3], + threshold = threshold || 127; + + average = (Number(average) < Number(threshold)) ? 0 : 255; + this.setSource([average, average, average, currentAlpha]); + return this; + }, + + /** + * Overlays color with another color + * @method overlayWith + * @param {String|fabric.Color} otherColor + * @return {fabric.Color} thisArg + */ + overlayWith: function(otherColor) { + if (!(otherColor instanceof Color)) { + otherColor = new Color(otherColor); + } + + var result = [], + alpha = this.getAlpha(), + otherAlpha = 0.5, + source = this.getSource(), + otherSource = otherColor.getSource(); + + for (var i = 0; i < 3; i++) { + result.push(Math.round((source[i] * (1 - otherAlpha)) + (otherSource[i] * otherAlpha))); + } + + result[4] = alpha; + this.setSource(result); + return this; } - } - - /** - * @method getSource - * @return {Array} - */ - Color.prototype.getSource = function() { - return this._source; - }; - - /** - * @method setSource - * @param {Array} source - */ - Color.prototype.setSource = function(source) { - this._source = source; - }; - - /** - * @method toRgb - * @return {String} ex: rgb(0-255,0-255,0-255) - */ - Color.prototype.toRgb = function() { - var source = this.getSource(); - return 'rgb(' + source[0] + ',' + source[1] + ',' + source[2] + ')'; - }; - - /** - * @method toRgba - * @return {String} ex: rgba(0-255,0-255,0-255,0-1) - */ - Color.prototype.toRgba = function() { - var source = this.getSource(); - return 'rgba(' + source[0] + ',' + source[1] + ',' + source[2] + ',' + source[3] + ')'; - }; - - /** - * @method toHex - * @return {String} ex: FF5555 - */ - Color.prototype.toHex = function() { - var source = this.getSource(); - - var r = source[0].toString(16); - r = (r.length == 1) ? ('0' + r) : r; - - var g = source[1].toString(16); - g = (g.length == 1) ? ('0' + g) : g; - - var b = source[2].toString(16); - b = (b.length == 1) ? ('0' + b) : b; - - return r.toUpperCase() + g.toUpperCase() + b.toUpperCase(); - }; - - /** - * @method getAlpha - * @return {Number} 0-1 - */ - Color.prototype.getAlpha = function() { - return this.getSource()[3]; - }; - - /** - * @method setAlpha - * @param {Number} 0-1 - * @return {Color} thisArg - */ - Color.prototype.setAlpha = function(alpha) { - var source = this.getSource(); - source[3] = alpha; - this.setSource(source); - return this; - }; - - /** - * Transforms color to its grayscale representation - * @method toGrayscale - * @return {Color} thisArg - */ - Color.prototype.toGrayscale = function() { - var source = this.getSource(), - average = parseInt((source[0] * 0.3 + source[1] * 0.59 + source[2] * 0.11).toFixed(0), 10), - currentAlpha = source[3]; - this.setSource([average, average, average, currentAlpha]); - return this; - }; - - /** - * Transforms color to its black and white representation - * @method toGrayscale - * @return {Color} thisArg - */ - Color.prototype.toBlackWhite = function(threshold) { - var source = this.getSource(), - average = (source[0] * 0.3 + source[1] * 0.59 + source[2] * 0.11).toFixed(0), - currentAlpha = source[3], - threshold = threshold || 127; - - average = (Number(average) < Number(threshold)) ? 0 : 255; - this.setSource([average, average, average, currentAlpha]); - return this; - }; - - /** - * Overlays color with another color - * @method overlayWith - * @param {Color} otherColor - * @return {Color} thisArg - */ - Color.prototype.overlayWith = function(otherColor) { - otherColor = new Color(otherColor); - - var result = [], - alpha = this.getAlpha(), - otherAlpha = 0.5, - source = this.getSource(), - otherSource = otherColor.getSource(); - - for (var i = 0; i < 3; i++) { - result.push(Math.round((source[i] * (1 - otherAlpha)) + (otherSource[i] * otherAlpha))); - } - - result[4] = alpha; - this.setSource(result); - return this; }; /** + * Regex matching color in RGB or RGBA formats (ex: rgb(0, 0, 0), rgb(255, 100, 10, 0.5), rgb(1,1,1)) * @static - * @field reRGBa + * @field */ - Color.reRGBa = /^rgba?\((\d{1,3})\s*,\s*(\d{1,3})\s*,\s*(\d{1,3})(?:\s*,\s*(\d+(?:\.\d+)?))?\)$/; + fabric.Color.reRGBa = /^rgba?\((\d{1,3})\s*,\s*(\d{1,3})\s*,\s*(\d{1,3})(?:\s*,\s*(\d+(?:\.\d+)?))?\)$/; /** + * Regex matching color in HEX format (ex: #FF5555, 010155, aff) * @static - * @field reHex + * @field */ - Color.reHex = /^#?([0-9a-f]{6}|[0-9a-f]{3})$/i; + fabric.Color.reHex = /^#?([0-9a-f]{6}|[0-9a-f]{3})$/i; /** + * Returns new color object, when given a color in RGB format * @method fromRgb * @param {String} color ex: rgb(0-255,0-255,0-255) - * @return {Color} + * @return {fabric.Color} */ - Color.fromRgb = function(color) { + fabric.Color.fromRgb = function(color) { return Color.fromSource(Color.sourceFromRgb(color)); }; /** + * Returns array represenatation (ex: [100, 100, 200, 1]) of a color that's in RGB or RGBA format * @method sourceFromRgb * @param {String} color ex: rgb(0-255,0-255,0-255) * @return {Array} source */ - Color.sourceFromRgb = function(color) { + fabric.Color.sourceFromRgb = function(color) { var match = color.match(Color.reRGBa); if (match) { return [ @@ -201,28 +221,33 @@ }; /** + * Returns new color object, when given a color in RGBA format * @static + * @function * @method fromRgba - * @return {Color} + * @param {String} color + * @return {fabric.Color} */ - Color.fromRgba = Color.fromRgb; + fabric.Color.fromRgba = Color.fromRgb; /** + * Returns new color object, when given a color in HEX format * @static * @method fromHex - * @return {Color} + * @return {fabric.Color} */ - Color.fromHex = function(color) { + fabric.Color.fromHex = function(color) { return Color.fromSource(Color.sourceFromHex(color)); }; /** + * Returns array represenatation (ex: [100, 100, 200, 1]) of a color that's in HEX format * @static * @method sourceFromHex - * @param {String} ex: FF5555 + * @param {String} color ex: FF5555 * @return {Array} source */ - Color.sourceFromHex = function(color) { + fabric.Color.sourceFromHex = function(color) { if (color.match(Color.reHex)) { var value = color.slice(color.indexOf('#') + 1), isShortNotation = (value.length === 3), @@ -240,11 +265,12 @@ }; /** + * Returns new color object, when given color in array representation (ex: [200, 100, 100, 0.5]) * @static * @method fromSource - * @return {Color} + * @return {fabric.Color} */ - Color.fromSource = function(source) { + fabric.Color.fromSource = function(source) { var oColor = new Color(); oColor.setSource(source); return oColor; diff --git a/src/element.class.js b/src/element.class.js index c26d9880..fa5483a4 100644 --- a/src/element.class.js +++ b/src/element.class.js @@ -177,10 +177,11 @@ * @return {fabric.Element} thisArg * @chainable */ - // TODO (kangax): test callback - setOverlayImage: function (url, callback) { + setOverlayImage: function (url, callback) { // TODO (kangax): test callback if (url) { var _this = this, img = new Image(); + + /** @ignore */ img.onload = function () { _this.overlayImage = img; if (callback) { @@ -194,13 +195,13 @@ }, /** - * canvas class's initialization method. This method is automatically - * called by constructor, and sets up all DOM references for - * pre-existing markup, and creates required markup if it is not + * Canvas class' initialization method; This method is automatically + * called by constructor, sets up all DOM references for + * pre-existing markup, and creates required markup if it is not. * already present. * @method _initElement - * @param canvasEl {HTMLElement|String} canvasEl canvas element - * + * @param {HTMLElement|String} canvasEl Canvas element + * @throws {CANVAS_INIT_ERROR} If canvas can not be initialized */ _initElement: function (canvasEl) { var el = fabric.util.getById(canvasEl); @@ -1730,6 +1731,8 @@ // else append a new image element else { var imgEl = new Image(); + + /** @ignore */ imgEl.onload = function () { imgEl.onload = null; @@ -1750,6 +1753,11 @@ } })(), + /** + * @method loadSVGFromURL + * @param {String} url + * @param {Function} callback + */ loadSVGFromURL: function (url, callback) { var _this = this; @@ -1952,7 +1960,7 @@ }, /** - * Removes an active object + * Removes currently active object * @method removeActiveObject * @return {fabric.Element} thisArg * @chainable @@ -1966,9 +1974,9 @@ }, /** - * Sets current group to a speicified one + * Sets active group to a speicified one * @method setActiveGroup - * @param group {fabric.Group} group to set as a current one + * @param {fabric.Group} group Group to set as a current one * @return {fabric.Element} thisArg * @chainable */ @@ -1978,7 +1986,7 @@ }, /** - * Returns current group + * Returns currently active group * @method getActiveGroup * @return {fabric.Group} Current group */ @@ -1987,7 +1995,7 @@ }, /** - * Removes current group + * Removes currently active group * @method removeActiveGroup * @return {fabric.Element} thisArg */ @@ -2000,6 +2008,7 @@ }, /** + * Returns object at specified index * @method item * @param {Number} index * @return {fabric.Object} diff --git a/src/ellipse.class.js b/src/ellipse.class.js index 2eb93b9d..64bb70ca 100644 --- a/src/ellipse.class.js +++ b/src/ellipse.class.js @@ -11,14 +11,19 @@ return; } - fabric.Ellipse = fabric.util.createClass(fabric.Object, { + /** + * @class Ellipse + * @extends fabric.Object + */ + fabric.Ellipse = fabric.util.createClass(fabric.Object, /** @scope fabric.Ellipse.prototype */ { + /** @property */ type: 'ellipse', /** - * @constructor + * Constructor * @method initialize - * @param options {Object} options object + * @param {Object} [options] Options object * @return {Object} thisArg */ initialize: function(options) { @@ -87,11 +92,12 @@ fabric.Ellipse.ATTRIBUTE_NAMES = 'cx cy rx ry fill fill-opacity stroke stroke-width transform'.split(' '); /** + * Returns fabric.Ellipse instance from an SVG element * @static * @method fabric.Ellipse.fromElement - * @param element {SVGElement} element to parse - * @param options {Object} options object - * @return {Object} instance of fabric.Ellipse + * @param {SVGElement} element Element to parse + * @param {Object} [options] Options object + * @return {fabric.Ellipse} */ fabric.Ellipse.fromElement = function(element, options) { options || (options = { }); @@ -106,10 +112,11 @@ }; /** + * Returns fabric.Ellipse instance from an object representation * @static * @method fabric.Ellipse.fromObject - * @param object {Object} object to create an instance from - * @return {Object} instance of fabric.Ellipse + * @param {Object} object Object to create an instance from + * @return {fabric.Ellipse} */ fabric.Ellipse.fromObject = function(object) { return new fabric.Ellipse(object); diff --git a/src/group.class.js b/src/group.class.js index 6953ea44..2e4eec05 100644 --- a/src/group.class.js +++ b/src/group.class.js @@ -13,16 +13,20 @@ return; } - fabric.Group = fabric.util.createClass(fabric.Object, { + /** + * @class Group + * @extends fabric.Object + */ + fabric.Group = fabric.util.createClass(fabric.Object, /** @scope fabric.Group.prototype */ { - /** - * @property type - */ + /** @property */ type: 'group', /** - * @constructor + * Constructor + * @method initialized * @param {Object} objects Group objects + * @param {Object} [options] Options object * @return {Object} thisArg */ initialize: function(objects, options) { @@ -73,6 +77,7 @@ }, /** + * Returns string represenation of a group * @method toString * @return {String} */ @@ -81,6 +86,7 @@ }, /** + * Returns an array of all objects in this group * @method getObjects * @return {Array} group objects */ @@ -89,10 +95,10 @@ }, /** - * Adds an object to a group. Recalculates group's dimension, position. + * Adds an object to a group; Then recalculates group's dimension, position. * @method add * @param {Object} object - * @return {Object} thisArg + * @return {fabric.Group} thisArg * @chainable */ add: function(object) { @@ -105,9 +111,9 @@ }, /** - * Removes an object from a group. Recalculates group's dimension, position. + * Removes an object from a group; Then recalculates group's dimension, position. * @param {Object} object - * @return {Object} thisArg + * @return {fabric.Group} thisArg * @chainable */ remove: function(object) { @@ -120,7 +126,7 @@ }, /** - * Returns a size of a group (i.e. length of an array containing its objects) + * Returns a size of a group (i.e: length of an array containing its objects) * @return {Number} Group size */ size: function() { @@ -131,8 +137,8 @@ * Sets property to a given value * @method set * @param {String} name - * @param {Object | Function} value - * @return {Object} thisArg + * @param {Object|Function} value + * @return {fabric.Group} thisArg * @chainable */ set: function(name, value) { @@ -159,7 +165,7 @@ * Returns true if a group contains an object * @method contains * @param {Object} object Object to check against - * @return {Boolean} true if group contains an object + * @return {Boolean} `true` if group contains an object */ contains: function(object) { return this.objects.indexOf(object) > -1; @@ -179,7 +185,7 @@ /** * Renders instance on a given context * @method render - * @param ctx {CanvasRenderingContext2D} context to render instance on + * @param {CanvasRenderingContext2D} ctx context to render instance on */ render: function(ctx) { ctx.save(); @@ -200,6 +206,7 @@ }, /** + * Returns object from the group at the specified index * @method item * @param index {Number} index of item to get * @return {fabric.Object} @@ -209,6 +216,7 @@ }, /** + * Returns complexity of an instance * @method complexity * @return {Number} complexity */ @@ -220,7 +228,7 @@ }, /** - * Retores original state of each of group objects + * Retores original state of each of group objects (original state is that which was before group was created). * @private * @method _restoreObjectsState * @return {fabric.Group} thisArg @@ -232,9 +240,11 @@ }, /** + * Restores original state of a specified object in group * @private * @method _restoreObjectState * @param {fabric.Object} object + * @return {fabric.Group} thisArg */ _restoreObjectState: function(object) { @@ -263,6 +273,7 @@ }, /** + * Destroys a group (restoring state of its objects) * @method destroy * @return {fabric.Group} thisArg * @chainable @@ -282,6 +293,10 @@ return this; }, + /** + * @method hasMoved + * @return {Boolean} true if an object was moved (since fabric.Group#saveCoords was called) + */ hasMoved: function() { return this._originalLeft !== this.get('left') || this._originalTop !== this.get('top'); @@ -311,6 +326,7 @@ }, /** + * Activates (makes active) all group objects * @method setActive * @param {Boolean} value `true` to activate object, `false` otherwise * @return {fabric.Group} thisArg @@ -332,9 +348,9 @@ * Callback is invoked in a context of Global Object (e.g. `window`) * when no `context` argument is given * - * @param {Object} context a.k.a. thisObject + * @param {Object} context Context (aka thisObject) * - * @return {fabric.Group} + * @return {fabric.Group} thisArg * @chainable */ forEachObject: function(callback, context) { diff --git a/src/image.class.js b/src/image.class.js index ae19acd9..a1c01644 100644 --- a/src/image.class.js +++ b/src/image.class.js @@ -19,22 +19,34 @@ return; } - - fabric.Image = fabric.util.createClass(fabric.Object, { + /** + * @class Image + * @extends fabric.Object + */ + fabric.Image = fabric.util.createClass(fabric.Object, /** @scope fabric.Image.prototype */ { + /** @property */ maxwidth: null, + + /** @property */ maxheight: null, + + /** @property */ active: false, + /** @property */ bordervisibility: false, + + /** @property */ cornervisibility: false, + /** @property */ type: 'image', __isGrayscaled: false, /** - * @constructor + * Constructor * @param {HTMLImageElement | String} element Image element * @param {Object} options optional */ @@ -45,6 +57,7 @@ }, /** + * Returns image element which this instance if based on * @method getElement * @return {HTMLImageElement} image element */ @@ -53,8 +66,11 @@ }, /** + * Sets image element for this instance to a specified one * @method setElement + * @param {HTMLImageElement} element * @return {fabric.Image} thisArg + * @chainable */ setElement: function(element) { this._element = element; @@ -62,12 +78,12 @@ }, /** - * Method that resizes an image depending on whether maxwidth and maxheight are set up. + * Resizes an image depending on whether maxwidth and maxheight are set up; * Width and height have to mantain the same proportion in the final image as it was in the initial one. * @method getNormalizedSize * @param {Object} oImg - * @param {Number} maxwidth maximum width of the image in px - * @param {Number} maxheight maximum height of the image in px + * @param {Number} maxwidth maximum width of the image (in px) + * @param {Number} maxheight maximum height of the image (in px) */ getNormalizedSize: function(oImg, maxwidth, maxheight) { if (maxheight && maxwidth && (oImg.width > oImg.height && (oImg.width / oImg.height) < (maxwidth / maxheight))) { @@ -97,6 +113,7 @@ }, /** + * Returns original size of an image * @method getOriginalSize * @return {Object} object with "width" and "height" properties */ @@ -109,24 +126,29 @@ }, /** + * Sets border visibility * @method setBorderVisibility - * @param showBorder {Boolean} when true, border is being set visible + * @param {Boolean} visible When true, border is set to be visible */ - setBorderVisibility: function(showBorder) { + setBorderVisibility: function(visible) { this._resetWidthHeight(); this._adjustWidthHeightToBorders(showBorder); this.setCoords(); }, /** + * Sets corner visibility * @method setCornersVisibility + * @param {Boolean} visible When true, corners are set to be visible */ setCornersVisibility: function(visible) { this.cornervisibility = !!visible; }, /** + * Renders image on a specified context * @method render + * @param {CanvasRenderingContext2D} ctx Context to render on */ render: function(ctx, noTransform) { ctx.save(); @@ -142,8 +164,9 @@ }, /** + * Returns object representation of an instance * @method toObject - * @return {Object} object representation of an instance + * @return {Object} Object representation of an instance */ toObject: function() { return extend(this.callSuper('toObject'), { @@ -152,30 +175,34 @@ }, /** + * Returns source of an image * @method getSrc - * @return {String} source of an image + * @return {String} Source of an image */ getSrc: function() { return this.getElement().src; }, /** + * Returns string representation of an instance * @method toString - * @return {String} string representation of an instance + * @return {String} String representation of an instance */ toString: function() { return '#'; }, /** + * Returns a clone of an instance * @mthod clone - * @param {Function} callback + * @param {Function} callback Callback is invoked with a clone as a first argument */ clone: function(callback) { this.constructor.fromObject(this.toObject(), callback); }, /** + * Makes image grayscale * @mthod toGrayscale * @param {Function} callback */ @@ -195,7 +222,8 @@ canvasEl.getContext('2d').drawImage(imgEl, 0, 0); fabric.Element.toGrayscale(canvasEl); - + + /** @ignore */ replacement.onload = function() { _this.setElement(replacement); callback && callback(); @@ -291,26 +319,29 @@ this.height = (this.getElement().height || 0) + sidesBorderWidth; }, + /** + * Returns complexity of an instance + * @method complexity + * @return {Number} complexity + */ complexity: function() { return 1; } }); /** - * Constant for the default CSS class name that represents a Canvas - * @property fabric.Image.CSS_CANVAS + * Default CSS class name for canvas * @static - * @final * @type String */ fabric.Image.CSS_CANVAS = "canvas-img"; /** * Creates an instance of fabric.Image from its object representation + * @static * @method fromObject * @param object {Object} * @param callback {Function} optional - * @static */ fabric.Image.fromObject = function(object, callback) { var img = document.createElement('img'), @@ -322,6 +353,8 @@ if (object.height) { img.height = object.height; } + + /** @ignore */ img.onload = function() { if (callback) { callback(new fabric.Image(img, object)); @@ -333,14 +366,16 @@ /** * Creates an instance of fabric.Image from an URL string - * @method fromURL - * @param url {String} - * @param callback {Function} optional - * @param imgOptions {Object} optional * @static + * @method fromURL + * @param {String} url URL to create an image from + * @param {Function} [callback] Callback to invoke when image is created (newly created image is passed as a first argument) + * @param {Object} [imgOptions] Options object */ fabric.Image.fromURL = function(url, callback, imgOptions) { var img = document.createElement('img'); + + /** @ignore */ img.onload = function() { if (callback) { callback(new fabric.Image(img, imgOptions)); diff --git a/src/intersection.class.js b/src/intersection.class.js index 5931dd6e..9e81e084 100644 --- a/src/intersection.class.js +++ b/src/intersection.class.js @@ -11,25 +11,52 @@ fabric.warn('fabric.Intersection is already defined'); return; } - + + /** + * @class Intersection + * @memberOf fabric + */ function Intersection(status) { if (arguments.length > 0) { this.init(status); } } - Intersection.prototype.init = function (status) { - this.status = status; - this.points = []; - }; - Intersection.prototype.appendPoint = function (point) { - this.points.push(point); - }; - Intersection.prototype.appendPoints = function (points) { - this.points = this.points.concat(points); + fabric.Intersection = Intersection; + + fabric.Intersection.prototype = /** @scope fabric.Intersection.prototype */ { + + /** + * @method init + * @param {String} status + */ + init: function (status) { + this.status = status; + this.points = []; + }, + + /** + * @method appendPoint + * @param {String} status + */ + appendPoint: function (point) { + this.points.push(point); + }, + + /** + * @method appendPoints + * @param {String} status + */ + appendPoints: function (points) { + this.points = this.points.concat(points); + } }; - Intersection.intersectLineLine = function (a1, a2, b1, b2) { + /** + * @static + * @method intersectLineLine + */ + fabric.Intersection.intersectLineLine = function (a1, a2, b1, b2) { var result, ua_t = (b2.x - b1.x) * (a1.y - b1.y) - (b2.y - b1.y) * (a1.x - b1.x), ub_t = (a2.x - a1.x) * (a1.y - b1.y) - (a2.y - a1.y) * (a1.x - b1.x), @@ -56,7 +83,10 @@ return result; }; - Intersection.intersectLinePolygon = function(a1,a2,points){ + /** + * @method intersectLinePolygon + */ + fabric.Intersection.intersectLinePolygon = function(a1,a2,points){ var result = new Intersection("No Intersection"), length = points.length; @@ -73,7 +103,10 @@ return result; }; - Intersection.intersectPolygonPolygon = function (points1, points2) { + /** + * @method intersectPolygonPolygon + */ + fabric.Intersection.intersectPolygonPolygon = function (points1, points2) { var result = new Intersection("No Intersection"), length = points1.length; @@ -90,7 +123,10 @@ return result; }; - Intersection.intersectPolygonRectangle = function (points, r1, r2) { + /** + * @method intersectPolygonRectangle + */ + fabric.Intersection.intersectPolygonRectangle = function (points, r1, r2) { var min = r1.min(r2), max = r1.max(r2), topRight = new fabric.Point(max.x, min.y), @@ -111,6 +147,4 @@ return result; }; - fabric.Intersection = Intersection; - })(); \ No newline at end of file diff --git a/src/line.class.js b/src/line.class.js index 36deaab7..aa3e1b23 100644 --- a/src/line.class.js +++ b/src/line.class.js @@ -1,24 +1,30 @@ //= require "object.class" -(function(){ +(function() { var fabric = this.fabric || (this.fabric = { }), extend = fabric.util.object.extend; if (fabric.Line) { + fabric.warn('fabric.Line is already defined'); return; } - fabric.Line = fabric.util.createClass(fabric.Object, { + /** + * @class Line + * @extends fabric.Object + */ + fabric.Line = fabric.util.createClass(fabric.Object, /** @scope fabric.Line.prototype */ { + /** @property */ type: 'line', /** - * @constructor + * Constructor * @method initialize - * @param points {Array} array of points - * @param options {Object} options object - * @return {Object} thisArg + * @param {Array} points Array of points + * @param {Object} [options] Options object + * @return {fabric.Line} thisArg */ initialize: function(points, options) { if (!points) { @@ -41,7 +47,7 @@ /** * @private * @method _render - * @param ctx {CanvasRenderingContext2D} context to render on + * @param {CanvasRenderingContext2D} ctx Context to render on */ _render: function(ctx) { ctx.beginPath(); @@ -68,6 +74,7 @@ }, /** + * Returns object representation of an instance * @methd toObject * @return {Object} */ @@ -81,15 +88,17 @@ } }); - // http://www.w3.org/TR/SVG/shapes.html#LineElement + /** + * @see http://www.w3.org/TR/SVG/shapes.html#LineElement + */ fabric.Element.ATTRIBUTE_NAMES = 'x1 y1 x2 y2 stroke stroke-width transform'.split(' '); /** * @static * @method fabric.Line.fromElement - * @param element {SVGElement} element to parse - * @param options {Object} options object - * @return {Object} instance of fabric.Line + * @param {SVGElement} element Element to parse + * @param {Object} [options] Options object + * @return {fabric.Line} instance of fabric.Line */ fabric.Line.fromElement = function(element, options) { var parsedAttributes = fabric.parseAttributes(element, fabric.Element.ATTRIBUTE_NAMES); @@ -105,8 +114,8 @@ /** * @static * @method fabric.Line.fromObject - * @param object {Object} object to create an instance from - * @return {Object} instance of fabric.Line + * @param {Object} object Object to create an instance from + * @return {fabric.Line} instance of fabric.Line */ fabric.Line.fromObject = function(object) { var points = [object.x1, object.y1, object.x2, object.y2]; diff --git a/src/object.class.js b/src/object.class.js index 091f6f50..ec4d5530 100644 --- a/src/object.class.js +++ b/src/object.class.js @@ -1,11 +1,6 @@ (function(){ var global = this, - - /** - * @name Canvas - * @namespace - */ fabric = global.fabric || (global.fabric = { }), extend = fabric.util.object.extend, clone = fabric.util.object.clone, @@ -20,12 +15,14 @@ /** * @class Object - * @memberOf Canvas + * @memberOf fabric */ - fabric.Object = fabric.util.createClass({ + fabric.Object = fabric.util.createClass(/** @scope fabric.Object.prototype */ { + /** @property */ type: 'object', + /** @property */ includeDefaultValues: true, /** @@ -48,17 +45,14 @@ */ MIN_SCALE_LIMIT: 0.1, - /** - * @field - */ + /** @property */ stateProperties: ('top left width height scaleX scaleY flipX flipY ' + 'theta angle opacity cornersize fill overlayFill stroke ' + 'strokeWidth fillRule borderScaleFactor transformMatrix').split(' '), - /** - * @field - */ // TODO (kangax): rename to `defaultOptions` + + /** @property */ options: { top: 0, left: 0, @@ -85,6 +79,10 @@ transformMatrix: null }, + /** + * @method callSuper + * @param {String} methodName + */ callSuper: function(methodName) { var fn = this.constructor.superclass.prototype[methodName]; return (arguments.length > 1) @@ -93,8 +91,9 @@ }, /** - * @constructs - * @param options {Object} options + * Constructor + * @method initialize + * @param {Object} [options] Options object */ initialize: function(options) { // overwrite default options with specified ones @@ -109,6 +108,10 @@ this.saveState(); }, + /** + * @method setOptions + * @param {Object} [options] + */ setOptions: function(options) { // this.constructor.superclass.prototype.options -> this.options -> options this.options = extend(this._getOptions(), options); @@ -636,17 +639,20 @@ cloneAsImage: function(callback) { if (fabric.Image) { var i = new Image(); + + /** @ignore */ i.onload = function() { if (callback) { callback(new fabric.Image(i), orig); } i = i.onload = null; - } + }; + var orig = { angle: this.get('angle'), flipX: this.get('flipX'), flipY: this.get('flipY') - } + }; // normalize angle this.set('angle', 0).set('flipX', false).set('flipY', false); diff --git a/src/parser.js b/src/parser.js index 1703d240..594dc91e 100644 --- a/src/parser.js +++ b/src/parser.js @@ -1,5 +1,7 @@ (function(){ + /** @name fabric */ + var fabric = this.fabric || (this.fabric = { }), extend = fabric.util.object.extend, capitalize = fabric.util.string.capitalize, @@ -18,8 +20,12 @@ }; /** - * Returns an object of attributes' name/value, given element and an array of attribute names - * Parses parent "g" nodes recursively upwards + * Returns an object of attributes' name/value, given element and an array of attribute names; + * Parses parent "g" nodes recursively upwards. + * + * @static + * @memberOf fabric + * @method parseAttributes * @param {DOMElement} element Element to parse * @param {Array} attributes Array of attributes to parse * @return {Object} object containing parsed attributes' names/values @@ -70,7 +76,9 @@ /** * @static - * @method fabric.parseTransformAttribute + * @function + * @memberOf fabric + * @method parseTransformAttribute * @param attributeValue {String} string containing attribute value * @return {Array} array of 6 elements representing transformation matrix */ @@ -201,7 +209,8 @@ /** * @static - * @method fabric.parsePointsAttribute + * @memberOf fabric + * @method parsePointsAttribute * @param points {String} points attribute string * @return {Array} array of points */ @@ -239,9 +248,10 @@ /** * @static - * @method fabric.parseStyleAttribute - * @param element {SVGElement} element to parse - * @return {Object} objects with values parsed from style attribute of an element + * @memberOf fabric + * @method parseStyleAttribute + * @param {SVGElement} element Element to parse + * @return {Object} Objects with values parsed from style attribute of an element */ function parseStyleAttribute(element) { var oStyle = { }, @@ -271,10 +281,11 @@ /** * @static - * @method fabric.parseElements - * @param elements {Array} array of elements to parse - * @param options {Object} options object - * @return {Array} array of corresponding instances (transformed from SVG elements) + * @memberOf fabric + * @method parseElements + * @param {Array} elements Array of elements to parse + * @param {Object} options Options object + * @return {Array} Array of corresponding instances (transformed from SVG elements) */ function parseElements(elements, options) { // transform svg elements to fabric.Path elements @@ -297,12 +308,13 @@ /** * @static - * @method fabric.parseSVGDocument - * @param doc {SVGDocument} SVG document to parse - * @param callback {Function} callback to call when parsing is finished. - * Callback is being passed array of elements (parsed from a document) + * @function + * @memberOf fabric + * @method parseSVGDocument + * @param {SVGDocument} doc SVG document to parse + * @param {Function} callback Callback to call when parsing is finished; It's being passed an array of elements (parsed from a document). */ - fabric.parseSVGDocument = (function(){ + fabric.parseSVGDocument = (function() { var reAllowedSVGTagNames = /^(path|circle|polygon|polyline|ellipse|rect|line)$/; diff --git a/src/path.class.js b/src/path.class.js index 2f21e378..ac74223a 100644 --- a/src/path.class.js +++ b/src/path.class.js @@ -16,16 +16,40 @@ return; } - // Instance methods - fabric.Path = fabric.util.createClass(fabric.Object, { + /** + * @private + */ + function getX(item) { + if (item[0] === 'H') { + return item[1]; + } + return item[item.length - 2]; + } + + /** + * @private + */ + function getY(item) { + if (item[0] === 'V') { + return item[1]; + } + return item[item.length - 1]; + } + + /** + * @class Path + * @extends fabric.Object + */ + fabric.Path = fabric.util.createClass(fabric.Object, /** @scope fabric.Path.prototype */ { + /** @property */ type: 'path', /** - * @constructor - * @param path {Array | String} path data - * (i.e. sequence of coordinates and corresponding "command" tokens) - * @param options {Object} options object + * Constructor + * @method initialize + * @param {Array|String} path Path data (sequence of coordinates and corresponding "command" tokens) + * @param {Object} [options] Options object */ initialize: function(path, options) { options = options || { }; @@ -342,7 +366,12 @@ delete o.sourcePath; return o; }, - + + /** + * Returns number representation of an instance complexity + * @method complexity + * @return {Number} complexity + */ complexity: function() { return this.path.length; }, @@ -366,6 +395,9 @@ return result; }, + /** + * @method _parseDimensions + */ _parseDimensions: function() { var aX = [], aY = [], @@ -374,18 +406,7 @@ isLowerCase = false, x, y; - function getX(item) { - if (item[0] === 'H') { - return item[1]; - } - return item[item.length - 2]; - } - function getY(item) { - if (item[0] === 'V') { - return item[1]; - } - return item[item.length - 1]; - } + this.path.forEach(function(item, i) { if (item[0] !== 'H') { previousX = (i === 0) ? getX(item) : getX(this.path[i-1]); diff --git a/src/path_group.class.js b/src/path_group.class.js index a740a72a..679ed0af 100644 --- a/src/path_group.class.js +++ b/src/path_group.class.js @@ -15,11 +15,25 @@ return; } - fabric.PathGroup = fabric.util.createClass(fabric.Path, { + /** + * @class PathGroup + * @extends fabric.Path + */ + fabric.PathGroup = fabric.util.createClass(fabric.Path, /** @scope fabric.PathGroup.prototype */ { + /** @property */ type: 'path-group', + + /** @property */ forceFillOverwrite: false, + /** + * Constructor + * @method initialize + * @param {Array} paths + * @param {Object} [options] Options object + * @return {fabric.PathGroup} thisArg + */ initialize: function(paths, options) { options = options || { }; diff --git a/src/point.class.js b/src/point.class.js index 558a0904..32c3b99c 100644 --- a/src/point.class.js +++ b/src/point.class.js @@ -8,107 +8,179 @@ fabric.warn('fabric.Point is already defined'); return; } + + fabric.Point = Point; + /** + * @name Point + * @memberOf fabric + * @constructor + * @param {Number} x + * @param {Number} y + * @return {fabric.Point} thisArg + */ function Point(x, y) { if (arguments.length > 0) { this.init(x, y); } } - Point.prototype = { + Point.prototype = /** @scope fabric.Point.prototype */ { + constructor: Point, + + /** + * @method init + * @param {Number} x + * @param {Number} y + */ init: function (x, y) { this.x = x; this.y = y; }, + + /** + * @method add + * @param {fabric.Point} that + * @return {fabric.Point} new Point instance with added values + */ add: function (that) { return new Point(this.x + that.x, this.y + that.y); }, + + /** + * @method addEquals + * @param {fabric.Point} that + * @return {fabric.Point} thisArg + */ addEquals: function (that) { this.x += that.x; this.y += that.y; return this; }, + + /** + * @method scalarAdd + * @param {Number} scalar + * @return {fabric.Point} new Point with added value + */ scalarAdd: function (scalar) { return new Point(this.x + scalar, this.y + scalar); }, + + /** + * @method scalarAddEquals + * @param {Number} scalar + * @param {fabric.Point} thisArg + */ scalarAddEquals: function (scalar) { this.x += scalar; this.y += scalar; return this; }, + + /** + * @method subtract + * @param {fabric.Point} that + * @return {fabric.Point} new Point object with subtracted values + */ subtract: function (that) { return new Point(this.x - that.x, this.y - that.y); }, + + /** + * @method subtractEquals + * @param {fabric.Point} that + * @return {fabric.Point} thisArg + */ subtractEquals: function (that) { this.x -= that.x; this.y -= that.y; return this; }, + scalarSubtract: function (scalar) { return new Point(this.x - scalar, this.y - scalar); }, + scalarSubtractEquals: function (scalar) { this.x -= scalar; this.y -= scalar; return this; }, + multiply: function (scalar) { return new Point(this.x * scalar, this.y * scalar); }, + multiplyEquals: function (scalar) { this.x *= scalar; this.y *= scalar; return this; }, + divide: function (scalar) { return new Point(this.x / scalar, this.y / scalar); }, + divideEquals: function (scalar) { this.x /= scalar; this.y /= scalar; return this; }, + eq: function (that) { return (this.x == that.x && this.y == that.y); }, + lt: function (that) { return (this.x < that.x && this.y < that.y); }, + lte: function (that) { return (this.x <= that.x && this.y <= that.y); }, + gt: function (that) { return (this.x > that.x && this.y > that.y); }, + gte: function (that) { return (this.x >= that.x && this.y >= that.y); }, + lerp: function (that, t) { return new Point(this.x + (that.x - this.x) * t, this.y + (that.y - this.y) * t); }, + distanceFrom: function (that) { var dx = this.x - that.x, dy = this.y - that.y; return Math.sqrt(dx * dx + dy * dy); }, + min: function (that) { return new Point(Math.min(this.x, that.x), Math.min(this.y, that.y)); }, + max: function (that) { return new Point(Math.max(this.x, that.x), Math.max(this.y, that.y)); }, + toString: function () { return this.x + "," + this.y; }, + setXY: function (x, y) { this.x = x; this.y = y; }, + setFromPoint: function (that) { this.x = that.x; this.y = that.y; }, + swap: function (that) { var x = this.x, y = this.y; @@ -119,6 +191,4 @@ } }; - fabric.Point = Point; - })(); \ No newline at end of file diff --git a/src/polygon.class.js b/src/polygon.class.js index d5197c65..624f31d3 100644 --- a/src/polygon.class.js +++ b/src/polygon.class.js @@ -1,6 +1,6 @@ //= require "object.class" -(function(){ +(function() { var fabric = this.fabric || (this.fabric = { }), extend = fabric.util.object.extend, @@ -15,16 +15,21 @@ function byX(p) { return p.x; } function byY(p) { return p.y; } - fabric.Polygon = fabric.util.createClass(fabric.Object, { + /** + * @class Polygon + * @extends fabric.Object + */ + fabric.Polygon = fabric.util.createClass(fabric.Object, /** @scope fabric.Polygon.prototype */ { + /** @property */ type: 'polygon', /** - * @constructor + * Constructor * @method initialize - * @param points {Array} array of points - * @param options {Object} options object - * @return thisArg + * @param {Array} points Array of points + * @param {Object} options Options object + * @return {fabric.Polygon} thisArg */ initialize: function(points, options) { options = options || { }; @@ -93,15 +98,20 @@ } }); - // http://www.w3.org/TR/SVG/shapes.html#PolygonElement + /** + * List of attribute names to account for when parsing SVG element (used by `fabric.Polygon.fromElement`) + * @static + * @see: http://www.w3.org/TR/SVG/shapes.html#PolygonElement + */ fabric.Polygon.ATTRIBUTE_NAMES = 'fill fill-opacity stroke stroke-width transform'.split(' '); /** + * Returns fabric.Polygon instance from an SVG element * @static * @method fabric.Polygon.fromElement - * @param element {SVGElement} element to parse - * @param options {Object} options object - * @return {Object} instance of fabric.Polygon + * @param {SVGElement} element Element to parse + * @param {Object} options Options object + * @return {fabric.Polygon} */ fabric.Polygon.fromElement = function(element, options) { if (!element) { @@ -122,10 +132,11 @@ }; /** + * Returns fabric.Polygon instance from an object representation * @static * @method fabric.Polygon.fromObject - * @param object {Object} object to create an instance from - * @return {Object} instance of fabric.Polygon + * @param {Object} object Object to create an instance from + * @return {fabric.Polygon} */ fabric.Polygon.fromObject = function(object) { return new fabric.Polygon(object.points, object); diff --git a/src/polyline.class.js b/src/polyline.class.js index 7f4a1dd3..f072ca3d 100644 --- a/src/polyline.class.js +++ b/src/polyline.class.js @@ -1,6 +1,6 @@ //= require "object.class" -(function(){ +(function() { var fabric = this.fabric || (this.fabric = { }); @@ -9,15 +9,20 @@ return; } - fabric.Polyline = fabric.util.createClass(fabric.Object, { + /** + * @class Polyline + * @extends fabric.Object + */ + fabric.Polyline = fabric.util.createClass(fabric.Object, /** @scope fabric.Polyline.prototype */ { + /** @property */ type: 'polyline', /** - * @constructor + * Constructor * @method initialize - * @param points {Array} array of points - * @param options {Object} options object + * @param {Array} points array of points + * @param {Object} [options] Options object * @return {Object} thisArg */ initialize: function(points, options) { @@ -38,7 +43,7 @@ /** * Returns object representation of an instance * @method toObject - * @return {Object} object representation of an instance + * @return {Object} Object representation of an instance */ toObject: function() { return fabric.Polygon.prototype.toObject.call(this); @@ -47,7 +52,7 @@ /** * @private * @method _render - * @param ctx {CanvasRenderingContext2D} context to render on + * @param {CanvasRenderingContext2D} ctx Context to render on */ _render: function(ctx) { var point; @@ -65,6 +70,7 @@ }, /** + * Returns complexity of an instance * @method complexity * @return {Number} complexity */ @@ -73,14 +79,19 @@ } }); - // http://www.w3.org/TR/SVG/shapes.html#PolylineElement + /** + * List of attribute names to account for when parsing SVG element (used by `fabric.Polyline.fromElement`) + * @static + * @see: http://www.w3.org/TR/SVG/shapes.html#PolylineElement + */ var ATTRIBUTE_NAMES = 'fill fill-opacity stroke stroke-width transform'.split(' '); /** + * Returns fabric.Polyline instance from an SVG element * @static * @method fabric.Polyline.fromElement - * @param element {SVGElement} element to parse - * @param options {Object} options object + * @param {SVGElement} element Element to parse + * @param {Object} [options] Options object * @return {Object} instance of fabric.Polyline */ fabric.Polyline.fromElement = function(element, options) { @@ -102,13 +113,15 @@ }; /** + * Returns fabric.Polyline instance from an object representation * @static * @method fabric.Polyline.fromObject - * @param object {Object} object to create an instance from - * @return {Object} instance of fabric.Polyline + * @param {Object} [object] Object to create an instance from + * @return {fabric.Polyline} */ fabric.Polyline.fromObject = function(object) { var points = object.points; return new fabric.Polyline(points, object); - } + }; + })(); \ No newline at end of file diff --git a/src/rect.class.js b/src/rect.class.js index 310352dc..145f0eb8 100644 --- a/src/rect.class.js +++ b/src/rect.class.js @@ -1,10 +1,11 @@ //= require "object.class" -(function(){ +(function() { var fabric = this.fabric || (this.fabric = { }); if (fabric.Rect) { + console.warn('fabric.Rect is already defined'); return; } @@ -12,17 +13,19 @@ * @class Rect * @extends fabric.Object */ - fabric.Rect = fabric.util.createClass(fabric.Object, /** @lends fabric.Rect.prototype */ { + fabric.Rect = fabric.util.createClass(fabric.Object, /** @scope fabric.Rect.prototype */ { + /** @property */ type: 'rect', + /** @property */ options: { rx: 0, ry: 0 }, /** - * @constructs + * Constructor * @method initialize * @param options {Object} options object * @return {Object} thisArg @@ -115,7 +118,7 @@ * @method fabric.Rect.fromElement * @param element {SVGElement} element to parse * @param options {Object} options object - * @return {Object} instance of fabric.Rect + * @return {fabric.Rect} instance of fabric.Rect */ fabric.Rect.fromElement = function(element, options) { if (!element) { diff --git a/src/text.class.js b/src/text.class.js index 624eeda2..92a4b7ec 100644 --- a/src/text.class.js +++ b/src/text.class.js @@ -1,6 +1,6 @@ //= require "object.class" -(function(){ +(function() { var fabric = this.fabric || (this.fabric = { }), extend = fabric.util.object.extend, @@ -15,8 +15,13 @@ return; } - fabric.Text = fabric.util.createClass(fabric.Object, { + /** + * @class Text + * @extends fabric.Object + */ + fabric.Text = fabric.util.createClass(fabric.Object, /** @scope fabric.Text.prototype */ { + /** @property */ options: { top: 10, left: 10, @@ -26,8 +31,16 @@ path: null }, + /** @property */ type: 'text', + /** + * Constructor + * @method initialize + * @param {String} text + * @param {Object} [options] + * @return {fabric.Text} thisArg + */ initialize: function(text, options) { this.originalState = { }; this.initStateProperties(); @@ -39,6 +52,9 @@ this.setCoords(); }, + /** + * @method initStateProperties + */ initStateProperties: function() { var o; if ((o = this.constructor) && @@ -51,11 +67,21 @@ } }, + /** + * Returns string representation of an instance + * @method toString + * @return {String} String representation of text object + */ toString: function() { return '#'; }, + /** + * @private + * @method _render + * @param {CanvasRenderingContext2D} ctx Context to render on + */ _render: function(context) { var o = Cufon.textOptions || (Cufon.textOptions = { }); @@ -81,6 +107,10 @@ this.height = o.height; }, + /** + * @private + * @method _initDummyElement + */ _initDummyElement: function() { var el = document.createElement('div'); el.innerHTML = this.text; @@ -97,6 +127,10 @@ return el; }, + /** + * @method render + * @param ctx {CanvasRenderingContext2D} context to render on + */ render: function(context) { context.save(); this._render(context); @@ -109,7 +143,7 @@ /** * @method toObject - * @return {Object} object representation of an instance + * @return {Object} Object representation of text object */ toObject: function() { return extend(this.callSuper('toObject'), { @@ -153,9 +187,11 @@ }, /** + * Sets text of an instance, and updates its coordinates * @method setText * @param {String} value * @return {fabric.Text} thisArg + * @chainable */ setText: function(value) { this.set('text', value); @@ -163,6 +199,14 @@ return this; }, + /** + * Sets specified property to a specified value + * @method set + * @param {String} name + * @param {Any} value + * @return {fabric.Text} thisArg + * @chainable + */ set: function(name, value) { this[name] = value; if (name === 'fontfamily') { @@ -173,6 +217,7 @@ }); /** + * Returns fabric.Text instance from an object representation * @static * @method fromObject * @param {Object} object to create an instance from diff --git a/src/triangle.class.js b/src/triangle.class.js index 8c48628c..89af4d59 100644 --- a/src/triangle.class.js +++ b/src/triangle.class.js @@ -1,18 +1,23 @@ -(function(){ +(function() { var fabric = this.fabric || (this.fabric = { }); - if (fabric.Triangle) return; + if (fabric.Triangle) { + fabric.warn('fabric.Triangle is already defined'); + return; + } - fabric.Triangle = fabric.util.createClass(fabric.Object, { + /** + * @class Triangle + * @extends fabric.Object + */ + fabric.Triangle = fabric.util.createClass(fabric.Object, /** @scope fabric.Triangle.prototype */ { - /** - * @field - */ + /** @property */ type: 'triangle', /** - * @constructs + * Constructor * @method initialize * @param options {Object} options object * @return {Object} thisArg @@ -29,7 +34,7 @@ /** * @private * @method _render - * @param ctx {CanvasRenderingContext2D} context to render on + * @param ctx {CanvasRenderingContext2D} Context to render on */ _render: function(ctx) { var widthBy2 = this.width / 2, @@ -60,6 +65,7 @@ }); /** + * Returns fabric.Triangle instance from an object representation * @static * @method Canvas.Trangle.fromObject * @param object {Object} object to create an instance from diff --git a/src/util.js b/src/util.js index 02be4ee1..de0dad2e 100644 --- a/src/util.js +++ b/src/util.js @@ -3,7 +3,8 @@ var fabric = this.fabric || (this.fabric = { }), slice = Array.prototype.slice, apply = Function.prototype.apply; - + + /** @namespace */ fabric.util = { }; //= require "util/misc" diff --git a/test/unit/color.js b/test/unit/color.js index 5f3dddbd..20a256f2 100644 --- a/test/unit/color.js +++ b/test/unit/color.js @@ -167,5 +167,9 @@ oColor = new fabric.Color('rgb(255,255,255)'); oColor.overlayWith('rgb(0,0,0)'); equals(oColor.toRgb(), 'rgb(128,128,128)'); + + oColor = new fabric.Color('rgb(255,255,255)'); + oColor.overlayWith(new fabric.Color('rgb(0,0,0)')); + equals(oColor.toRgb(), 'rgb(128,128,128)'); }); })(); \ No newline at end of file