@genspectrum/dashboard-components 0.19.8 → 0.19.9
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/custom-elements.json +31 -13
- package/dist/assets/mutationOverTimeWorker-BzmkceEA.js.map +1 -0
- package/dist/components.d.ts +35 -35
- package/dist/components.js +4 -6
- package/dist/components.js.map +1 -1
- package/dist/util.d.ts +35 -35
- package/package.json +1 -1
- package/src/web-components/input/introduction.mdx +57 -2
- package/src/web-components/tutorials/CreateYourFirstOwnDashboard.mdx +85 -0
- package/src/web-components/tutorials/UseTheComponentsWithPlainJavaScript.mdx +140 -0
- package/src/web-components/tutorials/UseTheComponentsWithReact.mdx +166 -0
- package/src/web-components/visualization/gs-mutations.tsx +2 -2
- package/src/web-components/visualization/introduction.mdx +51 -0
- package/standalone-bundle/assets/mutationOverTimeWorker-jUeItsGM.js.map +1 -0
- package/standalone-bundle/dashboard-components.js +7070 -7101
- package/standalone-bundle/dashboard-components.js.map +1 -1
- package/dist/assets/mutationOverTimeWorker-CBXsEsiT.js.map +0 -1
- package/src/web-components/visualization/data_visualization_statistical_analysis.mdx +0 -26
- package/standalone-bundle/assets/mutationOverTimeWorker-CN4SJC7C.js.map +0 -1
- /package/src/web-components/{MutationAnnotations.mdx → mutationAnnotations.mdx} +0 -0
- /package/src/web-components/{ResizeContainer.mdx → sizeOfComponents.mdx} +0 -0
package/dist/util.d.ts
CHANGED
|
@@ -936,6 +936,22 @@ declare global {
|
|
|
936
936
|
}
|
|
937
937
|
|
|
938
938
|
|
|
939
|
+
declare global {
|
|
940
|
+
interface HTMLElementTagNameMap {
|
|
941
|
+
'gs-wastewater-mutations-over-time': WastewaterMutationsOverTimeComponent;
|
|
942
|
+
}
|
|
943
|
+
}
|
|
944
|
+
|
|
945
|
+
|
|
946
|
+
declare global {
|
|
947
|
+
namespace JSX {
|
|
948
|
+
interface IntrinsicElements {
|
|
949
|
+
'gs-wastewater-mutations-over-time': DetailedHTMLProps<HTMLAttributes<HTMLElement>, HTMLElement>;
|
|
950
|
+
}
|
|
951
|
+
}
|
|
952
|
+
}
|
|
953
|
+
|
|
954
|
+
|
|
939
955
|
declare global {
|
|
940
956
|
interface HTMLElementTagNameMap {
|
|
941
957
|
'gs-genome-data-viewer': GenomeDataViewerComponent;
|
|
@@ -970,7 +986,7 @@ declare global {
|
|
|
970
986
|
|
|
971
987
|
declare global {
|
|
972
988
|
interface HTMLElementTagNameMap {
|
|
973
|
-
'gs-mutations
|
|
989
|
+
'gs-mutations': MutationsComponent;
|
|
974
990
|
}
|
|
975
991
|
}
|
|
976
992
|
|
|
@@ -978,7 +994,7 @@ declare global {
|
|
|
978
994
|
declare global {
|
|
979
995
|
namespace JSX {
|
|
980
996
|
interface IntrinsicElements {
|
|
981
|
-
'gs-mutations
|
|
997
|
+
'gs-mutations': DetailedHTMLProps<HTMLAttributes<HTMLElement>, HTMLElement>;
|
|
982
998
|
}
|
|
983
999
|
}
|
|
984
1000
|
}
|
|
@@ -986,7 +1002,7 @@ declare global {
|
|
|
986
1002
|
|
|
987
1003
|
declare global {
|
|
988
1004
|
interface HTMLElementTagNameMap {
|
|
989
|
-
'gs-
|
|
1005
|
+
'gs-relative-growth-advantage': RelativeGrowthAdvantageComponent;
|
|
990
1006
|
}
|
|
991
1007
|
}
|
|
992
1008
|
|
|
@@ -994,7 +1010,7 @@ declare global {
|
|
|
994
1010
|
declare global {
|
|
995
1011
|
namespace JSX {
|
|
996
1012
|
interface IntrinsicElements {
|
|
997
|
-
'gs-
|
|
1013
|
+
'gs-relative-growth-advantage': DetailedHTMLProps<HTMLAttributes<HTMLElement>, HTMLElement>;
|
|
998
1014
|
}
|
|
999
1015
|
}
|
|
1000
1016
|
}
|
|
@@ -1002,7 +1018,7 @@ declare global {
|
|
|
1002
1018
|
|
|
1003
1019
|
declare global {
|
|
1004
1020
|
interface HTMLElementTagNameMap {
|
|
1005
|
-
'gs-
|
|
1021
|
+
'gs-prevalence-over-time': PrevalenceOverTimeComponent;
|
|
1006
1022
|
}
|
|
1007
1023
|
}
|
|
1008
1024
|
|
|
@@ -1010,7 +1026,7 @@ declare global {
|
|
|
1010
1026
|
declare global {
|
|
1011
1027
|
namespace JSX {
|
|
1012
1028
|
interface IntrinsicElements {
|
|
1013
|
-
'gs-
|
|
1029
|
+
'gs-prevalence-over-time': DetailedHTMLProps<HTMLAttributes<HTMLElement>, HTMLElement>;
|
|
1014
1030
|
}
|
|
1015
1031
|
}
|
|
1016
1032
|
}
|
|
@@ -1102,10 +1118,7 @@ declare global {
|
|
|
1102
1118
|
|
|
1103
1119
|
declare global {
|
|
1104
1120
|
interface HTMLElementTagNameMap {
|
|
1105
|
-
'gs-
|
|
1106
|
-
}
|
|
1107
|
-
interface HTMLElementEventMap {
|
|
1108
|
-
[gsEventNames.locationChanged]: LocationChangedEvent;
|
|
1121
|
+
'gs-statistics': StatisticsComponent;
|
|
1109
1122
|
}
|
|
1110
1123
|
}
|
|
1111
1124
|
|
|
@@ -1113,7 +1126,7 @@ declare global {
|
|
|
1113
1126
|
declare global {
|
|
1114
1127
|
namespace JSX {
|
|
1115
1128
|
interface IntrinsicElements {
|
|
1116
|
-
'gs-
|
|
1129
|
+
'gs-statistics': DetailedHTMLProps<HTMLAttributes<HTMLElement>, HTMLElement>;
|
|
1117
1130
|
}
|
|
1118
1131
|
}
|
|
1119
1132
|
}
|
|
@@ -1121,7 +1134,10 @@ declare global {
|
|
|
1121
1134
|
|
|
1122
1135
|
declare global {
|
|
1123
1136
|
interface HTMLElementTagNameMap {
|
|
1124
|
-
'gs-
|
|
1137
|
+
'gs-location-filter': LocationFilterComponent;
|
|
1138
|
+
}
|
|
1139
|
+
interface HTMLElementEventMap {
|
|
1140
|
+
[gsEventNames.locationChanged]: LocationChangedEvent;
|
|
1125
1141
|
}
|
|
1126
1142
|
}
|
|
1127
1143
|
|
|
@@ -1129,7 +1145,7 @@ declare global {
|
|
|
1129
1145
|
declare global {
|
|
1130
1146
|
namespace JSX {
|
|
1131
1147
|
interface IntrinsicElements {
|
|
1132
|
-
'gs-
|
|
1148
|
+
'gs-location-filter': DetailedHTMLProps<HTMLAttributes<HTMLElement>, HTMLElement>;
|
|
1133
1149
|
}
|
|
1134
1150
|
}
|
|
1135
1151
|
}
|
|
@@ -1156,10 +1172,10 @@ declare global {
|
|
|
1156
1172
|
|
|
1157
1173
|
declare global {
|
|
1158
1174
|
interface HTMLElementTagNameMap {
|
|
1159
|
-
'gs-
|
|
1175
|
+
'gs-mutation-filter': MutationFilterComponent;
|
|
1160
1176
|
}
|
|
1161
1177
|
interface HTMLElementEventMap {
|
|
1162
|
-
[gsEventNames.
|
|
1178
|
+
[gsEventNames.mutationFilterChanged]: CustomEvent<MutationsFilter>;
|
|
1163
1179
|
}
|
|
1164
1180
|
}
|
|
1165
1181
|
|
|
@@ -1167,7 +1183,7 @@ declare global {
|
|
|
1167
1183
|
declare global {
|
|
1168
1184
|
namespace JSX {
|
|
1169
1185
|
interface IntrinsicElements {
|
|
1170
|
-
'gs-
|
|
1186
|
+
'gs-mutation-filter': DetailedHTMLProps<HTMLAttributes<HTMLElement>, HTMLElement>;
|
|
1171
1187
|
}
|
|
1172
1188
|
}
|
|
1173
1189
|
}
|
|
@@ -1175,10 +1191,10 @@ declare global {
|
|
|
1175
1191
|
|
|
1176
1192
|
declare global {
|
|
1177
1193
|
interface HTMLElementTagNameMap {
|
|
1178
|
-
'gs-
|
|
1194
|
+
'gs-lineage-filter': LineageFilterComponent;
|
|
1179
1195
|
}
|
|
1180
1196
|
interface HTMLElementEventMap {
|
|
1181
|
-
[gsEventNames.
|
|
1197
|
+
[gsEventNames.lineageFilterChanged]: LineageFilterChangedEvent;
|
|
1182
1198
|
}
|
|
1183
1199
|
}
|
|
1184
1200
|
|
|
@@ -1186,7 +1202,7 @@ declare global {
|
|
|
1186
1202
|
declare global {
|
|
1187
1203
|
namespace JSX {
|
|
1188
1204
|
interface IntrinsicElements {
|
|
1189
|
-
'gs-
|
|
1205
|
+
'gs-lineage-filter': DetailedHTMLProps<HTMLAttributes<HTMLElement>, HTMLElement>;
|
|
1190
1206
|
}
|
|
1191
1207
|
}
|
|
1192
1208
|
}
|
|
@@ -1212,22 +1228,6 @@ declare global {
|
|
|
1212
1228
|
}
|
|
1213
1229
|
|
|
1214
1230
|
|
|
1215
|
-
declare global {
|
|
1216
|
-
interface HTMLElementTagNameMap {
|
|
1217
|
-
'gs-wastewater-mutations-over-time': WastewaterMutationsOverTimeComponent;
|
|
1218
|
-
}
|
|
1219
|
-
}
|
|
1220
|
-
|
|
1221
|
-
|
|
1222
|
-
declare global {
|
|
1223
|
-
namespace JSX {
|
|
1224
|
-
interface IntrinsicElements {
|
|
1225
|
-
'gs-wastewater-mutations-over-time': DetailedHTMLProps<HTMLAttributes<HTMLElement>, HTMLElement>;
|
|
1226
|
-
}
|
|
1227
|
-
}
|
|
1228
|
-
}
|
|
1229
|
-
|
|
1230
|
-
|
|
1231
1231
|
declare module 'chart.js' {
|
|
1232
1232
|
interface CartesianScaleTypeRegistry {
|
|
1233
1233
|
logit: {
|
package/package.json
CHANGED
|
@@ -7,5 +7,60 @@ import { Meta } from '@storybook/blocks';
|
|
|
7
7
|
The components in this section let the user specify values for LAPIS filters.
|
|
8
8
|
The filters can then be used as input to the visualization components.
|
|
9
9
|
|
|
10
|
-
Every component fires `CustomEvent`s when the user interacts with it
|
|
11
|
-
|
|
10
|
+
Every component fires `CustomEvent`s when the user interacts with it.
|
|
11
|
+
`event.detail` contains the payload of the event.
|
|
12
|
+
|
|
13
|
+
Every component fires an event that can be used to update the LAPIS filters.
|
|
14
|
+
It is supposed to be used in the style of:
|
|
15
|
+
|
|
16
|
+
```javascript
|
|
17
|
+
component.addEventListener('gs-example-event', (event) => {
|
|
18
|
+
setNewLapisFilter({
|
|
19
|
+
...previousLapisFilter,
|
|
20
|
+
...event.detail,
|
|
21
|
+
});
|
|
22
|
+
});
|
|
23
|
+
```
|
|
24
|
+
|
|
25
|
+
## Controlled Input Components
|
|
26
|
+
|
|
27
|
+
HTML input components can be controlled or uncontrolled.
|
|
28
|
+
In a controlled component, the value is controlled by surrounding Javascript code.
|
|
29
|
+
In an uncontrolled component, the value is controlled by the DOM and the surrounding Javascript code only reads the value
|
|
30
|
+
(e.g. by listening to events).
|
|
31
|
+
|
|
32
|
+
All our input components can be used in both ways.
|
|
33
|
+
Every component fires one or two events.
|
|
34
|
+
If the event details can be used to update the LAPIS filter
|
|
35
|
+
_and_ the value then the component will only fire one event,
|
|
36
|
+
otherwise it will fire one event to update the LAPIS filter and one to update the value of the component.
|
|
37
|
+
Refer to the documentation of the individual components for details on which event you can use for which purpose.
|
|
38
|
+
|
|
39
|
+
**Example**: A controlled input component in a React app could conceptually look like this:
|
|
40
|
+
|
|
41
|
+
```javascript
|
|
42
|
+
import { useEffect, useRef, useState } from 'react';
|
|
43
|
+
|
|
44
|
+
const ExampleInput = () => {
|
|
45
|
+
const [value, setValue] = useState('foo');
|
|
46
|
+
const inputRef = useRef(null);
|
|
47
|
+
|
|
48
|
+
useEffect(() => {
|
|
49
|
+
if (!inputRef.current) {
|
|
50
|
+
return;
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
const eventListener = (event) => {
|
|
54
|
+
setValue(event.detail);
|
|
55
|
+
};
|
|
56
|
+
|
|
57
|
+
inputRef.current.addEventListener('gs-input', eventListener);
|
|
58
|
+
|
|
59
|
+
return () => {
|
|
60
|
+
inputRef.current.removeEventListener('gs-input', eventListener);
|
|
61
|
+
};
|
|
62
|
+
}, []);
|
|
63
|
+
|
|
64
|
+
return <gs-example-input ref={inputRef} value={value} />;
|
|
65
|
+
};
|
|
66
|
+
```
|
|
@@ -0,0 +1,85 @@
|
|
|
1
|
+
import { Meta } from '@storybook/blocks';
|
|
2
|
+
|
|
3
|
+
<Meta title='Tutorials/Create your first own dashboard' />
|
|
4
|
+
|
|
5
|
+
# Create your first own dashboard
|
|
6
|
+
|
|
7
|
+
In this tutorial, you’ll learn how to integrate our `visualization` components into your HTML page.
|
|
8
|
+
We’ll walk through building a simple dashboard that displays the number of sequences over time, along with some general statistics.
|
|
9
|
+
This example serves as a foundation for your own dashboards—you can easily extend it by adding more components as needed.
|
|
10
|
+
The data for these components must be provided by a LAPIS instance.
|
|
11
|
+
For this tutorial, we’ll use one of our own [LAPIS](https://lapis.cov-spectrum.org/open/v2/docs/) instances, but you’re free to use any LAPIS instance that supplies the required data.
|
|
12
|
+
|
|
13
|
+
## Create your HTML page
|
|
14
|
+
|
|
15
|
+
Let's start by creating a simple HTML page. If you already have one, you can skip this step.
|
|
16
|
+
Name the file `index.html` and add the following code. This will be the main file for your dashboard.
|
|
17
|
+
|
|
18
|
+
```html
|
|
19
|
+
<!doctype html>
|
|
20
|
+
<html lang="en">
|
|
21
|
+
<head>
|
|
22
|
+
<meta charset="UTF-8" />
|
|
23
|
+
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
|
24
|
+
<title>My dashboard</title>
|
|
25
|
+
</head>
|
|
26
|
+
<body>
|
|
27
|
+
We will fill this section later
|
|
28
|
+
</body>
|
|
29
|
+
</html>
|
|
30
|
+
```
|
|
31
|
+
|
|
32
|
+
## Include the dashboard components
|
|
33
|
+
|
|
34
|
+
To use the components, you need to include the dashboard bundle in your HTML file.
|
|
35
|
+
Add the following code to the `head` section:
|
|
36
|
+
|
|
37
|
+
```html
|
|
38
|
+
<script
|
|
39
|
+
type="module"
|
|
40
|
+
src="https://unpkg.com/@genspectrum/dashboard-components@latest/standalone-bundle/dashboard-components.js"
|
|
41
|
+
></script>
|
|
42
|
+
```
|
|
43
|
+
|
|
44
|
+
This approach uses a standalone bundle, which includes all the code for the components in a single step.
|
|
45
|
+
It is the easiest way to get started, although the bundle size is larger.
|
|
46
|
+
Alternatively, you can use the components as modules, but this requires a build step.
|
|
47
|
+
For more information, see the "Use the Components with Plain JavaScript" tutorial.
|
|
48
|
+
|
|
49
|
+
## Add the dashboard components to your HTML file
|
|
50
|
+
|
|
51
|
+
We are now ready to add the components to our HTML file.
|
|
52
|
+
You can do this by adding the following code to the `body` section of your HTML file:
|
|
53
|
+
|
|
54
|
+
```html
|
|
55
|
+
<gs-app lapis="https://lapis.genspectrum.org/open/v2">
|
|
56
|
+
<h2>Statistics</h2>
|
|
57
|
+
<gs-statistics numeratorFilter='{"pangoLineage": "EG*"}' denominatorFilter="{}" width="100%"></gs-statistics>
|
|
58
|
+
<h2>Number of sequences over time</h2>
|
|
59
|
+
<gs-number-sequences-over-time
|
|
60
|
+
lapisFilters='[{ "displayName": "EG", "lapisFilter": { "pangoLineage": "EG*" } }]'
|
|
61
|
+
lapisDateField="date"
|
|
62
|
+
views='["bar", "line", "table"]'
|
|
63
|
+
width="100%"
|
|
64
|
+
granularity="month"
|
|
65
|
+
smoothingWindow="0"
|
|
66
|
+
pageSize="10"
|
|
67
|
+
></gs-number-sequences-over-time>
|
|
68
|
+
</gs-app>
|
|
69
|
+
```
|
|
70
|
+
|
|
71
|
+
Here, we are using three components:
|
|
72
|
+
|
|
73
|
+
- `gs-app`: This is the main component that wraps all the other components. It is used to provide the context for the other components. Each of our components needs to be wrapped in this component.
|
|
74
|
+
It provides the `lapis` attribute, which is the URL of the LAPIS server. This is the server that provides the data for the components. In this example, we are using the LAPIS server for open SARS-CoV-2 data.
|
|
75
|
+
- `gs-statistics` and `gs-number-sequences-over-time`: Visualization components that display data from the LAPIS server.
|
|
76
|
+
|
|
77
|
+
You can find more examples and detailed descriptions of each component in our documentation.
|
|
78
|
+
|
|
79
|
+
You now have your first dashboard. Open the `index.html` file in your browser to see it in action.
|
|
80
|
+
Feel free to change some parameters to see how they affect the dashboard, or explore our Storybook for more examples.
|
|
81
|
+
|
|
82
|
+
The parameters are currently fixed in the HTML file.
|
|
83
|
+
If you want users to be able to change them—especially the filters—we also provide input components.
|
|
84
|
+
To use them, add the input components to your HTML and connect them with JavaScript.
|
|
85
|
+
For more information, see the "Use the Components with Plain JavaScript" tutorial.
|
|
@@ -0,0 +1,140 @@
|
|
|
1
|
+
import { Meta } from '@storybook/blocks';
|
|
2
|
+
|
|
3
|
+
<Meta title='Tutorials/Use the components with plain JavaScript' />
|
|
4
|
+
|
|
5
|
+
# Use the components in plain JavaScript
|
|
6
|
+
|
|
7
|
+
In this tutorial, we will show you how to use dashboard components with plain JavaScript,
|
|
8
|
+
which might be useful if you want to use the components in a framework like Svelte or Vue.js.
|
|
9
|
+
For React, we have a separate tutorial.
|
|
10
|
+
We will create a simple dashboard that shows the number of sequences over time and allows you to filter the data by location.
|
|
11
|
+
You can find a similar working example in our [examples directory](https://github.com/GenSpectrum/dashboard-components/tree/4ae6a7a9aab3c4c583704f49845c042bcbb6d311/examples/plainJavascript)
|
|
12
|
+
The data for these components must be provided by a LAPIS instance.
|
|
13
|
+
For this tutorial, we’ll use one of our own [LAPIS](https://lapis.cov-spectrum.org/open/v2/docs/) instances, but you’re free to use any LAPIS instance that supplies the required data.
|
|
14
|
+
|
|
15
|
+
## Prerequisites
|
|
16
|
+
|
|
17
|
+
We assume that you already have a working environment with the following:
|
|
18
|
+
|
|
19
|
+
- Node.js installed
|
|
20
|
+
- A package manager (npm or yarn)
|
|
21
|
+
- A html file where you want to use the components. Here we will use a file called `index.html`.
|
|
22
|
+
|
|
23
|
+
For this tutorial, we use [Vite](https://vite.dev/guide/#index-html-and-project-root) as a build tool. You can use any other build tool, but this will not be covered in this tutorial.
|
|
24
|
+
|
|
25
|
+
## Install the dashboard components
|
|
26
|
+
|
|
27
|
+
First, install the components by running the following command in your terminal:
|
|
28
|
+
|
|
29
|
+
```bash
|
|
30
|
+
npm install @genspectrum/dashboard-components
|
|
31
|
+
```
|
|
32
|
+
|
|
33
|
+
Then, load the components in your HTML file by adding the following code to the `head` section of your HTML file:
|
|
34
|
+
|
|
35
|
+
```html
|
|
36
|
+
<script type="module" src="node_modules/@genspectrum/dashboard-components/dist/components.js"></script>
|
|
37
|
+
```
|
|
38
|
+
|
|
39
|
+
**Note**: Currently, there is an issue with one of our dependencies. To resolve this, create an additional file called `vite.config.js` and add the following code to it:
|
|
40
|
+
|
|
41
|
+
```javascript
|
|
42
|
+
import { defineConfig } from 'vite';
|
|
43
|
+
|
|
44
|
+
export default defineConfig({
|
|
45
|
+
optimizeDeps: {
|
|
46
|
+
include: ['leaflet'],
|
|
47
|
+
},
|
|
48
|
+
});
|
|
49
|
+
```
|
|
50
|
+
|
|
51
|
+
## Add the dashboard components to your HTML file
|
|
52
|
+
|
|
53
|
+
You can now add components to your HTML file by adding, for example, the following code to the `body` section of your HTML file:
|
|
54
|
+
|
|
55
|
+
```html
|
|
56
|
+
<gs-app lapis="https://lapis.genspectrum.org/open/v2">
|
|
57
|
+
<h2>Filter By Location</h2>
|
|
58
|
+
<gs-location-filter
|
|
59
|
+
fields='["region", "country", "division"]'
|
|
60
|
+
width="100%"
|
|
61
|
+
placeholderText="Enter a location"
|
|
62
|
+
></gs-location-filter>
|
|
63
|
+
<h2>Number of sequences over time</h2>
|
|
64
|
+
<gs-number-sequences-over-time
|
|
65
|
+
lapisFilters='[{ "displayName": "Data", "lapisFilter": {}}]'
|
|
66
|
+
lapisDateField="date"
|
|
67
|
+
views='["bar", "line", "table"]'
|
|
68
|
+
width="100%"
|
|
69
|
+
granularity="month"
|
|
70
|
+
smoothingWindow="0"
|
|
71
|
+
pageSize="10"
|
|
72
|
+
></gs-number-sequences-over-time>
|
|
73
|
+
</gs-app>
|
|
74
|
+
```
|
|
75
|
+
|
|
76
|
+
As you can see, we are using three components:
|
|
77
|
+
|
|
78
|
+
- `gs-app`: This is the main component that wraps all the other components, providing the context for them. Each of our components must be wrapped in this component.
|
|
79
|
+
It provides the `lapis` prop, which is the URL of the LAPIS server, the server that provides the data for the components. In this example, we are using the LAPIS server for open SARS-CoV-2 data.
|
|
80
|
+
- `gs-location-filter`: This is an example of our input components, which are used to create LAPIS filters for the visualization components. In this case, it is used to filter the data by location.
|
|
81
|
+
- `gs-number-sequences-over-time`: This is an example of our visualization components, which are used to visualize the data from the LAPIS server. In this case, it shows the number of sequences over time.
|
|
82
|
+
|
|
83
|
+
You can find more examples and descriptions of each component in our documentation.
|
|
84
|
+
|
|
85
|
+
Now you can look at your dashboard by running vite in your terminal:
|
|
86
|
+
|
|
87
|
+
```bash
|
|
88
|
+
npx vite dev
|
|
89
|
+
```
|
|
90
|
+
|
|
91
|
+
If you only want to use the visualization components, you are finished here. If you want to use the input components, you will need to add some additional code to make them work.
|
|
92
|
+
|
|
93
|
+
## Add interactivity between the components
|
|
94
|
+
|
|
95
|
+
Each of our `input` components emits an event when the user selects a new value. You can listen to this event and update the `visualization` components accordingly.
|
|
96
|
+
First, you need to add a script tag to your HTML file and listen to the events. This should only be done after the page has loaded. You can do this by adding the following code below the `gs-app` component:
|
|
97
|
+
|
|
98
|
+
```html
|
|
99
|
+
<script>
|
|
100
|
+
document.addEventListener('DOMContentLoaded', function () {
|
|
101
|
+
document.querySelector('gs-location-filter').addEventListener('gs-location-changed', (event) => {
|
|
102
|
+
const newLocationFilter = event.detail;
|
|
103
|
+
console.log('newLocationFilter', newLocationFilter);
|
|
104
|
+
});
|
|
105
|
+
});
|
|
106
|
+
</script>
|
|
107
|
+
```
|
|
108
|
+
|
|
109
|
+
You should now see the location value in the browser console after changing the value in the location filter.
|
|
110
|
+
You can find more information about event listeners in the [MDN documentation](https://developer.mozilla.org/en-US/docs/Web/API/EventTarget/addEventListener).
|
|
111
|
+
|
|
112
|
+
Now, you need to add the code to update the `gs-number-sequences-over-time` component.
|
|
113
|
+
There, you need to update the `lapisFilters`.
|
|
114
|
+
You first get the current filter values of the component, and then you add the new location filter to each of them.
|
|
115
|
+
|
|
116
|
+
```html
|
|
117
|
+
<script>
|
|
118
|
+
document.addEventListener('DOMContentLoaded', function () {
|
|
119
|
+
document.querySelector('gs-location-filter').addEventListener('gs-location-changed', (event) => {
|
|
120
|
+
const newLocationFilter = event.detail;
|
|
121
|
+
const numberOfSequencesOverTimeComponent = document.querySelectorAll('gs-number-sequences-over-time');
|
|
122
|
+
numberOfSequencesOverTimeComponent.forEach((element) => {
|
|
123
|
+
const oldFilters = JSON.parse(element.getAttribute('lapisFilters'));
|
|
124
|
+
const newFilters = oldFilters.map((filter) => {
|
|
125
|
+
return {
|
|
126
|
+
...filter,
|
|
127
|
+
lapisFilter: {
|
|
128
|
+
...filter.lapisFilter,
|
|
129
|
+
...newLocationFilter,
|
|
130
|
+
},
|
|
131
|
+
};
|
|
132
|
+
});
|
|
133
|
+
element.setAttribute('lapisFilters', JSON.stringify(newFilters));
|
|
134
|
+
});
|
|
135
|
+
});
|
|
136
|
+
});
|
|
137
|
+
</script>
|
|
138
|
+
```
|
|
139
|
+
|
|
140
|
+
Now you can see, after running vite that the `gs-number-sequences-over-time` component updates when you select a new location in the `gs-location-filter` component.
|
|
@@ -0,0 +1,166 @@
|
|
|
1
|
+
import { Meta } from '@storybook/blocks';
|
|
2
|
+
|
|
3
|
+
<Meta title='Tutorials/Use the components with React' />
|
|
4
|
+
|
|
5
|
+
# Use the components with React
|
|
6
|
+
|
|
7
|
+
In this tutorial, we will show you how to use dashboard components with React.
|
|
8
|
+
We will create a simple dashboard that shows the prevalence of a specific variant over time and allows you to filter the data by location.
|
|
9
|
+
You can find a similar working example in our [examples directory](https://github.com/GenSpectrum/dashboard-components/tree/4ae6a7a9aab3c4c583704f49845c042bcbb6d311/examples/React).
|
|
10
|
+
The data for these components must be provided by a LAPIS instance.
|
|
11
|
+
For this tutorial, we’ll use one of our own [LAPIS](https://lapis.cov-spectrum.org/open/v2/docs/) instances, but you’re free to use any LAPIS instance that supplies the required data.
|
|
12
|
+
|
|
13
|
+
## Prerequisites and setup
|
|
14
|
+
|
|
15
|
+
We assume that you already have a working React environment. We have tested this with React 18.2.0
|
|
16
|
+
|
|
17
|
+
First, install the components by running the following command in your terminal:
|
|
18
|
+
|
|
19
|
+
```bash
|
|
20
|
+
npm install @genspectrum/dashboard-components
|
|
21
|
+
```
|
|
22
|
+
|
|
23
|
+
Then, import the components in your React entry point script (the tsx file that is included in your `index.html` file):
|
|
24
|
+
|
|
25
|
+
```javascript
|
|
26
|
+
import '@genspectrum/dashboard-components/components';
|
|
27
|
+
```
|
|
28
|
+
|
|
29
|
+
## Add the dashboard components to your React file
|
|
30
|
+
|
|
31
|
+
You can now use the components in your own React components.
|
|
32
|
+
Here we create a new component called `Dashboard` that will contain all the logic.
|
|
33
|
+
|
|
34
|
+
```javascript
|
|
35
|
+
function Dashboard() {
|
|
36
|
+
return (
|
|
37
|
+
<gs-app lapis='https://lapis.cov-spectrum.org/open/v2/'>
|
|
38
|
+
<h2>Filter By Location</h2>
|
|
39
|
+
<gs-location-filter
|
|
40
|
+
fields='["region", "country", "division", "location"]'
|
|
41
|
+
width='100%'
|
|
42
|
+
placeholderText='Enter a location'
|
|
43
|
+
></gs-location-filter>
|
|
44
|
+
<h2>Prevalence over time</h2>
|
|
45
|
+
<gs-prevalence-over-time
|
|
46
|
+
numeratorFilters='[{"displayName":"EG","lapisFilter":{"country":"USA","pangoLineage":"EG*","dateFrom":"2023-01-01"}},{"displayName":"JN.1","lapisFilter":{"country":"USA","pangoLineage":"JN.1*","dateFrom":"2023-01-01"}}]'
|
|
47
|
+
denominatorFilter='{"country":"USA","dateFrom":"2023-01-01"}'
|
|
48
|
+
lapisDateField='date'
|
|
49
|
+
granularity='day'
|
|
50
|
+
smoothingWindow='7'
|
|
51
|
+
views='["line", "table"]'
|
|
52
|
+
></gs-prevalence-over-time>
|
|
53
|
+
</gs-app>
|
|
54
|
+
);
|
|
55
|
+
}
|
|
56
|
+
```
|
|
57
|
+
|
|
58
|
+
As you can see, we are using three components:
|
|
59
|
+
|
|
60
|
+
- `gs-app`: This is the main component that wraps all the other components, providing the context for them. Each of our components must be wrapped in this component.
|
|
61
|
+
It provides the `lapis` prop, which is the URL of the LAPIS server, the server that provides the data for the components. In this example, we are using the LAPIS server for open SARS-CoV-2 data.
|
|
62
|
+
- `gs-location-filter`: This is an example of our input components, which are used to create LAPIS filters for the visualization components. In this case, it is used to filter the data by location.
|
|
63
|
+
- `gs-prevalence-over-time`: This is an example of our visualization components, which are used to visualize the data from the LAPIS server. In this case, it shows the prevalence of a specific variant over time.
|
|
64
|
+
|
|
65
|
+
For now, we have provided fixed values for the `numerator`, and `denominator`.
|
|
66
|
+
If you only want to use the visualization components, you are finished here.
|
|
67
|
+
If you want to use the input components, you will need to add some additional code to make them work.
|
|
68
|
+
|
|
69
|
+
## Add interactivity between the components
|
|
70
|
+
|
|
71
|
+
Each of our `input` components emits an event when the user selects a new value.
|
|
72
|
+
You can listen to this event and update the `visualization` components accordingly.
|
|
73
|
+
In this example, we will use the `gs-location-filter` component to filter the data by location.
|
|
74
|
+
|
|
75
|
+
Before we do that, we need to create a state to store the current location. We will use the `useState` hook for this:
|
|
76
|
+
|
|
77
|
+
```javascript
|
|
78
|
+
const [location, setLocation] = useState<Record<string, string | undefined>>({
|
|
79
|
+
region: undefined,
|
|
80
|
+
country: undefined,
|
|
81
|
+
division: undefined,
|
|
82
|
+
location: undefined,
|
|
83
|
+
});
|
|
84
|
+
```
|
|
85
|
+
|
|
86
|
+
We then add an event listener to the `gs-location-filter` component to update the `location` state when the user selects a new location:
|
|
87
|
+
|
|
88
|
+
```javascript
|
|
89
|
+
import {gsEventNames, LocationChangedEvent} from '@genspectrum/dashboard-components/util';
|
|
90
|
+
|
|
91
|
+
// in the Dashboard component
|
|
92
|
+
const locationFilterRef = useRef<HTMLElement>();
|
|
93
|
+
// ...
|
|
94
|
+
useEffect(() => {
|
|
95
|
+
const locationFilter = locationFilterRef.current;
|
|
96
|
+
if (!locationFilter) {
|
|
97
|
+
return;
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
const handleLocationChange = (event: LocationChangedEvent) => setLocation(event.detail);
|
|
101
|
+
|
|
102
|
+
locationFilter.addEventListener(gsEventNames.locationChanged, handleLocationChange);
|
|
103
|
+
|
|
104
|
+
return () => {
|
|
105
|
+
locationFilter.removeEventListener(gsEventNames.locationChanged, handleLocationChange);
|
|
106
|
+
};
|
|
107
|
+
}, []);
|
|
108
|
+
// ...
|
|
109
|
+
<gs-location-filter
|
|
110
|
+
fields='["region", "country", "division", "location"]'
|
|
111
|
+
placeholderText='Enter a location'
|
|
112
|
+
ref={locationFilterRef}
|
|
113
|
+
lapisFilter={JSON.stringify(location)}
|
|
114
|
+
value={JSON.stringify(location)}
|
|
115
|
+
></gs-location-filter>
|
|
116
|
+
```
|
|
117
|
+
|
|
118
|
+
As you can see, we provide the `location` state as the `value` prop to the `gs-location-filter` component.
|
|
119
|
+
This allows the component to display the current location and update it when the user selects a new location.
|
|
120
|
+
We also provide the `lapisFilter` prop, which is used in the `gs-location-filter` component itself to provide counts for the selected location on the dropdown.
|
|
121
|
+
|
|
122
|
+
In the end, we create the numerator and denominator filters for the `gs-prevalence-over-time` component from the `dateRange` state.
|
|
123
|
+
|
|
124
|
+
```javascript
|
|
125
|
+
const denominator = {
|
|
126
|
+
...location,
|
|
127
|
+
};
|
|
128
|
+
|
|
129
|
+
const numerator = {
|
|
130
|
+
displayName: 'My variant',
|
|
131
|
+
lapisFilter: {
|
|
132
|
+
...denominator,
|
|
133
|
+
pangoLineage: 'B.1.1.7*',
|
|
134
|
+
},
|
|
135
|
+
};
|
|
136
|
+
```
|
|
137
|
+
|
|
138
|
+
You can also create a more complex filters, but this will be enough for this example.
|
|
139
|
+
You also might want users to be able to select the variant they want to see. Here it is fixed to `B.1.1.7`.
|
|
140
|
+
Refer to our documentation of our other input components.
|
|
141
|
+
|
|
142
|
+
Finally, we use the new variables (`numerator`, `denominator`) in the components:
|
|
143
|
+
|
|
144
|
+
```javascript
|
|
145
|
+
return (
|
|
146
|
+
<gs-app lapis='https://lapis.cov-spectrum.org/open/v2/'>
|
|
147
|
+
<h2>Filter By Location</h2>
|
|
148
|
+
<gs-location-filter
|
|
149
|
+
fields='["region", "country", "division", "location"]'
|
|
150
|
+
placeholderText='Enter a location'
|
|
151
|
+
ref={locationFilterRef}
|
|
152
|
+
lapisFilter={JSON.stringify(location)}
|
|
153
|
+
value={JSON.stringify(location)}
|
|
154
|
+
></gs-location-filter>
|
|
155
|
+
<h2>Prevalence over time</h2>
|
|
156
|
+
<gs-prevalence-over-time
|
|
157
|
+
numeratorFilters={JSON.stringify([numerator])}
|
|
158
|
+
denominatorFilter={JSON.stringify(denominator)}
|
|
159
|
+
lapisDateField='date'
|
|
160
|
+
granularity='day'
|
|
161
|
+
smoothingWindow='7'
|
|
162
|
+
views='["line", "table"]'
|
|
163
|
+
></gs-prevalence-over-time>
|
|
164
|
+
</gs-app>
|
|
165
|
+
);
|
|
166
|
+
```
|
|
@@ -153,7 +153,7 @@ export class MutationsComponent extends PreactLitAdapterWithGridJsStyles {
|
|
|
153
153
|
|
|
154
154
|
declare global {
|
|
155
155
|
interface HTMLElementTagNameMap {
|
|
156
|
-
'gs-mutations
|
|
156
|
+
'gs-mutations': MutationsComponent;
|
|
157
157
|
}
|
|
158
158
|
}
|
|
159
159
|
|
|
@@ -161,7 +161,7 @@ declare global {
|
|
|
161
161
|
// eslint-disable-next-line @typescript-eslint/no-namespace
|
|
162
162
|
namespace JSX {
|
|
163
163
|
interface IntrinsicElements {
|
|
164
|
-
'gs-mutations
|
|
164
|
+
'gs-mutations': DetailedHTMLProps<HTMLAttributes<HTMLElement>, HTMLElement>;
|
|
165
165
|
}
|
|
166
166
|
}
|
|
167
167
|
}
|