Skip to content

Commit

Permalink
v250 (fabricjs#5465)
Browse files Browse the repository at this point in the history
  • Loading branch information
asturur authored Jan 7, 2019
1 parent eb04d24 commit 6a3d1ff
Show file tree
Hide file tree
Showing 3 changed files with 102 additions and 92 deletions.
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

0 comments on commit 6a3d1ff

Please sign in to comment.