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 112 /** 113 * List of attribute names to account for when parsing SVG element (used by `fabric.Rect.fromElement`) 114 * @static 115 */ 116 fabric.Rect.ATTRIBUTE_NAMES = 'x y width height rx ry fill fill-opacity stroke stroke-width transform'.split(' '); 117 118 /** 119 * @private 120 */ 121 function _setDefaultLeftTopValues(attributes) { 122 attributes.left = attributes.left || 0; 123 attributes.top = attributes.top || 0; 124 return attributes; 125 } 126 127 /** 128 * Returns fabric.Rect instance from an SVG element 129 * @static 130 * @method fabric.Rect.fromElement 131 * @param element {SVGElement} element to parse 132 * @param options {Object} options object 133 * @return {fabric.Rect} instance of fabric.Rect 134 */ 135 fabric.Rect.fromElement = function(element, options) { 136 if (!element) { 137 return null; 138 } 139 140 var parsedAttributes = fabric.parseAttributes(element, fabric.Rect.ATTRIBUTE_NAMES); 141 parsedAttributes = _setDefaultLeftTopValues(parsedAttributes); 142 143 var rect = new fabric.Rect(fabric.util.object.extend(options || { }, parsedAttributes)); 144 rect._normalizeLeftTopProperties(parsedAttributes); 145 146 return rect; 147 }; 148 149 /** 150 * Returns fabric.Rect instance from an object representation 151 * @static 152 * @method fabric.Rect.fromObject 153 * @param object {Object} object to create an instance from 154 * @return {Object} instance of fabric.Rect 155 */ 156 fabric.Rect.fromObject = function(object) { 157 return new fabric.Rect(object); 158 }; 159 })();