Update to 2.4.0 (#5254)

* build240

* added small changelog
This commit is contained in:
Andrea Bogazzi 2018-09-22 13:02:52 +02:00 committed by GitHub
parent 5138496163
commit 90a4df78e7
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
5 changed files with 367 additions and 147 deletions

View file

@ -1,3 +1,6 @@
**Version 2.4.0**
- Add: Add clipPath support to canvas and svg import/export. Low compatibility yet.
**Version 2.3.6**
- Fix: Make image.class aware of naturalWidth and naturalHeight. [#5178](https://github.com/fabricjs/fabric.js/pull/5178)
- Fix: Make 2 finger events works again [#5177](https://github.com/fabricjs/fabric.js/pull/5177)

View file

@ -1,6 +1,6 @@
/*! Fabric.js Copyright 2008-2015, Printio (Juriy Zaytsev, Maxim Chernyak) */
var fabric = fabric || { version: '2.3.6' };
var fabric = fabric || { version: '2.4.0' };
if (typeof exports !== 'undefined') {
exports.fabric = fabric;
}

505
dist/fabric.js vendored
View file

@ -1,7 +1,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.6' };
var fabric = fabric || { version: '2.4.0' };
if (typeof exports !== 'undefined') {
exports.fabric = fabric;
}
@ -48,15 +48,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_ */
@ -1171,6 +1171,20 @@ fabric.CommonMethods = {
return fabric.document.createElement('canvas');
},
/**
* 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
@ -3360,10 +3374,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 +3404,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 +3421,7 @@ if (typeof console !== 'undefined') {
fabric.cssRules = { };
fabric.gradientDefs = { };
fabric.clipPaths = { };
function normalizeAttr(attr) {
// transform attribute names
@ -3962,7 +3979,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
@ -3975,7 +3992,6 @@ if (typeof console !== 'undefined') {
el = element;
matrix = el.getAttribute('transform') + matrix;
}
el.setAttribute('transform', matrix);
return parsedDim;
}
@ -4036,13 +4052,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);
};
@ -4395,82 +4422,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;
this.createObjects();
};
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);
}
};
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);
}
catch (err) {
fabric.log(err);
}
}
else {
this.checkIfDone();
}
};
fabric.ElementsParser.prototype._createObject = function(klass, el, index) {
klass.fromElement(el, this.createCallback(index, el), this.options);
};
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();
(function(proto) {
proto.parse = function() {
this.instances = new Array(this.elements.length);
this.numElements = this.elements.length;
this.createObjects();
};
};
fabric.ElementsParser.prototype.resolveGradient = function(obj, property) {
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));
}
};
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;
proto.createObjects = function() {
var _this = this;
this.elements.forEach(function(element, i) {
element.setAttribute('svgUid', _this.svgUid);
_this.createObject(element, i);
});
this.callback(this.instances, this.elements);
}
};
};
proto.findTag = function(el) {
return fabric[fabric.util.string.capitalize(el.tagName.replace('svg:', ''))];
};
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);
}
}
else {
this.checkIfDone();
}
};
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();
};
};
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];
};
proto.resolveGradient = function(obj, property) {
var gradientDef = this.extractPropertyDefinition(obj, property, 'gradientDefs');
if (gradientDef) {
obj.set(property, fabric.Gradient.fromElement(gradientDef, obj));
}
};
proto.createClipPathCallback = function(obj, container) {
return function(_newObj) {
_newObj._removeTransformMatrix();
_newObj.fillRule = _newObj.clipRule;
container.push(_newObj);
};
};
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) {
@ -6668,6 +6743,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 &lt;canvas> element to initialize instance on
@ -7363,11 +7447,11 @@ fabric.ElementsParser.prototype.checkIfDone = function() {
* @chainable
*/
renderCanvas: function(ctx, objects) {
var v = this.viewportTransform;
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);
}
@ -7384,11 +7468,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();
},
/**
@ -7585,11 +7696,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);
@ -12867,6 +12980,36 @@ fabric.util.object.extend(fabric.StaticCanvas.prototype, /** @lends fabric.Stati
' strokeLineCap strokeLineJoin strokeMiterLimit backgroundColor'
).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
@ -12939,8 +13082,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
@ -12972,9 +13115,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;
}
@ -13091,9 +13235,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);
@ -13284,15 +13434,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 {
@ -13307,6 +13449,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
*/
@ -13328,6 +13482,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;
},
@ -13354,15 +13511,61 @@ fabric.util.object.extend(fabric.StaticCanvas.prototype, /** @lends fabric.Stati
return !!this.shadow && (this.shadow.offsetX !== 0 || this.shadow.offsetY !== 0);
},
/**
* 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);
},
/**
@ -13388,7 +13591,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;
@ -13456,6 +13662,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
@ -14067,8 +14279,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);
});
});
};
@ -15179,8 +15394,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('');
},
/**
@ -15256,7 +15474,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));
@ -15267,6 +15485,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;
},
@ -16283,7 +16509,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,
@ -16465,7 +16691,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(),
@ -16683,7 +16909,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(), '"',
@ -16823,7 +17049,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,
@ -17052,7 +17278,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,
@ -17248,7 +17474,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(),
@ -17939,7 +18165,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,
@ -18714,13 +18940,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) {
@ -18904,7 +19131,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(),
@ -19195,15 +19422,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
@ -19415,7 +19633,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
@ -19539,9 +19757,7 @@ 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');
@ -20420,6 +20636,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 || { };
/**
@ -28090,7 +28307,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" ',

2
dist/fabric.min.js vendored

File diff suppressed because one or more lines are too long

View file

@ -2,7 +2,7 @@
"name": "fabric",
"description": "Object model for HTML5 canvas, and SVG-to-canvas parser. Backed by jsdom and node-canvas.",
"homepage": "http://fabricjs.com/",
"version": "2.3.6",
"version": "2.4.0",
"author": "Juriy Zaytsev <kangax@gmail.com>",
"contributors": [
{