Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Version 2.5.0 #5465

Merged
merged 1 commit into from
Jan 7, 2019
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 6 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,11 @@
# Changelog

## [2.5.0]
- Fix: textbox transform report newScaleX and newScaleY values [#5464](https://github.com/fabricjs/fabric.js/pull/5464)
- Fix: export of svg and gradient with transforms [#5456](https://github.com/fabricjs/fabric.js/pull/5456)
- Fix: detection of controls in perPixelTargetFind + cache [#5455](https://github.com/fabricjs/fabric.js/pull/5455)
- Add: added canvas.toCanvasElement method [#5452](https://github.com/fabricjs/fabric.js/pull/5452)

## [2.4.6]
- Fix: unbreak the svg export broken in 2.4.5 [#5438](https://github.com/fabricjs/fabric.js/pull/5438)

Expand Down
2 changes: 1 addition & 1 deletion HEADER.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
/*! Fabric.js Copyright 2008-2015, Printio (Juriy Zaytsev, Maxim Chernyak) */

var fabric = fabric || { version: '2.4.6' };
var fabric = fabric || { version: '2.5.0' };
if (typeof exports !== 'undefined') {
exports.fabric = fabric;
}
Expand Down
186 changes: 95 additions & 91 deletions dist/fabric.js
Original file line number Diff line number Diff line change
@@ -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.4.6' };
var fabric = fabric || { version: '2.5.0' };
if (typeof exports !== 'undefined') {
exports.fabric = fabric;
}
Expand Down Expand Up @@ -5874,29 +5874,25 @@ fabric.ElementsParser = function(elements, callback, options, reviver, parsingOp
var coords = clone(this.coords, true), i, len,
markup, commonAttributes, colorStops = clone(this.colorStops, true),
needsSwap = coords.r1 > coords.r2,
offsetX = object.width / 2, offsetY = object.height / 2;
transform = this.gradientTransform ? this.gradientTransform.concat() : fabric.iMatrix.concat(),
offsetX = object.width / 2 - this.offsetX, offsetY = object.height / 2 - this.offsetY;
// colorStops must be sorted ascending
colorStops.sort(function(a, b) {
return a.offset - b.offset;
});

if (object.type === 'path') {
offsetX -= object.pathOffset.x;
offsetY -= object.pathOffset.y;
}
for (var prop in coords) {
if (prop === 'x1' || prop === 'x2') {
coords[prop] += this.offsetX - offsetX;
}
else if (prop === 'y1' || prop === 'y2') {
coords[prop] += this.offsetY - offsetY;
}
}

transform[4] -= offsetX;
transform[5] -= offsetY;

commonAttributes = 'id="SVGID_' + this.id +
'" gradientUnits="userSpaceOnUse"';
if (this.gradientTransform) {
commonAttributes += ' gradientTransform="matrix(' + this.gradientTransform.join(' ') + ')" ';
}
commonAttributes += ' gradientTransform="matrix(' + transform.join(' ') + ')" ';

if (this.type === 'linear') {
markup = [
'<linearGradient ',
Expand Down Expand Up @@ -6631,6 +6627,7 @@ fabric.ElementsParser = function(elements, callback, options, reviver, parsingOp

/**
* Indicates whether toObject/toDatalessObject should include default values
* if set to false, takes precedence over the object value.
* @type Boolean
* @default
*/
Expand Down Expand Up @@ -7713,7 +7710,7 @@ fabric.ElementsParser = function(elements, callback, options, reviver, parsingOp
objects: this._toObjects(methodName, propertiesToInclude),
};
if (clipPath) {
clipPath = clipPath.toObject(propertiesToInclude);
data.clipPath = this._toObjectMethod(clipPath, methodName, propertiesToInclude);
}
extend(data, this.__serializeBgOverlay(methodName, propertiesToInclude));

Expand Down Expand Up @@ -9714,13 +9711,15 @@ fabric.PatternBrush = fabric.util.createClass(fabric.PencilBrush, /** @lends fab
* @return {Boolean}
*/
isTargetTransparent: function (target, x, y) {
if (target.shouldCache() && target._cacheCanvas) {
// in case the target is the activeObject, we cannot execute this optimization
// because we need to draw controls too.
if (target.shouldCache() && target._cacheCanvas && target !== this._activeObject) {
var normalizedPointer = this._normalizePointer(target, {x: x, y: y}),
targetRelativeX = target.cacheTranslationX + (normalizedPointer.x * target.zoomX),
targetRelativeY = target.cacheTranslationY + (normalizedPointer.y * target.zoomY);
targetRelativeX = Math.max(target.cacheTranslationX + (normalizedPointer.x * target.zoomX), 0),
targetRelativeY = Math.max(target.cacheTranslationY + (normalizedPointer.y * target.zoomY), 0);

var isTransparent = fabric.util.isTransparent(
target._cacheContext, targetRelativeX, targetRelativeY, this.targetFindTolerance);
target._cacheContext, Math.round(targetRelativeX), Math.round(targetRelativeY), this.targetFindTolerance);

return isTransparent;
}
Expand Down Expand Up @@ -10099,12 +10098,10 @@ fabric.PatternBrush = fabric.util.createClass(fabric.PencilBrush, /** @lends fab
*/
_setObjectScale: function(localMouse, transform, lockScalingX, lockScalingY, by, lockScalingFlip, _dim) {
var target = transform.target, forbidScalingX = false, forbidScalingY = false, scaled = false,
changeX, changeY, scaleX, scaleY;

scaleX = localMouse.x * target.scaleX / _dim.x;
scaleY = localMouse.y * target.scaleY / _dim.y;
changeX = target.scaleX !== scaleX;
changeY = target.scaleY !== scaleY;
scaleX = localMouse.x * target.scaleX / _dim.x,
scaleY = localMouse.y * target.scaleY / _dim.y,
changeX = target.scaleX !== scaleX,
changeY = target.scaleY !== scaleY;

if (lockScalingFlip && scaleX <= 0 && scaleX < target.scaleX) {
forbidScalingX = true;
Expand All @@ -10124,10 +10121,10 @@ fabric.PatternBrush = fabric.util.createClass(fabric.PencilBrush, /** @lends fab
forbidScalingY || lockScalingY || (target.set('scaleY', scaleY) && (scaled = scaled || changeY));
}
else if (by === 'x' && !target.get('lockUniScaling')) {
forbidScalingX || lockScalingX || (target.set('scaleX', scaleX) && (scaled = scaled || changeX));
forbidScalingX || lockScalingX || (target.set('scaleX', scaleX) && (scaled = changeX));
}
else if (by === 'y' && !target.get('lockUniScaling')) {
forbidScalingY || lockScalingY || (target.set('scaleY', scaleY) && (scaled = scaled || changeY));
forbidScalingY || lockScalingY || (target.set('scaleY', scaleY) && (scaled = changeY));
}
transform.newScaleX = scaleX;
transform.newScaleY = scaleY;
Expand All @@ -10145,15 +10142,15 @@ fabric.PatternBrush = fabric.util.createClass(fabric.PencilBrush, /** @lends fab
lastDist = _dim.y * transform.original.scaleY / target.scaleY +
_dim.x * transform.original.scaleX / target.scaleX,
scaled, signX = localMouse.x < 0 ? -1 : 1,
signY = localMouse.y < 0 ? -1 : 1;
signY = localMouse.y < 0 ? -1 : 1, newScaleX, newScaleY;

// We use transform.scaleX/Y instead of target.scaleX/Y
// because the object may have a min scale and we'll loose the proportions
transform.newScaleX = signX * Math.abs(transform.original.scaleX * dist / lastDist);
transform.newScaleY = signY * Math.abs(transform.original.scaleY * dist / lastDist);
scaled = transform.newScaleX !== target.scaleX || transform.newScaleY !== target.scaleY;
target.set('scaleX', transform.newScaleX);
target.set('scaleY', transform.newScaleY);
newScaleX = signX * Math.abs(transform.original.scaleX * dist / lastDist);
newScaleY = signY * Math.abs(transform.original.scaleY * dist / lastDist);
scaled = newScaleX !== target.scaleX || newScaleY !== target.scaleY;
target.set('scaleX', newScaleX);
target.set('scaleY', newScaleY);
return scaled;
},

Expand Down Expand Up @@ -12119,70 +12116,69 @@ fabric.PatternBrush = fabric.util.createClass(fabric.PencilBrush, /** @lends fab

var format = options.format || 'png',
quality = options.quality || 1,
multiplier = (options.multiplier || 1) * (options.enableRetinaScaling ? 1 : 1 / this.getRetinaScaling()),
cropping = {
left: options.left || 0,
top: options.top || 0,
width: options.width || 0,
height: options.height || 0,
};
return this.__toDataURLWithMultiplier(format, quality, cropping, multiplier);
},

/**
* @private
*/
__toDataURLWithMultiplier: function(format, quality, cropping, multiplier) {

var origWidth = this.width,
origHeight = this.height,
scaledWidth = (cropping.width || this.width) * multiplier,
multiplier = (options.multiplier || 1) * (options.enableRetinaScaling ? this.getRetinaScaling() : 1),
canvasEl = this.toCanvasElement(multiplier, options);
return this.__toDataURL(canvasEl, format, quality);
},

/**
* Create a new HTMLCanvas element painted with the current canvas content.
* No need to resize the actual one or repaint it.
* Will transfer object ownership to a new canvas, paint it, and set everything back.
* This is an intermediary step used to get to a dataUrl but also it is usefull to
* create quick image copies of a canvas without passing for the dataUrl string
* @param {Number} [multiplier] a zoom factor.
* @param {Object} [cropping] Cropping informations
* @param {Number} [cropping.left] Cropping left offset.
* @param {Number} [cropping.top] Cropping top offset.
* @param {Number} [cropping.width] Cropping width.
* @param {Number} [cropping.height] Cropping height.
*/
toCanvasElement: function(multiplier, cropping) {
multiplier = multiplier || 1;
cropping = cropping || { };
var scaledWidth = (cropping.width || this.width) * multiplier,
scaledHeight = (cropping.height || this.height) * multiplier,
zoom = this.getZoom(),
originalWidth = this.width,
originalHeight = this.height,
newZoom = zoom * multiplier,
vp = this.viewportTransform,
translateX = (vp[4] - cropping.left) * multiplier,
translateY = (vp[5] - cropping.top) * multiplier,
newVp = [newZoom, 0, 0, newZoom, translateX, translateY],
translateX = (vp[4] - (cropping.left || 0)) * multiplier,
translateY = (vp[5] - (cropping.top || 0)) * multiplier,
originalInteractive = this.interactive,
originalSkipOffScreen = this.skipOffscreen,
needsResize = origWidth !== scaledWidth || origHeight !== scaledHeight;

this.viewportTransform = newVp;
this.skipOffscreen = false;
// setting interactive to false avoid exporting controls
originalContext = this.contextContainer,
newVp = [newZoom, 0, 0, newZoom, translateX, translateY],
canvasEl = fabric.util.createCanvasElement();
canvasEl.width = scaledWidth;
canvasEl.height = scaledHeight;
this.interactive = false;
if (needsResize) {
this.setDimensions({ width: scaledWidth, height: scaledHeight }, { backstoreOnly: true });
}
// call a renderAll to force sync update. This will cancel the scheduled requestRenderAll
// from setDimensions
this.viewportTransform = newVp;
this.width = scaledWidth;
this.height = scaledHeight;
this.calcViewportBoundaries();
this.contextContainer = canvasEl.getContext('2d');
// will be renderAllExport();
this.renderAll();
var data = this.__toDataURL(format, quality, cropping);
this.interactive = originalInteractive;
this.skipOffscreen = originalSkipOffScreen;
this.viewportTransform = vp;
//setDimensions with no option object is taking care of:
//this.width, this.height, this.requestRenderAll()
if (needsResize) {
this.setDimensions({ width: origWidth, height: origHeight }, { backstoreOnly: true });
}
this.renderAll();
return data;
this.width = originalWidth;
this.height = originalHeight;
this.calcViewportBoundaries();
this.contextContainer = originalContext;
this.interactive = originalInteractive;
return canvasEl;
},

/**
* since 2.5.0 does not need to be on canvas instance anymore.
* leave it here for context;
* @private
*/
__toDataURL: function(format, quality) {

var canvasEl = this.contextContainer.canvas;
var data = supportQuality
__toDataURL: function(canvasEl, format, quality) {
return supportQuality
? canvasEl.toDataURL('image/' + format, quality)
: canvasEl.toDataURL('image/' + format);

return data;
},
}
});

})();
Expand Down Expand Up @@ -13781,18 +13777,19 @@ fabric.util.object.extend(fabric.StaticCanvas.prototype, /** @lends fabric.Stati
return;
}

var multX = (this.canvas && this.canvas.viewportTransform[0]) || 1,
multY = (this.canvas && this.canvas.viewportTransform[3]) || 1,
var shadow = this.shadow, canvas = this.canvas,
multX = (canvas && canvas.viewportTransform[0]) || 1,
multY = (canvas && canvas.viewportTransform[3]) || 1,
scaling = this.getObjectScaling();
if (this.canvas && this.canvas._isRetinaScaling()) {
if (canvas && canvas._isRetinaScaling()) {
multX *= fabric.devicePixelRatio;
multY *= fabric.devicePixelRatio;
}
ctx.shadowColor = this.shadow.color;
ctx.shadowBlur = this.shadow.blur * fabric.browserShadowBlurConstant *
ctx.shadowColor = shadow.color;
ctx.shadowBlur = shadow.blur * fabric.browserShadowBlurConstant *
(multX + multY) * (scaling.scaleX + scaling.scaleY) / 4;
ctx.shadowOffsetX = this.shadow.offsetX * multX * scaling.scaleX;
ctx.shadowOffsetY = this.shadow.offsetY * multY * scaling.scaleY;
ctx.shadowOffsetX = shadow.offsetX * multX * scaling.scaleX;
ctx.shadowOffsetY = shadow.offsetY * multY * scaling.scaleY;
},

/**
Expand All @@ -13812,6 +13809,8 @@ fabric.util.object.extend(fabric.StaticCanvas.prototype, /** @lends fabric.Stati
* @private
* @param {CanvasRenderingContext2D} ctx Context to render on
* @param {Object} filler fabric.Pattern or fabric.Gradient
* @return {Object} offset.offsetX offset for text rendering
* @return {Object} offset.offsetY offset for text rendering
*/
_applyPatternGradientTransform: function(ctx, filler) {
if (!filler || !filler.toLive) {
Expand Down Expand Up @@ -14785,7 +14784,7 @@ fabric.util.object.extend(fabric.StaticCanvas.prototype, /** @lends fabric.Stati
/**
* Checks if object is contained within the canvas with current viewportTransform
* the check is done stopping at first point that appears on screen
* @param {Boolean} [calculate] use coordinates of current position instead of .oCoords
* @param {Boolean} [calculate] use coordinates of current position instead of .aCoords
* @return {Boolean} true if object is fully or partially contained within canvas
*/
isOnScreen: function(calculate) {
Expand Down Expand Up @@ -29064,13 +29063,18 @@ fabric.util.object.extend(fabric.IText.prototype, /** @lends fabric.IText.protot
fabric.Canvas.prototype._setObjectScale = function(localMouse, transform,
lockScalingX, lockScalingY, by, lockScalingFlip, _dim) {

var t = transform.target;
var t = transform.target, scaled,
scaleX = localMouse.x * t.scaleX / _dim.x,
scaleY = localMouse.y * t.scaleY / _dim.y;
if (by === 'x' && t instanceof fabric.Textbox) {
var tw = t._getTransformedDimensions().x;
var w = t.width * (localMouse.x / tw);
transform.newScaleX = scaleX;
transform.newScaleY = scaleY;
if (w >= t.getMinWidth()) {
scaled = w !== t.width;
t.set('width', w);
return true;
return scaled;
}
}
else {
Expand Down