@cdc/chart 1.3.4 → 9.22.9

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 (41) 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/gallery/bar-chart-horizontal/horizontal-bar-chart-with-numbers-on-bar.json +198 -0
  5. package/examples/gallery/bar-chart-horizontal/horizontal-bar-chart.json +241 -0
  6. package/examples/gallery/bar-chart-horizontal/horizontal-stacked.json +248 -0
  7. package/examples/gallery/bar-chart-vertical/combo-line-chart.json +137 -0
  8. package/examples/gallery/bar-chart-vertical/vertical-bar-chart-categorical.json +80 -0
  9. package/examples/gallery/bar-chart-vertical/vertical-bar-chart-stacked.json +81 -0
  10. package/examples/gallery/bar-chart-vertical/vertical-bar-chart-with-confidence.json +68 -0
  11. package/examples/gallery/bar-chart-vertical/vertical-bar-chart.json +111 -0
  12. package/examples/gallery/lollipop/lollipop-style-horizontal.json +220 -0
  13. package/examples/gallery/paired-bar/paired-bar-chart.json +196 -0
  14. package/examples/horizontal-chart.json +3 -0
  15. package/examples/paired-bar-data.json +1 -1
  16. package/examples/paired-bar-example.json +2 -0
  17. package/examples/planet-combo-example-config.json +2 -0
  18. package/examples/planet-example-config.json +2 -2
  19. package/examples/planet-example-data.json +1 -1
  20. package/examples/planet-pie-example-config.json +2 -0
  21. package/examples/private/line-test-data.json +22 -0
  22. package/examples/private/line-test-two.json +216 -0
  23. package/examples/private/line-test.json +102 -0
  24. package/examples/stacked-vertical-bar-example.json +228 -0
  25. package/package.json +3 -3
  26. package/src/CdcChart.tsx +79 -47
  27. package/src/components/BarChart.tsx +82 -39
  28. package/src/components/DataTable.tsx +17 -10
  29. package/src/components/EditorPanel.js +233 -169
  30. package/src/components/LineChart.tsx +3 -0
  31. package/src/components/LinearChart.tsx +171 -77
  32. package/src/components/PairedBarChart.tsx +139 -42
  33. package/src/components/PieChart.tsx +31 -6
  34. package/src/components/SparkLine.js +4 -1
  35. package/src/components/useIntersectionObserver.tsx +32 -0
  36. package/src/data/initial-state.js +17 -7
  37. package/src/hooks/useReduceData.ts +50 -23
  38. package/src/index.html +5 -9
  39. package/src/scss/editor-panel.scss +34 -4
  40. package/src/scss/main.scss +165 -5
  41. package/src/components/BarStackVertical.js +0 -0
@@ -66,6 +66,9 @@ export default function LineChart({ xScale, yScale, getXAxisData, getYAxisData }
66
66
  strokeWidth={2}
67
67
  strokeOpacity={1}
68
68
  shapeRendering="geometricPrecision"
69
+ defined={(item,i) => {
70
+ return item[config.runtime.seriesLabels[seriesKey]] !== "";
71
+ }}
69
72
  />
70
73
  </Group>
71
74
  ))
@@ -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
 
21
22
  export default function LinearChart() {
22
- const { transformedData: data, dimensions, config, parseDate, formatDate, currentViewport,formatNumber } = useContext<any>(Context);
23
+ const { transformedData: data, dimensions, config, parseDate, formatDate, currentViewport, formatNumber, handleChartAriaLabels } = useContext<any>(Context);
23
24
  let [ width ] = dimensions;
24
- const {minValue,maxValue} = useReduceData(config,data)
25
+ const {minValue,maxValue,existPositiveValue} = useReduceData(config,data)
26
+ const [animatedChart, setAnimatedChart] = useState<boolean>((!config.animate));
27
+ const [animatedChartPlayed, setAnimatedChartPlayed] = useState<boolean>(false);
28
+
29
+ const triggerRef = useRef();
30
+ const dataRef = useIntersectionObserver(triggerRef, {
31
+ freezeOnceVisible: false
32
+ });
33
+
34
+ // If the chart is in view and set to animate and it has not already played
35
+ if( dataRef?.isIntersecting && config.animate && ! animatedChartPlayed ) {
36
+ setTimeout(() => {
37
+ setAnimatedChart(true);
38
+ }, 500);
39
+
40
+ setTimeout(() => {
41
+ setAnimatedChartPlayed(!animatedChartPlayed);
42
+ }, 600);
43
+ }
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,23 @@ export default function LinearChart() {
38
58
  let yScale;
39
59
  let seriesScale;
40
60
 
61
+ // desctructure users enetered value from initial state config.
62
+ const {max:enteredMaxValue,min:enteredMinValue} = config.runtime.yAxis;
63
+ // validation for for min/max that user entered;
64
+ const isMaxValid = existPositiveValue ? numberFromString(enteredMaxValue) >= numberFromString(maxValue) : numberFromString(enteredMaxValue) >= 0;
65
+ const isMinValid = ((numberFromString(enteredMinValue) <= 0 && numberFromString(minValue) >=0) || (numberFromString(enteredMinValue) <= minValue && minValue < 0));
66
+
41
67
  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;
68
+ let min = enteredMinValue && isMinValid ? enteredMinValue : minValue;
69
+ let max = enteredMaxValue && isMaxValid ? enteredMaxValue : Number.MIN_VALUE;
44
70
 
45
71
  if((config.visualizationType === 'Bar' || config.visualizationType === 'Combo') && min > 0) {
46
72
  min = 0;
47
73
  }
48
74
  //If data value max wasn't provided, calculate it
49
75
  if(max === Number.MIN_VALUE){
50
- max = maxValue
76
+ // if all values in data are negative set max = 0
77
+ max = existPositiveValue ? maxValue : 0;
51
78
  }
52
79
 
53
80
  //Adds Y Axis data padding if applicable
@@ -59,41 +86,65 @@ export default function LinearChart() {
59
86
 
60
87
  let xAxisDataMapped = data.map(d => getXAxisData(d));
61
88
 
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
- });
89
+ if (config.isLollipopChart && config.yAxis.displayNumbersOnBar) {
90
+ const dataKey = data.map((item) => item[config.series[0].dataKey]);
91
+ const maxDataVal = Math.max(...dataKey).toString().length;
92
+
93
+ switch (true) {
94
+ case maxDataVal > 8 && maxDataVal <= 12:
95
+ max = max * 1.3;
96
+ break;
97
+ case maxDataVal > 4 && maxDataVal <= 7:
98
+ max = max * 1.1;
99
+ break;
100
+ }
92
101
  }
93
102
 
103
+ if (config.runtime.horizontal) {
104
+ xScale = scaleLinear<number>({
105
+ domain: [min, max],
106
+ range: [0, xMax],
107
+ });
108
+
109
+ yScale =
110
+ config.runtime.xAxis.type === "date"
111
+ ? scaleLinear<number>({
112
+ domain: [
113
+ Math.min(...xAxisDataMapped),
114
+ Math.max(...xAxisDataMapped),
115
+ ],
116
+ })
117
+ : scalePoint<string>({ domain: xAxisDataMapped, padding: 0.5 });
118
+
119
+ seriesScale = scalePoint<string>({
120
+ domain: config.runtime.barSeriesKeys || config.runtime.seriesKeys,
121
+ range: [0, yMax],
122
+ });
123
+
124
+ yScale.rangeRound([0, yMax]);
125
+ } else {
126
+ min = min < 0 ? min * 1.11 : min;
127
+
128
+ yScale = scaleLinear<number>({
129
+ domain: [min, max],
130
+ range: [yMax, 0],
131
+ });
132
+
133
+ xScale = scalePoint<string>({
134
+ domain: xAxisDataMapped,
135
+ range: [0, xMax],
136
+ padding: 0.5,
137
+ });
138
+
139
+ seriesScale = scalePoint<string>({
140
+ domain: config.runtime.barSeriesKeys || config.runtime.seriesKeys,
141
+ range: [0, xMax],
142
+ });
143
+ }
144
+
94
145
 
95
146
  if(config.visualizationType === 'Paired Bar') {
96
-
147
+
97
148
 
98
149
  let groupOneMax = Math.max.apply(Math, data.map(d => d[config.series[0].dataKey]))
99
150
  let groupTwoMax = Math.max.apply(Math, data.map(d => d[config.series[1].dataKey]))
@@ -103,7 +154,7 @@ export default function LinearChart() {
103
154
  domain: [0, Math.max(groupOneMax,groupTwoMax) ],
104
155
  range: [xMax/2, 0]
105
156
  })
106
-
157
+
107
158
  // group 2
108
159
  var g2xScale = scaleLinear<number>({
109
160
  domain: g1xScale.domain(),
@@ -119,10 +170,18 @@ export default function LinearChart() {
119
170
  ReactTooltip.rebuild();
120
171
  });
121
172
 
122
-
123
- return (
173
+ return isNaN(width) ? <></> : (
124
174
  <ErrorBoundary component="LinearChart">
125
- <svg width={width} height={height} className="linear">
175
+ <svg
176
+ width={width}
177
+ height={height}
178
+ // If the chart is set to not replay the filter and has already animated, don't add the animated class
179
+ // className={`linear ${(config.animate) || (config.animateReplay && animatedChartPlayed) ? 'animated' : ''} ${animatedChart ? 'animate' : ''}`}
180
+ className={`linear ${(config.animate) ? 'animated' : ''} ${animatedChart ? '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} />
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 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
  )}