diff --git a/CHANGELOG.md b/CHANGELOG.md index bb07dee4451..3cc307aadf5 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,7 @@ ## [next] +- DRAFT WIP BREAKING: remove opacity from colorstops in live Gradient class [#9622](https://github.com/fabricjs/fabric.js/pull/9622) - feat(LayoutManager): Handle the case of activeSelection with objects inside different groups [#9651](https://github.com/fabricjs/fabric.js/pull/9651) ## [6.0.0-beta20] diff --git a/src/gradient/Gradient.spec.ts b/src/gradient/Gradient.spec.ts index ac053418252..d0f9702dba6 100644 --- a/src/gradient/Gradient.spec.ts +++ b/src/gradient/Gradient.spec.ts @@ -62,10 +62,8 @@ describe('Gradient', () => { expect(gradient.colorStops[0].offset).toEqual(1); expect(gradient.colorStops[1].offset).toEqual(0); - expect(gradient.colorStops[0].color).toEqual('rgb(0,0,0)'); - expect(gradient.colorStops[1].color).toEqual('rgb(255,255,255)'); - - expect(gradient.colorStops[0].opacity).toEqual(0); + expect(gradient.colorStops[0].color).toEqual('rgba(0,0,0,0)'); + expect(gradient.colorStops[1].color).toEqual('rgba(255,255,255,1)'); }); test('fromElement linearGradient with floats percentage - objectBoundingBox', () => { @@ -191,10 +189,8 @@ describe('Gradient', () => { expect(gradient.colorStops[0].offset).toEqual(1); expect(gradient.colorStops[1].offset).toEqual(0); - expect(gradient.colorStops[0].color).toEqual('rgb(0,0,0)'); - expect(gradient.colorStops[1].color).toEqual('rgb(255,255,255)'); - - expect(gradient.colorStops[0].opacity).toEqual(0); + expect(gradient.colorStops[0].color).toEqual('rgba(0,0,0,0)'); + expect(gradient.colorStops[1].color).toEqual('rgba(255,255,255,1)'); }); test('fromElement without stop', () => { @@ -392,7 +388,7 @@ describe('Gradient', () => { element.appendChild(stop2); const object = new FabricObject({ width: 100, height: 100 }); - const gradient = fromElement(element, object, {}); + const gradient = fromElement(element, object, {}) as Gradient<'radial'>; expect(gradient instanceof Gradient).toBeTruthy(); @@ -406,8 +402,8 @@ describe('Gradient', () => { expect(gradient.colorStops[0].offset).toEqual(1); expect(gradient.colorStops[1].offset).toEqual(0); - expect(gradient.colorStops[0].color).toEqual('rgb(0,0,0)'); - expect(gradient.colorStops[1].color).toEqual('rgb(255,255,255)'); + expect(gradient.colorStops[0].color).toEqual('rgba(0,0,0,1)'); + expect(gradient.colorStops[1].color).toEqual('rgba(255,255,255,1)'); }); test('fromElement radialGradient with transform', () => { @@ -495,15 +491,10 @@ describe('Gradient', () => { expect(gradient.colorStops[2].offset).toEqual(0.5); expect(gradient.colorStops[3].offset).toEqual(0); - expect(gradient.colorStops[0].color).toEqual('rgb(255,0,0)'); - expect(gradient.colorStops[1].color).toEqual('rgb(0,0,255)'); - expect(gradient.colorStops[2].color).toEqual('rgb(0,0,0)'); - expect(gradient.colorStops[3].color).toEqual('rgb(0,0,0)'); - - expect(gradient.colorStops[0].opacity).toEqual(0.5); - expect(gradient.colorStops[1].opacity).toEqual(0.9); - expect(gradient.colorStops[2].opacity).toEqual(1); - expect(gradient.colorStops[3].opacity).toEqual(1); + expect(gradient.colorStops[0].color).toEqual('rgba(255,0,0,0.5)'); + expect(gradient.colorStops[1].color).toEqual('rgba(0,0,255,0.9)'); + expect(gradient.colorStops[2].color).toEqual('rgba(0,0,0,1)'); + expect(gradient.colorStops[3].color).toEqual('rgba(0,0,0,1)'); }); test('fromElement radialGradient colorStop attributes/styles', () => { @@ -557,14 +548,9 @@ describe('Gradient', () => { expect(gradient.colorStops[2].offset).toEqual(0.5); expect(gradient.colorStops[3].offset).toEqual(0); - expect(gradient.colorStops[0].color).toEqual('rgb(255,0,0)'); - expect(gradient.colorStops[1].color).toEqual('rgb(0,0,255)'); - expect(gradient.colorStops[2].color).toEqual('rgb(0,0,0)'); - expect(gradient.colorStops[3].color).toEqual('rgb(0,0,0)'); - - expect(gradient.colorStops[0].opacity).toEqual(0.5); - expect(gradient.colorStops[1].opacity).toEqual(0.9); - expect(gradient.colorStops[2].opacity).toEqual(1); - expect(gradient.colorStops[3].opacity).toEqual(1); + expect(gradient.colorStops[0].color).toEqual('rgba(255,0,0,0.5)'); + expect(gradient.colorStops[1].color).toEqual('rgba(0,0,255,0.9)'); + expect(gradient.colorStops[2].color).toEqual('rgba(0,0,0,1)'); + expect(gradient.colorStops[3].color).toEqual('rgba(0,0,0,1)'); }); }); diff --git a/src/gradient/Gradient.ts b/src/gradient/Gradient.ts index 5d650ba4268..26b06ef8f6f 100644 --- a/src/gradient/Gradient.ts +++ b/src/gradient/Gradient.ts @@ -1,4 +1,3 @@ -import { Color } from '../color/Color'; import { iMatrix } from '../constants'; import { parseTransformAttribute } from '../parser/parseTransformAttribute'; import type { FabricObject } from '../shapes/Object/FabricObject'; @@ -133,11 +132,9 @@ export class Gradient< */ addColorStop(colorStops: Record) { for (const position in colorStops) { - const color = new Color(colorStops[position]); this.colorStops.push({ offset: parseFloat(position), - color: color.toRgb(), - opacity: color.getAlpha(), + color: colorStops[position], }); } return this; @@ -152,8 +149,8 @@ export class Gradient< return { ...pick(this, propertiesToInclude as (keyof this)[]), type: this.type, - coords: this.coords, - colorStops: this.colorStops, + coords: { ...this.coords }, + colorStops: this.colorStops.map((colorStop) => ({ ...colorStop })), offsetX: this.offsetX, offsetY: this.offsetY, gradientUnits: this.gradientUnits, @@ -269,15 +266,9 @@ export class Gradient< } } - colorStops.forEach(({ color, offset, opacity }) => { + colorStops.forEach(({ color, offset }) => { markup.push( - '\n' + `\n` ); }); @@ -309,13 +300,8 @@ export class Gradient< coords.r2 ); - this.colorStops.forEach(({ color, opacity, offset }) => { - gradient.addColorStop( - offset, - typeof opacity !== 'undefined' - ? new Color(color).setAlpha(opacity).toRgba() - : color - ); + this.colorStops.forEach(({ color, offset }) => { + gradient.addColorStop(offset, color); }); return gradient; diff --git a/src/gradient/parser/parseColorStops.ts b/src/gradient/parser/parseColorStops.ts index c97da3bcca6..d718440e143 100644 --- a/src/gradient/parser/parseColorStops.ts +++ b/src/gradient/parser/parseColorStops.ts @@ -6,8 +6,8 @@ import type { ColorStop } from '../typedefs'; const RE_KEY_VALUE_PAIRS = /\s*;\s*/; const RE_KEY_VALUE = /\s*:\s*/; -function parseColorStop(el: SVGStopElement, multiplier: number) { - let colorValue, opacity; +function parseColorStop(el: SVGStopElement, opacityMultiplier: number) { + let colorValue, opacityValue; const style = el.getAttribute('style'); if (style) { const keyValuePairs = style.split(RE_KEY_VALUE_PAIRS); @@ -23,22 +23,24 @@ function parseColorStop(el: SVGStopElement, multiplier: number) { if (key === 'stop-color') { colorValue = value; } else if (key === 'stop-opacity') { - opacity = value; + opacityValue = value; } } } - const color = new Color( - colorValue || el.getAttribute('stop-color') || 'rgb(0,0,0)' + colorValue = colorValue || el.getAttribute('stop-color') || 'rgb(0,0,0)'; + opacityValue = ifNaN( + parseFloat(opacityValue || el.getAttribute('stop-opacity') || ''), + 1 ); + const color = new Color(colorValue); + + color.setAlpha(color.getAlpha() * opacityValue * opacityMultiplier); + return { offset: parsePercent(el.getAttribute('offset'), 0), - color: color.toRgb(), - opacity: - ifNaN(parseFloat(opacity || el.getAttribute('stop-opacity') || ''), 1) * - color.getAlpha() * - multiplier, + color: color.toRgba(), }; } diff --git a/src/gradient/typedefs.ts b/src/gradient/typedefs.ts index 64930c7ff97..547fffdf3c9 100644 --- a/src/gradient/typedefs.ts +++ b/src/gradient/typedefs.ts @@ -9,7 +9,6 @@ export type GradientCoordValue = number | Percent | string; export type ColorStop = { color: string; offset: number; - opacity?: number; }; export type LinearGradientCoords = {