@cdc/waffle-chart 4.23.4 → 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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@cdc/waffle-chart",
3
- "version": "4.23.4",
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.4",
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": "dcd395d76f70b2d113f2b4c6fe50a52522655cd1"
44
+ "gitHead": "aaed0388b487adfeb3e7e278b4ce74df09cbaade"
42
45
  }
@@ -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
- <div className={`cove-waffle-chart${orientation === 'vertical' ? ' cove-waffle-chart--verical' : ''}${config.overallFontSize ? ' font-' + config.overallFontSize : ''}`}>
282
- <div className='cove-waffle-chart__chart' style={{ width: setRatio() }}>
283
- <svg width={setRatio()} height={setRatio()} role='img' aria-label={handleWaffleChartAriaLabel(config)} tabIndex={0}>
284
- <Group>{buildWaffle()}</Group>
285
- </svg>
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
- {(dataPercentage || content) && (
288
- <div className='cove-waffle-chart__data'>
289
- {dataPercentage && (
290
- <div className='cove-waffle-chart__data--primary' style={dataFontSize}>
291
- {prefix ? prefix : null}
292
- {dataPercentage}
293
- {suffix ? suffix : null}
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
- </div>
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
- updateConfig({ ...defaults, ...response })
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
- <Accordion.Section title='Data'>
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
- <hr className='cove-accordion__divider' />
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
- <div className='cove-accordion__panel-row cove-accordion__small-inputs' style={{ marginTop: '1rem', marginBottom: '1rem' }}>
382
- <div className='cove-accordion__panel-col'>
383
- <InputText type='number' value={config.nodeWidth} fieldName='nodeWidth' label='Width' updateField={updateField} />
384
- </div>
385
- <div className='cove-accordion__panel-col'>
386
- <InputText type='number' value={config.nodeSpacer} fieldName='nodeSpacer' label='Spacer' updateField={updateField} />
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
- </div>
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 Waffle Chart</h2>
472
+ <h2 className='cove-editor__heading'>Configure Chart</h2>
448
473
  <section className='cove-editor__content'>{editorContent}</section>
449
474
  </div>
450
475
  </section>
@@ -1,5 +1,10 @@
1
1
  export default {
2
2
  title: 'Waffle Chart',
3
+ visualizationType: 'Waffle',
4
+ visualizationSubType: 'linear',
5
+ showPercent: true,
6
+ showDenominator: true,
7
+ valueDescription: 'out of',
3
8
  content: '',
4
9
  subtext: '',
5
10
  orientation: 'horizontal',
@@ -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>
@@ -1,3 +1,4 @@
1
+ @import '@cdc/core/styles/v2/components/input';
1
2
  @import '@cdc/core/styles/v2/main';
2
3
  @import 'waffle-chart';
3
4
 
@@ -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
- .cove-waffle-chart__data--primary {
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
- .cove-waffle-chart__data--primary {
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
- .cove-waffle-chart__data--primary {
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
  }