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