svelte-plotly.js 0.2.1 → 0.3.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.eslintrc.cjs +20 -0
- package/.prettierrc +7 -0
- package/.vscode/settings.json +3 -0
- package/README.md +24 -1
- package/package.json +21 -10
- package/src/app.d.ts +10 -0
- package/src/app.html +12 -0
- package/src/lib/Plot.svelte +281 -0
- package/src/routes/index.svelte +103 -0
- package/src/types/plotly.d.ts +3 -0
- package/static/favicon.png +0 -0
- package/svelte.config.js +15 -0
- package/tsconfig.json +17 -0
- package/Plot.svelte +0 -158
- package/Plot.svelte.d.ts +0 -76
package/.eslintrc.cjs
ADDED
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
module.exports = {
|
|
2
|
+
root: true,
|
|
3
|
+
parser: '@typescript-eslint/parser',
|
|
4
|
+
extends: ['eslint:recommended', 'plugin:@typescript-eslint/recommended', 'prettier'],
|
|
5
|
+
plugins: ['svelte3', '@typescript-eslint'],
|
|
6
|
+
ignorePatterns: ['*.cjs'],
|
|
7
|
+
overrides: [{ files: ['*.svelte'], processor: 'svelte3/svelte3' }],
|
|
8
|
+
settings: {
|
|
9
|
+
'svelte3/typescript': () => require('typescript')
|
|
10
|
+
},
|
|
11
|
+
parserOptions: {
|
|
12
|
+
sourceType: 'module',
|
|
13
|
+
ecmaVersion: 2020
|
|
14
|
+
},
|
|
15
|
+
env: {
|
|
16
|
+
browser: true,
|
|
17
|
+
es2017: true,
|
|
18
|
+
node: true
|
|
19
|
+
}
|
|
20
|
+
};
|
package/.prettierrc
ADDED
package/README.md
CHANGED
|
@@ -4,7 +4,10 @@ This is an unofficial package that lets you efficiently use [plotly.js](https://
|
|
|
4
4
|
## Usage
|
|
5
5
|
|
|
6
6
|
1. Install using `yarn add svelte-plotly.js` or `npm install svelte-plotly.js`.
|
|
7
|
-
2.
|
|
7
|
+
2. Choose a Plotly distribution:
|
|
8
|
+
* If you want to use `plotly.js-dist`, just install it.
|
|
9
|
+
* If you want to use a different distribution, take a look at [this section](#custom-plotly-distribution).
|
|
10
|
+
3. Use in your app:
|
|
8
11
|
|
|
9
12
|
```svelte
|
|
10
13
|
<script lang="ts">
|
|
@@ -28,6 +31,26 @@ This is an unofficial package that lets you efficiently use [plotly.js](https://
|
|
|
28
31
|
/>
|
|
29
32
|
```
|
|
30
33
|
|
|
34
|
+
## Custom Plotly distribution
|
|
35
|
+
Let's say you want to use svelte-plotly.js with a custom Plotly.js distribution, for example [`plotly.js-basic-dist-min`](https://www.npmjs.com/package/plotly.js-basic-dist-min). If you use Vite for bundling, the recommended way to do this would be to install `plotly.js-basic-dist-min` and then register it as an alias for `plotly.js-dist` by adding the following to your [`vite.config.js`](https://vitejs.dev/config/shared-options.html#resolve-alias):
|
|
36
|
+
```js
|
|
37
|
+
resolve: {
|
|
38
|
+
alias: {
|
|
39
|
+
"plotly.js-dist": "plotly.js-basic-dist-min",
|
|
40
|
+
lodash: "lodash-es",
|
|
41
|
+
},
|
|
42
|
+
},
|
|
43
|
+
```
|
|
44
|
+
If you don't use Vite, or this approach doesn't work for you, you can also use the `libPlotly` prop of the `Plotly` component:
|
|
45
|
+
```svelte
|
|
46
|
+
<script lang="ts">
|
|
47
|
+
import Plot from 'svelte-plotly.js';
|
|
48
|
+
import libPlotly from 'plotly.js-basic-dist-min';
|
|
49
|
+
</script>
|
|
50
|
+
|
|
51
|
+
<Plot {libPlotly} ... />
|
|
52
|
+
```
|
|
53
|
+
|
|
31
54
|
## Properties
|
|
32
55
|
| Prop | Type | Description
|
|
33
56
|
| --------- | ----------- | -------------
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "svelte-plotly.js",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.3.1",
|
|
4
4
|
"author": {
|
|
5
5
|
"name": "Michal Grňo (m93a)",
|
|
6
6
|
"url": "https://github.com/m93a/"
|
|
@@ -17,6 +17,17 @@
|
|
|
17
17
|
"src/types/*.d.ts"
|
|
18
18
|
]
|
|
19
19
|
},
|
|
20
|
+
"scripts": {
|
|
21
|
+
"dev": "svelte-kit dev",
|
|
22
|
+
"build": "svelte-kit build",
|
|
23
|
+
"package": "svelte-kit package",
|
|
24
|
+
"preview": "svelte-kit preview",
|
|
25
|
+
"prepare": "svelte-kit sync",
|
|
26
|
+
"check": "svelte-check --tsconfig ./tsconfig.json",
|
|
27
|
+
"check:watch": "svelte-check --tsconfig ./tsconfig.json --watch",
|
|
28
|
+
"lint": "prettier --ignore-path .gitignore --check --plugin-search-dir=. . && eslint --ignore-path .gitignore .",
|
|
29
|
+
"format": "prettier --ignore-path .gitignore --write --plugin-search-dir=. ."
|
|
30
|
+
},
|
|
20
31
|
"devDependencies": {
|
|
21
32
|
"@sveltejs/adapter-auto": "next",
|
|
22
33
|
"@sveltejs/kit": "next",
|
|
@@ -27,6 +38,7 @@
|
|
|
27
38
|
"eslint-plugin-svelte3": "^4.0.0",
|
|
28
39
|
"prettier": "^2.5.1",
|
|
29
40
|
"prettier-plugin-svelte": "^2.5.0",
|
|
41
|
+
"plotly.js-dist": "^2.12.1",
|
|
30
42
|
"sass": "^1.51.0",
|
|
31
43
|
"svelte": "^3.44.0",
|
|
32
44
|
"svelte-check": "^2.2.6",
|
|
@@ -38,15 +50,14 @@
|
|
|
38
50
|
"type": "module",
|
|
39
51
|
"dependencies": {
|
|
40
52
|
"@types/lodash-es": "^4.17.6",
|
|
41
|
-
"@types/plotly.js": "^2.12.
|
|
42
|
-
"lodash-es": "^4.17
|
|
43
|
-
|
|
53
|
+
"@types/plotly.js": "^2.12.5",
|
|
54
|
+
"lodash-es": "^4.17"
|
|
55
|
+
},
|
|
56
|
+
"peerDependencies": {
|
|
57
|
+
"plotly.js-dist": "^2.12"
|
|
44
58
|
},
|
|
45
59
|
"types": "./Plot.svelte.d.ts",
|
|
46
60
|
"exports": {
|
|
47
|
-
"
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
},
|
|
51
|
-
"svelte": "./Plot.svelte"
|
|
52
|
-
}
|
|
61
|
+
".": "./Plot.svelte"
|
|
62
|
+
}
|
|
63
|
+
}
|
package/src/app.d.ts
ADDED
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
/// <reference types="@sveltejs/kit" />
|
|
2
|
+
|
|
3
|
+
// See https://kit.svelte.dev/docs/types#app
|
|
4
|
+
// for information about these interfaces
|
|
5
|
+
declare namespace App {
|
|
6
|
+
// interface Locals {}
|
|
7
|
+
// interface Platform {}
|
|
8
|
+
// interface Session {}
|
|
9
|
+
// interface Stuff {}
|
|
10
|
+
}
|
package/src/app.html
ADDED
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
<!DOCTYPE html>
|
|
2
|
+
<html lang="en">
|
|
3
|
+
<head>
|
|
4
|
+
<meta charset="utf-8" />
|
|
5
|
+
<link rel="icon" href="%svelte.assets%/favicon.png" />
|
|
6
|
+
<meta name="viewport" content="width=device-width, initial-scale=1" />
|
|
7
|
+
%svelte.head%
|
|
8
|
+
</head>
|
|
9
|
+
<body>
|
|
10
|
+
<div>%svelte.body%</div>
|
|
11
|
+
</body>
|
|
12
|
+
</html>
|
|
@@ -0,0 +1,281 @@
|
|
|
1
|
+
<script context="module" lang="ts">
|
|
2
|
+
import type {
|
|
3
|
+
Data,
|
|
4
|
+
Layout,
|
|
5
|
+
Config,
|
|
6
|
+
PlotlyHTMLElement,
|
|
7
|
+
BeforePlotEvent,
|
|
8
|
+
ClickAnnotationEvent,
|
|
9
|
+
FrameAnimationEvent,
|
|
10
|
+
LegendClickEvent,
|
|
11
|
+
PlotMouseEvent,
|
|
12
|
+
PlotHoverEvent,
|
|
13
|
+
PlotRelayoutEvent,
|
|
14
|
+
PlotRestyleEvent,
|
|
15
|
+
PlotSelectionEvent,
|
|
16
|
+
SliderEndEvent,
|
|
17
|
+
SliderChangeEvent,
|
|
18
|
+
SliderStartEvent,
|
|
19
|
+
SunburstClickEvent
|
|
20
|
+
} from 'plotly.js';
|
|
21
|
+
|
|
22
|
+
export type {
|
|
23
|
+
Data,
|
|
24
|
+
Layout,
|
|
25
|
+
Config,
|
|
26
|
+
PlotlyHTMLElement,
|
|
27
|
+
BeforePlotEvent,
|
|
28
|
+
ClickAnnotationEvent,
|
|
29
|
+
FrameAnimationEvent,
|
|
30
|
+
LegendClickEvent,
|
|
31
|
+
PlotMouseEvent,
|
|
32
|
+
PlotHoverEvent,
|
|
33
|
+
PlotRelayoutEvent,
|
|
34
|
+
PlotRestyleEvent,
|
|
35
|
+
PlotSelectionEvent,
|
|
36
|
+
SliderChangeEvent,
|
|
37
|
+
SliderStartEvent,
|
|
38
|
+
SunburstClickEvent
|
|
39
|
+
};
|
|
40
|
+
|
|
41
|
+
export type FillParent = boolean | 'width' | 'height';
|
|
42
|
+
import type { DebounceSettings } from 'lodash-es';
|
|
43
|
+
|
|
44
|
+
export interface DebounceOptions extends DebounceSettings {
|
|
45
|
+
wait: number;
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
export interface ButtonClickedEvent {
|
|
49
|
+
menu: any;
|
|
50
|
+
button: any;
|
|
51
|
+
active: any;
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
export interface PlotUpdateEvent {
|
|
55
|
+
data: Data;
|
|
56
|
+
layout: Layout;
|
|
57
|
+
}
|
|
58
|
+
</script>
|
|
59
|
+
|
|
60
|
+
<script lang="ts">
|
|
61
|
+
import { onMount, onDestroy, createEventDispatcher } from 'svelte';
|
|
62
|
+
import { debounce as debouncify } from 'lodash-es';
|
|
63
|
+
const browser = typeof window === 'object';
|
|
64
|
+
type not = undefined | null;
|
|
65
|
+
|
|
66
|
+
const nextFrame = browser ? requestAnimationFrame : () => void 0;
|
|
67
|
+
|
|
68
|
+
async function loadPlotly() {
|
|
69
|
+
if (!browser) return;
|
|
70
|
+
|
|
71
|
+
if (libPlotly === undefined) {
|
|
72
|
+
if (window.Plotly) {
|
|
73
|
+
libPlotly = window.Plotly;
|
|
74
|
+
} else {
|
|
75
|
+
const p = await import('plotly.js-dist');
|
|
76
|
+
if (libPlotly === undefined) libPlotly = 'default' in p ? p.default : p;
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
const DEFAULT_WIDTH = 500;
|
|
82
|
+
const DEFAULT_HEIGHT = 300;
|
|
83
|
+
|
|
84
|
+
// events
|
|
85
|
+
interface $$Events {
|
|
86
|
+
afterExport: undefined;
|
|
87
|
+
afterPlot: undefined;
|
|
88
|
+
animated: undefined;
|
|
89
|
+
animating: undefined;
|
|
90
|
+
animatingFrame: FrameAnimationEvent;
|
|
91
|
+
animationInterrupted: undefined;
|
|
92
|
+
autoSize: undefined;
|
|
93
|
+
beforeExport: undefined;
|
|
94
|
+
beforeHover: PlotMouseEvent;
|
|
95
|
+
beforePlot: BeforePlotEvent;
|
|
96
|
+
buttonClicked: ButtonClickedEvent;
|
|
97
|
+
click: PlotMouseEvent;
|
|
98
|
+
clickAnnotation: ClickAnnotationEvent;
|
|
99
|
+
deselect: undefined;
|
|
100
|
+
doubleClick: undefined;
|
|
101
|
+
framework: undefined;
|
|
102
|
+
hover: PlotHoverEvent;
|
|
103
|
+
legendClick: LegendClickEvent;
|
|
104
|
+
legendDoubleClick: LegendClickEvent;
|
|
105
|
+
react: PlotUpdateEvent;
|
|
106
|
+
redraw: undefined;
|
|
107
|
+
relayout: PlotRelayoutEvent;
|
|
108
|
+
relayouting: PlotRelayoutEvent;
|
|
109
|
+
restyle: PlotRestyleEvent;
|
|
110
|
+
selected: PlotSelectionEvent;
|
|
111
|
+
selecting: PlotSelectionEvent;
|
|
112
|
+
sliderChange: SliderChangeEvent;
|
|
113
|
+
sliderEnd: SliderEndEvent;
|
|
114
|
+
sliderStart: SliderStartEvent;
|
|
115
|
+
sunburstClick: SunburstClickEvent;
|
|
116
|
+
transitioned: undefined;
|
|
117
|
+
transitioning: undefined;
|
|
118
|
+
transitionInterrupted: undefined;
|
|
119
|
+
unhover: PlotMouseEvent;
|
|
120
|
+
update: PlotUpdateEvent;
|
|
121
|
+
webGLContextLost: undefined;
|
|
122
|
+
}
|
|
123
|
+
const events = <const>{
|
|
124
|
+
plotly_afterexport: 'afterExport',
|
|
125
|
+
plotly_afterplot: 'afterPlot',
|
|
126
|
+
plotly_animated: 'animated',
|
|
127
|
+
plotly_animating: 'animating',
|
|
128
|
+
plotly_animatingframe: 'animatingFrame',
|
|
129
|
+
plotly_animationinterrupted: 'animationInterrupted',
|
|
130
|
+
plotly_autosize: 'autoSize',
|
|
131
|
+
plotly_beforeexport: 'beforeExport',
|
|
132
|
+
plotly_beforehover: 'beforeHover',
|
|
133
|
+
plotly_beforeplot: 'beforePlot',
|
|
134
|
+
plotly_buttonclicked: 'buttonClicked',
|
|
135
|
+
plotly_click: 'click',
|
|
136
|
+
plotly_clickannotation: 'clickAnnotation',
|
|
137
|
+
plotly_deselect: 'deselect',
|
|
138
|
+
plotly_doubleclick: 'doubleClick',
|
|
139
|
+
plotly_framework: 'framework',
|
|
140
|
+
plotly_hover: 'hover',
|
|
141
|
+
plotly_legendclick: 'legendClick',
|
|
142
|
+
plotly_legenddoubleclick: 'legendDoubleClick',
|
|
143
|
+
plotly_react: 'react',
|
|
144
|
+
plotly_redraw: 'redraw',
|
|
145
|
+
plotly_relayout: 'relayout',
|
|
146
|
+
plotly_relayouting: 'relayouting',
|
|
147
|
+
plotly_restyle: 'restyle',
|
|
148
|
+
plotly_selected: 'selected',
|
|
149
|
+
plotly_selecting: 'selecting',
|
|
150
|
+
plotly_sliderchange: 'sliderChange',
|
|
151
|
+
plotly_sliderend: 'sliderEnd',
|
|
152
|
+
plotly_sliderstart: 'sliderStart',
|
|
153
|
+
plotly_sunburstclick: 'sunburstClick',
|
|
154
|
+
plotly_transitioned: 'transitioned',
|
|
155
|
+
plotly_transitioning: 'transitioning',
|
|
156
|
+
plotly_transitioninterrupted: 'transitionInterrupted',
|
|
157
|
+
plotly_unhover: 'unhover',
|
|
158
|
+
plotly_update: 'update',
|
|
159
|
+
plotly_webglcontextlost: 'webGLContextLost'
|
|
160
|
+
// TODO add all plotly_${traceType}click
|
|
161
|
+
};
|
|
162
|
+
const dispatch = createEventDispatcher<$$Events>();
|
|
163
|
+
|
|
164
|
+
// bind props
|
|
165
|
+
export let element: HTMLDivElement | not = undefined;
|
|
166
|
+
export let plot: PlotlyHTMLElement | not = undefined;
|
|
167
|
+
|
|
168
|
+
// input props
|
|
169
|
+
export let libPlotly: typeof import('plotly.js-dist') | null | undefined = undefined;
|
|
170
|
+
export let data: Data[];
|
|
171
|
+
export let layout: Partial<Layout> | undefined = undefined;
|
|
172
|
+
export let config: Partial<Config> | undefined = undefined;
|
|
173
|
+
export let fillParent: FillParent = false;
|
|
174
|
+
export let debounce: number | DebounceOptions = 0;
|
|
175
|
+
let className = '';
|
|
176
|
+
export { className as class };
|
|
177
|
+
|
|
178
|
+
// set up
|
|
179
|
+
onMount(async () => {
|
|
180
|
+
(window as any).global = window;
|
|
181
|
+
await loadPlotly();
|
|
182
|
+
});
|
|
183
|
+
|
|
184
|
+
// state props
|
|
185
|
+
let datarevision = 0;
|
|
186
|
+
let previousLib = libPlotly;
|
|
187
|
+
let previousPlot = plot;
|
|
188
|
+
let width: number = DEFAULT_WIDTH;
|
|
189
|
+
let height: number = DEFAULT_HEIGHT;
|
|
190
|
+
|
|
191
|
+
// updates
|
|
192
|
+
$: debounceWait = typeof debounce === 'object' ? debounce.wait : debounce ?? 0;
|
|
193
|
+
$: debounceOptions = typeof debounce === 'object' ? debounce : {};
|
|
194
|
+
$: data, (datarevision = (datarevision + 1) % 1000);
|
|
195
|
+
$: layout_ = { datarevision, width, height, ...layout };
|
|
196
|
+
$: config_ = { displaylogo: false, ...config };
|
|
197
|
+
$: draw(libPlotly, element, data, layout_, config_);
|
|
198
|
+
$: {
|
|
199
|
+
if (element && previousLib !== libPlotly) {
|
|
200
|
+
previousLib?.purge(element);
|
|
201
|
+
plot = undefined;
|
|
202
|
+
}
|
|
203
|
+
previousLib = libPlotly;
|
|
204
|
+
loadPlotly();
|
|
205
|
+
}
|
|
206
|
+
$: if (previousPlot !== plot) {
|
|
207
|
+
for (const [plotlyEvent, svelteEvent] of Object.entries(events)) {
|
|
208
|
+
previousPlot?.removeAllListeners?.(plotlyEvent);
|
|
209
|
+
plot?.on(plotlyEvent as any, (e: any) => dispatch(svelteEvent, e));
|
|
210
|
+
}
|
|
211
|
+
previousPlot = plot;
|
|
212
|
+
}
|
|
213
|
+
|
|
214
|
+
const drawUndebounced = (
|
|
215
|
+
lib: typeof libPlotly,
|
|
216
|
+
e: HTMLDivElement | not,
|
|
217
|
+
d: Data[],
|
|
218
|
+
l: Partial<Layout>,
|
|
219
|
+
c: Partial<Config>
|
|
220
|
+
) => {
|
|
221
|
+
if (e) lib?.react(e, d, l, c).then(p => (plot = p));
|
|
222
|
+
};
|
|
223
|
+
|
|
224
|
+
$: draw = debouncify(drawUndebounced, debounceWait, debounceOptions);
|
|
225
|
+
|
|
226
|
+
// destroy
|
|
227
|
+
onDestroy(() => element && libPlotly?.purge(element));
|
|
228
|
+
|
|
229
|
+
// autosizing
|
|
230
|
+
$: fillParent, nextFrame(onResize);
|
|
231
|
+
$: fillParentWidth = fillParent === true || fillParent === 'width';
|
|
232
|
+
$: fillParentHeight = fillParent === true || fillParent === 'height';
|
|
233
|
+
$: parent = element?.parentElement;
|
|
234
|
+
let lastParent: typeof parent = null;
|
|
235
|
+
$: {
|
|
236
|
+
parentMounted(parent);
|
|
237
|
+
parentUnmounted(lastParent);
|
|
238
|
+
lastParent = parent;
|
|
239
|
+
}
|
|
240
|
+
|
|
241
|
+
let resizeObserver: ResizeObserver | not;
|
|
242
|
+
onMount(() => (resizeObserver = new ResizeObserver(onResize)));
|
|
243
|
+
const parentMounted = (parent: Element | not) => parent && resizeObserver?.observe(parent);
|
|
244
|
+
const parentUnmounted = (parent: Element | not) => parent && resizeObserver?.unobserve(parent);
|
|
245
|
+
|
|
246
|
+
function onResize() {
|
|
247
|
+
if (!parent || !element) return;
|
|
248
|
+
|
|
249
|
+
const { offsetHeight, offsetWidth } = parent;
|
|
250
|
+
const { paddingLeft, paddingTop, paddingRight, paddingBottom } =
|
|
251
|
+
window.getComputedStyle(parent);
|
|
252
|
+
|
|
253
|
+
const maxWidth = offsetWidth - parseInt(paddingLeft) - parseInt(paddingRight);
|
|
254
|
+
const maxHeight = offsetHeight - parseInt(paddingTop) - parseInt(paddingRight);
|
|
255
|
+
|
|
256
|
+
width = fillParentWidth ? maxWidth : DEFAULT_WIDTH;
|
|
257
|
+
height = fillParentHeight ? maxHeight : DEFAULT_HEIGHT;
|
|
258
|
+
}
|
|
259
|
+
</script>
|
|
260
|
+
|
|
261
|
+
<div
|
|
262
|
+
class={className}
|
|
263
|
+
class:fillParent
|
|
264
|
+
class:fillParentWidth
|
|
265
|
+
class:fillParentHeight
|
|
266
|
+
bind:this={element}
|
|
267
|
+
/>
|
|
268
|
+
|
|
269
|
+
<style lang="scss">
|
|
270
|
+
.fillParent {
|
|
271
|
+
overflow: visible;
|
|
272
|
+
}
|
|
273
|
+
.fillParentWidth {
|
|
274
|
+
width: 0 !important;
|
|
275
|
+
max-width: 0 !important;
|
|
276
|
+
}
|
|
277
|
+
.fillParentHeight {
|
|
278
|
+
height: 0 !important;
|
|
279
|
+
max-height: 0 !important;
|
|
280
|
+
}
|
|
281
|
+
</style>
|
|
@@ -0,0 +1,103 @@
|
|
|
1
|
+
<script lang="ts">
|
|
2
|
+
import Plot from '$lib/Plot.svelte';
|
|
3
|
+
import type { Data, FillParent, DebounceOptions, Config } from '$lib/Plot.svelte';
|
|
4
|
+
|
|
5
|
+
// FA icons borrowed for testing purposes only
|
|
6
|
+
const MAXIMIZE_ICON = {
|
|
7
|
+
width: 448,
|
|
8
|
+
height: 512,
|
|
9
|
+
path: 'M447.1 319.1v135.1c0 13.26-10.75 23.1-23.1 23.1h-135.1c-12.94 0-24.61-7.781-29.56-19.75c-4.906-11.1-2.203-25.72 6.937-34.87l30.06-30.06L224 323.9l-71.43 71.44l30.06 30.06c9.156 9.156 11.91 22.91 6.937 34.87C184.6 472.2 172.9 479.1 160 479.1H24c-13.25 0-23.1-10.74-23.1-23.1v-135.1c0-12.94 7.781-24.61 19.75-29.56C23.72 288.8 27.88 288 32 288c8.312 0 16.5 3.242 22.63 9.367l30.06 30.06l71.44-71.44L84.69 184.6L54.63 214.6c-9.156 9.156-22.91 11.91-34.87 6.937C7.798 216.6 .0013 204.9 .0013 191.1v-135.1c0-13.26 10.75-23.1 23.1-23.1h135.1c12.94 0 24.61 7.781 29.56 19.75C191.2 55.72 191.1 59.87 191.1 63.1c0 8.312-3.237 16.5-9.362 22.63L152.6 116.7l71.44 71.44l71.43-71.44l-30.06-30.06c-9.156-9.156-11.91-22.91-6.937-34.87c4.937-11.95 16.62-19.75 29.56-19.75h135.1c13.26 0 23.1 10.75 23.1 23.1v135.1c0 12.94-7.781 24.61-19.75 29.56c-11.1 4.906-25.72 2.203-34.87-6.937l-30.06-30.06l-71.43 71.43l71.44 71.44l30.06-30.06c9.156-9.156 22.91-11.91 34.87-6.937C440.2 295.4 447.1 307.1 447.1 319.1z'
|
|
10
|
+
};
|
|
11
|
+
const MINIMIZE_ICON = {
|
|
12
|
+
width: 512,
|
|
13
|
+
height: 512,
|
|
14
|
+
path: 'M200 287.1H64c-12.94 0-24.62 7.797-29.56 19.75c-4.969 11.97-2.219 25.72 6.937 34.87l30.06 30.06l-62.06 62.07c-12.49 12.5-12.5 32.75-.0012 45.25l22.62 22.62c12.5 12.5 32.76 12.5 45.26 .0012l62.06-62.07l30.06 30.06c6.125 6.125 14.31 9.375 22.62 9.375c4.125 0 8.281-.7969 12.25-2.437c11.97-4.953 19.75-16.62 19.75-29.56V311.1C224 298.7 213.3 287.1 200 287.1zM312 224h135.1c12.94 0 24.62-7.797 29.56-19.75c4.969-11.97 2.219-25.72-6.937-34.87l-30.06-30.06l62.06-62.07c12.5-12.5 12.5-32.76 .0003-45.26l-22.62-22.62c-12.5-12.5-32.76-12.5-45.26-.0003l-62.06 62.07l-30.06-30.06c-9.156-9.141-22.87-11.84-34.87-6.937C295.8 39.39 288 51.06 288 64v135.1C288 213.3 298.7 224 312 224zM204.3 34.44C192.3 29.47 178.5 32.22 169.4 41.38L139.3 71.44L77.25 9.374C64.75-3.123 44.49-3.123 31.1 9.374l-22.63 22.63c-12.49 12.49-12.49 32.75 .0018 45.25l62.07 62.06L41.38 169.4C35.25 175.5 32 183.7 32 192c0 4.125 .7969 8.281 2.438 12.25C39.39 216.2 51.07 224 64 224h135.1c13.25 0 23.1-10.75 23.1-23.1V64C224 51.06 216.2 39.38 204.3 34.44zM440.6 372.7l30.06-30.06c9.141-9.156 11.84-22.88 6.938-34.87C472.6 295.8 460.9 287.1 448 287.1h-135.1c-13.25 0-23.1 10.75-23.1 23.1v135.1c0 12.94 7.797 24.62 19.75 29.56c11.97 4.969 25.72 2.219 34.87-6.937l30.06-30.06l62.06 62.06c12.5 12.5 32.76 12.5 45.26 .0002l22.62-22.62c12.5-12.5 12.5-32.76 .0002-45.26L440.6 372.7z'
|
|
15
|
+
};
|
|
16
|
+
|
|
17
|
+
let y0 = 1;
|
|
18
|
+
let useDefaultLib = true;
|
|
19
|
+
let fillParent: FillParent = false;
|
|
20
|
+
let debounce: DebounceOptions | number | undefined;
|
|
21
|
+
|
|
22
|
+
let fullscreen = false;
|
|
23
|
+
$: {
|
|
24
|
+
if (fullscreen) fillParent = true;
|
|
25
|
+
else fillParent = false;
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
let data: Data[];
|
|
29
|
+
$: data = [
|
|
30
|
+
{
|
|
31
|
+
x: [1, 2, 3, 4, 5],
|
|
32
|
+
y: [y0, 2, 4, 8, 16]
|
|
33
|
+
}
|
|
34
|
+
];
|
|
35
|
+
|
|
36
|
+
let config: Partial<Config>;
|
|
37
|
+
$: config = {
|
|
38
|
+
modeBarButtonsToAdd: [
|
|
39
|
+
{
|
|
40
|
+
name: 'fullscreen',
|
|
41
|
+
title: fullscreen ? 'Disable Fullscreen' : 'Enable Fullscreen',
|
|
42
|
+
icon: fullscreen ? MINIMIZE_ICON : MAXIMIZE_ICON,
|
|
43
|
+
click: () => (fullscreen = !fullscreen)
|
|
44
|
+
}
|
|
45
|
+
]
|
|
46
|
+
};
|
|
47
|
+
|
|
48
|
+
function addData() {
|
|
49
|
+
data.push({
|
|
50
|
+
x: [1, 2, 3, 4, 5],
|
|
51
|
+
y: Array(5)
|
|
52
|
+
.fill(0)
|
|
53
|
+
.map(_ => 10 * Math.random())
|
|
54
|
+
});
|
|
55
|
+
data = data;
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
function changeY0() {
|
|
59
|
+
y0++;
|
|
60
|
+
}
|
|
61
|
+
</script>
|
|
62
|
+
|
|
63
|
+
<Plot
|
|
64
|
+
{data}
|
|
65
|
+
{fillParent}
|
|
66
|
+
{debounce}
|
|
67
|
+
{config}
|
|
68
|
+
layout={{
|
|
69
|
+
margin: { t: 0 }
|
|
70
|
+
}}
|
|
71
|
+
libPlotly={useDefaultLib ? undefined : null}
|
|
72
|
+
on:click={console.log}
|
|
73
|
+
on:relayout={console.log}
|
|
74
|
+
/>
|
|
75
|
+
|
|
76
|
+
<div class="controls">
|
|
77
|
+
<button on:click={addData}>Add trace</button>
|
|
78
|
+
<button on:click={changeY0}>Increase y<sub>0</sub></button>
|
|
79
|
+
<button on:click={() => (useDefaultLib = !useDefaultLib)}>Swap lib</button>
|
|
80
|
+
<button on:click={() => (fillParent = false)}>Fixed size</button>
|
|
81
|
+
<button on:click={() => (fillParent = true)}>Fill parent</button>
|
|
82
|
+
<button on:click={() => (fillParent = 'width')}>Fill width</button>
|
|
83
|
+
<button on:click={() => (fillParent = 'height')}>Fill height</button>
|
|
84
|
+
<button on:click={() => (debounce = undefined)}>Don't debounce</button>
|
|
85
|
+
<button on:click={() => (debounce = 500)}>Debounce 500ms</button>
|
|
86
|
+
<button on:click={() => (debounce = { wait: 500, maxWait: 2000 })}
|
|
87
|
+
>Debounce 500ms, max wait 2s</button
|
|
88
|
+
>
|
|
89
|
+
</div>
|
|
90
|
+
|
|
91
|
+
<style lang="scss">
|
|
92
|
+
:global(html, body, body > div) {
|
|
93
|
+
padding: 0;
|
|
94
|
+
margin: 0;
|
|
95
|
+
width: 100vw;
|
|
96
|
+
height: 100vh;
|
|
97
|
+
}
|
|
98
|
+
.controls {
|
|
99
|
+
position: absolute;
|
|
100
|
+
left: 0;
|
|
101
|
+
bottom: 0;
|
|
102
|
+
}
|
|
103
|
+
</style>
|
|
Binary file
|
package/svelte.config.js
ADDED
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import adapter from '@sveltejs/adapter-auto';
|
|
2
|
+
import preprocess from 'svelte-preprocess';
|
|
3
|
+
|
|
4
|
+
/** @type {import('@sveltejs/kit').Config} */
|
|
5
|
+
const config = {
|
|
6
|
+
// Consult https://github.com/sveltejs/svelte-preprocess
|
|
7
|
+
// for more information about preprocessors
|
|
8
|
+
preprocess: preprocess(),
|
|
9
|
+
|
|
10
|
+
kit: {
|
|
11
|
+
adapter: adapter()
|
|
12
|
+
}
|
|
13
|
+
};
|
|
14
|
+
|
|
15
|
+
export default config;
|
package/tsconfig.json
ADDED
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
{
|
|
2
|
+
"extends": "./.svelte-kit/tsconfig.json",
|
|
3
|
+
"compilerOptions": {
|
|
4
|
+
"allowJs": true,
|
|
5
|
+
"checkJs": true,
|
|
6
|
+
"esModuleInterop": true,
|
|
7
|
+
"forceConsistentCasingInFileNames": true,
|
|
8
|
+
"lib": ["es2020", "DOM"],
|
|
9
|
+
"moduleResolution": "node",
|
|
10
|
+
"module": "es2020",
|
|
11
|
+
"resolveJsonModule": true,
|
|
12
|
+
"skipLibCheck": true,
|
|
13
|
+
"sourceMap": true,
|
|
14
|
+
"strict": true,
|
|
15
|
+
"target": "es2020"
|
|
16
|
+
}
|
|
17
|
+
}
|
package/Plot.svelte
DELETED
|
@@ -1,158 +0,0 @@
|
|
|
1
|
-
<script context="module">export {};
|
|
2
|
-
</script>
|
|
3
|
-
|
|
4
|
-
<script>import { onMount, onDestroy, createEventDispatcher } from 'svelte';
|
|
5
|
-
import { debounce as debouncify } from 'lodash-es';
|
|
6
|
-
const browser = typeof window === 'object';
|
|
7
|
-
const nextFrame = browser ? requestAnimationFrame : () => void 0;
|
|
8
|
-
async function loadPlotly() {
|
|
9
|
-
if (!browser)
|
|
10
|
-
return;
|
|
11
|
-
if (libPlotly === undefined) {
|
|
12
|
-
const p = await import('plotly.js-dist');
|
|
13
|
-
if (libPlotly === undefined)
|
|
14
|
-
libPlotly = p;
|
|
15
|
-
}
|
|
16
|
-
}
|
|
17
|
-
const DEFAULT_WIDTH = 500;
|
|
18
|
-
const DEFAULT_HEIGHT = 300;
|
|
19
|
-
const events = {
|
|
20
|
-
plotly_afterexport: 'afterExport',
|
|
21
|
-
plotly_afterplot: 'afterPlot',
|
|
22
|
-
plotly_animated: 'animated',
|
|
23
|
-
plotly_animating: 'animating',
|
|
24
|
-
plotly_animatingframe: 'animatingFrame',
|
|
25
|
-
plotly_animationinterrupted: 'animationInterrupted',
|
|
26
|
-
plotly_autosize: 'autoSize',
|
|
27
|
-
plotly_beforeexport: 'beforeExport',
|
|
28
|
-
plotly_beforehover: 'beforeHover',
|
|
29
|
-
plotly_beforeplot: 'beforePlot',
|
|
30
|
-
plotly_buttonclicked: 'buttonClicked',
|
|
31
|
-
plotly_click: 'click',
|
|
32
|
-
plotly_clickannotation: 'clickAnnotation',
|
|
33
|
-
plotly_deselect: 'deselect',
|
|
34
|
-
plotly_doubleclick: 'doubleClick',
|
|
35
|
-
plotly_framework: 'framework',
|
|
36
|
-
plotly_hover: 'hover',
|
|
37
|
-
plotly_legendclick: 'legendClick',
|
|
38
|
-
plotly_legenddoubleclick: 'legendDoubleClick',
|
|
39
|
-
plotly_react: 'react',
|
|
40
|
-
plotly_redraw: 'redraw',
|
|
41
|
-
plotly_relayout: 'relayout',
|
|
42
|
-
plotly_relayouting: 'relayouting',
|
|
43
|
-
plotly_restyle: 'restyle',
|
|
44
|
-
plotly_selected: 'selected',
|
|
45
|
-
plotly_selecting: 'selecting',
|
|
46
|
-
plotly_sliderchange: 'sliderChange',
|
|
47
|
-
plotly_sliderend: 'sliderEnd',
|
|
48
|
-
plotly_sliderstart: 'sliderStart',
|
|
49
|
-
plotly_sunburstclick: 'sunburstClick',
|
|
50
|
-
plotly_transitioned: 'transitioned',
|
|
51
|
-
plotly_transitioning: 'transitioning',
|
|
52
|
-
plotly_transitioninterrupted: 'transitionInterrupted',
|
|
53
|
-
plotly_unhover: 'unhover',
|
|
54
|
-
plotly_update: 'update',
|
|
55
|
-
plotly_webglcontextlost: 'webGLContextLost'
|
|
56
|
-
// TODO add all plotly_${traceType}click
|
|
57
|
-
};
|
|
58
|
-
const dispatch = createEventDispatcher();
|
|
59
|
-
// bind props
|
|
60
|
-
export let element = undefined;
|
|
61
|
-
export let plot = undefined;
|
|
62
|
-
// input props
|
|
63
|
-
export let libPlotly = undefined;
|
|
64
|
-
export let data;
|
|
65
|
-
export let layout = undefined;
|
|
66
|
-
export let config = undefined;
|
|
67
|
-
export let fillParent = false;
|
|
68
|
-
export let debounce = 0;
|
|
69
|
-
let className = '';
|
|
70
|
-
export { className as class };
|
|
71
|
-
// set up
|
|
72
|
-
onMount(async () => {
|
|
73
|
-
window.global = window;
|
|
74
|
-
await loadPlotly();
|
|
75
|
-
});
|
|
76
|
-
// state props
|
|
77
|
-
let datarevision = 0;
|
|
78
|
-
let previousLib = libPlotly;
|
|
79
|
-
let previousPlot = plot;
|
|
80
|
-
let width = DEFAULT_WIDTH;
|
|
81
|
-
let height = DEFAULT_HEIGHT;
|
|
82
|
-
// updates
|
|
83
|
-
$: debounceWait = typeof debounce === 'object' ? debounce.wait : debounce ?? 0;
|
|
84
|
-
$: debounceOptions = typeof debounce === 'object' ? debounce : {};
|
|
85
|
-
$: data, (datarevision = (datarevision + 1) % 1000);
|
|
86
|
-
$: layout_ = { datarevision, width, height, ...layout };
|
|
87
|
-
$: config_ = { displaylogo: false, ...config };
|
|
88
|
-
$: draw(libPlotly, element, data, layout_, config_);
|
|
89
|
-
$: {
|
|
90
|
-
if (element && previousLib !== libPlotly) {
|
|
91
|
-
previousLib?.purge(element);
|
|
92
|
-
plot = undefined;
|
|
93
|
-
}
|
|
94
|
-
previousLib = libPlotly;
|
|
95
|
-
loadPlotly();
|
|
96
|
-
}
|
|
97
|
-
$: if (previousPlot !== plot) {
|
|
98
|
-
for (const [plotlyEvent, svelteEvent] of Object.entries(events)) {
|
|
99
|
-
previousPlot?.removeAllListeners?.(plotlyEvent);
|
|
100
|
-
plot?.on(plotlyEvent, (e) => dispatch(svelteEvent, e));
|
|
101
|
-
}
|
|
102
|
-
previousPlot = plot;
|
|
103
|
-
}
|
|
104
|
-
const drawUndebounced = (lib, e, d, l, c) => {
|
|
105
|
-
if (e)
|
|
106
|
-
lib?.react(e, d, l, c).then(p => (plot = p));
|
|
107
|
-
};
|
|
108
|
-
$: draw = debouncify(drawUndebounced, debounceWait, debounceOptions);
|
|
109
|
-
// destroy
|
|
110
|
-
onDestroy(() => element && libPlotly?.purge(element));
|
|
111
|
-
// autosizing
|
|
112
|
-
$: fillParent, nextFrame(onResize);
|
|
113
|
-
$: fillParentWidth = fillParent === true || fillParent === 'width';
|
|
114
|
-
$: fillParentHeight = fillParent === true || fillParent === 'height';
|
|
115
|
-
$: parent = element?.parentElement;
|
|
116
|
-
let lastParent = null;
|
|
117
|
-
$: {
|
|
118
|
-
parentMounted(parent);
|
|
119
|
-
parentUnmounted(lastParent);
|
|
120
|
-
lastParent = parent;
|
|
121
|
-
}
|
|
122
|
-
let resizeObserver;
|
|
123
|
-
onMount(() => (resizeObserver = new ResizeObserver(onResize)));
|
|
124
|
-
const parentMounted = (parent) => parent && resizeObserver?.observe(parent);
|
|
125
|
-
const parentUnmounted = (parent) => parent && resizeObserver?.unobserve(parent);
|
|
126
|
-
function onResize() {
|
|
127
|
-
if (!parent || !element)
|
|
128
|
-
return;
|
|
129
|
-
const { offsetHeight, offsetWidth } = parent;
|
|
130
|
-
const { paddingLeft, paddingTop, paddingRight, paddingBottom } = window.getComputedStyle(parent);
|
|
131
|
-
const maxWidth = offsetWidth - parseInt(paddingLeft) - parseInt(paddingRight);
|
|
132
|
-
const maxHeight = offsetHeight - parseInt(paddingTop) - parseInt(paddingRight);
|
|
133
|
-
width = fillParentWidth ? maxWidth : DEFAULT_WIDTH;
|
|
134
|
-
height = fillParentHeight ? maxHeight : DEFAULT_HEIGHT;
|
|
135
|
-
}
|
|
136
|
-
</script>
|
|
137
|
-
|
|
138
|
-
<div
|
|
139
|
-
class={className}
|
|
140
|
-
class:fillParent
|
|
141
|
-
class:fillParentWidth
|
|
142
|
-
class:fillParentHeight
|
|
143
|
-
bind:this={element}
|
|
144
|
-
/>
|
|
145
|
-
|
|
146
|
-
<style>.fillParent {
|
|
147
|
-
overflow: visible;
|
|
148
|
-
}
|
|
149
|
-
|
|
150
|
-
.fillParentWidth {
|
|
151
|
-
width: 0 !important;
|
|
152
|
-
max-width: 0 !important;
|
|
153
|
-
}
|
|
154
|
-
|
|
155
|
-
.fillParentHeight {
|
|
156
|
-
height: 0 !important;
|
|
157
|
-
max-height: 0 !important;
|
|
158
|
-
}</style>
|
package/Plot.svelte.d.ts
DELETED
|
@@ -1,76 +0,0 @@
|
|
|
1
|
-
/// <reference types="lodash" />
|
|
2
|
-
import { SvelteComponentTyped } from "svelte";
|
|
3
|
-
import type { Data, Layout, Config, PlotlyHTMLElement, BeforePlotEvent, ClickAnnotationEvent, FrameAnimationEvent, LegendClickEvent, PlotMouseEvent, PlotHoverEvent, PlotRelayoutEvent, PlotRestyleEvent, PlotSelectionEvent, SliderEndEvent, SliderChangeEvent, SliderStartEvent, SunburstClickEvent } from 'plotly.js';
|
|
4
|
-
export type { Data, Layout, Config, PlotlyHTMLElement, BeforePlotEvent, ClickAnnotationEvent, FrameAnimationEvent, LegendClickEvent, PlotMouseEvent, PlotHoverEvent, PlotRelayoutEvent, PlotRestyleEvent, PlotSelectionEvent, SliderChangeEvent, SliderStartEvent, SunburstClickEvent };
|
|
5
|
-
export declare type FillParent = boolean | 'width' | 'height';
|
|
6
|
-
import type { DebounceSettings } from 'lodash-es';
|
|
7
|
-
export interface DebounceOptions extends DebounceSettings {
|
|
8
|
-
wait: number;
|
|
9
|
-
}
|
|
10
|
-
export interface ButtonClickedEvent {
|
|
11
|
-
menu: any;
|
|
12
|
-
button: any;
|
|
13
|
-
active: any;
|
|
14
|
-
}
|
|
15
|
-
export interface PlotUpdateEvent {
|
|
16
|
-
data: Data;
|
|
17
|
-
layout: Layout;
|
|
18
|
-
}
|
|
19
|
-
declare const __propDef: {
|
|
20
|
-
props: {
|
|
21
|
-
element?: (null | undefined) | HTMLDivElement;
|
|
22
|
-
plot?: (null | undefined) | PlotlyHTMLElement;
|
|
23
|
-
libPlotly?: typeof import('plotly.js-dist') | null | undefined;
|
|
24
|
-
data: Data[];
|
|
25
|
-
layout?: Partial<Layout> | undefined;
|
|
26
|
-
config?: Partial<Config> | undefined;
|
|
27
|
-
fillParent?: FillParent | undefined;
|
|
28
|
-
debounce?: number | DebounceOptions | undefined;
|
|
29
|
-
class?: string | undefined;
|
|
30
|
-
};
|
|
31
|
-
slots: {};
|
|
32
|
-
getters: {};
|
|
33
|
-
events: {
|
|
34
|
-
afterExport: undefined;
|
|
35
|
-
afterPlot: undefined;
|
|
36
|
-
animated: undefined;
|
|
37
|
-
animating: undefined;
|
|
38
|
-
animatingFrame: FrameAnimationEvent;
|
|
39
|
-
animationInterrupted: undefined;
|
|
40
|
-
autoSize: undefined;
|
|
41
|
-
beforeExport: undefined;
|
|
42
|
-
beforeHover: PlotMouseEvent;
|
|
43
|
-
beforePlot: BeforePlotEvent;
|
|
44
|
-
buttonClicked: ButtonClickedEvent;
|
|
45
|
-
click: PlotMouseEvent;
|
|
46
|
-
clickAnnotation: ClickAnnotationEvent;
|
|
47
|
-
deselect: undefined;
|
|
48
|
-
doubleClick: undefined;
|
|
49
|
-
framework: undefined;
|
|
50
|
-
hover: PlotHoverEvent;
|
|
51
|
-
legendClick: LegendClickEvent;
|
|
52
|
-
legendDoubleClick: LegendClickEvent;
|
|
53
|
-
react: PlotUpdateEvent;
|
|
54
|
-
redraw: undefined;
|
|
55
|
-
relayout: PlotRelayoutEvent;
|
|
56
|
-
relayouting: PlotRelayoutEvent;
|
|
57
|
-
restyle: PlotRestyleEvent;
|
|
58
|
-
selected: PlotSelectionEvent;
|
|
59
|
-
selecting: PlotSelectionEvent;
|
|
60
|
-
sliderChange: SliderChangeEvent;
|
|
61
|
-
sliderEnd: SliderEndEvent;
|
|
62
|
-
sliderStart: SliderStartEvent;
|
|
63
|
-
sunburstClick: SunburstClickEvent;
|
|
64
|
-
transitioned: undefined;
|
|
65
|
-
transitioning: undefined;
|
|
66
|
-
transitionInterrupted: undefined;
|
|
67
|
-
unhover: PlotMouseEvent;
|
|
68
|
-
update: PlotUpdateEvent;
|
|
69
|
-
webGLContextLost: undefined;
|
|
70
|
-
};
|
|
71
|
-
};
|
|
72
|
-
export declare type PlotProps = typeof __propDef.props;
|
|
73
|
-
export declare type PlotEvents = typeof __propDef.events;
|
|
74
|
-
export declare type PlotSlots = typeof __propDef.slots;
|
|
75
|
-
export default class Plot extends SvelteComponentTyped<PlotProps, PlotEvents, PlotSlots> {
|
|
76
|
-
}
|