@cdc/chart 4.24.5 → 4.24.7
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 +39128 -35959
- package/examples/feature/annotations/index.json +542 -0
- package/examples/xaxis.json +493 -0
- package/index.html +5 -4
- package/package.json +5 -4
- package/src/CdcChart.tsx +104 -64
- package/src/_stories/Chart.stories.tsx +18 -171
- package/src/_stories/ChartAnnotation.stories.tsx +32 -0
- package/src/_stories/_mock/annotation_category_mock.json +473 -0
- package/src/_stories/_mock/annotation_date-linear_mock.json +530 -0
- package/src/_stories/_mock/annotation_date-time_mock.json +530 -0
- package/src/_stories/_mock/line_chart_two_points_new_chart.json +128 -0
- package/src/_stories/_mock/line_chart_two_points_regression_test.json +127 -0
- package/src/_stories/_mock/lollipop.json +171 -0
- package/src/components/Annotations/components/AnnotationDraggable.styles.css +31 -0
- package/src/components/Annotations/components/AnnotationDraggable.tsx +154 -0
- package/src/components/Annotations/components/AnnotationDropdown.styles.css +14 -0
- package/src/components/Annotations/components/AnnotationDropdown.tsx +72 -0
- package/src/components/Annotations/components/AnnotationList.styles.css +45 -0
- package/src/components/Annotations/components/AnnotationList.tsx +42 -0
- package/src/components/Annotations/components/findNearestDatum.ts +138 -0
- package/src/components/Annotations/components/helpers/index.tsx +46 -0
- package/src/components/Annotations/index.tsx +13 -0
- package/src/components/AreaChart/components/AreaChart.Stacked.jsx +1 -1
- package/src/components/AreaChart/components/AreaChart.jsx +1 -1
- package/src/components/BarChart/components/BarChart.Horizontal.tsx +44 -42
- package/src/components/BarChart/components/BarChart.StackedHorizontal.tsx +1 -2
- package/src/components/BarChart/components/BarChart.StackedVertical.tsx +11 -11
- package/src/components/BarChart/components/BarChart.Vertical.tsx +50 -22
- package/src/components/BarChart/helpers/index.ts +102 -0
- package/src/components/EditorPanel/EditorPanel.tsx +232 -98
- package/src/components/EditorPanel/components/Panels/Panel.Annotate.tsx +306 -0
- package/src/components/EditorPanel/components/Panels/Panel.General.tsx +117 -6
- package/src/components/EditorPanel/components/Panels/Panel.Sankey.tsx +2 -3
- package/src/components/EditorPanel/components/Panels/Panel.Visual.tsx +3 -2
- package/src/components/EditorPanel/components/Panels/index.tsx +3 -1
- package/src/components/EditorPanel/components/panels.scss +4 -0
- package/src/components/EditorPanel/editor-panel.scss +19 -0
- package/src/components/EditorPanel/useEditorPermissions.js +19 -2
- package/src/components/Legend/Legend.Component.tsx +7 -8
- package/src/components/Legend/helpers/createFormatLabels.tsx +1 -1
- package/src/components/Legend/helpers/index.ts +5 -0
- package/src/components/LineChart/LineChartProps.ts +3 -0
- package/src/components/LineChart/helpers.ts +21 -7
- package/src/components/LineChart/index.tsx +7 -7
- package/src/components/LinearChart.jsx +179 -136
- package/src/components/PairedBarChart.jsx +9 -9
- package/src/components/PieChart/PieChart.tsx +4 -4
- package/src/components/Sankey/index.tsx +73 -20
- package/src/components/ScatterPlot/ScatterPlot.jsx +22 -8
- package/src/components/ZoomBrush.tsx +90 -44
- package/src/data/initial-state.js +14 -6
- package/src/helpers/handleChartTabbing.ts +8 -0
- package/src/helpers/isConvertLineToBarGraph.ts +4 -0
- package/src/hooks/{useBarChart.js → useBarChart.ts} +2 -40
- package/src/hooks/useColorScale.ts +1 -1
- package/src/hooks/useMinMax.ts +8 -3
- package/src/hooks/useScales.ts +25 -3
- package/src/hooks/useTooltip.tsx +58 -11
- package/src/scss/main.scss +21 -14
- package/src/types/ChartConfig.ts +50 -3
- package/src/types/ChartContext.ts +9 -0
- package/tests-examples/helpers/testZeroValue.test.ts +30 -0
- package/LICENSE +0 -201
- package/src/helpers/filterData.ts +0 -18
- package/src/helpers/tests/computeMarginBottom.test.ts +0 -21
- /package/src/hooks/{useLegendClasses.js → useLegendClasses.ts} +0 -0
- /package/src/hooks/{useReduceData.js → useReduceData.ts} +0 -0
|
@@ -5,7 +5,7 @@ import Button from '@cdc/core/components/elements/Button'
|
|
|
5
5
|
import useLegendClasses from '../../hooks/useLegendClasses'
|
|
6
6
|
import { useHighlightedBars } from '../../hooks/useHighlightedBars'
|
|
7
7
|
import { handleLineType } from '../../helpers/handleLineType'
|
|
8
|
-
import {
|
|
8
|
+
import { getMarginTop } from './helpers/index'
|
|
9
9
|
import { Line } from '@visx/shape'
|
|
10
10
|
import { Label } from '../../types/Label'
|
|
11
11
|
import { ChartConfig } from '../../types/ChartConfig'
|
|
@@ -27,25 +27,24 @@ export interface LegendProps {
|
|
|
27
27
|
/* eslint-disable jsx-a11y/no-noninteractive-tabindex, jsx-a11y/no-static-element-interactions */
|
|
28
28
|
const Legend: React.FC<LegendProps> = forwardRef(({ config, colorScale, seriesHighlight, highlight, highlightReset, currentViewport, formatLabels, skipId = 'legend' }, ref) => {
|
|
29
29
|
const { innerClasses, containerClasses } = useLegendClasses(config)
|
|
30
|
-
const { runtime,
|
|
30
|
+
const { runtime, legend } = config
|
|
31
31
|
|
|
32
32
|
if (!legend) return null
|
|
33
|
-
const isBottomOrSmallViewport = legend
|
|
33
|
+
const isBottomOrSmallViewport = legend?.position === 'bottom' || (['sm', 'xs', 'xxs'].includes(currentViewport) && !legend.hide)
|
|
34
34
|
|
|
35
35
|
const legendClasses = {
|
|
36
36
|
marginBottom: isBottomOrSmallViewport ? '15px' : '0px',
|
|
37
|
-
marginTop: isBottomOrSmallViewport
|
|
37
|
+
marginTop: isBottomOrSmallViewport && config.orientation === 'horizontal' ? `${config.yAxis.label && config.isResponsiveTicks ? config.dynamicMarginTop : config.runtime.xAxis.size}px` : getMarginTop(isBottomOrSmallViewport, config.brush.active)
|
|
38
38
|
}
|
|
39
39
|
|
|
40
40
|
const { HighLightedBarUtils } = useHighlightedBars(config)
|
|
41
41
|
|
|
42
42
|
let highLightedLegendItems = HighLightedBarUtils.findDuplicates(config.highlightedBarValues)
|
|
43
|
-
const fontSize = ['sm', 'xs', 'xxs'].includes(currentViewport) ? { fontSize: '11px' } : null
|
|
44
43
|
|
|
45
44
|
return (
|
|
46
45
|
<aside ref={ref} style={legendClasses} id={skipId || 'legend'} className={containerClasses.join(' ')} role='region' aria-label='legend' tabIndex={0}>
|
|
47
46
|
{legend.label && <h3>{parse(legend.label)}</h3>}
|
|
48
|
-
{legend.description && <p
|
|
47
|
+
{legend.description && <p>{parse(legend.description)}</p>}
|
|
49
48
|
|
|
50
49
|
<LegendOrdinal scale={colorScale} itemDirection='row' labelMargin='0 20px 0 0' shapeMargin='0 10px 0'>
|
|
51
50
|
{labels => {
|
|
@@ -103,7 +102,7 @@ const Legend: React.FC<LegendProps> = forwardRef(({ config, colorScale, seriesHi
|
|
|
103
102
|
)}
|
|
104
103
|
</div>
|
|
105
104
|
|
|
106
|
-
<LegendLabel
|
|
105
|
+
<LegendLabel align='left' margin='0 0 0 4px'>
|
|
107
106
|
{label.text}
|
|
108
107
|
</LegendLabel>
|
|
109
108
|
</LegendItem>
|
|
@@ -145,7 +144,7 @@ const Legend: React.FC<LegendProps> = forwardRef(({ config, colorScale, seriesHi
|
|
|
145
144
|
</div>
|
|
146
145
|
|
|
147
146
|
<>
|
|
148
|
-
{config?.preliminaryData?.some(pd => pd.label && pd.type === 'effect' && pd.style) && ['Line', 'Combo'].includes(config.visualizationType) && (
|
|
147
|
+
{config?.preliminaryData?.some(pd => pd.label && pd.type === 'effect' && pd.style === 'Open Circles') && ['Line', 'Combo'].includes(config.visualizationType) && (
|
|
149
148
|
<>
|
|
150
149
|
<hr></hr>
|
|
151
150
|
<div className={config.legend.singleRow && isBottomOrSmallViewport ? 'legend-container__inner bottom single-row' : ''}>
|
|
@@ -9,7 +9,7 @@ export const createFormatLabels =
|
|
|
9
9
|
(defaultLabels: Label[]): Label[] => {
|
|
10
10
|
const { visualizationType, visualizationSubType, series, runtime } = config
|
|
11
11
|
|
|
12
|
-
const reverseLabels = labels => (config.legend.reverseLabelOrder && config.legend
|
|
12
|
+
const reverseLabels = labels => (config.legend.reverseLabelOrder && config.legend?.position === 'bottom' ? labels.reverse() : labels)
|
|
13
13
|
const colorCode = config.legend?.colorCode
|
|
14
14
|
if (visualizationType === 'Deviation Bar') {
|
|
15
15
|
const [belowColor, aboveColor] = twoColorPalette[config.twoColor.palette]
|
|
@@ -29,16 +29,30 @@ export const createStyles = (props: StyleProps): Style[] => {
|
|
|
29
29
|
|
|
30
30
|
export const filterCircles = (preliminaryData: PreliminaryDataItem[], data: DataItem[], seriesKey: string): DataItem[] => {
|
|
31
31
|
// Filter and map preliminaryData to get circlesFiltered
|
|
32
|
-
const circlesFiltered = preliminaryData?.filter(item => item.style
|
|
33
|
-
const filteredData
|
|
32
|
+
const circlesFiltered = preliminaryData?.filter(item => item.style.includes('Circles') && item.type === 'effect').map(item => ({ column: item.column, value: item.value, seriesKey: item.seriesKey, circleSize: item.circleSize, style: item.style }))
|
|
33
|
+
const filteredData = []
|
|
34
34
|
// Process data to find matching items
|
|
35
35
|
data.forEach(item => {
|
|
36
36
|
circlesFiltered.forEach(fc => {
|
|
37
|
-
if (item[fc.column] === fc.value && fc.seriesKey === seriesKey) {
|
|
38
|
-
|
|
37
|
+
if (item[fc.column] === fc.value && fc.seriesKey === seriesKey && item[seriesKey] && fc.style === 'Open Circles') {
|
|
38
|
+
const result = {
|
|
39
|
+
data: item,
|
|
40
|
+
size: fc.circleSize,
|
|
41
|
+
isFilled: false
|
|
42
|
+
}
|
|
43
|
+
filteredData.push(result)
|
|
44
|
+
}
|
|
45
|
+
if ((!fc.value || item[fc.column] === fc.value) && fc.seriesKey === seriesKey && item[seriesKey] && fc.style === 'Filled Circles') {
|
|
46
|
+
const result = {
|
|
47
|
+
data: item,
|
|
48
|
+
size: fc.circleSize,
|
|
49
|
+
isFilled: true
|
|
50
|
+
}
|
|
51
|
+
filteredData.push(result)
|
|
39
52
|
}
|
|
40
53
|
})
|
|
41
54
|
})
|
|
55
|
+
|
|
42
56
|
return filteredData
|
|
43
57
|
}
|
|
44
58
|
|
|
@@ -56,7 +70,7 @@ const handleFirstIndex = (data, seriesKey, preliminaryData) => {
|
|
|
56
70
|
|
|
57
71
|
// Function to check if a data item matches the suppression criteria
|
|
58
72
|
const isSuppressed = pd => {
|
|
59
|
-
if (pd.type === 'effect') return
|
|
73
|
+
if (pd.type === 'effect' || pd.hideLineStyle) return
|
|
60
74
|
return pd.type == 'suppression' && pd.value === firstIndexDataItem[seriesKey] && (!pd.column || pd.column === seriesKey)
|
|
61
75
|
}
|
|
62
76
|
|
|
@@ -93,7 +107,7 @@ const handleLastIndex = (data, seriesKey, preliminaryData) => {
|
|
|
93
107
|
let lastAddedIndex = -1 // Tracks the last index added to the result
|
|
94
108
|
preliminaryData?.forEach(pd => {
|
|
95
109
|
if (pd.type === 'effect') return
|
|
96
|
-
if (data[data.length - 1][seriesKey] === pd.value && pd.style && (!pd.column || pd.column === seriesKey) && pd.type == 'suppression') {
|
|
110
|
+
if (data[data.length - 1][seriesKey] === pd.value && pd.style && (!pd.column || pd.column === seriesKey) && pd.type == 'suppression' && !pd.hideLineStyle) {
|
|
97
111
|
const lastIndex = data.length - 1
|
|
98
112
|
const modifiedItem = { ...data[lastIndex], [seriesKey]: 0 }
|
|
99
113
|
result.data.push(modifiedItem)
|
|
@@ -123,7 +137,7 @@ function handleMiddleIndices(data, seriesKey, dataKey, preliminaryData) {
|
|
|
123
137
|
const isValidMiddleIndex = index => index > 0 && index < data.length - 1
|
|
124
138
|
|
|
125
139
|
preliminaryData?.forEach(pd => {
|
|
126
|
-
if (pd.type === 'effect') return
|
|
140
|
+
if (pd.type === 'effect' || pd.hideLineStyle) return
|
|
127
141
|
const targetValue = pd.value
|
|
128
142
|
|
|
129
143
|
// Find all indices
|
|
@@ -46,7 +46,7 @@ const LineChart = (props: LineChartProps) => {
|
|
|
46
46
|
let data = transformedData
|
|
47
47
|
let tableD = tableData
|
|
48
48
|
// if brush on use brush data and clean
|
|
49
|
-
if (brushConfig.data.length) {
|
|
49
|
+
if (brushConfig.data.length > 0 && config.brush?.active) {
|
|
50
50
|
data = clean(brushConfig.data)
|
|
51
51
|
tableD = clean(brushConfig.data)
|
|
52
52
|
}
|
|
@@ -207,7 +207,7 @@ const LineChart = (props: LineChartProps) => {
|
|
|
207
207
|
<LinePath
|
|
208
208
|
curve={allCurves[seriesData[0].lineType]}
|
|
209
209
|
data={
|
|
210
|
-
config.xAxis.type === 'date-time'
|
|
210
|
+
config.xAxis.type === 'date-time' || config.xAxis.type === 'date'
|
|
211
211
|
? data.sort((d1, d2) => {
|
|
212
212
|
let x1 = getXAxisData(d1)
|
|
213
213
|
let x2 = getXAxisData(d2)
|
|
@@ -232,16 +232,16 @@ const LineChart = (props: LineChartProps) => {
|
|
|
232
232
|
)}
|
|
233
233
|
|
|
234
234
|
{/* circles for preliminaryData data */}
|
|
235
|
-
{circleData.map((
|
|
235
|
+
{circleData.map((item, i) => {
|
|
236
236
|
return (
|
|
237
237
|
<circle
|
|
238
238
|
key={i}
|
|
239
|
-
cx={xPos(
|
|
240
|
-
cy={seriesAxis === 'Right' ? yScaleRight(getYAxisData(
|
|
241
|
-
r={
|
|
239
|
+
cx={xPos(item.data)}
|
|
240
|
+
cy={seriesAxis === 'Right' ? yScaleRight(getYAxisData(item.data, seriesKey)) : yScale(Number(getYAxisData(item.data, seriesKey)))}
|
|
241
|
+
r={item.size}
|
|
242
242
|
strokeWidth={seriesData[0].weight || 2}
|
|
243
243
|
stroke={colorScale ? colorScale(config.runtime.seriesLabels[seriesKey]) : '#000'}
|
|
244
|
-
fill='#fff'
|
|
244
|
+
fill={item.isFilled ? (colorScale ? colorScale(config.runtime.seriesLabels[seriesKey]) : '#000') : '#fff'}
|
|
245
245
|
/>
|
|
246
246
|
)
|
|
247
247
|
})}
|