@cdc/chart 4.23.10-alpha → 4.23.11
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/cdcchart.js +30598 -28669
- package/examples/feature/bar/example-bar-chart.json +1 -46
- package/examples/feature/dev-4261.json +399 -0
- package/examples/feature/forest-plot/{broken.json → linear.json} +55 -50
- package/examples/{private/forest-plot.json → feature/forest-plot/logarithmic.json} +305 -355
- package/examples/feature/line/line-points.json +340 -0
- package/examples/feature/regions/index.json +462 -0
- package/examples/gallery/bar-chart-vertical/combo-line-chart.json +181 -48
- package/examples/sparkline-multilple.json +846 -0
- package/index.html +11 -8
- package/package.json +3 -3
- package/src/CdcChart.tsx +71 -60
- package/src/_stories/Chart.tooltip.stories.tsx +305 -0
- package/src/_stories/ChartBrush.stories.tsx +19 -0
- package/src/_stories/ChartSuppress.stories.tsx +19 -0
- package/{examples/private/missing-color.json → src/_stories/_mock/brush_mock.json} +392 -332
- package/src/_stories/_mock/suppress_mock.json +911 -0
- package/src/components/AreaChart.Stacked.jsx +4 -5
- package/src/components/AreaChart.jsx +6 -35
- package/src/components/{BarChart.Horizontal.jsx → BarChart.Horizontal.tsx} +106 -29
- package/src/components/{BarChart.StackedHorizontal.jsx → BarChart.StackedHorizontal.tsx} +22 -17
- package/src/components/{BarChart.StackedVertical.jsx → BarChart.StackedVertical.tsx} +22 -26
- package/src/components/{BarChart.Vertical.jsx → BarChart.Vertical.tsx} +175 -31
- package/src/components/BarChart.jsx +1 -1
- package/src/components/DeviationBar.jsx +4 -3
- package/src/components/EditorPanel.jsx +176 -50
- package/src/components/ForestPlot/ForestPlotProps.ts +11 -0
- package/src/components/ForestPlot/index.scss +1 -0
- package/src/components/{ForestPlot.jsx → ForestPlot/index.tsx} +51 -31
- package/src/components/ForestPlotSettings.jsx +162 -112
- package/src/components/Legend.jsx +35 -2
- package/src/components/{LineChart.Circle.tsx → LineChart/LineChart.Circle.tsx} +26 -23
- package/src/components/LineChart/LineChartProps.ts +17 -0
- package/src/components/LineChart/index.scss +1 -0
- package/src/components/{LineChart.tsx → LineChart/index.tsx} +60 -24
- package/src/components/LinearChart.jsx +120 -60
- package/src/components/PairedBarChart.jsx +2 -2
- package/src/components/Series.jsx +22 -3
- package/src/components/ZoomBrush.tsx +168 -0
- package/src/data/initial-state.js +27 -12
- package/src/hooks/useBarChart.js +70 -6
- package/src/hooks/useColorScale.ts +50 -0
- package/src/hooks/useEditorPermissions.js +22 -4
- package/src/hooks/{useMinMax.js → useMinMax.ts} +75 -23
- package/src/hooks/{useRightAxis.js → useRightAxis.ts} +10 -2
- package/src/hooks/{useScales.js → useScales.ts} +64 -17
- package/src/hooks/useTooltip.jsx +68 -41
- package/src/scss/main.scss +3 -35
- package/src/types/ChartConfig.ts +43 -0
- package/src/types/ChartContext.ts +38 -0
- package/src/types/ChartProps.ts +7 -0
- package/src/types/ForestPlot.ts +60 -0
- package/examples/private/full.json +0 -45324
- /package/{examples/private/TESTING.json → src/components/ForestPlot/Readme.md} +0 -0
|
@@ -2,6 +2,8 @@ import React, { useContext, memo, useState, useEffect } from 'react'
|
|
|
2
2
|
import ConfigContext from '../ConfigContext'
|
|
3
3
|
import { useDebounce } from 'use-debounce'
|
|
4
4
|
import WarningImage from '../images/warning.svg'
|
|
5
|
+
import Tooltip from '@cdc/core/components/ui/Tooltip'
|
|
6
|
+
import Icon from '@cdc/core/components/ui/Icon'
|
|
5
7
|
|
|
6
8
|
import { AccordionItem, AccordionItemHeading, AccordionItemPanel, AccordionItemButton } from 'react-accessible-accordion'
|
|
7
9
|
|
|
@@ -180,7 +182,7 @@ const ForestPlotSettings = () => {
|
|
|
180
182
|
}
|
|
181
183
|
|
|
182
184
|
if (section === 'forestPlot' && subsection) {
|
|
183
|
-
|
|
185
|
+
let newConfig = {
|
|
184
186
|
...config,
|
|
185
187
|
[section]: {
|
|
186
188
|
...config[section],
|
|
@@ -189,7 +191,9 @@ const ForestPlotSettings = () => {
|
|
|
189
191
|
[fieldName]: newValue
|
|
190
192
|
}
|
|
191
193
|
}
|
|
192
|
-
}
|
|
194
|
+
}
|
|
195
|
+
|
|
196
|
+
updateConfig(newConfig)
|
|
193
197
|
return
|
|
194
198
|
}
|
|
195
199
|
|
|
@@ -244,116 +248,99 @@ const ForestPlotSettings = () => {
|
|
|
244
248
|
</AccordionItemButton>
|
|
245
249
|
</AccordionItemHeading>
|
|
246
250
|
<AccordionItemPanel>
|
|
247
|
-
<
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
min={0}
|
|
255
|
-
max={100}
|
|
256
|
-
value={config.forestPlot.width || ''}
|
|
257
|
-
onChange={e => {
|
|
251
|
+
<Select
|
|
252
|
+
value={config.forestPlot.type}
|
|
253
|
+
label='Forest Plot Type'
|
|
254
|
+
initial={'Select'}
|
|
255
|
+
required={true}
|
|
256
|
+
onChange={e => {
|
|
257
|
+
if (e.target.value !== '' && e.target.value !== 'Select') {
|
|
258
258
|
updateConfig({
|
|
259
259
|
...config,
|
|
260
260
|
forestPlot: {
|
|
261
261
|
...config.forestPlot,
|
|
262
|
-
|
|
262
|
+
type: e.target.value
|
|
263
263
|
}
|
|
264
264
|
})
|
|
265
|
-
}
|
|
266
|
-
|
|
267
|
-
|
|
265
|
+
}
|
|
266
|
+
e.target.value = ''
|
|
267
|
+
}}
|
|
268
|
+
options={['Linear', 'Logarithmic']}
|
|
269
|
+
tooltip={
|
|
270
|
+
<Tooltip style={{ textTransform: 'none' }}>
|
|
271
|
+
<Tooltip.Target>
|
|
272
|
+
<Icon display='question' style={{ marginLeft: '0.5rem' }} />
|
|
273
|
+
</Tooltip.Target>
|
|
274
|
+
<Tooltip.Content>
|
|
275
|
+
<p>
|
|
276
|
+
Linear - Typically used for continuous outcomes. Line of no effect is positioned on 0 (zero) <br />
|
|
277
|
+
<br /> Logarithmic - Typically used for binary outcomes such as risk ratios and odds ratios. Line of no effect is positioned on 1.
|
|
278
|
+
</p>
|
|
279
|
+
</Tooltip.Content>
|
|
280
|
+
</Tooltip>
|
|
281
|
+
}
|
|
282
|
+
/>
|
|
268
283
|
|
|
269
|
-
<label
|
|
270
|
-
<span className='edit-label column-heading'>Chart Offset Left (%)</span>
|
|
271
|
-
<input
|
|
272
|
-
type='number'
|
|
273
|
-
min={0}
|
|
274
|
-
max={100}
|
|
275
|
-
value={config.forestPlot.leftWidthOffset || 0}
|
|
276
|
-
onChange={e => {
|
|
277
|
-
updateConfig({
|
|
278
|
-
...config,
|
|
279
|
-
forestPlot: {
|
|
280
|
-
...config.forestPlot,
|
|
281
|
-
leftWidthOffset: e.target.value
|
|
282
|
-
}
|
|
283
|
-
})
|
|
284
|
-
}}
|
|
285
|
-
/>
|
|
286
|
-
</label>
|
|
284
|
+
<TextField type='text' value={config.forestPlot?.title || ''} updateField={updateField} section='forestPlot' fieldName='title' label='Plot Title' />
|
|
287
285
|
|
|
288
|
-
<
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
min={0}
|
|
293
|
-
max={100}
|
|
294
|
-
value={config.forestPlot.leftWidthOffsetMobile || 0}
|
|
295
|
-
onChange={e => {
|
|
296
|
-
updateConfig({
|
|
297
|
-
...config,
|
|
298
|
-
forestPlot: {
|
|
299
|
-
...config.forestPlot,
|
|
300
|
-
leftWidthOffsetMobile: e.target.value
|
|
301
|
-
}
|
|
302
|
-
})
|
|
303
|
-
}}
|
|
304
|
-
/>
|
|
305
|
-
</label>
|
|
286
|
+
<br />
|
|
287
|
+
<hr />
|
|
288
|
+
<br />
|
|
289
|
+
<h4>Column Settings</h4>
|
|
306
290
|
|
|
307
|
-
<
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
value
|
|
314
|
-
onChange={e => {
|
|
291
|
+
<Select
|
|
292
|
+
value={config.forestPlot.estimateField}
|
|
293
|
+
label='Point Estimate Column'
|
|
294
|
+
initial={config.forestPlot.estimateField || 'Select'}
|
|
295
|
+
required={true}
|
|
296
|
+
onChange={e => {
|
|
297
|
+
if (e.target.value !== '' && e.target.value !== 'Select') {
|
|
315
298
|
updateConfig({
|
|
316
299
|
...config,
|
|
317
300
|
forestPlot: {
|
|
318
301
|
...config.forestPlot,
|
|
319
|
-
|
|
302
|
+
estimateField: e.target.value
|
|
320
303
|
}
|
|
321
304
|
})
|
|
322
|
-
}
|
|
323
|
-
|
|
324
|
-
|
|
305
|
+
}
|
|
306
|
+
e.target.value = ''
|
|
307
|
+
}}
|
|
308
|
+
options={getColumns(false)}
|
|
309
|
+
/>
|
|
325
310
|
|
|
326
|
-
<
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
value={config.forestPlot.rightWidthOffsetMobile || 0}
|
|
333
|
-
onChange={e => {
|
|
311
|
+
<Select
|
|
312
|
+
value={config.forestPlot.shape}
|
|
313
|
+
label='Point Estimate Shape'
|
|
314
|
+
initial={config.forestPlot.shape || 'Select'}
|
|
315
|
+
onChange={e => {
|
|
316
|
+
if (e.target.value !== '' && e.target.value !== 'Select') {
|
|
334
317
|
updateConfig({
|
|
335
318
|
...config,
|
|
336
319
|
forestPlot: {
|
|
337
320
|
...config.forestPlot,
|
|
338
|
-
|
|
321
|
+
shape: e.target.value
|
|
339
322
|
}
|
|
340
323
|
})
|
|
341
|
-
}
|
|
342
|
-
|
|
343
|
-
|
|
324
|
+
}
|
|
325
|
+
e.target.value = ''
|
|
326
|
+
}}
|
|
327
|
+
options={['text', 'circle', 'square']}
|
|
328
|
+
/>
|
|
344
329
|
|
|
345
330
|
<Select
|
|
346
|
-
value={config.forestPlot.
|
|
347
|
-
label='
|
|
331
|
+
value={config.forestPlot.radius.scalingColumn}
|
|
332
|
+
label='Scale Radius Column'
|
|
348
333
|
initial={'Select'}
|
|
349
|
-
required={true}
|
|
350
334
|
onChange={e => {
|
|
351
335
|
if (e.target.value !== '' && e.target.value !== 'Select') {
|
|
352
336
|
updateConfig({
|
|
353
337
|
...config,
|
|
354
338
|
forestPlot: {
|
|
355
339
|
...config.forestPlot,
|
|
356
|
-
|
|
340
|
+
radius: {
|
|
341
|
+
...config.forestPlot.radius,
|
|
342
|
+
scalingColumn: e.target.value
|
|
343
|
+
}
|
|
357
344
|
}
|
|
358
345
|
})
|
|
359
346
|
}
|
|
@@ -366,7 +353,7 @@ const ForestPlotSettings = () => {
|
|
|
366
353
|
value={config.forestPlot.lower}
|
|
367
354
|
label='Lower CI Column'
|
|
368
355
|
required={true}
|
|
369
|
-
initial={'Select'}
|
|
356
|
+
initial={config.forestPlot.lower || 'Select'}
|
|
370
357
|
onChange={e => {
|
|
371
358
|
if (e.target.value !== '' && e.target.value !== 'Select') {
|
|
372
359
|
updateConfig({
|
|
@@ -381,10 +368,11 @@ const ForestPlotSettings = () => {
|
|
|
381
368
|
}}
|
|
382
369
|
options={getColumns(false)}
|
|
383
370
|
/>
|
|
371
|
+
|
|
384
372
|
<Select
|
|
385
373
|
value={config.forestPlot.upper}
|
|
386
374
|
label='Upper CI Column'
|
|
387
|
-
initial={'Select'}
|
|
375
|
+
initial={config.forestPlot.upper || 'Select'}
|
|
388
376
|
required={true}
|
|
389
377
|
onChange={e => {
|
|
390
378
|
if (e.target.value !== '' && e.target.value !== 'Select') {
|
|
@@ -402,44 +390,112 @@ const ForestPlotSettings = () => {
|
|
|
402
390
|
/>
|
|
403
391
|
|
|
404
392
|
<Select
|
|
405
|
-
value={config.forestPlot.
|
|
406
|
-
label='
|
|
407
|
-
initial={'Select'}
|
|
393
|
+
value={config.forestPlot.pooledResult.column}
|
|
394
|
+
label='Pooled Result Row'
|
|
395
|
+
initial={config.forestPlot.pooledResult.column || 'Select'}
|
|
396
|
+
required={false}
|
|
408
397
|
onChange={e => {
|
|
409
398
|
if (e.target.value !== '' && e.target.value !== 'Select') {
|
|
410
399
|
updateConfig({
|
|
411
400
|
...config,
|
|
412
401
|
forestPlot: {
|
|
413
402
|
...config.forestPlot,
|
|
414
|
-
|
|
403
|
+
pooledResult: {
|
|
404
|
+
...config.forestPlot.pooledResult,
|
|
405
|
+
column: e.target.value
|
|
406
|
+
}
|
|
415
407
|
}
|
|
416
408
|
})
|
|
417
409
|
}
|
|
418
410
|
e.target.value = ''
|
|
419
411
|
}}
|
|
420
|
-
options={['
|
|
412
|
+
options={['None', ...config.data.map(d => d[config.xAxis.dataKey])]}
|
|
421
413
|
/>
|
|
422
|
-
|
|
423
|
-
|
|
424
|
-
|
|
425
|
-
|
|
426
|
-
|
|
427
|
-
|
|
414
|
+
|
|
415
|
+
<CheckBox value={config.forestPlot?.hideDateCategoryCol || false} section='forestPlot' fieldName='hideDateCategoryCol' label='Hide Date Category Column' updateField={updateField} />
|
|
416
|
+
<CheckBox value={config.forestPlot?.lineOfNoEffect?.show || false} section='forestPlot' subsection='lineOfNoEffect' fieldName='show' label='Show Line of No Effect' updateField={updateField} />
|
|
417
|
+
|
|
418
|
+
<br />
|
|
419
|
+
<hr />
|
|
420
|
+
<br />
|
|
421
|
+
<h4>Width Settings</h4>
|
|
422
|
+
|
|
423
|
+
<label>
|
|
424
|
+
<span className='edit-label column-heading'>Chart Offset Left (%)</span>
|
|
425
|
+
<input
|
|
426
|
+
type='number'
|
|
427
|
+
min={0}
|
|
428
|
+
max={100}
|
|
429
|
+
value={config.forestPlot.leftWidthOffset || 0}
|
|
430
|
+
onChange={e => {
|
|
428
431
|
updateConfig({
|
|
429
432
|
...config,
|
|
430
433
|
forestPlot: {
|
|
431
434
|
...config.forestPlot,
|
|
432
|
-
|
|
433
|
-
...config.forestPlot.radius,
|
|
434
|
-
scalingColumn: e.target.value
|
|
435
|
-
}
|
|
435
|
+
leftWidthOffset: e.target.value
|
|
436
436
|
}
|
|
437
437
|
})
|
|
438
|
-
}
|
|
439
|
-
|
|
440
|
-
|
|
441
|
-
|
|
442
|
-
|
|
438
|
+
}}
|
|
439
|
+
/>
|
|
440
|
+
</label>
|
|
441
|
+
|
|
442
|
+
<label>
|
|
443
|
+
<span className='edit-label column-heading'>Chart Offset Left Mobile(%)</span>
|
|
444
|
+
<input
|
|
445
|
+
type='number'
|
|
446
|
+
min={0}
|
|
447
|
+
max={100}
|
|
448
|
+
value={config.forestPlot.leftWidthOffsetMobile || 0}
|
|
449
|
+
onChange={e => {
|
|
450
|
+
updateConfig({
|
|
451
|
+
...config,
|
|
452
|
+
forestPlot: {
|
|
453
|
+
...config.forestPlot,
|
|
454
|
+
leftWidthOffsetMobile: e.target.value
|
|
455
|
+
}
|
|
456
|
+
})
|
|
457
|
+
}}
|
|
458
|
+
/>
|
|
459
|
+
</label>
|
|
460
|
+
|
|
461
|
+
<label>
|
|
462
|
+
<span className='edit-label column-heading'>Chart Offset Right (%)</span>
|
|
463
|
+
<input
|
|
464
|
+
type='number'
|
|
465
|
+
min={0}
|
|
466
|
+
max={100}
|
|
467
|
+
value={config.forestPlot.rightWidthOffset || 0}
|
|
468
|
+
onChange={e => {
|
|
469
|
+
updateConfig({
|
|
470
|
+
...config,
|
|
471
|
+
forestPlot: {
|
|
472
|
+
...config.forestPlot,
|
|
473
|
+
rightWidthOffset: e.target.value
|
|
474
|
+
}
|
|
475
|
+
})
|
|
476
|
+
}}
|
|
477
|
+
/>
|
|
478
|
+
</label>
|
|
479
|
+
|
|
480
|
+
<label>
|
|
481
|
+
<span className='edit-label column-heading'>Chart Offset Right Mobile(%)</span>
|
|
482
|
+
<input
|
|
483
|
+
type='number'
|
|
484
|
+
min={0}
|
|
485
|
+
max={100}
|
|
486
|
+
value={config.forestPlot.rightWidthOffsetMobile || 0}
|
|
487
|
+
onChange={e => {
|
|
488
|
+
updateConfig({
|
|
489
|
+
...config,
|
|
490
|
+
forestPlot: {
|
|
491
|
+
...config.forestPlot,
|
|
492
|
+
rightWidthOffsetMobile: e.target.value
|
|
493
|
+
}
|
|
494
|
+
})
|
|
495
|
+
}}
|
|
496
|
+
/>
|
|
497
|
+
</label>
|
|
498
|
+
|
|
443
499
|
<label>
|
|
444
500
|
<span className='edit-label column-heading'>Radius Minimum Size</span>
|
|
445
501
|
<input
|
|
@@ -490,15 +546,9 @@ const ForestPlotSettings = () => {
|
|
|
490
546
|
<br />
|
|
491
547
|
<hr />
|
|
492
548
|
<br />
|
|
493
|
-
|
|
494
|
-
|
|
495
|
-
|
|
496
|
-
<TextField type='number' value={config.forestPlot?.regression?.estimateField || ''} updateField={updateField} section='forestPlot' subsection='regression' fieldName='estimateField' label='Line of No Effect' />
|
|
497
|
-
<TextField type='text' value={config.forestPlot?.regression?.baseLineColor || 'black'} updateField={updateField} section='forestPlot' subsection='regression' fieldName='baseLineColor' label='Base Color' />
|
|
498
|
-
<CheckBox value={config.forestPlot?.regression?.showBaseLine || false} section='forestPlot' subsection='regression' fieldName='showBaseLine' label='Show base line' updateField={updateField} />
|
|
499
|
-
<CheckBox value={config.forestPlot?.regression?.showDiamond || false} section='forestPlot' subsection='regression' fieldName='showDiamond' label='Show Diamond' updateField={updateField} />
|
|
500
|
-
<CheckBox value={config.forestPlot?.hideDateCategoryCol || false} section='forestPlot' fieldName='hideDateCategoryCol' label='Hide Date Category Column' updateField={updateField} />
|
|
501
|
-
<TextField type='text' value={config.forestPlot?.regression?.description || ''} updateField={updateField} section='forestPlot' subsection='regression' fieldName='description' label='Description' />
|
|
549
|
+
<h4>Labels Settings</h4>
|
|
550
|
+
<TextField type='text' value={config.forestPlot?.leftLabel || ''} updateField={updateField} section='forestPlot' fieldName='leftLabel' label='Left Label' />
|
|
551
|
+
<TextField type='text' value={config.forestPlot?.rightLabel || ''} updateField={updateField} section='forestPlot' fieldName='rightLabel' label='Right Label' />
|
|
502
552
|
</AccordionItemPanel>
|
|
503
553
|
</AccordionItem>
|
|
504
554
|
)
|
|
@@ -8,6 +8,8 @@ import useLegendClasses from './../hooks/useLegendClasses'
|
|
|
8
8
|
import { useHighlightedBars } from '../hooks/useHighlightedBars'
|
|
9
9
|
import { Line } from '@visx/shape'
|
|
10
10
|
import { sequentialPalettes } from '@cdc/core/data/colorPalettes'
|
|
11
|
+
import { scaleOrdinal } from '@visx/scale'
|
|
12
|
+
import { FaStar } from 'react-icons/fa'
|
|
11
13
|
|
|
12
14
|
// * FILE REVIEW *
|
|
13
15
|
// TODO: fix eslint-disable jsxa11y issues
|
|
@@ -38,6 +40,11 @@ const Legend = () => {
|
|
|
38
40
|
const { visualizationType, visualizationSubType, series, runtime, orientation } = config
|
|
39
41
|
// create fn to reverse labels while legend is Bottom. Legend-right , legend-left works by default.
|
|
40
42
|
const reverseLabels = labels => (config.legend.reverseLabelOrder && config.legend.position === 'bottom' ? labels.reverse() : labels)
|
|
43
|
+
const displayScale = scaleOrdinal({
|
|
44
|
+
domain: config.suppressedData?.map(d => d.label),
|
|
45
|
+
range: ['none'],
|
|
46
|
+
unknown: 'block'
|
|
47
|
+
})
|
|
41
48
|
|
|
42
49
|
const createLegendLabels = defaultLabels => {
|
|
43
50
|
const colorCode = config.legend?.colorCode
|
|
@@ -155,6 +162,29 @@ const Legend = () => {
|
|
|
155
162
|
return reverseLabels(uniqueLabels)
|
|
156
163
|
}
|
|
157
164
|
|
|
165
|
+
if ((config.visualizationType === 'Bar' || config.visualizationType === 'Combo') && config.visualizationSubType === 'regular' && config.suppressedData) {
|
|
166
|
+
const lastIndex = defaultLabels.length - 1
|
|
167
|
+
let newLabels = []
|
|
168
|
+
|
|
169
|
+
config.suppressedData?.forEach(({ label, icon, value }, index) => {
|
|
170
|
+
const dataExists = data.some(d => {
|
|
171
|
+
return runtime.seriesKeys.some(column => d[column] === value)
|
|
172
|
+
})
|
|
173
|
+
|
|
174
|
+
if (label && icon) {
|
|
175
|
+
const newLabel = {
|
|
176
|
+
datum: label,
|
|
177
|
+
index: lastIndex + index,
|
|
178
|
+
text: label,
|
|
179
|
+
icon: <FaStar color='#000' size={15} />
|
|
180
|
+
}
|
|
181
|
+
newLabels.push(newLabel)
|
|
182
|
+
}
|
|
183
|
+
})
|
|
184
|
+
|
|
185
|
+
return [...defaultLabels, ...newLabels]
|
|
186
|
+
}
|
|
187
|
+
|
|
158
188
|
return reverseLabels(defaultLabels)
|
|
159
189
|
}
|
|
160
190
|
|
|
@@ -162,7 +192,7 @@ const Legend = () => {
|
|
|
162
192
|
|
|
163
193
|
const legendClasses = {
|
|
164
194
|
marginBottom: isBottomOrSmallViewport ? '15px' : '0px',
|
|
165
|
-
marginTop: isBottomOrSmallViewport && orientation === 'horizontal' ? `${config.yAxis.label && config.isResponsiveTicks ? config.dynamicMarginTop : config.runtime.xAxis.size}px` : `${config.dynamicMarginTop + 15}px`
|
|
195
|
+
marginTop: isBottomOrSmallViewport && orientation === 'horizontal' ? `${config.yAxis.label && config.isResponsiveTicks ? config.dynamicMarginTop : config.runtime.xAxis.size}px` : `${isBottomOrSmallViewport ? config.dynamicMarginTop + 15 : 0}px`
|
|
166
196
|
}
|
|
167
197
|
|
|
168
198
|
const { HighLightedBarUtils } = useHighlightedBars(config)
|
|
@@ -220,7 +250,10 @@ const Legend = () => {
|
|
|
220
250
|
<Line from={{ x: 10, y: 10 }} to={{ x: 40, y: 10 }} stroke={label.value} strokeWidth={2} strokeDasharray={handleLineType(config.series[i]?.type ? config.series[i]?.type : '')} />
|
|
221
251
|
</svg>
|
|
222
252
|
) : (
|
|
223
|
-
<
|
|
253
|
+
<div style={{ display: 'flex', flexDirection: 'column' }}>
|
|
254
|
+
<LegendCircle margin='0' fill={label.value} display={displayScale(label.datum)} />
|
|
255
|
+
<div style={{ marginTop: '2px', marginRight: '6px' }}>{label.icon}</div>
|
|
256
|
+
</div>
|
|
224
257
|
)}
|
|
225
258
|
|
|
226
259
|
<LegendLabel align='left' margin='0 0 0 4px'>
|
|
@@ -1,13 +1,11 @@
|
|
|
1
1
|
import React from 'react'
|
|
2
|
+
import chroma from 'chroma-js'
|
|
3
|
+
import { type ChartConfig } from '../../types/ChartConfig'
|
|
2
4
|
|
|
3
5
|
// todo: change this config obj to ChartConfig once its created
|
|
4
6
|
type LineChartCircleProps = {
|
|
5
|
-
config:
|
|
6
|
-
|
|
7
|
-
data: Object[]
|
|
8
|
-
lineDatapointStyle: string
|
|
9
|
-
runtime: Object
|
|
10
|
-
}
|
|
7
|
+
config: ChartConfig
|
|
8
|
+
data: object[]
|
|
11
9
|
d?: Object
|
|
12
10
|
displayArea: boolean
|
|
13
11
|
seriesKey: string
|
|
@@ -25,29 +23,27 @@ type LineChartCircleProps = {
|
|
|
25
23
|
}
|
|
26
24
|
|
|
27
25
|
const LineChartCircle = (props: LineChartCircleProps) => {
|
|
28
|
-
const { config, d, displayArea, seriesKey, tooltipData, xScale, yScale, colorScale, parseDate, yScaleRight } = props
|
|
26
|
+
const { config, d, displayArea, seriesKey, tooltipData, xScale, yScale, colorScale, parseDate, yScaleRight, data } = props
|
|
29
27
|
const { lineDatapointStyle } = config
|
|
30
28
|
const filtered = config?.series.filter(s => s.dataKey === seriesKey)?.[0]
|
|
29
|
+
// If we're not showing the circle, simply return
|
|
30
|
+
if (lineDatapointStyle === 'hidden') return <></>
|
|
31
31
|
|
|
32
|
-
|
|
32
|
+
const getIndex = seriesKey => config.runtime.seriesLabelsAll.indexOf(seriesKey)
|
|
33
33
|
|
|
34
|
-
const getColor = (displayArea, colorScale, config
|
|
35
|
-
const customColors = config.customColors || []
|
|
34
|
+
const getColor = (displayArea: boolean, colorScale: Function, config: ChartConfig, hoveredKey: string, seriesKey: string) => {
|
|
36
35
|
const seriesLabels = config.runtime.seriesLabels || []
|
|
37
36
|
let color
|
|
38
37
|
|
|
39
|
-
const getIndex = seriesKey => config.runtime.seriesLabelsAll.indexOf(seriesKey)
|
|
40
|
-
|
|
41
38
|
if (displayArea) {
|
|
42
|
-
|
|
43
|
-
if (getIndex(hoveredKey) === false) return
|
|
44
|
-
color = colorScale(seriesLabels[hoveredKey] || seriesKey)
|
|
45
|
-
} else if (customColors) {
|
|
46
|
-
color = customColors.length > 0 ? colorScale(getIndex(hoveredKey)) : 'transparent'
|
|
47
|
-
}
|
|
39
|
+
color = colorScale(seriesLabels[hoveredKey] || seriesKey)
|
|
48
40
|
} else {
|
|
49
41
|
color = 'transparent'
|
|
50
42
|
}
|
|
43
|
+
|
|
44
|
+
if (config.lineDatapointColor === 'Lighter than Line' && color !== 'transparent' && color) {
|
|
45
|
+
color = chroma(color).brighten(1)
|
|
46
|
+
}
|
|
51
47
|
return color
|
|
52
48
|
}
|
|
53
49
|
|
|
@@ -59,7 +55,7 @@ const LineChartCircle = (props: LineChartCircleProps) => {
|
|
|
59
55
|
r={4.5}
|
|
60
56
|
opacity={d[seriesKey] ? 1 : 0}
|
|
61
57
|
fillOpacity={1}
|
|
62
|
-
fill={displayArea
|
|
58
|
+
fill={getColor(displayArea, colorScale, config, seriesKey, seriesKey)}
|
|
63
59
|
style={{ filter: 'unset', opacity: 1 }}
|
|
64
60
|
/>
|
|
65
61
|
)
|
|
@@ -67,18 +63,24 @@ const LineChartCircle = (props: LineChartCircleProps) => {
|
|
|
67
63
|
|
|
68
64
|
if (lineDatapointStyle === 'hover') {
|
|
69
65
|
if (!tooltipData) return
|
|
66
|
+
if (!seriesKey) return
|
|
70
67
|
if (!tooltipData.data) return
|
|
71
68
|
let hoveredXValue = tooltipData?.data?.[0]?.[1]
|
|
72
69
|
if (!hoveredXValue) return
|
|
70
|
+
|
|
73
71
|
let hoveredSeriesValue
|
|
74
72
|
let hoveredSeriesIndex
|
|
75
73
|
let hoveredSeriesData = tooltipData.data.filter(d => d[0] === seriesKey)
|
|
76
74
|
let hoveredSeriesKey = hoveredSeriesData?.[0]?.[0]
|
|
77
75
|
let hoveredSeriesAxis = hoveredSeriesData?.[0]?.[2]
|
|
78
|
-
|
|
79
|
-
|
|
76
|
+
if (!hoveredSeriesKey) return
|
|
77
|
+
hoveredSeriesIndex = tooltipData?.data.indexOf(hoveredSeriesKey)
|
|
78
|
+
hoveredSeriesValue = data?.find(d => {
|
|
79
|
+
return d[config?.xAxis.dataKey] === hoveredXValue
|
|
80
|
+
})?.[seriesKey]
|
|
80
81
|
|
|
81
|
-
|
|
82
|
+
// hoveredSeriesValue = extractNumber(hoveredSeriesValue)
|
|
83
|
+
return tooltipData?.data.map((tooltipItem, index) => {
|
|
82
84
|
let seriesIndex = config.runtime.seriesLabelsAll.indexOf(hoveredXValue)
|
|
83
85
|
|
|
84
86
|
if (isNaN(hoveredSeriesValue)) return <></>
|
|
@@ -89,8 +91,9 @@ const LineChartCircle = (props: LineChartCircleProps) => {
|
|
|
89
91
|
r={4.5}
|
|
90
92
|
opacity={1}
|
|
91
93
|
fillOpacity={1}
|
|
92
|
-
fill={getColor(displayArea, colorScale, config,
|
|
94
|
+
fill={getColor(displayArea, colorScale, config, hoveredSeriesKey, seriesKey)}
|
|
93
95
|
style={{ filter: 'unset', opacity: 1 }}
|
|
96
|
+
key={`line-chart-circle--${JSON.stringify(tooltipItem)}--${index}`}
|
|
94
97
|
/>
|
|
95
98
|
)
|
|
96
99
|
})
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
// todo: review tooltipData type
|
|
2
|
+
// todo: review svgRef type
|
|
3
|
+
export type LineChartProps = {
|
|
4
|
+
xScale: Function
|
|
5
|
+
yScale: Function
|
|
6
|
+
getXAxisData: Function
|
|
7
|
+
getYAxisData: Function
|
|
8
|
+
xMax: number
|
|
9
|
+
yMax: number
|
|
10
|
+
handleTooltipMouseOver: Function
|
|
11
|
+
handleTooltipMouseOff: Function
|
|
12
|
+
showTooltip: boolean
|
|
13
|
+
seriesStyle: String
|
|
14
|
+
svgRef: any
|
|
15
|
+
handleTooltipClick: Function
|
|
16
|
+
tooltipData: any
|
|
17
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
// Line Chart Styles...
|