1 //= require "object.class"
  2 
  3 (function() {
  4   
  5   var fabric = this.fabric || (this.fabric = { });
  6   
  7   if (fabric.Rect) {
  8     console.warn('fabric.Rect is already defined');
  9     return;
 10   }
 11   
 12   /** 
 13    * @class Rect
 14    * @extends fabric.Object
 15    */
 16   fabric.Rect = fabric.util.createClass(fabric.Object, /** @scope fabric.Rect.prototype */ {
 17     
 18     /**
 19      * @property
 20      * @type String
 21      */
 22     type: 'rect',
 23     
 24     /**
 25      * @property
 26      * @type Object
 27      */
 28     options: {
 29       rx: 0,
 30       ry: 0
 31     },
 32     
 33     /**
 34      * Constructor
 35      * @method initialize
 36      * @param options {Object} options object
 37      * @return {Object} thisArg
 38      */
 39     initialize: function(options) {
 40       this.callSuper('initialize', options);
 41       this._initRxRy();
 42     },
 43     
 44     /**
 45      * @private
 46      * @method _initRxRy
 47      */
 48     _initRxRy: function() {
 49       if (this.options.rx && !this.options.ry) {
 50         this.options.ry = this.options.rx;
 51       }
 52       else if (this.options.ry && !this.options.rx) {
 53         this.options.rx = this.options.ry;
 54       }
 55     },
 56     
 57     /**
 58      * @private
 59      * @method _render
 60      * @param ctx {CanvasRenderingContext2D} context to render on
 61      */
 62     _render: function(ctx) {   
 63       var rx = this.options.rx || 0,
 64           ry = this.options.ry || 0,
 65           x = -this.width / 2,
 66           y = -this.height / 2,
 67           w = this.width,
 68           h = this.height;
 69       
 70       ctx.beginPath();
 71       ctx.moveTo(x+rx, y);
 72       ctx.lineTo(x+w-rx, y);
 73       ctx.bezierCurveTo(x+w, y, x+w, y+ry, x+w, y+ry);
 74       ctx.lineTo(x+w, y+h-ry);
 75       ctx.bezierCurveTo(x+w,y+h,x+w-rx,y+h,x+w-rx,y+h);
 76       ctx.lineTo(x+rx,y+h);
 77       ctx.bezierCurveTo(x,y+h,x,y+h-ry,x,y+h-ry);
 78       ctx.lineTo(x,y+ry);
 79       ctx.bezierCurveTo(x,y,x+rx,y,x+rx,y);
 80       ctx.closePath();
 81       
 82       if (this.fill) {
 83         ctx.fill();
 84       }
 85       if (this.stroke) {
 86         ctx.stroke();
 87       }
 88     },
 89     
 90     // since our coordinate system differs from that of SVG
 91     _normalizeLeftTopProperties: function(parsedAttributes) {
 92       if (parsedAttributes.left) {
 93         this.set('left', parsedAttributes.left + this.getWidth() / 2);
 94       }
 95       if (parsedAttributes.top) {
 96         this.set('top', parsedAttributes.top + this.getHeight() / 2);
 97       }
 98       return this;
 99     },
100     
101     /**
102      * @method complexity
103      * @return {Number} complexity
104      */
105     complexity: function() {
106       return 1;
107     }
108   });
109   
110   // TODO (kangax): implement rounded rectangles (both parsing and rendering)
111   fabric.Rect.ATTRIBUTE_NAMES = 'x y width height rx ry fill fill-opacity stroke stroke-width transform'.split(' ');
112   
113   /**
114    * @private
115    */
116   function _setDefaultLeftTopValues(attributes) {
117     attributes.left = attributes.left || 0;
118     attributes.top  = attributes.top  || 0;
119     return attributes;
120   }
121   
122   /**
123    * @static
124    * @method fabric.Rect.fromElement
125    * @param element {SVGElement} element to parse
126    * @param options {Object} options object
127    * @return {fabric.Rect} instance of fabric.Rect
128    */
129   fabric.Rect.fromElement = function(element, options) {
130     if (!element) {
131       return null;
132     }
133     
134     var parsedAttributes = fabric.parseAttributes(element, fabric.Rect.ATTRIBUTE_NAMES);
135     parsedAttributes = _setDefaultLeftTopValues(parsedAttributes);
136     
137     var rect = new fabric.Rect(fabric.util.object.extend(options || { }, parsedAttributes));
138     rect._normalizeLeftTopProperties(parsedAttributes);
139     
140     return rect;
141   };
142   
143   /**
144    * @static
145    * @method fabric.Rect.fromObject
146    * @param object {Object} object to create an instance from
147    * @return {Object} instance of fabric.Rect
148    */
149   fabric.Rect.fromObject = function(object) {
150     return new fabric.Rect(object);
151   };
152 })();