@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/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-component': MutationsComponent;
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-component': DetailedHTMLProps<HTMLAttributes<HTMLElement>, HTMLElement>;
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-prevalence-over-time': PrevalenceOverTimeComponent;
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-prevalence-over-time': DetailedHTMLProps<HTMLAttributes<HTMLElement>, HTMLElement>;
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-relative-growth-advantage': RelativeGrowthAdvantageComponent;
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-relative-growth-advantage': DetailedHTMLProps<HTMLAttributes<HTMLElement>, HTMLElement>;
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-location-filter': LocationFilterComponent;
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-location-filter': DetailedHTMLProps<HTMLAttributes<HTMLElement>, HTMLElement>;
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-statistics': StatisticsComponent;
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-statistics': DetailedHTMLProps<HTMLAttributes<HTMLElement>, HTMLElement>;
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-lineage-filter': LineageFilterComponent;
1175
+ 'gs-mutation-filter': MutationFilterComponent;
1160
1176
  }
1161
1177
  interface HTMLElementEventMap {
1162
- [gsEventNames.lineageFilterChanged]: LineageFilterChangedEvent;
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-lineage-filter': DetailedHTMLProps<HTMLAttributes<HTMLElement>, HTMLElement>;
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-mutation-filter': MutationFilterComponent;
1194
+ 'gs-lineage-filter': LineageFilterComponent;
1179
1195
  }
1180
1196
  interface HTMLElementEventMap {
1181
- [gsEventNames.mutationFilterChanged]: CustomEvent<MutationsFilter>;
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-mutation-filter': DetailedHTMLProps<HTMLAttributes<HTMLElement>, HTMLElement>;
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
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@genspectrum/dashboard-components",
3
- "version": "0.19.8",
3
+ "version": "0.19.9",
4
4
  "description": "GenSpectrum web components for building dashboards",
5
5
  "type": "module",
6
6
  "license": "AGPL-3.0-only",
@@ -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, which can be used to update the LAPIS filters.
11
- The `detail` of the event is designed such that it can be directly passed to the LAPIS API.
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-component': MutationsComponent;
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-component': DetailedHTMLProps<HTMLAttributes<HTMLElement>, HTMLElement>;
164
+ 'gs-mutations': DetailedHTMLProps<HTMLAttributes<HTMLElement>, HTMLElement>;
165
165
  }
166
166
  }
167
167
  }