//= require "path.class" (function(global) { "use strict"; var fabric = global.fabric || (global.fabric = { }), extend = fabric.util.object.extend, invoke = fabric.util.array.invoke, parentSet = fabric.Object.prototype.set, 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; } /** * @class PathGroup * @extends fabric.Path */ fabric.PathGroup = fabric.util.createClass(fabric.Path, /** @scope fabric.PathGroup.prototype */ { /** * @property * @type String */ type: 'path-group', /** * @property * @type Boolean */ forceFillOverwrite: false, /** * Constructor * @method initialize * @param {Array} paths * @param {Object} [options] Options object * @return {fabric.PathGroup} thisArg */ initialize: function(paths, options) { options = options || { }; this.paths = paths; this.setOptions(options); //this._initProperties(); this.setCoords(); if (options.sourcePath) { this.setSourcePath(options.sourcePath); } }, /** * @private * @method _initProperties */ // _initProperties: function() { // this.stateProperties.forEach(function(prop) { // if (prop === 'fill') { // this.set(prop, this.options[prop]); // } // else if (prop === 'angle') { // this.setAngle(this.options[prop]); // } // else { // this[prop] = this.options[prop]; // } // }, this); // }, /** * Renders this group on a specified context * @method render * @param {CanvasRenderingContext2D} ctx Context to render this instance on */ render: function(ctx) { if (this.stub) { // fast-path, rendering image stub ctx.save(); this.transform(ctx); this.stub.render(ctx, false /* no transform */); if (this.active) { this.drawBorders(ctx); this.drawCorners(ctx); } ctx.restore(); } else { 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); for (var i = 0, l = this.paths.length; i < l; ++i) { this.paths[i].render(ctx, true); } if (this.active) { this.drawBorders(ctx); this.hideCorners || this.drawCorners(ctx); } ctx.restore(); } }, /** * Sets certain property to a certain value * @method set * @param {String} prop * @param {Any} value * @return {fabric.PathGroup} thisArg */ set: function(prop, value) { if ((prop === 'fill' || prop === 'overlayFill') && this.isSameColor()) { this[prop] = value; var i = this.paths.length; while (i--) { this.paths[i].set(prop, value); } } else { // skipping parent "class" - fabric.Path parentSet.call(this, prop, value); } return this; }, /** * Returns object representation of this path group * @method toObject * @return {Object} object representation of an instance */ toObject: function() { return extend(parentToObject.call(this), { paths: invoke(this.getObjects(), 'clone'), sourcePath: this.sourcePath }); }, /** * Returns dataless object representation of this path group * @method toDatalessObject * @return {Object} dataless object representation of an instance */ toDatalessObject: function() { var o = this.toObject(); if (this.sourcePath) { o.paths = this.sourcePath; } return o; }, /** * Returns a string representation of this path group * @method toString * @return {String} string representation of an object */ toString: function() { return '#'; }, /** * Returns true if all paths in this group are of same color * @method isSameColor * @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 * @method 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 * @method toGrayscale * @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 * @method getObjects * @return {Array} array of path objects included in this path group */ getObjects: function() { return this.paths; } }); /** * @private * @method instantiatePaths */ 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.Triangle instance from an object representation * @static * @method fabric.PathGroup.fromObject * @param {Object} object * @return {fabric.PathGroup} */ fabric.PathGroup.fromObject = function(object) { var paths = instantiatePaths(object.paths); return new fabric.PathGroup(paths, object); }; })(this);