Version 2.3.4 (#5144)

* built

* added changelog

* Update CHANGELOG.md
This commit is contained in:
Andrea Bogazzi 2018-08-06 00:50:56 +02:00 committed by GitHub
parent 133c674697
commit db292dfb2f
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
6 changed files with 274 additions and 171 deletions

View file

@ -1,3 +1,16 @@
**Version 2.3.4**
- Fix: ToSVG was ignoring excludeFromExport for backgroundImage and OverlayImage. [#5075](https://github.com/fabricjs/fabric.js/pull/5075)
- Fix: ToSVG for circle with start and end angles. [#5085](https://github.com/fabricjs/fabric.js/pull/5085)
- Fix: Added callback for setPatternFill. [#5101](https://github.com/fabricjs/fabric.js/pull/5101)
- Fix: Resize filter taking in account multiple scale sources. [#5117](https://github.com/fabricjs/fabric.js/pull/5117)
- Fix: Blend image filter clean after refilter. [#5121](https://github.com/fabricjs/fabric.js/pull/5121)
- Fix: Object.toDataURL should not be influenced by zoom. [#5139](https://github.com/fabricjs/fabric.js/pull/5139)
- Improvement: requestRenderAllBound add to Canvas instance. [#5138](https://github.com/fabricjs/fabric.js/pull/5138)
- Improvement: Make path bounding cache optional and also reacheable/cleanable [#5140](https://github.com/fabricjs/fabric.js/pull/5140)
- Improvement: Make the logic of isNeutralState filters work before filtering start. [#5129](https://github.com/fabricjs/fabric.js/pull/5129)
- Improvement: Added some code to clean up some memory when canvas is disposed in nodejs. [#5142](https://github.com/fabricjs/fabric.js/pull/5142)
- Fix: Make numeric origins work with group creation. [#5143](https://github.com/fabricjs/fabric.js/pull/5143)
**Version 2.3.3**
- Fix: Fixed font generic names for text, measurement of zero width related characters and also trailing of cursor when zooming. [#5048](https://github.com/fabricjs/fabric.js/pull/5048)

View file

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

422
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.3' };
var fabric = fabric || { version: '2.3.4' };
if (typeof exports !== 'undefined') {
exports.fabric = fabric;
}
@ -141,6 +141,28 @@ fabric.devicePixelRatio = fabric.window.devicePixelRatio ||
*/
fabric.browserShadowBlurConstant = 1;
/**
* This object contains the result of arc to beizer conversion for faster retrieving if the same arc needs to be converted again.
* It was an internal variable, is accessible since version 2.3.4
*/
fabric.arcToSegmentsCache = { };
/**
* This object keeps the results of the boundsOfCurve calculation mapped by the joined arguments necessary to calculate it.
* It does speed up calculation, if you parse and add always the same paths, but in case of heavy usage of freedrawing
* you do not get any speed benefit and you get a big object in memory.
* The object was a private variable before, while now is appended to the lib so that you have access to it and you
* can eventually clear it.
* It was an internal variable, is accessible since version 2.3.4
*/
fabric.boundsOfCurveCache = { };
/**
* If disabled boundsOfCurveCache is not used. For apps that make heavy usage of pencil drawing probably disabling it is better
* @default true
*/
fabric.cachesBoundsOfCurve = true;
fabric.initFilterBackend = function() {
if (fabric.enableGLFiltering && fabric.isWebglSupported && fabric.isWebglSupported(fabric.textureSize)) {
console.log('max texture size: ' + fabric.maxTextureSize);
@ -1223,6 +1245,12 @@ fabric.CommonMethods = {
return fabric.util.multiplyTransformMatrices(scaleMatrix, skewMatrixX, true);
},
/**
* reset an object transform state to neutral. Top and left are not accounted for
* @static
* @memberOf fabric.util
* @param {fabric.Object} target object to transform
*/
resetObjectTransform: function (target) {
target.scaleX = 1;
target.scaleY = 1;
@ -1233,6 +1261,27 @@ fabric.CommonMethods = {
target.rotate(0);
},
/**
* Extract Object transform values
* @static
* @memberOf fabric.util
* @param {fabric.Object} target object to read from
* @return {Object} Components of transform
*/
saveObjectTransform: function (target) {
return {
scaleX: target.scaleX,
scaleY: target.scaleY,
skewX: target.skewX,
skewY: target.skewY,
angle: target.angle,
left: target.left,
flipX: target.flipX,
flipY: target.flipY,
top: target.top
};
},
/**
* Returns string representation of function body
* @param {Function} fn Function to get body of
@ -1370,10 +1419,7 @@ fabric.CommonMethods = {
(function() {
var arcToSegmentsCache = { },
segmentToBezierCache = { },
boundsOfCurveCache = { },
_join = Array.prototype.join;
var _join = Array.prototype.join;
/* Adapted from http://dxr.mozilla.org/mozilla-central/source/content/svg/content/src/nsSVGPathDataParser.cpp
* by Andrea Bogazzi code is under MPL. if you don't have a copy of the license you can take it here
@ -1381,8 +1427,8 @@ fabric.CommonMethods = {
*/
function arcToSegments(toX, toY, rx, ry, large, sweep, rotateX) {
var argsString = _join.call(arguments);
if (arcToSegmentsCache[argsString]) {
return arcToSegmentsCache[argsString];
if (fabric.arcToSegmentsCache[argsString]) {
return fabric.arcToSegmentsCache[argsString];
}
var PI = Math.PI, th = rotateX * PI / 180,
@ -1436,16 +1482,11 @@ fabric.CommonMethods = {
mTheta = th3;
th3 += mDelta;
}
arcToSegmentsCache[argsString] = result;
fabric.arcToSegmentsCache[argsString] = result;
return result;
}
function segmentToBezier(th2, th3, cosTh, sinTh, rx, ry, cx1, cy1, mT, fromX, fromY) {
var argsString2 = _join.call(arguments);
if (segmentToBezierCache[argsString2]) {
return segmentToBezierCache[argsString2];
}
var costh2 = fabric.util.cos(th2),
sinth2 = fabric.util.sin(th2),
costh3 = fabric.util.cos(th3),
@ -1457,12 +1498,11 @@ fabric.CommonMethods = {
cp2X = toX + mT * ( cosTh * rx * sinth3 + sinTh * ry * costh3),
cp2Y = toY + mT * ( sinTh * rx * sinth3 - cosTh * ry * costh3);
segmentToBezierCache[argsString2] = [
return [
cp1X, cp1Y,
cp2X, cp2Y,
toX, toY
];
return segmentToBezierCache[argsString2];
}
/*
@ -1548,9 +1588,12 @@ fabric.CommonMethods = {
*/
// taken from http://jsbin.com/ivomiq/56/edit no credits available for that.
function getBoundsOfCurve(x0, y0, x1, y1, x2, y2, x3, y3) {
var argsString = _join.call(arguments);
if (boundsOfCurveCache[argsString]) {
return boundsOfCurveCache[argsString];
var argsString;
if (fabric.cachesBoundsOfCurve) {
argsString = _join.call(arguments);
if (fabric.boundsOfCurveCache[argsString]) {
return fabric.boundsOfCurveCache[argsString];
}
}
var sqrt = Math.sqrt,
@ -1620,7 +1663,9 @@ fabric.CommonMethods = {
y: max.apply(null, bounds[1])
}
];
boundsOfCurveCache[argsString] = result;
if (fabric.cachesBoundsOfCurve) {
fabric.boundsOfCurveCache[argsString] = result;
}
return result;
}
@ -2625,6 +2670,21 @@ fabric.CommonMethods = {
return impl._canvas || impl._image;
};
function cleanUpJsdomNode(element) {
if (!fabric.isLikelyNode) {
return;
}
var impl = fabric.jsdomImplForWrapper(element);
if (impl) {
impl._image = null;
impl._canvas = null;
// unsure if necessary
impl._currentSrc = null;
impl._attributes = null;
impl._classList = null;
}
}
fabric.util.getById = getById;
fabric.util.toArray = toArray;
fabric.util.makeElement = makeElement;
@ -2634,6 +2694,7 @@ fabric.CommonMethods = {
fabric.util.getElementOffset = getElementOffset;
fabric.util.getElementStyle = getElementStyle;
fabric.util.getNodeCanvas = getNodeCanvas;
fabric.util.cleanUpJsdomNode = cleanUpJsdomNode;
})();
@ -2646,10 +2707,10 @@ fabric.CommonMethods = {
var makeXHR = (function() {
var factories = [
function() { return new fabric.window.XMLHttpRequest(); },
function() { return new ActiveXObject('Microsoft.XMLHTTP'); },
function() { return new ActiveXObject('Msxml2.XMLHTTP'); },
function() { return new ActiveXObject('Msxml2.XMLHTTP.3.0'); },
function() { return new XMLHttpRequest(); }
function() { return new ActiveXObject('Msxml2.XMLHTTP.3.0'); }
];
for (var i = factories.length; i--; ) {
try {
@ -2676,7 +2737,6 @@ fabric.CommonMethods = {
* @return {XMLHttpRequest} request
*/
function request(url, options) {
options || (options = { });
var method = options.method ? options.method.toUpperCase() : 'GET',
@ -7794,7 +7854,7 @@ fabric.ElementsParser.prototype.checkIfDone = function() {
* @private
*/
_setSVGBgOverlayImage: function(markup, property, reviver) {
if (this[property] && this[property].toSVG) {
if (this[property] && !this[property].excludeFromExport && this[property].toSVG) {
markup.push(this[property].toSVG(reviver));
}
},
@ -8067,11 +8127,18 @@ fabric.ElementsParser.prototype.checkIfDone = function() {
object.dispose && object.dispose();
});
this._objects = [];
if (this.backgroundImage && this.backgroundImage.dispose) {
this.backgroundImage.dispose();
}
this.backgroundImage = null;
if (this.overlayImage && this.overlayImage.dispose) {
this.overlayImage.dispose();
}
this.overlayImage = null;
this._iTextInstances = null;
this.lowerCanvasEl = null;
this.contextContainer = null;
fabric.util.cleanUpJsdomNode(this.lowerCanvasEl);
this.lowerCanvasEl = undefined;
return this;
},
@ -8925,7 +8992,7 @@ fabric.PatternBrush = fabric.util.createClass(fabric.PencilBrush, /** @lends fab
var dotWidth = 20,
dotDistance = 5,
patternCanvas = fabric.document.createElement('canvas'),
patternCanvas = fabric.util.createCanvasElement(),
patternCtx = patternCanvas.getContext('2d');
patternCanvas.width = patternCanvas.height = dotWidth + dotDistance;
@ -9038,6 +9105,7 @@ fabric.PatternBrush = fabric.util.createClass(fabric.PencilBrush, /** @lends fab
initialize: function(el, options) {
options || (options = { });
this.renderAndResetBound = this.renderAndReset.bind(this);
this.requestRenderAllBound = this.requestRenderAll.bind(this);
this._initStatic(el, options);
this._initInteractive();
this._createCacheCanvas();
@ -9679,19 +9747,12 @@ fabric.PatternBrush = fabric.util.createClass(fabric.PencilBrush, /** @lends fab
mouseXSign: 1,
mouseYSign: 1,
shiftKey: e.shiftKey,
altKey: e[this.centeredKey]
altKey: e[this.centeredKey],
original: fabric.util.saveObjectTransform(target),
};
this._currentTransform.original = {
left: target.left,
top: target.top,
scaleX: target.scaleX,
scaleY: target.scaleY,
skewX: target.skewX,
skewY: target.skewY,
originX: origin.x,
originY: origin.y
};
this._currentTransform.original.originX = origin.x;
this._currentTransform.original.originY = origin.y;
this._resetCurrentTransform();
this._beforeTransform(e);
@ -10072,18 +10133,6 @@ fabric.PatternBrush = fabric.util.createClass(fabric.PencilBrush, /** @lends fab
this.upperCanvasEl.style.cursor = value;
},
/**
* @param {fabric.Object} target to reset transform
* @private
*/
_resetObjectTransform: function (target) {
target.scaleX = 1;
target.scaleY = 1;
target.skewX = 0;
target.skewY = 0;
target.rotate(0);
},
/**
* @private
* @param {CanvasRenderingContext2D} ctx to draw the selection on
@ -10572,10 +10621,12 @@ fabric.PatternBrush = fabric.util.createClass(fabric.PencilBrush, /** @lends fab
this.removeListeners();
wrapper.removeChild(this.upperCanvasEl);
wrapper.removeChild(this.lowerCanvasEl);
this.upperCanvasEl = null;
this.cacheCanvasEl = null;
this.contextCache = null;
this.contextTop = null;
['upperCanvasEl', 'cacheCanvasEl'].forEach((function(element) {
fabric.util.cleanUpJsdomNode(this[element]);
this[element] = undefined;
}).bind(this));
if (wrapper.parentNode) {
wrapper.parentNode.replaceChild(this.lowerCanvasEl, this.wrapperEl);
}
@ -12168,7 +12219,7 @@ fabric.util.object.extend(fabric.StaticCanvas.prototype, /** @lends fabric.Stati
* @param {Object} [callback] Receives cloned instance as a first argument
*/
cloneWithoutData: function(callback) {
var el = fabric.document.createElement('canvas');
var el = fabric.util.createCanvasElement();
el.width = this.width;
el.height = this.height;
@ -12783,6 +12834,9 @@ fabric.util.object.extend(fabric.StaticCanvas.prototype, /** @lends fabric.Stati
/**
* List of properties to consider when checking if cache needs refresh
* Those properties are checked by statefullCache ON ( or lazy mode if we want ) or from single
* calls to Object.set(key, value). If the key is in this list, the object is marked as dirty
* and refreshed at the next render
* @type Array
*/
cacheProperties: (
@ -12806,7 +12860,7 @@ fabric.util.object.extend(fabric.StaticCanvas.prototype, /** @lends fabric.Stati
*/
_createCacheCanvas: function() {
this._cacheProperties = {};
this._cacheCanvas = fabric.document.createElement('canvas');
this._cacheCanvas = fabric.util.createCanvasElement();
this._cacheContext = this._cacheCanvas.getContext('2d');
this._updateCacheCanvas();
// if canvas gets created, is empty, so dirty.
@ -12870,12 +12924,10 @@ fabric.util.object.extend(fabric.StaticCanvas.prototype, /** @lends fabric.Stati
* @return {Object}.zoomY zoomY zoom value to unscale the canvas before drawing cache
*/
_getCacheCanvasDimensions: function() {
var zoom = this.canvas && this.canvas.getZoom() || 1,
objectScale = this.getObjectScaling(),
retina = this.canvas && this.canvas._isRetinaScaling() ? fabric.devicePixelRatio : 1,
var objectScale = this.getTotalObjectScaling(),
dim = this._getNonTransformedDimensions(),
zoomX = objectScale.scaleX * zoom * retina,
zoomY = objectScale.scaleY * zoom * retina,
zoomX = objectScale.scaleX,
zoomY = objectScale.scaleY,
width = dim.x * zoomX,
height = dim.y * zoomY;
return {
@ -13082,6 +13134,21 @@ fabric.util.object.extend(fabric.StaticCanvas.prototype, /** @lends fabric.Stati
return { scaleX: scaleX, scaleY: scaleY };
},
/**
* Return the object scale factor counting also the group scaling, zoom and retina
* @return {Object} object with scaleX and scaleY properties
*/
getTotalObjectScaling: function() {
var scale = this.getObjectScaling(), scaleX = scale.scaleX, scaleY = scale.scaleY;
if (this.canvas) {
var zoom = this.canvas.getZoom();
var retina = this.canvas.getRetinaScaling();
scaleX *= zoom * retina;
scaleY *= zoom * retina;
}
return { scaleX: scaleX, scaleY: scaleY };
},
/**
* Return the object opacity counting also the group property
* @return {Number}
@ -13627,17 +13694,24 @@ fabric.util.object.extend(fabric.StaticCanvas.prototype, /** @lends fabric.Stati
* @param {Number} [options.width] Cropping width. Introduced in v1.2.14
* @param {Number} [options.height] Cropping height. Introduced in v1.2.14
* @param {Boolean} [options.enableRetinaScaling] Enable retina scaling for clone image. Introduce in 1.6.4
* @param {Boolean} [options.withoutTransform] Remove current object transform ( no scale , no angle, no flip, no skew ). Introduced in 2.3.4
* @return {String} Returns a data: URL containing a representation of the object in the format specified by options.format
*/
toDataURL: function(options) {
options || (options = { });
var origParams = fabric.util.saveObjectTransform(this);
if (options.withoutTransform) {
fabric.util.resetObjectTransform(this);
}
var el = fabric.util.createCanvasElement(),
boundingRect = this.getBoundingRect();
// skip canvas zoom and calculate with setCoords now.
boundingRect = this.getBoundingRect(true, true);
el.width = boundingRect.width;
el.height = boundingRect.height;
fabric.util.wrapElement(el, 'div');
var canvas = new fabric.StaticCanvas(el, {
enableRetinaScaling: options.enableRetinaScaling,
renderOnAddRemove: false,
@ -13652,11 +13726,6 @@ fabric.util.object.extend(fabric.StaticCanvas.prototype, /** @lends fabric.Stati
canvas.backgroundColor = '#fff';
}
var origParams = {
left: this.left,
top: this.top
};
this.setPositionByOrigin(new fabric.Point(canvas.width / 2, canvas.height / 2), 'center', 'center');
var originalCanvas = this.canvas;
@ -13780,20 +13849,18 @@ fabric.util.object.extend(fabric.StaticCanvas.prototype, /** @lends fabric.Stati
* @param {String} [options.repeat=repeat] Repeat property of a pattern (one of repeat, repeat-x, repeat-y or no-repeat)
* @param {Number} [options.offsetX=0] Pattern horizontal offset from object's left/top corner
* @param {Number} [options.offsetY=0] Pattern vertical offset from object's left/top corner
* @param {Function} [callback] Callback to invoke when image set as a pattern
* @return {fabric.Object} thisArg
* @chainable
* @see {@link http://jsfiddle.net/fabricjs/QT3pa/|jsFiddle demo}
* @example <caption>Set pattern</caption>
* fabric.util.loadImage('http://fabricjs.com/assets/escheresque_ste.png', function(img) {
* object.setPatternFill({
* source: img,
* repeat: 'repeat'
* });
* canvas.renderAll();
* });
* object.setPatternFill({
* source: 'http://fabricjs.com/assets/escheresque_ste.png',
* repeat: 'repeat'
* },canvas.renderAll.bind(canvas));
*/
setPatternFill: function(options) {
return this.set('fill', new fabric.Pattern(options));
setPatternFill: function(options, callback) {
return this.set('fill', new fabric.Pattern(options, callback));
},
/**
@ -14706,8 +14773,8 @@ fabric.util.object.extend(fabric.StaticCanvas.prototype, /** @lends fabric.Stati
},
/**
* Sets corner position coordinates based on current angle, width and height
* See https://github.com/kangax/fabric.js/wiki/When-to-call-setCoords
* Sets corner position coordinates based on current angle, width and height.
* See {@link https://github.com/kangax/fabric.js/wiki/When-to-call-setCoords|When-to-call-setCoords}
* @param {Boolean} [ignoreZoom] set oCoords with or without the viewport transform.
* @param {Boolean} [skipAbsolute] skip calculation of aCoords, usefull in setViewportTransform
* @return {fabric.Object} thisArg
@ -16400,7 +16467,7 @@ fabric.util.object.extend(fabric.Object.prototype, /** @lends fabric.Object.prot
'" transform="', this.getSvgTransform(),
' ', this.getSvgTransformMatrix(), '"',
this.addPaintOrder(),
'"/>\n'
'/>\n'
);
}
@ -18371,13 +18438,6 @@ fabric.util.object.extend(fabric.Object.prototype, /** @lends fabric.Object.prot
this._objects[i].group = this;
}
if (options.originX) {
this.originX = options.originX;
}
if (options.originY) {
this.originY = options.originY;
}
if (!isAlreadyGrouped) {
var center = options && options.centerPoint;
// if coming from svg i do not want to calc bounds.
@ -18783,7 +18843,7 @@ fabric.util.object.extend(fabric.Object.prototype, /** @lends fabric.Object.prot
}
}
this.set(this._getBounds(aX, aY, onlyWidthHeight));
this._getBounds(aX, aY, onlyWidthHeight);
},
/**
@ -18792,28 +18852,14 @@ fabric.util.object.extend(fabric.Object.prototype, /** @lends fabric.Object.prot
_getBounds: function(aX, aY, onlyWidthHeight) {
var minXY = new fabric.Point(min(aX), min(aY)),
maxXY = new fabric.Point(max(aX), max(aY)),
obj = {
width: (maxXY.x - minXY.x) || 0,
height: (maxXY.y - minXY.y) || 0
};
top = minXY.y || 0, left = minXY.x || 0,
width = (maxXY.x - minXY.x) || 0,
height = (maxXY.y - minXY.y) || 0;
this.width = width;
this.height = height;
if (!onlyWidthHeight) {
obj.left = minXY.x || 0;
obj.top = minXY.y || 0;
if (this.originX === 'center') {
obj.left += obj.width / 2;
}
if (this.originX === 'right') {
obj.left += obj.width;
}
if (this.originY === 'center') {
obj.top += obj.height / 2;
}
if (this.originY === 'bottom') {
obj.top += obj.height;
}
this.setPositionByOrigin({ x: left, y: top }, 'left', 'top');
}
return obj;
},
/* _TO_SVG_START_ */
@ -19244,9 +19290,11 @@ fabric.util.object.extend(fabric.Object.prototype, /** @lends fabric.Object.prot
backend.evictCachesForKey(this.cacheKey);
backend.evictCachesForKey(this.cacheKey + '_filtered');
}
this._originalElement = undefined;
this._element = undefined;
this._filteredEl = undefined;
this._cacheContext = undefined;
['_originalElement', '_element', '_filteredEl', '_cacheCanvas'].forEach((function(element) {
fabric.util.cleanUpJsdomNode(this[element]);
this[element] = undefined;
}).bind(this));
},
/**
@ -19445,10 +19493,10 @@ fabric.util.object.extend(fabric.Object.prototype, /** @lends fabric.Object.prot
applyResizeFilters: function() {
var filter = this.resizeFilter,
retinaScaling = this.canvas ? this.canvas.getRetinaScaling() : 1,
minimumScale = this.minimumScaleTrigger,
scaleX = this.scaleX * retinaScaling,
scaleY = this.scaleY * retinaScaling,
objectScale = this.getTotalObjectScaling(),
scaleX = objectScale.scaleX,
scaleY = objectScale.scaleY,
elementToFilter = this._filteredEl || this._originalElement;
if (this.group) {
this.set('dirty', true);
@ -19457,6 +19505,8 @@ fabric.util.object.extend(fabric.Object.prototype, /** @lends fabric.Object.prot
this._element = elementToFilter;
this._filterScalingX = 1;
this._filterScalingY = 1;
this._lastScaleX = scaleX;
this._lastScaleY = scaleY;
return;
}
if (!fabric.filterBackend) {
@ -19468,8 +19518,8 @@ fabric.util.object.extend(fabric.Object.prototype, /** @lends fabric.Object.prot
canvasEl.width = sourceWidth;
canvasEl.height = sourceHeight;
this._element = canvasEl;
filter.scaleX = scaleX;
filter.scaleY = scaleY;
this._lastScaleX = filter.scaleX = scaleX;
this._lastScaleY = filter.scaleY = scaleY;
fabric.filterBackend.applyFilters(
[filter], elementToFilter, sourceWidth, sourceHeight, this._element, cacheKey);
this._filterScalingX = canvasEl.width / this._originalElement.width;
@ -19487,7 +19537,7 @@ fabric.util.object.extend(fabric.Object.prototype, /** @lends fabric.Object.prot
applyFilters: function(filters) {
filters = filters || this.filters || [];
filters = filters.filter(function(filter) { return filter; });
filters = filters.filter(function(filter) { return filter && !filter.isNeutralState(); });
if (this.group) {
this.set('dirty', true);
}
@ -19533,9 +19583,7 @@ fabric.util.object.extend(fabric.Object.prototype, /** @lends fabric.Object.prot
* @param {CanvasRenderingContext2D} ctx Context to render on
*/
_render: function(ctx) {
if (this.isMoving === false && this.resizeFilter && this._needsResize()) {
this._lastScaleX = this.scaleX;
this._lastScaleY = this.scaleY;
if (this.isMoving !== true && this.resizeFilter && this._needsResize()) {
this.applyResizeFilters();
}
this._stroke(ctx);
@ -19557,7 +19605,8 @@ fabric.util.object.extend(fabric.Object.prototype, /** @lends fabric.Object.prot
* @private, needed to check if image needs resize
*/
_needsResize: function() {
return (this.scaleX !== this._lastScaleX || this.scaleY !== this._lastScaleY);
var scale = this.getTotalObjectScaling();
return (scale.scaleX !== this._lastScaleX || scale.scaleY !== this._lastScaleY);
},
/**
@ -20555,11 +20604,31 @@ fabric.Image.filters.BaseFilter = fabric.util.createClass(/** @lends fabric.Imag
},
/**
* Intentionally left blank, to be overridden in custom filters
* Generic isNeutral implementation for one parameter based filters.
* Used only in image applyFilters to discard filters that will not have an effect
* on the image
* Other filters may need their own verison ( ColorMatrix, HueRotation, gamma, ComposedFilter )
* @param {Object} options
**/
isNeutralState: function(/* options */) {
return false;
var main = this.mainParameter,
_class = fabric.Image.filters[this.type].prototype;
if (main) {
if (Array.isArray(_class[main])) {
for (var i = _class[main].length; i--;) {
if (this[main][i] !== _class[main][i]) {
return false;
}
}
return true;
}
else {
return _class[main] === this[main];
}
}
else {
return false;
}
},
/**
@ -20577,15 +20646,11 @@ fabric.Image.filters.BaseFilter = fabric.util.createClass(/** @lends fabric.Imag
*/
applyTo: function(options) {
if (options.webgl) {
if (options.passes > 1 && this.isNeutralState(options)) {
// avoid doing something that we do not need
return;
}
this._setupFrameBuffer(options);
this.applyToWebGL(options);
this._swapTextures(options);
}
else if (!this.isNeutralState()) {
else {
this.applyTo2d(options);
}
},
@ -20793,20 +20858,6 @@ fabric.Image.filters.BaseFilter.fromObject = function(object, callback) {
this.matrix = this.matrix.slice(0);
},
/**
* Intentionally left blank, to be overridden in custom filters
* @param {Object} options
**/
isNeutralState: function(/* options */) {
var _class = filters.ColorMatrix;
for (var i = 20; i--;) {
if (this.matrix[i] !== _class.prototype.matrix[i]) {
return false;
}
}
return true;
},
/**
* Apply the ColorMatrix operation to a Uint8Array representing the pixels of an image.
*
@ -21485,6 +21536,15 @@ fabric.Image.filters.BaseFilter.fromObject = function(object, callback) {
var mode = 1;
gl.uniform1i(uniformLocations.uMode, mode);
},
/**
* Grayscale filter isNeutralState implementation
* The filter is never neutral
* on the image
**/
isNeutralState: function() {
return false;
},
});
/**
@ -21556,9 +21616,6 @@ fabric.Image.filters.BaseFilter.fromObject = function(object, callback) {
* @param {ImageData} options.imageData The Uint8Array to be filtered.
*/
applyTo2d: function(options) {
if (!this.invert) {
return;
}
var imageData = options.imageData,
data = imageData.data, i,
len = data.length;
@ -21569,6 +21626,16 @@ fabric.Image.filters.BaseFilter.fromObject = function(object, callback) {
}
},
/**
* Invert filter isNeutralState implementation
* Used only in image applyFilters to discard filters that will not have an effect
* on the image
* @param {Object} options
**/
isNeutralState: function() {
return !this.invert;
},
/**
* Return WebGL uniform locations for this filter's shader.
*
@ -21804,9 +21871,6 @@ fabric.Image.filters.BaseFilter.fromObject = function(object, callback) {
* @param {ImageData} options.imageData The Uint8ClampedArray to be filtered.
*/
applyTo2d: function(options) {
if (this.blocksize === 1) {
return;
}
var imageData = options.imageData,
data = imageData.data,
iLen = imageData.height,
@ -22436,7 +22500,8 @@ fabric.Image.filters.BaseFilter.fromObject = function(object, callback) {
mode: 'multiply',
/**
* alpha value. represent the strength of the blend color operation.
* alpha value. represent the strength of the blend image operation.
* not implemented.
**/
alpha: 1,
@ -22535,21 +22600,24 @@ fabric.Image.filters.BaseFilter.fromObject = function(object, callback) {
var imageData = options.imageData,
resources = options.filterBackend.resources,
data = imageData.data, iLen = data.length,
width = options.imageData.width,
height = options.imageData.height,
width = imageData.width,
height = imageData.height,
tr, tg, tb, ta,
r, g, b, a,
canvas1, context, image = this.image, blendData;
if (!resources.blendImage) {
resources.blendImage = document.createElement('canvas');
resources.blendImage = fabric.util.createCanvasElement();
}
canvas1 = resources.blendImage;
context = canvas1.getContext('2d');
if (canvas1.width !== width || canvas1.height !== height) {
canvas1.width = width;
canvas1.height = height;
}
context = canvas1.getContext('2d');
else {
context.clearRect(0, 0, width, height);
}
context.setTransform(image.scaleX, 0, 0, image.scaleY, image.left, image.top);
context.drawImage(image._element, 0, 0, width, height);
blendData = context.getImageData(0, 0, width, height).data;
@ -22668,6 +22736,8 @@ fabric.Image.filters.BaseFilter.fromObject = function(object, callback) {
/**
* Resize type
* for webgl resizyType is just lanczos, for canvas2d can be:
* bilinear, hermite, sliceHacl, lanczos.
* @param {String} resizeType
* @default
*/
@ -22678,17 +22748,17 @@ fabric.Image.filters.BaseFilter.fromObject = function(object, callback) {
* @param {Number} scaleX
* @default
*/
scaleX: 0,
scaleX: 1,
/**
* Scale factor for resizing, y axis
* @param {Number} scaleY
* @default
*/
scaleY: 0,
scaleY: 1,
/**
* LanczosLobes parameter for lanczos filter
* LanczosLobes parameter for lanczos filter, valid for resizeType lanczos
* @param {Number} lanczosLobes
* @default
*/
@ -22794,10 +22864,6 @@ fabric.Image.filters.BaseFilter.fromObject = function(object, callback) {
*/
applyTo: function(options) {
if (options.webgl) {
if (options.passes > 1 && this.isNeutralState(options)) {
// avoid doing something that we do not need
return;
}
options.passes++;
this.width = options.sourceWidth;
this.horizontal = true;
@ -22822,15 +22888,13 @@ fabric.Image.filters.BaseFilter.fromObject = function(object, callback) {
this._swapTextures(options);
options.sourceHeight = options.destinationHeight;
}
else if (!this.isNeutralState(options)) {
else {
this.applyTo2d(options);
}
},
isNeutralState: function(options) {
var scaleX = options.scaleX || this.scaleX,
scaleY = options.scaleY || this.scaleY;
return scaleX === 1 && scaleY === 1;
isNeutralState: function() {
return this.scaleX === 1 && this.scaleY === 1;
},
lanczosCreate: function(lobes) {
@ -23631,6 +23695,15 @@ fabric.Image.filters.BaseFilter.fromObject = function(object, callback) {
*/
mainParameter: 'gamma',
/**
* Constructor
* @param {Object} [options] Options object
*/
initialize: function(options) {
this.gamma = [1, 1, 1];
filters.BaseFilter.prototype.initialize.call(this, options);
},
/**
* Apply the Gamma operation to a Uint8Array representing the pixels of an image.
*
@ -23754,6 +23827,10 @@ fabric.Image.filters.BaseFilter.fromObject = function(object, callback) {
subFilters: this.subFilters.map(function(filter) { return filter.toObject(); }),
});
},
isNeutralState: function() {
return !this.subFilters.some(function(filter) { return !filter.isNeutralState(); });
}
});
/**
@ -23837,6 +23914,17 @@ fabric.Image.filters.BaseFilter.fromObject = function(object, callback) {
this.matrix[12] = cos + aThird * OneMinusCos;
},
/**
* HueRotation isNeutralState implementation
* Used only in image applyFilters to discard filters that will not have an effect
* on the image
* @param {Object} options
**/
isNeutralState: function(options) {
this.calculateMatrix();
return filters.BaseFilter.prototype.isNeutralState.call(this, options);
},
/**
* Apply this filter to the input image data provided.
*
@ -23852,7 +23940,7 @@ fabric.Image.filters.BaseFilter.fromObject = function(object, callback) {
*/
applyTo: function(options) {
this.calculateMatrix();
fabric.Image.filters.BaseFilter.prototype.applyTo.call(this, options);
filters.BaseFilter.prototype.applyTo.call(this, options);
},
});
@ -23964,21 +24052,21 @@ fabric.Image.filters.BaseFilter.fromObject = function(object, callback) {
/**
* Text decoration underline.
* @type String
* @type Boolean
* @default
*/
underline: false,
/**
* Text decoration overline.
* @type String
* @type Boolean
* @default
*/
overline: false,
/**
* Text decoration linethrough.
* @type String
* @type Boolean
* @default
*/
linethrough: false,
@ -27320,9 +27408,11 @@ fabric.util.object.extend(fabric.IText.prototype, /** @lends fabric.IText.protot
this.hiddenTextarea.setAttribute('data-fabric-hiddentextarea', '');
this.hiddenTextarea.setAttribute('wrap', 'off');
var style = this._calcTextareaPosition();
// line-height: 1px; was removed from the style to fix this:
// https://bugs.chromium.org/p/chromium/issues/detail?id=870966
this.hiddenTextarea.style.cssText = 'position: absolute; top: ' + style.top +
'; left: ' + style.left + '; z-index: -999; opacity: 0; width: 1px; height: 1px; font-size: 1px;' +
' line-height: 1px; paddingーtop: ' + style.fontSize + ';';
' paddingーtop: ' + style.fontSize + ';';
fabric.document.body.appendChild(this.hiddenTextarea);
fabric.util.addListener(this.hiddenTextarea, 'keydown', this.onKeyDown.bind(this));

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.3",
"version": "2.3.4",
"author": "Juriy Zaytsev <kangax@gmail.com>",
"contributors": [
{

View file

@ -874,12 +874,12 @@
canvas.renderOnAddRemove = false;
canvas.backgroundImage = imageBG;
canvas.overlayImage = imageOL;
var expectedSVG = '<?xml version="1.0" encoding="UTF-8" standalone="no" ?>\n<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">\n<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" version="1.1" width="600" height="600" viewBox="0 0 600 600" xml:space="preserve">\n<desc>Created with Fabric.js 2.3.3</desc>\n<defs>\n</defs>\n<g transform="translate(0 0)">\n\t<image xlink:href="" x="0" y="0" style="stroke: none; stroke-width: 0; stroke-dasharray: none; stroke-linecap: butt; stroke-linejoin: miter; stroke-miterlimit: 4; fill: rgb(0,0,0); fill-rule: nonzero; opacity: 1;" width="0" height="0"></image>\n</g>\n<g transform="translate(0 0)">\n\t<image xlink:href="" x="0" y="0" style="stroke: none; stroke-width: 0; stroke-dasharray: none; stroke-linecap: butt; stroke-linejoin: miter; stroke-miterlimit: 4; fill: rgb(0,0,0); fill-rule: nonzero; opacity: 1;" width="0" height="0"></image>\n</g>\n</svg>';
var expectedSVG = '<?xml version="1.0" encoding="UTF-8" standalone="no" ?>\n<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">\n<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" version="1.1" width="600" height="600" viewBox="0 0 600 600" xml:space="preserve">\n<desc>Created with Fabric.js ' + fabric.version + '</desc>\n<defs>\n</defs>\n<g transform="translate(0 0)">\n\t<image xlink:href="" x="0" y="0" style="stroke: none; stroke-width: 0; stroke-dasharray: none; stroke-linecap: butt; stroke-linejoin: miter; stroke-miterlimit: 4; fill: rgb(0,0,0); fill-rule: nonzero; opacity: 1;" width="0" height="0"></image>\n</g>\n<g transform="translate(0 0)">\n\t<image xlink:href="" x="0" y="0" style="stroke: none; stroke-width: 0; stroke-dasharray: none; stroke-linecap: butt; stroke-linejoin: miter; stroke-miterlimit: 4; fill: rgb(0,0,0); fill-rule: nonzero; opacity: 1;" width="0" height="0"></image>\n</g>\n</svg>';
var svg1 = canvas.toSVG();
assert.equal(svg1, expectedSVG, 'svg with bg and overlay do not match');
imageBG.excludeFromExport = true;
imageOL.excludeFromExport = true;
var expectedSVG2 = '<?xml version="1.0" encoding="UTF-8" standalone="no" ?>\n<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">\n<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" version="1.1" width="600" height="600" viewBox="0 0 600 600" xml:space="preserve">\n<desc>Created with Fabric.js 2.3.3</desc>\n<defs>\n</defs>\n</svg>';
var expectedSVG2 = '<?xml version="1.0" encoding="UTF-8" standalone="no" ?>\n<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">\n<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" version="1.1" width="600" height="600" viewBox="0 0 600 600" xml:space="preserve">\n<desc>Created with Fabric.js ' + fabric.version + '</desc>\n<defs>\n</defs>\n</svg>';
var svg2 = canvas.toSVG();
assert.equal(svg2, expectedSVG2, 'svg without bg and overlay do not match');
canvas.backgroundImage = null;