From 35cc427d3695a9649a1af958c7f6c82f72da02f3 Mon Sep 17 00:00:00 2001 From: gka Date: Sun, 25 May 2025 18:31:44 +0200 Subject: [PATCH 01/42] refine graticule mark props --- src/lib/marks/Graticule.svelte | 20 ++++++++++++-------- 1 file changed, 12 insertions(+), 8 deletions(-) diff --git a/src/lib/marks/Graticule.svelte b/src/lib/marks/Graticule.svelte index aa6ae92d..05d4c9c0 100644 --- a/src/lib/marks/Graticule.svelte +++ b/src/lib/marks/Graticule.svelte @@ -1,8 +1,18 @@ + + - - From 7ab586bfbb9bd1ee71dc0a0135cb535f7642a40f Mon Sep 17 00:00:00 2001 From: gka Date: Sun, 25 May 2025 18:42:35 +0200 Subject: [PATCH 03/42] refine & export arrow mark props --- src/lib/marks/Arrow.svelte | 46 ++++++++++++++++---------------- src/lib/types.ts | 54 +++++++++++++++++++------------------- 2 files changed, 50 insertions(+), 50 deletions(-) diff --git a/src/lib/marks/Arrow.svelte b/src/lib/marks/Arrow.svelte index 211a176d..c8197cb1 100644 --- a/src/lib/marks/Arrow.svelte +++ b/src/lib/marks/Arrow.svelte @@ -1,32 +1,14 @@ - + + + @@ -102,7 +107,12 @@ You can compare the metric to a different "baseline" by providing a constant _y1 ```svelte live @@ -80,10 +82,11 @@ The meaning of the interval mark option depends on the associated mark, such as const DAY_MONTH = new Intl.DateTimeFormat('en-US', { day: 'numeric', - month: 'short', + month: 'short' }); - const tickFormat = (date: Date) => DAY_MONTH.format(date).split(' ').reverse(); + const tickFormat = (date: Date) => + DAY_MONTH.format(date).split(' ').reverse(); diff --git a/src/tests/barX.test.svelte b/src/tests/barX.test.svelte index c642cfe5..d16a8d1c 100644 --- a/src/tests/barX.test.svelte +++ b/src/tests/barX.test.svelte @@ -6,7 +6,7 @@ plotArgs: ComponentProps; barArgs: ComponentProps; } - + let { plotArgs, barArgs }: Props = $props(); diff --git a/src/tests/barX.test.ts b/src/tests/barX.test.ts index 8884e19e..5b186d83 100644 --- a/src/tests/barX.test.ts +++ b/src/tests/barX.test.ts @@ -3,15 +3,18 @@ import { render } from '@testing-library/svelte'; import BarXTest from './barX.test.svelte'; import { parseSVG, makeAbsolute } from 'svg-path-parser'; -const testData = [{ - year: '2010', - low: 2, - high: 5 -}, { - year: '2011', - low: 4, - high: 7 -}] +const testData = [ + { + year: '2010', + low: 2, + high: 5 + }, + { + year: '2011', + low: 4, + high: 7 + } +]; describe('BarX mark', () => { it('simple bar chart from number array', () => { @@ -29,10 +32,16 @@ describe('BarX mark', () => { expect(bars.length).toBe(5); const barDims = Array.from(bars).map(getRectDims); // check that bar height are equal - expect(barDims.map(d => d.h)).toStrictEqual(new Array(5).fill(barDims[0].h)) + expect(barDims.map((d) => d.h)).toStrictEqual(new Array(5).fill(barDims[0].h)); // check that bar length match data - expect(barDims.map(d => d.w)).toStrictEqual([1, 2, 3, 4, 5].map(m => barDims[0].w * m)) - expect(barDims.map(d => d.strokeWidth)).toStrictEqual(['1px', '2px', '3px', '4px', '5px']); + expect(barDims.map((d) => d.w)).toStrictEqual([1, 2, 3, 4, 5].map((m) => barDims[0].w * m)); + expect(barDims.map((d) => d.strokeWidth)).toStrictEqual([ + '1px', + '2px', + '3px', + '4px', + '5px' + ]); }); it('bar chart from objects', () => { @@ -71,9 +80,9 @@ describe('BarX mark', () => { expect(bars.length).toBe(5); const barDims = Array.from(bars).map(getPathDims); // // check that bar height are equal - expect(barDims.map(d => d.h)).toStrictEqual(new Array(5).fill(barDims[0].h)) + expect(barDims.map((d) => d.h)).toStrictEqual(new Array(5).fill(barDims[0].h)); // // check that bar length match data - expect(barDims.map(d => d.w)).toStrictEqual([1, 2, 3, 4, 5].map(m => barDims[0].w * m)) + expect(barDims.map((d) => d.w)).toStrictEqual([1, 2, 3, 4, 5].map((m) => barDims[0].w * m)); }); }); @@ -88,14 +97,14 @@ function getRectDims(rect: SVGRectElement) { h: Math.round(+rect.getAttribute('height')), fill: rect.style.fill, stroke: rect.style.stroke, - strokeWidth: rect.style.strokeWidth, - } + strokeWidth: rect.style.strokeWidth + }; } function getPathDims(path: SVGPathElement) { const r = makeAbsolute(parseSVG(path.getAttribute('d'))); - const x = r.flatMap(d => [d.x, d.x0, d.x1]).filter(x => x != null); - const y = r.flatMap(d => [d.y, d.y0, d.y1]).filter(y => y != null); + const x = r.flatMap((d) => [d.x, d.x0, d.x1]).filter((x) => x != null); + const y = r.flatMap((d) => [d.y, d.y0, d.y1]).filter((y) => y != null); const t = path ?.getAttribute('transform') ?.match(/translate\((\d+(?:\.\d+)?),(\d+(?:\.\d+)?)\)/); @@ -107,6 +116,6 @@ function getPathDims(path: SVGPathElement) { h: Math.round(Math.max(...y) - Math.min(...y)), fill: path.style.fill, stroke: path.style.stroke, - strokeWidth: path.style.strokeWidth, + strokeWidth: path.style.strokeWidth }; } diff --git a/src/tests/barY.test.ts b/src/tests/barY.test.ts index 972d6452..118b2725 100644 --- a/src/tests/barY.test.ts +++ b/src/tests/barY.test.ts @@ -27,7 +27,13 @@ describe('BarY mark', () => { expect(barDims[2].h).toBe(barDims[0].h * 3); expect(barDims[3].h).toBe(barDims[0].h * 4); expect(barDims[4].h).toBe(barDims[0].h * 5); - expect(barDims.map(d => d.strokeWidth)).toStrictEqual(['1px', '2px', '3px', '4px', '5px']); + expect(barDims.map((d) => d.strokeWidth)).toStrictEqual([ + '1px', + '2px', + '3px', + '4px', + '5px' + ]); }); it('stacked bar chart', () => { @@ -117,14 +123,14 @@ function getRectDims(rect: SVGRectElement) { h: Math.round(+rect.getAttribute('height')), fill: rect.style.fill, stroke: rect.style.stroke, - strokeWidth: rect.style.strokeWidth, - } + strokeWidth: rect.style.strokeWidth + }; } function getPathDims(path: SVGPathElement) { const r = makeAbsolute(parseSVG(path.getAttribute('d'))); - const x = r.flatMap(d => [d.x, d.x0, d.x1]).filter(x => x != null); - const y = r.flatMap(d => [d.y, d.y0, d.y1]).filter(y => y != null); + const x = r.flatMap((d) => [d.x, d.x0, d.x1]).filter((x) => x != null); + const y = r.flatMap((d) => [d.y, d.y0, d.y1]).filter((y) => y != null); const t = path ?.getAttribute('transform') ?.match(/translate\((\d+(?:\.\d+)?),(\d+(?:\.\d+)?)\)/); @@ -136,6 +142,6 @@ function getPathDims(path: SVGPathElement) { h: Math.round(Math.max(...y) - Math.min(...y)), fill: path.style.fill, stroke: path.style.stroke, - strokeWidth: path.style.strokeWidth, + strokeWidth: path.style.strokeWidth }; } diff --git a/src/tests/brush.svelte.test.ts b/src/tests/brush.svelte.test.ts index 956c0998..f2eaaca4 100644 --- a/src/tests/brush.svelte.test.ts +++ b/src/tests/brush.svelte.test.ts @@ -4,14 +4,13 @@ import { userEvent } from '@testing-library/user-event'; import BrushTest from './brush.test.svelte'; import { tick, type ComponentProps } from 'svelte'; - describe('Brush mark', () => { it('single brush with basic properties', async () => { const props: ComponentProps = $state({ plotArgs: { x: { domain: [0, 10] }, y: { domain: [0, 10] } }, brushArgs: {}, brush: { enabled: false } - }) + }); const { container } = render(BrushTest, props); @@ -21,12 +20,11 @@ describe('Brush mark', () => { }); it('brush reacts to state changes', async () => { - const props: ComponentProps = $state({ plotArgs: { x: { domain: [0, 10] }, y: { domain: [0, 10] } }, brushArgs: {}, brush: { enabled: false } - }) + }); const { container } = render(BrushTest, props); @@ -48,7 +46,7 @@ describe('Brush mark', () => { plotArgs: { width: 400, x: { domain: [0, 10] }, y: { domain: [0, 10] } }, brushArgs: {}, brush: { enabled: false } - }) + }); const { container } = render(BrushTest, props); @@ -81,6 +79,4 @@ describe('Brush mark', () => { const draggedRect = container.querySelectorAll('rect.brush-rect'); expect(draggedRect.length).toBe(1); }); - - }); diff --git a/src/tests/colors.test.ts b/src/tests/colors.test.ts index 14204cbf..4229456b 100644 --- a/src/tests/colors.test.ts +++ b/src/tests/colors.test.ts @@ -10,11 +10,15 @@ describe('Colors', () => { const { container } = render(ColorsTest, { props: { dotOptions: { - data: [{ - x: 1, sex: 'male' - }, { - x: 2, sex: 'female' - } + data: [ + { + x: 1, + sex: 'male' + }, + { + x: 2, + sex: 'female' + } ], x: 'x', y: 0, @@ -34,13 +38,19 @@ describe('Colors', () => { const { container } = render(ColorsTest, { props: { dotOptions: { - data: [{ - x: 1, sex: 'male' - }, { - x: 2, sex: 'female' - }, { - x: 3, sex: 'in-between' - } + data: [ + { + x: 1, + sex: 'male' + }, + { + x: 2, + sex: 'female' + }, + { + x: 3, + sex: 'in-between' + } ], x: 'x', y: 0, @@ -66,6 +76,6 @@ describe('Colors', () => { function getDotStyle(path: SVGPathElement) { return { fill: path.style.fill, - stroke: path.style.stroke, - } + stroke: path.style.stroke + }; } diff --git a/src/tests/gridX.test.svelte b/src/tests/gridX.test.svelte index 575fb611..6df26db0 100644 --- a/src/tests/gridX.test.svelte +++ b/src/tests/gridX.test.svelte @@ -1,15 +1,15 @@ - + diff --git a/src/tests/gridX.test.ts b/src/tests/gridX.test.ts index 3d7645c8..42c34fea 100644 --- a/src/tests/gridX.test.ts +++ b/src/tests/gridX.test.ts @@ -2,27 +2,28 @@ import { describe, it, expect } from 'vitest'; import { render } from '@testing-library/svelte'; import GridXTest from './gridX.test.svelte'; - describe('GridX mark', () => { - it('simple x grid with stroke styles', () => { - const { container } = render(GridXTest, { - props: { - plotArgs: { - x: { domain: [0, 10] }, - y: { domain: [0, 10] }, - }, - gridArgs: { - stroke: '#008000', - strokeOpacity: 0.5, - strokeDasharray: '5, 5', - data: [0, 5, 10], - }, - }, + it('simple x grid with stroke styles', () => { + const { container } = render(GridXTest, { + props: { + plotArgs: { + x: { domain: [0, 10] }, + y: { domain: [0, 10] } + }, + gridArgs: { + stroke: '#008000', + strokeOpacity: 0.5, + strokeDasharray: '5, 5', + data: [0, 5, 10] + } + } + }); + const gridLines = container.querySelectorAll( + 'g.grid-x > line' + ) as NodeListOf; + expect(gridLines.length).toBe(3); + expect(gridLines[0].style.strokeDasharray).toBe('5, 5'); + expect(gridLines[0].style.stroke).toBe('#008000'); + expect(gridLines[0].style.strokeOpacity).toBe('0.5'); }); - const gridLines = container.querySelectorAll('g.grid-x > line') as NodeListOf; - expect(gridLines.length).toBe(3); - expect(gridLines[0].style.strokeDasharray).toBe('5, 5'); - expect(gridLines[0].style.stroke).toBe('#008000'); - expect(gridLines[0].style.strokeOpacity).toBe('0.5'); - }) -}) \ No newline at end of file +}); diff --git a/src/tests/gridY.test.svelte b/src/tests/gridY.test.svelte index af06a78a..7f6cfeea 100644 --- a/src/tests/gridY.test.svelte +++ b/src/tests/gridY.test.svelte @@ -1,15 +1,15 @@ - + diff --git a/src/tests/gridY.test.ts b/src/tests/gridY.test.ts index c774c167..aece75c0 100644 --- a/src/tests/gridY.test.ts +++ b/src/tests/gridY.test.ts @@ -3,25 +3,27 @@ import { render } from '@testing-library/svelte'; import GridYTest from './gridY.test.svelte'; describe('GridY mark', () => { - it('simple y grid with stroke styles', () => { - const { container } = render(GridYTest, { - props: { - plotArgs: { - x: { domain: [0, 10] }, - y: { domain: [0, 10] }, - }, - gridArgs: { - stroke: '#008000', - strokeOpacity: 0.5, - strokeDasharray: '5, 5', - data: [0, 5, 10], - }, - }, + it('simple y grid with stroke styles', () => { + const { container } = render(GridYTest, { + props: { + plotArgs: { + x: { domain: [0, 10] }, + y: { domain: [0, 10] } + }, + gridArgs: { + stroke: '#008000', + strokeOpacity: 0.5, + strokeDasharray: '5, 5', + data: [0, 5, 10] + } + } + }); + const gridLines = container.querySelectorAll( + 'g.grid-y > line' + ) as NodeListOf; + expect(gridLines.length).toBe(3); + expect(gridLines[0].style.strokeDasharray).toBe('5, 5'); + expect(gridLines[0].style.stroke).toBe('#008000'); + expect(gridLines[0].style.strokeOpacity).toBe('0.5'); }); - const gridLines = container.querySelectorAll('g.grid-y > line') as NodeListOf; - expect(gridLines.length).toBe(3); - expect(gridLines[0].style.strokeDasharray).toBe('5, 5'); - expect(gridLines[0].style.stroke).toBe('#008000'); - expect(gridLines[0].style.strokeOpacity).toBe('0.5'); - }) -}) \ No newline at end of file +}); diff --git a/src/tests/line.test.ts b/src/tests/line.test.ts index 51fe1363..bf43e795 100644 --- a/src/tests/line.test.ts +++ b/src/tests/line.test.ts @@ -35,7 +35,9 @@ describe('Line mark', () => { } }); - const lines = container.querySelectorAll('g.lines > g > path') as NodeListOf; + const lines = container.querySelectorAll( + 'g.lines > g > path' + ) as NodeListOf; expect(lines).toHaveLength(1); expect(lines[0]?.getAttribute('d')).toBe( 'M1,95L8.917,80C16.833,65,32.667,35,48.5,27.5C64.333,20,80.167,35,88.083,42.5L96,50' @@ -78,7 +80,9 @@ describe('Line mark', () => { } }); - const lines = container.querySelectorAll('g.lines > g > path') as NodeListOf; + const lines = container.querySelectorAll( + 'g.lines > g > path' + ) as NodeListOf; expect(lines).toHaveLength(1); const line = lines[0]; expect(line?.getAttribute('d')).toBe('M1,95L48.5,50L96,5'); @@ -102,7 +106,9 @@ describe('Line mark', () => { }); // The implementation might differ from our expectation - look for any path elements - const paths = container.querySelectorAll('g.lines > g > path') as NodeListOf;; + const paths = container.querySelectorAll( + 'g.lines > g > path' + ) as NodeListOf; expect(paths.length).toBeGreaterThan(0); // Check if at least one path has the expected styles @@ -214,7 +220,9 @@ describe('Line mark', () => { } }); - const lines = container.querySelectorAll('g.lines > g > path') as NodeListOf; + const lines = container.querySelectorAll( + 'g.lines > g > path' + ) as NodeListOf; expect(lines).toHaveLength(2); // Verify we have two distinct lines with different stroke colors expect(lines[0]?.style.stroke).not.toBe(lines[1]?.style.stroke); diff --git a/src/tests/plot.test.ts b/src/tests/plot.test.ts index 47f59252..9beb0b10 100644 --- a/src/tests/plot.test.ts +++ b/src/tests/plot.test.ts @@ -133,7 +133,7 @@ describe('Plot component', () => { const { container } = render(PlotTest, { props: { width: 100, - height: 150, + height: 150 } }); diff --git a/src/tests/polyfill.d.ts b/src/tests/polyfill.d.ts index 16470312..cd8347ff 100644 --- a/src/tests/polyfill.d.ts +++ b/src/tests/polyfill.d.ts @@ -1,7 +1,7 @@ declare module 'resize-observer-polyfill' { - const ResizeObserver: { - new (callback: ResizeObserverCallback): ResizeObserver; - prototype: ResizeObserver; - }; - export default ResizeObserver; -} \ No newline at end of file + const ResizeObserver: { + new (callback: ResizeObserverCallback): ResizeObserver; + prototype: ResizeObserver; + }; + export default ResizeObserver; +} diff --git a/src/tests/setup.ts b/src/tests/setup.ts index 321cb0d1..6d879976 100644 --- a/src/tests/setup.ts +++ b/src/tests/setup.ts @@ -2,14 +2,14 @@ import ResizeObserver from 'resize-observer-polyfill'; import MatchMediaMock from 'vitest-matchmedia-mock'; import type MatchMedia from 'vitest-matchmedia-mock'; -import { afterEach, beforeAll } from "vitest"; +import { afterEach, beforeAll } from 'vitest'; let matchMedia: MatchMedia = new MatchMediaMock(); beforeAll(() => { global.ResizeObserver = ResizeObserver; -}) +}); afterEach(() => { matchMedia.clear(); -}); \ No newline at end of file +}); diff --git a/tsconfig.json b/tsconfig.json index 6b7a1779..20f50d38 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -10,10 +10,10 @@ "sourceMap": true, "strict": true, "moduleResolution": "bundler", - "module": "esnext" + "module": "esnext" } // Path aliases are handled by https://kit.svelte.dev/docs/configuration#alias // // If you want to overwrite includes/excludes, make sure to copy over the relevant includes/excludes // from the referenced tsconfig.json - TypeScript does not merge them in -} \ No newline at end of file +} diff --git a/vite.config.js b/vite.config.js index af1879a0..1f4626b8 100644 --- a/vite.config.js +++ b/vite.config.js @@ -10,8 +10,8 @@ export default defineConfig({ resolve: { ...(process.env.VITEST ? { - conditions: ['browser'] - } + conditions: ['browser'] + } : undefined), alias: { svelteplot: path.resolve(__dirname, './src/lib/index.js'), From 6cee75237825ff77047b9f009237ef9639a6029a Mon Sep 17 00:00:00 2001 From: gka Date: Sun, 25 May 2025 22:18:32 +0200 Subject: [PATCH 07/42] chore: fix eslint errors --- src/lib/marks/BarX.svelte | 9 ++++-- src/lib/marks/Text.svelte | 29 +++++++++----------- src/lib/marks/TickX.svelte | 2 +- src/lib/marks/TickY.svelte | 2 +- src/lib/marks/Vector.svelte | 2 +- src/lib/marks/helpers/BaseAxisX.svelte | 2 +- src/lib/marks/helpers/LinearGradientX.svelte | 2 +- src/lib/marks/helpers/LinearGradientY.svelte | 2 +- src/lib/marks/helpers/MarkerPath.svelte | 2 +- src/lib/marks/helpers/RectPath.svelte | 4 +-- src/lib/ui/RadioInput.svelte | 2 +- src/lib/ui/Select.svelte | 2 +- src/routes/features/marks/+page.md | 4 ++- 13 files changed, 34 insertions(+), 30 deletions(-) diff --git a/src/lib/marks/BarX.svelte b/src/lib/marks/BarX.svelte index cf6b6b92..a6cfb01a 100644 --- a/src/lib/marks/BarX.svelte +++ b/src/lib/marks/BarX.svelte @@ -6,7 +6,12 @@ import Mark from '../Mark.svelte'; import { getContext } from 'svelte'; import { stackX, recordizeX, intervalX, sort } from '$lib/index.js'; - import type { PlotContext, BaseMarkProps, RectMarkProps, ChannelAccessor } from '../types.js'; + import type { + PlotContext, + BaseMarkProps, + BaseRectMarkProps, + ChannelAccessor + } from '../types.js'; import type { StackOptions } from '$lib/transforms/stack.js'; import type { DataRow } from '$lib/types.js'; import GroupMultiple from './helpers/GroupMultiple.svelte'; @@ -19,7 +24,7 @@ x2?: ChannelAccessor; y?: ChannelAccessor; stack?: StackOptions; - } & RectMarkProps; + } & BaseRectMarkProps; let { data = [{}], class: className = null, stack, ...options }: BarXProps = $props(); diff --git a/src/lib/marks/Text.svelte b/src/lib/marks/Text.svelte index d1e51d8a..b01245b1 100644 --- a/src/lib/marks/Text.svelte +++ b/src/lib/marks/Text.svelte @@ -78,7 +78,7 @@ {...args}> {#snippet children({ mark, scaledData, usedScales })} - {#each scaledData as d} + {#each scaledData as d, i (i)} {#if d.valid} {@const title = resolveProp(args.title, d.datum, '')} {@const frameAnchor = resolveProp(args.frameAnchor, d.datum)} @@ -148,20 +148,17 @@ {#each textLines as line, l}{#each textLines as line, l (l)}{textLines[0]}{#if title}{title}{/if} {/if} diff --git a/src/lib/marks/TickX.svelte b/src/lib/marks/TickX.svelte index dcf0ec19..dca5df17 100644 --- a/src/lib/marks/TickX.svelte +++ b/src/lib/marks/TickX.svelte @@ -47,7 +47,7 @@ {#snippet children({ mark, usedScales })} - {#each args.data as datum} + {#each args.data as datum, i (i)} {#if testFacet(datum, mark.options) && testFilter(datum, args)} {@const x_ = resolveChannel('x', datum, args)} {@const y_ = resolveChannel('y', datum, args)} diff --git a/src/lib/marks/TickY.svelte b/src/lib/marks/TickY.svelte index 84e4c4c8..49305b3f 100644 --- a/src/lib/marks/TickY.svelte +++ b/src/lib/marks/TickY.svelte @@ -48,7 +48,7 @@ {#snippet children({ mark, usedScales })} - {#each args.data as datum} + {#each args.data as datum, i (i)} {#if testFacet(datum, mark.options) && testFilter(datum, args)} {@const y_ = resolveChannel('y', datum, args)} {@const x_ = resolveChannel('x', datum, args)} diff --git a/src/lib/marks/Vector.svelte b/src/lib/marks/Vector.svelte index 55502a19..8e92d569 100644 --- a/src/lib/marks/Vector.svelte +++ b/src/lib/marks/Vector.svelte @@ -170,7 +170,7 @@ implement canvas rendering for vector mark {:else} - {#each scaledData as d} + {#each scaledData as d, i (i)} {@const r = resolveChannel('r', d.datum, { r: 3, ...args })} {#if d.valid && isValid(r)} {@const dx = +resolveProp(args.dx, d.datum, 0)} diff --git a/src/lib/marks/helpers/BaseAxisX.svelte b/src/lib/marks/helpers/BaseAxisX.svelte index fe531fb2..daa2f33d 100644 --- a/src/lib/marks/helpers/BaseAxisX.svelte +++ b/src/lib/marks/helpers/BaseAxisX.svelte @@ -198,7 +198,7 @@ {#if textLines.length === 1} {textLines[0]} {:else} - {#each textLines as line, i} + {#each textLines as line, i (i)} {!prevTextLines || prevTextLines[i] !== line ? line diff --git a/src/lib/marks/helpers/LinearGradientX.svelte b/src/lib/marks/helpers/LinearGradientX.svelte index 2cc27bf6..4d64d50b 100644 --- a/src/lib/marks/helpers/LinearGradientX.svelte +++ b/src/lib/marks/helpers/LinearGradientX.svelte @@ -21,7 +21,7 @@ - {#each projectedStops as { px, color }} + {#each projectedStops as { px, color }, i (i)} {/each} diff --git a/src/lib/marks/helpers/LinearGradientY.svelte b/src/lib/marks/helpers/LinearGradientY.svelte index 5418e1ff..8ee1f6f0 100644 --- a/src/lib/marks/helpers/LinearGradientY.svelte +++ b/src/lib/marks/helpers/LinearGradientY.svelte @@ -21,7 +21,7 @@ - {#each projectedStops as { py, color }} + {#each projectedStops as { py, color }, i (i)} {/each} diff --git a/src/lib/marks/helpers/MarkerPath.svelte b/src/lib/marks/helpers/MarkerPath.svelte index d7d3ef2e..8ca944f6 100644 --- a/src/lib/marks/helpers/MarkerPath.svelte +++ b/src/lib/marks/helpers/MarkerPath.svelte @@ -96,7 +96,7 @@ class={className} stroke-width={strokeWidth_} use:addEventHandlers={{ getPlotState, options: mark.options, datum }}> - {#each Object.entries( { start: markerStart, mid: markerMid, end: markerEnd, all: marker } ) as [key, marker]} + {#each Object.entries( { start: markerStart, mid: markerMid, end: markerEnd, all: marker } ) as [key, marker] (key)} {@const markerId = `marker-${key === 'all' ? '' : `${key}-`}${id}`} {#if isSnippet(marker)} {@render marker(markerId, color)} diff --git a/src/lib/marks/helpers/RectPath.svelte b/src/lib/marks/helpers/RectPath.svelte index 565c76bc..5142ffe2 100644 --- a/src/lib/marks/helpers/RectPath.svelte +++ b/src/lib/marks/helpers/RectPath.svelte @@ -99,7 +99,7 @@ Helper component for rendering rectangular marks in SVG {#if hasBorderRadius} {:else} {label}: {/if} - {#each options as p} + {#each options as p (p)}