UNPKG

fabric

Version:

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

571 lines (476 loc) 21.1 kB
import { expect } from '@jest/globals'; import { getFabricDocument } from '../env'; import { FabricObject } from '../shapes/Object/FabricObject'; import { Gradient } from './Gradient'; import type { SVGOptions } from './typedefs'; import { classRegistry } from '../ClassRegistry'; 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); } it('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('rgb(0,0,0)'); expect(gradient.colorStops[1].color).toEqual('rgb(255,255,255)'); expect(gradient.colorStops[0].opacity).toEqual(0); }); 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('rgb(0,0,0)'); expect(gradient.colorStops[1].color).toEqual('rgb(255,255,255)'); expect(gradient.colorStops[0].opacity).toEqual(0); }); 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, {}); 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('rgb(0,0,0)'); expect(gradient.colorStops[1].color).toEqual('rgb(255,255,255)'); }); 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('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); }); 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('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); }); });