diff --git a/src/gradient.class.js b/src/gradient.class.js index 720ad9768e9..fa0dd7b95c8 100644 --- a/src/gradient.class.js +++ b/src/gradient.class.js @@ -317,28 +317,34 @@ /** * Returns an instance of CanvasGradient * @param {CanvasRenderingContext2D} ctx Context to render on + * @param {fabric.Object} object the fabric.Object for which the gradient is * @return {CanvasGradient} */ - toLive: function(ctx) { - var gradient, coords = fabric.util.object.clone(this.coords), i, len; + toLive: function(ctx, object) { + var gradient, coords = fabric.util.object.clone(this.coords), i, len, + x1 = coords.x1, y1 = coords.y1, x2 = coords.x2, y2 = coords.y2, + stops = this.colorStops; if (!this.type) { return; } + if (object instanceof fabric.Text && this.gradientUnits === 'percentage') { + x1 *= object.width; + y1 *= object.height; + x2 *= object.width; + y2 *= object.height; + } if (this.type === 'linear') { - gradient = ctx.createLinearGradient( - coords.x1, coords.y1, coords.x2, coords.y2); + gradient = ctx.createLinearGradient(x1, y1, x2, y2); } else if (this.type === 'radial') { - gradient = ctx.createRadialGradient( - coords.x1, coords.y1, coords.r1, coords.x2, coords.y2, coords.r2); + gradient = ctx.createRadialGradient(x1, y1, coords.r1, x2, y2, coords.r2); } - - for (i = 0, len = this.colorStops.length; i < len; i++) { - var color = this.colorStops[i].color, - opacity = this.colorStops[i].opacity, - offset = this.colorStops[i].offset; + for (i = 0, len = stops.length; i < len; i++) { + var color = stops[i].color, + opacity = stops[i].opacity, + offset = stops[i].offset; if (typeof opacity !== 'undefined') { color = new fabric.Color(color).setAlpha(opacity).toRgba(); diff --git a/src/shapes/text.class.js b/src/shapes/text.class.js index 233fd15538d..ada5d009c4e 100644 --- a/src/shapes/text.class.js +++ b/src/shapes/text.class.js @@ -817,6 +817,24 @@ return -this.height / 2; }, + /** + * @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) { + return { offsetX: 0, offsetY: 0 }; + } + var offsetX = -this.width / 2 + filler.offsetX || 0, + offsetY = -this.height / 2 + filler.offsetY || 0; + + ctx.transform(1, 0, 0, 1, offsetX, offsetY); + return { offsetX: offsetX, offsetY: offsetY }; + }, + /** * @private * @param {CanvasRenderingContext2D} ctx Context to render on diff --git a/test/visual/golden/text7.png b/test/visual/golden/text7.png new file mode 100644 index 00000000000..10198be0f1d Binary files /dev/null and b/test/visual/golden/text7.png differ diff --git a/test/visual/text.js b/test/visual/text.js index d8d2ee40bc1..c61faf78081 100644 --- a/test/visual/text.js +++ b/test/visual/text.js @@ -212,5 +212,41 @@ percentage: 0.06, }); + function text7(canvas, callback) { + var gradient = new fabric.Gradient({ + coords: { + x1: 0, + y1: 0, + x2: 1, + y2: 0 + }, + gradientUnits: 'percentage', + colorStops: [{ + offset: 0, + color: 'red', + }, { + offset: 1, + color: 'blue' + }] + }); + var text = new fabric.Text('PERCENTAGE GRADIENT\nPERCENTAGE GRADIENT\nPERCENTAGE GRADIENT', { + left: 0, + top: 0, + fontSize: 16, + fill: gradient, + }); + canvas.add(text); + canvas.renderAll(); + callback(canvas.lowerCanvasEl); + } + + tests.push({ + test: 'Text percentage gradient', + code: text7, + golden: 'text7.png', + disabled: !fabric.isLikelyNode, + percentage: 0.05, + }); + tests.forEach(visualTestLoop(QUnit)); })();