fabric.js/src/shapes/rect.class.js
2014-02-17 11:55:54 -05:00

289 lines
7.7 KiB
JavaScript

(function(global) {
'use strict';
var fabric = global.fabric || (global.fabric = { }),
extend = fabric.util.object.extend;
if (fabric.Rect) {
console.warn('fabric.Rect is already defined');
return;
}
var stateProperties = fabric.Object.prototype.stateProperties.concat();
stateProperties.push('rx', 'ry', 'x', 'y');
/**
* Rectangle class
* @class fabric.Rect
* @extends fabric.Object
* @return {fabric.Rect} thisArg
* @see {@link fabric.Rect#initialize} for constructor definition
*/
fabric.Rect = fabric.util.createClass(fabric.Object, /** @lends fabric.Rect.prototype */ {
/**
* List of properties to consider when checking if state of an object is changed ({@link fabric.Object#hasStateChanged})
* as well as for history (undo/redo) purposes
* @type Array
*/
stateProperties: stateProperties,
/**
* Type of an object
* @type String
* @default
*/
type: 'rect',
/**
* Horizontal border radius
* @type Number
* @default
*/
rx: 0,
/**
* Vertical border radius
* @type Number
* @default
*/
ry: 0,
/**
* @type Number
* @default
*/
x: 0,
/**
* @type Number
* @default
*/
y: 0,
/**
* Used to specify dash pattern for stroke on this object
* @type Array
*/
strokeDashArray: null,
/**
* Constructor
* @param {Object} [options] Options object
* @return {Object} thisArg
*/
initialize: function(options) {
options = options || { };
this.callSuper('initialize', options);
this._initRxRy();
this.x = options.x || 0;
this.y = options.y || 0;
},
/**
* Initializes rx/ry attributes
* @private
*/
_initRxRy: function() {
if (this.rx && !this.ry) {
this.ry = this.rx;
}
else if (this.ry && !this.rx) {
this.rx = this.ry;
}
},
/**
* @private
* @param ctx {CanvasRenderingContext2D} context to render on
*/
_render: function(ctx) {
// optimize 1x1 case (used in spray brush)
if (this.width === 1 && this.height === 1) {
ctx.fillRect(0, 0, 1, 1);
return;
}
var rx = this.rx || 0,
ry = this.ry || 0,
w = this.width,
h = this.height,
x = -w / 2,
y = -h / 2,
isInPathGroup = this.group && this.group.type === 'path-group',
isRounded = rx !== 0 || ry !== 0;
ctx.beginPath();
ctx.globalAlpha = isInPathGroup ? (ctx.globalAlpha * this.opacity) : this.opacity;
if (this.transformMatrix && isInPathGroup) {
ctx.translate(
this.width / 2 + this.x,
this.height / 2 + this.y);
}
if (!this.transformMatrix && isInPathGroup) {
ctx.translate(
-this.group.width / 2 + this.width / 2 + this.x,
-this.group.height / 2 + this.height / 2 + this.y);
}
ctx.moveTo(x + rx, y);
ctx.lineTo(x + w - rx, y);
isRounded && ctx.quadraticCurveTo(x + w, y, x + w, y + ry, x + w, y + ry);
ctx.lineTo(x + w, y + h - ry);
isRounded && ctx.quadraticCurveTo(x + w, y + h, x + w - rx, y + h, x + w - rx, y + h);
ctx.lineTo(x + rx, y + h);
isRounded && ctx.quadraticCurveTo(x, y + h, x, y + h - ry, x, y + h - ry);
ctx.lineTo(x, y + ry);
isRounded && ctx.quadraticCurveTo(x, y, x + rx, y, x + rx, y);
ctx.closePath();
this._renderFill(ctx);
this._renderStroke(ctx);
},
/**
* @private
* @param ctx {CanvasRenderingContext2D} context to render on
*/
_renderDashedStroke: function(ctx) {
var x = -this.width / 2,
y = -this.height / 2,
w = this.width,
h = this.height;
ctx.beginPath();
fabric.util.drawDashedLine(ctx, x, y, x + w, y, this.strokeDashArray);
fabric.util.drawDashedLine(ctx, x + w, y, x + w, y + h, this.strokeDashArray);
fabric.util.drawDashedLine(ctx, x + w, y + h, x, y + h, this.strokeDashArray);
fabric.util.drawDashedLine(ctx, x, y + h, x, y, this.strokeDashArray);
ctx.closePath();
},
/**
* Since coordinate system differs from that of SVG
* @private
*/
_normalizeLeftTopProperties: function(parsedAttributes) {
if ('left' in parsedAttributes) {
this.set('left', parsedAttributes.left + this.getWidth() / 2);
}
this.set('x', parsedAttributes.left || 0);
if ('top' in parsedAttributes) {
this.set('top', parsedAttributes.top + this.getHeight() / 2);
}
this.set('y', parsedAttributes.top || 0);
return this;
},
/**
* Returns object representation of an instance
* @param {Array} [propertiesToInclude] Any properties that you might want to additionally include in the output
* @return {Object} object representation of an instance
*/
toObject: function(propertiesToInclude) {
var object = extend(this.callSuper('toObject', propertiesToInclude), {
rx: this.get('rx') || 0,
ry: this.get('ry') || 0,
x: this.get('x'),
y: this.get('y')
});
if (!this.includeDefaultValues) {
this._removeDefaultValues(object);
}
return object;
},
/* _TO_SVG_START_ */
/**
* Returns svg representation of an instance
* @param {Function} [reviver] Method for further parsing of svg representation.
* @return {String} svg representation of an instance
*/
toSVG: function(reviver) {
var markup = this._createBaseSVGMarkup();
markup.push(
'<rect ',
'x="', (-1 * this.width / 2), '" y="', (-1 * this.height / 2),
'" rx="', this.get('rx'), '" ry="', this.get('ry'),
'" width="', this.width, '" height="', this.height,
'" style="', this.getSvgStyles(),
'" transform="', this.getSvgTransform(),
'"/>');
return reviver ? reviver(markup.join('')) : markup.join('');
},
/* _TO_SVG_END_ */
/**
* Returns complexity of an instance
* @return {Number} complexity
*/
complexity: function() {
return 1;
}
});
/* _FROM_SVG_START_ */
/**
* List of attribute names to account for when parsing SVG element (used by `fabric.Rect.fromElement`)
* @static
* @memberOf fabric.Rect
* @see: http://www.w3.org/TR/SVG/shapes.html#RectElement
*/
fabric.Rect.ATTRIBUTE_NAMES = fabric.SHARED_ATTRIBUTES.concat('x y rx ry width height'.split(' '));
/**
* @private
*/
function _setDefaultLeftTopValues(attributes) {
attributes.left = attributes.left || 0;
attributes.top = attributes.top || 0;
return attributes;
}
/**
* Returns {@link fabric.Rect} instance from an SVG element
* @static
* @memberOf fabric.Rect
* @param {SVGElement} element Element to parse
* @param {Object} [options] Options object
* @return {fabric.Rect} Instance of fabric.Rect
*/
fabric.Rect.fromElement = function(element, options) {
if (!element) {
return null;
}
var parsedAttributes = fabric.parseAttributes(element, fabric.Rect.ATTRIBUTE_NAMES);
parsedAttributes = _setDefaultLeftTopValues(parsedAttributes);
var rect = new fabric.Rect(extend((options ? fabric.util.object.clone(options) : { }), parsedAttributes));
rect._normalizeLeftTopProperties(parsedAttributes);
return rect;
};
/* _FROM_SVG_END_ */
/**
* Returns {@link fabric.Rect} instance from an object representation
* @static
* @memberOf fabric.Rect
* @param object {Object} object to create an instance from
* @return {Object} instance of fabric.Rect
*/
fabric.Rect.fromObject = function(object) {
return new fabric.Rect(object);
};
})(typeof exports !== 'undefined' ? exports : this);