From 400b95c67a992d223bb2eaf39188264198fea3df Mon Sep 17 00:00:00 2001 From: m93a Date: Thu, 1 Aug 2024 18:02:06 +0200 Subject: [PATCH] fix: fixes #10, adds configReactivityStrategy prop --- README.md | 23 ++++++++++++----------- src/lib/Plot.svelte | 40 ++++++++++++++++++++++++++++++---------- src/routes/+page.svelte | 22 ++++++++-------------- 3 files changed, 50 insertions(+), 35 deletions(-) diff --git a/README.md b/README.md index 407843f..55cbb22 100644 --- a/README.md +++ b/README.md @@ -58,17 +58,18 @@ If you don't use Vite, or this approach doesn't work for you, you can also use t ## Properties -| Prop | Type | Description | -| ------------------- | -------------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------- | -| **required `data`** | `Data[]` | array of trace data, see https://plot.ly/javascript/reference/ | -| `layout` | `Partial` | layout of the plot, see https://plot.ly/javascript/reference/#layout | -| `config` | `Partial` | configuration, see https://plot.ly/javascript/configuration-options/ | -| `class` | `string` | class that will be passed to the HTML element wrapping the plot | -| `fillParent` | `boolean \| 'width' \| 'height'` | automatically resize the plot to fill the width and/or height of its parent element | -| `debounce` | `number \| DebounceOptions` | debounce all changes to the plot | -| `libPlotly` | `Plotly \| null \| undefined` | an alternative Plotly bundle to use; if undefined, it defaults to the `plotly.js-dist` package; if null, no plot will be drawn and no library will be downloaded | -| `bind:element` | `HTMLDivElement` | the HTML element wrapping the plot | -| `bind:plot` | `PlotlyHTMLElement` | the inner HTML element containing the plot | +| Prop | Type | Description | +| -------------------------- | -------------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------- | +| **required `data`** | `Data[]` | array of trace data, see https://plot.ly/javascript/reference/ | +| `layout` | `Partial` | layout of the plot, see https://plot.ly/javascript/reference/#layout | +| `config` | `Partial` | configuration, see https://plot.ly/javascript/configuration-options/ | +| `class` | `string` | class that will be passed to the HTML element wrapping the plot | +| `fillParent` | `boolean \| 'width' \| 'height'` | automatically resize the plot to fill the width and/or height of its parent element | +| `debounce` | `number \| DebounceOptions` | debounce all changes to the plot | +| `libPlotly` | `Plotly \| null \| undefined` | an alternative Plotly bundle to use; if undefined, it defaults to the `plotly.js-dist` package; if null, no plot will be drawn and no library will be downloaded | +| `configReactivityStrategy` | `'none' \| 'static-plot'` | walkaround for an [upstream bug](https://github.com/m93a/svelte-plotly.js/issues/10) causing `config` not to update, enabled by default | +| `bind:element` | `HTMLDivElement` | the HTML element wrapping the plot | +| `bind:plot` | `PlotlyHTMLElement` | the inner HTML element containing the plot | ## Events diff --git a/src/lib/Plot.svelte b/src/lib/Plot.svelte index 7cb9699..4e940c7 100644 --- a/src/lib/Plot.svelte +++ b/src/lib/Plot.svelte @@ -203,6 +203,20 @@ */ export let debounce: number | DebounceOptions = 0; + /** + * Because of an [upstream bug](https://github.com/m93a/svelte-plotly.js/issues/10), + * changes in the `config` prop don't always render. + * This prop enables a walkaround, which makes sure + * that changes in `config` just work. + * + * - `'static-plot'` – when changing `config`, briefly disable + * chart interactivity to force update + * + * - `'none'` – disable the walkaround; updating mode bar + * buttons might not work + */ + export let configReactivityStrategy: 'none' | 'static-plot' = 'static-plot'; + /** * Class attribute that will be passed to the HTML element * wrapping the plot @@ -229,7 +243,10 @@ $: data, (datarevision = (datarevision + 1) % 1000); $: layout_ = { datarevision, width, height, ...layout }; $: config_ = { displaylogo: false, ...config }; - $: draw(libPlotly, element, data, layout_, config_); + + let configUpdated = false; + $: config_, (configUpdated = true); + $: { if (element && previousLib !== libPlotly) { previousLib?.purge(element); @@ -246,19 +263,22 @@ previousPlot = plot; } - const drawUndebounced = async ( - lib: typeof libPlotly, - e: HTMLDivElement | undefined, - d: Data[], - l: Partial, - c: Partial - ) => { - if (lib && e) { - plot = await lib.react(e, d, l, c); + const drawUndebounced = async () => { + if (!libPlotly || !element) return; + + if (configUpdated && configReactivityStrategy === 'static-plot') { + configUpdated = false; + await libPlotly.react(element, data, layout_, { + ...config_, + staticPlot: !config_.staticPlot + }); } + + plot = await libPlotly.react(element, data, layout_, config_); }; $: draw = debouncify(drawUndebounced, debounceWait, debounceOptions); + $: libPlotly, element, data, layout_, config_, configUpdated, draw(); // destroy onDestroy(() => element && libPlotly?.purge(element)); diff --git a/src/routes/+page.svelte b/src/routes/+page.svelte index 0a6ea81..db6ffc5 100644 --- a/src/routes/+page.svelte +++ b/src/routes/+page.svelte @@ -26,18 +26,13 @@ let debounce: DebounceOptions | number | undefined; let fullscreen = false; - // $: { - // if (fullscreen) fillParent = true; - // else fillParent = false; - // } + $: { + if (fullscreen) fillParent = true; + else fillParent = false; + } let data: Data[]; - $: data = [ - { - x: [1, 2, 3, 4, 5], - y: [y0, 2, 4, 8, 16] - } - ]; + $: data = [{ x: [1, 2, 3, 4, 5], y: [y0, 2, 4, 8, 16] }]; let config: Partial; $: config = { @@ -55,7 +50,7 @@ staticPlot, displaylogo: showLogo }; - $: console.log(config); + $: console.log('config:', config); function addData() { data.push({ @@ -79,9 +74,7 @@ {fillParent} {debounce} {config} - layout={{ - margin: { t: 0 } - }} + layout={{ margin: { t: 0 } }} libPlotly={useDefaultLib ? undefined : null} on:click={console.log} on:relayout={console.log} @@ -128,6 +121,7 @@ on:click={() => { if (modeBarButtons?.length && modeBarButtons[0].length) { any(modeBarButtons[0][0]).title = prompt('Enter new name'); + modeBarButtons = modeBarButtons; } }}>Rename first custom button