2010-10-22 02:54:00 +00:00
|
|
|
(function(global) {
|
2012-06-26 14:42:45 +00:00
|
|
|
|
2014-02-16 21:36:03 +00:00
|
|
|
'use strict';
|
2012-06-26 14:42:45 +00:00
|
|
|
|
2010-10-22 02:54:00 +00:00
|
|
|
var fabric = global.fabric || (global.fabric = { }),
|
2010-07-26 23:20:19 +00:00
|
|
|
extend = fabric.util.object.extend,
|
2010-07-27 18:07:59 +00:00
|
|
|
invoke = fabric.util.array.invoke,
|
2013-07-22 12:39:07 +00:00
|
|
|
parentToObject = fabric.Object.prototype.toObject;
|
2012-06-26 14:42:45 +00:00
|
|
|
|
2010-07-09 23:43:50 +00:00
|
|
|
if (fabric.PathGroup) {
|
2010-10-11 18:45:06 +00:00
|
|
|
fabric.warn('fabric.PathGroup is already defined');
|
2010-06-10 17:57:59 +00:00
|
|
|
return;
|
|
|
|
|
}
|
2012-06-26 14:42:45 +00:00
|
|
|
|
|
|
|
|
/**
|
2012-12-15 16:05:23 +00:00
|
|
|
* Path group class
|
2013-04-25 18:21:32 +00:00
|
|
|
* @class fabric.PathGroup
|
2010-10-14 21:42:39 +00:00
|
|
|
* @extends fabric.Path
|
2013-09-28 10:31:32 +00:00
|
|
|
* @tutorial {@link http://fabricjs.com/fabric-intro-part-1/#path_and_pathgroup}
|
2013-10-05 18:21:28 +00:00
|
|
|
* @see {@link fabric.PathGroup#initialize} for constructor definition
|
2010-10-14 21:42:39 +00:00
|
|
|
*/
|
2013-04-24 16:58:04 +00:00
|
|
|
fabric.PathGroup = fabric.util.createClass(fabric.Path, /** @lends fabric.PathGroup.prototype */ {
|
2012-06-26 14:42:45 +00:00
|
|
|
|
2010-10-15 02:16:24 +00:00
|
|
|
/**
|
2012-12-02 10:53:38 +00:00
|
|
|
* Type of an object
|
2010-10-15 02:16:24 +00:00
|
|
|
* @type String
|
2013-05-18 11:01:34 +00:00
|
|
|
* @default
|
2010-10-15 02:16:24 +00:00
|
|
|
*/
|
2010-06-09 22:34:55 +00:00
|
|
|
type: 'path-group',
|
2012-06-26 14:42:45 +00:00
|
|
|
|
2012-09-10 23:50:47 +00:00
|
|
|
/**
|
2012-12-15 16:05:23 +00:00
|
|
|
* Fill value
|
2012-09-10 23:50:47 +00:00
|
|
|
* @type String
|
2013-05-18 11:01:34 +00:00
|
|
|
* @default
|
2012-09-10 23:50:47 +00:00
|
|
|
*/
|
|
|
|
|
fill: '',
|
|
|
|
|
|
2010-10-14 21:42:39 +00:00
|
|
|
/**
|
|
|
|
|
* Constructor
|
|
|
|
|
* @param {Array} paths
|
|
|
|
|
* @param {Object} [options] Options object
|
|
|
|
|
* @return {fabric.PathGroup} thisArg
|
|
|
|
|
*/
|
2010-06-09 22:34:55 +00:00
|
|
|
initialize: function(paths, options) {
|
2012-06-26 14:42:45 +00:00
|
|
|
|
2010-06-09 22:34:55 +00:00
|
|
|
options = options || { };
|
2011-09-20 18:25:25 +00:00
|
|
|
this.paths = paths || [ ];
|
2012-06-26 14:42:45 +00:00
|
|
|
|
2011-07-09 15:10:40 +00:00
|
|
|
for (var i = this.paths.length; i--; ) {
|
|
|
|
|
this.paths[i].group = this;
|
|
|
|
|
}
|
2012-06-26 14:42:45 +00:00
|
|
|
|
2015-03-31 02:09:58 +00:00
|
|
|
if (options.toBeParsed) {
|
|
|
|
|
this.parseDimensionsFromPaths(options);
|
|
|
|
|
delete options.toBeParsed;
|
2014-04-10 17:57:24 +00:00
|
|
|
}
|
2015-03-31 02:09:58 +00:00
|
|
|
this.setOptions(options);
|
2010-06-09 22:34:55 +00:00
|
|
|
this.setCoords();
|
2012-06-26 14:42:45 +00:00
|
|
|
|
2010-06-09 22:34:55 +00:00
|
|
|
if (options.sourcePath) {
|
|
|
|
|
this.setSourcePath(options.sourcePath);
|
|
|
|
|
}
|
|
|
|
|
},
|
2012-06-26 14:42:45 +00:00
|
|
|
|
2015-03-31 02:09:58 +00:00
|
|
|
/**
|
|
|
|
|
* Calculate width and height based on paths contained
|
|
|
|
|
*/
|
|
|
|
|
parseDimensionsFromPaths: function(options) {
|
|
|
|
|
var points, i, p, xC = [ ], yC = [ ], path, height, width,
|
|
|
|
|
m = this.transformMatrix;
|
2015-04-06 10:24:32 +00:00
|
|
|
for (var j = this.paths.length; j--;) {
|
2015-03-31 02:09:58 +00:00
|
|
|
path = this.paths[j];
|
|
|
|
|
height = path.height + path.strokeWidth;
|
|
|
|
|
width = path.width + path.strokeWidth;
|
|
|
|
|
points = [
|
|
|
|
|
{ x: path.left, y: path.top },
|
|
|
|
|
{ x: path.left + width, y: path.top },
|
|
|
|
|
{ x: path.left, y: path.top + height },
|
|
|
|
|
{ x: path.left + width, y: path.top + height }
|
|
|
|
|
];
|
2015-04-06 10:24:32 +00:00
|
|
|
for (var i = 0; i < points.length; i++) {
|
2015-03-31 02:09:58 +00:00
|
|
|
p = points[i];
|
|
|
|
|
if (m) {
|
|
|
|
|
p = fabric.util.transformPoint(p, m, false);
|
|
|
|
|
}
|
|
|
|
|
xC.push(p.x);
|
|
|
|
|
yC.push(p.y);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
options.width = Math.max.apply(null, xC);
|
|
|
|
|
options.height = Math.max.apply(null, yC);
|
|
|
|
|
},
|
|
|
|
|
|
2010-10-19 20:27:24 +00:00
|
|
|
/**
|
|
|
|
|
* Renders this group on a specified context
|
|
|
|
|
* @param {CanvasRenderingContext2D} ctx Context to render this instance on
|
|
|
|
|
*/
|
2010-06-09 22:34:55 +00:00
|
|
|
render: function(ctx) {
|
2013-03-09 21:15:31 +00:00
|
|
|
// do not render if object is not visible
|
2014-08-03 14:47:27 +00:00
|
|
|
if (!this.visible) {
|
|
|
|
|
return;
|
|
|
|
|
}
|
2013-03-09 21:15:31 +00:00
|
|
|
|
2012-08-21 17:31:39 +00:00
|
|
|
ctx.save();
|
2012-06-26 14:42:45 +00:00
|
|
|
|
2012-08-21 17:31:39 +00:00
|
|
|
var m = this.transformMatrix;
|
2014-07-17 14:18:57 +00:00
|
|
|
|
2012-08-21 17:31:39 +00:00
|
|
|
if (m) {
|
|
|
|
|
ctx.transform(m[0], m[1], m[2], m[3], m[4], m[5]);
|
2010-06-09 22:34:55 +00:00
|
|
|
}
|
2012-08-21 17:31:39 +00:00
|
|
|
this.transform(ctx);
|
2013-02-04 19:47:02 +00:00
|
|
|
|
|
|
|
|
this._setShadow(ctx);
|
2013-03-10 20:06:17 +00:00
|
|
|
this.clipTo && fabric.util.clipContext(this, ctx);
|
2012-08-21 17:31:39 +00:00
|
|
|
for (var i = 0, l = this.paths.length; i < l; ++i) {
|
|
|
|
|
this.paths[i].render(ctx, true);
|
|
|
|
|
}
|
2013-03-10 20:06:17 +00:00
|
|
|
this.clipTo && ctx.restore();
|
2013-02-04 19:47:02 +00:00
|
|
|
this._removeShadow(ctx);
|
2013-10-31 17:36:18 +00:00
|
|
|
ctx.restore();
|
2010-06-09 22:34:55 +00:00
|
|
|
},
|
2012-06-26 14:42:45 +00:00
|
|
|
|
2010-06-09 22:34:55 +00:00
|
|
|
/**
|
2010-10-19 20:27:24 +00:00
|
|
|
* Sets certain property to a certain value
|
2010-06-09 22:34:55 +00:00
|
|
|
* @param {String} prop
|
|
|
|
|
* @param {Any} value
|
2010-07-09 23:43:50 +00:00
|
|
|
* @return {fabric.PathGroup} thisArg
|
2010-06-09 22:34:55 +00:00
|
|
|
*/
|
2012-09-10 23:46:22 +00:00
|
|
|
_set: function(prop, value) {
|
|
|
|
|
|
2013-09-28 21:46:14 +00:00
|
|
|
if (prop === 'fill' && value && this.isSameColor()) {
|
2010-06-09 22:34:55 +00:00
|
|
|
var i = this.paths.length;
|
|
|
|
|
while (i--) {
|
2012-09-10 23:46:22 +00:00
|
|
|
this.paths[i]._set(prop, value);
|
2010-06-09 22:34:55 +00:00
|
|
|
}
|
|
|
|
|
}
|
2012-09-10 23:46:22 +00:00
|
|
|
|
|
|
|
|
return this.callSuper('_set', prop, value);
|
2010-06-09 22:34:55 +00:00
|
|
|
},
|
2012-06-26 14:42:45 +00:00
|
|
|
|
2010-06-09 22:34:55 +00:00
|
|
|
/**
|
2010-10-19 20:27:24 +00:00
|
|
|
* Returns object representation of this path group
|
2013-09-29 07:56:29 +00:00
|
|
|
* @param {Array} [propertiesToInclude] Any properties that you might want to additionally include in the output
|
2010-06-09 22:34:55 +00:00
|
|
|
* @return {Object} object representation of an instance
|
|
|
|
|
*/
|
2012-11-30 22:46:09 +00:00
|
|
|
toObject: function(propertiesToInclude) {
|
2013-09-29 07:56:29 +00:00
|
|
|
var o = extend(parentToObject.call(this, propertiesToInclude), {
|
|
|
|
|
paths: invoke(this.getObjects(), 'toObject', propertiesToInclude)
|
2010-06-09 22:34:55 +00:00
|
|
|
});
|
2013-09-29 07:56:29 +00:00
|
|
|
if (this.sourcePath) {
|
|
|
|
|
o.sourcePath = this.sourcePath;
|
|
|
|
|
}
|
|
|
|
|
return o;
|
2010-06-09 22:34:55 +00:00
|
|
|
},
|
2012-06-26 14:42:45 +00:00
|
|
|
|
2010-06-09 22:34:55 +00:00
|
|
|
/**
|
2010-10-19 20:27:24 +00:00
|
|
|
* Returns dataless object representation of this path group
|
2013-09-29 07:56:29 +00:00
|
|
|
* @param {Array} [propertiesToInclude] Any properties that you might want to additionally include in the output
|
2010-06-09 22:34:55 +00:00
|
|
|
* @return {Object} dataless object representation of an instance
|
|
|
|
|
*/
|
2012-12-01 12:57:27 +00:00
|
|
|
toDatalessObject: function(propertiesToInclude) {
|
|
|
|
|
var o = this.toObject(propertiesToInclude);
|
2010-06-09 22:34:55 +00:00
|
|
|
if (this.sourcePath) {
|
|
|
|
|
o.paths = this.sourcePath;
|
|
|
|
|
}
|
|
|
|
|
return o;
|
|
|
|
|
},
|
2012-06-26 14:42:45 +00:00
|
|
|
|
2013-05-09 18:19:06 +00:00
|
|
|
/* _TO_SVG_START_ */
|
2012-01-02 21:14:20 +00:00
|
|
|
/**
|
|
|
|
|
* Returns svg representation of an instance
|
2013-09-29 07:22:44 +00:00
|
|
|
* @param {Function} [reviver] Method for further parsing of svg representation.
|
2012-12-15 16:05:23 +00:00
|
|
|
* @return {String} svg representation of an instance
|
2012-01-02 21:14:20 +00:00
|
|
|
*/
|
2013-09-29 07:22:44 +00:00
|
|
|
toSVG: function(reviver) {
|
2014-02-16 21:36:03 +00:00
|
|
|
var objects = this.getObjects(),
|
2015-03-01 18:21:10 +00:00
|
|
|
p = this.getPointByOrigin('left', 'top'),
|
|
|
|
|
translatePart = 'translate(' + p.x + ' ' + p.y + ')',
|
2014-02-16 21:36:03 +00:00
|
|
|
markup = [
|
2014-08-03 14:47:27 +00:00
|
|
|
//jscs:disable validateIndentation
|
2014-02-16 21:36:03 +00:00
|
|
|
'<g ',
|
|
|
|
|
'style="', this.getSvgStyles(), '" ',
|
2015-01-28 08:13:52 +00:00
|
|
|
'transform="', this.getSvgTransformMatrix(), translatePart, this.getSvgTransform(), '" ',
|
2014-08-05 10:54:08 +00:00
|
|
|
'>\n'
|
2014-08-03 14:47:27 +00:00
|
|
|
//jscs:enable validateIndentation
|
2014-02-16 21:36:03 +00:00
|
|
|
];
|
2012-01-02 21:14:20 +00:00
|
|
|
|
|
|
|
|
for (var i = 0, len = objects.length; i < len; i++) {
|
2013-09-29 07:22:44 +00:00
|
|
|
markup.push(objects[i].toSVG(reviver));
|
2012-01-02 21:14:20 +00:00
|
|
|
}
|
2014-08-05 10:54:08 +00:00
|
|
|
markup.push('</g>\n');
|
2012-01-02 21:14:20 +00:00
|
|
|
|
2013-09-29 07:22:44 +00:00
|
|
|
return reviver ? reviver(markup.join('')) : markup.join('');
|
2012-01-02 21:14:20 +00:00
|
|
|
},
|
2013-05-09 18:19:06 +00:00
|
|
|
/* _TO_SVG_END_ */
|
2012-06-26 14:42:45 +00:00
|
|
|
|
2012-12-15 16:05:23 +00:00
|
|
|
/**
|
|
|
|
|
* Returns a string representation of this path group
|
|
|
|
|
* @return {String} string representation of an object
|
|
|
|
|
*/
|
2010-06-09 22:34:55 +00:00
|
|
|
toString: function() {
|
2012-06-26 14:42:45 +00:00
|
|
|
return '#<fabric.PathGroup (' + this.complexity() +
|
2010-06-09 22:34:55 +00:00
|
|
|
'): { top: ' + this.top + ', left: ' + this.left + ' }>';
|
|
|
|
|
},
|
2012-06-26 14:42:45 +00:00
|
|
|
|
2010-06-09 22:34:55 +00:00
|
|
|
/**
|
2010-10-19 20:27:24 +00:00
|
|
|
* Returns true if all paths in this group are of same color
|
2010-06-09 22:34:55 +00:00
|
|
|
* @return {Boolean} true if all paths are of the same color (`fill`)
|
|
|
|
|
*/
|
|
|
|
|
isSameColor: function() {
|
2014-04-14 16:17:06 +00:00
|
|
|
var firstPathFill = (this.getObjects()[0].get('fill') || '').toLowerCase();
|
2010-07-09 14:21:40 +00:00
|
|
|
return this.getObjects().every(function(path) {
|
2014-04-14 16:17:06 +00:00
|
|
|
return (path.get('fill') || '').toLowerCase() === firstPathFill;
|
2010-06-09 22:34:55 +00:00
|
|
|
});
|
|
|
|
|
},
|
2012-06-26 14:42:45 +00:00
|
|
|
|
2010-06-09 22:34:55 +00:00
|
|
|
/**
|
2012-12-15 16:05:23 +00:00
|
|
|
* Returns number representation of object's complexity
|
|
|
|
|
* @return {Number} complexity
|
|
|
|
|
*/
|
2010-06-09 22:34:55 +00:00
|
|
|
complexity: function() {
|
2010-06-17 14:00:47 +00:00
|
|
|
return this.paths.reduce(function(total, path) {
|
2010-06-09 22:34:55 +00:00
|
|
|
return total + ((path && path.complexity) ? path.complexity() : 0);
|
2010-06-17 14:00:47 +00:00
|
|
|
}, 0);
|
2010-06-09 22:34:55 +00:00
|
|
|
},
|
2012-06-26 14:42:45 +00:00
|
|
|
|
2010-06-09 22:34:55 +00:00
|
|
|
/**
|
2010-10-19 20:27:24 +00:00
|
|
|
* Returns all paths in this path group
|
2010-06-09 22:34:55 +00:00
|
|
|
* @return {Array} array of path objects included in this path group
|
|
|
|
|
*/
|
|
|
|
|
getObjects: function() {
|
|
|
|
|
return this.paths;
|
|
|
|
|
}
|
|
|
|
|
});
|
2012-06-26 14:42:45 +00:00
|
|
|
|
2010-06-09 22:34:55 +00:00
|
|
|
/**
|
2012-10-16 23:18:54 +00:00
|
|
|
* Creates fabric.PathGroup instance from an object representation
|
2010-06-09 22:34:55 +00:00
|
|
|
* @static
|
2013-08-08 16:31:26 +00:00
|
|
|
* @memberOf fabric.PathGroup
|
2013-09-29 07:56:29 +00:00
|
|
|
* @param {Object} object Object to create an instance from
|
2013-07-18 20:21:19 +00:00
|
|
|
* @param {Function} callback Callback to invoke when an fabric.PathGroup instance is created
|
2010-06-09 22:34:55 +00:00
|
|
|
*/
|
2013-07-12 20:38:21 +00:00
|
|
|
fabric.PathGroup.fromObject = function(object, callback) {
|
|
|
|
|
if (typeof object.paths === 'string') {
|
|
|
|
|
fabric.loadSVGFromURL(object.paths, function (elements) {
|
2013-07-13 16:56:41 +00:00
|
|
|
|
|
|
|
|
var pathUrl = object.paths;
|
2013-07-12 20:38:21 +00:00
|
|
|
delete object.paths;
|
2013-07-13 16:56:41 +00:00
|
|
|
|
|
|
|
|
var pathGroup = fabric.util.groupSVGElements(elements, object, pathUrl);
|
|
|
|
|
|
2013-07-12 20:38:21 +00:00
|
|
|
callback(pathGroup);
|
|
|
|
|
});
|
|
|
|
|
}
|
|
|
|
|
else {
|
2013-07-18 20:21:19 +00:00
|
|
|
fabric.util.enlivenObjects(object.paths, function(enlivenedObjects) {
|
|
|
|
|
delete object.paths;
|
|
|
|
|
callback(new fabric.PathGroup(enlivenedObjects, object));
|
|
|
|
|
});
|
2013-07-12 20:38:21 +00:00
|
|
|
}
|
2010-07-29 17:50:09 +00:00
|
|
|
};
|
2011-08-05 23:00:26 +00:00
|
|
|
|
2013-07-12 20:38:21 +00:00
|
|
|
/**
|
|
|
|
|
* Indicates that instances of this type are async
|
|
|
|
|
* @static
|
2013-08-08 16:31:26 +00:00
|
|
|
* @memberOf fabric.PathGroup
|
2013-07-12 20:38:21 +00:00
|
|
|
* @type Boolean
|
2013-08-08 16:31:26 +00:00
|
|
|
* @default
|
2013-07-12 20:38:21 +00:00
|
|
|
*/
|
|
|
|
|
fabric.PathGroup.async = true;
|
|
|
|
|
|
2013-04-24 16:58:04 +00:00
|
|
|
})(typeof exports !== 'undefined' ? exports : this);
|