@cdc/waffle-chart 4.26.1 → 4.26.3
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/LICENSE +201 -0
- package/dist/cdcwafflechart.js +10982 -9773
- package/examples/default.json +10 -0
- package/examples/tp5-gauge-white.json +158 -0
- package/examples/tp5-gauge.json +158 -0
- package/index.html +1 -33
- package/package.json +30 -33
- package/src/CdcWaffleChart.tsx +222 -92
- package/src/_stories/WaffleChart.Editor.stories.tsx +245 -7
- package/src/_stories/WaffleChart.stories.tsx +49 -2
- package/src/components/EditorPanel.jsx +89 -63
- package/src/data/initial-state.js +3 -1
- package/src/scss/main.scss +3 -10
- package/src/scss/waffle-chart.scss +195 -21
- package/src/store/chart.reducer.ts +1 -1
- package/src/test/CdcWaffleChart.test.jsx +2 -2
- package/src/types/Config.ts +5 -1
- package/src/images/callout-flag.svg +0 -7
package/src/CdcWaffleChart.tsx
CHANGED
|
@@ -25,13 +25,14 @@ import { publish } from '@cdc/core/helpers/events'
|
|
|
25
25
|
import chartReducer from './store/chart.reducer'
|
|
26
26
|
import coveUpdateWorker from '@cdc/core/helpers/coveUpdateWorker'
|
|
27
27
|
import useDataVizClasses from '@cdc/core/helpers/useDataVizClasses'
|
|
28
|
+
import { processMarkupVariables } from '@cdc/core/helpers/markupProcessor'
|
|
28
29
|
|
|
29
30
|
import './scss/main.scss'
|
|
30
31
|
import Title from '@cdc/core/components/ui/Title'
|
|
31
|
-
import
|
|
32
|
+
import { VisualizationContainer, VisualizationContent } from '@cdc/core/components/Layout'
|
|
32
33
|
|
|
33
34
|
// images
|
|
34
|
-
import CalloutFlag from '
|
|
35
|
+
import CalloutFlag from '@cdc/core/assets/callout-flag.svg?url'
|
|
35
36
|
|
|
36
37
|
// TP5 Style Constants
|
|
37
38
|
const TP5_NODE_WIDTH = 13
|
|
@@ -72,6 +73,59 @@ const WaffleChart = ({ config, isEditor, link = '', showConfigConfirm, updateCon
|
|
|
72
73
|
roundToPlace
|
|
73
74
|
} = config
|
|
74
75
|
|
|
76
|
+
const processedTextFields = useMemo(() => {
|
|
77
|
+
if (!config.enableMarkupVariables || !config.markupVariables?.length) {
|
|
78
|
+
return {
|
|
79
|
+
title,
|
|
80
|
+
content,
|
|
81
|
+
subtext,
|
|
82
|
+
valueDescription: config.valueDescription
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
const markupOptions = {
|
|
87
|
+
isEditor,
|
|
88
|
+
showNoDataMessage: false,
|
|
89
|
+
allowHideSection: false,
|
|
90
|
+
filters: config.filters || [],
|
|
91
|
+
locale: config.locale,
|
|
92
|
+
dataMetadata: config.dataMetadata
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
return {
|
|
96
|
+
title: title
|
|
97
|
+
? processMarkupVariables(title, config.data || [], config.markupVariables, markupOptions).processedContent
|
|
98
|
+
: title,
|
|
99
|
+
content: content
|
|
100
|
+
? processMarkupVariables(content, config.data || [], config.markupVariables, markupOptions).processedContent
|
|
101
|
+
: content,
|
|
102
|
+
subtext: subtext
|
|
103
|
+
? processMarkupVariables(subtext, config.data || [], config.markupVariables, markupOptions).processedContent
|
|
104
|
+
: subtext,
|
|
105
|
+
valueDescription: config.valueDescription
|
|
106
|
+
? processMarkupVariables(config.valueDescription, config.data || [], config.markupVariables, markupOptions)
|
|
107
|
+
.processedContent
|
|
108
|
+
: config.valueDescription
|
|
109
|
+
}
|
|
110
|
+
}, [
|
|
111
|
+
config.enableMarkupVariables,
|
|
112
|
+
config.markupVariables,
|
|
113
|
+
config.data,
|
|
114
|
+
config.filters,
|
|
115
|
+
config.locale,
|
|
116
|
+
config.dataMetadata,
|
|
117
|
+
config.valueDescription,
|
|
118
|
+
title,
|
|
119
|
+
content,
|
|
120
|
+
subtext,
|
|
121
|
+
isEditor
|
|
122
|
+
])
|
|
123
|
+
|
|
124
|
+
const processedTitle = processedTextFields.title
|
|
125
|
+
const processedContent = processedTextFields.content
|
|
126
|
+
const processedSubtext = processedTextFields.subtext
|
|
127
|
+
const processedValueDescription = processedTextFields.valueDescription
|
|
128
|
+
|
|
75
129
|
const gaugeColor = config.visual.colors[config.theme]
|
|
76
130
|
let dataFontSize = config.fontSize ? { fontSize: config.fontSize + 'px' } : null
|
|
77
131
|
|
|
@@ -351,7 +405,7 @@ const WaffleChart = ({ config, isEditor, link = '', showConfigConfirm, updateCon
|
|
|
351
405
|
return setRatio() + 2
|
|
352
406
|
}, [nodeWidth, nodeSpacer, config.visualizationType])
|
|
353
407
|
|
|
354
|
-
const {
|
|
408
|
+
const { contentClasses } = useDataVizClasses(config)
|
|
355
409
|
|
|
356
410
|
const xScale = scaleLinear({
|
|
357
411
|
domain: [0, waffleDenominator],
|
|
@@ -397,103 +451,182 @@ const WaffleChart = ({ config, isEditor, link = '', showConfigConfirm, updateCon
|
|
|
397
451
|
<Error updateConfig={updateConfig} config={config} />
|
|
398
452
|
)}
|
|
399
453
|
{config.newViz && showConfigConfirm && <Confirm updateConfig={updateConfig} config={config} />}
|
|
400
|
-
|
|
401
|
-
{config.
|
|
402
|
-
<div className=
|
|
403
|
-
|
|
404
|
-
|
|
405
|
-
|
|
406
|
-
|
|
407
|
-
|
|
408
|
-
|
|
409
|
-
|
|
410
|
-
|
|
411
|
-
|
|
412
|
-
|
|
413
|
-
|
|
414
|
-
|
|
415
|
-
|
|
416
|
-
|
|
417
|
-
|
|
418
|
-
|
|
419
|
-
|
|
420
|
-
|
|
421
|
-
|
|
422
|
-
|
|
423
|
-
|
|
424
|
-
|
|
425
|
-
|
|
426
|
-
</div>
|
|
427
|
-
)}
|
|
428
|
-
{config.visualizationType !== 'Gauge' && (
|
|
429
|
-
<div
|
|
430
|
-
className={`cove-waffle-chart${orientation === 'vertical' ? ' cove-waffle-chart--verical' : ''}${
|
|
431
|
-
config.overallFontSize ? ' font-' + config.overallFontSize : ''
|
|
432
|
-
}`}
|
|
433
|
-
>
|
|
434
|
-
<div className='cove-waffle-chart__chart' style={{ width: setRatio() }}>
|
|
435
|
-
<svg width={setSvgSize()} height={setSvgSize()} style={{ display: 'block' }}>
|
|
436
|
-
<Group top={1} left={1}>
|
|
437
|
-
{buildWaffle()}
|
|
438
|
-
</Group>
|
|
439
|
-
</svg>
|
|
440
|
-
</div>
|
|
441
|
-
{(dataPercentage || content) && (
|
|
442
|
-
<div className='cove-waffle-chart__data'>
|
|
443
|
-
{dataPercentage && (
|
|
444
|
-
<div className='cove-waffle-chart__data--primary' style={dataFontSize}>
|
|
445
|
-
{prefix ? prefix : null}
|
|
446
|
-
{dataPercentage}
|
|
447
|
-
{suffix ? suffix : null}
|
|
454
|
+
{(config.visualizationType === 'Gauge' || config.visualizationType === 'TP5 Gauge') && (
|
|
455
|
+
<div className={`cove-gauge-chart${config.overallFontSize ? ' font-' + config.overallFontSize : ''}`}>
|
|
456
|
+
<div className='cove-gauge-chart__chart'>
|
|
457
|
+
{config.visualizationType === 'TP5 Gauge' ? (
|
|
458
|
+
<>
|
|
459
|
+
<div
|
|
460
|
+
className={`cove-gauge-chart__body d-flex flex-row align-items-start flex-grow-1${
|
|
461
|
+
!processedContent ? ' justify-content-center' : ''
|
|
462
|
+
}`}
|
|
463
|
+
>
|
|
464
|
+
<div className='cove-gauge-chart__value-section flex-shrink-0'>
|
|
465
|
+
<div className='cove-waffle-chart__data--primary' style={dataFontSize}>
|
|
466
|
+
{prefix ? prefix : ' '}
|
|
467
|
+
{config.showPercent ? dataPercentage : waffleNumerator}
|
|
468
|
+
{suffix ? suffix + ' ' : ' '} {processedValueDescription}{' '}
|
|
469
|
+
{config.showDenominator && waffleDenominator ? waffleDenominator : ' '}
|
|
470
|
+
</div>
|
|
471
|
+
</div>
|
|
472
|
+
<div className='cove-gauge-chart__content flex-grow-1 d-flex flex-column min-w-0'>
|
|
473
|
+
{processedContent ? (
|
|
474
|
+
<div className='cove-waffle-chart__data--text'>{parse(processedContent)}</div>
|
|
475
|
+
) : (
|
|
476
|
+
<div className='cove-waffle-chart__data--text' aria-hidden='true'>
|
|
477
|
+
|
|
478
|
+
</div>
|
|
479
|
+
)}
|
|
448
480
|
</div>
|
|
481
|
+
</div>
|
|
482
|
+
<svg
|
|
483
|
+
height={config.gauge.height + 2}
|
|
484
|
+
width={'100%'}
|
|
485
|
+
className='mt-2'
|
|
486
|
+
style={{ overflow: 'visible', padding: '1px' }}
|
|
487
|
+
>
|
|
488
|
+
<Group>
|
|
489
|
+
<Bar
|
|
490
|
+
x={0}
|
|
491
|
+
y={0}
|
|
492
|
+
width={config.gauge.width}
|
|
493
|
+
height={config.gauge.height}
|
|
494
|
+
fill='#dff2f6'
|
|
495
|
+
stroke='#007A99'
|
|
496
|
+
strokeWidth={1}
|
|
497
|
+
rx={10}
|
|
498
|
+
ry={10}
|
|
499
|
+
/>
|
|
500
|
+
<Bar
|
|
501
|
+
x={0}
|
|
502
|
+
y={0}
|
|
503
|
+
width={xScale(waffleNumerator)}
|
|
504
|
+
height={config.gauge.height}
|
|
505
|
+
fill='#007A99'
|
|
506
|
+
rx={10}
|
|
507
|
+
ry={10}
|
|
508
|
+
/>
|
|
509
|
+
</Group>
|
|
510
|
+
</svg>
|
|
511
|
+
{processedSubtext && (
|
|
512
|
+
<div className='cove-waffle-chart__subtext subtext fst-italic mt-2'>{parse(processedSubtext)}</div>
|
|
449
513
|
)}
|
|
450
|
-
|
|
451
|
-
|
|
452
|
-
|
|
453
|
-
|
|
514
|
+
</>
|
|
515
|
+
) : (
|
|
516
|
+
<>
|
|
517
|
+
<div className='cove-waffle-chart__data--primary' style={dataFontSize}>
|
|
518
|
+
{prefix ? prefix : ' '}
|
|
519
|
+
{config.showPercent ? dataPercentage : waffleNumerator}
|
|
520
|
+
{suffix ? suffix + ' ' : ' '} {processedValueDescription}{' '}
|
|
521
|
+
{config.showDenominator && waffleDenominator ? waffleDenominator : ' '}
|
|
522
|
+
</div>
|
|
523
|
+
<div className='cove-waffle-chart__data--text'>{parse(processedContent)}</div>
|
|
524
|
+
<svg height={config.gauge.height} width={'100%'}>
|
|
525
|
+
<Group>
|
|
526
|
+
<Bar
|
|
527
|
+
x={0}
|
|
528
|
+
y={0}
|
|
529
|
+
width={config.gauge.width}
|
|
530
|
+
height={config.gauge.height}
|
|
531
|
+
fill='#e0e0e0'
|
|
532
|
+
stroke='#999'
|
|
533
|
+
strokeWidth={1}
|
|
534
|
+
rx={4}
|
|
535
|
+
ry={4}
|
|
536
|
+
/>
|
|
537
|
+
<Bar
|
|
538
|
+
x={0}
|
|
539
|
+
y={0}
|
|
540
|
+
width={xScale(waffleNumerator)}
|
|
541
|
+
height={config.gauge.height}
|
|
542
|
+
fill={gaugeColor}
|
|
543
|
+
rx={4}
|
|
544
|
+
ry={4}
|
|
545
|
+
/>
|
|
546
|
+
</Group>
|
|
547
|
+
</svg>
|
|
548
|
+
<div className={'cove-waffle-chart__subtext subtext'}>{parse(processedSubtext)}</div>
|
|
549
|
+
</>
|
|
454
550
|
)}
|
|
455
551
|
</div>
|
|
456
|
-
|
|
457
|
-
|
|
552
|
+
</div>
|
|
553
|
+
)}
|
|
554
|
+
{config.visualizationType !== 'Gauge' && config.visualizationType !== 'TP5 Gauge' && (
|
|
555
|
+
<div
|
|
556
|
+
className={`cove-waffle-chart${orientation === 'vertical' ? ' cove-waffle-chart--verical' : ''}${
|
|
557
|
+
config.overallFontSize ? ' font-' + config.overallFontSize : ''
|
|
558
|
+
}`}
|
|
559
|
+
>
|
|
560
|
+
<div className='cove-waffle-chart__chart' style={{ width: setRatio() }}>
|
|
561
|
+
<svg width={setSvgSize()} height={setSvgSize()} style={{ display: 'block' }}>
|
|
562
|
+
<Group top={1} left={1}>
|
|
563
|
+
{buildWaffle()}
|
|
564
|
+
</Group>
|
|
565
|
+
</svg>
|
|
566
|
+
</div>
|
|
567
|
+
{(dataPercentage || processedContent) && (
|
|
568
|
+
<div className='cove-waffle-chart__data'>
|
|
569
|
+
{dataPercentage && (
|
|
570
|
+
<div className='cove-waffle-chart__data--primary' style={dataFontSize}>
|
|
571
|
+
{prefix ? prefix : null}
|
|
572
|
+
{dataPercentage}
|
|
573
|
+
{suffix ? suffix : null}
|
|
574
|
+
</div>
|
|
575
|
+
)}
|
|
576
|
+
{processedContent && <div className='cove-waffle-chart__data--text'>{parse(processedContent)}</div>}
|
|
577
|
+
|
|
578
|
+
{processedSubtext && (
|
|
579
|
+
<div className='cove-waffle-chart__subtext subtext fst-italic'>{parse(processedSubtext)}</div>
|
|
580
|
+
)}
|
|
581
|
+
</div>
|
|
582
|
+
)}
|
|
583
|
+
</div>
|
|
584
|
+
)}
|
|
458
585
|
</>
|
|
459
586
|
)
|
|
460
587
|
|
|
461
|
-
// TP5 Style: render with callout wrapper inside cove-
|
|
462
|
-
if (config.visualizationType === 'TP5 Waffle') {
|
|
588
|
+
// TP5 Style: render with callout wrapper inside cove-visualization__body
|
|
589
|
+
if (config.visualizationType === 'TP5 Waffle' || config.visualizationType === 'TP5 Gauge') {
|
|
463
590
|
const calloutClasses = ['cdc-callout', 'd-flex', 'flex-column']
|
|
464
591
|
if (!config.visual?.whiteBackground) {
|
|
465
592
|
calloutClasses.push('dfe-block', 'cdc-callout--data')
|
|
466
593
|
}
|
|
467
594
|
|
|
468
595
|
return (
|
|
469
|
-
<
|
|
596
|
+
<VisualizationContent
|
|
597
|
+
bodyClassName={['no-borders', ...contentClasses].filter(Boolean).join(' ')}
|
|
598
|
+
footer={link && link}
|
|
599
|
+
>
|
|
470
600
|
<div className={calloutClasses.join(' ')}>
|
|
471
601
|
{!config.visual?.whiteBackground && (
|
|
472
602
|
<img src={CalloutFlag} alt='' className='cdc-callout__flag' aria-hidden='true' />
|
|
473
603
|
)}
|
|
474
|
-
{config.showTitle &&
|
|
475
|
-
<h3 className='cdc-callout__heading fw-bold flex-shrink-0'>{parse(
|
|
604
|
+
{config.showTitle && processedTitle && processedTitle.trim() && (
|
|
605
|
+
<h3 className='cdc-callout__heading fw-bold flex-shrink-0'>{parse(processedTitle)}</h3>
|
|
476
606
|
)}
|
|
477
607
|
<div className='w-100 mw-100 overflow-hidden'>{renderChartContent()}</div>
|
|
478
608
|
</div>
|
|
479
|
-
|
|
480
|
-
</div>
|
|
609
|
+
</VisualizationContent>
|
|
481
610
|
)
|
|
482
611
|
}
|
|
483
612
|
|
|
484
613
|
// Original Style: Regular title and content
|
|
485
614
|
return (
|
|
486
|
-
<
|
|
487
|
-
|
|
488
|
-
|
|
489
|
-
|
|
490
|
-
|
|
491
|
-
|
|
492
|
-
|
|
493
|
-
|
|
494
|
-
|
|
495
|
-
|
|
496
|
-
|
|
615
|
+
<VisualizationContent
|
|
616
|
+
bodyClassName={contentClasses.join(' ')}
|
|
617
|
+
header={
|
|
618
|
+
<Title
|
|
619
|
+
showTitle={config.showTitle}
|
|
620
|
+
title={processedTitle}
|
|
621
|
+
titleStyle='legacy'
|
|
622
|
+
config={config}
|
|
623
|
+
classes={['chart-title', `${config.theme}`, 'mb-0']}
|
|
624
|
+
/>
|
|
625
|
+
}
|
|
626
|
+
footer={link && link}
|
|
627
|
+
>
|
|
628
|
+
{renderChartContent()}
|
|
629
|
+
</VisualizationContent>
|
|
497
630
|
)
|
|
498
631
|
}
|
|
499
632
|
|
|
@@ -535,7 +668,9 @@ const CdcWaffleChart = ({
|
|
|
535
668
|
let responseData = response.data ?? {}
|
|
536
669
|
|
|
537
670
|
if (response.dataUrl) {
|
|
538
|
-
|
|
671
|
+
const { data, dataMetadata } = await fetchRemoteData(response.dataUrl)
|
|
672
|
+
responseData = data
|
|
673
|
+
response.dataMetadata = dataMetadata
|
|
539
674
|
}
|
|
540
675
|
|
|
541
676
|
response.data = responseData
|
|
@@ -564,8 +699,7 @@ const CdcWaffleChart = ({
|
|
|
564
699
|
|
|
565
700
|
//Load initial config
|
|
566
701
|
useEffect(() => {
|
|
567
|
-
|
|
568
|
-
loadConfig().catch(err => console.log(err))
|
|
702
|
+
loadConfig().catch(err => console.warn(err))
|
|
569
703
|
}, [])
|
|
570
704
|
|
|
571
705
|
useEffect(() => {
|
|
@@ -586,17 +720,12 @@ const CdcWaffleChart = ({
|
|
|
586
720
|
|
|
587
721
|
if (loading === false) {
|
|
588
722
|
content = (
|
|
589
|
-
|
|
590
|
-
|
|
591
|
-
|
|
592
|
-
|
|
593
|
-
|
|
594
|
-
|
|
595
|
-
showConfigConfirm={showConfigConfirm}
|
|
596
|
-
updateConfig={updateConfig}
|
|
597
|
-
/>
|
|
598
|
-
</Layout.Responsive>
|
|
599
|
-
</>
|
|
723
|
+
<WaffleChart
|
|
724
|
+
config={config}
|
|
725
|
+
isEditor={isEditor}
|
|
726
|
+
showConfigConfirm={showConfigConfirm}
|
|
727
|
+
updateConfig={updateConfig}
|
|
728
|
+
/>
|
|
600
729
|
)
|
|
601
730
|
}
|
|
602
731
|
|
|
@@ -605,14 +734,15 @@ const CdcWaffleChart = ({
|
|
|
605
734
|
<ConfigContext.Provider
|
|
606
735
|
value={{ config, updateConfig, loading, data: config.data, setParentConfig, isDashboard, outerContainerRef }}
|
|
607
736
|
>
|
|
608
|
-
<
|
|
737
|
+
<VisualizationContainer
|
|
609
738
|
config={config}
|
|
610
739
|
isEditor={isEditor}
|
|
740
|
+
currentViewport={currentViewport}
|
|
611
741
|
ref={outerContainerRef}
|
|
612
|
-
|
|
742
|
+
editorPanel={<EditorPanel showConfigConfirm={showConfigConfirm} />}
|
|
613
743
|
>
|
|
614
744
|
{content}
|
|
615
|
-
</
|
|
745
|
+
</VisualizationContainer>
|
|
616
746
|
</ConfigContext.Provider>
|
|
617
747
|
</ErrorBoundary>
|
|
618
748
|
)
|