@cdc/chart 4.24.7 → 4.24.9-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/LICENSE +201 -0
- package/dist/cdcchart.js +47567 -42391
- package/examples/cases-year.json +13379 -0
- package/examples/gallery/bar-chart-vertical/combo-line-chart.json +76 -15
- package/examples/gallery/bar-chart-vertical/vertical-bar-chart-stacked.json +5 -5
- package/index.html +17 -8
- package/package.json +2 -2
- package/src/CdcChart.tsx +382 -133
- package/src/_stories/Chart.Legend.Gradient.tsx +19 -0
- package/src/_stories/_mock/legend.gradient_mock.json +236 -0
- package/src/components/Annotations/components/AnnotationDraggable.tsx +64 -11
- package/src/components/Axis/Categorical.Axis.tsx +145 -0
- package/src/components/BarChart/components/BarChart.Horizontal.tsx +4 -3
- package/src/components/BarChart/components/BarChart.StackedHorizontal.tsx +1 -1
- package/src/components/BarChart/components/BarChart.StackedVertical.tsx +2 -5
- package/src/components/BarChart/components/BarChart.Vertical.tsx +17 -8
- package/src/components/BarChart/helpers/index.ts +5 -16
- package/src/components/BrushChart.tsx +205 -0
- package/src/components/EditorPanel/EditorPanel.tsx +1767 -510
- package/src/components/EditorPanel/components/Panels/Panel.Annotate.tsx +22 -8
- package/src/components/EditorPanel/components/Panels/Panel.General.tsx +190 -37
- package/src/components/EditorPanel/components/Panels/Panel.Sankey.tsx +43 -7
- package/src/components/EditorPanel/components/Panels/Panel.Series.tsx +4 -4
- package/src/components/EditorPanel/components/Panels/Panel.Visual.tsx +1 -11
- package/src/components/EditorPanel/editor-panel.scss +16 -3
- package/src/components/EditorPanel/{useEditorPermissions.js → useEditorPermissions.ts} +90 -19
- package/src/components/Legend/Legend.Component.tsx +185 -193
- package/src/components/Legend/Legend.Suppression.tsx +146 -0
- package/src/components/Legend/Legend.tsx +21 -5
- package/src/components/Legend/helpers/index.ts +33 -3
- package/src/components/LegendWrapper.tsx +26 -0
- package/src/components/LineChart/LineChartProps.ts +1 -18
- package/src/components/LineChart/components/LineChart.BumpCircle.tsx +103 -0
- package/src/components/LineChart/components/LineChart.Circle.tsx +57 -8
- package/src/components/LineChart/helpers.ts +55 -11
- package/src/components/LineChart/index.tsx +113 -38
- package/src/components/LinearChart.tsx +1366 -0
- package/src/components/PieChart/PieChart.tsx +74 -17
- package/src/components/Sankey/index.tsx +22 -16
- package/src/components/Sparkline/components/SparkLine.tsx +2 -2
- package/src/data/initial-state.js +13 -3
- package/src/hooks/useLegendClasses.ts +52 -15
- package/src/hooks/useMinMax.ts +4 -4
- package/src/hooks/useScales.ts +34 -24
- package/src/hooks/useTooltip.tsx +85 -22
- package/src/scss/DataTable.scss +2 -1
- package/src/scss/main.scss +107 -14
- package/src/types/ChartConfig.ts +34 -8
- package/src/types/ChartContext.ts +5 -4
- package/examples/feature/line/line-chart.json +0 -449
- package/src/components/BrushHandle.jsx +0 -17
- package/src/components/LineChart/index.scss +0 -1
- package/src/components/LinearChart.jsx +0 -817
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import type { Meta, StoryObj } from '@storybook/react'
|
|
2
|
+
import chartGradientConfig from './_mock/legend.gradient_mock.json'
|
|
3
|
+
|
|
4
|
+
import Chart from '../CdcChart'
|
|
5
|
+
|
|
6
|
+
const meta: Meta<typeof Chart> = {
|
|
7
|
+
title: 'Components/Templates/Chart/Legend',
|
|
8
|
+
component: Chart
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
type Story = StoryObj<typeof Chart>
|
|
12
|
+
|
|
13
|
+
export const Legend_gradient: Story = {
|
|
14
|
+
args: {
|
|
15
|
+
config: chartGradientConfig
|
|
16
|
+
}
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
export default meta
|
|
@@ -0,0 +1,236 @@
|
|
|
1
|
+
{
|
|
2
|
+
"annotations": [],
|
|
3
|
+
"type": "chart",
|
|
4
|
+
"debugSvg": false,
|
|
5
|
+
"chartMessage": { "noData": "No Data Available" },
|
|
6
|
+
"title": "Combo Bar-Line Chart",
|
|
7
|
+
"showTitle": true,
|
|
8
|
+
"showDownloadMediaButton": false,
|
|
9
|
+
"theme": "theme-purple",
|
|
10
|
+
"animate": false,
|
|
11
|
+
"fontSize": "medium",
|
|
12
|
+
"lineDatapointStyle": "hover",
|
|
13
|
+
"lineDatapointColor": "Same as Line",
|
|
14
|
+
"barHasBorder": "false",
|
|
15
|
+
"isLollipopChart": false,
|
|
16
|
+
"lollipopShape": "circle",
|
|
17
|
+
"lollipopColorStyle": "two-tone",
|
|
18
|
+
"visualizationSubType": "regular",
|
|
19
|
+
"barStyle": "flat",
|
|
20
|
+
"roundingStyle": "standard",
|
|
21
|
+
"tipRounding": "top",
|
|
22
|
+
"isResponsiveTicks": false,
|
|
23
|
+
"general": { "annotationDropdownText": "Annotations", "showDownloadButton": false, "showMissingDataLabel": true, "showSuppressedSymbol": true, "showZeroValueDataLabel": true },
|
|
24
|
+
"padding": { "left": 5, "right": 5 },
|
|
25
|
+
"preliminaryData": [],
|
|
26
|
+
"yAxis": {
|
|
27
|
+
"hideAxis": false,
|
|
28
|
+
"displayNumbersOnBar": false,
|
|
29
|
+
"hideLabel": false,
|
|
30
|
+
"hideTicks": false,
|
|
31
|
+
"size": "68",
|
|
32
|
+
"gridLines": true,
|
|
33
|
+
"enablePadding": false,
|
|
34
|
+
"min": "",
|
|
35
|
+
"max": "",
|
|
36
|
+
"labelColor": "#333",
|
|
37
|
+
"tickLabelColor": "#333",
|
|
38
|
+
"tickColor": "#333",
|
|
39
|
+
"rightHideAxis": true,
|
|
40
|
+
"rightAxisSize": 50,
|
|
41
|
+
"rightLabel": "",
|
|
42
|
+
"rightLabelOffsetSize": 0,
|
|
43
|
+
"rightAxisLabelColor": "#333",
|
|
44
|
+
"rightAxisTickLabelColor": "#333",
|
|
45
|
+
"rightAxisTickColor": "#333",
|
|
46
|
+
"numTicks": "",
|
|
47
|
+
"axisPadding": 0,
|
|
48
|
+
"scalePadding": 10,
|
|
49
|
+
"tickRotation": 0,
|
|
50
|
+
"anchors": [],
|
|
51
|
+
"shoMissingDataLabel": true,
|
|
52
|
+
"showMissingDataLine": true,
|
|
53
|
+
"categories": [],
|
|
54
|
+
"label": "Y-Axis Label Example",
|
|
55
|
+
"maxValue": 1000
|
|
56
|
+
},
|
|
57
|
+
"boxplot": {
|
|
58
|
+
"plots": [],
|
|
59
|
+
"borders": "true",
|
|
60
|
+
"firstQuartilePercentage": 25,
|
|
61
|
+
"thirdQuartilePercentage": 75,
|
|
62
|
+
"boxWidthPercentage": 40,
|
|
63
|
+
"plotOutlierValues": false,
|
|
64
|
+
"plotNonOutlierValues": true,
|
|
65
|
+
"legend": { "showHowToReadText": false, "howToReadText": "" },
|
|
66
|
+
"labels": { "q1": "Lower Quartile", "q2": "q2", "q3": "Upper Quartile", "q4": "q4", "minimum": "Minimum", "maximum": "Maximum", "mean": "Mean", "median": "Median", "sd": "Standard Deviation", "iqr": "Interquartile Range", "total": "Total", "outliers": "Outliers", "values": "Values" }
|
|
67
|
+
},
|
|
68
|
+
"topAxis": { "hasLine": false },
|
|
69
|
+
"isLegendValue": false,
|
|
70
|
+
"barThickness": 0.35,
|
|
71
|
+
"barHeight": 25,
|
|
72
|
+
"barSpace": 15,
|
|
73
|
+
"heights": { "vertical": 300, "horizontal": 750 },
|
|
74
|
+
"xAxis": {
|
|
75
|
+
"sortDates": false,
|
|
76
|
+
"anchors": [],
|
|
77
|
+
"type": "date-time",
|
|
78
|
+
"showTargetLabel": true,
|
|
79
|
+
"targetLabel": "Target",
|
|
80
|
+
"hideAxis": false,
|
|
81
|
+
"hideLabel": false,
|
|
82
|
+
"hideTicks": false,
|
|
83
|
+
"size": "78",
|
|
84
|
+
"tickRotation": "25",
|
|
85
|
+
"min": "",
|
|
86
|
+
"max": "",
|
|
87
|
+
"labelColor": "#333",
|
|
88
|
+
"tickLabelColor": "#333",
|
|
89
|
+
"tickColor": "#333",
|
|
90
|
+
"numTicks": "",
|
|
91
|
+
"labelOffset": 65,
|
|
92
|
+
"axisPadding": 0,
|
|
93
|
+
"target": 0,
|
|
94
|
+
"maxTickRotation": 0,
|
|
95
|
+
"dataKey": "Date",
|
|
96
|
+
"label": "X-Axis Example Label",
|
|
97
|
+
"dateParseFormat": "%m/%d/%Y",
|
|
98
|
+
"dateDisplayFormat": "%m/%d/%Y",
|
|
99
|
+
"tickWidthMax": 91,
|
|
100
|
+
"padding": 6,
|
|
101
|
+
"axisBBox": 164.5282745361328
|
|
102
|
+
},
|
|
103
|
+
"table": {
|
|
104
|
+
"label": "Data Table",
|
|
105
|
+
"expanded": true,
|
|
106
|
+
"limitHeight": false,
|
|
107
|
+
"height": "",
|
|
108
|
+
"caption": "",
|
|
109
|
+
"showDownloadUrl": false,
|
|
110
|
+
"showDataTableLink": true,
|
|
111
|
+
"indexLabel": "",
|
|
112
|
+
"download": true,
|
|
113
|
+
"showVertical": false,
|
|
114
|
+
"dateDisplayFormat": "",
|
|
115
|
+
"showMissingDataLabel": true,
|
|
116
|
+
"showSuppressedSymbol": true,
|
|
117
|
+
"show": true
|
|
118
|
+
},
|
|
119
|
+
"orientation": "vertical",
|
|
120
|
+
"color": "pinkpurple",
|
|
121
|
+
"columns": {},
|
|
122
|
+
"legend": {
|
|
123
|
+
"hide": false,
|
|
124
|
+
"behavior": "highlight",
|
|
125
|
+
"axisAlign": true,
|
|
126
|
+
"singleRow": false,
|
|
127
|
+
"colorCode": "",
|
|
128
|
+
"reverseLabelOrder": false,
|
|
129
|
+
"description": "",
|
|
130
|
+
"dynamicLegend": false,
|
|
131
|
+
"dynamicLegendDefaultText": "Show All",
|
|
132
|
+
"dynamicLegendItemLimit": 5,
|
|
133
|
+
"dynamicLegendItemLimitMessage": "Dynamic Legend Item Limit Hit.",
|
|
134
|
+
"dynamicLegendChartMessage": "Select Options from the Legend",
|
|
135
|
+
"label": "",
|
|
136
|
+
"lineMode": false,
|
|
137
|
+
"verticalSorted": false,
|
|
138
|
+
"highlightOnHover": false,
|
|
139
|
+
"hideSuppressedLabels": false,
|
|
140
|
+
"seriesHighlight": [],
|
|
141
|
+
"style": "gradient",
|
|
142
|
+
"subStyle": "smooth",
|
|
143
|
+
"hasBorder": true,
|
|
144
|
+
"tickRotation": "0",
|
|
145
|
+
"position": "top"
|
|
146
|
+
},
|
|
147
|
+
"brush": {
|
|
148
|
+
"height": 25,
|
|
149
|
+
"active": false,
|
|
150
|
+
"data": [
|
|
151
|
+
{ "Date": "1/15/2016", "Data 1": "1000", "Data 2": "110", "Data 3": "100", "Data 4": "90", "Monthly-Goal": "100" },
|
|
152
|
+
{ "Date": "2/15/2016", "Data 1": "100", "Data 2": "110", "Data 3": "100", "Data 4": "100", "Monthly-Goal": "100" },
|
|
153
|
+
{ "Date": "3/15/2016", "Data 1": "80", "Data 2": "90", "Data 3": "100", "Data 4": "120", "Monthly-Goal": "110" },
|
|
154
|
+
{ "Date": "4/15/2016", "Data 1": "80", "Data 2": "90", "Data 3": "110", "Data 4": "120", "Monthly-Goal": "110" },
|
|
155
|
+
{ "Date": "5/15/2016", "Data 1": "70", "Data 2": "90", "Data 3": "110", "Data 4": "130", "Monthly-Goal": "120" },
|
|
156
|
+
{ "Date": "6/15/2016", "Data 1": "100", "Data 2": "120", "Data 3": "120", "Data 4": "130", "Monthly-Goal": "120" },
|
|
157
|
+
{ "Date": "7/15/2016", "Data 1": "110", "Data 2": "140", "Data 3": "120", "Data 4": "130", "Monthly-Goal": "130" },
|
|
158
|
+
{ "Date": "8/15/2016", "Data 1": "110", "Data 2": "130", "Data 3": "120", "Data 4": "140", "Monthly-Goal": "130" },
|
|
159
|
+
{ "Date": "9/15/2016", "Data 1": "120", "Data 2": "130", "Data 3": "120", "Data 4": "150", "Monthly-Goal": "140" }
|
|
160
|
+
]
|
|
161
|
+
},
|
|
162
|
+
"exclusions": { "active": false, "keys": [] },
|
|
163
|
+
"palette": "sequential-blue",
|
|
164
|
+
"isPaletteReversed": false,
|
|
165
|
+
"twoColor": { "palette": "monochrome-1", "isPaletteReversed": false },
|
|
166
|
+
"labels": false,
|
|
167
|
+
"dataFormat": { "commas": false, "prefix": "", "suffix": "", "abbreviated": false, "bottomSuffix": "", "bottomPrefix": "", "bottomAbbreviated": false },
|
|
168
|
+
"confidenceKeys": {},
|
|
169
|
+
"visual": { "border": true, "accent": true, "background": true, "verticalHoverLine": false, "horizontalHoverLine": false },
|
|
170
|
+
"useLogScale": false,
|
|
171
|
+
"filterBehavior": "Filter Change",
|
|
172
|
+
"highlightedBarValues": [],
|
|
173
|
+
"series": [
|
|
174
|
+
{ "dataKey": "Data 2", "type": "Bar", "axis": "Left", "tooltip": true },
|
|
175
|
+
{ "dataKey": "Data 1", "type": "Bar", "axis": "Left", "tooltip": true },
|
|
176
|
+
{ "dataKey": "Data 3", "type": "Bar", "axis": "Left", "tooltip": true }
|
|
177
|
+
],
|
|
178
|
+
"tooltips": { "opacity": 90, "singleSeries": false, "dateDisplayFormat": "" },
|
|
179
|
+
"forestPlot": {
|
|
180
|
+
"startAt": 0,
|
|
181
|
+
"colors": { "line": "", "shape": "" },
|
|
182
|
+
"lineOfNoEffect": { "show": true },
|
|
183
|
+
"type": "",
|
|
184
|
+
"pooledResult": { "diamondHeight": 5, "column": "" },
|
|
185
|
+
"estimateField": "",
|
|
186
|
+
"estimateRadius": "",
|
|
187
|
+
"shape": "",
|
|
188
|
+
"rowHeight": 20,
|
|
189
|
+
"description": { "show": true, "text": "description", "location": 0 },
|
|
190
|
+
"result": { "show": true, "text": "result", "location": 100 },
|
|
191
|
+
"radius": { "min": 1, "max": 8, "scalingColumn": "" },
|
|
192
|
+
"regression": { "lower": 0, "upper": 0, "estimateField": 0 },
|
|
193
|
+
"leftWidthOffset": 0,
|
|
194
|
+
"rightWidthOffset": 0,
|
|
195
|
+
"showZeroLine": false,
|
|
196
|
+
"leftLabel": "",
|
|
197
|
+
"rightLabel": "",
|
|
198
|
+
"hideDateCategoryCol": false
|
|
199
|
+
},
|
|
200
|
+
"area": { "isStacked": false },
|
|
201
|
+
"sankey": {
|
|
202
|
+
"title": { "defaultColor": "black" },
|
|
203
|
+
"iterations": 1,
|
|
204
|
+
"rxValue": 0.9,
|
|
205
|
+
"overallSize": { "width": 900, "height": 700 },
|
|
206
|
+
"margin": { "margin_y": 25, "margin_x": 0 },
|
|
207
|
+
"nodeSize": { "nodeWidth": 26, "nodeHeight": 40 },
|
|
208
|
+
"nodePadding": 55,
|
|
209
|
+
"nodeFontColor": "black",
|
|
210
|
+
"nodeColor": { "default": "#ff8500", "inactive": "#808080" },
|
|
211
|
+
"linkColor": { "default": "#ffc900", "inactive": "#D3D3D3" },
|
|
212
|
+
"opacity": { "nodeOpacityDefault": 1, "nodeOpacityInactive": 0.1, "LinkOpacityDefault": 1, "LinkOpacityInactive": 0.1 },
|
|
213
|
+
"storyNodeFontColor": "#006778",
|
|
214
|
+
"storyNodeText": [],
|
|
215
|
+
"nodeValueStyle": { "textBefore": "(", "textAfter": ")" },
|
|
216
|
+
"data": []
|
|
217
|
+
},
|
|
218
|
+
"suppressedData": [],
|
|
219
|
+
"height": "332",
|
|
220
|
+
"data": [
|
|
221
|
+
{ "Date": "1/15/2016", "Data 1": "$1,000", "Data 2": "110", "Data 3": "100", "Data 4": "90", "Monthly-Goal": "100" },
|
|
222
|
+
{ "Date": "2/15/2016", "Data 1": "100", "Data 2": "110", "Data 3": "100", "Data 4": "100", "Monthly-Goal": "100" },
|
|
223
|
+
{ "Date": "3/15/2016", "Data 1": "80", "Data 2": "90", "Data 3": "100", "Data 4": "120", "Monthly-Goal": "110" },
|
|
224
|
+
{ "Date": "4/15/2016", "Data 1": "80", "Data 2": "90", "Data 3": "110", "Data 4": "120", "Monthly-Goal": "110" },
|
|
225
|
+
{ "Date": "5/15/2016", "Data 1": "70", "Data 2": "90", "Data 3": "110", "Data 4": "130", "Monthly-Goal": "120" },
|
|
226
|
+
{ "Date": "6/15/2016", "Data 1": "100", "Data 2": "120", "Data 3": "120", "Data 4": "130", "Monthly-Goal": "120" },
|
|
227
|
+
{ "Date": "7/15/2016", "Data 1": "110", "Data 2": "140", "Data 3": "120", "Data 4": "130", "Monthly-Goal": "130" },
|
|
228
|
+
{ "Date": "8/15/2016", "Data 1": "110", "Data 2": "130", "Data 3": "120", "Data 4": "140", "Monthly-Goal": "130" },
|
|
229
|
+
{ "Date": "9/15/2016", "Data 1": "120", "Data 2": "130", "Data 3": "120", "Data 4": "150", "Monthly-Goal": "140" }
|
|
230
|
+
],
|
|
231
|
+
"visualizationType": "Bar",
|
|
232
|
+
"filters": [],
|
|
233
|
+
"validated": 4.23,
|
|
234
|
+
"dynamicMarginTop": 0,
|
|
235
|
+
"version": "4.24.9"
|
|
236
|
+
}
|
|
@@ -90,9 +90,17 @@ const Annotations = ({ xScale, yScale, xScaleAnnotation, xMax, svgRef, onDragSta
|
|
|
90
90
|
props.x
|
|
91
91
|
)
|
|
92
92
|
|
|
93
|
-
updatedAnnotations[index] = {
|
|
93
|
+
updatedAnnotations[index] = {
|
|
94
|
+
...updatedAnnotations[index],
|
|
95
|
+
x: xScaleAnnotation.invert(xScale(nearestDatum.x)),
|
|
96
|
+
y: yScale(nearestDatum.y)
|
|
97
|
+
}
|
|
94
98
|
} else {
|
|
95
|
-
updatedAnnotations[index] = {
|
|
99
|
+
updatedAnnotations[index] = {
|
|
100
|
+
...updatedAnnotations[index],
|
|
101
|
+
x: xScaleAnnotation.invert(props.x),
|
|
102
|
+
y: props.y
|
|
103
|
+
}
|
|
96
104
|
}
|
|
97
105
|
}
|
|
98
106
|
|
|
@@ -102,7 +110,12 @@ const Annotations = ({ xScale, yScale, xScaleAnnotation, xMax, svgRef, onDragSta
|
|
|
102
110
|
})
|
|
103
111
|
}}
|
|
104
112
|
>
|
|
105
|
-
<HtmlLabel
|
|
113
|
+
<HtmlLabel
|
|
114
|
+
className='annotation__desktop-label'
|
|
115
|
+
showAnchorLine={false}
|
|
116
|
+
horizontalAnchor={handleConnectionHorizontalType(annotation, xScale, config)}
|
|
117
|
+
verticalAnchor={handleConnectionVerticalType(annotation, xScale, config)}
|
|
118
|
+
>
|
|
106
119
|
<div
|
|
107
120
|
style={{
|
|
108
121
|
borderRadius: 5, // Optional: set border radius
|
|
@@ -113,7 +126,7 @@ const Annotations = ({ xScale, yScale, xScaleAnnotation, xMax, svgRef, onDragSta
|
|
|
113
126
|
justifyContent: 'start',
|
|
114
127
|
flexDirection: 'row'
|
|
115
128
|
}}
|
|
116
|
-
role='presentation'
|
|
129
|
+
// role='presentation'
|
|
117
130
|
tabIndex={0}
|
|
118
131
|
aria-label={`Annotation text that reads: ${annotation.text}`}
|
|
119
132
|
>
|
|
@@ -127,22 +140,62 @@ const Annotations = ({ xScale, yScale, xScaleAnnotation, xMax, svgRef, onDragSta
|
|
|
127
140
|
<div style={{ fontSize: fontSizes[config.fontSize] }} dangerouslySetInnerHTML={sanitizedData()} />
|
|
128
141
|
</div>
|
|
129
142
|
</HtmlLabel>
|
|
130
|
-
{annotation.connectionType === 'line' &&
|
|
131
|
-
|
|
143
|
+
{annotation.connectionType === 'line' && (
|
|
144
|
+
<Connector type='line' pathProps={{ markerStart: `url(#marker-start--${index})` }} />
|
|
145
|
+
)}
|
|
146
|
+
{annotation.connectionType === 'elbow' && (
|
|
147
|
+
<Connector type='elbow' pathProps={{ markerStart: `url(#marker-start--${index})` }} />
|
|
148
|
+
)}
|
|
132
149
|
{annotation.connectionType === 'curve' && (
|
|
133
150
|
<LinePath
|
|
134
151
|
d={`M ${annotationX},${annotation.y}
|
|
135
|
-
Q ${annotationX + annotation.dx / 2}, ${
|
|
152
|
+
Q ${annotationX + annotation.dx / 2}, ${
|
|
153
|
+
annotation.y + annotation.dy / 2 + Number(annotation?.bezier) || 0
|
|
154
|
+
} ${annotationX + annotation.dx},${annotation.y + annotation.dy}`}
|
|
136
155
|
stroke='black'
|
|
137
156
|
strokeWidth='2'
|
|
138
157
|
fill='none'
|
|
139
158
|
marker-start={`url(#marker-start--${index})`}
|
|
140
159
|
/>
|
|
141
160
|
)}
|
|
142
|
-
{annotation.marker === 'circle' &&
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
161
|
+
{annotation.marker === 'circle' && (
|
|
162
|
+
<CircleSubject
|
|
163
|
+
id={`marker-start--${index}`}
|
|
164
|
+
className='circle-subject'
|
|
165
|
+
stroke={colorScale(annotation.seriesKey)}
|
|
166
|
+
radius={8}
|
|
167
|
+
/>
|
|
168
|
+
)}
|
|
169
|
+
{annotation.marker === 'arrow' && (
|
|
170
|
+
<MarkerArrow
|
|
171
|
+
fill='black'
|
|
172
|
+
id={`marker-start--${index}`}
|
|
173
|
+
x={annotationX}
|
|
174
|
+
y={annotation.y}
|
|
175
|
+
stroke='#333'
|
|
176
|
+
markerWidth={10}
|
|
177
|
+
size={10}
|
|
178
|
+
strokeWidth={1}
|
|
179
|
+
orient='auto-start-reverse'
|
|
180
|
+
markerUnits='userSpaceOnUse'
|
|
181
|
+
/>
|
|
182
|
+
)}
|
|
183
|
+
<circle
|
|
184
|
+
fill='white'
|
|
185
|
+
cx={annotationX + annotation.dx}
|
|
186
|
+
cy={annotation.y + annotation.dy}
|
|
187
|
+
r={16}
|
|
188
|
+
className='annotation__mobile-label annotation__mobile-label-circle'
|
|
189
|
+
stroke={colorScale(annotation.seriesKey)}
|
|
190
|
+
/>
|
|
191
|
+
<text
|
|
192
|
+
height={16}
|
|
193
|
+
x={annotationX + annotation.dx}
|
|
194
|
+
y={annotation.y + annotation.dy}
|
|
195
|
+
className='annotation__mobile-label'
|
|
196
|
+
alignmentBaseline='middle'
|
|
197
|
+
textAnchor='middle'
|
|
198
|
+
>
|
|
146
199
|
{index + 1}
|
|
147
200
|
</text>
|
|
148
201
|
</AnnotationComponent>
|
|
@@ -0,0 +1,145 @@
|
|
|
1
|
+
import React, { useContext } from 'react'
|
|
2
|
+
import { BarStack, Line } from '@visx/shape'
|
|
3
|
+
import { scaleBand, scaleLinear, scaleOrdinal } from '@visx/scale'
|
|
4
|
+
import { Group } from '@visx/group'
|
|
5
|
+
import { Text } from '@visx/text'
|
|
6
|
+
import ConfigContext from '../../ConfigContext'
|
|
7
|
+
import chroma from 'chroma-js'
|
|
8
|
+
import createBarElement from '@cdc/core/components/createBarElement'
|
|
9
|
+
import { useBarChart } from '../../hooks/useBarChart'
|
|
10
|
+
|
|
11
|
+
const CategoricalYAxis = ({ yMax, leftSize, max, xMax }) => {
|
|
12
|
+
const { config, getTextWidth } = useContext(ConfigContext)
|
|
13
|
+
const { fontSize } = useBarChart()
|
|
14
|
+
|
|
15
|
+
const { orientation } = config
|
|
16
|
+
|
|
17
|
+
const getValidColor = (color, defaultColor = '#f1f1f1') => {
|
|
18
|
+
try {
|
|
19
|
+
return chroma(color).hex() // Returns the color if valid
|
|
20
|
+
} catch (e) {
|
|
21
|
+
return defaultColor
|
|
22
|
+
}
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
const categories = config.yAxis?.categories
|
|
26
|
+
|
|
27
|
+
const createDataShape = categories => {
|
|
28
|
+
const categoryObj = [...categories].reduce((acc, item) => {
|
|
29
|
+
acc[item.label] = item.height
|
|
30
|
+
return acc
|
|
31
|
+
}, {})
|
|
32
|
+
|
|
33
|
+
return categoryObj
|
|
34
|
+
}
|
|
35
|
+
const updateCategory = categoryObj => {
|
|
36
|
+
// Get all the heights in the object
|
|
37
|
+
const heights = Object.keys(categoryObj)
|
|
38
|
+
|
|
39
|
+
// Get the last label
|
|
40
|
+
const lastheight = heights[heights.length - 1]
|
|
41
|
+
|
|
42
|
+
// Check if the last label's value is empty
|
|
43
|
+
if (categoryObj[lastheight] === '') {
|
|
44
|
+
// Calculate the sum of the numeric values of all other heights
|
|
45
|
+
const sumOfValues = heights.slice(0, -1).reduce((sum, label) => {
|
|
46
|
+
const value = parseInt(categoryObj[label], 10)
|
|
47
|
+
return sum + (isNaN(value) ? 0 : value)
|
|
48
|
+
}, 0)
|
|
49
|
+
|
|
50
|
+
// Calculate the new value for the last emty height
|
|
51
|
+
const newValue = max - sumOfValues
|
|
52
|
+
|
|
53
|
+
// Update the last height with the new value
|
|
54
|
+
categoryObj[lastheight] = newValue.toString()
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
return [categoryObj]
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
const transformedData = updateCategory(createDataShape(categories))
|
|
61
|
+
|
|
62
|
+
// Define the scales
|
|
63
|
+
const xScaleValue = 0
|
|
64
|
+
|
|
65
|
+
const xScale = scaleBand<number>({
|
|
66
|
+
domain: [xScaleValue],
|
|
67
|
+
padding: 0,
|
|
68
|
+
range: [0, leftSize]
|
|
69
|
+
})
|
|
70
|
+
|
|
71
|
+
const yScale = scaleLinear({
|
|
72
|
+
domain: [0, max],
|
|
73
|
+
range: [yMax, 0],
|
|
74
|
+
clamp: true
|
|
75
|
+
})
|
|
76
|
+
|
|
77
|
+
const colorScale = scaleOrdinal({
|
|
78
|
+
domain: categories.map(d => d?.label),
|
|
79
|
+
range: categories.map(d => getValidColor(d?.color?.trim()))
|
|
80
|
+
})
|
|
81
|
+
|
|
82
|
+
const keys = Object.keys(transformedData[0])
|
|
83
|
+
return (
|
|
84
|
+
<Group left={leftSize - xScale.bandwidth()} top={0}>
|
|
85
|
+
<BarStack data={transformedData} keys={keys} x={() => xScale(xScaleValue)} xScale={xScale} yScale={yScale} color={colorScale}>
|
|
86
|
+
{barStacks =>
|
|
87
|
+
barStacks.map(barStack =>
|
|
88
|
+
barStack.bars.map(bar => {
|
|
89
|
+
const isLastIndex = config.yAxis.categories.length - 1 === barStack.index
|
|
90
|
+
const textSize = fontSize[config.fontSize] / 1.3
|
|
91
|
+
const textColor = chroma(bar.color).luminance() < 0.4 ? '#fff' : '#000'
|
|
92
|
+
const textWidth = getTextWidth(bar.key, `normal ${textSize}px sans-serif`)
|
|
93
|
+
const displayText = Number(textWidth) < bar.width && bar.height > textSize
|
|
94
|
+
const tooltip = `<ul>
|
|
95
|
+
<li class="tooltip-heading""> Label : ${bar.key} </li>
|
|
96
|
+
</li></ul>`
|
|
97
|
+
return (
|
|
98
|
+
<Group key={`${barStack.index}--${bar.index}--${orientation}`}>
|
|
99
|
+
<Group key={`bar-stack-${barStack.index}-${bar.index}`} id={`barStack${barStack.index}-${bar.index}`} className='stack vertical'>
|
|
100
|
+
{createBarElement({
|
|
101
|
+
type: 'axisBar',
|
|
102
|
+
config: config,
|
|
103
|
+
index: barStack.index,
|
|
104
|
+
background: colorScale(bar.key),
|
|
105
|
+
borderColor: '#333',
|
|
106
|
+
borderStyle: 'solid',
|
|
107
|
+
borderWidth: 0,
|
|
108
|
+
width: xScale.bandwidth(),
|
|
109
|
+
height: bar.height,
|
|
110
|
+
x: bar.x,
|
|
111
|
+
y: bar.y,
|
|
112
|
+
tooltipHtml: tooltip,
|
|
113
|
+
tooltipId: `cdc-open-viz-tooltip-${config.runtime.uniqueId}`
|
|
114
|
+
})}
|
|
115
|
+
{/* Label for axis stacks */}
|
|
116
|
+
<Text // ignore
|
|
117
|
+
display={!displayText ? 'none' : 'block'}
|
|
118
|
+
key={`text-${barStack.index}-${bar.index}`}
|
|
119
|
+
x={bar.x + xScale.bandwidth() / 2}
|
|
120
|
+
y={bar.y + bar.height / 2}
|
|
121
|
+
fill={textColor}
|
|
122
|
+
textAnchor='middle'
|
|
123
|
+
verticalAnchor='middle'
|
|
124
|
+
style={{ fontSize: textSize }}
|
|
125
|
+
>
|
|
126
|
+
{bar.key}
|
|
127
|
+
</Text>
|
|
128
|
+
{/* gridLines */}
|
|
129
|
+
{config.runtime.yAxis.gridLines && <Line from={{ x: bar.x + xScale.bandwidth(), y: bar.y }} to={{ x: xMax + xScale.bandwidth(), y: bar.y }} stroke='rgba(0,0,0,0.3)' />}
|
|
130
|
+
{/* White background spacing between stackes */}
|
|
131
|
+
{!isLastIndex && <rect x={bar.x} y={bar.y} width={bar.width} height={1} fill={'#fff'}></rect>}
|
|
132
|
+
{/* Right side Axis line */}
|
|
133
|
+
<rect x={bar.x + bar.width} y={0} width={1} height={yMax} fill={'#000'}></rect>
|
|
134
|
+
</Group>
|
|
135
|
+
</Group>
|
|
136
|
+
)
|
|
137
|
+
})
|
|
138
|
+
)
|
|
139
|
+
}
|
|
140
|
+
</BarStack>
|
|
141
|
+
</Group>
|
|
142
|
+
)
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
export default CategoricalYAxis
|
|
@@ -51,7 +51,7 @@ export const BarChartHorizontal = () => {
|
|
|
51
51
|
return updateBars(barGroups).map((barGroup, index) => (
|
|
52
52
|
<Group className={`bar-group-${barGroup.index}-${barGroup.x0}--${index} ${config.orientation}`} key={`bar-group-${barGroup.index}-${barGroup.x0}--${index}`} id={`bar-group-${barGroup.index}-${barGroup.x0}--${index}`} top={barGroup.y}>
|
|
53
53
|
{barGroup.bars.map((bar, index) => {
|
|
54
|
-
const scaleVal = config.
|
|
54
|
+
const scaleVal = config.yAxis.type === 'logarithmic' ? 0.1 : 0
|
|
55
55
|
let highlightedBarValues = config.highlightedBarValues.map(item => item.value).filter(item => item !== ('' || undefined))
|
|
56
56
|
highlightedBarValues = config.xAxis.type === 'date' ? HighLightedBarUtils.formatDates(highlightedBarValues) : highlightedBarValues
|
|
57
57
|
let transparentBar = config.legend.behavior === 'highlight' && seriesHighlight.length > 0 && seriesHighlight.indexOf(bar.key) === -1
|
|
@@ -75,7 +75,7 @@ export const BarChartHorizontal = () => {
|
|
|
75
75
|
const barDefaultLabel = !config.yAxis.displayNumbersOnBar ? '' : yAxisValue
|
|
76
76
|
|
|
77
77
|
// check if bar text/value string fits into each bars.
|
|
78
|
-
const textWidth =
|
|
78
|
+
const textWidth = getTextWidth(barDefaultLabel, `normal ${fontSize[config.fontSize]}px sans-serif`)
|
|
79
79
|
const textFits = Number(textWidth) < defaultBarWidth - 5
|
|
80
80
|
|
|
81
81
|
// control text position
|
|
@@ -177,6 +177,7 @@ export const BarChartHorizontal = () => {
|
|
|
177
177
|
const hasAsterisk = String(pd.symbol).includes('Asterisk')
|
|
178
178
|
const verticalAnchor = hasAsterisk ? 'middle' : 'end'
|
|
179
179
|
const iconSize = pd.symbol === 'Asterisk' ? barHeight * 1.2 : pd.symbol === 'Double Asterisk' ? barHeight : barHeight / 1.5
|
|
180
|
+
const fillColor = pd.displayGray ? '#8b8b8a' : '#000'
|
|
180
181
|
return (
|
|
181
182
|
<Text // prettier-ignore
|
|
182
183
|
key={index}
|
|
@@ -185,7 +186,7 @@ export const BarChartHorizontal = () => {
|
|
|
185
186
|
opacity={transparentBar ? 0.5 : 1}
|
|
186
187
|
x={barX}
|
|
187
188
|
y={config.barHeight / 2 + config.barHeight * bar.index}
|
|
188
|
-
fill={
|
|
189
|
+
fill={fillColor}
|
|
189
190
|
dy={config.barHeight / 5}
|
|
190
191
|
dx={10}
|
|
191
192
|
textAnchor='start'
|
|
@@ -49,7 +49,7 @@ const BarChartStackedHorizontal = () => {
|
|
|
49
49
|
const xAxisValue = formatNumber(data[bar.index][bar.key], 'left')
|
|
50
50
|
const yAxisValue = config.runtime.yAxis.type === 'date' ? formatDate(parseDate(data[bar.index][config.runtime.originalXAxis.dataKey])) : data[bar.index][config.runtime.originalXAxis.dataKey]
|
|
51
51
|
const yAxisTooltip = config.runtime.yAxis.label ? `${config.runtime.yAxis.label}: ${yAxisValue}` : yAxisValue
|
|
52
|
-
const textWidth =
|
|
52
|
+
const textWidth = getTextWidth(xAxisValue, `normal ${fontSize[config.fontSize]}px sans-serif`)
|
|
53
53
|
const additionalColTooltip = getAdditionalColumn(hoveredBar)
|
|
54
54
|
const tooltipBody = `${config.runtime.seriesLabels[bar.key]}: ${xAxisValue}`
|
|
55
55
|
const tooltip = `<ul>
|
|
@@ -30,8 +30,8 @@ const BarChartStackedVertical = () => {
|
|
|
30
30
|
barStack.bars.map(bar => {
|
|
31
31
|
let transparentBar = config.legend.behavior === 'highlight' && seriesHighlight.length > 0 && seriesHighlight.indexOf(bar.key) === -1
|
|
32
32
|
let displayBar = config.legend.behavior === 'highlight' || seriesHighlight.length === 0 || seriesHighlight.indexOf(bar.key) !== -1
|
|
33
|
-
let barThickness = isDateAxisType ?
|
|
34
|
-
if(config.runtime.xAxis.type !==
|
|
33
|
+
let barThickness = isDateAxisType ? seriesScale.range()[1] - seriesScale.range()[0] : xMax / barStack.bars.length
|
|
34
|
+
if (config.runtime.xAxis.type !== 'date') barThickness = config.barThickness * barThickness
|
|
35
35
|
// tooltips
|
|
36
36
|
const rawXValue = bar.bar.data[config.runtime.xAxis.dataKey]
|
|
37
37
|
const xAxisValue = isDateAxisType ? formatDate(parseDate(rawXValue)) : rawXValue
|
|
@@ -52,9 +52,6 @@ const BarChartStackedVertical = () => {
|
|
|
52
52
|
return (
|
|
53
53
|
<Group key={`${barStack.index}--${bar.index}--${orientation}`}>
|
|
54
54
|
<Group key={`bar-stack-${barStack.index}-${bar.index}`} id={`barStack${barStack.index}-${bar.index}`} className='stack vertical'>
|
|
55
|
-
<Text display={config.labels && displayBar ? 'block' : 'none'} opacity={transparentBar ? 0.5 : 1} x={barX + barWidth / 2} y={bar.y - 5} fill={'#000'} textAnchor='middle'>
|
|
56
|
-
{yAxisValue}
|
|
57
|
-
</Text>
|
|
58
55
|
{createBarElement({
|
|
59
56
|
config: config,
|
|
60
57
|
seriesHighlight,
|