@cdc/waffle-chart 4.23.5 → 4.23.6
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/cdcwafflechart.js +4848 -3488
- package/package.json +6 -3
- package/src/CdcWaffleChart.jsx +54 -22
- package/src/components/EditorPanel.jsx +44 -19
- package/src/data/initial-state.js +5 -0
- package/src/images/warning.svg +1 -0
- package/src/scss/main.scss +1 -0
- package/src/scss/waffle-chart.scss +54 -10
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@cdc/waffle-chart",
|
|
3
|
-
"version": "4.23.
|
|
3
|
+
"version": "4.23.6",
|
|
4
4
|
"description": "React component for displaying a single piece of data in a card module",
|
|
5
5
|
"moduleName": "CdcWaffleChart",
|
|
6
6
|
"main": "dist/cdcwafflechart",
|
|
@@ -26,8 +26,11 @@
|
|
|
26
26
|
"license": "Apache-2.0",
|
|
27
27
|
"homepage": "https://github.com/CDCgov/cdc-open-viz#readme",
|
|
28
28
|
"dependencies": {
|
|
29
|
-
"@cdc/core": "^4.23.
|
|
29
|
+
"@cdc/core": "^4.23.6",
|
|
30
|
+
"@visx/group": "^3.0.0",
|
|
31
|
+
"@visx/scale": "^3.0.0",
|
|
30
32
|
"@visx/shape": "^3.0.0",
|
|
33
|
+
"@visx/text": "^3.0.0",
|
|
31
34
|
"chroma": "0.0.1",
|
|
32
35
|
"chroma-js": "^2.1.0",
|
|
33
36
|
"html-react-parser": "^3.0.8",
|
|
@@ -38,5 +41,5 @@
|
|
|
38
41
|
"react": "^18.2.0",
|
|
39
42
|
"react-dom": "^18.2.0"
|
|
40
43
|
},
|
|
41
|
-
"gitHead": "
|
|
44
|
+
"gitHead": "aaed0388b487adfeb3e7e278b4ce74df09cbaade"
|
|
42
45
|
}
|
package/src/CdcWaffleChart.jsx
CHANGED
|
@@ -2,6 +2,7 @@ import React, { useCallback, useEffect, useState } from 'react'
|
|
|
2
2
|
import parse from 'html-react-parser'
|
|
3
3
|
import { Group } from '@visx/group'
|
|
4
4
|
import { Circle, Bar } from '@visx/shape'
|
|
5
|
+
import { scaleLinear } from '@visx/scale'
|
|
5
6
|
|
|
6
7
|
import ResizeObserver from 'resize-observer-polyfill'
|
|
7
8
|
import getViewport from '@cdc/core/helpers/getViewport'
|
|
@@ -17,6 +18,7 @@ import defaults from './data/initial-state'
|
|
|
17
18
|
import { publish } from '@cdc/core/helpers/events'
|
|
18
19
|
|
|
19
20
|
import useDataVizClasses from '@cdc/core/helpers/useDataVizClasses'
|
|
21
|
+
import coveUpdateWorker from '@cdc/core/helpers/coveUpdateWorker'
|
|
20
22
|
|
|
21
23
|
import './scss/main.scss'
|
|
22
24
|
|
|
@@ -202,10 +204,10 @@ const WaffleChart = ({ config, isEditor, link }) => {
|
|
|
202
204
|
}
|
|
203
205
|
|
|
204
206
|
// @ts-ignore
|
|
205
|
-
return applyPrecision((waffleNumerator / waffleDenominator) * 100)
|
|
207
|
+
return [applyPrecision((waffleNumerator / waffleDenominator) * 100), waffleDenominator, applyPrecision(waffleNumerator)]
|
|
206
208
|
}, [dataColumn, dataFunction, config.data, filters, dataConditionalColumn, dataConditionalOperator, dataConditionalComparate, customDenom, dataDenomColumn, dataDenomFunction, roundToPlace, dataDenom])
|
|
207
209
|
|
|
208
|
-
const dataPercentage = calculateData()
|
|
210
|
+
const [dataPercentage, waffleDenominator, waffleNumerator] = calculateData()
|
|
209
211
|
|
|
210
212
|
const buildWaffle = useCallback(() => {
|
|
211
213
|
let waffleData = []
|
|
@@ -267,6 +269,14 @@ const WaffleChart = ({ config, isEditor, link }) => {
|
|
|
267
269
|
console.error(e.message)
|
|
268
270
|
}
|
|
269
271
|
}
|
|
272
|
+
const gaugeWidth = '100%'
|
|
273
|
+
const gaugeHeight = 35
|
|
274
|
+
|
|
275
|
+
const xScale = scaleLinear({
|
|
276
|
+
domain: [0, config.dataDenom],
|
|
277
|
+
range: [0, gaugeWidth]
|
|
278
|
+
})
|
|
279
|
+
const gaugeColor = themeColor[theme]
|
|
270
280
|
|
|
271
281
|
return (
|
|
272
282
|
<div className={innerContainerClasses.join(' ')}>
|
|
@@ -278,27 +288,48 @@ const WaffleChart = ({ config, isEditor, link }) => {
|
|
|
278
288
|
)}
|
|
279
289
|
<div className={contentClasses.join(' ')}>
|
|
280
290
|
<div className='cove-component__content-wrap'>
|
|
281
|
-
|
|
282
|
-
<div className=
|
|
283
|
-
<
|
|
284
|
-
<
|
|
285
|
-
|
|
291
|
+
{config.visualizationType === 'Gauge' && (
|
|
292
|
+
<div className={`cove-gauge-chart${config.overallFontSize ? ' font-' + config.overallFontSize : ''}`}>
|
|
293
|
+
<div className='cove-gauge-chart__chart'>
|
|
294
|
+
<div style={dataFontSize}>
|
|
295
|
+
{prefix ? prefix : ' '}
|
|
296
|
+
{config.showPercent ? dataPercentage : waffleNumerator}
|
|
297
|
+
{suffix ? suffix + ' ' : ' '} {config.valueDescription} {config.showDenominator && waffleDenominator ? waffleDenominator : ' '}
|
|
298
|
+
</div>
|
|
299
|
+
<div className='cove-gauge-chart__data--text'>{parse(content)}</div>
|
|
300
|
+
<svg height={gaugeHeight} width={'100%'}>
|
|
301
|
+
<Group>
|
|
302
|
+
<foreignObject style={{ border: '1px solid black' }} x={0} y={0} width={gaugeWidth} height={gaugeHeight} fill='#fff' />
|
|
303
|
+
<Bar x={0} y={0} width={xScale(dataPercentage)} height={gaugeHeight} fill={gaugeColor} />
|
|
304
|
+
</Group>
|
|
305
|
+
</svg>
|
|
306
|
+
<div className={'cove-gauge-chart__subtext'}>{parse(subtext)}</div>
|
|
307
|
+
</div>
|
|
286
308
|
</div>
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
</div>
|
|
295
|
-
)}
|
|
296
|
-
<div className='cove-waffle-chart__data--text'>{parse(content)}</div>
|
|
297
|
-
|
|
298
|
-
{subtext && <div className='cove-waffle-chart__subtext'>{parse(subtext)}</div>}
|
|
309
|
+
)}
|
|
310
|
+
{config.visualizationType !== 'Gauge' && (
|
|
311
|
+
<div className={`cove-waffle-chart${orientation === 'vertical' ? ' cove-waffle-chart--verical' : ''}${config.overallFontSize ? ' font-' + config.overallFontSize : ''}`}>
|
|
312
|
+
<div className='cove-waffle-chart__chart' style={{ width: setRatio() }}>
|
|
313
|
+
<svg width={setRatio()} height={setRatio()} role='img' aria-label={handleWaffleChartAriaLabel(config)} tabIndex={0}>
|
|
314
|
+
<Group>{buildWaffle()}</Group>
|
|
315
|
+
</svg>
|
|
299
316
|
</div>
|
|
300
|
-
|
|
301
|
-
|
|
317
|
+
{(dataPercentage || content) && (
|
|
318
|
+
<div className='cove-waffle-chart__data'>
|
|
319
|
+
{dataPercentage && (
|
|
320
|
+
<div className='cove-waffle-chart__data--primary' style={dataFontSize}>
|
|
321
|
+
{prefix ? prefix : null}
|
|
322
|
+
{dataPercentage}
|
|
323
|
+
{suffix ? suffix : null}
|
|
324
|
+
</div>
|
|
325
|
+
)}
|
|
326
|
+
<div className='cove-waffle-chart__data--text'>{parse(content)}</div>
|
|
327
|
+
|
|
328
|
+
{subtext && <div className='cove-waffle-chart__subtext'>{parse(subtext)}</div>}
|
|
329
|
+
</div>
|
|
330
|
+
)}
|
|
331
|
+
</div>
|
|
332
|
+
)}
|
|
302
333
|
</div>
|
|
303
334
|
</div>
|
|
304
335
|
{link && link}
|
|
@@ -341,7 +372,8 @@ const CdcWaffleChart = ({ configUrl, config: configObj, isDashboard = false, isE
|
|
|
341
372
|
|
|
342
373
|
response.data = responseData
|
|
343
374
|
|
|
344
|
-
|
|
375
|
+
const processedConfig = { ...(await coveUpdateWorker(response)) }
|
|
376
|
+
updateConfig({ ...defaults, ...processedConfig })
|
|
345
377
|
setLoading(false)
|
|
346
378
|
}, [])
|
|
347
379
|
|
|
@@ -13,6 +13,7 @@ import InputSelect from '@cdc/core/components/inputs/InputSelect'
|
|
|
13
13
|
import InputCheckbox from '@cdc/core/components/inputs/InputCheckbox'
|
|
14
14
|
|
|
15
15
|
import '@cdc/core/styles/v2/components/editor.scss'
|
|
16
|
+
import WarningImage from '../images/warning.svg'
|
|
16
17
|
|
|
17
18
|
import { DATA_OPERATORS, DATA_FUNCTIONS } from '../CdcWaffleChart'
|
|
18
19
|
|
|
@@ -194,12 +195,23 @@ const EditorPanel = memo(props => {
|
|
|
194
195
|
}
|
|
195
196
|
return filterDataOptions
|
|
196
197
|
}
|
|
198
|
+
//visualizationType
|
|
199
|
+
|
|
200
|
+
const approvedWaffleChartOptions = [
|
|
201
|
+
'Waffle'
|
|
202
|
+
// 'Gauge'
|
|
203
|
+
]
|
|
197
204
|
|
|
198
205
|
const editorContent = (
|
|
199
206
|
<Accordion>
|
|
200
207
|
<Accordion.Section title='General'>
|
|
208
|
+
<div className='cove-accordion__panel-section'>
|
|
209
|
+
<div style={{ width: '100%', display: 'block' }} className='cove-input-group'>
|
|
210
|
+
<InputSelect value={config.visualizationType} fieldName='visualizationType' label='Chart Type' updateField={updateField} options={approvedWaffleChartOptions} className='cove-input' />
|
|
211
|
+
{config.visualizationType === 'Gauge' && <InputSelect value={config.visualizationSubType} fieldName='visualizationSubType' label='Chart Subtype' updateField={updateField} options={['Linear']} className='cove-input' />}
|
|
212
|
+
</div>
|
|
213
|
+
</div>
|
|
201
214
|
<InputText value={config.title} fieldName='title' label='Title' placeholder='Waffle Chart Title' updateField={updateField} />
|
|
202
|
-
|
|
203
215
|
<InputText
|
|
204
216
|
type='textarea'
|
|
205
217
|
value={config.content}
|
|
@@ -236,7 +248,13 @@ const EditorPanel = memo(props => {
|
|
|
236
248
|
}
|
|
237
249
|
/>
|
|
238
250
|
</Accordion.Section>
|
|
239
|
-
|
|
251
|
+
|
|
252
|
+
<Accordion.Section icon={!config.dataColumn || !config.dataFunction ? <WarningImage width='15' className='warning-icon' /> : ''} title='Data'>
|
|
253
|
+
{(!config.dataColumn || !config.dataFunction) && (
|
|
254
|
+
<div className='cove-accordion__panel-section'>
|
|
255
|
+
<p className='warning-text'>Please select numerator</p>
|
|
256
|
+
</div>
|
|
257
|
+
)}
|
|
240
258
|
<h4 style={{ fontWeight: '600' }}>Numerator</h4>
|
|
241
259
|
<div className='cove-accordion__panel-section'>
|
|
242
260
|
<div className='cove-input-group'>
|
|
@@ -308,9 +326,16 @@ const EditorPanel = memo(props => {
|
|
|
308
326
|
</div>
|
|
309
327
|
</li>
|
|
310
328
|
</ul>
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
329
|
+
{false && (
|
|
330
|
+
<>
|
|
331
|
+
<hr className='cove-accordion__divider' />
|
|
332
|
+
<div className='cove-accordion__panel-section reverse-labels'>
|
|
333
|
+
<InputText inline size='small' value={config.valueDescription} label='Value Descriptor' fieldName='valueDescription' updateField={updateField} />
|
|
334
|
+
<InputCheckbox inline size='small' value={config.showPercent} label='Show Percentage' fieldName='showPercent' updateField={updateField} />
|
|
335
|
+
<InputCheckbox inline size='small' label='Show Denominator' value={config.showDenominator} fieldName='showDenominator' updateField={updateField} />
|
|
336
|
+
</div>
|
|
337
|
+
</>
|
|
338
|
+
)}
|
|
314
339
|
<label style={{ marginBottom: '1rem' }}>
|
|
315
340
|
<span className='edit-label'>Data Point Filters</span>
|
|
316
341
|
<Tooltip style={{ textTransform: 'none' }}>
|
|
@@ -322,6 +347,7 @@ const EditorPanel = memo(props => {
|
|
|
322
347
|
</Tooltip.Content>
|
|
323
348
|
</Tooltip>
|
|
324
349
|
</label>
|
|
350
|
+
|
|
325
351
|
{config.filters && (
|
|
326
352
|
<ul className='filters-list' style={{ paddingLeft: 0, marginBottom: '1rem' }}>
|
|
327
353
|
{config.filters.map((filter, index) => (
|
|
@@ -376,20 +402,19 @@ const EditorPanel = memo(props => {
|
|
|
376
402
|
</Button>
|
|
377
403
|
</Accordion.Section>
|
|
378
404
|
<Accordion.Section title='Visual'>
|
|
379
|
-
<InputSelect value={config.shape} fieldName='shape' label='Shape' updateField={updateField} options={['circle', 'square', 'person']} className='cove-input' />
|
|
380
|
-
|
|
381
|
-
|
|
382
|
-
|
|
383
|
-
|
|
384
|
-
|
|
385
|
-
|
|
386
|
-
|
|
405
|
+
{config.visualizationType !== 'Gauge' && <InputSelect value={config.shape} fieldName='shape' label='Shape' updateField={updateField} options={['circle', 'square', 'person']} className='cove-input' />}
|
|
406
|
+
{config.visualizationType !== 'Gauge' && (
|
|
407
|
+
<div className='cove-accordion__panel-row cove-accordion__small-inputs' style={{ marginTop: '1rem', marginBottom: '1rem' }}>
|
|
408
|
+
<div className='cove-accordion__panel-col'>
|
|
409
|
+
<InputText type='number' value={config.nodeWidth} fieldName='nodeWidth' label='Width' updateField={updateField} />
|
|
410
|
+
</div>
|
|
411
|
+
<div className='cove-accordion__panel-col'>
|
|
412
|
+
<InputText type='number' value={config.nodeSpacer} fieldName='nodeSpacer' label='Spacer' updateField={updateField} />
|
|
413
|
+
</div>
|
|
387
414
|
</div>
|
|
388
|
-
|
|
415
|
+
)}
|
|
389
416
|
|
|
390
|
-
<div className='cove-input-group'>
|
|
391
|
-
<InputSelect value={config.orientation} fieldName='orientation' label='Layout' updateField={updateField} className='cove-input' options={['horizontal', 'vertical']} />
|
|
392
|
-
</div>
|
|
417
|
+
<div className='cove-input-group'>{config.visualizationType !== 'Gauge' && <InputSelect value={config.orientation} fieldName='orientation' label='Layout' updateField={updateField} className='cove-input' options={['horizontal', 'vertical']} />}</div>
|
|
393
418
|
|
|
394
419
|
<div className='cove-input-group'>
|
|
395
420
|
<label>
|
|
@@ -400,7 +425,7 @@ const EditorPanel = memo(props => {
|
|
|
400
425
|
<InputText type='number' value={config.fontSize} fieldName='fontSize' updateField={updateField} />
|
|
401
426
|
</div>
|
|
402
427
|
<div className='cove-accordion__panel-col' style={{ display: 'flex', alignItems: 'center' }}>
|
|
403
|
-
<label className='accordion__panel-label--muted'>default (50px)</label>
|
|
428
|
+
<label className='accordion__panel-label--muted'> {config.visualizationType === 'Gauge' ? ' default (16px)' : ' default (50px)'}</label>
|
|
404
429
|
</div>
|
|
405
430
|
</div>
|
|
406
431
|
</div>
|
|
@@ -444,7 +469,7 @@ const EditorPanel = memo(props => {
|
|
|
444
469
|
<button className={`cove-editor--toggle` + (!displayPanel ? ` collapsed` : ``)} title={displayPanel ? `Collapse Editor` : `Expand Editor`} onClick={onBackClick} />
|
|
445
470
|
<section className={`cove-editor__panel` + (displayPanel ? `` : ' hidden')}>
|
|
446
471
|
<div className='cove-editor__panel-container'>
|
|
447
|
-
<h2 className='cove-editor__heading'>Configure
|
|
472
|
+
<h2 className='cove-editor__heading'>Configure Chart</h2>
|
|
448
473
|
<section className='cove-editor__content'>{editorContent}</section>
|
|
449
474
|
</div>
|
|
450
475
|
</section>
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 512 512"><path fill="currentColor" d="M504 256c0 136.997-111.043 248-248 248S8 392.997 8 256C8 119.083 119.043 8 256 8s248 111.083 248 248zm-248 50c-25.405 0-46 20.595-46 46s20.595 46 46 46 46-20.595 46-46-20.595-46-46-46zm-43.673-165.346l7.418 136c.347 6.364 5.609 11.346 11.982 11.346h48.546c6.373 0 11.635-4.982 11.982-11.346l7.418-136c.375-6.874-5.098-12.654-11.982-12.654h-63.383c-6.884 0-12.356 5.78-11.981 12.654z"/></svg>
|
package/src/scss/main.scss
CHANGED
|
@@ -18,6 +18,21 @@
|
|
|
18
18
|
// }
|
|
19
19
|
//}
|
|
20
20
|
|
|
21
|
+
.warning-icon {
|
|
22
|
+
position: absolute;
|
|
23
|
+
top: 50%;
|
|
24
|
+
left: 20%;
|
|
25
|
+
transform: translate(-50%, -50%);
|
|
26
|
+
color: red;
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
.warning-text {
|
|
30
|
+
background-color: rgba(235, 146, 146, 0.953);
|
|
31
|
+
color: red;
|
|
32
|
+
text-align: center;
|
|
33
|
+
padding: 12px 0;
|
|
34
|
+
}
|
|
35
|
+
|
|
21
36
|
.cove {
|
|
22
37
|
&-editor__panel {
|
|
23
38
|
ul.color-palette {
|
|
@@ -25,6 +40,27 @@
|
|
|
25
40
|
}
|
|
26
41
|
}
|
|
27
42
|
|
|
43
|
+
.cove-gauge-chart {
|
|
44
|
+
&__chart {
|
|
45
|
+
width: 85%;
|
|
46
|
+
margin: 0 auto;
|
|
47
|
+
margin-left: auto;
|
|
48
|
+
height: auto;
|
|
49
|
+
display: flex;
|
|
50
|
+
flex-direction: column;
|
|
51
|
+
justify-items: center;
|
|
52
|
+
align-items: flex-start;
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
&__subtext {
|
|
56
|
+
font-size: 0.75em;
|
|
57
|
+
}
|
|
58
|
+
&__text {
|
|
59
|
+
line-height: 1.25em;
|
|
60
|
+
width: 100%;
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
|
|
28
64
|
.cove-waffle-chart {
|
|
29
65
|
display: flex;
|
|
30
66
|
flex-wrap: wrap;
|
|
@@ -54,7 +90,6 @@
|
|
|
54
90
|
}
|
|
55
91
|
|
|
56
92
|
.cove-waffle-chart__subtext {
|
|
57
|
-
font-style: italic;
|
|
58
93
|
font-size: 0.75em;
|
|
59
94
|
}
|
|
60
95
|
|
|
@@ -92,29 +127,38 @@
|
|
|
92
127
|
}
|
|
93
128
|
|
|
94
129
|
@at-root {
|
|
95
|
-
.cove-waffle-chart.font-small
|
|
96
|
-
|
|
130
|
+
.cove-waffle-chart.font-small,
|
|
131
|
+
.cove-gauge-chart.font-small #{&} {
|
|
132
|
+
.cove-waffle-chart__data--primary,
|
|
133
|
+
.cove-gauge-chart__data--primary {
|
|
97
134
|
font-size: 35px;
|
|
98
135
|
}
|
|
99
|
-
.cove-waffle-chart__data--text
|
|
136
|
+
.cove-waffle-chart__data--text,
|
|
137
|
+
.cove-gauge-chart__data--text {
|
|
100
138
|
font-size: 14px;
|
|
101
139
|
}
|
|
102
140
|
}
|
|
103
141
|
|
|
104
|
-
.cove-waffle-chart.font-medium
|
|
105
|
-
|
|
142
|
+
.cove-waffle-chart.font-medium,
|
|
143
|
+
.cove-gauge-chart.font-medium #{&} {
|
|
144
|
+
.cove-waffle-chart__data--primary,
|
|
145
|
+
.cove-gauge-chart__data--primary {
|
|
106
146
|
font-size: 50px;
|
|
107
147
|
}
|
|
108
|
-
.cove-waffle-chart__data--text
|
|
148
|
+
.cove-waffle-chart__data--text,
|
|
149
|
+
.cove-gauge-chart__data--text {
|
|
109
150
|
font-size: 18px;
|
|
110
151
|
}
|
|
111
152
|
}
|
|
112
153
|
|
|
113
|
-
.cove-waffle-chart.font-large
|
|
114
|
-
|
|
154
|
+
.cove-waffle-chart.font-large,
|
|
155
|
+
.cove-gauge-chart.font-large #{&} {
|
|
156
|
+
.cove-waffle-chart__data--primary,
|
|
157
|
+
.cove-gauge-chart__data--primary {
|
|
115
158
|
font-size: 80px;
|
|
116
159
|
}
|
|
117
|
-
.cove-waffle-chart__data--text
|
|
160
|
+
.cove-waffle-chart__data--text,
|
|
161
|
+
.cove-gauge-chart__data--text {
|
|
118
162
|
font-size: 20px;
|
|
119
163
|
}
|
|
120
164
|
}
|