Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

📝 Clarify documentation on using DocumenterVitepress #6

Merged
merged 1 commit into from
Jan 13, 2025
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
113 changes: 107 additions & 6 deletions docs/src/vitepress.md
Original file line number Diff line number Diff line change
@@ -1,21 +1,117 @@
# Usage with DocumenterVitepress

PlotlyDocumenter provides an extension to work with DocumenterVitepress. As raw javascript code cannot be executed in Vue, an alternate approach is required.
For this reason, when using DocumenterVitepress, the custom plot object will be rendered as the `<VuePlotly/>` component from the [vue3-plotly-ts](https://github.com/boscoh/vue3-plotly-ts) package.
For this reason, when using DocumenterVitepress, the custom plot object will be rendered as the `<VuePlotly/>` component.

!!! warning
The keyword arguments for `to_documenter` are ignored when using DocumenterVitepress.

To make this work, first install the `vue3-plotly-ts` package in your project:
To make this work, first install the `plotly.js-dist-min` package and associated types `@types/plotly.js-dist-min` in your project:

```bash
npm install vue3-plotly-ts
npm install plotly.js-dist-min
npm install --save-dev @types/plotly.js-dist-min
```

Then, add the `VuePlotly` component to your `.vitepress/theme/index.ts` file:
Then, in your `docs/src/components` directory create a file called `PlotlyWrapper.vue` with the following content:

```typescript
import VuePlotly from "vue3-plotly-ts"
<template>
<div ref="divRef" :id="plotlyId"></div>
</template>

<script setup lang="ts">
import { onBeforeUnmount, ref, watchEffect } from 'vue'
import type { Data, Layout, Config } from 'plotly.js-dist-min'

const props = defineProps<{
data?: Plotly.Data[]
layout?: Partial<Plotly.Layout>
config?: Partial<Plotly.Config>
}>();

const randomString = Math.random().toString(36).slice(2, 7);
const plotlyId = ref<string>(`plotly-${randomString}`);
const divRef = ref<Plotly.PlotlyHTMLElement>();

defineExpose({ plotlyId });

function debounce<Params extends any[]>(
func: (...args: Params) => any,
timeout: number
): (...args: Params) => void {
let timer: NodeJS.Timeout
return (...args: Params) => {
clearTimeout(timer)
timer = setTimeout(() => {
func(...args)
}, timeout)
}
}

// SSR check - everything after this will only run on the client
if (typeof window == 'undefined') return;

const Plotly = await import('plotly.js-dist-min');

let isCreated = false

function resize() {
Plotly.Plots.resize(divRef.value as Plotly.Root)
}

const resizeObserver = new ResizeObserver(debounce(resize, 50))

watchEffect(async () => {
const data = props.data ? props.data : []
const div = divRef.value as Plotly.Root
if (isCreated) {
Plotly.react(div, data, props.layout, props.config)
} else if (div) {
await Plotly.newPlot(div, data, props.layout, props.config)
resizeObserver.observe(div as Plotly.PlotlyHTMLElement)
isCreated = true
}
})

onBeforeUnmount(() => {
resizeObserver.disconnect()
Plotly.purge(divRef.value as Plotly.Root)
})
</script>
```

and a component called `VuePlotly.vue` with the following content:

```typescript
<template>
<Suspense>
<VuePlotly
:data="props.data"
:layout="props.layout"
:config="props.config"
/>
<template #fallback>
<div>Loading plot...</div>
</template>
</Suspense>
</template>

<script setup lang="ts">
import VuePlotly from './PlotlyWrapper.vue'
import type { Data, Layout, Config } from 'plotly.js-dist-min'

const props = defineProps<{
data?: Data[]
layout?: Partial<Layout>
config?: Partial<Config>
}>()
</script>
```

Finally, in your `docs/src/.vitepress/theme/index.ts` file, add the following code:
```typescript
import VuePlotly from "../../components/VuePlotly.vue"

export default {
...
Expand All @@ -26,5 +122,10 @@ enhanceApp({ app, router, siteData }) {
}
} satisfies Theme
```

In your `make.jl`, make sure you call `using PlotlyDocumenter` before `makedocs`.


## Explanation

Due to SSR requirements of vitepress, we have to import plotly.js dynamically. This is done in the `PlotlyWrapper.vue` component.
Since this dynamic import requires a suspense boundary, this boundary is provided by the `VuePlotly.vue` component, which simply wraps the `PlotlyWrapper.vue` component.
Loading