@cdc/chart 4.24.3 → 4.24.4

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.
@@ -2,16 +2,13 @@ import parse from 'html-react-parser'
2
2
  import { LegendOrdinal, LegendItem, LegendLabel } from '@visx/legend'
3
3
  import LegendCircle from '@cdc/core/components/LegendCircle'
4
4
  import Button from '@cdc/core/components/elements/Button'
5
-
6
5
  import useLegendClasses from '../../hooks/useLegendClasses'
7
6
  import { useHighlightedBars } from '../../hooks/useHighlightedBars'
8
7
  import { handleLineType } from '../../helpers/handleLineType'
9
8
  import { Line } from '@visx/shape'
10
- import { scaleOrdinal } from '@visx/scale'
11
9
  import { Label } from '../../types/Label'
12
10
  import { ChartConfig } from '../../types/ChartConfig'
13
11
  import { ColorScale } from '../../types/ChartContext'
14
- import { Group } from '@visx/group'
15
12
  import { forwardRef } from 'react'
16
13
 
17
14
  interface LegendProps {
@@ -20,43 +17,17 @@ interface LegendProps {
20
17
  seriesHighlight: string[]
21
18
  highlight: Function
22
19
  highlightReset: Function
23
- currentViewport: string
20
+ currentViewport: 'lg' | 'md' | 'sm' | 'xs' | 'xxs'
24
21
  formatLabels: (labels: Label[]) => Label[]
25
22
  ref: React.Ref<() => void>
23
+ skipId: string
26
24
  }
27
25
 
28
26
  /* eslint-disable jsx-a11y/no-noninteractive-tabindex, jsx-a11y/no-static-element-interactions */
29
- const Legend: React.FC<LegendProps> = forwardRef(({ config, colorScale, seriesHighlight, highlight, highlightReset, currentViewport, formatLabels }, ref) => {
27
+ const Legend: React.FC<LegendProps> = forwardRef(({ config, colorScale, seriesHighlight, highlight, highlightReset, currentViewport, formatLabels, skipId = 'legend' }, ref) => {
30
28
  const { innerClasses, containerClasses } = useLegendClasses(config)
31
29
  const { runtime, orientation, legend } = config
32
30
  if (!legend) return null
33
- // create fn to reverse labels while legend is Bottom. Legend-right , legend-left works by default.
34
- const displayScale = scaleOrdinal({
35
- domain: config.suppressedData?.map(d => d.label),
36
- range: ['none'],
37
- unknown: 'block'
38
- })
39
-
40
- const renderDashes = style => {
41
- const dashCount = style === 'Dashed Small' ? 3 : 2
42
- const dashClass = `dashes ${style.toLowerCase().replace(' ', '-')}`
43
-
44
- return (
45
- <div className={dashClass}>
46
- {Array.from({ length: dashCount }, (_, i) => (
47
- <span key={i}>-</span>
48
- ))}
49
- </div>
50
- )
51
- }
52
- const renderDashesOrCircle = style => {
53
- if (['Dashed Small', 'Dashed Medium', 'Dashed Large'].includes(style)) {
54
- return renderDashes(style)
55
- } else if (style === 'Open Circles') {
56
- return <div className='dashes open-circles'></div>
57
- }
58
- }
59
-
60
31
  const isBottomOrSmallViewport = legend.position === 'bottom' || ['sm', 'xs', 'xxs'].includes(currentViewport)
61
32
 
62
33
  const legendClasses = {
@@ -67,11 +38,13 @@ const Legend: React.FC<LegendProps> = forwardRef(({ config, colorScale, seriesHi
67
38
  const { HighLightedBarUtils } = useHighlightedBars(config)
68
39
 
69
40
  let highLightedLegendItems = HighLightedBarUtils.findDuplicates(config.highlightedBarValues)
41
+ const fontSize = ['sm', 'xs', 'xxs'].includes(currentViewport) ? { fontSize: '11px' } : null
70
42
 
71
43
  return (
72
- <aside ref={ref} style={legendClasses} id='legend' className={containerClasses.join(' ')} role='region' aria-label='legend' tabIndex={0}>
44
+ <aside ref={ref} style={legendClasses} id={skipId || 'legend'} className={containerClasses.join(' ')} role='region' aria-label='legend' tabIndex={0}>
73
45
  {legend.label && <h3>{parse(legend.label)}</h3>}
74
- {legend.description && <p>{parse(legend.description)}</p>}
46
+ {legend.description && <p style={fontSize}>{parse(legend.description)}</p>}
47
+
75
48
  <LegendOrdinal scale={colorScale} itemDirection='row' labelMargin='0 20px 0 0' shapeMargin='0 10px 0'>
76
49
  {labels => {
77
50
  return (
@@ -116,18 +89,19 @@ const Legend: React.FC<LegendProps> = forwardRef(({ config, colorScale, seriesHi
116
89
  }}
117
90
  role='button'
118
91
  >
119
- {config.visualizationType === 'Line' && config.legend.lineMode ? (
120
- <svg width={40} height={20}>
121
- <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 : '')} />
122
- </svg>
123
- ) : (
124
- <div style={{ display: 'flex', flexDirection: 'column' }}>
125
- <LegendCircle margin='0' fill={label.value} display={displayScale(label.datum)} />
126
- <div style={{ marginTop: '2px', marginRight: '6px' }}>{label.icon}</div>
127
- </div>
128
- )}
129
-
130
- <LegendLabel align='left' margin='0 0 0 4px'>
92
+ <div>
93
+ {config.visualizationType === 'Line' && config.legend.lineMode ? (
94
+ <svg width={40} height={20}>
95
+ <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 : '')} />
96
+ </svg>
97
+ ) : (
98
+ <div style={{ display: 'flex', flexDirection: 'column' }}>
99
+ <LegendCircle viewport={currentViewport} margin='0' fill={label.value} display={true} />
100
+ </div>
101
+ )}
102
+ </div>
103
+
104
+ <LegendLabel style={fontSize} align='left' margin='0 0 0 4px'>
131
105
  {label.text}
132
106
  </LegendLabel>
133
107
  </LegendItem>
@@ -177,10 +151,8 @@ const Legend: React.FC<LegendProps> = forwardRef(({ config, colorScale, seriesHi
177
151
  return (
178
152
  <>
179
153
  {pd.label && (
180
- <div style={{ display: 'flex', flexDirection: 'row', alignItems: 'center' }}>
181
- <svg style={{ width: '50px' }} key={index} height={'23px'}>
182
- {pd.style.includes('Dashed') ? <Line from={{ x: 10, y: 10 }} to={{ x: 40, y: 10 }} stroke={'#000'} strokeWidth={2} strokeDasharray={handleLineType(pd.style)} /> : <circle r={6} strokeWidth={2} stroke={'#000'} cx={22} cy={10} fill='transparent' />}
183
- </svg>
154
+ <div key={index} className='legend-preliminary'>
155
+ <svg>{pd.style.includes('Dashed') ? <Line from={{ x: 10, y: 10 }} to={{ x: 40, y: 10 }} stroke={'#000'} strokeWidth={2} strokeDasharray={handleLineType(pd.style)} /> : <circle r={6} strokeWidth={2} stroke={'#000'} cx={22} cy={10} fill='transparent' />}</svg>
184
156
  <span> {pd.label}</span>
185
157
  </div>
186
158
  )}
@@ -22,7 +22,11 @@ const Legend = forwardRef((props, ref) => {
22
22
 
23
23
  const createLegendLabels = createFormatLabels(config, tableData, data, colorScale)
24
24
 
25
- return !['Box Plot', 'Pie'].includes(config.visualizationType) && <LegendComponent ref={ref} config={config} colorScale={colorScale} seriesHighlight={seriesHighlight} highlight={highlight} highlightReset={highlightReset} currentViewport={currentViewport} formatLabels={createLegendLabels} />
25
+ return (
26
+ !['Box Plot', 'Pie'].includes(config.visualizationType) && (
27
+ <LegendComponent ref={ref} skipId={props.skipId || 'legend'} config={config} colorScale={colorScale} seriesHighlight={seriesHighlight} highlight={highlight} highlightReset={highlightReset} currentViewport={currentViewport} formatLabels={createLegendLabels} />
28
+ )
29
+ )
26
30
  })
27
31
 
28
32
  export default Legend
@@ -28,7 +28,7 @@ import Regions from './Regions'
28
28
  import useMinMax from '../hooks/useMinMax'
29
29
  import useReduceData from '../hooks/useReduceData'
30
30
  import useRightAxis from '../hooks/useRightAxis'
31
- import useScales from '../hooks/useScales'
31
+ import useScales, { getTickValues } from '../hooks/useScales'
32
32
  import useTopAxis from '../hooks/useTopAxis'
33
33
  import { useTooltip as useCoveTooltip } from '../hooks/useTooltip'
34
34
  import { useEditorPermissions } from './EditorPanel/useEditorPermissions'
@@ -375,6 +375,7 @@ const LinearChart = props => {
375
375
  stroke='#333'
376
376
  numTicks={countNumOfTicks('xAxis')}
377
377
  tickStroke='#333'
378
+ tickValues={config.xAxis.manual ? getTickValues(xAxisDataMapped, xScale, config.xAxis.type === 'date-time' ? countNumOfTicks('xAxis') : config.xAxis.manualStep) : undefined}
378
379
  >
379
380
  {props => {
380
381
  const axisCenter = config.visualizationType !== 'Forest Plot' ? (props.axisToPoint.x - props.axisFromPoint.x) / 2 : dimensions[0] / 2
@@ -238,6 +238,38 @@ const useScales = (properties: useScaleProps) => {
238
238
 
239
239
  export default useScales
240
240
 
241
+ export const getTickValues = (xAxisDataMapped, xScale, num) => {
242
+ const xDomain = xScale.domain();
243
+
244
+ if(xScale.type === 'time'){
245
+ const xDomainMax = xAxisDataMapped[xAxisDataMapped.length - 1];
246
+ const xDomainMin = xAxisDataMapped[0];
247
+ const step = (xDomainMax - xDomainMin) / (num - 1);
248
+ const tickValues = [];
249
+ for(let i = xDomainMax; i >= xDomainMin; i -= step){
250
+ tickValues.push(i);
251
+ }
252
+ if(tickValues[tickValues.length - 1] !== xDomainMin){
253
+ tickValues.push(xDomainMin);
254
+ }
255
+ tickValues.reverse();
256
+
257
+ return tickValues;
258
+ }
259
+
260
+ if(xDomain.length > 2){
261
+ const step = num || 1;
262
+ const tickValues = [];
263
+ for(let i = xDomain.length; i > 0; i -= step){
264
+ const adjustedIndex = Math.max(Math.round(i) - 1, 0);
265
+ tickValues.push(xDomain[adjustedIndex]);
266
+ }
267
+ tickValues.reverse();
268
+
269
+ return tickValues;
270
+ }
271
+ }
272
+
241
273
  /// helper functions
242
274
  const composeXScale = ({ min, max, xMax, config }) => {
243
275
  // Adjust min value if using logarithmic scale
@@ -130,6 +130,9 @@
130
130
  word-wrap: break-word;
131
131
  white-space: pre-wrap;
132
132
  word-break: break-word;
133
+ @include breakpoint(xs) {
134
+ font-size: $font-small;
135
+ }
133
136
  }
134
137
  }
135
138
 
@@ -150,6 +153,9 @@
150
153
  h3,
151
154
  p {
152
155
  margin-bottom: 0.8em;
156
+ @include breakpoint(xs) {
157
+ font-size: $font-small + 0.2em;
158
+ }
153
159
  }
154
160
  & div.legend-item {
155
161
  margin-bottom: 0.5em !important;
@@ -192,6 +198,20 @@
192
198
  }
193
199
  }
194
200
 
201
+ .legend-preliminary {
202
+ display: flex;
203
+ flex-direction: row;
204
+ align-items: center;
205
+ @include breakpoint(xs) {
206
+ font-size: $font-small;
207
+ }
208
+
209
+ & > svg {
210
+ width: 50px;
211
+ height: 23px;
212
+ }
213
+ }
214
+
195
215
  .visx-tooltip {
196
216
  z-index: 100000;
197
217
  }
@@ -599,6 +619,11 @@
599
619
  }
600
620
  }
601
621
 
622
+ .cdc-open-viz-module .is-editor .cdc-chart-inner-container {
623
+ overflow: hidden;
624
+ background-color: var(--white);
625
+ }
626
+
602
627
  .isEditor.type-sparkline .cdc-chart-inner-container {
603
628
  margin: 3em auto 0;
604
629
  max-width: 60%;