|
| 1 | +import type { IVegaChartRef } from '../interfaces'; |
| 2 | +import { combineCanvases, combineSVGs, getCompositeGridLayout } from './vegaApiExport'; |
| 3 | + |
| 4 | +const chartRef = (x: number, y: number, w: number, h: number): IVegaChartRef => ({ |
| 5 | + x, |
| 6 | + y, |
| 7 | + w, |
| 8 | + h, |
| 9 | + innerWidth: w, |
| 10 | + innerHeight: h, |
| 11 | + view: null, |
| 12 | + canvas: null, |
| 13 | +}); |
| 14 | + |
| 15 | +describe('Vega export composition', () => { |
| 16 | + test('lays out unequal grid cells using the largest item in each row and column', () => { |
| 17 | + const layout = getCompositeGridLayout([ |
| 18 | + { x: 0, y: 0, width: 100, height: 40 }, |
| 19 | + { x: 1, y: 0, width: 120, height: 50 }, |
| 20 | + { x: 0, y: 1, width: 90, height: 60 }, |
| 21 | + { x: 1, y: 1, width: 110, height: 55 }, |
| 22 | + ]); |
| 23 | + |
| 24 | + expect(layout).toEqual({ |
| 25 | + width: 220, |
| 26 | + height: 110, |
| 27 | + items: [ |
| 28 | + { x: 0, y: 0, width: 100, height: 40, offsetX: 0, offsetY: 0 }, |
| 29 | + { x: 1, y: 0, width: 120, height: 50, offsetX: 100, offsetY: 0 }, |
| 30 | + { x: 0, y: 1, width: 90, height: 60, offsetX: 0, offsetY: 50 }, |
| 31 | + { x: 1, y: 1, width: 110, height: 55, offsetX: 100, offsetY: 50 }, |
| 32 | + ], |
| 33 | + }); |
| 34 | + }); |
| 35 | + |
| 36 | + test('draws canvases into one image using their grid offsets', () => { |
| 37 | + const drawImage = jest.fn(); |
| 38 | + const combinedCanvas = { |
| 39 | + width: 0, |
| 40 | + height: 0, |
| 41 | + getContext: () => ({ drawImage }), |
| 42 | + }; |
| 43 | + const previousDocument = globalThis.document; |
| 44 | + Object.defineProperty(globalThis, 'document', { |
| 45 | + configurable: true, |
| 46 | + value: { |
| 47 | + createElement: (name: string) => { |
| 48 | + expect(name).toBe('canvas'); |
| 49 | + return combinedCanvas; |
| 50 | + }, |
| 51 | + }, |
| 52 | + }); |
| 53 | + |
| 54 | + try { |
| 55 | + const first = { width: 100, height: 40 } as HTMLCanvasElement; |
| 56 | + const second = { width: 120, height: 50 } as HTMLCanvasElement; |
| 57 | + const result = combineCanvases([first, second], [chartRef(0, 0, 100, 40), chartRef(1, 0, 120, 50)]); |
| 58 | + |
| 59 | + expect(result).toBe(combinedCanvas); |
| 60 | + expect(combinedCanvas.width).toBe(220); |
| 61 | + expect(combinedCanvas.height).toBe(50); |
| 62 | + expect(drawImage).toHaveBeenNthCalledWith(1, first, 0, 0); |
| 63 | + expect(drawImage).toHaveBeenNthCalledWith(2, second, 100, 0); |
| 64 | + } finally { |
| 65 | + Object.defineProperty(globalThis, 'document', { |
| 66 | + configurable: true, |
| 67 | + value: previousDocument, |
| 68 | + }); |
| 69 | + } |
| 70 | + }); |
| 71 | + |
| 72 | + test('combines repeated SVG views and namespaces their definitions', () => { |
| 73 | + const first = '<svg width="100" height="40"><defs><clipPath id="clip"><path /></clipPath></defs><g clip-path="url(#clip)" /></svg>'; |
| 74 | + const second = |
| 75 | + '<svg width="120" height="50"><defs><clipPath id="clip"><path /></clipPath></defs><g aria-labelledby="title"><title id="title">B</title><g clip-path="url(#clip)" /></g></svg>'; |
| 76 | + |
| 77 | + const combined = combineSVGs([first, second], [chartRef(0, 0, 100, 40), chartRef(1, 0, 120, 50)]); |
| 78 | + |
| 79 | + expect(combined).toContain('width="220" height="50" viewBox="0 0 220 50"'); |
| 80 | + expect(combined).toContain('<svg x="0" y="0" width="100" height="40">'); |
| 81 | + expect(combined).toContain('<svg x="100" y="0" width="120" height="50">'); |
| 82 | + expect(combined).toContain('id="gw-export-0-clip"'); |
| 83 | + expect(combined).toContain('url(#gw-export-0-clip)'); |
| 84 | + expect(combined).toContain('id="gw-export-1-clip"'); |
| 85 | + expect(combined).toContain('url(#gw-export-1-clip)'); |
| 86 | + expect(combined).toContain('aria-labelledby="gw-export-1-title"'); |
| 87 | + expect(combined).toContain('id="gw-export-1-title"'); |
| 88 | + }); |
| 89 | + |
| 90 | + test('keeps a single SVG unchanged', () => { |
| 91 | + const svg = '<svg width="100" height="40"><g /></svg>'; |
| 92 | + expect(combineSVGs([svg], [chartRef(0, 0, 100, 40)])).toBe(svg); |
| 93 | + }); |
| 94 | +}); |
0 commit comments