UNPKG

fabric

Version:

Object model for HTML5 canvas, and SVG-to-canvas parser. Backed by jsdom and node-canvas.

822 lines (698 loc) 29.7 kB
import { getFabricDocument } from '../env'; import { FabricObject } from '../shapes/Object/FabricObject'; import { Gradient } from './Gradient'; import type { GradientUnits, SVGOptions } from './typedefs'; import { classRegistry } from '../ClassRegistry'; import { describe, expect, it, test, vi } from 'vitest'; import { StaticCanvas } from '../canvas/StaticCanvas'; vi.mock('../util/internals/uid', () => ({ uid: () => 0, })); function createLinearGradient(units: GradientUnits = 'pixels', id?: string) { return new Gradient({ type: 'linear', id, gradientUnits: units, coords: { x1: 0, y1: 10, x2: 100, y2: 200, }, colorStops: [ { offset: 0, color: 'rgba(255,0,0,0)' }, { offset: 1, color: 'green' }, ], }); } function createRadialGradient(units: GradientUnits = 'pixels') { return new Gradient({ type: 'radial', gradientUnits: units, coords: { x1: 0, y1: 10, x2: 100, y2: 200, r1: 0, r2: 50, }, colorStops: [ { offset: 0, color: 'red' }, { offset: 1, color: 'rgba(0,255,0,0)' }, ], }); } function createRadialGradientWithInternalRadius() { return new Gradient({ type: 'radial', coords: { x1: 0, y1: 10, x2: 100, y2: 200, r1: 10, r2: 50, }, colorStops: [ { offset: 0, color: 'red' }, { offset: 1, color: 'rgba(0,255,0,0)' }, ], }); } function createRadialGradientSwapped() { return new Gradient({ type: 'radial', coords: { x1: 0, y1: 10, x2: 100, y2: 200, r1: 50, r2: 10, }, colorStops: [ { offset: 0, color: 'red' }, { offset: 1, color: 'rgba(0,255,0,0)' }, ], }); } const SVG_LINEAR = '<linearGradient id="SVGID_0" gradientUnits="userSpaceOnUse" gradientTransform="matrix(1 0 0 1 -50 -50)" x1="0" y1="10" x2="100" y2="200">\n<stop offset="0%" style="stop-color:rgba(255,0,0,0);"/>\n<stop offset="100%" style="stop-color:green;"/>\n</linearGradient>\n'; const SVG_RADIAL = '<radialGradient id="SVGID_0" gradientUnits="userSpaceOnUse" gradientTransform="matrix(1 0 0 1 -50 -50)" cx="100" cy="200" r="50" fx="0" fy="10">\n<stop offset="0%" style="stop-color:red;"/>\n<stop offset="100%" style="stop-color:rgba(0,255,0,0);"/>\n</radialGradient>\n'; const SVG_INTERNALRADIUS = '<radialGradient id="SVGID_0" gradientUnits="userSpaceOnUse" gradientTransform="matrix(1 0 0 1 -50 -50)" cx="100" cy="200" r="50" fx="0" fy="10">\n<stop offset="20%" style="stop-color:red;"/>\n<stop offset="100%" style="stop-color:rgba(0,255,0,0);"/>\n</radialGradient>\n'; const SVG_SWAPPED = '<radialGradient id="SVGID_0" gradientUnits="userSpaceOnUse" gradientTransform="matrix(1 0 0 1 -50 -50)" cx="0" cy="10" r="50" fx="100" fy="200">\n<stop offset="20%" style="stop-color:rgba(0,255,0,0);"/>\n<stop offset="100%" style="stop-color:red;"/>\n</radialGradient>\n'; const SVG_LINEAR_PERCENTAGE = '<linearGradient id="SVGID_0" gradientUnits="objectBoundingBox" gradientTransform="matrix(1 0 0 1 0 0)" x1="0" y1="10" x2="100" y2="200">\n<stop offset="0%" style="stop-color:rgba(255,0,0,0);"/>\n<stop offset="100%" style="stop-color:green;"/>\n</linearGradient>\n'; const SVG_RADIAL_PERCENTAGE = '<radialGradient id="SVGID_0" gradientUnits="objectBoundingBox" gradientTransform="matrix(1 0 0 1 0 0)" cx="100" cy="200" r="50" fx="0" fy="10">\n<stop offset="0%" style="stop-color:red;"/>\n<stop offset="100%" style="stop-color:rgba(0,255,0,0);"/>\n</radialGradient>\n'; describe('Gradient', () => { function fromElement( gradientDef: SVGGradientElement, obj: FabricObject, options: Partial<SVGOptions> = {}, ) { return Gradient.fromElement(gradientDef, obj, { width: 0, height: 0, viewBoxHeight: 0, viewBoxWidth: 0, opacity: 1, ...options, } as SVGOptions); } test('constructor linearGradient', () => { const gradient = createLinearGradient(); expect(gradient instanceof Gradient).toBe(true); }); test('constructor radialGradient', () => { const gradient = createRadialGradient(); expect(gradient instanceof Gradient).toBe(true); }); test('properties linearGradient', () => { const gradient = createLinearGradient(); expect(gradient.coords.x1).toBe(0); expect(gradient.coords.y1).toBe(10); expect(gradient.coords.x2).toBe(100); expect(gradient.coords.y2).toBe(200); expect(gradient.type).toBe('linear'); expect(gradient.colorStops[0].offset).toBe(0); expect(gradient.colorStops[0].color).toBe('rgba(255,0,0,0)'); expect(gradient.colorStops[1].offset).toBe(1); expect(gradient.colorStops[1].color).toBe('green'); }); test('toSVG', () => { const gradient = createLinearGradient(); expect(gradient.toSVG, 'toSVG function exists').toBeTruthy(); }); describe('SVG exports', () => { test('toSVG linear', () => { const gradient = createLinearGradient(); const baseObj = new FabricObject({ width: 100, height: 100 }); expect(gradient.toSVG(baseObj)).toEqual(SVG_LINEAR); }); test('toSVG radial', () => { const gradient = createRadialGradient(); const baseObj = new FabricObject({ width: 100, height: 100 }); expect(gradient.toSVG(baseObj)).toEqual(SVG_RADIAL); }); test('toSVG radial with r1 > 0', () => { const gradient = createRadialGradientWithInternalRadius(); const obj = new FabricObject({ width: 100, height: 100 }); expect(gradient.toSVG(obj)).toEqual(SVG_INTERNALRADIUS); }); test('toSVG radial with r1 > 0 swapped', () => { const gradient = createRadialGradientSwapped(); const obj = new FabricObject({ width: 100, height: 100 }); const gradientColorStops = JSON.stringify(gradient.colorStops); expect(gradient.toSVG(obj), 'it exports as expected').toBe(SVG_SWAPPED); const gradientColorStopsAfterExport = JSON.stringify(gradient.colorStops); expect(gradient.toSVG(obj), 'it exports as expected a second time').toBe( SVG_SWAPPED, ); expect(gradientColorStops, 'colorstops do not change').toBe( gradientColorStopsAfterExport, ); }); test('toSVG linear objectBoundingBox', () => { const gradient = createLinearGradient('percentage'); const obj = new FabricObject({ width: 100, height: 100 }); expect(gradient.toSVG(obj)).toBe(SVG_LINEAR_PERCENTAGE); }); test('toSVG radial objectBoundingBox', () => { const gradient = createRadialGradient('percentage'); const obj = new FabricObject({ width: 100, height: 100 }); expect(gradient.toSVG(obj)).toBe(SVG_RADIAL_PERCENTAGE); }); }); test('properties radialGradient', () => { const gradient = createRadialGradient(); expect(gradient.coords.x1).toBe(0); expect(gradient.coords.y1).toBe(10); expect(gradient.coords.x2).toBe(100); expect(gradient.coords.y2).toBe(200); expect(gradient.coords.r1).toBe(0); expect(gradient.coords.r2).toBe(50); expect(gradient.type, 'radial'); expect(gradient.colorStops[0].offset).toBe(0); expect(gradient.colorStops[0].color).toBe('red'); expect(gradient.colorStops[1].offset).toBe(1); expect(gradient.colorStops[1].color).toBe('rgba(0,255,0,0)'); }); test('toObject linearGradient', () => { const gradient = createLinearGradient(); gradient.gradientTransform = [1, 0, 0, 1, 50, 50]; expect(typeof gradient.toObject === 'function'); const object = gradient.toObject(); expect(object.coords).toEqual(gradient.coords); expect(object.coords, 'coords are not referenced').not.toBe( gradient.coords, ); expect(object.gradientUnits).toBe(gradient.gradientUnits); expect(object.type).toBe(gradient.type); expect(object.gradientTransform).toEqual(gradient.gradientTransform); expect(object.gradientTransform, 'matrix is not referenced').not.toBe( gradient.gradientTransform, ); expect(object.colorStops).toEqual(gradient.colorStops); expect(object.colorStops, 'colorStops are not referenced').not.toBe( gradient.colorStops, ); }); test('toObject with custom props', () => { const gradient = createLinearGradient('pixels', 'myId'); const object = gradient.toObject(['id']); expect(object.id).toBe('myId_0'); }); test('toObject radialGradient', () => { const gradient = createRadialGradient(); const object = gradient.toObject(); expect(object.coords).toEqual(gradient.coords); expect(object.coords).not.toBe(gradient.coords); expect(object.type).toBe(gradient.type); expect(object.colorStops).not.toBe(gradient.colorStops); expect(object.colorStops).toEqual(gradient.colorStops); }); test('toLive linearGradient', () => { const canvas = new StaticCanvas(undefined, { enableRetinaScaling: false, }); const gradient = createLinearGradient(); const gradientHTML = canvas.contextContainer.createLinearGradient( 0, 0, 1, 1, ); expect(gradient.toLive).toBeTruthy(); const gradientCtx = gradient.toLive(canvas.contextContainer); expect(gradientCtx.toString(), 'The type match').toEqual( gradientHTML.toString(), ); }); test('toLive radialGradient', () => { const canvas = new StaticCanvas(undefined, { enableRetinaScaling: false, }); const gradient = createRadialGradient(); const gradientHTML = canvas.contextContainer.createRadialGradient( 0, 0, 1, 1, 2, 2, ); const gradientCtx = gradient.toLive(canvas.contextContainer); expect(gradientCtx.toString(), 'is a gradient for canvas radial').toEqual( gradientHTML.toString(), ); }); test('registered in class registry', () => { expect(classRegistry.getClass('gradient')).toEqual(Gradient); expect(classRegistry.getClass('linear')).toEqual(Gradient); expect(classRegistry.getClass('radial')).toEqual(Gradient); }); test('fromElement linearGradient', () => { expect(typeof Gradient.fromElement === 'function').toBeTruthy(); const namespace = 'http://www.w3.org/2000/svg'; const element = getFabricDocument().createElementNS( namespace, 'linearGradient', ); const stop1 = getFabricDocument().createElement('stop'); const stop2 = getFabricDocument().createElement('stop'); stop1.setAttributeNS(namespace, 'offset', '0%'); stop1.setAttributeNS(namespace, 'stop-color', 'white'); stop2.setAttributeNS(namespace, 'offset', '100%'); stop2.setAttributeNS(namespace, 'stop-color', 'black'); stop2.setAttributeNS(namespace, 'stop-opacity', '0'); element.appendChild(stop1); element.appendChild(stop2); const object = new FabricObject({ width: 100, height: 100 }); const gradient = fromElement(element, object, { opacity: '' }); expect(gradient instanceof Gradient).toBeTruthy(); expect(gradient.type).toEqual('linear'); expect(gradient.coords.x1).toEqual(0); expect(gradient.coords.y1).toEqual(0); expect(gradient.coords.x2).toEqual(1); expect(gradient.coords.y2).toEqual(0); expect(gradient.gradientUnits).toEqual('percentage'); expect(gradient.colorStops[0].offset).toEqual(1); expect(gradient.colorStops[1].offset).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', () => { const namespace = 'http://www.w3.org/2000/svg'; const element = getFabricDocument().createElementNS( namespace, 'linearGradient', ); element.setAttributeNS(namespace, 'gradientUnits', 'objectBoundingBox'); element.setAttributeNS(namespace, 'x1', '10%'); element.setAttributeNS(namespace, 'y1', '0.2%'); element.setAttributeNS(namespace, 'x2', '200'); element.setAttributeNS(namespace, 'y2', '20%'); const stop1 = getFabricDocument().createElement('stop'); const stop2 = getFabricDocument().createElement('stop'); stop1.setAttributeNS(namespace, 'offset', '0%'); stop1.setAttributeNS(namespace, 'stop-color', 'white'); stop2.setAttributeNS(namespace, 'offset', '100%'); stop2.setAttributeNS(namespace, 'stop-color', 'black'); stop2.setAttributeNS(namespace, 'stop-opacity', '0'); element.appendChild(stop1); element.appendChild(stop2); const object = new FabricObject({ width: 200, height: 200 }); const gradient = fromElement(element, object, { opacity: '' }); expect(gradient instanceof Gradient).toBeTruthy(); expect(gradient.coords.x1).toEqual(0.1); expect(gradient.coords.y1).toEqual(0.002); expect(gradient.coords.x2).toEqual(200); expect(gradient.coords.y2).toEqual(0.2); expect(gradient.gradientUnits).toEqual('percentage'); }); test('fromElement linearGradient with floats percentage - userSpaceOnUse', () => { const namespace = 'http://www.w3.org/2000/svg'; const element = getFabricDocument().createElementNS( namespace, 'linearGradient', ); element.setAttributeNS(namespace, 'gradientUnits', 'userSpaceOnUse'); element.setAttributeNS(namespace, 'x1', '10%'); element.setAttributeNS(namespace, 'y1', '0.2%'); element.setAttributeNS(namespace, 'x2', '200'); element.setAttributeNS(namespace, 'y2', '20%'); const stop1 = getFabricDocument().createElement('stop'); const stop2 = getFabricDocument().createElement('stop'); stop1.setAttributeNS(namespace, 'offset', '0%'); stop1.setAttributeNS(namespace, 'stop-color', 'white'); stop2.setAttributeNS(namespace, 'offset', '100%'); stop2.setAttributeNS(namespace, 'stop-color', 'black'); stop2.setAttributeNS(namespace, 'stop-opacity', '0'); element.appendChild(stop1); element.appendChild(stop2); const object = new FabricObject({ left: 10, top: 15, width: 200, height: 200, }); const gradient = fromElement(element, object, { opacity: '', viewBoxWidth: 400, viewBoxHeight: 300, }); expect(gradient instanceof Gradient).toBeTruthy(); expect(gradient.gradientUnits).toEqual('pixels'); expect(gradient.offsetX).toEqual(-10); expect(gradient.offsetY).toEqual(-15); expect(gradient.coords.x1).toEqual(40); expect(gradient.coords.y1).toEqual(0.6); expect(gradient.coords.x2).toEqual(200); expect(gradient.coords.y2).toEqual(60); }); test('fromElement linearGradient with Infinity', () => { const namespace = 'http://www.w3.org/2000/svg'; const element = getFabricDocument().createElementNS( namespace, 'linearGradient', ); const stop1 = getFabricDocument().createElementNS(namespace, 'stop'); const stop2 = getFabricDocument().createElementNS(namespace, 'stop'); stop1.setAttributeNS(namespace, 'offset', '0%'); stop1.setAttributeNS(namespace, 'stop-color', 'white'); stop2.setAttributeNS(namespace, 'offset', '100%'); stop2.setAttributeNS(namespace, 'stop-color', 'black'); stop2.setAttributeNS(namespace, 'stop-opacity', '0'); element.setAttributeNS(namespace, 'x1', '-Infinity'); element.setAttributeNS(namespace, 'x2', 'Infinity'); element.setAttributeNS(namespace, 'y1', 'Infinity'); element.setAttributeNS(namespace, 'y2', '-Infinity'); element.appendChild(stop1); element.appendChild(stop2); const object = new FabricObject({ width: 100, height: 300, top: 20, left: 30, }); const gradient = fromElement(element, object, { opacity: '' }); expect(gradient instanceof Gradient).toBeTruthy(); expect(gradient.coords.x1).toEqual(0); expect(gradient.coords.y1).toEqual(1); expect(gradient.coords.x2).toEqual(1); expect(gradient.coords.y2).toEqual(0); expect(gradient.colorStops[0].offset).toEqual(1); expect(gradient.colorStops[1].offset).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', () => { const namespace = 'http://www.w3.org/2000/svg'; const element = getFabricDocument().createElementNS( namespace, 'linearGradient', ); const stop1 = getFabricDocument().createElementNS(namespace, 'stop'); const stop2 = getFabricDocument().createElementNS(namespace, 'stop'); stop1.setAttributeNS(namespace, 'stop-color', 'white'); stop2.setAttributeNS(namespace, 'offset', '100%'); stop2.setAttributeNS(namespace, 'stop-color', 'black'); stop2.setAttributeNS(namespace, 'stop-opacity', '0'); element.appendChild(stop1); element.appendChild(stop2); const object = new FabricObject({ width: 100, height: 100 }); const gradient = fromElement(element, object, { opacity: '' }); expect(gradient instanceof Gradient).toBeTruthy(); expect(gradient.colorStops[0].offset).toEqual(1); expect(gradient.colorStops[1].offset).toEqual(0); }); describe('fromElement with x1,x2,y1,2 linear', () => { const namespace = 'http://www.w3.org/2000/svg'; const element = getFabricDocument().createElementNS( namespace, 'linearGradient', ); element.setAttributeNS(namespace, 'x1', '30%'); element.setAttributeNS(namespace, 'x2', '20%'); element.setAttributeNS(namespace, 'y1', '0.1'); element.setAttributeNS(namespace, 'y2', 'Infinity'); const object = new FabricObject({ width: 200, height: 200 }); const gradient = fromElement(element, object, { opacity: '' }); expect(gradient.coords.x1).toEqual(0.3); expect(gradient.coords.y1).toEqual(0.1); expect(gradient.coords.x2).toEqual(0.2); expect(gradient.coords.y2).toEqual(1); it('top and left do not change the output', () => { const object = new FabricObject({ width: 200, height: 200, top: 50, left: 10, }); const gradient = fromElement(element, object, { opacity: '' }); expect(gradient.coords.x1).toEqual(0.3); expect(gradient.coords.y1).toEqual(0.1); expect(gradient.coords.x2).toEqual(0.2); expect(gradient.coords.y2).toEqual(1); }); }); describe('fromElement with x1,x2,y1,2 radial', () => { const namespace = 'http://www.w3.org/2000/svg'; const element = getFabricDocument().createElementNS( namespace, 'radialGradient', ); element.setAttributeNS(namespace, 'fx', '30%'); element.setAttributeNS(namespace, 'fy', '20%'); element.setAttributeNS(namespace, 'cx', '0.1'); element.setAttributeNS(namespace, 'cy', '1'); element.setAttributeNS(namespace, 'r', '100%'); let object = new FabricObject({ width: 200, height: 200 }); let gradient = fromElement(element, object, { opacity: '' }); it('should not change with width height', () => { expect(gradient.coords.x1).toEqual(0.3); expect(gradient.coords.y1).toEqual(0.2); expect(gradient.coords.x2).toEqual(0.1); expect(gradient.coords.y2).toEqual(1); expect(gradient.coords.r1).toEqual(0); expect(gradient.coords.r2).toEqual(1); }); it('should not change with top left', () => { object = new FabricObject({ width: 200, height: 200, top: 10, left: 10 }); gradient = fromElement(element, object, { opacity: '' }); expect(gradient.coords.x1).toEqual(0.3); expect(gradient.coords.y1).toEqual(0.2); expect(gradient.coords.x2).toEqual(0.1); expect(gradient.coords.y2).toEqual(1); expect(gradient.coords.r1).toEqual(0); expect(gradient.coords.r2).toEqual(1); }); }); describe('fromElement with x1,x2,y1,2 radial userSpaceOnUse', () => { const namespace = 'http://www.w3.org/2000/svg'; const element = getFabricDocument().createElementNS( namespace, 'radialGradient', ); element.setAttributeNS(namespace, 'fx', '30'); element.setAttributeNS(namespace, 'fy', '20'); element.setAttributeNS(namespace, 'cx', '15'); element.setAttributeNS(namespace, 'cy', '18'); element.setAttributeNS(namespace, 'r', '100'); element.setAttributeNS(namespace, 'gradientUnits', 'userSpaceOnUse'); it('should not change with width height', () => { const object = new FabricObject({ width: 200, height: 200 }); const gradient = fromElement(element, object, { opacity: '' }); expect(gradient.coords.x1).toEqual(30); expect(gradient.coords.y1).toEqual(20); expect(gradient.coords.x2).toEqual(15); expect(gradient.coords.y2).toEqual(18); expect(gradient.coords.r1).toEqual(0); expect(gradient.coords.r2).toEqual(100); }); it('should not change with top left', () => { const object = new FabricObject({ width: 200, height: 200, top: 50, left: 60, }); const gradient = fromElement(element, object, { opacity: '' }); expect(gradient.coords.x1).toEqual(30); expect(gradient.coords.y1).toEqual(20); expect(gradient.coords.x2).toEqual(15); expect(gradient.coords.y2).toEqual(18); expect(gradient.coords.r1).toEqual(0); expect(gradient.coords.r2).toEqual(100); }); }); describe('fromElement with x1,x2,y1,2 linear userSpaceOnUse', () => { const namespace = 'http://www.w3.org/2000/svg'; const element = getFabricDocument().createElementNS( namespace, 'linearGradient', ); element.setAttributeNS(namespace, 'x1', '30'); element.setAttributeNS(namespace, 'y1', '20'); element.setAttributeNS(namespace, 'x2', '15'); element.setAttributeNS(namespace, 'y2', '18'); element.setAttributeNS(namespace, 'gradientUnits', 'userSpaceOnUse'); it('should not change with width height', () => { const object = new FabricObject({ width: 200, height: 200 }); const gradient = fromElement(element, object, { opacity: '' }); expect(gradient.coords.x1).toEqual(30); expect(gradient.coords.y1).toEqual(20); expect(gradient.coords.x2).toEqual(15); expect(gradient.coords.y2).toEqual(18); }); it('should not change with top left', () => { const object = new FabricObject({ width: 200, height: 200, top: 40, left: 40, }); const gradient = fromElement(element, object, { opacity: '' }); expect(gradient.coords.x1).toEqual(30); expect(gradient.coords.y1).toEqual(20); expect(gradient.coords.x2).toEqual(15); expect(gradient.coords.y2).toEqual(18); }); }); test('fromElement radialGradient defaults', () => { const namespace = 'http://www.w3.org/2000/svg'; const element = getFabricDocument().createElementNS( namespace, 'radialGradient', ); const stop1 = getFabricDocument().createElementNS(namespace, 'stop'); const stop2 = getFabricDocument().createElementNS(namespace, 'stop'); stop1.setAttributeNS(namespace, 'offset', '0%'); stop1.setAttributeNS(namespace, 'stop-color', 'white'); stop2.setAttributeNS(namespace, 'offset', '100%'); stop2.setAttributeNS(namespace, 'stop-color', 'black'); element.appendChild(stop1); element.appendChild(stop2); const object = new FabricObject({ width: 100, height: 100 }); const gradient = fromElement(element, object, {}) as Gradient<'radial'>; expect(gradient instanceof Gradient).toBeTruthy(); expect(gradient.coords.x1).toEqual(0.5); expect(gradient.coords.y1).toEqual(0.5); expect(gradient.coords.x2).toEqual(0.5); expect(gradient.coords.y2).toEqual(0.5); expect(gradient.coords.r1).toEqual(0); expect(gradient.coords.r2).toEqual(0.5); expect(gradient.colorStops[0].offset).toEqual(1); expect(gradient.colorStops[1].offset).toEqual(0); 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', () => { const namespace = 'http://www.w3.org/2000/svg'; const element = getFabricDocument().createElementNS( namespace, 'radialGradient', ); const stop1 = getFabricDocument().createElementNS(namespace, 'stop'); const stop2 = getFabricDocument().createElementNS(namespace, 'stop'); stop1.setAttributeNS(namespace, 'offset', '0%'); stop1.setAttributeNS(namespace, 'stop-color', 'white'); stop2.setAttributeNS(namespace, 'offset', '100%'); stop2.setAttributeNS(namespace, 'stop-color', 'black'); element.appendChild(stop1); element.appendChild(stop2); element.setAttributeNS( namespace, 'gradientTransform', 'matrix(3.321 -0.6998 0.4077 1.9347 -440.9168 -408.0598)', ); const object = new FabricObject({ width: 100, height: 100 }); const gradient = fromElement(element, object, {}); expect(gradient.gradientTransform).toEqual([ 3.321, -0.6998, 0.4077, 1.9347, -440.9168, -408.0598, ]); }); test('fromElement linearGradient colorStop attributes/styles', () => { const namespace = 'http://www.w3.org/2000/svg'; const element = getFabricDocument().createElementNS( namespace, 'linearGradient', ); const stop1 = getFabricDocument().createElementNS(namespace, 'stop'); const stop2 = getFabricDocument().createElementNS(namespace, 'stop'); const stop3 = getFabricDocument().createElementNS(namespace, 'stop'); const stop4 = getFabricDocument().createElementNS(namespace, 'stop'); stop1.setAttributeNS(namespace, 'offset', '0%'); stop1.setAttributeNS(namespace, 'stop-color', ''); stop1.setAttributeNS(namespace, 'stop-opacity', ''); stop2.setAttributeNS(namespace, 'offset', '0.5'); stop2.setAttributeNS( namespace, 'style', 'stop-color: black; stop-opacity:;', ); stop2.setAttributeNS(namespace, 'stop-color', 'white'); stop3.setAttributeNS(namespace, 'offset', '75%'); stop3.setAttributeNS(namespace, 'style', 'stop-color:; stop-opacity:;'); stop3.setAttributeNS(namespace, 'stop-opacity', '0.9'); stop3.setAttributeNS(namespace, 'stop-color', 'blue'); stop4.setAttributeNS(namespace, 'offset', '100%'); stop4.setAttributeNS( namespace, 'style', 'stop-color: red; stop-opacity: 0.5;', ); stop4.setAttributeNS(namespace, 'stop-opacity', '0.9'); element.appendChild(stop1); element.appendChild(stop2); element.appendChild(stop3); element.appendChild(stop4); const object = new FabricObject({ width: 100, height: 100 }); const gradient = fromElement(element, object, { opacity: '' }); expect(gradient instanceof Gradient).toBeTruthy(); expect(gradient.coords.x1).toEqual(0); expect(gradient.coords.y1).toEqual(0); expect(gradient.coords.x2).toEqual(1); expect(gradient.coords.y2).toEqual(0); expect(gradient.colorStops[0].offset).toEqual(1); expect(gradient.colorStops[1].offset).toEqual(0.75); expect(gradient.colorStops[2].offset).toEqual(0.5); expect(gradient.colorStops[3].offset).toEqual(0); 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', () => { const namespace = 'http://www.w3.org/2000/svg'; const element = getFabricDocument().createElementNS( namespace, 'radialGradient', ); const stop1 = getFabricDocument().createElementNS(namespace, 'stop'); const stop2 = getFabricDocument().createElementNS(namespace, 'stop'); const stop3 = getFabricDocument().createElementNS(namespace, 'stop'); const stop4 = getFabricDocument().createElementNS(namespace, 'stop'); stop1.setAttributeNS(namespace, 'offset', '0%'); stop1.setAttributeNS(namespace, 'stop-color', ''); stop1.setAttributeNS(namespace, 'stop-opacity', ''); stop2.setAttributeNS(namespace, 'offset', '0.5'); stop2.setAttributeNS( namespace, 'style', 'stop-color: black; stop-opacity:;', ); stop2.setAttributeNS(namespace, 'stop-color', 'white'); stop3.setAttributeNS(namespace, 'offset', '75%'); stop3.setAttributeNS(namespace, 'style', 'stop-color:; stop-opacity:;'); stop3.setAttributeNS(namespace, 'stop-opacity', '0.9'); stop3.setAttributeNS(namespace, 'stop-color', 'blue'); stop4.setAttributeNS(namespace, 'offset', '100%'); stop4.setAttributeNS( namespace, 'style', 'stop-color: red; stop-opacity: 0.5;', ); stop4.setAttributeNS(namespace, 'stop-opacity', '0.9'); element.appendChild(stop1); element.appendChild(stop2); element.appendChild(stop3); element.appendChild(stop4); const object = new FabricObject({ width: 100, height: 100 }); const gradient = fromElement(element, object, { opacity: '' }); expect(gradient instanceof Gradient).toBeTruthy(); expect(gradient.colorStops[0].offset).toEqual(1); expect(gradient.colorStops[1].offset).toEqual(0.75); expect(gradient.colorStops[2].offset).toEqual(0.5); expect(gradient.colorStops[3].offset).toEqual(0); 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)'); }); });