fabric.js/src/path_group.class.js

232 lines
5.9 KiB
JavaScript

(function(global) {
"use strict";
var fabric = global.fabric || (global.fabric = { }),
extend = fabric.util.object.extend,
invoke = fabric.util.array.invoke,
parentToObject = fabric.Object.prototype.toObject,
camelize = fabric.util.string.camelize,
capitalize = fabric.util.string.capitalize;
if (fabric.PathGroup) {
fabric.warn('fabric.PathGroup is already defined');
return;
}
/**
* Path group class
* @class fabric.PathGroup
* @extends fabric.Path
*/
fabric.PathGroup = fabric.util.createClass(fabric.Path, /** @lends fabric.PathGroup.prototype */ {
/**
* Type of an object
* @type String
*/
type: 'path-group',
/**
* Fill value
* @type String
*/
fill: '',
/**
* Constructor
* @param {Array} paths
* @param {Object} [options] Options object
* @return {fabric.PathGroup} thisArg
*/
initialize: function(paths, options) {
options = options || { };
this.paths = paths || [ ];
for (var i = this.paths.length; i--; ) {
this.paths[i].group = this;
}
this.setOptions(options);
this.setCoords();
if (options.sourcePath) {
this.setSourcePath(options.sourcePath);
}
},
/**
* Renders this group on a specified context
* @param {CanvasRenderingContext2D} ctx Context to render this instance on
*/
render: function(ctx) {
// do not render if object is not visible
if (!this.visible) return;
ctx.save();
var m = this.transformMatrix;
if (m) {
ctx.transform(m[0], m[1], m[2], m[3], m[4], m[5]);
}
this.transform(ctx);
this._setShadow(ctx);
this.clipTo && fabric.util.clipContext(this, ctx);
for (var i = 0, l = this.paths.length; i < l; ++i) {
this.paths[i].render(ctx, true);
}
this.clipTo && ctx.restore();
this._removeShadow(ctx);
if (this.active) {
this.drawBorders(ctx);
this.drawControls(ctx);
}
ctx.restore();
},
/**
* Sets certain property to a certain value
* @param {String} prop
* @param {Any} value
* @return {fabric.PathGroup} thisArg
*/
_set: function(prop, value) {
if ((prop === 'fill' || prop === 'overlayFill') && value && this.isSameColor()) {
var i = this.paths.length;
while (i--) {
this.paths[i]._set(prop, value);
}
}
return this.callSuper('_set', prop, value);
},
/**
* Returns object representation of this path group
* @param {Array} [propertiesToInclude]
* @return {Object} object representation of an instance
*/
toObject: function(propertiesToInclude) {
return extend(parentToObject.call(this, propertiesToInclude), {
paths: invoke(this.getObjects(), 'toObject', propertiesToInclude),
sourcePath: this.sourcePath
});
},
/**
* Returns dataless object representation of this path group
* @param {Array} [propertiesToInclude]
* @return {Object} dataless object representation of an instance
*/
toDatalessObject: function(propertiesToInclude) {
var o = this.toObject(propertiesToInclude);
if (this.sourcePath) {
o.paths = this.sourcePath;
}
return o;
},
/* _TO_SVG_START_ */
/**
* Returns svg representation of an instance
* @return {String} svg representation of an instance
*/
toSVG: function() {
var objects = this.getObjects();
var markup = [
'<g ',
'style="', this.getSvgStyles(), '" ',
'transform="', this.getSvgTransform(), '" ',
'>'
];
for (var i = 0, len = objects.length; i < len; i++) {
markup.push(objects[i].toSVG());
}
markup.push('</g>');
return markup.join('');
},
/* _TO_SVG_END_ */
/**
* Returns a string representation of this path group
* @return {String} string representation of an object
*/
toString: function() {
return '#<fabric.PathGroup (' + this.complexity() +
'): { top: ' + this.top + ', left: ' + this.left + ' }>';
},
/**
* Returns true if all paths in this group are of same color
* @return {Boolean} true if all paths are of the same color (`fill`)
*/
isSameColor: function() {
var firstPathFill = this.getObjects()[0].get('fill');
return this.getObjects().every(function(path) {
return path.get('fill') === firstPathFill;
});
},
/**
* Returns number representation of object's complexity
* @return {Number} complexity
*/
complexity: function() {
return this.paths.reduce(function(total, path) {
return total + ((path && path.complexity) ? path.complexity() : 0);
}, 0);
},
/**
* Makes path group grayscale
* @return {fabric.PathGroup} thisArg
*/
toGrayscale: function() {
var i = this.paths.length;
while (i--) {
this.paths[i].toGrayscale();
}
return this;
},
/**
* Returns all paths in this path group
* @return {Array} array of path objects included in this path group
*/
getObjects: function() {
return this.paths;
}
});
/**
* @private
*/
function instantiatePaths(paths) {
for (var i = 0, len = paths.length; i < len; i++) {
if (!(paths[i] instanceof fabric.Object)) {
var klassName = camelize(capitalize(paths[i].type));
paths[i] = fabric[klassName].fromObject(paths[i]);
}
}
return paths;
}
/**
* Creates fabric.PathGroup instance from an object representation
* @static
* @param {Object} object
* @return {fabric.PathGroup}
*/
fabric.PathGroup.fromObject = function(object) {
var paths = instantiatePaths(object.paths);
return new fabric.PathGroup(paths, object);
};
})(typeof exports !== 'undefined' ? exports : this);