From cf609415f6220786c68a8a52be974b4b354dc51c Mon Sep 17 00:00:00 2001 From: James Scott-Brown Date: Fri, 23 May 2025 15:49:39 +0100 Subject: [PATCH 1/3] initial POC implementation of theming --- src/lib/core/Plot.svelte | 2 + src/lib/index.ts | 2 + src/lib/marks/AreaY.svelte | 5 ++- src/lib/marks/AxisX.svelte | 5 ++- src/lib/marks/AxisY.svelte | 4 +- src/lib/marks/Dot.svelte | 4 +- src/lib/marks/Line.svelte | 4 +- src/lib/marks/RuleX.svelte | 8 +++- src/lib/marks/RuleY.svelte | 8 +++- src/routes/why-svelteplot/+page.md | 70 ++++++++++++++++++------------ 10 files changed, 77 insertions(+), 35 deletions(-) diff --git a/src/lib/core/Plot.svelte b/src/lib/core/Plot.svelte index 2f98825a..f1a0315d 100644 --- a/src/lib/core/Plot.svelte +++ b/src/lib/core/Plot.svelte @@ -92,12 +92,14 @@ class: className = '', css = DEFAULTS.css, width: fixedWidth, + theme, ...initialOpts }: Partial = $props(); let width = $state(DEFAULTS.initialWidth); setContext('svelteplot/_defaults', DEFAULTS); + setContext('svelteplot/theme', theme); // information that influences the default plot options type PlotOptionsParameters = { diff --git a/src/lib/index.ts b/src/lib/index.ts index b6db48f5..454f0f7d 100644 --- a/src/lib/index.ts +++ b/src/lib/index.ts @@ -1,6 +1,8 @@ export { default as Plot } from './Plot.svelte'; export { default as PlotCore } from './core/Plot.svelte'; +export { demoTheme } from './themes/demoTheme'; + export * from './marks/index.js'; export * from './transforms/index.js'; diff --git a/src/lib/marks/AreaY.svelte b/src/lib/marks/AreaY.svelte index e607e40a..bd5a4c9c 100644 --- a/src/lib/marks/AreaY.svelte +++ b/src/lib/marks/AreaY.svelte @@ -4,6 +4,7 @@ import { stackY } from '$lib/transforms/stack.js'; import { recordizeY } from '$lib/transforms/recordize.js'; import type { DataRecord, BaseMarkProps, ChannelAccessor } from '../types.js'; + import { getContext } from 'svelte'; /** * AreaY mark foo @@ -19,7 +20,9 @@ y?: ChannelAccessor; } & AreaMarkProps; - let { data, stack, ...options }: AreaYProps = $props(); + const theme = getContext('svelteplot/theme'); + const p = $props(); + let { data, stack, ...options }: AreaYProps = { ...(theme?.marks?.areaY || {}), ...p }; const args = $derived( renameChannels( diff --git a/src/lib/marks/AxisX.svelte b/src/lib/marks/AxisX.svelte index 45cf8caf..96c1b583 100644 --- a/src/lib/marks/AxisX.svelte +++ b/src/lib/marks/AxisX.svelte @@ -42,6 +42,9 @@ tickClass?: ConstantAccessor; }; + const theme = getContext('svelteplot/theme'); + + const p = $props(); let { data = [], automatic = false, @@ -56,7 +59,7 @@ tickFormat, tickClass, ...options - }: AxisXProps = $props(); + }: AxisXProps = { ...(theme?.marks?.axisX || {}), ...p }; const { getPlotState } = getContext('svelteplot'); let plot = $derived(getPlotState()); diff --git a/src/lib/marks/AxisY.svelte b/src/lib/marks/AxisY.svelte index 88915d05..784497ff 100644 --- a/src/lib/marks/AxisY.svelte +++ b/src/lib/marks/AxisY.svelte @@ -40,6 +40,8 @@ tickClass?: ConstantAccessor; }; + const theme = getContext('svelteplot/theme'); + const p = $props(); let { data = [], automatic = false, @@ -53,7 +55,7 @@ tickFormat, tickClass, ...options - }: AxisYProps = $props(); + }: AxisYProps = { ...(theme?.marks?.axisY || {}), ...p }; const { getPlotState } = getContext('svelteplot'); const plot = $derived(getPlotState()); diff --git a/src/lib/marks/Dot.svelte b/src/lib/marks/Dot.svelte index f7189ec7..b16f455e 100644 --- a/src/lib/marks/Dot.svelte +++ b/src/lib/marks/Dot.svelte @@ -40,6 +40,8 @@ wrap?: Snippet; }; + const theme = getContext('svelteplot/theme'); + const p = $props(); let { data = [{}], canvas = false, @@ -50,7 +52,7 @@ out: tOut = undefined, outParams = undefined, ...options - }: DotProps = $props(); + }: DotProps = { ...(theme?.marks?.dot || {}), ...p }; const { getPlotState } = getContext('svelteplot'); const plot = $derived(getPlotState()); diff --git a/src/lib/marks/Line.svelte b/src/lib/marks/Line.svelte index 9c54ffff..0fe88b3e 100644 --- a/src/lib/marks/Line.svelte +++ b/src/lib/marks/Line.svelte @@ -59,6 +59,8 @@ import { recordizeXY } from '$lib/transforms/recordize.js'; import GroupMultiple from './helpers/GroupMultiple.svelte'; + const theme = getContext('svelteplot/theme'); + const p = $props(); let { data = [{}], curve = 'auto', @@ -68,7 +70,7 @@ class: className = null, lineClass = null, ...options - }: LineMarkProps = $props(); + }: LineMarkProps = { ...(theme?.marks?.line || {}), ...p }; const args = $derived(sort(recordizeXY({ data, ...options }))); diff --git a/src/lib/marks/RuleX.svelte b/src/lib/marks/RuleX.svelte index ad0fbcce..ecd421b4 100644 --- a/src/lib/marks/RuleX.svelte +++ b/src/lib/marks/RuleX.svelte @@ -24,7 +24,13 @@ dy?: ConstantAccessor; }; - let { data = [{}], class: className = null, ...options }: RuleXMarkProps = $props(); + const theme = getContext('svelteplot/theme'); + const p = $props(); + let { + data = [{}], + class: className = null, + ...options + }: RuleXMarkProps = { ...(theme?.marks?.ruleX || {}), ...p }; const { getPlotState } = getContext('svelteplot'); const plot = $derived(getPlotState()); diff --git a/src/lib/marks/RuleY.svelte b/src/lib/marks/RuleY.svelte index 4312d1e6..7edb77b7 100644 --- a/src/lib/marks/RuleY.svelte +++ b/src/lib/marks/RuleY.svelte @@ -24,7 +24,13 @@ dy?: ConstantAccessor; }; - let { data = [{}], class: className = null, ...options }: RuleYMarkProps = $props(); + const theme = getContext('svelteplot/theme'); + const p = $props(); + let { + data = [{}], + class: className = null, + ...options + }: RuleYMarkProps = { ...(theme?.marks?.ruleY || {}), ...p }; const { getPlotState } = getContext('svelteplot'); const plot = $derived(getPlotState()); diff --git a/src/routes/why-svelteplot/+page.md b/src/routes/why-svelteplot/+page.md index b0fb163b..d17f0e11 100644 --- a/src/routes/why-svelteplot/+page.md +++ b/src/routes/why-svelteplot/+page.md @@ -13,12 +13,16 @@ This means there is no "scatterplot" component in SveltePlot, but you can use th ```svelte live - + - import { Plot, Dot, GridY, AxisX } from 'svelteplot'; + import { + demoTheme, + Plot, + Dot, + GridY, + AxisX + } from 'svelteplot'; import { page } from '$app/state'; const { languages } = $derived(page.data.data); @@ -53,10 +63,11 @@ You can think of marks as the building blocks for your visualizations -- or the ``` ```svelte ``` @@ -97,7 +107,13 @@ This makes it a lot easier to iterate over different ideas for visualizations. F ```svelte live @@ -127,7 +144,6 @@ This makes it a lot easier to iterate over different ideas for visualizations. F data={languages} x="Total speakers" y="Language" - fill sort={{ channel: '-x' }} /> ``` @@ -144,7 +160,6 @@ This makes it a lot easier to iterate over different ideas for visualizations. F data={languages} x="Total speakers" y="Language" - fill sort={{ channel: '-x' }} /> ``` @@ -154,6 +169,7 @@ And if we wanted to add uncertainty ranges, we can add a [Rule mark](/marks/rule ```svelte live @@ -198,7 +215,6 @@ And if we wanted to add uncertainty ranges, we can add a [Rule mark](/marks/rule data={languages} x="Total speakers" y="Language" - fill sort={{ channel: '-x' }} /> ``` @@ -219,7 +235,7 @@ Take the following example, where you can filter the data using the [filter](/tr ```svelte live {#if rand.length > 1} - - + + - import { Plot, Line } from 'svelteplot'; + import { demoTheme, Plot, Line } from 'svelteplot'; import { fly, fade } from 'svelte/transition'; import { page } from '$app/state'; @@ -421,7 +435,7 @@ You can extend SveltePlot by injecting regular Svelte snippets. For instance, th }); - + Date: Fri, 23 May 2025 15:54:00 +0100 Subject: [PATCH 2/3] commit the themes/ directory --- src/lib/themes/demoTheme.js | 52 +++++++++++++++++++++++++++++++++++++ 1 file changed, 52 insertions(+) create mode 100644 src/lib/themes/demoTheme.js diff --git a/src/lib/themes/demoTheme.js b/src/lib/themes/demoTheme.js new file mode 100644 index 00000000..856f60a9 --- /dev/null +++ b/src/lib/themes/demoTheme.js @@ -0,0 +1,52 @@ +import { get } from 'svelte/store'; + +export const demoTheme = { + marks: { + axisX: { + textPadding: 0, + tickSize: 0, + labelAnchor: 'top', + labelArrow: 'none', + labelOffset: 0, + lineAnchor: 'bottom' + }, + + axisY: { + textAnchor: 'start', + // textPadding: 0, + tickSize: 0, + labelAnchor: 'top', + labelArrow: 'none', + // labelOffset: 0, + lineAnchor: 'bottom', + dy: -4, + dx: 8 + }, + + dot: { + stroke: null, + fill: '#007acc', //get(currentTheme).color.data.primary, + fillOpacity: 0.7, + strokeWidth: 2, + r: 2 + }, + + line: { + stroke: '#007acc', + strokeWidth: 2 + }, + ruleX: { + stroke: '#007acc' + }, + ruleY: { + stroke: '#007acc' + }, + + areaY: { + stroke: '#007acc', + strokeWidth: 0, + fill: '#007acc', + fillOpacity: 0.2 + } + } +}; From 8e134b23fd07a9df8622c484d99297363462ba55 Mon Sep 17 00:00:00 2001 From: James Scott-Brown Date: Fri, 23 May 2025 16:27:15 +0100 Subject: [PATCH 3/3] make marks reactive to changes in props again --- src/lib/marks/AreaY.svelte | 5 +++-- src/lib/marks/Dot.svelte | 9 +++++---- src/lib/marks/Line.svelte | 9 +++++---- src/lib/marks/RuleX.svelte | 9 +++++---- src/lib/marks/RuleY.svelte | 9 +++++---- 5 files changed, 23 insertions(+), 18 deletions(-) diff --git a/src/lib/marks/AreaY.svelte b/src/lib/marks/AreaY.svelte index bd5a4c9c..ed13992a 100644 --- a/src/lib/marks/AreaY.svelte +++ b/src/lib/marks/AreaY.svelte @@ -20,9 +20,10 @@ y?: ChannelAccessor; } & AreaMarkProps; + let { data, stack, ...opts }: AreaYProps = $props(); + const theme = getContext('svelteplot/theme'); - const p = $props(); - let { data, stack, ...options }: AreaYProps = { ...(theme?.marks?.areaY || {}), ...p }; + const options = $derived({...(theme?.marks?.areaY || {}), ...opts}) const args = $derived( renameChannels( diff --git a/src/lib/marks/Dot.svelte b/src/lib/marks/Dot.svelte index b16f455e..317b8b2d 100644 --- a/src/lib/marks/Dot.svelte +++ b/src/lib/marks/Dot.svelte @@ -40,8 +40,6 @@ wrap?: Snippet; }; - const theme = getContext('svelteplot/theme'); - const p = $props(); let { data = [{}], canvas = false, @@ -51,8 +49,11 @@ inParams = undefined, out: tOut = undefined, outParams = undefined, - ...options - }: DotProps = { ...(theme?.marks?.dot || {}), ...p }; + ...opts + }: DotProps = $props(); + + const theme = getContext('svelteplot/theme'); + const options = $derived({...(theme?.marks?.dot || {}), ...opts}) const { getPlotState } = getContext('svelteplot'); const plot = $derived(getPlotState()); diff --git a/src/lib/marks/Line.svelte b/src/lib/marks/Line.svelte index 0fe88b3e..feb8dc59 100644 --- a/src/lib/marks/Line.svelte +++ b/src/lib/marks/Line.svelte @@ -59,8 +59,6 @@ import { recordizeXY } from '$lib/transforms/recordize.js'; import GroupMultiple from './helpers/GroupMultiple.svelte'; - const theme = getContext('svelteplot/theme'); - const p = $props(); let { data = [{}], curve = 'auto', @@ -69,8 +67,11 @@ canvas = false, class: className = null, lineClass = null, - ...options - }: LineMarkProps = { ...(theme?.marks?.line || {}), ...p }; + ...opts + }: LineMarkProps = $props(); + + const theme = getContext('svelteplot/theme'); + const options = $derived({...(theme?.marks?.line || {}), ...opts}) const args = $derived(sort(recordizeXY({ data, ...options }))); diff --git a/src/lib/marks/RuleX.svelte b/src/lib/marks/RuleX.svelte index ecd421b4..b66d45b5 100644 --- a/src/lib/marks/RuleX.svelte +++ b/src/lib/marks/RuleX.svelte @@ -24,13 +24,14 @@ dy?: ConstantAccessor; }; - const theme = getContext('svelteplot/theme'); - const p = $props(); let { data = [{}], class: className = null, - ...options - }: RuleXMarkProps = { ...(theme?.marks?.ruleX || {}), ...p }; + ...opts + }: RuleXMarkProps = $props(); + + const theme = getContext('svelteplot/theme'); + const options = $derived({...(theme?.marks?.ruleX || {}), ...opts}) const { getPlotState } = getContext('svelteplot'); const plot = $derived(getPlotState()); diff --git a/src/lib/marks/RuleY.svelte b/src/lib/marks/RuleY.svelte index 7edb77b7..2133d8ab 100644 --- a/src/lib/marks/RuleY.svelte +++ b/src/lib/marks/RuleY.svelte @@ -24,13 +24,14 @@ dy?: ConstantAccessor; }; - const theme = getContext('svelteplot/theme'); - const p = $props(); let { data = [{}], class: className = null, - ...options - }: RuleYMarkProps = { ...(theme?.marks?.ruleY || {}), ...p }; + ...opts + }: RuleYMarkProps = $props(); + + const theme = getContext('svelteplot/theme'); + const options = $derived({...(theme?.marks?.ruleY || {}), ...opts}) const { getPlotState } = getContext('svelteplot'); const plot = $derived(getPlotState()); pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy