@cdc/chart 4.24.12 → 4.25.1
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/cdcchart.js +79611 -78971
- package/examples/feature/boxplot/boxplot.json +2 -157
- package/examples/feature/boxplot/testing.csv +23 -38
- package/examples/feature/tests-non-numerics/example-combo-bar-nonnumeric.json +394 -30
- package/examples/private/ehdi.json +29939 -0
- package/examples/private/not-loading.json +360 -0
- package/index.html +7 -14
- package/package.json +2 -2
- package/src/CdcChart.tsx +92 -1512
- package/src/CdcChartComponent.tsx +1105 -0
- package/src/_stories/Chart.Anchors.stories.tsx +1 -1
- package/src/_stories/Chart.CustomColors.stories.tsx +1 -1
- package/src/_stories/Chart.DynamicSeries.stories.tsx +1 -1
- package/src/_stories/Chart.Legend.Gradient.stories.tsx +2 -2
- package/src/_stories/Chart.ScatterPlot.stories.tsx +19 -0
- package/src/_stories/Chart.tooltip.stories.tsx +1 -2
- package/src/_stories/ChartAnnotation.stories.tsx +1 -1
- package/src/_stories/ChartAxisLabels.stories.tsx +1 -1
- package/src/_stories/ChartAxisTitles.stories.tsx +1 -1
- package/src/_stories/ChartEditor.stories.tsx +1 -1
- package/src/_stories/ChartLine.Suppression.stories.tsx +1 -1
- package/src/_stories/ChartLine.Symbols.stories.tsx +18 -0
- package/src/_stories/ChartPrefixSuffix.stories.tsx +1 -1
- package/src/_stories/_mock/line_chart_symbols.json +437 -0
- package/src/_stories/_mock/scatterplot-image-download.json +1244 -0
- package/src/components/Annotations/components/AnnotationDraggable.tsx +3 -11
- package/src/components/Annotations/components/AnnotationDropdown.tsx +3 -3
- package/src/components/Axis/Categorical.Axis.tsx +3 -4
- package/src/components/BarChart/components/BarChart.Horizontal.tsx +14 -5
- package/src/components/BarChart/components/BarChart.StackedHorizontal.tsx +10 -4
- package/src/components/BarChart/components/BarChart.Vertical.tsx +2 -2
- package/src/components/BoxPlot/BoxPlot.tsx +34 -32
- package/src/components/BoxPlot/helpers/index.ts +108 -18
- package/src/components/DeviationBar.jsx +2 -6
- package/src/components/EditorPanel/EditorPanel.tsx +62 -6
- package/src/components/EditorPanel/components/Panels/Panel.General.tsx +4 -0
- package/src/components/EditorPanel/components/Panels/Panel.Visual.tsx +44 -7
- package/src/components/ForestPlot/ForestPlot.tsx +176 -26
- package/src/components/Legend/Legend.Component.tsx +29 -38
- package/src/components/Legend/Legend.Suppression.tsx +3 -5
- package/src/components/Legend/Legend.tsx +2 -2
- package/src/components/Legend/LegendLine.Shape.tsx +51 -0
- package/src/components/Legend/helpers/createFormatLabels.tsx +29 -26
- package/src/components/Legend/helpers/getLegendClasses.ts +20 -38
- package/src/components/Legend/helpers/index.ts +14 -7
- package/src/components/Legend/tests/getLegendClasses.test.ts +3 -20
- package/src/components/LineChart/components/LineChart.Circle.tsx +90 -88
- package/src/components/LineChart/index.tsx +4 -0
- package/src/components/LinearChart.tsx +65 -31
- package/src/components/PairedBarChart.jsx +2 -9
- package/src/components/ZoomBrush.tsx +5 -7
- package/src/data/initial-state.js +6 -3
- package/src/helpers/getBoxPlotConfig.ts +68 -0
- package/src/helpers/getColorScale.ts +28 -0
- package/src/helpers/getComboChartConfig.ts +42 -0
- package/src/helpers/getExcludedData.ts +37 -0
- package/src/helpers/getTopAxis.ts +7 -0
- package/src/hooks/useBarChart.ts +28 -9
- package/src/hooks/{useHighlightedBars.js → useHighlightedBars.ts} +2 -1
- package/src/hooks/useIntersectionObserver.ts +37 -0
- package/src/hooks/useMinMax.ts +4 -0
- package/src/hooks/useReduceData.ts +1 -1
- package/src/hooks/useTooltip.tsx +9 -1
- package/src/index.jsx +1 -0
- package/src/scss/DataTable.scss +0 -5
- package/src/scss/main.scss +30 -115
- package/src/types/ChartConfig.ts +6 -3
- package/src/types/ChartContext.ts +1 -3
- package/src/helpers/getQuartiles.ts +0 -27
- package/src/hooks/useColorScale.ts +0 -50
- package/src/hooks/useIntersectionObserver.jsx +0 -29
- package/src/hooks/useTopAxis.js +0 -6
|
@@ -27,7 +27,7 @@ import CategoricalYAxis from './Axis/Categorical.Axis'
|
|
|
27
27
|
|
|
28
28
|
// Helpers
|
|
29
29
|
import { isConvertLineToBarGraph } from '../helpers/isConvertLineToBarGraph'
|
|
30
|
-
import { isLegendWrapViewport } from '@cdc/core/helpers/viewports'
|
|
30
|
+
import { isLegendWrapViewport, isMobileHeightViewport } from '@cdc/core/helpers/viewports'
|
|
31
31
|
import { getTextWidth } from '@cdc/core/helpers/getTextWidth'
|
|
32
32
|
import { calcInitialHeight } from '../helpers/sizeHelpers'
|
|
33
33
|
|
|
@@ -36,13 +36,13 @@ import useMinMax from '../hooks/useMinMax'
|
|
|
36
36
|
import useReduceData from '../hooks/useReduceData'
|
|
37
37
|
import useRightAxis from '../hooks/useRightAxis'
|
|
38
38
|
import useScales, { getTickValues, filterAndShiftLinearDateTicks } from '../hooks/useScales'
|
|
39
|
-
import
|
|
39
|
+
import getTopAxis from '../helpers/getTopAxis'
|
|
40
40
|
import { useTooltip as useCoveTooltip } from '../hooks/useTooltip'
|
|
41
41
|
import { useEditorPermissions } from './EditorPanel/useEditorPermissions'
|
|
42
42
|
import Annotation from './Annotations'
|
|
43
43
|
import { BlurStrokeText } from '@cdc/core/components/BlurStrokeText'
|
|
44
|
-
import { fontSizes } from '@cdc/core/helpers/cove/fontSettings'
|
|
45
44
|
import { countNumOfTicks } from '../helpers/countNumOfTicks'
|
|
45
|
+
import _ from 'lodash'
|
|
46
46
|
|
|
47
47
|
type LinearChartProps = {
|
|
48
48
|
parentWidth: number
|
|
@@ -50,9 +50,14 @@ type LinearChartProps = {
|
|
|
50
50
|
}
|
|
51
51
|
|
|
52
52
|
const BOTTOM_LABEL_PADDING = 9
|
|
53
|
-
const X_TICK_LABEL_PADDING =
|
|
53
|
+
const X_TICK_LABEL_PADDING = 4.5
|
|
54
54
|
const DEFAULT_TICK_LENGTH = 8
|
|
55
55
|
const MONTH_AS_MS = 1000 * 60 * 60 * 24 * 30
|
|
56
|
+
const TICK_LABEL_FONT_SIZE = 16
|
|
57
|
+
const TICK_LABEL_FONT_SIZE_SMALL = 13
|
|
58
|
+
const AXIS_LABEL_FONT_SIZE = 18
|
|
59
|
+
const AXIS_LABEL_FONT_SIZE_SMALL = 14
|
|
60
|
+
const TICK_LABEL_MARGIN_RIGHT = 4.5
|
|
56
61
|
|
|
57
62
|
const LinearChart = forwardRef<SVGAElement, LinearChartProps>(({ parentHeight, parentWidth }, svgRef) => {
|
|
58
63
|
// prettier-ignore
|
|
@@ -99,7 +104,7 @@ const LinearChart = forwardRef<SVGAElement, LinearChartProps>(({ parentHeight, p
|
|
|
99
104
|
// HOOKS % STATES
|
|
100
105
|
const { minValue, maxValue, existPositiveValue, isAllLine } = useReduceData(config, data)
|
|
101
106
|
const { visSupportsReactTooltip } = useEditorPermissions()
|
|
102
|
-
const { hasTopAxis } =
|
|
107
|
+
const { hasTopAxis } = getTopAxis(config)
|
|
103
108
|
const [animatedChart, setAnimatedChart] = useState(false)
|
|
104
109
|
const [point, setPoint] = useState({ x: 0, y: 0 })
|
|
105
110
|
const [suffixWidth, setSuffixWidth] = useState(0)
|
|
@@ -129,6 +134,9 @@ const LinearChart = forwardRef<SVGAElement, LinearChartProps>(({ parentHeight, p
|
|
|
129
134
|
const labelsOverflow = onlyShowTopPrefixSuffix && !suffixHasNoSpace
|
|
130
135
|
const padding = orientation === 'horizontal' ? Number(config.xAxis.size) : Number(config.yAxis.size)
|
|
131
136
|
const yLabelOffset = isNaN(parseInt(`${runtime.yAxis.labelOffset}`)) ? 0 : parseInt(`${runtime.yAxis.labelOffset}`)
|
|
137
|
+
const tickLabelFontSize = isMobileHeightViewport(currentViewport) ? TICK_LABEL_FONT_SIZE_SMALL : TICK_LABEL_FONT_SIZE
|
|
138
|
+
const axisLabelFontSize = isMobileHeightViewport(currentViewport) ? AXIS_LABEL_FONT_SIZE_SMALL : AXIS_LABEL_FONT_SIZE
|
|
139
|
+
const GET_TEXT_WIDTH_FONT = `normal ${tickLabelFontSize}px Nunito, sans-serif`
|
|
132
140
|
|
|
133
141
|
// zero if not forest plot
|
|
134
142
|
const forestRowsHeight = isForestPlot ? config.data.length * config.forestPlot.rowHeight : 0
|
|
@@ -410,21 +418,37 @@ const LinearChart = forwardRef<SVGAElement, LinearChartProps>(({ parentHeight, p
|
|
|
410
418
|
useEffect(() => {
|
|
411
419
|
if (lastMaxValue.current === maxValue) return
|
|
412
420
|
lastMaxValue.current = maxValue
|
|
421
|
+
|
|
413
422
|
if (!yAxisAutoPadding) return
|
|
414
423
|
setYAxisAutoPadding(0)
|
|
415
424
|
}, [maxValue])
|
|
425
|
+
|
|
416
426
|
useEffect(() => {
|
|
417
427
|
if (orientation === 'horizontal') return
|
|
428
|
+
if (!labelsOverflow) return
|
|
429
|
+
|
|
430
|
+
// minimum percentage of the max value that the distance should be from the top grid line
|
|
431
|
+
const MINIMUM_DISTANCE_PERCENTAGE = 0.025
|
|
418
432
|
|
|
419
|
-
const
|
|
433
|
+
const topGridLine = Math.max(...yScale.ticks(handleNumTicks))
|
|
434
|
+
const needsPaddingThreshold = topGridLine - maxValue * MINIMUM_DISTANCE_PERCENTAGE
|
|
435
|
+
const maxValueIsGreaterThanThreshold = maxValue > needsPaddingThreshold
|
|
420
436
|
|
|
421
|
-
if (!
|
|
437
|
+
if (!maxValueIsGreaterThanThreshold) return
|
|
422
438
|
|
|
423
|
-
const
|
|
439
|
+
const ticks = yScale.ticks(handleNumTicks)
|
|
440
|
+
const tickGap = ticks.length === 1 ? ticks[0] : ticks[1] - ticks[0]
|
|
424
441
|
const nextTick = Math.max(...yScale.ticks(handleNumTicks)) + tickGap
|
|
425
|
-
const
|
|
442
|
+
const divideBy = minValue < 0 ? maxValue / 2 : maxValue
|
|
443
|
+
const calculatedPadding = (nextTick - maxValue) / divideBy
|
|
426
444
|
|
|
427
|
-
|
|
445
|
+
// if auto padding is too close to next tick, add one more ticks worth of padding
|
|
446
|
+
const newPadding =
|
|
447
|
+
calculatedPadding > MINIMUM_DISTANCE_PERCENTAGE ? calculatedPadding : calculatedPadding + tickGap / divideBy
|
|
448
|
+
|
|
449
|
+
/* sometimes even though the padding is getting to the next tick exactly,
|
|
450
|
+
d3 still doesn't show the tick. we add 0.1 to ensure to tip it over the edge */
|
|
451
|
+
setYAxisAutoPadding(newPadding * 100 + 0.1)
|
|
428
452
|
}, [maxValue, labelsOverflow, yScale, handleNumTicks])
|
|
429
453
|
|
|
430
454
|
// Render Functions
|
|
@@ -433,12 +457,12 @@ const LinearChart = forwardRef<SVGAElement, LinearChartProps>(({ parentHeight, p
|
|
|
433
457
|
|
|
434
458
|
const getTickPositions = (ticks, xScale) => {
|
|
435
459
|
if (!ticks.length) return false
|
|
436
|
-
//
|
|
460
|
+
// filter out first index
|
|
437
461
|
const filteredTicks = ticks.filter(tick => tick.index !== 0)
|
|
438
462
|
const numberOfTicks = filteredTicks?.length
|
|
439
463
|
const xMaxHalf = xScale.range()[0] || xMax / 2
|
|
440
464
|
const tickWidthAll = filteredTicks.map(tick =>
|
|
441
|
-
getTextWidth(formatNumber(tick.value, 'left'),
|
|
465
|
+
getTextWidth(formatNumber(tick.value, 'left'), GET_TEXT_WIDTH_FONT)
|
|
442
466
|
)
|
|
443
467
|
const accumulator = 100
|
|
444
468
|
const sumOfTickWidth = tickWidthAll.reduce((a, b) => a + b, accumulator)
|
|
@@ -475,10 +499,6 @@ const LinearChart = forwardRef<SVGAElement, LinearChartProps>(({ parentHeight, p
|
|
|
475
499
|
return (
|
|
476
500
|
<Group className='bottom-axis'>
|
|
477
501
|
{props.ticks.map((tick, i) => {
|
|
478
|
-
const textWidth = getTextWidth(
|
|
479
|
-
formatNumber(tick.value, 'left'),
|
|
480
|
-
`normal ${fontSizes[config.fontSize]}px sans-serif`
|
|
481
|
-
)
|
|
482
502
|
const isTicksOverlapping = getTickPositions(props.ticks, g1xScale)
|
|
483
503
|
const maxTickRotation = Number(config.xAxis.maxTickRotation) || 90
|
|
484
504
|
const isResponsiveTicks = config.isResponsiveTicks && isTicksOverlapping
|
|
@@ -497,6 +517,7 @@ const LinearChart = forwardRef<SVGAElement, LinearChartProps>(({ parentHeight, p
|
|
|
497
517
|
angle={-angle}
|
|
498
518
|
verticalAnchor={angle ? 'middle' : 'start'}
|
|
499
519
|
textAnchor={textAnchor}
|
|
520
|
+
fontSize={tickLabelFontSize}
|
|
500
521
|
>
|
|
501
522
|
{formatNumber(tick.value, 'left')}
|
|
502
523
|
</Text>
|
|
@@ -527,10 +548,6 @@ const LinearChart = forwardRef<SVGAElement, LinearChartProps>(({ parentHeight, p
|
|
|
527
548
|
<>
|
|
528
549
|
<Group className='bottom-axis'>
|
|
529
550
|
{props.ticks.map((tick, i) => {
|
|
530
|
-
const textWidth = getTextWidth(
|
|
531
|
-
formatNumber(tick.value, 'left'),
|
|
532
|
-
`normal ${fontSizes[config.fontSize]}px sans-serif`
|
|
533
|
-
)
|
|
534
551
|
const isTicksOverlapping = getTickPositions(props.ticks, g2xScale)
|
|
535
552
|
const maxTickRotation = Number(config.xAxis.maxTickRotation) || 90
|
|
536
553
|
const isResponsiveTicks = config.isResponsiveTicks && isTicksOverlapping
|
|
@@ -548,6 +565,7 @@ const LinearChart = forwardRef<SVGAElement, LinearChartProps>(({ parentHeight, p
|
|
|
548
565
|
angle={-angle}
|
|
549
566
|
verticalAnchor={angle ? 'middle' : 'start'}
|
|
550
567
|
textAnchor={textAnchor}
|
|
568
|
+
fontSize={tickLabelFontSize}
|
|
551
569
|
>
|
|
552
570
|
{formatNumber(tick.value, 'left')}
|
|
553
571
|
</Text>
|
|
@@ -565,6 +583,7 @@ const LinearChart = forwardRef<SVGAElement, LinearChartProps>(({ parentHeight, p
|
|
|
565
583
|
stroke='#333'
|
|
566
584
|
textAnchor={'middle'}
|
|
567
585
|
verticalAnchor='start'
|
|
586
|
+
fontSize={axisLabelFontSize}
|
|
568
587
|
>
|
|
569
588
|
{runtime.xAxis.label}
|
|
570
589
|
</Text>
|
|
@@ -641,6 +660,7 @@ const LinearChart = forwardRef<SVGAElement, LinearChartProps>(({ parentHeight, p
|
|
|
641
660
|
transform={`translate(${-1 * runtime.yAxis.size + yLabelOffset}, ${axisCenter}) rotate(-90)`}
|
|
642
661
|
fontWeight='bold'
|
|
643
662
|
fill={config.yAxis.labelColor}
|
|
663
|
+
fontSize={axisLabelFontSize}
|
|
644
664
|
>
|
|
645
665
|
{props.label}
|
|
646
666
|
</Text>
|
|
@@ -1034,7 +1054,7 @@ const LinearChart = forwardRef<SVGAElement, LinearChartProps>(({ parentHeight, p
|
|
|
1034
1054
|
const lastTick = props.ticks.length - 1 === i
|
|
1035
1055
|
const hideTopTick = lastTick && onlyShowTopPrefixSuffix && suffix && !suffixHasNoSpace
|
|
1036
1056
|
const valueOnLinePadding = hideAxis ? -8 : -12
|
|
1037
|
-
const labelXPadding = labelsAboveGridlines ? valueOnLinePadding :
|
|
1057
|
+
const labelXPadding = labelsAboveGridlines ? valueOnLinePadding : TICK_LABEL_MARGIN_RIGHT
|
|
1038
1058
|
const labelYPadding = labelsAboveGridlines ? 4 : 0
|
|
1039
1059
|
const labelX = tick.to.x - labelXPadding
|
|
1040
1060
|
const labelY = tick.to.y - labelYPadding
|
|
@@ -1051,6 +1071,7 @@ const LinearChart = forwardRef<SVGAElement, LinearChartProps>(({ parentHeight, p
|
|
|
1051
1071
|
to={isLogarithmicAxis ? to : tick.to}
|
|
1052
1072
|
stroke={config.yAxis.tickColor}
|
|
1053
1073
|
display={orientation === 'horizontal' ? 'none' : 'block'}
|
|
1074
|
+
fontSize={tickLabelFontSize}
|
|
1054
1075
|
/>
|
|
1055
1076
|
)}
|
|
1056
1077
|
|
|
@@ -1068,6 +1089,7 @@ const LinearChart = forwardRef<SVGAElement, LinearChartProps>(({ parentHeight, p
|
|
|
1068
1089
|
}) rotate(-${config.runtime.horizontal ? config.runtime.yAxis.tickRotation || 0 : 0})`}
|
|
1069
1090
|
verticalAnchor={'start'}
|
|
1070
1091
|
textAnchor={'end'}
|
|
1092
|
+
fontSize={tickLabelFontSize}
|
|
1071
1093
|
>
|
|
1072
1094
|
{tick.formattedValue}
|
|
1073
1095
|
</Text>
|
|
@@ -1083,6 +1105,7 @@ const LinearChart = forwardRef<SVGAElement, LinearChartProps>(({ parentHeight, p
|
|
|
1083
1105
|
}) rotate(-${runtime.horizontal ? runtime.yAxis.tickRotation : 0})`}
|
|
1084
1106
|
verticalAnchor={'start'}
|
|
1085
1107
|
textAnchor={'end'}
|
|
1108
|
+
fontSize={tickLabelFontSize}
|
|
1086
1109
|
>
|
|
1087
1110
|
{tick.formattedValue}
|
|
1088
1111
|
</Text>
|
|
@@ -1097,6 +1120,7 @@ const LinearChart = forwardRef<SVGAElement, LinearChartProps>(({ parentHeight, p
|
|
|
1097
1120
|
}) rotate(-${runtime.horizontal ? runtime.yAxis.tickRotation : 0})`}
|
|
1098
1121
|
textAnchor={'end'}
|
|
1099
1122
|
verticalAnchor='middle'
|
|
1123
|
+
fontSize={tickLabelFontSize}
|
|
1100
1124
|
>
|
|
1101
1125
|
{tick.formattedValue}
|
|
1102
1126
|
</Text>
|
|
@@ -1112,6 +1136,7 @@ const LinearChart = forwardRef<SVGAElement, LinearChartProps>(({ parentHeight, p
|
|
|
1112
1136
|
}) rotate(-${runtime.horizontal ? runtime.yAxis.tickRotation : 0})`}
|
|
1113
1137
|
textAnchor={'end'}
|
|
1114
1138
|
verticalAnchor='middle'
|
|
1139
|
+
fontSize={tickLabelFontSize}
|
|
1115
1140
|
>
|
|
1116
1141
|
{tick.formattedValue}
|
|
1117
1142
|
</Text>
|
|
@@ -1130,6 +1155,7 @@ const LinearChart = forwardRef<SVGAElement, LinearChartProps>(({ parentHeight, p
|
|
|
1130
1155
|
verticalAnchor={config.runtime.horizontal ? 'start' : 'middle'}
|
|
1131
1156
|
textAnchor={config.runtime.horizontal ? 'start' : 'end'}
|
|
1132
1157
|
fill={config.yAxis.tickLabelColor}
|
|
1158
|
+
fontSize={tickLabelFontSize}
|
|
1133
1159
|
>
|
|
1134
1160
|
{config.runtime.seriesLabelsAll[tick.formattedValue - 1]}
|
|
1135
1161
|
</Text>
|
|
@@ -1172,6 +1198,7 @@ const LinearChart = forwardRef<SVGAElement, LinearChartProps>(({ parentHeight, p
|
|
|
1172
1198
|
paintOrder={'stroke'} // keeps stroke under fill
|
|
1173
1199
|
strokeLinejoin='round'
|
|
1174
1200
|
style={{ whiteSpace: 'pre-wrap' }} // prevents leading spaces from being trimmed
|
|
1201
|
+
fontSize={tickLabelFontSize}
|
|
1175
1202
|
>
|
|
1176
1203
|
{suffix}
|
|
1177
1204
|
</BlurStrokeText>
|
|
@@ -1193,6 +1220,7 @@ const LinearChart = forwardRef<SVGAElement, LinearChartProps>(({ parentHeight, p
|
|
|
1193
1220
|
strokeLinejoin='round'
|
|
1194
1221
|
paintOrder={'stroke'} // keeps stroke under fill
|
|
1195
1222
|
style={{ whiteSpace: 'pre-wrap' }} // prevents leading spaces from being trimmed
|
|
1223
|
+
fontSize={tickLabelFontSize}
|
|
1196
1224
|
>
|
|
1197
1225
|
{`${tick.formattedValue}${combineDomSuffixWithValue ? suffix : ''}`}
|
|
1198
1226
|
</BlurStrokeText>
|
|
@@ -1208,6 +1236,7 @@ const LinearChart = forwardRef<SVGAElement, LinearChartProps>(({ parentHeight, p
|
|
|
1208
1236
|
transform={`translate(${-1 * runtime.yAxis.size + yLabelOffset}, ${axisCenter}) rotate(-90)`}
|
|
1209
1237
|
fontWeight='bold'
|
|
1210
1238
|
fill={config.yAxis.labelColor}
|
|
1239
|
+
fontSize={axisLabelFontSize}
|
|
1211
1240
|
>
|
|
1212
1241
|
{props.label}
|
|
1213
1242
|
</Text>
|
|
@@ -1270,6 +1299,7 @@ const LinearChart = forwardRef<SVGAElement, LinearChartProps>(({ parentHeight, p
|
|
|
1270
1299
|
verticalAnchor={runtime.horizontal ? 'start' : 'middle'}
|
|
1271
1300
|
textAnchor={'start'}
|
|
1272
1301
|
fill={config.yAxis.rightAxisTickLabelColor}
|
|
1302
|
+
fontSize={tickLabelFontSize}
|
|
1273
1303
|
>
|
|
1274
1304
|
{tick.formattedValue}
|
|
1275
1305
|
</Text>
|
|
@@ -1289,6 +1319,7 @@ const LinearChart = forwardRef<SVGAElement, LinearChartProps>(({ parentHeight, p
|
|
|
1289
1319
|
}, ${axisCenter}) rotate(-90)`}
|
|
1290
1320
|
fontWeight='bold'
|
|
1291
1321
|
fill={config.yAxis.rightAxisLabelColor}
|
|
1322
|
+
fontSize={axisLabelFontSize}
|
|
1292
1323
|
>
|
|
1293
1324
|
{props.label}
|
|
1294
1325
|
</Text>
|
|
@@ -1328,17 +1359,18 @@ const LinearChart = forwardRef<SVGAElement, LinearChartProps>(({ parentHeight, p
|
|
|
1328
1359
|
numTicks={useDateSpanMonths ? dateSpanMonths : xTickCount}
|
|
1329
1360
|
tickStroke='#333'
|
|
1330
1361
|
tickValues={
|
|
1331
|
-
config.xAxis.manual
|
|
1362
|
+
config.runtime.xAxis.manual
|
|
1332
1363
|
? getTickValues(xAxisDataMapped, xScale, isDateTime ? xTickCount : getManualStep(), config)
|
|
1333
|
-
: config.xAxis.type === 'date'
|
|
1364
|
+
: config.runtime.xAxis.type === 'date'
|
|
1334
1365
|
? xAxisDataMapped
|
|
1335
1366
|
: undefined
|
|
1336
1367
|
}
|
|
1337
1368
|
>
|
|
1338
1369
|
{props => {
|
|
1370
|
+
const hasDynamicCategory = config.series.some(s => s.dynamicCategory)
|
|
1339
1371
|
// For these charts, we generated all ticks in tickValues above, and now need to filter/shift them
|
|
1340
1372
|
// so the last tick is always labeled
|
|
1341
|
-
if (config.xAxis.type === 'date' && !config.xAxis.manual) {
|
|
1373
|
+
if (config.runtime.xAxis.type === 'date' && !config.runtime.xAxis.manual && !hasDynamicCategory) {
|
|
1342
1374
|
props.ticks = filterAndShiftLinearDateTicks(config, props, xAxisDataMapped, formatDate)
|
|
1343
1375
|
}
|
|
1344
1376
|
|
|
@@ -1346,7 +1378,11 @@ const LinearChart = forwardRef<SVGAElement, LinearChartProps>(({ parentHeight, p
|
|
|
1346
1378
|
useDateSpanMonths &&
|
|
1347
1379
|
xScale
|
|
1348
1380
|
.ticks(xTickCount)
|
|
1349
|
-
.map(t =>
|
|
1381
|
+
.map(t =>
|
|
1382
|
+
props.ticks.findIndex(
|
|
1383
|
+
tick => (typeof tick.value === 'number' ? tick.value : tick.value.getTime()) === t.getTime()
|
|
1384
|
+
)
|
|
1385
|
+
)
|
|
1350
1386
|
.slice(0, 2)
|
|
1351
1387
|
.reduce((acc, curr) => curr - acc)
|
|
1352
1388
|
|
|
@@ -1370,16 +1406,12 @@ const LinearChart = forwardRef<SVGAElement, LinearChartProps>(({ parentHeight, p
|
|
|
1370
1406
|
|
|
1371
1407
|
// Calculate sumOfTickWidth here, before map function
|
|
1372
1408
|
const tickWidthMax = Math.max(
|
|
1373
|
-
...filteredTicks.map(tick =>
|
|
1374
|
-
getTextWidth(tick.formattedValue, `normal ${fontSizes[config.fontSize]}px sans-serif`)
|
|
1375
|
-
)
|
|
1409
|
+
...filteredTicks.map(tick => getTextWidth(tick.formattedValue, GET_TEXT_WIDTH_FONT))
|
|
1376
1410
|
)
|
|
1377
1411
|
// const marginTop = 20 // moved to top bc need for yMax calcs
|
|
1378
1412
|
const accumulator = ismultiLabel ? 180 : 100
|
|
1379
1413
|
|
|
1380
|
-
const textWidths = filteredTicks.map(tick =>
|
|
1381
|
-
getTextWidth(tick.formattedValue, `normal ${fontSizes[config.fontSize]}px sans-serif`)
|
|
1382
|
-
)
|
|
1414
|
+
const textWidths = filteredTicks.map(tick => getTextWidth(tick.formattedValue, GET_TEXT_WIDTH_FONT))
|
|
1383
1415
|
const sumOfTickWidth = textWidths.reduce((a, b) => a + b, accumulator)
|
|
1384
1416
|
const spaceBetweenEachTick = (xMax - sumOfTickWidth) / (filteredTicks.length - 1)
|
|
1385
1417
|
|
|
@@ -1471,6 +1503,7 @@ const LinearChart = forwardRef<SVGAElement, LinearChartProps>(({ parentHeight, p
|
|
|
1471
1503
|
: undefined
|
|
1472
1504
|
}
|
|
1473
1505
|
fill={config.xAxis.tickLabelColor}
|
|
1506
|
+
fontSize={tickLabelFontSize}
|
|
1474
1507
|
>
|
|
1475
1508
|
{tick.formattedValue}
|
|
1476
1509
|
</Text>
|
|
@@ -1488,6 +1521,7 @@ const LinearChart = forwardRef<SVGAElement, LinearChartProps>(({ parentHeight, p
|
|
|
1488
1521
|
verticalAnchor='start'
|
|
1489
1522
|
fontWeight='bold'
|
|
1490
1523
|
fill={config.xAxis.labelColor}
|
|
1524
|
+
fontSize={axisLabelFontSize}
|
|
1491
1525
|
>
|
|
1492
1526
|
{props.label}
|
|
1493
1527
|
</Text>
|
|
@@ -15,7 +15,6 @@ const PairedBarChart = ({ width, height, originalWidth }) => {
|
|
|
15
15
|
|
|
16
16
|
const borderWidth = config.barHasBorder === 'true' ? 1 : 0
|
|
17
17
|
const halfWidth = width / 2
|
|
18
|
-
const fontSize = { small: 16, medium: 18, large: 20 }
|
|
19
18
|
const offset = 1.02 // Offset of the left bar from the Axis
|
|
20
19
|
|
|
21
20
|
const groupOne = {
|
|
@@ -109,10 +108,7 @@ const PairedBarChart = ({ width, height, originalWidth }) => {
|
|
|
109
108
|
const totalheight = (Number(config.barSpace) + barHeight + borderWidth) * data.length
|
|
110
109
|
config.heights.horizontal = totalheight
|
|
111
110
|
// check if text fits inside of the bar including suffix/prefix,comma,fontSize ..etc
|
|
112
|
-
const textWidth = getTextWidth(
|
|
113
|
-
formatNumber(d[groupOne.dataKey], 'left'),
|
|
114
|
-
`normal ${fontSize[config.fontSize]}px sans-serif`
|
|
115
|
-
)
|
|
111
|
+
const textWidth = getTextWidth(formatNumber(d[groupOne.dataKey], 'left'))
|
|
116
112
|
const textFits = textWidth < barWidth - 5 // minus padding dx(5)
|
|
117
113
|
|
|
118
114
|
return (
|
|
@@ -170,10 +166,7 @@ const PairedBarChart = ({ width, height, originalWidth }) => {
|
|
|
170
166
|
const totalheight = (Number(config.barSpace) + barHeight + borderWidth) * data.length
|
|
171
167
|
config.heights.horizontal = totalheight
|
|
172
168
|
// check if text fits inside of the bar including suffix/prefix,comma,fontSize ..etc
|
|
173
|
-
const textWidth = getTextWidth(
|
|
174
|
-
formatNumber(d[groupTwo.dataKey], 'left'),
|
|
175
|
-
`normal ${fontSize[config.fontSize]}px sans-serif`
|
|
176
|
-
)
|
|
169
|
+
const textWidth = getTextWidth(formatNumber(d[groupTwo.dataKey], 'left'))
|
|
177
170
|
const isTextFits = textWidth < barWidth - 5 // minus padding dx(5)
|
|
178
171
|
|
|
179
172
|
return (
|
|
@@ -1,13 +1,13 @@
|
|
|
1
1
|
import { Brush } from '@visx/brush'
|
|
2
2
|
import { Group } from '@visx/group'
|
|
3
3
|
import { Text } from '@visx/text'
|
|
4
|
-
import { useBarChart } from '../hooks/useBarChart'
|
|
5
4
|
import { FC, useContext, useEffect, useRef, useState } from 'react'
|
|
6
5
|
import ConfigContext from '../ConfigContext'
|
|
7
6
|
import { ScaleLinear, ScaleBand } from 'd3-scale'
|
|
8
7
|
import { isDateScale } from '@cdc/core/helpers/cove/date'
|
|
9
8
|
import ErrorBoundary from '@cdc/core/components/ErrorBoundary'
|
|
10
9
|
import { getTextWidth } from '@cdc/core/helpers/getTextWidth'
|
|
10
|
+
import { appFontSize } from '@cdc/core/helpers/cove/fontSettings'
|
|
11
11
|
|
|
12
12
|
interface Props {
|
|
13
13
|
xScaleBrush: ScaleLinear<number, number>
|
|
@@ -19,7 +19,6 @@ const ZoomBrush: FC<Props> = props => {
|
|
|
19
19
|
const { tableData, config, parseDate, formatDate, setBrushConfig, dashboardConfig } = useContext(ConfigContext)
|
|
20
20
|
const sharedFilters = dashboardConfig?.dashboard?.sharedFilters ?? []
|
|
21
21
|
const isDashboardFilters = sharedFilters?.length > 0
|
|
22
|
-
const { fontSize } = useBarChart()
|
|
23
22
|
const [showTooltip, setShowTooltip] = useState(false)
|
|
24
23
|
const [brushKey, setBrushKey] = useState(0)
|
|
25
24
|
const brushRef = useRef(null)
|
|
@@ -178,7 +177,6 @@ const ZoomBrush: FC<Props> = props => {
|
|
|
178
177
|
showTooltip={showTooltip}
|
|
179
178
|
pixelDistance={textProps.endPosition - textProps.startPosition}
|
|
180
179
|
textProps={textProps}
|
|
181
|
-
fontSize={fontSize[config.fontSize]}
|
|
182
180
|
{...props}
|
|
183
181
|
isBrushing={brushRef.current?.state.isBrushing}
|
|
184
182
|
/>
|
|
@@ -202,7 +200,7 @@ const ZoomBrush: FC<Props> = props => {
|
|
|
202
200
|
}
|
|
203
201
|
|
|
204
202
|
const BrushHandle = props => {
|
|
205
|
-
const { x, isBrushActive, isBrushing, className, textProps,
|
|
203
|
+
const { x, isBrushActive, isBrushing, className, textProps, showTooltip, left } = props
|
|
206
204
|
const pathWidth = 8
|
|
207
205
|
if (!isBrushActive) {
|
|
208
206
|
return null
|
|
@@ -212,7 +210,7 @@ const BrushHandle = props => {
|
|
|
212
210
|
const transform = isLeft ? 'scale(-1, 1)' : 'translate(0,0)'
|
|
213
211
|
const textAnchor = isLeft ? 'end' : 'start'
|
|
214
212
|
const tooltipText = isLeft ? ` Drag edges to focus on a specific segment ` : ''
|
|
215
|
-
const textWidth = getTextWidth(tooltipText, `normal ${
|
|
213
|
+
const textWidth = getTextWidth(tooltipText, `normal ${appFontSize / 1.1}px sans-serif`)
|
|
216
214
|
|
|
217
215
|
return (
|
|
218
216
|
<>
|
|
@@ -221,7 +219,7 @@ const BrushHandle = props => {
|
|
|
221
219
|
x={(Number(textProps.xMax) - textWidth) / 2}
|
|
222
220
|
dy={-12}
|
|
223
221
|
pointerEvents='visiblePainted'
|
|
224
|
-
fontSize={
|
|
222
|
+
fontSize={appFontSize / 1.1}
|
|
225
223
|
>
|
|
226
224
|
{tooltipText}
|
|
227
225
|
</Text>
|
|
@@ -234,7 +232,7 @@ const BrushHandle = props => {
|
|
|
234
232
|
y={25}
|
|
235
233
|
verticalAnchor='start'
|
|
236
234
|
textAnchor={textAnchor}
|
|
237
|
-
fontSize={
|
|
235
|
+
fontSize={appFontSize / 1.4}
|
|
238
236
|
>
|
|
239
237
|
{isLeft ? textProps.startValue : textProps.endValue}
|
|
240
238
|
</Text>
|
|
@@ -11,10 +11,9 @@ export default {
|
|
|
11
11
|
showDownloadMediaButton: false,
|
|
12
12
|
theme: 'theme-blue',
|
|
13
13
|
animate: false,
|
|
14
|
-
fontSize: 'medium',
|
|
15
14
|
lineDatapointStyle: 'hover',
|
|
16
15
|
lineDatapointColor: 'Same as Line',
|
|
17
|
-
barHasBorder: '
|
|
16
|
+
barHasBorder: 'true',
|
|
18
17
|
isLollipopChart: false,
|
|
19
18
|
lollipopShape: 'circle',
|
|
20
19
|
lollipopColorStyle: 'two-tone',
|
|
@@ -167,6 +166,7 @@ export default {
|
|
|
167
166
|
seriesHighlight: [],
|
|
168
167
|
style: 'circles',
|
|
169
168
|
subStyle: 'linear blocks',
|
|
169
|
+
shape: 'circle',
|
|
170
170
|
tickRotation: '',
|
|
171
171
|
hideBorder: {
|
|
172
172
|
side: false,
|
|
@@ -198,13 +198,16 @@ export default {
|
|
|
198
198
|
bottomPrefix: '',
|
|
199
199
|
bottomAbbreviated: false
|
|
200
200
|
},
|
|
201
|
+
filters: [],
|
|
201
202
|
confidenceKeys: {},
|
|
202
203
|
visual: {
|
|
203
204
|
border: true,
|
|
204
205
|
accent: true,
|
|
205
206
|
background: true,
|
|
206
207
|
verticalHoverLine: false,
|
|
207
|
-
horizontalHoverLine: false
|
|
208
|
+
horizontalHoverLine: false,
|
|
209
|
+
lineDatapointSymbol: 'none',
|
|
210
|
+
maximumShapeAmount: 7
|
|
208
211
|
},
|
|
209
212
|
useLogScale: false,
|
|
210
213
|
filterBehavior: 'Filter Change',
|
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
import _ from 'lodash'
|
|
2
|
+
import { ChartConfig } from '../types/ChartConfig'
|
|
3
|
+
import * as d3 from 'd3-array'
|
|
4
|
+
|
|
5
|
+
export const getBoxPlotConfig = (newConfig: ChartConfig, data: object[]) => {
|
|
6
|
+
const combinedData = data
|
|
7
|
+
const groups = _.uniq(_.map(combinedData, newConfig.xAxis.dataKey))
|
|
8
|
+
const seriesKeys = _.map(newConfig.series, 'dataKey')
|
|
9
|
+
const plots: any[] = []
|
|
10
|
+
|
|
11
|
+
groups.forEach(g => {
|
|
12
|
+
seriesKeys.forEach(seriesKey => {
|
|
13
|
+
try {
|
|
14
|
+
if (!g) throw new Error('No groups resolved in box plots')
|
|
15
|
+
|
|
16
|
+
// Start handle operations on combinedData
|
|
17
|
+
const { count, sortedData } = _.chain(combinedData)
|
|
18
|
+
// Filter by xAxis data key
|
|
19
|
+
.filter(item => item[newConfig.xAxis.dataKey] === g)
|
|
20
|
+
// perform multiple operations on the filtered data
|
|
21
|
+
.thru(filteredData => ({
|
|
22
|
+
count: filteredData.length,
|
|
23
|
+
sortedData: _.map(filteredData, item => Number(item[seriesKey])).sort()
|
|
24
|
+
}))
|
|
25
|
+
// get the results from the chain
|
|
26
|
+
.value()
|
|
27
|
+
|
|
28
|
+
if (!sortedData) throw new Error('boxplots dont have data yet')
|
|
29
|
+
if (!plots) throw new Error('boxplots dont have plots yet')
|
|
30
|
+
|
|
31
|
+
const q1 = d3.quantile(sortedData, 0.25)
|
|
32
|
+
const q3 = d3.quantile(sortedData, 0.75)
|
|
33
|
+
|
|
34
|
+
const iqr = q3 - q1
|
|
35
|
+
const lowerBounds = q1 - 1.5 * iqr
|
|
36
|
+
const upperBounds = q3 + 1.5 * iqr
|
|
37
|
+
const nonOutliers = sortedData.filter(value => value >= lowerBounds && value <= upperBounds)
|
|
38
|
+
plots.push({
|
|
39
|
+
columnCategory: g,
|
|
40
|
+
columnMax: d3.max(nonOutliers),
|
|
41
|
+
columnThirdQuartile: _.round(q3, newConfig.dataFormat.roundTo),
|
|
42
|
+
columnMedian: Number(d3.median(sortedData)).toFixed(newConfig.dataFormat.roundTo),
|
|
43
|
+
columnFirstQuartile: _.round(q1, newConfig.dataFormat.roundTo),
|
|
44
|
+
columnMin: _.min(nonOutliers),
|
|
45
|
+
columnCount: count,
|
|
46
|
+
columnSd: Number(d3.deviation(sortedData)).toFixed(newConfig.dataFormat.roundTo),
|
|
47
|
+
columnMean: Number(d3.mean(sortedData)).toFixed(newConfig.dataFormat.roundTo),
|
|
48
|
+
columnIqr: _.round(iqr, newConfig.dataFormat.roundTo),
|
|
49
|
+
values: sortedData,
|
|
50
|
+
columnLowerBounds: lowerBounds,
|
|
51
|
+
columnUpperBounds: upperBounds,
|
|
52
|
+
columnOutliers: _.filter(sortedData, value => value < lowerBounds || value > upperBounds),
|
|
53
|
+
columnNonOutliers: _.filter(sortedData, value => value >= lowerBounds && value <= upperBounds)
|
|
54
|
+
})
|
|
55
|
+
} catch (e) {
|
|
56
|
+
console.error('COVE: ', e.message) // eslint-disable-line
|
|
57
|
+
}
|
|
58
|
+
})
|
|
59
|
+
})
|
|
60
|
+
|
|
61
|
+
// Generate a flat list of categories based on seriesKeys and groups
|
|
62
|
+
const categories =
|
|
63
|
+
seriesKeys.length > 1
|
|
64
|
+
? _.flatMap(groups, value => _.map(seriesKeys, key => `${_.capitalize(key)} - ${_.capitalize(value)}`))
|
|
65
|
+
: groups
|
|
66
|
+
|
|
67
|
+
return [plots, categories]
|
|
68
|
+
}
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
import { colorPalettesChart as colorPalettes, twoColorPalette } from '@cdc/core/data/colorPalettes'
|
|
2
|
+
import { scaleOrdinal } from '@visx/scale'
|
|
3
|
+
import { ChartConfig } from '../types/ChartConfig'
|
|
4
|
+
|
|
5
|
+
export const getColorScale = (config: ChartConfig): ((value: string) => string) => {
|
|
6
|
+
const configPalette = ['Paired Bar', 'Deviation Bar'].includes(config.visualizationType)
|
|
7
|
+
? config.twoColor.palette
|
|
8
|
+
: config.palette
|
|
9
|
+
const allPalettes: Record<string, string[]> = { ...colorPalettes, ...twoColorPalette }
|
|
10
|
+
let palette = config.customColors || allPalettes[configPalette]
|
|
11
|
+
let numberOfKeys = config.runtime.seriesKeys.length
|
|
12
|
+
let newColorScale
|
|
13
|
+
|
|
14
|
+
while (numberOfKeys > palette.length) {
|
|
15
|
+
palette = palette.concat(palette)
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
palette = palette.slice(0, numberOfKeys)
|
|
19
|
+
|
|
20
|
+
newColorScale = () =>
|
|
21
|
+
scaleOrdinal({
|
|
22
|
+
domain: config.runtime.seriesLabelsAll,
|
|
23
|
+
range: palette,
|
|
24
|
+
unknown: null
|
|
25
|
+
})
|
|
26
|
+
|
|
27
|
+
return newColorScale
|
|
28
|
+
}
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
import _ from 'lodash'
|
|
2
|
+
import { ChartConfig } from '../types/ChartConfig'
|
|
3
|
+
import * as d3 from 'd3-array'
|
|
4
|
+
|
|
5
|
+
export const getComboChartConfig = (newConfig: ChartConfig) => {
|
|
6
|
+
if (newConfig.visualizationType !== 'Combo' || !newConfig.series) return
|
|
7
|
+
|
|
8
|
+
const runtimeKeys = {
|
|
9
|
+
barSeriesKeys: [],
|
|
10
|
+
lineSeriesKeys: [],
|
|
11
|
+
areaSeriesKeys: [],
|
|
12
|
+
forecastingSeriesKeys: []
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
// Define a mapping of series types to runtime keys
|
|
16
|
+
const seriesTypeMap = new Map([
|
|
17
|
+
['Area Chart', 'areaSeriesKeys'],
|
|
18
|
+
['Forecasting', 'forecastingSeriesKeys'],
|
|
19
|
+
['Bar', 'barSeriesKeys'],
|
|
20
|
+
['Combo', 'barSeriesKeys'],
|
|
21
|
+
['Line', 'lineSeriesKeys'],
|
|
22
|
+
['dashed-sm', 'lineSeriesKeys'],
|
|
23
|
+
['dashed-md', 'lineSeriesKeys'],
|
|
24
|
+
['dashed-lg', 'lineSeriesKeys']
|
|
25
|
+
])
|
|
26
|
+
|
|
27
|
+
newConfig.series.forEach(series => {
|
|
28
|
+
const runtimeKey = seriesTypeMap.get(series.type)
|
|
29
|
+
if (runtimeKey) {
|
|
30
|
+
const valueToPush = runtimeKey === 'barSeriesKeys' || runtimeKey === 'lineSeriesKeys' ? series.dataKey : series
|
|
31
|
+
runtimeKeys[runtimeKey].push(valueToPush)
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
// Change Combo series type to Bar
|
|
35
|
+
if (series.type === 'Combo') {
|
|
36
|
+
series.type = 'Bar'
|
|
37
|
+
}
|
|
38
|
+
})
|
|
39
|
+
|
|
40
|
+
// Assign the processed runtime keys to the configuration
|
|
41
|
+
return { ...newConfig.runtime, ...runtimeKeys }
|
|
42
|
+
}
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
import { isDateScale } from '@cdc/core/helpers/cove/date'
|
|
2
|
+
import _ from 'lodash'
|
|
3
|
+
import { ChartConfig } from '../types/ChartConfig'
|
|
4
|
+
export const getExcludedData = (newConfig: ChartConfig, data: object[]) => {
|
|
5
|
+
let newExcludedData = data
|
|
6
|
+
if (newConfig.exclusions && newConfig.exclusions.active) {
|
|
7
|
+
if (newConfig.xAxis.type === 'categorical' && newConfig.exclusions.keys?.length > 0) {
|
|
8
|
+
newExcludedData = data.filter(e => !newConfig.exclusions.keys.includes(e[newConfig.xAxis.dataKey]))
|
|
9
|
+
} else if (
|
|
10
|
+
isDateScale(newConfig.xAxis) &&
|
|
11
|
+
(newConfig.exclusions.dateStart || newConfig.exclusions.dateEnd) &&
|
|
12
|
+
newConfig.xAxis.dateParseFormat
|
|
13
|
+
) {
|
|
14
|
+
// Filter dates
|
|
15
|
+
const timestamp = e => new Date(e).getTime()
|
|
16
|
+
|
|
17
|
+
let startDate = timestamp(newConfig.exclusions.dateStart)
|
|
18
|
+
let endDate = timestamp(newConfig.exclusions.dateEnd) + 86399999 //Increase by 24h in ms (86400000ms - 1ms) to include selected end date for .getTime() comparative
|
|
19
|
+
|
|
20
|
+
let startDateValid = undefined !== typeof startDate && false === isNaN(startDate)
|
|
21
|
+
let endDateValid = undefined !== typeof endDate && false === isNaN(endDate)
|
|
22
|
+
|
|
23
|
+
if (startDateValid && endDateValid) {
|
|
24
|
+
newExcludedData = data.filter(
|
|
25
|
+
e => timestamp(e[newConfig.xAxis.dataKey]) >= startDate && timestamp(e[newConfig.xAxis.dataKey]) <= endDate
|
|
26
|
+
)
|
|
27
|
+
} else if (startDateValid) {
|
|
28
|
+
newExcludedData = data.filter(e => timestamp(e[newConfig.xAxis.dataKey]) >= startDate)
|
|
29
|
+
} else if (endDateValid) {
|
|
30
|
+
newExcludedData = data.filter(e => timestamp(e[newConfig.xAxis.dataKey]) <= endDate)
|
|
31
|
+
}
|
|
32
|
+
} else {
|
|
33
|
+
newExcludedData = data
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
return newExcludedData
|
|
37
|
+
}
|