You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@openmeetings.apache.org by so...@apache.org on 2018/09/29 15:44:52 UTC
[openmeetings] branch master updated: [OPENMEETINGS-1928] fabricjs
is updated
This is an automated email from the ASF dual-hosted git repository.
solomax pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/openmeetings.git
The following commit(s) were added to refs/heads/master by this push:
new 957fa79 [OPENMEETINGS-1928] fabricjs is updated
957fa79 is described below
commit 957fa79b0d41c8e2f8ee97e03eb810bb8f455f60
Author: Maxim Solodovnik <so...@gmail.com>
AuthorDate: Sat Sep 29 22:40:33 2018 +0700
[OPENMEETINGS-1928] fabricjs is updated
---
.../org/apache/openmeetings/web/room/wb/fabric.js | 708 ++++++++++++++-------
1 file changed, 465 insertions(+), 243 deletions(-)
diff --git a/openmeetings-web/src/main/java/org/apache/openmeetings/web/room/wb/fabric.js b/openmeetings-web/src/main/java/org/apache/openmeetings/web/room/wb/fabric.js
index aef061d..d514e65 100644
--- a/openmeetings-web/src/main/java/org/apache/openmeetings/web/room/wb/fabric.js
+++ b/openmeetings-web/src/main/java/org/apache/openmeetings/web/room/wb/fabric.js
@@ -2,7 +2,7 @@
/* build: `node build.js modules=ALL exclude=gestures,accessors requirejs minifier=uglifyjs` */
/*! Fabric.js Copyright 2008-2015, Printio (Juriy Zaytsev, Maxim Chernyak) */
-var fabric = fabric || { version: '2.3.4' };
+var fabric = fabric || { version: '2.4.0' };
if (typeof exports !== 'undefined') {
exports.fabric = fabric;
}
@@ -49,15 +49,15 @@ fabric.isLikelyNode = typeof Buffer !== 'undefined' &&
* @type array
*/
fabric.SHARED_ATTRIBUTES = [
- "display",
- "transform",
- "fill", "fill-opacity", "fill-rule",
- "opacity",
- "stroke", "stroke-dasharray", "stroke-linecap",
- "stroke-linejoin", "stroke-miterlimit",
- "stroke-opacity", "stroke-width",
- "id", "paint-order",
- "instantiated_by_use"
+ 'display',
+ 'transform',
+ 'fill', 'fill-opacity', 'fill-rule',
+ 'opacity',
+ 'stroke', 'stroke-dasharray', 'stroke-linecap',
+ 'stroke-linejoin', 'stroke-miterlimit',
+ 'stroke-opacity', 'stroke-width',
+ 'id', 'paint-order',
+ 'instantiated_by_use', 'clip-path'
];
/* _FROM_SVG_END_ */
@@ -353,7 +353,7 @@ fabric.Collection = {
* @chainable
*/
insertAt: function (object, index, nonSplicing) {
- var objects = this.getObjects();
+ var objects = this._objects;
if (nonSplicing) {
objects[index] = object;
}
@@ -372,7 +372,7 @@ fabric.Collection = {
* @chainable
*/
remove: function() {
- var objects = this.getObjects(),
+ var objects = this._objects,
index, somethingRemoved = false;
for (var i = 0, length = arguments.length; i < length; i++) {
@@ -413,12 +413,13 @@ fabric.Collection = {
/**
* Returns an array of children objects of this instance
* Type parameter introduced in 1.3.10
+ * since 2.3.5 this method return always a COPY of the array;
* @param {String} [type] When specified, only objects of this type are returned
* @return {Array}
*/
getObjects: function(type) {
if (typeof type === 'undefined') {
- return this._objects;
+ return this._objects.concat();
}
return this._objects.filter(function(o) {
return o.type === type;
@@ -431,7 +432,7 @@ fabric.Collection = {
* @return {Self} thisArg
*/
item: function (index) {
- return this.getObjects()[index];
+ return this._objects[index];
},
/**
@@ -439,7 +440,7 @@ fabric.Collection = {
* @return {Boolean} true if collection is empty
*/
isEmpty: function () {
- return this.getObjects().length === 0;
+ return this._objects.length === 0;
},
/**
@@ -447,7 +448,7 @@ fabric.Collection = {
* @return {Number} Collection size
*/
size: function() {
- return this.getObjects().length;
+ return this._objects.length;
},
/**
@@ -456,7 +457,7 @@ fabric.Collection = {
* @return {Boolean} `true` if collection contains an object
*/
contains: function(object) {
- return this.getObjects().indexOf(object) > -1;
+ return this._objects.indexOf(object) > -1;
},
/**
@@ -464,7 +465,7 @@ fabric.Collection = {
* @return {Number} complexity
*/
complexity: function () {
- return this.getObjects().reduce(function (memo, current) {
+ return this._objects.reduce(function (memo, current) {
memo += current.complexity ? current.complexity() : 0;
return memo;
}, 0);
@@ -1172,6 +1173,20 @@ fabric.CommonMethods = {
},
/**
+ * Creates a canvas element that is a copy of another and is also painted
+ * @static
+ * @memberOf fabric.util
+ * @return {CanvasElement} initialized canvas element
+ */
+ copyCanvasElement: function(canvas) {
+ var newCanvas = fabric.document.createElement('canvas');
+ newCanvas.width = canvas.width;
+ newCanvas.height = canvas.height;
+ newCanvas.getContext('2d').drawImage(canvas, 0, 0);
+ return newCanvas;
+ },
+
+ /**
* Creates image element (works on client and node)
* @static
* @memberOf fabric.util
@@ -3360,10 +3375,10 @@ if (typeof console !== 'undefined') {
multiplyTransformMatrices = fabric.util.multiplyTransformMatrices,
svgValidTagNames = ['path', 'circle', 'polygon', 'polyline', 'ellipse', 'rect', 'line',
- 'image', 'text', 'linearGradient', 'radialGradient', 'stop'],
+ 'image', 'text'],
svgViewBoxElements = ['symbol', 'image', 'marker', 'pattern', 'view', 'svg'],
svgInvalidAncestors = ['pattern', 'defs', 'symbol', 'metadata', 'clipPath', 'mask', 'desc'],
- svgValidParents = ['symbol', 'g', 'a', 'svg'],
+ svgValidParents = ['symbol', 'g', 'a', 'svg', 'clipPath', 'defs'],
attributesMap = {
cx: 'left',
@@ -3390,7 +3405,9 @@ if (typeof console !== 'undefined') {
'stroke-width': 'strokeWidth',
'text-decoration': 'textDecoration',
'text-anchor': 'textAnchor',
- opacity: 'opacity'
+ opacity: 'opacity',
+ 'clip-path': 'clipPath',
+ 'clip-rule': 'clipRule',
},
colorAttributes = {
@@ -3405,6 +3422,7 @@ if (typeof console !== 'undefined') {
fabric.cssRules = { };
fabric.gradientDefs = { };
+ fabric.clipPaths = { };
function normalizeAttr(attr) {
// transform attribute names
@@ -3809,7 +3827,7 @@ if (typeof console !== 'undefined') {
while (nodelist.length && i < nodelist.length) {
var el = nodelist[i],
- xlink = el.getAttribute('xlink:href').substr(1),
+ xlink = (el.getAttribute('xlink:href') || el.getAttribute('href')).substr(1),
x = el.getAttribute('x') || 0,
y = el.getAttribute('y') || 0,
el2 = elementById(doc, xlink).cloneNode(true),
@@ -3832,7 +3850,8 @@ if (typeof console !== 'undefined') {
for (j = 0, attrs = el.attributes, len = attrs.length; j < len; j++) {
attr = attrs.item(j);
- if (attr.nodeName === 'x' || attr.nodeName === 'y' || attr.nodeName === 'xlink:href') {
+ if (attr.nodeName === 'x' || attr.nodeName === 'y' ||
+ attr.nodeName === 'xlink:href' || attr.nodeName === 'href') {
continue;
}
@@ -3961,7 +3980,7 @@ if (typeof console !== 'undefined') {
scaleY + ' ' +
(minX * scaleX + widthDiff) + ' ' +
(minY * scaleY + heightDiff) + ') ';
-
+ parsedDim.viewboxTransform = fabric.parseTransformAttribute(matrix);
if (element.nodeName === 'svg') {
el = element.ownerDocument.createElement('g');
// element.firstChild != null
@@ -3974,7 +3993,6 @@ if (typeof console !== 'undefined') {
el = element;
matrix = el.getAttribute('transform') + matrix;
}
-
el.setAttribute('transform', matrix);
return parsedDim;
}
@@ -4035,13 +4053,24 @@ if (typeof console !== 'undefined') {
callback && callback([], {});
return;
}
-
+ var clipPaths = { };
+ descendants.filter(function(el) {
+ return el.nodeName.replace('svg:', '') === 'clipPath';
+ }).forEach(function(el) {
+ clipPaths[el.id] = fabric.util.toArray(el.getElementsByTagName('*')).filter(function(el) {
+ return fabric.svgValidTagNamesRegEx.test(el.nodeName.replace('svg:', ''));
+ });
+ });
fabric.gradientDefs[svgUid] = fabric.getGradientDefs(doc);
fabric.cssRules[svgUid] = fabric.getCSSRules(doc);
+ fabric.clipPaths[svgUid] = clipPaths;
// Precedence of rules: style > class > attribute
fabric.parseElements(elements, function(instances, elements) {
if (callback) {
callback(instances, options, elements, descendants);
+ delete fabric.gradientDefs[svgUid];
+ delete fabric.cssRules[svgUid];
+ delete fabric.clipPaths[svgUid];
}
}, clone(options), reviver, parsingOptions);
};
@@ -4394,82 +4423,130 @@ fabric.ElementsParser = function(elements, callback, options, reviver, parsingOp
this.regexUrl = /^url\(['"]?#([^'"]+)['"]?\)/g;
};
-fabric.ElementsParser.prototype.parse = function() {
- this.instances = new Array(this.elements.length);
- this.numElements = this.elements.length;
+(function(proto) {
+ proto.parse = function() {
+ this.instances = new Array(this.elements.length);
+ this.numElements = this.elements.length;
+ this.createObjects();
+ };
- this.createObjects();
-};
+ proto.createObjects = function() {
+ var _this = this;
+ this.elements.forEach(function(element, i) {
+ element.setAttribute('svgUid', _this.svgUid);
+ _this.createObject(element, i);
+ });
+ };
-fabric.ElementsParser.prototype.createObjects = function() {
- for (var i = 0, len = this.elements.length; i < len; i++) {
- this.elements[i].setAttribute('svgUid', this.svgUid);
- (function(_obj, i) {
- setTimeout(function() {
- _obj.createObject(_obj.elements[i], i);
- }, 0);
- })(this, i);
- }
-};
+ proto.findTag = function(el) {
+ return fabric[fabric.util.string.capitalize(el.tagName.replace('svg:', ''))];
+ };
-fabric.ElementsParser.prototype.createObject = function(el, index) {
- var klass = fabric[fabric.util.string.capitalize(el.tagName.replace('svg:', ''))];
- if (klass && klass.fromElement) {
- try {
- this._createObject(klass, el, index);
+ proto.createObject = function(el, index) {
+ var klass = this.findTag(el);
+ if (klass && klass.fromElement) {
+ try {
+ klass.fromElement(el, this.createCallback(index, el), this.options);
+ }
+ catch (err) {
+ fabric.log(err);
+ }
}
- catch (err) {
- fabric.log(err);
+ else {
+ this.checkIfDone();
}
- }
- else {
- this.checkIfDone();
- }
-};
+ };
-fabric.ElementsParser.prototype._createObject = function(klass, el, index) {
- klass.fromElement(el, this.createCallback(index, el), this.options);
-};
+ proto.createCallback = function(index, el) {
+ var _this = this;
+ return function(obj) {
+ var _options;
+ _this.resolveGradient(obj, 'fill');
+ _this.resolveGradient(obj, 'stroke');
+ if (obj instanceof fabric.Image) {
+ _options = obj.parsePreserveAspectRatioAttribute(el);
+ }
+ obj._removeTransformMatrix(_options);
+ _this.resolveClipPath(obj);
+ _this.reviver && _this.reviver(el, obj);
+ _this.instances[index] = obj;
+ _this.checkIfDone();
+ };
+ };
-fabric.ElementsParser.prototype.createCallback = function(index, el) {
- var _this = this;
- return function(obj) {
- var _options;
- _this.resolveGradient(obj, 'fill');
- _this.resolveGradient(obj, 'stroke');
- if (obj instanceof fabric.Image) {
- _options = obj.parsePreserveAspectRatioAttribute(el);
- }
- obj._removeTransformMatrix(_options);
- _this.reviver && _this.reviver(el, obj);
- _this.instances[index] = obj;
- _this.checkIfDone();
+ proto.extractPropertyDefinition = function(obj, property, storage) {
+ var value = obj[property];
+ if (!(/^url\(/).test(value)) {
+ return;
+ }
+ var id = this.regexUrl.exec(value)[1];
+ this.regexUrl.lastIndex = 0;
+ return fabric[storage][this.svgUid][id];
};
-};
-fabric.ElementsParser.prototype.resolveGradient = function(obj, property) {
+ proto.resolveGradient = function(obj, property) {
+ var gradientDef = this.extractPropertyDefinition(obj, property, 'gradientDefs');
+ if (gradientDef) {
+ obj.set(property, fabric.Gradient.fromElement(gradientDef, obj));
+ }
+ };
- var instanceFillValue = obj[property];
- if (!(/^url\(/).test(instanceFillValue)) {
- return;
- }
- var gradientId = this.regexUrl.exec(instanceFillValue)[1];
- this.regexUrl.lastIndex = 0;
- if (fabric.gradientDefs[this.svgUid][gradientId]) {
- obj.set(property,
- fabric.Gradient.fromElement(fabric.gradientDefs[this.svgUid][gradientId], obj));
- }
-};
+ proto.createClipPathCallback = function(obj, container) {
+ return function(_newObj) {
+ _newObj._removeTransformMatrix();
+ _newObj.fillRule = _newObj.clipRule;
+ container.push(_newObj);
+ };
+ };
-fabric.ElementsParser.prototype.checkIfDone = function() {
- if (--this.numElements === 0) {
- this.instances = this.instances.filter(function(el) {
- // eslint-disable-next-line no-eq-null, eqeqeq
- return el != null;
- });
- this.callback(this.instances, this.elements);
- }
-};
+ proto.resolveClipPath = function(obj) {
+ var clipPath = this.extractPropertyDefinition(obj, 'clipPath', 'clipPaths'),
+ element, klass, objTransformInv, container, gTransform, options;
+ if (clipPath) {
+ container = [];
+ objTransformInv = fabric.util.invertTransform(obj.calcTransformMatrix());
+ for (var i = 0; i < clipPath.length; i++) {
+ element = clipPath[i];
+ klass = this.findTag(element);
+ klass.fromElement(
+ element,
+ this.createClipPathCallback(obj, container),
+ this.options
+ );
+ }
+ if (container.length === 1) {
+ clipPath = container[0];
+ }
+ else {
+ clipPath = new fabric.Group(container);
+ }
+ gTransform = fabric.util.multiplyTransformMatrices(
+ objTransformInv,
+ clipPath.calcTransformMatrix()
+ );
+ var options = fabric.util.qrDecompose(gTransform);
+ clipPath.flipX = false;
+ clipPath.flipY = false;
+ clipPath.set('scaleX', options.scaleX);
+ clipPath.set('scaleY', options.scaleY);
+ clipPath.angle = options.angle;
+ clipPath.skewX = options.skewX;
+ clipPath.skewY = 0;
+ clipPath.setPositionByOrigin({ x: options.translateX, y: options.translateY }, 'center', 'center');
+ obj.clipPath = clipPath;
+ }
+ };
+
+ proto.checkIfDone = function() {
+ if (--this.numElements === 0) {
+ this.instances = this.instances.filter(function(el) {
+ // eslint-disable-next-line no-eq-null, eqeqeq
+ return el != null;
+ });
+ this.callback(this.instances, this.elements);
+ }
+ };
+})(fabric.ElementsParser.prototype);
(function(global) {
@@ -6207,9 +6284,16 @@ fabric.ElementsParser.prototype.checkIfDone = function() {
patternImgSrc = '';
if (this.repeat === 'repeat-x' || this.repeat === 'no-repeat') {
patternHeight = 1;
+ if (patternOffsetY) {
+ patternHeight += Math.abs(patternOffsetY);
+ }
}
if (this.repeat === 'repeat-y' || this.repeat === 'no-repeat') {
patternWidth = 1;
+ if (patternOffsetX) {
+ patternWidth += Math.abs(patternOffsetX);
+ }
+
}
if (patternSource.src) {
patternImgSrc = patternSource.src;
@@ -6567,7 +6651,10 @@ fabric.ElementsParser.prototype.checkIfDone = function() {
/**
* Function that determines clipping of entire canvas area
- * Being passed context as first argument. See clipping canvas area in {@link https://github.com/kangax/fabric.js/wiki/FAQ}
+ * Being passed context as first argument.
+ * If you are using code minification, ctx argument can be minified/manglied you should use
+ * as a workaround `var ctx = arguments[0];` in the function;
+ * See clipping canvas area in {@link https://github.com/kangax/fabric.js/wiki/FAQ}
* @deprecated since 2.0.0
* @type Function
* @default
@@ -6658,6 +6745,15 @@ fabric.ElementsParser.prototype.checkIfDone = function() {
skipOffscreen: true,
/**
+ * a fabricObject that, without stroke define a clipping area with their shape. filled in black
+ * the clipPath object gets used when the canvas has rendered, and the context is placed in the
+ * top left corner of the canvas.
+ * clipPath will clip away controls, if you do not want this to happen use controlsAboveOverlay = true
+ * @type fabric.Object
+ */
+ clipPath: undefined,
+
+ /**
* @private
* @param {HTMLElement | String} el <canvas> element to initialize instance on
* @param {Object} [options] Options object
@@ -7293,6 +7389,10 @@ fabric.ElementsParser.prototype.checkIfDone = function() {
/**
* Function created to be instance bound at initialization
* used in requestAnimationFrame rendering
+ * Let the fabricJS call it. If you call it manually you could have more
+ * animationFrame stacking on to of each other
+ * for an imperative rendering, use canvas.renderAll
+ * @private
* @return {fabric.Canvas} instance
* @chainable
*/
@@ -7303,6 +7403,7 @@ fabric.ElementsParser.prototype.checkIfDone = function() {
/**
* Append a renderAll request to next animation frame.
+ * unless one is already in progress, in that case nothing is done
* a boolean flag will avoid appending more.
* @return {fabric.Canvas} instance
* @chainable
@@ -7332,6 +7433,13 @@ fabric.ElementsParser.prototype.checkIfDone = function() {
return points;
},
+ cancelRequestedRender: function() {
+ if (this.isRendering) {
+ fabric.util.cancelAnimFrame(this.isRendering);
+ this.isRendering = 0;
+ }
+ },
+
/**
* Renders background, objects, overlay and controls.
* @param {CanvasRenderingContext2D} ctx
@@ -7340,14 +7448,11 @@ fabric.ElementsParser.prototype.checkIfDone = function() {
* @chainable
*/
renderCanvas: function(ctx, objects) {
- var v = this.viewportTransform;
- if (this.isRendering) {
- fabric.util.cancelAnimFrame(this.isRendering);
- this.isRendering = 0;
- }
+ var v = this.viewportTransform, path = this.clipPath;
+ this.cancelRequestedRender();
this.calcViewportBoundaries();
this.clearContext(ctx);
- this.fire('before:render');
+ this.fire('before:render', { ctx: ctx, });
if (this.clipTo) {
fabric.util.clipContext(this, ctx);
}
@@ -7364,11 +7469,38 @@ fabric.ElementsParser.prototype.checkIfDone = function() {
if (this.clipTo) {
ctx.restore();
}
+ if (path) {
+ if (path.isCacheDirty()) {
+ // needed to setup a couple of variables
+ path.shouldCache();
+ path.canvas = this;
+ path._transformDone = true;
+ path.renderCache({ forClipping: true });
+ }
+ this.drawClipPathOnCanvas(ctx);
+ }
this._renderOverlay(ctx);
if (this.controlsAboveOverlay && this.interactive) {
this.drawControls(ctx);
}
- this.fire('after:render');
+ this.fire('after:render', { ctx: ctx, });
+ },
+
+ /**
+ * Paint the cached clipPath on the lowerCanvasEl
+ * @param {CanvasRenderingContext2D} ctx Context to render on
+ */
+ drawClipPathOnCanvas: function(ctx) {
+ var v = this.viewportTransform, path = this.clipPath;
+ ctx.save();
+ ctx.transform(v[0], v[1], v[2], v[3], v[4], v[5]);
+ // DEBUG: uncomment this line, comment the following
+ // ctx.globalAlpha = 0.4
+ ctx.globalCompositeOperation = 'destination-in';
+ path.transform(ctx);
+ ctx.scale(1 / path.zoomX, 1 / path.zoomY);
+ ctx.drawImage(path._cacheCanvas, -path.cacheTranslationX, -path.cacheTranslationY);
+ ctx.restore();
},
/**
@@ -7565,11 +7697,13 @@ fabric.ElementsParser.prototype.checkIfDone = function() {
*/
_toObjectMethod: function (methodName, propertiesToInclude) {
- var data = {
+ var clipPath = this.clipPath, data = {
version: fabric.version,
- objects: this._toObjects(methodName, propertiesToInclude)
+ objects: this._toObjects(methodName, propertiesToInclude),
};
-
+ if (clipPath) {
+ clipPath = clipPath.toObject(propertiesToInclude);
+ }
extend(data, this.__serializeBgOverlay(methodName, propertiesToInclude));
fabric.util.populateWithProperties(this, data, propertiesToInclude);
@@ -7581,7 +7715,7 @@ fabric.ElementsParser.prototype.checkIfDone = function() {
* @private
*/
_toObjects: function(methodName, propertiesToInclude) {
- return this.getObjects().filter(function(object) {
+ return this._objects.filter(function(object) {
return !object.excludeFromExport;
}).map(function(instance) {
return this._toObject(instance, methodName, propertiesToInclude);
@@ -7783,7 +7917,7 @@ fabric.ElementsParser.prototype.checkIfDone = function() {
createSVGFontFacesMarkup: function() {
var markup = '', fontList = { }, obj, fontFamily,
style, row, rowIndex, _char, charIndex, i, len,
- fontPaths = fabric.fontPaths, objects = this.getObjects();
+ fontPaths = fabric.fontPaths, objects = this._objects;
for (i = 0, len = objects.length; i < len; i++) {
obj = objects[i];
@@ -7834,7 +7968,7 @@ fabric.ElementsParser.prototype.checkIfDone = function() {
* @private
*/
_setSVGObjects: function(markup, reviver) {
- var instance, i, len, objects = this.getObjects();
+ var instance, i, len, objects = this._objects;
for (i = 0, len = objects.length; i < len; i++) {
instance = objects[i];
if (instance.excludeFromExport) {
@@ -8149,7 +8283,7 @@ fabric.ElementsParser.prototype.checkIfDone = function() {
*/
toString: function () {
return '#<fabric.Canvas (' + this.complexity() + '): ' +
- '{ objects: ' + this.getObjects().length + ' }>';
+ '{ objects: ' + this._objects.length + ' }>';
}
});
@@ -8729,7 +8863,7 @@ fabric.CircleBrush = fabric.util.createClass(fabric.BaseBrush, /** @lends fabric
circles.push(circle);
}
- var group = new fabric.Group(circles, { originX: 'center', originY: 'center' });
+ var group = new fabric.Group(circles);
group.canvas = this.canvas;
this.canvas.add(group);
@@ -8876,7 +9010,7 @@ fabric.SprayBrush = fabric.util.createClass( fabric.BaseBrush, /** @lends fabric
rects = this._getOptimizedRects(rects);
}
- var group = new fabric.Group(rects, { originX: 'center', originY: 'center' });
+ var group = new fabric.Group(rects);
this.shadow && group.setShadow(this.shadow);
this.canvas.add(group);
this.canvas.fire('path:created', { path: group });
@@ -11813,7 +11947,7 @@ fabric.PatternBrush = fabric.util.createClass(fabric.PencilBrush, /** @lends fab
* @param {Object} target
*/
_createGroup: function(target) {
- var objects = this.getObjects(),
+ var objects = this._objects,
isActiveLower = objects.indexOf(this._activeObject) < objects.indexOf(target),
groupObjects = isActiveLower
? [this._activeObject, target]
@@ -12685,7 +12819,9 @@ fabric.util.object.extend(fabric.StaticCanvas.prototype, /** @lends fabric.Stati
includeDefaultValues: true,
/**
- * Function that determines clipping of an object (context is passed as a first argument)
+ * Function that determines clipping of an object (context is passed as a first argument).
+ * If you are using code minification, ctx argument can be minified/manglied you should use
+ * as a workaround `var ctx = arguments[0];` in the function;
* Note that context origin is at the object's center point (not left/top corner)
* @deprecated since 2.0.0
* @type Function
@@ -12846,6 +12982,36 @@ fabric.util.object.extend(fabric.StaticCanvas.prototype, /** @lends fabric.Stati
).split(' '),
/**
+ * a fabricObject that, without stroke define a clipping area with their shape. filled in black
+ * the clipPath object gets used when the object has rendered, and the context is placed in the center
+ * of the object cacheCanvas.
+ * If you want 0,0 of a clipPath to align with an object center, use clipPath.originX/Y to 'center'
+ * @type fabric.Object
+ */
+ clipPath: undefined,
+
+ /**
+ * Meaningfull ONLY when the object is used as clipPath.
+ * if true, the clipPath will make the object clip to the outside of the clipPath
+ * since 2.4.0
+ * @type boolean
+ * @default false
+ */
+ inverted: false,
+
+ /**
+ * Meaningfull ONLY when the object is used as clipPath.
+ * if true, the clipPath will have its top and left relative to canvas, and will
+ * not be influenced by the object transform. This will make the clipPath relative
+ * to the canvas, but clipping just a particular object.
+ * WARNING this is beta, this feature may change or be renamed.
+ * since 2.4.0
+ * @type boolean
+ * @default false
+ */
+ absolutePositioned: false,
+
+ /**
* Constructor
* @param {Object} [options] Options object
*/
@@ -12917,8 +13083,8 @@ fabric.util.object.extend(fabric.StaticCanvas.prototype, /** @lends fabric.Stati
* Return the dimension and the zoom level needed to create a cache canvas
* big enough to host the object to be cached.
* @private
- * @param {Object} dim.x width of object to be cached
- * @param {Object} dim.y height of object to be cached
+ * @return {Object}.x width of object to be cached
+ * @return {Object}.y height of object to be cached
* @return {Object}.width width of canvas
* @return {Object}.height height of canvas
* @return {Object}.zoomX zoomX zoom value to unscale the canvas before drawing cache
@@ -12950,9 +13116,10 @@ fabric.util.object.extend(fabric.StaticCanvas.prototype, /** @lends fabric.Stati
* @return {Boolean} true if the canvas has been resized
*/
_updateCacheCanvas: function() {
- if (this.noScaleCache && this.canvas && this.canvas._currentTransform) {
- var target = this.canvas._currentTransform.target,
- action = this.canvas._currentTransform.action;
+ var targetCanvas = this.canvas;
+ if (this.noScaleCache && targetCanvas && targetCanvas._currentTransform) {
+ var target = targetCanvas._currentTransform.target,
+ action = targetCanvas._currentTransform.action;
if (this === target && action.slice && action.slice(0, 5) === 'scale') {
return false;
}
@@ -13069,9 +13236,15 @@ fabric.util.object.extend(fabric.StaticCanvas.prototype, /** @lends fabric.Stati
globalCompositeOperation: this.globalCompositeOperation,
transformMatrix: this.transformMatrix ? this.transformMatrix.concat() : null,
skewX: toFixed(this.skewX, NUM_FRACTION_DIGITS),
- skewY: toFixed(this.skewY, NUM_FRACTION_DIGITS)
+ skewY: toFixed(this.skewY, NUM_FRACTION_DIGITS),
};
+ if (this.clipPath) {
+ object.clipPath = this.clipPath.toObject(propertiesToInclude);
+ object.clipPath.inverted = this.clipPath.inverted;
+ object.clipPath.absolutePositioned = this.clipPath.absolutePositioned;
+ }
+
fabric.util.populateWithProperties(this, object, propertiesToInclude);
if (!this.includeDefaultValues) {
object = this._removeDefaultValues(object);
@@ -13262,15 +13435,7 @@ fabric.util.object.extend(fabric.StaticCanvas.prototype, /** @lends fabric.Stati
}
this.clipTo && fabric.util.clipContext(this, ctx);
if (this.shouldCache()) {
- if (!this._cacheCanvas) {
- this._createCacheCanvas();
-
- }
- if (this.isCacheDirty()) {
- this.statefullCache && this.saveState({ propertySet: 'cacheProperties' });
- this.drawObject(this._cacheContext);
- this.dirty = false;
- }
+ this.renderCache();
this.drawCacheOnCanvas(ctx);
}
else {
@@ -13285,6 +13450,18 @@ fabric.util.object.extend(fabric.StaticCanvas.prototype, /** @lends fabric.Stati
ctx.restore();
},
+ renderCache: function(options) {
+ options = options || {};
+ if (!this._cacheCanvas) {
+ this._createCacheCanvas();
+ }
+ if (this.isCacheDirty(false)) {
+ this.statefullCache && this.saveState({ propertySet: 'cacheProperties' });
+ this.drawObject(this._cacheContext, options.forClipping);
+ this.dirty = false;
+ }
+ },
+
/**
* Remove cacheCanvas and its dimensions from the objects
*/
@@ -13306,6 +13483,9 @@ fabric.util.object.extend(fabric.StaticCanvas.prototype, /** @lends fabric.Stati
if (this.paintFirst === 'stroke' && typeof this.shadow === 'object') {
return true;
}
+ if (this.clipPath) {
+ return true;
+ }
return false;
},
@@ -13333,14 +13513,60 @@ fabric.util.object.extend(fabric.StaticCanvas.prototype, /** @lends fabric.Stati
},
/**
+ * Execute the drawing operation for an object clipPath
+ * @param {CanvasRenderingContext2D} ctx Context to render on
+ */
+ drawClipPathOnCache: function(ctx) {
+ var path = this.clipPath;
+ ctx.save();
+ // DEBUG: uncomment this line, comment the following
+ // ctx.globalAlpha = 0.4
+ if (path.inverted) {
+ ctx.globalCompositeOperation = 'destination-out';
+ }
+ else {
+ ctx.globalCompositeOperation = 'destination-in';
+ }
+ //ctx.scale(1 / 2, 1 / 2);
+ if (path.absolutePositioned) {
+ var m = fabric.util.invertTransform(this.calcTransformMatrix());
+ ctx.transform(m[0], m[1], m[2], m[3], m[4], m[5]);
+ }
+ path.transform(ctx);
+ ctx.scale(1 / path.zoomX, 1 / path.zoomY);
+ ctx.drawImage(path._cacheCanvas, -path.cacheTranslationX, -path.cacheTranslationY);
+ ctx.restore();
+ },
+
+ /**
* Execute the drawing operation for an object on a specified context
* @param {CanvasRenderingContext2D} ctx Context to render on
*/
- drawObject: function(ctx) {
- this._renderBackground(ctx);
- this._setStrokeStyles(ctx, this);
- this._setFillStyles(ctx, this);
+ drawObject: function(ctx, forClipping) {
+
+ if (forClipping) {
+ this._setClippingProperties(ctx);
+ }
+ else {
+ this._renderBackground(ctx);
+ this._setStrokeStyles(ctx, this);
+ this._setFillStyles(ctx, this);
+ }
this._render(ctx);
+ this._drawClipPath(ctx);
+ },
+
+ _drawClipPath: function(ctx) {
+ var path = this.clipPath;
+ if (!path) { return; }
+ // needed to setup a couple of variables
+ // path canvas gets overridden with this one.
+ // TODO find a better solution?
+ path.canvas = this.canvas;
+ path.shouldCache();
+ path._transformDone = true;
+ path.renderCache({ forClipping: true });
+ this.drawClipPathOnCache(ctx);
},
/**
@@ -13366,7 +13592,10 @@ fabric.util.object.extend(fabric.StaticCanvas.prototype, /** @lends fabric.Stati
return true;
}
else {
- if (this.dirty || (this.statefullCache && this.hasStateChanged('cacheProperties'))) {
+ if (this.dirty ||
+ (this.clipPath && this.clipPath.absolutePositioned) ||
+ (this.statefullCache && this.hasStateChanged('cacheProperties'))
+ ) {
if (this._cacheCanvas && !skipCanvas) {
var width = this.cacheWidth / this.zoomX;
var height = this.cacheHeight / this.zoomY;
@@ -13434,6 +13663,12 @@ fabric.util.object.extend(fabric.StaticCanvas.prototype, /** @lends fabric.Stati
}
},
+ _setClippingProperties: function(ctx) {
+ ctx.globalAlpha = 1;
+ ctx.strokeStyle = 'transparent';
+ ctx.fillStyle = '#000000';
+ },
+
/**
* @private
* Sets line dash
@@ -14045,8 +14280,11 @@ fabric.util.object.extend(fabric.StaticCanvas.prototype, /** @lends fabric.Stati
if (typeof patterns[1] !== 'undefined') {
object.stroke = patterns[1];
}
- var instance = extraParam ? new klass(object[extraParam], object) : new klass(object);
- callback && callback(instance);
+ fabric.util.enlivenObjects([object.clipPath], function(enlivedProps) {
+ object.clipPath = enlivedProps[0];
+ var instance = extraParam ? new klass(object[extraParam], object) : new klass(object);
+ callback && callback(instance);
+ });
});
};
@@ -15157,8 +15395,11 @@ fabric.util.object.extend(fabric.Object.prototype, /** @lends fabric.Object.prot
* Returns id attribute for svg output
* @return {String}
*/
- getSvgId: function() {
- return this.id ? 'id="' + this.id + '" ' : '';
+ getSvgCommons: function() {
+ return [
+ this.id ? 'id="' + this.id + '" ' : '',
+ this.clipPath ? 'clip-path="url(#' + this.clipPath.clipPathId + ')" ' : '',
+ ].join('');
},
/**
@@ -15234,7 +15475,7 @@ fabric.util.object.extend(fabric.Object.prototype, /** @lends fabric.Object.prot
* @private
*/
_createBaseSVGMarkup: function() {
- var markup = [];
+ var markup = [], clipPath = this.clipPath;
if (this.fill && this.fill.toLive) {
markup.push(this.fill.toSVG(this, false));
@@ -15245,6 +15486,14 @@ fabric.util.object.extend(fabric.Object.prototype, /** @lends fabric.Object.prot
if (this.shadow) {
markup.push(this.shadow.toSVG(this));
}
+ if (clipPath) {
+ clipPath.clipPathId = 'CLIPPATH_' + fabric.Object.__uid++;
+ markup.push(
+ '<clipPath id="' + clipPath.clipPathId + '" >\n\t',
+ this.clipPath.toSVG(),
+ '</clipPath>\n'
+ );
+ }
return markup;
},
@@ -16261,7 +16510,7 @@ fabric.util.object.extend(fabric.Object.prototype, /** @lends fabric.Object.prot
var markup = this._createBaseSVGMarkup(),
p = this.calcLinePoints();
markup.push(
- '<line ', this.getSvgId(),
+ '<line ', this.getSvgCommons(),
'x1="', p.x1,
'" y1="', p.y1,
'" x2="', p.x2,
@@ -16443,7 +16692,7 @@ fabric.util.object.extend(fabric.Object.prototype, /** @lends fabric.Object.prot
if (angle === 0) {
markup.push(
- '<circle ', this.getSvgId(),
+ '<circle ', this.getSvgCommons(),
'cx="' + x + '" cy="' + y + '" ',
'r="', this.radius,
'" style="', this.getSvgStyles(),
@@ -16661,7 +16910,7 @@ fabric.util.object.extend(fabric.Object.prototype, /** @lends fabric.Object.prot
.join(',');
markup.push(
- '<polygon ', this.getSvgId(),
+ '<polygon ', this.getSvgCommons(),
'points="', points,
'" style="', this.getSvgStyles(),
'" transform="', this.getSvgTransform(), '"',
@@ -16801,7 +17050,7 @@ fabric.util.object.extend(fabric.Object.prototype, /** @lends fabric.Object.prot
toSVG: function(reviver) {
var markup = this._createBaseSVGMarkup();
markup.push(
- '<ellipse ', this.getSvgId(),
+ '<ellipse ', this.getSvgCommons(),
'cx="0" cy="0" ',
'rx="', this.rx,
'" ry="', this.ry,
@@ -17030,7 +17279,7 @@ fabric.util.object.extend(fabric.Object.prototype, /** @lends fabric.Object.prot
toSVG: function(reviver) {
var markup = this._createBaseSVGMarkup(), x = -this.width / 2, y = -this.height / 2;
markup.push(
- '<rect ', this.getSvgId(),
+ '<rect ', this.getSvgCommons(),
'x="', x, '" y="', y,
'" rx="', this.get('rx'), '" ry="', this.get('ry'),
'" width="', this.width, '" height="', this.height,
@@ -17226,7 +17475,7 @@ fabric.util.object.extend(fabric.Object.prototype, /** @lends fabric.Object.prot
);
}
markup.push(
- '<', this.type, ' ', this.getSvgId(),
+ '<', this.type, ' ', this.getSvgCommons(),
'points="', points.join(''),
'" style="', this.getSvgStyles(),
'" transform="', this.getSvgTransform(),
@@ -17917,7 +18166,7 @@ fabric.util.object.extend(fabric.Object.prototype, /** @lends fabric.Object.prot
var path = chunks.join(' ');
addTransform = ' translate(' + (-this.pathOffset.x) + ', ' + (-this.pathOffset.y) + ') ';
markup.push(
- '<path ', this.getSvgId(),
+ '<path ', this.getSvgCommons(),
'd="', path,
'" style="', this.getSvgStyles(),
'" transform="', this.getSvgTransform(), addTransform,
@@ -18365,7 +18614,6 @@ fabric.util.object.extend(fabric.Object.prototype, /** @lends fabric.Object.prot
'use strict';
var fabric = global.fabric || (global.fabric = { }),
- extend = fabric.util.object.extend,
min = fabric.util.array.min,
max = fabric.util.array.max;
@@ -18441,6 +18689,16 @@ fabric.util.object.extend(fabric.Object.prototype, /** @lends fabric.Object.prot
if (!isAlreadyGrouped) {
var center = options && options.centerPoint;
+ // we want to set origins before calculating the bounding box.
+ // so that the topleft can be set with that in mind.
+ // if specific top and left are passed, are overwritten later
+ // with the callSuper('initialize', options)
+ if (options.originX !== undefined) {
+ this.originX = options.originX;
+ }
+ if (options.originY !== undefined) {
+ this.originY = options.originY;
+ }
// if coming from svg i do not want to calc bounds.
// i assume width and height are passed along options
center || this._calcBounds();
@@ -18570,12 +18828,11 @@ fabric.util.object.extend(fabric.Object.prototype, /** @lends fabric.Object.prot
}
}
if (key === 'canvas') {
- i = this._objects.length;
while (i--) {
this._objects[i]._set(key, value);
}
}
- this.callSuper('_set', key, value);
+ fabric.Object.prototype._set.call(this, key, value);
},
/**
@@ -18584,16 +18841,16 @@ fabric.util.object.extend(fabric.Object.prototype, /** @lends fabric.Object.prot
* @return {Object} object representation of an instance
*/
toObject: function(propertiesToInclude) {
- var objsToObject = this.getObjects().map(function(obj) {
+ var objsToObject = this._objects.map(function(obj) {
var originalDefaults = obj.includeDefaultValues;
obj.includeDefaultValues = obj.group.includeDefaultValues;
var _obj = obj.toObject(propertiesToInclude);
obj.includeDefaultValues = originalDefaults;
return _obj;
});
- return extend(this.callSuper('toObject', propertiesToInclude), {
- objects: objsToObject
- });
+ var obj = fabric.Object.prototype.toObject.call(this, propertiesToInclude);
+ obj.objects = objsToObject;
+ return obj;
},
/**
@@ -18607,7 +18864,7 @@ fabric.util.object.extend(fabric.Object.prototype, /** @lends fabric.Object.prot
objsToObject = sourcePath;
}
else {
- objsToObject = this.getObjects().map(function(obj) {
+ objsToObject = this._objects.map(function(obj) {
var originalDefaults = obj.includeDefaultValues;
obj.includeDefaultValues = obj.group.includeDefaultValues;
var _obj = obj.toDatalessObject(propertiesToInclude);
@@ -18615,9 +18872,9 @@ fabric.util.object.extend(fabric.Object.prototype, /** @lends fabric.Object.prot
return _obj;
});
}
- return extend(this.callSuper('toDatalessObject', propertiesToInclude), {
- objects: objsToObject
- });
+ var obj = fabric.Object.prototype.toDatalessObject.call(this, propertiesToInclude);
+ obj.objects = objsToObject;
+ return obj;
},
/**
@@ -18658,7 +18915,7 @@ fabric.util.object.extend(fabric.Object.prototype, /** @lends fabric.Object.prot
*/
willDrawShadow: function() {
if (this.shadow) {
- return this.callSuper('willDrawShadow');
+ return fabric.Object.prototype.willDrawShadow.call(this);
}
for (var i = 0, len = this._objects.length; i < len; i++) {
if (this._objects[i].willDrawShadow()) {
@@ -18684,13 +18941,14 @@ fabric.util.object.extend(fabric.Object.prototype, /** @lends fabric.Object.prot
for (var i = 0, len = this._objects.length; i < len; i++) {
this._objects[i].render(ctx);
}
+ this._drawClipPath(ctx);
},
/**
* Check if cache is dirty
*/
- isCacheDirty: function() {
- if (this.callSuper('isCacheDirty')) {
+ isCacheDirty: function(skipCanvas) {
+ if (this.callSuper('isCacheDirty', skipCanvas)) {
return true;
}
if (!this.statefullCache) {
@@ -18859,6 +19117,8 @@ fabric.util.object.extend(fabric.Object.prototype, /** @lends fabric.Object.prot
this.width = width;
this.height = height;
if (!onlyWidthHeight) {
+ // the bounding box always finds the topleft most corner.
+ // whatever is the group origin, we set up here the left/top position.
this.setPositionByOrigin({ x: left, y: top }, 'left', 'top');
}
},
@@ -18872,7 +19132,7 @@ fabric.util.object.extend(fabric.Object.prototype, /** @lends fabric.Object.prot
toSVG: function(reviver) {
var markup = this._createBaseSVGMarkup();
markup.push(
- '<g ', this.getSvgId(), 'transform="',
+ '<g ', this.getSvgCommons(), 'transform="',
/* avoiding styles intentionally */
this.getSvgTransform(),
this.getSvgTransformMatrix(),
@@ -18969,16 +19229,15 @@ fabric.util.object.extend(fabric.Object.prototype, /** @lends fabric.Object.prot
* @return {fabric.Group}
*/
toGroup: function() {
- var objects = this._objects;
+ var objects = this._objects.concat();
this._objects = [];
- var options = this.toObject();
+ var options = fabric.Object.prototype.toObject.call(this);
var newGroup = new fabric.Group([]);
- delete options.objects;
+ delete options.type;
newGroup.set(options);
- newGroup.type = 'group';
objects.forEach(function(object) {
- object.group = newGroup;
object.canvas.remove(object);
+ object.group = newGroup;
});
newGroup._objects = objects;
if (!this.canvas) {
@@ -19010,24 +19269,6 @@ fabric.util.object.extend(fabric.Object.prototype, /** @lends fabric.Object.prot
},
/**
- * @private
- */
- _set: function(key, value) {
- var i = this._objects.length;
- if (key === 'canvas') {
- while (i--) {
- this._objects[i].set(key, value);
- }
- }
- if (this.useSetOnGroup) {
- while (i--) {
- this._objects[i].setOnGroup(key, value);
- }
- }
- fabric.Object.prototype._set.call(this, key, value);
- },
-
- /**
* Decide if the object should cache or not. Create its own cache level
* objectCaching is a global flag, wins over everything
* needsItsOwnCache should be used when the object drawing method requires
@@ -19040,22 +19281,6 @@ fabric.util.object.extend(fabric.Object.prototype, /** @lends fabric.Object.prot
},
/**
- * Check if this object or a child object will cast a shadow
- * @return {Boolean}
- */
- willDrawShadow: function() {
- if (this.shadow) {
- return this.callSuper('willDrawShadow');
- }
- for (var i = 0, len = this._objects.length; i < len; i++) {
- if (this._objects[i].willDrawShadow()) {
- return true;
- }
- }
- return false;
- },
-
- /**
* Check if this group or its parent group are caching, recursively up
* @return {Boolean}
*/
@@ -19199,15 +19424,6 @@ fabric.util.object.extend(fabric.Object.prototype, /** @lends fabric.Object.prot
stateProperties: fabric.Object.prototype.stateProperties.concat('cropX', 'cropY'),
/**
- * When `true`, object is cached on an additional canvas.
- * default to false for images
- * since 1.7.0
- * @type Boolean
- * @default
- */
- objectCaching: false,
-
- /**
* key used to retrieve the texture representing this image
* since 2.0.0
* @type String
@@ -19251,7 +19467,7 @@ fabric.util.object.extend(fabric.Object.prototype, /** @lends fabric.Object.prot
* @return {HTMLImageElement} Image element
*/
getElement: function() {
- return this._element;
+ return this._element || {};
},
/**
@@ -19264,11 +19480,8 @@ fabric.util.object.extend(fabric.Object.prototype, /** @lends fabric.Object.prot
* @chainable
*/
setElement: function(element, options) {
- var backend = fabric.filterBackend;
- if (backend && backend.evictCachesForKey) {
- backend.evictCachesForKey(this.cacheKey);
- backend.evictCachesForKey(this.cacheKey + '_filtered');
- }
+ this.removeTexture(this.cacheKey);
+ this.removeTexture(this.cacheKey + '_filtered');
this._element = element;
this._originalElement = element;
this._initConfig(options);
@@ -19282,15 +19495,21 @@ fabric.util.object.extend(fabric.Object.prototype, /** @lends fabric.Object.prot
},
/**
- * Delete cacheKey if we have a webGlBackend
- * delete reference to image elements
+ * Delete a single texture if in webgl mode
*/
- dispose: function() {
+ removeTexture: function(key) {
var backend = fabric.filterBackend;
if (backend && backend.evictCachesForKey) {
- backend.evictCachesForKey(this.cacheKey);
- backend.evictCachesForKey(this.cacheKey + '_filtered');
+ backend.evictCachesForKey(key);
}
+ },
+
+ /**
+ * Delete textures, reference to elements and eventually JSDOM cleanup
+ */
+ dispose: function() {
+ this.removeTexture(this.cacheKey);
+ this.removeTexture(this.cacheKey + '_filtered');
this._cacheContext = undefined;
['_originalElement', '_element', '_filteredEl', '_cacheCanvas'].forEach((function(element) {
fabric.util.cleanUpJsdomNode(this[element]);
@@ -19317,8 +19536,8 @@ fabric.util.object.extend(fabric.Object.prototype, /** @lends fabric.Object.prot
getOriginalSize: function() {
var element = this.getElement();
return {
- width: element.width,
- height: element.height
+ width: element.naturalWidth || element.width,
+ height: element.naturalHeight || element.height
};
},
@@ -19415,7 +19634,7 @@ fabric.util.object.extend(fabric.Object.prototype, /** @lends fabric.Object.prot
clipPath = ' clip-path="url(#imageCrop_' + clipPathId + ')" ';
}
markup.push('<g transform="', this.getSvgTransform(), this.getSvgTransformMatrix(), '">\n');
- var imageMarkup = ['\t<image ', this.getSvgId(), 'xlink:href="', this.getSvgSrc(true),
+ var imageMarkup = ['\t<image ', this.getSvgCommons(), 'xlink:href="', this.getSvgSrc(true),
'" x="', x - this.cropX, '" y="', y - this.cropY,
'" style="', this.getSvgStyles(),
// we're essentially moving origin of transformation from top/left corner to the center of the shape
@@ -19514,7 +19733,7 @@ fabric.util.object.extend(fabric.Object.prototype, /** @lends fabric.Object.prot
fabric.filterBackend = fabric.initFilterBackend();
}
var canvasEl = fabric.util.createCanvasElement(),
- cacheKey = this._filteredEl ? this.cacheKey : (this.cacheKey + '_filtered'),
+ cacheKey = this._filteredEl ? (this.cacheKey + '_filtered') : this.cacheKey,
sourceWidth = elementToFilter.width, sourceHeight = elementToFilter.height;
canvasEl.width = sourceWidth;
canvasEl.height = sourceHeight;
@@ -19539,9 +19758,11 @@ fabric.util.object.extend(fabric.Object.prototype, /** @lends fabric.Object.prot
filters = filters || this.filters || [];
filters = filters.filter(function(filter) { return filter && !filter.isNeutralState(); });
- if (this.group) {
- this.set('dirty', true);
- }
+ this.set('dirty', true);
+
+ // needs to clear out or WEBGL will not resize correctly
+ this.removeTexture(this.cacheKey + '_filtered');
+
if (filters.length === 0) {
this._element = this._originalElement;
this._filteredEl = null;
@@ -19564,7 +19785,12 @@ fabric.util.object.extend(fabric.Object.prototype, /** @lends fabric.Object.prot
}
else {
// clear the existing element to get new filter data
- this._element.getContext('2d').clearRect(0, 0, sourceWidth, sourceHeight);
+ // also dereference the eventual resized _element
+ this._element = this._filteredEl;
+ this._filteredEl.getContext('2d').clearRect(0, 0, sourceWidth, sourceHeight);
+ // we also need to resize again at next renderAll, so remove saved _lastScaleX/Y
+ this._lastScaleX = 1;
+ this._lastScaleY = 1;
}
if (!fabric.filterBackend) {
fabric.filterBackend = fabric.initFilterBackend();
@@ -19614,10 +19840,7 @@ fabric.util.object.extend(fabric.Object.prototype, /** @lends fabric.Object.prot
* @private
*/
_resetWidthHeight: function() {
- var element = this.getElement();
-
- this.set('width', element.width);
- this.set('height', element.height);
+ this.set(this.getOriginalSize());
},
/**
@@ -19663,20 +19886,15 @@ fabric.util.object.extend(fabric.Object.prototype, /** @lends fabric.Object.prot
/**
* @private
+ * Set the width and the height of the image object, using the element or the
+ * options.
* @param {Object} [options] Object with width/height properties
*/
_setWidthHeight: function(options) {
- this.width = options && ('width' in options)
- ? options.width
- : (this.getElement()
- ? this.getElement().width || 0
- : 0);
-
- this.height = options && ('height' in options)
- ? options.height
- : (this.getElement()
- ? this.getElement().height || 0
- : 0);
+ options || (options = { });
+ var el = this.getElement();
+ this.width = options.width || el.naturalWidth || el.width || 0;
+ this.height = options.height || el.naturalHeight || el.height || 0;
},
/**
@@ -20419,6 +20637,7 @@ function copyGLTo2DPutImageData(gl, pipelineState) {
* @tutorial {@link http://fabricjs.com/fabric-intro-part-2#image_filters}
* @see {@link http://fabricjs.com/image-filters|ImageFilters demo}
*/
+fabric.Image = fabric.Image || { };
fabric.Image.filters = fabric.Image.filters || { };
/**
@@ -27289,13 +27508,15 @@ fabric.util.object.extend(fabric.IText.prototype, /** @lends fabric.IText.protot
*/
mouseUpHandler: function(options) {
this.__isMousedown = false;
- if (!this.editable ||
+ if (!this.editable || this.group ||
(options.transform && options.transform.actionPerformed) ||
(options.e.button && options.e.button !== 1)) {
return;
}
if (this.__lastSelected && !this.__corner) {
+ this.selected = false;
+ this.__lastSelected = false;
this.enterEditing(options.e);
if (this.selectionStart === this.selectionEnd) {
this.initDelayedCursor(true);
@@ -27304,7 +27525,9 @@ fabric.util.object.extend(fabric.IText.prototype, /** @lends fabric.IText.protot
this.renderCursorOrSelection();
}
}
- this.selected = true;
+ else {
+ this.selected = true;
+ }
},
/**
@@ -28085,7 +28308,7 @@ fabric.util.object.extend(fabric.IText.prototype, /** @lends fabric.IText.protot
style = filter === '' ? '' : ' style="' + filter + '"',
textDecoration = this.getSvgTextDecoration(this);
markup.push(
- '\t<g ', this.getSvgId(), 'transform="', this.getSvgTransform(), this.getSvgTransformMatrix(), '"',
+ '\t<g ', this.getSvgCommons(), 'transform="', this.getSvgTransform(), this.getSvgTransformMatrix(), '"',
style, '>\n',
textAndBg.textBgRects.join(''),
'\t\t<text xml:space="preserve" ',
@@ -28748,4 +28971,3 @@ fabric.util.object.extend(fabric.IText.prototype, /** @lends fabric.IText.protot
});
})();
-