@cdc/chart 1.3.3 → 4.22.10

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.
Files changed (49) hide show
  1. package/dist/cdcchart.js +6 -6
  2. package/examples/cutoff-example-config.json +2 -0
  3. package/examples/cutoff-example-data.json +1 -1
  4. package/examples/dynamic-legends.json +125 -0
  5. package/examples/gallery/bar-chart-horizontal/horizontal-bar-chart-with-numbers-on-bar.json +198 -0
  6. package/examples/gallery/bar-chart-horizontal/horizontal-bar-chart.json +241 -0
  7. package/examples/gallery/bar-chart-horizontal/horizontal-stacked.json +248 -0
  8. package/examples/gallery/bar-chart-vertical/combo-line-chart.json +137 -0
  9. package/examples/gallery/bar-chart-vertical/vertical-bar-chart-categorical.json +80 -0
  10. package/examples/gallery/bar-chart-vertical/vertical-bar-chart-stacked.json +81 -0
  11. package/examples/gallery/bar-chart-vertical/vertical-bar-chart-with-confidence.json +68 -0
  12. package/examples/gallery/bar-chart-vertical/vertical-bar-chart.json +111 -0
  13. package/examples/gallery/lollipop/lollipop-style-horizontal.json +220 -0
  14. package/examples/gallery/paired-bar/paired-bar-chart.json +196 -0
  15. package/examples/horizontal-chart.json +3 -0
  16. package/examples/paired-bar-data.json +1 -1
  17. package/examples/paired-bar-example.json +2 -0
  18. package/examples/planet-combo-example-config.json +2 -0
  19. package/examples/planet-example-config.json +2 -2
  20. package/examples/planet-example-data.json +1 -1
  21. package/examples/planet-pie-example-config.json +2 -0
  22. package/examples/private/line-test-data.json +22 -0
  23. package/examples/private/line-test-two.json +216 -0
  24. package/examples/private/line-test.json +102 -0
  25. package/examples/private/shawn.json +1296 -0
  26. package/examples/private/yaxis-test.json +132 -0
  27. package/examples/private/yaxis-testing.csv +27 -0
  28. package/examples/private/yaxis.json +28 -0
  29. package/examples/stacked-vertical-bar-example.json +228 -0
  30. package/package.json +3 -3
  31. package/src/CdcChart.tsx +121 -168
  32. package/src/components/BarChart.tsx +92 -40
  33. package/src/components/DataTable.tsx +28 -13
  34. package/src/components/EditorPanel.js +286 -182
  35. package/src/components/Legend.js +334 -0
  36. package/src/components/LineChart.tsx +57 -17
  37. package/src/components/LinearChart.tsx +171 -77
  38. package/src/components/PairedBarChart.tsx +139 -42
  39. package/src/components/PieChart.tsx +33 -6
  40. package/src/components/SparkLine.js +28 -27
  41. package/src/components/useIntersectionObserver.tsx +30 -0
  42. package/src/data/initial-state.js +23 -7
  43. package/src/hooks/useChartClasses.js +35 -0
  44. package/src/hooks/useLegendClasses.js +20 -0
  45. package/src/hooks/useReduceData.ts +72 -24
  46. package/src/index.html +29 -30
  47. package/src/scss/editor-panel.scss +34 -4
  48. package/src/scss/main.scss +201 -5
  49. package/src/components/BarStackVertical.js +0 -0
@@ -1,4 +1,4 @@
1
- import React, { Fragment, useContext, useEffect,useState } from 'react';
1
+ import React, { Fragment, useContext, useEffect, useRef, useState } from 'react';
2
2
  import ReactTooltip from 'react-tooltip';
3
3
 
4
4
  import { Group } from '@visx/group';
@@ -11,17 +11,37 @@ import BarChart from './BarChart';
11
11
  import LineChart from './LineChart';
12
12
  import Context from '../context';
13
13
  import PairedBarChart from './PairedBarChart';
14
+ import useIntersectionObserver from "./useIntersectionObserver";
14
15
  import SparkLine from './SparkLine';
15
16
 
16
17
  import ErrorBoundary from '@cdc/core/components/ErrorBoundary';
17
-
18
+ import numberFromString from '@cdc/core/helpers/numberFromString'
18
19
  import '../scss/LinearChart.scss';
19
20
  import useReduceData from '../hooks/useReduceData';
20
21
 
22
+ // TODO: remove unused imports/variables
23
+ // TODO: consider moving logic into hooks
24
+ // TODO: formatting
21
25
  export default function LinearChart() {
22
- const { transformedData: data, dimensions, config, parseDate, formatDate, currentViewport,formatNumber } = useContext<any>(Context);
26
+ const { transformedData: data, dimensions, config, parseDate, formatDate, currentViewport, formatNumber, handleChartAriaLabels } = useContext<any>(Context);
23
27
  let [ width ] = dimensions;
24
- const {minValue,maxValue} = useReduceData(config,data)
28
+ const {minValue,maxValue,existPositiveValue} = useReduceData(config,data)
29
+ const [animatedChart, setAnimatedChart] = useState<boolean>(false);
30
+ const [animatedChartPlayed, setAnimatedChartPlayed] = useState<boolean>(false);
31
+
32
+ const triggerRef = useRef();
33
+ const dataRef = useIntersectionObserver(triggerRef, {
34
+ freezeOnceVisible: false
35
+ });
36
+ // If the chart is in view and set to animate and it has not already played
37
+ useEffect( () => {
38
+ if( dataRef?.isIntersecting === true && config.animate ) {
39
+ setTimeout(() => {
40
+ setAnimatedChart(prevState => true);
41
+ }, 500);
42
+ }
43
+ }, [dataRef?.isIntersecting, config.animate]);
44
+
25
45
  if(config && config.legend && !config.legend.hide && (currentViewport === 'lg' || currentViewport === 'md')) {
26
46
  width = width * 0.73;
27
47
  }
@@ -38,16 +58,25 @@ export default function LinearChart() {
38
58
  let yScale;
39
59
  let seriesScale;
40
60
 
61
+ const {max:enteredMaxValue,min:enteredMinValue} = config.runtime.yAxis;
62
+ const isMaxValid = existPositiveValue ? numberFromString(enteredMaxValue) >= numberFromString(maxValue) : numberFromString(enteredMaxValue) >= 0;
63
+ const isMinValid = ((numberFromString(enteredMinValue) <= 0 && numberFromString(minValue) >=0) || (numberFromString(enteredMinValue) <= minValue && minValue < 0));
64
+
41
65
  if (data) {
42
- let min = config.runtime.yAxis.min !== undefined ? config.runtime.yAxis.min : minValue
43
- let max = config.runtime.yAxis.max !== undefined ? config.runtime.yAxis.max : Number.MIN_VALUE;
66
+ let min = enteredMinValue && isMinValid ? enteredMinValue : minValue;
67
+ let max = enteredMaxValue && isMaxValid ? enteredMaxValue : Number.MIN_VALUE;
44
68
 
45
69
  if((config.visualizationType === 'Bar' || config.visualizationType === 'Combo') && min > 0) {
46
70
  min = 0;
47
71
  }
72
+ if(config.visualizationType === 'Line' ){
73
+ const isMinValid = Number(enteredMinValue) < Number(minValue)
74
+ min = (enteredMinValue && isMinValid) ? Number(enteredMinValue) : minValue;
75
+ }
48
76
  //If data value max wasn't provided, calculate it
49
77
  if(max === Number.MIN_VALUE){
50
- max = maxValue
78
+ // if all values in data are negative set max = 0
79
+ max = existPositiveValue ? maxValue : 0;
51
80
  }
52
81
 
53
82
  //Adds Y Axis data padding if applicable
@@ -59,41 +88,65 @@ export default function LinearChart() {
59
88
 
60
89
  let xAxisDataMapped = data.map(d => getXAxisData(d));
61
90
 
62
- if(config.runtime.horizontal){
63
- xScale = scaleLinear<number>({
64
- domain: [min, max],
65
- range: [0, xMax]
66
- });
67
-
68
- yScale = config.runtime.xAxis.type === 'date' ?
69
- scaleLinear<number>({domain: [Math.min(...xAxisDataMapped), Math.max(...xAxisDataMapped)]}) :
70
- scalePoint<string>({domain: xAxisDataMapped, padding: 0.5});
71
-
72
- seriesScale = scalePoint<string>({
73
- domain: (config.runtime.barSeriesKeys || config.runtime.seriesKeys),
74
- range: [0, yMax]
75
- });
76
-
77
- yScale.rangeRound([0, yMax]);
78
- } else {
79
- min = min < 0 ? min * 1.11 : min
80
-
81
- yScale = scaleLinear<number>({
82
- domain: [min, max],
83
- range: [yMax, 0]
84
- });
85
-
86
- xScale = scalePoint<string>({domain: xAxisDataMapped, range: [0, xMax], padding: 0.5});
87
-
88
- seriesScale = scalePoint<string>({
89
- domain: (config.runtime.barSeriesKeys || config.runtime.seriesKeys),
90
- range: [0, xMax]
91
- });
91
+ if (config.isLollipopChart && config.yAxis.displayNumbersOnBar) {
92
+ const dataKey = data.map((item) => item[config.series[0].dataKey]);
93
+ const maxDataVal = Math.max(...dataKey).toString().length;
94
+
95
+ switch (true) {
96
+ case maxDataVal > 8 && maxDataVal <= 12:
97
+ max = max * 1.3;
98
+ break;
99
+ case maxDataVal > 4 && maxDataVal <= 7:
100
+ max = max * 1.1;
101
+ break;
102
+ }
92
103
  }
93
104
 
105
+ if (config.runtime.horizontal) {
106
+ xScale = scaleLinear<number>({
107
+ domain: [min, max],
108
+ range: [0, xMax],
109
+ });
110
+
111
+ yScale =
112
+ config.runtime.xAxis.type === "date"
113
+ ? scaleLinear<number>({
114
+ domain: [
115
+ Math.min(...xAxisDataMapped),
116
+ Math.max(...xAxisDataMapped),
117
+ ],
118
+ })
119
+ : scalePoint<string>({ domain: xAxisDataMapped, padding: 0.5 });
120
+
121
+ seriesScale = scalePoint<string>({
122
+ domain: config.runtime.barSeriesKeys || config.runtime.seriesKeys,
123
+ range: [0, yMax],
124
+ });
125
+
126
+ yScale.rangeRound([0, yMax]);
127
+ } else {
128
+ min = min < 0 ? min * 1.11 : min;
129
+
130
+ yScale = scaleLinear<number>({
131
+ domain: [min, max],
132
+ range: [yMax, 0],
133
+ });
134
+
135
+ xScale = scalePoint<string>({
136
+ domain: xAxisDataMapped,
137
+ range: [0, xMax],
138
+ padding: 0.5,
139
+ });
140
+
141
+ seriesScale = scalePoint<string>({
142
+ domain: config.runtime.barSeriesKeys || config.runtime.seriesKeys,
143
+ range: [0, xMax],
144
+ });
145
+ }
146
+
94
147
 
95
148
  if(config.visualizationType === 'Paired Bar') {
96
-
149
+
97
150
 
98
151
  let groupOneMax = Math.max.apply(Math, data.map(d => d[config.series[0].dataKey]))
99
152
  let groupTwoMax = Math.max.apply(Math, data.map(d => d[config.series[1].dataKey]))
@@ -103,7 +156,7 @@ export default function LinearChart() {
103
156
  domain: [0, Math.max(groupOneMax,groupTwoMax) ],
104
157
  range: [xMax/2, 0]
105
158
  })
106
-
159
+
107
160
  // group 2
108
161
  var g2xScale = scaleLinear<number>({
109
162
  domain: g1xScale.domain(),
@@ -119,10 +172,16 @@ export default function LinearChart() {
119
172
  ReactTooltip.rebuild();
120
173
  });
121
174
 
122
-
123
- return (
175
+ return isNaN(width) ? <></> : (
124
176
  <ErrorBoundary component="LinearChart">
125
- <svg width={width} height={height} className="linear">
177
+ <svg
178
+ width={width}
179
+ height={height}
180
+ className={`linear ${(config.animate) ? 'animated' : ''} ${animatedChart && config.animate ? 'animate' : ''}`}
181
+ role="img"
182
+ aria-label={handleChartAriaLabels(config)}
183
+ tabIndex={0}
184
+ >
126
185
  {/* Higlighted regions */}
127
186
  { config.regions ? config.regions.map((region) => {
128
187
  if(!Object.keys(region).includes('from') || !Object.keys(region).includes('to')) return null
@@ -173,7 +232,7 @@ export default function LinearChart() {
173
232
  const axisCenter = config.runtime.horizontal ? (props.axisToPoint.y - props.axisFromPoint.y) / 2 : (props.axisFromPoint.y - props.axisToPoint.y) / 2;
174
233
  const horizontalTickOffset = yMax / props.ticks.length / 2 - (yMax / props.ticks.length * (1 - config.barThickness)) + 5;
175
234
  const belowBarPaddingFromTop = 9;
176
- return (
235
+ return (
177
236
  <Group className="left-axis">
178
237
  {props.ticks.map((tick, i) => {
179
238
  return (
@@ -188,15 +247,16 @@ export default function LinearChart() {
188
247
  stroke="#333"
189
248
  display={config.runtime.horizontal ? 'none' : 'block'}
190
249
  />
191
- )}
192
- { config.runtime.yAxis.gridLines ? (
193
- <Line
194
- from={{x: tick.from.x + xMax, y: tick.from.y}}
195
- to={tick.from}
196
- stroke="rgba(0,0,0,0.3)"
197
- />
198
- ) : ''
199
- }
250
+ )}
251
+
252
+ { config.runtime.yAxis.gridLines ? (
253
+ <Line
254
+ from={{x: tick.from.x + xMax, y: tick.from.y}}
255
+ to={tick.from}
256
+ stroke="rgba(0,0,0,0.3)"
257
+ />
258
+ ) : ''
259
+ }
200
260
 
201
261
  {( config.orientation === "horizontal" && config.visualizationSubType !== 'stacked') && (config.yAxis.labelPlacement === 'On Date/Category Axis' ) && !config.yAxis.hideLabel &&
202
262
  // 17 is a magic number from the offset in barchart.
@@ -205,7 +265,7 @@ export default function LinearChart() {
205
265
  transform={`translate(${tick.to.x - 5}, ${ config.isLollipopChart ? tick.from.y : tick.from.y - 17 }) rotate(-${config.runtime.horizontal ? config.runtime.yAxis.tickRotation : 0})`}
206
266
  verticalAnchor={ config.isLollipopChart ? "middle" : "middle"}
207
267
  textAnchor={"end"}
208
- >{formatNumber(tick.formattedValue)}</Text>
268
+ >{tick.formattedValue}</Text>
209
269
  </Fragment>
210
270
  }
211
271
 
@@ -215,7 +275,16 @@ export default function LinearChart() {
215
275
  transform={`translate(${tick.to.x - 5}, ${ tick.from.y - config.barHeight / 2 - 3 }) rotate(-${config.runtime.horizontal ? config.runtime.yAxis.tickRotation : 0})`}
216
276
  verticalAnchor={ config.isLollipopChart ? "middle" : "middle"}
217
277
  textAnchor={"end"}
218
- >{formatNumber(tick.formattedValue)}</Text>
278
+ >{tick.formattedValue}</Text>
279
+ }
280
+
281
+ { (config.orientation === "horizontal" && config.visualizationType === 'Paired Bar') && !config.yAxis.hideLabel &&
282
+ // 17 is a magic number from the offset in barchart.
283
+ <Text
284
+ transform={`translate(${-15}, ${ tick.from.y }) rotate(-${config.runtime.horizontal ? config.runtime.yAxis.tickRotation : 0})`}
285
+ verticalAnchor={ config.isLollipopChart ? "middle" : "middle"}
286
+ textAnchor={"end"}
287
+ >{tick.formattedValue}</Text>
219
288
  }
220
289
 
221
290
  { (config.orientation === "horizontal" && config.visualizationType === 'Paired Bar') && !config.yAxis.hideLabel &&
@@ -235,7 +304,7 @@ export default function LinearChart() {
235
304
  verticalAnchor={config.runtime.horizontal ? "start" : "middle"}
236
305
  textAnchor={config.runtime.horizontal ? 'start' : 'end'}
237
306
  >
238
- {formatNumber(tick.value)}
307
+ {tick.formattedValue}
239
308
  </Text>
240
309
  }
241
310
 
@@ -343,7 +412,7 @@ export default function LinearChart() {
343
412
  top={yMax}
344
413
  left={config.runtime.yAxis.size}
345
414
  label={config.runtime.xAxis.label}
346
- tickFormat={config.runtime.xAxis.type === 'date' ? formatDate : (tick) => tick}
415
+ tickFormat={config.runtime.xAxis.type === 'date' ? formatDate :formatNumber}
347
416
  scale={g1xScale}
348
417
  stroke="#333"
349
418
  tickStroke="#333"
@@ -395,7 +464,7 @@ export default function LinearChart() {
395
464
  top={yMax}
396
465
  left={config.runtime.yAxis.size}
397
466
  label={config.runtime.xAxis.label}
398
- tickFormat={config.runtime.xAxis.type === 'date' ? formatDate : (tick) => tick}
467
+ tickFormat={config.runtime.xAxis.type === 'date' ? formatDate : config.runtime.xAxis.dataKey !=='Year'? formatNumber : (tick)=>tick}
399
468
  scale={g2xScale}
400
469
  stroke="#333"
401
470
  tickStroke="#333"
@@ -404,6 +473,7 @@ export default function LinearChart() {
404
473
  {props => {
405
474
  const axisCenter = (props.axisToPoint.x - props.axisFromPoint.x) / 2;
406
475
  return (
476
+ <>
407
477
  <Group className="bottom-axis">
408
478
  {props.ticks.map((tick, i) => {
409
479
  const tickWidth = xMax / props.ticks.length;
@@ -412,28 +482,45 @@ export default function LinearChart() {
412
482
  key={`vx-tick-${tick.value}-${i}`}
413
483
  className={'vx-axis-tick'}
414
484
  >
415
- <Line
416
- from={tick.from}
417
- to={tick.to}
418
- stroke="#333"
419
- />
420
- <Text
421
- transform={`translate(${tick.to.x}, ${tick.to.y}) rotate(-${60})`}
422
- verticalAnchor="start"
423
- textAnchor={'end'}
424
- width={config.runtime.xAxis.tickRotation && config.runtime.xAxis.tickRotation !== '0' ? undefined : tickWidth}
425
- >
426
- {tick.formattedValue}
427
- </Text>
485
+ {!config.runtime.yAxis.hideTicks &&
486
+ <Line
487
+ from={tick.from}
488
+ to={tick.to}
489
+ stroke="#333"
490
+ />
491
+ }
492
+ {!config.runtime.yAxis.hideLabel &&
493
+ <Text
494
+ transform={`translate(${tick.to.x}, ${tick.to.y}) rotate(-${60})`}
495
+ verticalAnchor="start"
496
+ textAnchor={'end'}
497
+ width={config.runtime.xAxis.tickRotation && config.runtime.xAxis.tickRotation !== '0' ? undefined : tickWidth}
498
+ >
499
+ {tick.formattedValue}
500
+ </Text>
501
+ }
428
502
  </Group>
429
503
  );
430
504
  })}
431
- <Line
432
- from={props.axisFromPoint}
433
- to={props.axisToPoint}
434
- stroke="#333"
435
- />
505
+ {!config.runtime.yAxis.hideAxis &&
506
+ <Line
507
+ from={props.axisFromPoint}
508
+ to={props.axisToPoint}
509
+ stroke="#333"
510
+ />
511
+ }
436
512
  </Group>
513
+ <Group>
514
+ <Text
515
+ transform={`translate(${xMax/2}, ${config.height - yMax + 20}) rotate(-${0})`}
516
+ verticalAnchor="start"
517
+ textAnchor={'middle'}
518
+ stroke="#333"
519
+ >
520
+ {config.runtime.xAxis.label}
521
+ </Text>
522
+ </Group>
523
+ </>
437
524
  );
438
525
  }}
439
526
  </AxisBottom>
@@ -445,15 +532,22 @@ export default function LinearChart() {
445
532
 
446
533
  {/* Bar chart */}
447
534
  { (config.visualizationType !== 'Line' && config.visualizationType !== 'Paired Bar') && (
448
- <BarChart xScale={xScale} yScale={yScale} seriesScale={seriesScale} xMax={xMax} yMax={yMax} getXAxisData={getXAxisData} getYAxisData={getYAxisData} />
535
+ <>
536
+ <BarChart xScale={xScale} yScale={yScale} seriesScale={seriesScale} xMax={xMax} yMax={yMax} getXAxisData={getXAxisData} getYAxisData={getYAxisData} animatedChart={animatedChart} visible={animatedChart} />
537
+ </>
538
+
449
539
  )}
450
540
 
451
541
  {/* Line chart */}
452
542
  { (config.visualizationType !== 'Bar' && config.visualizationType !== 'Paired Bar') && (
453
- <LineChart xScale={xScale} yScale={yScale} getXAxisData={getXAxisData} getYAxisData={getYAxisData} />
543
+ <>
544
+ <LineChart xScale={xScale} yScale={yScale} getXAxisData={getXAxisData} getYAxisData={getYAxisData} xMax={xMax} yMax={yMax} seriesStyle={config.series} />
545
+ </>
546
+
454
547
  )}
455
548
  </svg>
456
549
  <ReactTooltip id={`cdc-open-viz-tooltip-${config.runtime.uniqueId}`} html={true} type="light" arrowColor="rgba(0,0,0,0)" className="tooltip"/>
550
+ <div className='animation-trigger' ref={triggerRef} />
457
551
  </ErrorBoundary>
458
552
  )
459
553
  }
@@ -15,7 +15,7 @@ interface PairedBarChartProps {
15
15
 
16
16
  const PairedBarChart: React.FC<PairedBarChartProps> = ({ width, height }) => {
17
17
 
18
- const { config, colorScale, transformedData } = useContext<any>(Context);
18
+ const { config, colorScale, transformedData, formatNumber, seriesHighlight } = useContext<any>(Context);
19
19
 
20
20
  if(!config || config?.series?.length < 2) return;
21
21
 
@@ -49,7 +49,6 @@ const PairedBarChart: React.FC<PairedBarChartProps> = ({ width, height }) => {
49
49
  const yScale = scaleBand({
50
50
  range: [0, adjustedHeight],
51
51
  domain: data.map(d => d[config.dataDescription.xKey]),
52
- padding: 0.2
53
52
  });
54
53
 
55
54
  // Set label color
@@ -63,75 +62,173 @@ const PairedBarChart: React.FC<PairedBarChartProps> = ({ width, height }) => {
63
62
  groupTwo.labelColor = '#FFFFFF';
64
63
  }
65
64
 
65
+ const dataTipOne = (d) => {
66
+ return (
67
+ `<p>
68
+ ${config.dataDescription.seriesKey}: ${groupOne.dataKey}<br/>
69
+ ${config.xAxis.dataKey}: ${d[config.xAxis.dataKey]}<br/>
70
+ ${config.dataDescription.valueKey}: ${formatNumber(d[groupOne.dataKey])}
71
+ </p>`
72
+ )
73
+ }
74
+
75
+ const dataTipTwo = (d) => {
76
+ return (
77
+ `<p>
78
+ ${config.dataDescription.seriesKey}: ${groupTwo.dataKey}<br/>
79
+ ${config.xAxis.dataKey}: ${d[config.xAxis.dataKey]}<br/>
80
+ ${config.dataDescription.valueKey}: ${formatNumber(d[groupTwo.dataKey])}
81
+ </p>`
82
+ )
83
+ }
84
+
85
+ const isLabelBelowBar = config.yAxis.labelPlacement === "Below Bar";
86
+ const isLabelOnYAxis = config.yAxis.labelPlacement === "On Date/Category Axis";
87
+ const isLabelMissing = !config.yAxis.labelPlacement;
88
+
66
89
  return (width > 0) && (
67
90
  <>
91
+ <style>
92
+ {`
93
+ #cdc-visualization__paired-bar-chart,
94
+ #cdc-visualization__paired-bar-chart > .visx-group {
95
+ transform-origin: center
96
+ }
97
+ `}
98
+ </style>
68
99
  <svg
69
100
  id="cdc-visualization__paired-bar-chart"
70
101
  width={width}
71
- height={height}>
72
- <Group top={0} left={config.xAxis.size}>
73
- {data.filter(item => config.series[0].dataKey === groupOne.dataKey).map(d => {
102
+ height={height}
103
+ viewBox={`0 0 ${width} ${height}`}
104
+ role="img"
105
+ tabIndex={0}
106
+ >
107
+ <Group top={0} left={config.xAxis.size} >
108
+ {data.filter(item => config.series[0].dataKey === groupOne.dataKey).map( (d,index) => {
109
+
110
+ let transparentBar = config.legend.behavior === 'highlight' && seriesHighlight.length > 0 && seriesHighlight.indexOf(config.series[0].dataKey) === -1;
111
+ let displayBar = config.legend.behavior === 'highlight' || seriesHighlight.length === 0 || seriesHighlight.indexOf(config.series[0].dataKey) !== -1;
74
112
  let barWidth = (xScale(d[config.series[0].dataKey]))
113
+ let barHeight = Number(config.barHeight) ? Number(config.barHeight) : 25;
114
+ let barPadding = barHeight;
115
+ config.barHeight = Number(config.barHeight) ? Number(config.barHeight) : 25;
116
+ config.barPadding = config.barHeight;
117
+
118
+ if (config.orientation=== "horizontal") {
119
+
120
+ if(isLabelBelowBar || isLabelMissing || isLabelOnYAxis) {
121
+ if(barHeight < 40) {
122
+ config.barPadding = 40;
123
+ } else {
124
+ config.barPadding = barPadding;
125
+ }
126
+ } else {
127
+ config.barPadding = barPadding / 2;
128
+ }
129
+ }
130
+
131
+ config.height = (Number(barHeight) ) * data.length + (config.barPadding * data.length);
132
+
133
+ let y = yScale([d[config.dataDescription.xKey]]) + config.barHeight/1.5;
134
+ y = Number(config.barPadding) > 20 ? y += Number(config.barPadding/3.5) - config.barHeight/2 : y += 0
135
+
75
136
  return (
76
- <Group key={`group-${groupOne.dataKey}-${d[config.xAxis.dataKey]}`}>
137
+ <>
138
+ <Group key={`group-${groupOne.dataKey}-${d[config.xAxis.dataKey]}`} className='horizontal'>
77
139
  <Bar
78
- className="bar"
140
+ id={`bar-${groupOne.dataKey}-${d[config.dataDescription.xKey]}`}
141
+ className='bar group-1'
79
142
  key={`bar-${groupOne.dataKey}-${d[config.dataDescription.xKey]}`}
80
143
  x={halfWidth - barWidth}
81
- y={yScale([d[config.dataDescription.xKey]])}
144
+ y={ y }
82
145
  width={xScale(d[config.series[0].dataKey])}
83
- height={yScale.bandwidth()}
146
+ height={barHeight}
84
147
  fill={groupOne.color}
85
- data-tip={
86
- `<p>
87
- ${config.dataDescription.seriesKey}: ${groupOne.dataKey}<br/>
88
- ${config.xAxis.dataKey}: ${d[config.xAxis.dataKey]}<br/>
89
- ${config.dataDescription.valueKey}: ${d[groupOne.dataKey]}
90
- </p>`
91
- }
148
+ data-tip={ dataTipOne(d) }
92
149
  data-for={`cdc-open-viz-tooltip-${config.runtime.uniqueId}`}
150
+ stroke="#333"
151
+ strokeWidth={config.barBorderThickness || 1}
152
+ opacity={transparentBar ? 0.5 : 1}
153
+ display={displayBar ? 'block' : 'none'}
93
154
  />
94
- <Text
95
- textAnchor={barWidth < 100 ? 'end' : 'start' }
96
- x={halfWidth - (barWidth < 100 ? barWidth + 10 : barWidth - 5)}
97
- y={yScale([d[config.dataDescription.xKey]]) + yScale.bandwidth() / 1.5}
98
- fill={barWidth > 100 ? groupOne.labelColor : '#000' }>
99
- {d[config.dataDescription.xKey]}
100
- </Text>
155
+ {config.yAxis.displayNumbersOnBar && displayBar &&
156
+ <Text
157
+ textAnchor={barWidth < 100 ? 'end' : 'start' }
158
+ verticalAnchor="middle"
159
+ x={halfWidth - (barWidth < 100 ? barWidth + 10 : barWidth - 5)}
160
+ y={ y + config.barHeight/2}
161
+ fill={barWidth > 100 ? groupOne.labelColor : '#000' }>
162
+ {formatNumber(d[groupOne.dataKey])}
163
+ </Text>
164
+ }
101
165
  </Group>
166
+ </>
102
167
  )}
103
168
  )}
104
169
  {data.filter(item => config.series[1].dataKey === groupTwo.dataKey).map(d => {
105
170
  let barWidth = (xScale(d[config.series[1].dataKey]))
171
+ let transparentBar = config.legend.behavior === 'highlight' && seriesHighlight.length > 0 && seriesHighlight.indexOf(config.series[1].dataKey) === -1;
172
+ let displayBar = config.legend.behavior === 'highlight' || seriesHighlight.length === 0 || seriesHighlight.indexOf(config.series[1].dataKey) !== -1;
173
+
174
+ let barHeight = config.barHeight ? config.barHeight : 25;
175
+ let barPadding = barHeight;
176
+ config.barHeight = Number(config.barHeight)
177
+
178
+ let y = yScale([d[config.dataDescription.xKey]]) + config.barHeight/1.5;
179
+ y = Number(config.barPadding) > 20 ? y += Number(config.barPadding/3.5) - config.barHeight/2 : y += 0
180
+
181
+ if (config.orientation=== "horizontal") {
182
+
183
+ if(isLabelBelowBar || isLabelMissing || isLabelOnYAxis) {
184
+ if(barHeight < 40) {
185
+ config.barPadding = 40;
186
+ } else {
187
+ config.barPadding = barPadding;
188
+ }
189
+ } else {
190
+ config.barPadding = barPadding / 2;
191
+ }
192
+ }
106
193
 
107
194
  return(
108
- <Group key={`group-${groupTwo.dataKey}-${d[config.dataDescription.xKey]}`}>
195
+ <>
196
+ <style>
197
+ {`
198
+ .bar-${groupTwo.dataKey}-${d[config.xAxis.dataKey]} {
199
+ transform-origin: ${halfWidth}px ${y}px
200
+ }
201
+ `}
202
+ </style>
203
+ <Group key={`group-${groupTwo.dataKey}-${d[config.dataDescription.xKey]}`} className='horizontal'>
109
204
  <Bar
110
- className="bar"
205
+ id={`bar-${groupTwo.dataKey}-${d[config.dataDescription.xKey]}`}
206
+ className="bar group-2"
111
207
  key={`bar-${groupTwo.dataKey}-${d[config.dataDescription.xKey]}`}
112
208
  x={halfWidth}
113
- y={yScale([d[config.dataDescription.xKey]])}
209
+ y={ y }
114
210
  width={xScale(d[config.series[1].dataKey])}
115
- height={yScale.bandwidth()}
211
+ height={barHeight}
116
212
  fill={groupTwo.color}
117
- data-tip={
118
- `<p>
119
- ${config.dataDescription.seriesKey}: ${groupTwo.dataKey}<br/>
120
- ${config.xAxis.dataKey}: ${d[config.xAxis.dataKey]}<br/>
121
- ${config.dataDescription.valueKey}: ${d[groupTwo.dataKey]}
122
- </p>`
123
- }
213
+ data-tip={ dataTipTwo(d) }
124
214
  data-for={`cdc-open-viz-tooltip-${config.runtime.uniqueId}`}
125
-
215
+ strokeWidth={config.barBorderThickness || 1}
216
+ stroke="#333"
217
+ opacity={transparentBar ? 0.5 : 1}
218
+ display={displayBar ? 'block' : 'none'}
126
219
  />
127
- <Text
128
- textAnchor={barWidth < 100 ? 'start' : 'end' }
129
- x={halfWidth + (barWidth < 100 ? barWidth + 10 : barWidth - 10 )}
130
- y={yScale([d[config.dataDescription.xKey]]) + (yScale.bandwidth() / 1.5)}
131
- fill={barWidth > 100 ? groupTwo.labelColor : '#000' }>
132
- {d[config.dataDescription.xKey]}
133
- </Text>
220
+ {config.yAxis.displayNumbersOnBar && displayBar &&
221
+ <Text
222
+ textAnchor={barWidth < 100 ? 'start' : 'end' }
223
+ verticalAnchor="middle"
224
+ x={halfWidth + (barWidth < 100 ? barWidth + 10 : barWidth - 10 )}
225
+ y={ y + config.barHeight/2}
226
+ fill={barWidth > 100 ? groupTwo.labelColor : '#000' }>
227
+ {formatNumber(d[groupTwo.dataKey])}
228
+ </Text>
229
+ }
134
230
  </Group>
231
+ </>
135
232
  )
136
233
  }
137
234
  )}