2012-10-14 17:23:39 +00:00
|
|
|
(function(global) {
|
|
|
|
|
|
|
|
|
|
"use strict";
|
|
|
|
|
|
|
|
|
|
var fabric = global.fabric || (global.fabric = { }),
|
|
|
|
|
extend = fabric.util.object.extend,
|
|
|
|
|
toFixed = fabric.util.toFixed,
|
|
|
|
|
capitalize = fabric.util.string.capitalize,
|
2012-12-02 10:53:38 +00:00
|
|
|
degreesToRadians = fabric.util.degreesToRadians;
|
2012-10-14 17:23:39 +00:00
|
|
|
|
|
|
|
|
if (fabric.Object) {
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
2012-12-20 18:49:39 +00:00
|
|
|
var Image = global.Image;
|
|
|
|
|
try {
|
2012-12-23 14:19:21 +00:00
|
|
|
var NodeImage = (typeof require !== 'undefined') && require('canvas').Image;
|
2012-12-20 18:49:39 +00:00
|
|
|
if (NodeImage) {
|
|
|
|
|
Image = NodeImage;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
catch(err) {
|
|
|
|
|
fabric.log(err);
|
|
|
|
|
}
|
|
|
|
|
|
2012-10-14 17:23:39 +00:00
|
|
|
/**
|
2012-12-15 16:05:23 +00:00
|
|
|
* Root object class from which all 2d shape classes inherit from
|
2012-10-14 17:23:39 +00:00
|
|
|
* @class Object
|
|
|
|
|
* @memberOf fabric
|
|
|
|
|
*/
|
|
|
|
|
fabric.Object = fabric.util.createClass(/** @scope fabric.Object.prototype */ {
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Type of an object (rect, circle, path, etc)
|
|
|
|
|
* @property
|
|
|
|
|
* @type String
|
|
|
|
|
*/
|
|
|
|
|
type: 'object',
|
|
|
|
|
|
|
|
|
|
/**
|
2012-12-06 18:12:54 +00:00
|
|
|
* Horizontal origin of transformation of an object (one of "left", "right", "center")
|
|
|
|
|
* @property
|
|
|
|
|
* @type String
|
|
|
|
|
*/
|
|
|
|
|
originX: 'center',
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Vertical origin of transformation of an object (one of "top", "bottom", "center")
|
|
|
|
|
* @property
|
|
|
|
|
* @type String
|
|
|
|
|
*/
|
|
|
|
|
originY: 'center',
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Top position of an object
|
2012-10-14 17:23:39 +00:00
|
|
|
* @property
|
|
|
|
|
* @type Number
|
|
|
|
|
*/
|
|
|
|
|
top: 0,
|
|
|
|
|
|
|
|
|
|
/**
|
2012-12-06 18:12:54 +00:00
|
|
|
* Left position of an object
|
2012-10-14 17:23:39 +00:00
|
|
|
* @property
|
|
|
|
|
* @type Number
|
|
|
|
|
*/
|
|
|
|
|
left: 0,
|
|
|
|
|
|
|
|
|
|
/**
|
2012-12-15 16:05:23 +00:00
|
|
|
* Object width
|
2012-10-14 17:23:39 +00:00
|
|
|
* @property
|
|
|
|
|
* @type Number
|
|
|
|
|
*/
|
|
|
|
|
width: 0,
|
|
|
|
|
|
|
|
|
|
/**
|
2012-12-15 16:05:23 +00:00
|
|
|
* Object height
|
2012-10-14 17:23:39 +00:00
|
|
|
* @property
|
|
|
|
|
* @type Number
|
|
|
|
|
*/
|
|
|
|
|
height: 0,
|
|
|
|
|
|
|
|
|
|
/**
|
2012-12-15 16:05:23 +00:00
|
|
|
* Object scale factor (horizontal)
|
2012-10-14 17:23:39 +00:00
|
|
|
* @property
|
|
|
|
|
* @type Number
|
|
|
|
|
*/
|
|
|
|
|
scaleX: 1,
|
|
|
|
|
|
|
|
|
|
/**
|
2012-12-15 16:05:23 +00:00
|
|
|
* Object scale factor (vertical)
|
2012-10-14 17:23:39 +00:00
|
|
|
* @property
|
|
|
|
|
* @type Number
|
|
|
|
|
*/
|
|
|
|
|
scaleY: 1,
|
|
|
|
|
|
|
|
|
|
/**
|
2012-12-06 18:12:54 +00:00
|
|
|
* When true, an object is rendered as flipped horizontally
|
2012-10-14 17:23:39 +00:00
|
|
|
* @property
|
|
|
|
|
* @type Boolean
|
|
|
|
|
*/
|
|
|
|
|
flipX: false,
|
|
|
|
|
|
|
|
|
|
/**
|
2012-12-06 18:12:54 +00:00
|
|
|
* When true, an object is rendered as flipped vertically
|
2012-10-14 17:23:39 +00:00
|
|
|
* @property
|
|
|
|
|
* @type Boolean
|
|
|
|
|
*/
|
|
|
|
|
flipY: false,
|
|
|
|
|
|
|
|
|
|
/**
|
2012-12-06 18:12:54 +00:00
|
|
|
* Opacity of an object
|
2012-10-14 17:23:39 +00:00
|
|
|
* @property
|
|
|
|
|
* @type Number
|
|
|
|
|
*/
|
|
|
|
|
opacity: 1,
|
|
|
|
|
|
|
|
|
|
/**
|
2012-12-15 16:16:39 +00:00
|
|
|
* Angle of rotation of an object (in degrees)
|
2012-10-14 17:23:39 +00:00
|
|
|
* @property
|
|
|
|
|
* @type Number
|
|
|
|
|
*/
|
|
|
|
|
angle: 0,
|
|
|
|
|
|
|
|
|
|
/**
|
2012-12-06 18:12:54 +00:00
|
|
|
* Size of object's corners (in pixels)
|
2012-10-14 17:23:39 +00:00
|
|
|
* @property
|
|
|
|
|
* @type Number
|
|
|
|
|
*/
|
2012-12-22 15:37:43 +00:00
|
|
|
cornerSize: 12,
|
2012-10-14 17:23:39 +00:00
|
|
|
|
|
|
|
|
/**
|
2012-12-02 10:53:38 +00:00
|
|
|
* When true, object's corners are rendered as transparent inside (i.e. stroke instead of fill)
|
2012-10-14 17:23:39 +00:00
|
|
|
* @property
|
|
|
|
|
* @type Boolean
|
|
|
|
|
*/
|
|
|
|
|
transparentCorners: true,
|
|
|
|
|
|
|
|
|
|
/**
|
2012-12-06 18:12:54 +00:00
|
|
|
* Padding between object and its borders (in pixels)
|
2012-10-14 17:23:39 +00:00
|
|
|
* @property
|
|
|
|
|
* @type Number
|
|
|
|
|
*/
|
|
|
|
|
padding: 0,
|
|
|
|
|
|
|
|
|
|
/**
|
2012-12-15 16:05:23 +00:00
|
|
|
* Border color of an object (when it's active)
|
2012-10-14 17:23:39 +00:00
|
|
|
* @property
|
|
|
|
|
* @type String
|
|
|
|
|
*/
|
|
|
|
|
borderColor: 'rgba(102,153,255,0.75)',
|
|
|
|
|
|
|
|
|
|
/**
|
2012-12-15 16:05:23 +00:00
|
|
|
* Corner color of an object (when it's active)
|
2012-10-14 17:23:39 +00:00
|
|
|
* @property
|
|
|
|
|
* @type String
|
|
|
|
|
*/
|
|
|
|
|
cornerColor: 'rgba(102,153,255,0.5)',
|
|
|
|
|
|
|
|
|
|
/**
|
2012-12-06 18:12:54 +00:00
|
|
|
* Color of object's fill
|
2012-10-14 17:23:39 +00:00
|
|
|
* @property
|
|
|
|
|
* @type String
|
|
|
|
|
*/
|
|
|
|
|
fill: 'rgb(0,0,0)',
|
|
|
|
|
|
|
|
|
|
/**
|
2012-12-15 16:05:23 +00:00
|
|
|
* Fill rule used to fill an object
|
2012-10-14 17:23:39 +00:00
|
|
|
* @property
|
|
|
|
|
* @type String
|
|
|
|
|
*/
|
|
|
|
|
fillRule: 'source-over',
|
|
|
|
|
|
|
|
|
|
/**
|
2012-12-15 16:05:23 +00:00
|
|
|
* Overlay fill (takes precedence over fill value)
|
2012-10-14 17:23:39 +00:00
|
|
|
* @property
|
|
|
|
|
* @type String
|
|
|
|
|
*/
|
|
|
|
|
overlayFill: null,
|
|
|
|
|
|
|
|
|
|
/**
|
2012-12-06 18:12:54 +00:00
|
|
|
* When `true`, an object is rendered via stroke and this property specifies its color
|
2012-10-14 17:23:39 +00:00
|
|
|
* @property
|
|
|
|
|
* @type String
|
|
|
|
|
*/
|
|
|
|
|
stroke: null,
|
|
|
|
|
|
|
|
|
|
/**
|
2012-12-02 10:53:38 +00:00
|
|
|
* Width of a stroke used to render this object
|
2012-10-14 17:23:39 +00:00
|
|
|
* @property
|
|
|
|
|
* @type Number
|
|
|
|
|
*/
|
|
|
|
|
strokeWidth: 1,
|
|
|
|
|
|
|
|
|
|
/**
|
2012-12-15 16:05:23 +00:00
|
|
|
* Array specifying dash pattern of an object's stroke
|
2012-10-14 17:23:39 +00:00
|
|
|
* @property
|
|
|
|
|
* @type Array
|
|
|
|
|
*/
|
|
|
|
|
strokeDashArray: null,
|
|
|
|
|
|
|
|
|
|
/**
|
2012-12-06 18:12:54 +00:00
|
|
|
* Border opacity when object is active and moving
|
2012-10-14 17:23:39 +00:00
|
|
|
* @property
|
|
|
|
|
* @type Number
|
|
|
|
|
*/
|
|
|
|
|
borderOpacityWhenMoving: 0.4,
|
|
|
|
|
|
|
|
|
|
/**
|
2012-12-15 16:05:23 +00:00
|
|
|
* Border scale factor
|
2012-10-14 17:23:39 +00:00
|
|
|
* @property
|
|
|
|
|
* @type Number
|
|
|
|
|
*/
|
|
|
|
|
borderScaleFactor: 1,
|
|
|
|
|
|
|
|
|
|
/**
|
2012-12-06 18:12:54 +00:00
|
|
|
* Transform matrix (similar to SVG's transform matrix)
|
2012-10-14 17:23:39 +00:00
|
|
|
* @property
|
|
|
|
|
* @type Array
|
|
|
|
|
*/
|
|
|
|
|
transformMatrix: null,
|
|
|
|
|
|
2012-12-06 18:12:54 +00:00
|
|
|
/**
|
|
|
|
|
* Minimum allowed scale value of an object
|
|
|
|
|
* @property
|
|
|
|
|
* @type Number
|
|
|
|
|
*/
|
|
|
|
|
minScaleLimit: 0.01,
|
|
|
|
|
|
2012-10-14 17:23:39 +00:00
|
|
|
/**
|
|
|
|
|
* When set to `false`, an object can not be selected for modification (using either point-click-based or group-based selection)
|
|
|
|
|
* @property
|
|
|
|
|
* @type Boolean
|
|
|
|
|
*/
|
|
|
|
|
selectable: true,
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* When set to `false`, object's controls are not displayed and can not be used to manipulate object
|
|
|
|
|
* @property
|
|
|
|
|
* @type Boolean
|
|
|
|
|
*/
|
|
|
|
|
hasControls: true,
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* When set to `false`, object's borders are not rendered
|
|
|
|
|
* @property
|
|
|
|
|
* @type Boolean
|
|
|
|
|
*/
|
|
|
|
|
hasBorders: true,
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* When set to `false`, object's rotating point will not be visible or selectable
|
|
|
|
|
* @property
|
|
|
|
|
* @type Boolean
|
|
|
|
|
*/
|
2012-12-26 10:18:17 +00:00
|
|
|
hasRotatingPoint: true,
|
2012-10-14 17:23:39 +00:00
|
|
|
|
|
|
|
|
/**
|
2012-12-06 18:12:54 +00:00
|
|
|
* Offset for object's rotating point (when enabled via `hasRotatingPoint`)
|
2012-10-14 17:23:39 +00:00
|
|
|
* @property
|
|
|
|
|
* @type Number
|
|
|
|
|
*/
|
|
|
|
|
rotatingPointOffset: 40,
|
|
|
|
|
|
|
|
|
|
/**
|
2012-11-15 13:20:45 +00:00
|
|
|
* When set to `true`, objects are "found" on canvas on per-pixel basis rather than according to bounding box
|
2012-10-14 17:23:39 +00:00
|
|
|
* @property
|
2012-11-15 13:20:45 +00:00
|
|
|
* @type Boolean
|
2012-10-14 17:23:39 +00:00
|
|
|
*/
|
|
|
|
|
perPixelTargetFind: false,
|
|
|
|
|
|
2012-11-15 13:20:45 +00:00
|
|
|
/**
|
2012-12-06 18:12:54 +00:00
|
|
|
* When `false`, default object's values are not included in its serialization
|
2012-11-15 13:20:45 +00:00
|
|
|
* @property
|
|
|
|
|
* @type Boolean
|
|
|
|
|
*/
|
2012-10-14 17:23:39 +00:00
|
|
|
includeDefaultValues: true,
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* List of properties to consider when checking if state of an object is changed (fabric.Object#hasStateChanged);
|
|
|
|
|
* as well as for history (undo/redo) purposes
|
|
|
|
|
* @property
|
|
|
|
|
* @type Array
|
|
|
|
|
*/
|
|
|
|
|
stateProperties: (
|
|
|
|
|
'top left width height scaleX scaleY flipX flipY ' +
|
2012-12-26 10:18:17 +00:00
|
|
|
'angle opacity cornerSize fill overlayFill originX originY ' +
|
2012-10-14 17:23:39 +00:00
|
|
|
'stroke strokeWidth strokeDashArray fillRule ' +
|
|
|
|
|
'borderScaleFactor transformMatrix selectable'
|
|
|
|
|
).split(' '),
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Constructor
|
|
|
|
|
* @method initialize
|
|
|
|
|
* @param {Object} [options] Options object
|
|
|
|
|
*/
|
|
|
|
|
initialize: function(options) {
|
|
|
|
|
if (options) {
|
|
|
|
|
this.setOptions(options);
|
|
|
|
|
}
|
|
|
|
|
},
|
|
|
|
|
|
|
|
|
|
/**
|
2012-12-15 16:05:23 +00:00
|
|
|
* Sets object's properties from options
|
2012-10-14 17:23:39 +00:00
|
|
|
* @method setOptions
|
|
|
|
|
* @param {Object} [options]
|
|
|
|
|
*/
|
|
|
|
|
setOptions: function(options) {
|
2012-11-30 22:46:09 +00:00
|
|
|
for (var prop in options) {
|
|
|
|
|
this.set(prop, options[prop]);
|
2012-10-14 17:23:39 +00:00
|
|
|
}
|
|
|
|
|
this._initGradient(options);
|
|
|
|
|
},
|
|
|
|
|
|
|
|
|
|
/**
|
2012-12-15 16:05:23 +00:00
|
|
|
* Transforms context when rendering an object
|
2012-10-14 17:23:39 +00:00
|
|
|
* @method transform
|
|
|
|
|
* @param {CanvasRenderingContext2D} ctx Context
|
|
|
|
|
*/
|
|
|
|
|
transform: function(ctx) {
|
|
|
|
|
ctx.globalAlpha = this.opacity;
|
2012-12-06 18:12:54 +00:00
|
|
|
|
|
|
|
|
var center = this.getCenterPoint();
|
|
|
|
|
ctx.translate(center.x, center.y);
|
2012-11-15 13:20:45 +00:00
|
|
|
ctx.rotate(degreesToRadians(this.angle));
|
2012-10-14 17:23:39 +00:00
|
|
|
ctx.scale(
|
|
|
|
|
this.scaleX * (this.flipX ? -1 : 1),
|
|
|
|
|
this.scaleY * (this.flipY ? -1 : 1)
|
|
|
|
|
);
|
|
|
|
|
},
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Returns an object representation of an instance
|
|
|
|
|
* @method toObject
|
2012-12-01 12:57:27 +00:00
|
|
|
* @param {Array} propertiesToInclude
|
|
|
|
|
* @return {Object} object representation of an instance
|
2012-10-14 17:23:39 +00:00
|
|
|
*/
|
2012-11-30 22:46:09 +00:00
|
|
|
toObject: function(propertiesToInclude) {
|
2012-10-14 17:23:39 +00:00
|
|
|
|
|
|
|
|
var NUM_FRACTION_DIGITS = fabric.Object.NUM_FRACTION_DIGITS;
|
|
|
|
|
|
|
|
|
|
var object = {
|
|
|
|
|
type: this.type,
|
2012-12-06 18:12:54 +00:00
|
|
|
originX: this.originX,
|
|
|
|
|
originY: this.originY,
|
2012-10-14 17:23:39 +00:00
|
|
|
left: toFixed(this.left, NUM_FRACTION_DIGITS),
|
|
|
|
|
top: toFixed(this.top, NUM_FRACTION_DIGITS),
|
|
|
|
|
width: toFixed(this.width, NUM_FRACTION_DIGITS),
|
|
|
|
|
height: toFixed(this.height, NUM_FRACTION_DIGITS),
|
|
|
|
|
fill: (this.fill && this.fill.toObject) ? this.fill.toObject() : this.fill,
|
|
|
|
|
overlayFill: this.overlayFill,
|
|
|
|
|
stroke: this.stroke,
|
|
|
|
|
strokeWidth: this.strokeWidth,
|
|
|
|
|
strokeDashArray: this.strokeDashArray,
|
|
|
|
|
scaleX: toFixed(this.scaleX, NUM_FRACTION_DIGITS),
|
|
|
|
|
scaleY: toFixed(this.scaleY, NUM_FRACTION_DIGITS),
|
|
|
|
|
angle: toFixed(this.getAngle(), NUM_FRACTION_DIGITS),
|
|
|
|
|
flipX: this.flipX,
|
|
|
|
|
flipY: this.flipY,
|
|
|
|
|
opacity: toFixed(this.opacity, NUM_FRACTION_DIGITS),
|
|
|
|
|
selectable: this.selectable,
|
|
|
|
|
hasControls: this.hasControls,
|
|
|
|
|
hasBorders: this.hasBorders,
|
|
|
|
|
hasRotatingPoint: this.hasRotatingPoint,
|
|
|
|
|
transparentCorners: this.transparentCorners,
|
|
|
|
|
perPixelTargetFind: this.perPixelTargetFind
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
if (!this.includeDefaultValues) {
|
|
|
|
|
object = this._removeDefaultValues(object);
|
|
|
|
|
}
|
2012-11-30 22:46:09 +00:00
|
|
|
fabric.util.populateWithProperties(this, object, propertiesToInclude);
|
2012-10-14 17:23:39 +00:00
|
|
|
|
|
|
|
|
return object;
|
|
|
|
|
},
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Returns (dataless) object representation of an instance
|
|
|
|
|
* @method toDatalessObject
|
2012-12-15 16:05:23 +00:00
|
|
|
* @param {Array} [propertiesToInclude]
|
2012-12-01 12:57:27 +00:00
|
|
|
* @return {Object} object representation of an instance
|
2012-10-14 17:23:39 +00:00
|
|
|
*/
|
2012-11-30 22:46:09 +00:00
|
|
|
toDatalessObject: function(propertiesToInclude) {
|
2012-10-14 17:23:39 +00:00
|
|
|
// will be overwritten by subclasses
|
2012-11-30 22:46:09 +00:00
|
|
|
return this.toObject(propertiesToInclude);
|
2012-10-14 17:23:39 +00:00
|
|
|
},
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Returns styles-string for svg-export
|
|
|
|
|
* @method getSvgStyles
|
2012-12-15 16:05:23 +00:00
|
|
|
* @return {String}
|
2012-10-14 17:23:39 +00:00
|
|
|
*/
|
|
|
|
|
getSvgStyles: function() {
|
|
|
|
|
return [
|
|
|
|
|
"stroke: ", (this.stroke ? this.stroke : 'none'), "; ",
|
|
|
|
|
"stroke-width: ", (this.strokeWidth ? this.strokeWidth : '0'), "; ",
|
|
|
|
|
"stroke-dasharray: ", (this.strokeDashArray ? this.strokeDashArray.join(' ') : "; "),
|
|
|
|
|
"fill: ", (this.fill ? this.fill : 'none'), "; ",
|
|
|
|
|
"opacity: ", (this.opacity ? this.opacity : '1'), ";"
|
|
|
|
|
].join("");
|
|
|
|
|
},
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Returns transform-string for svg-export
|
|
|
|
|
* @method getSvgTransform
|
2012-12-15 16:05:23 +00:00
|
|
|
* @return {String}
|
2012-10-14 17:23:39 +00:00
|
|
|
*/
|
|
|
|
|
getSvgTransform: function() {
|
|
|
|
|
var angle = this.getAngle();
|
2012-12-06 18:12:54 +00:00
|
|
|
var center = this.getCenterPoint();
|
|
|
|
|
|
2012-10-24 20:05:19 +00:00
|
|
|
var NUM_FRACTION_DIGITS = fabric.Object.NUM_FRACTION_DIGITS;
|
2012-10-26 13:26:44 +00:00
|
|
|
|
|
|
|
|
var translatePart = "translate(" +
|
2012-12-06 18:12:54 +00:00
|
|
|
toFixed(center.x, NUM_FRACTION_DIGITS) +
|
2012-10-26 13:26:44 +00:00
|
|
|
" " +
|
2012-12-06 18:12:54 +00:00
|
|
|
toFixed(center.y, NUM_FRACTION_DIGITS) +
|
2012-10-26 13:26:44 +00:00
|
|
|
")";
|
|
|
|
|
|
|
|
|
|
var anglePart = angle !== 0
|
|
|
|
|
? (" rotate(" + toFixed(angle, NUM_FRACTION_DIGITS) + ")")
|
|
|
|
|
: '';
|
|
|
|
|
|
|
|
|
|
var scalePart = (this.scaleX === 1 && this.scaleY === 1)
|
|
|
|
|
? '' :
|
|
|
|
|
(" scale(" +
|
|
|
|
|
toFixed(this.scaleX, NUM_FRACTION_DIGITS) +
|
|
|
|
|
" " +
|
|
|
|
|
toFixed(this.scaleY, NUM_FRACTION_DIGITS) +
|
|
|
|
|
")");
|
|
|
|
|
|
|
|
|
|
var flipXPart = this.flipX ? "matrix(-1 0 0 1 0 0) " : "";
|
|
|
|
|
var flipYPart = this.flipY ? "matrix(1 0 0 -1 0 0)" : "";
|
|
|
|
|
|
|
|
|
|
return [ translatePart, anglePart, scalePart, flipXPart, flipYPart ].join('');
|
2012-10-14 17:23:39 +00:00
|
|
|
},
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* @private
|
|
|
|
|
* @method _removeDefaultValues
|
|
|
|
|
*/
|
|
|
|
|
_removeDefaultValues: function(object) {
|
|
|
|
|
var defaultOptions = fabric.Object.prototype.options;
|
|
|
|
|
if (defaultOptions) {
|
|
|
|
|
this.stateProperties.forEach(function(prop) {
|
|
|
|
|
if (object[prop] === defaultOptions[prop]) {
|
|
|
|
|
delete object[prop];
|
|
|
|
|
}
|
|
|
|
|
});
|
|
|
|
|
}
|
|
|
|
|
return object;
|
|
|
|
|
},
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Returns true if an object is in its active state
|
|
|
|
|
* @return {Boolean} true if an object is in its active state
|
|
|
|
|
*/
|
|
|
|
|
isActive: function() {
|
|
|
|
|
return !!this.active;
|
|
|
|
|
},
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Sets state of an object - `true` makes it active, `false` - inactive
|
|
|
|
|
* @param {Boolean} active
|
|
|
|
|
* @return {fabric.Object} thisArg
|
|
|
|
|
* @chainable
|
|
|
|
|
*/
|
|
|
|
|
setActive: function(active) {
|
|
|
|
|
this.active = !!active;
|
|
|
|
|
return this;
|
|
|
|
|
},
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Returns a string representation of an instance
|
|
|
|
|
* @return {String}
|
|
|
|
|
*/
|
|
|
|
|
toString: function() {
|
|
|
|
|
return "#<fabric." + capitalize(this.type) + ">";
|
|
|
|
|
},
|
|
|
|
|
|
2012-12-06 18:12:54 +00:00
|
|
|
/**
|
2013-01-20 16:30:34 +00:00
|
|
|
* Basic getter
|
|
|
|
|
* @method get
|
|
|
|
|
* @param {String} property
|
|
|
|
|
* @return {Any} value of a property
|
|
|
|
|
*/
|
|
|
|
|
get: function(property) {
|
|
|
|
|
return this[property];
|
2012-12-06 18:12:54 +00:00
|
|
|
},
|
|
|
|
|
|
2012-10-14 17:23:39 +00:00
|
|
|
/**
|
|
|
|
|
* Sets property to a given value
|
|
|
|
|
* @method set
|
|
|
|
|
* @param {String} name
|
|
|
|
|
* @param {Object|Function} value
|
|
|
|
|
* @return {fabric.Group} thisArg
|
|
|
|
|
* @chainable
|
|
|
|
|
*/
|
|
|
|
|
set: function(key, value) {
|
|
|
|
|
if (typeof key === 'object') {
|
|
|
|
|
for (var prop in key) {
|
|
|
|
|
this._set(prop, key[prop]);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
else {
|
|
|
|
|
if (typeof value === 'function') {
|
|
|
|
|
this._set(key, value(this.get(key)));
|
|
|
|
|
}
|
|
|
|
|
else {
|
|
|
|
|
this._set(key, value);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
return this;
|
|
|
|
|
},
|
|
|
|
|
|
2012-12-15 16:05:23 +00:00
|
|
|
/**
|
|
|
|
|
* @private
|
|
|
|
|
* @method _set
|
|
|
|
|
* @param key
|
|
|
|
|
* @param value
|
|
|
|
|
*/
|
2012-10-14 17:23:39 +00:00
|
|
|
_set: function(key, value) {
|
2012-12-06 18:12:54 +00:00
|
|
|
var shouldConstrainValue = (key === 'scaleX' || key === 'scaleY');
|
2012-10-14 17:23:39 +00:00
|
|
|
|
|
|
|
|
if (shouldConstrainValue) {
|
2012-12-06 18:12:54 +00:00
|
|
|
value = this._constrainScale(value);
|
|
|
|
|
}
|
|
|
|
|
if (key === 'scaleX' && value < 0) {
|
|
|
|
|
this.flipX = !this.flipX;
|
|
|
|
|
value *= -1;
|
2012-10-14 17:23:39 +00:00
|
|
|
}
|
2012-12-06 18:12:54 +00:00
|
|
|
else if (key === 'scaleY' && value < 0) {
|
|
|
|
|
this.flipY = !this.flipY;
|
|
|
|
|
value *= -1;
|
|
|
|
|
}
|
|
|
|
|
else if (key === 'width' || key === 'height') {
|
2012-12-15 16:09:21 +00:00
|
|
|
this.minScaleLimit = toFixed(Math.min(0.1, 1/Math.max(this.width, this.height)), 2);
|
2012-12-06 18:12:54 +00:00
|
|
|
}
|
|
|
|
|
|
2012-11-15 13:20:45 +00:00
|
|
|
this[key] = value;
|
2012-12-06 18:12:54 +00:00
|
|
|
|
|
|
|
|
return this;
|
2012-10-14 17:23:39 +00:00
|
|
|
},
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Toggles specified property from `true` to `false` or from `false` to `true`
|
|
|
|
|
* @method toggle
|
|
|
|
|
* @param {String} property property to toggle
|
|
|
|
|
* @return {fabric.Object} thisArg
|
|
|
|
|
* @chainable
|
|
|
|
|
*/
|
|
|
|
|
toggle: function(property) {
|
|
|
|
|
var value = this.get(property);
|
|
|
|
|
if (typeof value === 'boolean') {
|
|
|
|
|
this.set(property, !value);
|
|
|
|
|
}
|
|
|
|
|
return this;
|
|
|
|
|
},
|
|
|
|
|
|
|
|
|
|
/**
|
2012-12-15 16:05:23 +00:00
|
|
|
* Sets sourcePath of an object
|
2012-10-14 17:23:39 +00:00
|
|
|
* @method setSourcePath
|
|
|
|
|
* @param {String} value
|
|
|
|
|
* @return {fabric.Object} thisArg
|
|
|
|
|
* @chainable
|
|
|
|
|
*/
|
|
|
|
|
setSourcePath: function(value) {
|
|
|
|
|
this.sourcePath = value;
|
|
|
|
|
return this;
|
|
|
|
|
},
|
|
|
|
|
|
|
|
|
|
/**
|
2012-12-15 16:05:23 +00:00
|
|
|
* Renders an object on a specified context
|
2012-10-14 17:23:39 +00:00
|
|
|
* @method render
|
|
|
|
|
* @param {CanvasRenderingContext2D} ctx context to render on
|
|
|
|
|
* @param {Boolean} noTransform
|
|
|
|
|
*/
|
|
|
|
|
render: function(ctx, noTransform) {
|
|
|
|
|
|
|
|
|
|
// do not render if width or height are zeros
|
|
|
|
|
if (this.width === 0 || this.height === 0) return;
|
|
|
|
|
|
|
|
|
|
ctx.save();
|
|
|
|
|
|
|
|
|
|
var m = this.transformMatrix;
|
|
|
|
|
if (m && !this.group) {
|
|
|
|
|
ctx.setTransform(m[0], m[1], m[2], m[3], m[4], m[5]);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (!noTransform) {
|
|
|
|
|
this.transform(ctx);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (this.stroke || this.strokeDashArray) {
|
|
|
|
|
ctx.lineWidth = this.strokeWidth;
|
|
|
|
|
ctx.strokeStyle = this.stroke;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (this.overlayFill) {
|
|
|
|
|
ctx.fillStyle = this.overlayFill;
|
|
|
|
|
}
|
|
|
|
|
else if (this.fill) {
|
|
|
|
|
ctx.fillStyle = this.fill.toLiveGradient
|
|
|
|
|
? this.fill.toLiveGradient(ctx)
|
|
|
|
|
: this.fill;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (m && this.group) {
|
|
|
|
|
ctx.translate(-this.group.width/2, -this.group.height/2);
|
|
|
|
|
ctx.transform(m[0], m[1], m[2], m[3], m[4], m[5]);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
this._render(ctx, noTransform);
|
|
|
|
|
|
|
|
|
|
if (this.active && !noTransform) {
|
|
|
|
|
this.drawBorders(ctx);
|
2013-01-10 13:20:25 +00:00
|
|
|
this.hideCorners || this.drawCorners(ctx);
|
2012-10-14 17:23:39 +00:00
|
|
|
}
|
|
|
|
|
ctx.restore();
|
|
|
|
|
},
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Clones an instance
|
|
|
|
|
* @method clone
|
2012-12-01 12:57:27 +00:00
|
|
|
* @param {Function} callback Callback is invoked with a clone as a first argument
|
|
|
|
|
* @param {Array} propertiesToInclude
|
2012-10-14 17:23:39 +00:00
|
|
|
* @return {fabric.Object} clone of an instance
|
|
|
|
|
*/
|
2012-12-01 12:57:27 +00:00
|
|
|
clone: function(callback, propertiesToInclude) {
|
2012-10-14 17:23:39 +00:00
|
|
|
if (this.constructor.fromObject) {
|
2012-12-01 12:57:27 +00:00
|
|
|
return this.constructor.fromObject(this.toObject(propertiesToInclude), callback);
|
2012-10-14 17:23:39 +00:00
|
|
|
}
|
2012-12-01 12:57:27 +00:00
|
|
|
return new fabric.Object(this.toObject(propertiesToInclude));
|
2012-10-14 17:23:39 +00:00
|
|
|
},
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Creates an instance of fabric.Image out of an object
|
|
|
|
|
* @method cloneAsImage
|
|
|
|
|
* @param callback {Function} callback, invoked with an instance as a first argument
|
|
|
|
|
* @return {fabric.Object} thisArg
|
|
|
|
|
* @chainable
|
|
|
|
|
*/
|
|
|
|
|
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);
|
|
|
|
|
this.toDataURL(function(dataURL) {
|
|
|
|
|
i.src = dataURL;
|
|
|
|
|
});
|
|
|
|
|
}
|
|
|
|
|
return this;
|
|
|
|
|
},
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Converts an object into a data-url-like string
|
|
|
|
|
* @method toDataURL
|
2013-01-10 13:20:13 +00:00
|
|
|
* @param callback {Function} callback that recieves resulting data-url string
|
2012-10-14 17:23:39 +00:00
|
|
|
*/
|
|
|
|
|
toDataURL: function(callback) {
|
|
|
|
|
var el = fabric.document.createElement('canvas');
|
|
|
|
|
if (!el.getContext && typeof G_vmlCanvasManager !== 'undefined') {
|
|
|
|
|
G_vmlCanvasManager.initElement(el);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
el.width = this.getBoundingRectWidth();
|
|
|
|
|
el.height = this.getBoundingRectHeight();
|
|
|
|
|
|
|
|
|
|
fabric.util.wrapElement(el, 'div');
|
|
|
|
|
|
|
|
|
|
var canvas = new fabric.Canvas(el);
|
|
|
|
|
canvas.backgroundColor = 'transparent';
|
|
|
|
|
canvas.renderAll();
|
|
|
|
|
|
|
|
|
|
if (this.constructor.async) {
|
|
|
|
|
this.clone(proceed);
|
|
|
|
|
}
|
|
|
|
|
else {
|
|
|
|
|
proceed(this.clone());
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
function proceed(clone) {
|
|
|
|
|
clone.left = el.width / 2;
|
|
|
|
|
clone.top = el.height / 2;
|
|
|
|
|
|
|
|
|
|
clone.setActive(false);
|
|
|
|
|
|
|
|
|
|
canvas.add(clone);
|
|
|
|
|
var data = canvas.toDataURL('png');
|
|
|
|
|
|
|
|
|
|
canvas.dispose();
|
|
|
|
|
canvas = clone = null;
|
|
|
|
|
|
|
|
|
|
callback && callback(data);
|
|
|
|
|
}
|
|
|
|
|
},
|
|
|
|
|
|
|
|
|
|
/**
|
2012-12-15 16:05:23 +00:00
|
|
|
* Returns true if object state (one of its state properties) was changed
|
2012-10-14 17:23:39 +00:00
|
|
|
* @method hasStateChanged
|
|
|
|
|
* @return {Boolean} true if instance' state has changed
|
|
|
|
|
*/
|
|
|
|
|
hasStateChanged: function() {
|
|
|
|
|
return this.stateProperties.some(function(prop) {
|
|
|
|
|
return this[prop] !== this.originalState[prop];
|
|
|
|
|
}, this);
|
|
|
|
|
},
|
|
|
|
|
|
|
|
|
|
/**
|
2012-12-15 16:05:23 +00:00
|
|
|
* Saves state of an object
|
2012-10-14 17:23:39 +00:00
|
|
|
* @method saveState
|
|
|
|
|
* @return {fabric.Object} thisArg
|
|
|
|
|
* @chainable
|
|
|
|
|
*/
|
|
|
|
|
saveState: function() {
|
|
|
|
|
this.stateProperties.forEach(function(prop) {
|
|
|
|
|
this.originalState[prop] = this.get(prop);
|
|
|
|
|
}, this);
|
|
|
|
|
return this;
|
|
|
|
|
},
|
|
|
|
|
|
|
|
|
|
/**
|
2012-12-15 16:05:23 +00:00
|
|
|
* Setups state of an object
|
2012-10-14 17:23:39 +00:00
|
|
|
* @method setupState
|
|
|
|
|
*/
|
|
|
|
|
setupState: function() {
|
|
|
|
|
this.originalState = { };
|
|
|
|
|
this.saveState();
|
|
|
|
|
},
|
|
|
|
|
|
|
|
|
|
/**
|
2012-12-15 16:05:23 +00:00
|
|
|
* Returns true if specified type is identical to the type of an instance
|
2012-10-14 17:23:39 +00:00
|
|
|
* @method isType
|
|
|
|
|
* @param type {String} type to check against
|
2012-12-15 16:05:23 +00:00
|
|
|
* @return {Boolean}
|
2012-10-14 17:23:39 +00:00
|
|
|
*/
|
|
|
|
|
isType: function(type) {
|
|
|
|
|
return this.type === type;
|
|
|
|
|
},
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Makes object's color grayscale
|
|
|
|
|
* @method toGrayscale
|
|
|
|
|
* @return {fabric.Object} thisArg
|
|
|
|
|
*/
|
|
|
|
|
toGrayscale: function() {
|
|
|
|
|
var fillValue = this.get('fill');
|
|
|
|
|
if (fillValue) {
|
|
|
|
|
this.set('overlayFill', new fabric.Color(fillValue).toGrayscale().toRgb());
|
|
|
|
|
}
|
|
|
|
|
return this;
|
|
|
|
|
},
|
|
|
|
|
|
|
|
|
|
/**
|
2012-12-15 16:05:23 +00:00
|
|
|
* Returns complexity of an instance
|
2012-10-14 17:23:39 +00:00
|
|
|
* @method complexity
|
2012-12-15 16:05:23 +00:00
|
|
|
* @return {Number} complexity
|
2012-10-14 17:23:39 +00:00
|
|
|
*/
|
|
|
|
|
complexity: function() {
|
|
|
|
|
return 0;
|
|
|
|
|
},
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Returns a JSON representation of an instance
|
|
|
|
|
* @method toJSON
|
2012-12-01 12:57:27 +00:00
|
|
|
* @param {Array} propertiesToInclude
|
2012-10-14 17:23:39 +00:00
|
|
|
* @return {String} json
|
|
|
|
|
*/
|
2012-11-30 22:46:09 +00:00
|
|
|
toJSON: function(propertiesToInclude) {
|
2012-10-14 17:23:39 +00:00
|
|
|
// delegate, not alias
|
2012-11-30 22:46:09 +00:00
|
|
|
return this.toObject(propertiesToInclude);
|
2012-10-14 17:23:39 +00:00
|
|
|
},
|
|
|
|
|
|
|
|
|
|
/**
|
2012-12-15 16:05:23 +00:00
|
|
|
* Sets gradient fill of an object
|
2012-10-14 17:23:39 +00:00
|
|
|
* @method setGradientFill
|
|
|
|
|
*/
|
|
|
|
|
setGradientFill: function(options) {
|
|
|
|
|
this.set('fill', fabric.Gradient.forObject(this, options));
|
|
|
|
|
},
|
|
|
|
|
|
2013-01-20 16:30:34 +00:00
|
|
|
/**
|
|
|
|
|
* @private
|
|
|
|
|
* @method _initGradient
|
|
|
|
|
*/
|
|
|
|
|
_initGradient: function(options) {
|
|
|
|
|
if (options.fill && typeof options.fill === 'object' && !(options.fill instanceof fabric.Gradient)) {
|
|
|
|
|
this.set('fill', new fabric.Gradient(options.fill));
|
|
|
|
|
}
|
|
|
|
|
},
|
|
|
|
|
|
2012-10-14 17:23:39 +00:00
|
|
|
/**
|
2012-12-15 16:05:23 +00:00
|
|
|
* Animates object's properties
|
2012-10-14 17:23:39 +00:00
|
|
|
* @method animate
|
|
|
|
|
*
|
|
|
|
|
* As object — multiple properties
|
|
|
|
|
*
|
|
|
|
|
* object.animate({ left: ..., top: ... });
|
|
|
|
|
* object.animate({ left: ..., top: ... }, { duration: ... });
|
|
|
|
|
*
|
|
|
|
|
* As string — one property
|
|
|
|
|
*
|
|
|
|
|
* object.animate('left', ...);
|
|
|
|
|
* object.animate('left', { duration: ... });
|
|
|
|
|
*
|
|
|
|
|
*/
|
|
|
|
|
animate: function() {
|
|
|
|
|
if (arguments[0] && typeof arguments[0] === 'object') {
|
|
|
|
|
for (var prop in arguments[0]) {
|
|
|
|
|
this._animate(prop, arguments[0][prop], arguments[1]);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
else {
|
|
|
|
|
this._animate.apply(this, arguments);
|
|
|
|
|
}
|
|
|
|
|
return this;
|
|
|
|
|
},
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* @private
|
|
|
|
|
* @method _animate
|
|
|
|
|
*/
|
|
|
|
|
_animate: function(property, to, options) {
|
|
|
|
|
var obj = this;
|
|
|
|
|
|
2012-12-19 15:36:42 +00:00
|
|
|
to = to.toString();
|
2013-01-10 13:20:52 +00:00
|
|
|
|
|
|
|
|
if (!options) {
|
|
|
|
|
options = { };
|
|
|
|
|
}
|
|
|
|
|
else {
|
|
|
|
|
options = fabric.util.object.clone(options);
|
|
|
|
|
}
|
2012-10-14 17:23:39 +00:00
|
|
|
|
|
|
|
|
if (!('from' in options)) {
|
|
|
|
|
options.from = this.get(property);
|
|
|
|
|
}
|
|
|
|
|
|
2012-12-19 15:36:42 +00:00
|
|
|
if (~to.indexOf('=')) {
|
|
|
|
|
to = this.get(property) + parseFloat(to.replace('=', ''));
|
|
|
|
|
}
|
|
|
|
|
else {
|
|
|
|
|
to = parseFloat(to);
|
2012-10-14 17:23:39 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
fabric.util.animate({
|
|
|
|
|
startValue: options.from,
|
|
|
|
|
endValue: to,
|
|
|
|
|
byValue: options.by,
|
|
|
|
|
easing: options.easing,
|
|
|
|
|
duration: options.duration,
|
|
|
|
|
onChange: function(value) {
|
|
|
|
|
obj.set(property, value);
|
|
|
|
|
options.onChange && options.onChange();
|
|
|
|
|
},
|
|
|
|
|
onComplete: function() {
|
|
|
|
|
obj.setCoords();
|
|
|
|
|
options.onComplete && options.onComplete();
|
|
|
|
|
}
|
|
|
|
|
});
|
|
|
|
|
},
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Centers object horizontally on canvas to which it was added last
|
|
|
|
|
* @method centerH
|
|
|
|
|
* @return {fabric.Object} thisArg
|
|
|
|
|
*/
|
|
|
|
|
centerH: function () {
|
|
|
|
|
this.canvas.centerObjectH(this);
|
|
|
|
|
return this;
|
|
|
|
|
},
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Centers object vertically on canvas to which it was added last
|
|
|
|
|
* @method centerV
|
|
|
|
|
* @return {fabric.Object} thisArg
|
|
|
|
|
* @chainable
|
|
|
|
|
*/
|
|
|
|
|
centerV: function () {
|
|
|
|
|
this.canvas.centerObjectV(this);
|
|
|
|
|
return this;
|
|
|
|
|
},
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Centers object vertically and horizontally on canvas to which is was added last
|
|
|
|
|
* @method center
|
|
|
|
|
* @return {fabric.Object} thisArg
|
|
|
|
|
* @chainable
|
|
|
|
|
*/
|
|
|
|
|
center: function () {
|
|
|
|
|
return this.centerH().centerV();
|
|
|
|
|
},
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Removes object from canvas to which it was added last
|
|
|
|
|
* @method remove
|
|
|
|
|
* @return {fabric.Object} thisArg
|
|
|
|
|
* @chainable
|
|
|
|
|
*/
|
|
|
|
|
remove: function() {
|
|
|
|
|
return this.canvas.remove(this);
|
|
|
|
|
},
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Moves an object to the bottom of the stack of drawn objects
|
|
|
|
|
* @method sendToBack
|
|
|
|
|
* @return {fabric.Object} thisArg
|
|
|
|
|
* @chainable
|
|
|
|
|
*/
|
|
|
|
|
sendToBack: function() {
|
|
|
|
|
this.canvas.sendToBack(this);
|
|
|
|
|
return this;
|
|
|
|
|
},
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Moves an object to the top of the stack of drawn objects
|
|
|
|
|
* @method bringToFront
|
|
|
|
|
* @return {fabric.Object} thisArg
|
|
|
|
|
* @chainable
|
|
|
|
|
*/
|
|
|
|
|
bringToFront: function() {
|
|
|
|
|
this.canvas.bringToFront(this);
|
|
|
|
|
return this;
|
|
|
|
|
},
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Moves an object one level down in stack of drawn objects
|
|
|
|
|
* @method sendBackwards
|
|
|
|
|
* @return {fabric.Object} thisArg
|
|
|
|
|
* @chainable
|
|
|
|
|
*/
|
|
|
|
|
sendBackwards: function() {
|
|
|
|
|
this.canvas.sendBackwards(this);
|
|
|
|
|
return this;
|
|
|
|
|
},
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Moves an object one level up in stack of drawn objects
|
|
|
|
|
* @method bringForward
|
|
|
|
|
* @return {fabric.Object} thisArg
|
|
|
|
|
* @chainable
|
|
|
|
|
*/
|
|
|
|
|
bringForward: function() {
|
|
|
|
|
this.canvas.bringForward(this);
|
|
|
|
|
return this;
|
|
|
|
|
}
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
var proto = fabric.Object.prototype;
|
|
|
|
|
for (var i = proto.stateProperties.length; i--; ) {
|
|
|
|
|
|
|
|
|
|
var propName = proto.stateProperties[i],
|
|
|
|
|
capitalizedPropName = propName.charAt(0).toUpperCase() + propName.slice(1),
|
|
|
|
|
setterName = 'set' + capitalizedPropName,
|
|
|
|
|
getterName = 'get' + capitalizedPropName;
|
|
|
|
|
|
|
|
|
|
// using `new Function` for better introspection
|
|
|
|
|
if (!proto[getterName]) {
|
|
|
|
|
proto[getterName] = (function(property) {
|
|
|
|
|
return new Function('return this.get("' + property + '")');
|
|
|
|
|
})(propName);
|
|
|
|
|
}
|
|
|
|
|
if (!proto[setterName]) {
|
|
|
|
|
proto[setterName] = (function(property) {
|
|
|
|
|
return new Function('value', 'return this.set("' + property + '", value)');
|
|
|
|
|
})(propName);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2012-11-15 13:20:45 +00:00
|
|
|
/**
|
2012-12-02 10:53:38 +00:00
|
|
|
* Alias for {@link fabric.Object.prototype.setAngle}
|
2012-11-15 13:20:45 +00:00
|
|
|
* @alias rotate -> setAngle
|
|
|
|
|
*/
|
|
|
|
|
fabric.Object.prototype.rotate = fabric.Object.prototype.setAngle;
|
|
|
|
|
|
2012-10-14 17:23:39 +00:00
|
|
|
extend(fabric.Object.prototype, fabric.Observable);
|
|
|
|
|
|
2013-01-20 16:30:34 +00:00
|
|
|
/**
|
|
|
|
|
* @static
|
|
|
|
|
* @constant
|
|
|
|
|
* @type Number
|
|
|
|
|
*/
|
|
|
|
|
fabric.Object.NUM_FRACTION_DIGITS = 2;
|
2012-10-14 17:23:39 +00:00
|
|
|
|
|
|
|
|
})(typeof exports !== 'undefined' ? exports : this);
|