1
1
import React from "react"
2
- import { moveArrayItemToIndex , omit } from "@ourworldindata/utils"
2
+ import {
3
+ differenceOfSets ,
4
+ moveArrayItemToIndex ,
5
+ omit ,
6
+ } from "@ourworldindata/utils"
3
7
import { computed , action , observable } from "mobx"
4
8
import { observer } from "mobx-react"
5
9
import {
6
10
EntitySelectionMode ,
7
11
MissingDataStrategy ,
8
12
EntityName ,
13
+ SeriesName ,
9
14
} from "@ourworldindata/types"
10
15
import { Grapher } from "@ourworldindata/grapher"
11
16
import { ColorBox , SelectField , Section , FieldsRow } from "./Forms.js"
@@ -30,6 +35,11 @@ interface EntityItemProps extends React.HTMLProps<HTMLDivElement> {
30
35
onRemove ?: ( ) => void
31
36
}
32
37
38
+ interface SeriesItemProps extends React . HTMLProps < HTMLDivElement > {
39
+ seriesName : SeriesName
40
+ onRemove ?: ( ) => void
41
+ }
42
+
33
43
@observer
34
44
class EntityItem extends React . Component < EntityItemProps > {
35
45
@observable . ref isChoosingColor : boolean = false
@@ -88,6 +98,32 @@ class EntityItem extends React.Component<EntityItemProps> {
88
98
}
89
99
}
90
100
101
+ @observer
102
+ class SeriesItem extends React . Component < SeriesItemProps > {
103
+ @action . bound onRemove ( ) {
104
+ this . props . onRemove ?.( )
105
+ }
106
+
107
+ render ( ) {
108
+ const { props } = this
109
+ const { seriesName } = props
110
+ const rest = omit ( props , [ "seriesName" , "onRemove" ] )
111
+
112
+ return (
113
+ < div
114
+ className = "list-group-item EditableListItem"
115
+ key = { seriesName }
116
+ { ...rest }
117
+ >
118
+ < div > { seriesName } </ div >
119
+ < div className = "clickable" onClick = { this . onRemove } >
120
+ < FontAwesomeIcon icon = { faTimes } />
121
+ </ div >
122
+ </ div >
123
+ )
124
+ }
125
+ }
126
+
91
127
@observer
92
128
export class KeysSection extends React . Component < {
93
129
editor : AbstractChartEditor
@@ -216,6 +252,58 @@ export class KeysSection extends React.Component<{
216
252
}
217
253
}
218
254
255
+ @observer
256
+ export class FocusSection extends React . Component < {
257
+ editor : AbstractChartEditor
258
+ } > {
259
+ @computed get editor ( ) {
260
+ return this . props . editor
261
+ }
262
+
263
+ @action . bound onFocusSeries ( seriesName : SeriesName ) {
264
+ this . editor . grapher . focusArray . activate ( seriesName )
265
+ }
266
+
267
+ render ( ) {
268
+ const { editor } = this
269
+ const { grapher } = editor
270
+
271
+ const seriesNameSet = new Set ( grapher . chartSeriesNames )
272
+ const focusedSeriesNameSet = grapher . focusArray . activeSeriesNameSet
273
+ const availableSeriesNameSet = differenceOfSets < string > ( [
274
+ seriesNameSet ,
275
+ focusedSeriesNameSet ,
276
+ ] )
277
+
278
+ const availableSeriesNames : SeriesName [ ] = Array . from (
279
+ availableSeriesNameSet
280
+ )
281
+ const focusedSeriesNames : SeriesName [ ] =
282
+ Array . from ( focusedSeriesNameSet )
283
+
284
+ return (
285
+ < Section name = "Data to highlight" >
286
+ < FieldsRow >
287
+ < SelectField
288
+ onValue = { this . onFocusSeries }
289
+ value = "Select data"
290
+ options = { [ "Select data" ]
291
+ . concat ( availableSeriesNames )
292
+ . map ( ( key ) => ( { value : key } ) ) }
293
+ />
294
+ </ FieldsRow >
295
+ { focusedSeriesNames . map ( ( seriesName ) => (
296
+ < SeriesItem
297
+ key = { seriesName }
298
+ seriesName = { seriesName }
299
+ onRemove = { ( ) => grapher . focusArray . toggle ( seriesName ) }
300
+ />
301
+ ) ) }
302
+ </ Section >
303
+ )
304
+ }
305
+ }
306
+
219
307
@observer
220
308
class MissingDataSection <
221
309
Editor extends AbstractChartEditor ,
@@ -332,6 +420,7 @@ export class EditorDataTab<
332
420
</ div >
333
421
</ Section >
334
422
< KeysSection editor = { editor } />
423
+ < FocusSection editor = { editor } />
335
424
{ features . canSpecifyMissingDataStrategy && (
336
425
< MissingDataSection editor = { this . props . editor } />
337
426
) }
0 commit comments