@cdc/chart 4.26.7 → 4.26.10

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (255) hide show
  1. package/CONFIG.md +502 -368
  2. package/dist/cdcchart-CYc-Kayd.es.js +22488 -0
  3. package/dist/cdcchart-DCKn8NmI.es.js +20695 -0
  4. package/dist/cdcchart-Dyui9nk_.es.js +45828 -0
  5. package/dist/cdcchart.js +4 -97406
  6. package/examples/__data__/vega-remote-data.json +6 -0
  7. package/examples/dendrogram.json +18 -0
  8. package/examples/feature/bar/bar-chart-race-annual-change.json +68 -0
  9. package/examples/feature/heatmap/average-age-categorical.json +2 -2
  10. package/examples/feature/heatmap/calendar-heatmap.json +2 -2
  11. package/examples/feature/heatmap/cell-values-bottom-axis.json +2 -2
  12. package/examples/feature/heatmap/sparse-aggregation.json +2 -2
  13. package/examples/feature/line/line-chart-race.json +50 -0
  14. package/examples/feature/sankey/sankey-example-data.json +40 -1441
  15. package/examples/feature/sankey/sankey_chart_data.csv +9 -20
  16. package/examples/network.json +31 -0
  17. package/examples/private/box-plot.json +573 -0
  18. package/examples/private/custom-color-issue.json +625 -0
  19. package/examples/private/custom-colors.json +522 -0
  20. package/examples/private/cutoff.json +10750 -0
  21. package/examples/private/overlay-legend.json +485 -0
  22. package/examples/private/pie-test.json +469 -0
  23. package/examples/vega-remote.json +22 -0
  24. package/package.json +11 -5
  25. package/src/CdcChartComponent.tsx +405 -208
  26. package/src/_stories/Chart.BarRace.stories.tsx +443 -0
  27. package/src/_stories/Chart.BoxPlotNumericSort.stories.tsx +189 -0
  28. package/src/_stories/Chart.BoxPlotStatsParity.stories.tsx +207 -0
  29. package/src/_stories/Chart.ColorDistribution.stories.tsx +299 -0
  30. package/src/_stories/Chart.DataCutoff.stories.tsx +147 -0
  31. package/src/_stories/Chart.DataTableDownloadFilename.stories.tsx +60 -0
  32. package/src/_stories/Chart.Dendrogram.stories.tsx +373 -0
  33. package/src/_stories/Chart.Forecast.CILegend.stories.tsx +236 -0
  34. package/src/_stories/Chart.HeatMap.stories.tsx +170 -4
  35. package/src/_stories/Chart.Legend.AxisAlign.stories.tsx +119 -0
  36. package/src/_stories/Chart.LineRace.stories.tsx +149 -0
  37. package/src/_stories/Chart.Network.stories.tsx +432 -0
  38. package/src/_stories/Chart.PaletteConversion.Editor.stories.tsx +208 -0
  39. package/src/_stories/Chart.Patterns.smoke.stories.tsx +31 -0
  40. package/src/_stories/Chart.PercentageValue.stories.tsx +311 -0
  41. package/src/_stories/Chart.PieLabels.stories.tsx +4 -2
  42. package/src/_stories/Chart.RankByValueMutation.stories.tsx +206 -0
  43. package/src/_stories/Chart.RequiredFields.stories.tsx +681 -0
  44. package/src/_stories/Chart.Sankey.stories.tsx +417 -0
  45. package/src/_stories/Chart.SeriesColorAssignments.stories.tsx +47 -0
  46. package/src/_stories/Chart.SmallMultiplesNumericTileOrder.stories.tsx +137 -0
  47. package/src/_stories/Chart.TooltipSeriesLabels.stories.tsx +43 -0
  48. package/src/_stories/Chart.VegaRemoteData.stories.tsx +31 -0
  49. package/src/_stories/ChartAnnotation.Editor.stories.tsx +78 -0
  50. package/src/_stories/ChartAxisTitles.smoke.stories.tsx +48 -0
  51. package/src/_stories/ChartBar.Editor.stories.tsx +499 -57
  52. package/src/_stories/ChartBrush.Editor.stories.tsx +46 -67
  53. package/src/_stories/ChartBrush.Regression.stories.tsx +135 -0
  54. package/src/_stories/ChartEditor.Editor.stories.tsx +33 -3
  55. package/src/_stories/ChartLine.EffectCompatibility.stories.tsx +120 -0
  56. package/src/_stories/_mock/annotation_event-line_mock.json +2 -2
  57. package/src/_stories/_mock/editor-test-configs.json +20 -10
  58. package/src/_stories/_mock/editor-test-datasets.json +38 -42
  59. package/src/_stories/_mock/heatmap-average-age-categorical.json +2 -2
  60. package/src/_stories/_mock/heatmap.json +2 -2
  61. package/src/_stories/_mock/legend-axis-align-stacked-bar.json +125 -0
  62. package/src/_stories/_mock/sankey_mock.json +23 -27
  63. package/src/components/Annotations/components/AnnotationDraggable.styles.css +52 -0
  64. package/src/components/Annotations/components/AnnotationDraggable.tsx +639 -139
  65. package/src/components/Annotations/components/AnnotationDropdown.styles.css +44 -4
  66. package/src/components/Annotations/components/AnnotationDropdown.tsx +10 -32
  67. package/src/components/Annotations/helpers/resolveAnnotationLayout.ts +212 -0
  68. package/src/components/Annotations/tests/AnnotationDraggable.test.tsx +612 -19
  69. package/src/components/Annotations/tests/AnnotationDropdown.test.tsx +50 -0
  70. package/src/components/Annotations/tests/resolveAnnotationLayout.test.ts +203 -0
  71. package/src/components/Axis/BottomAxis.tsx +1 -1
  72. package/src/components/Axis/Categorical.Axis.tsx +3 -3
  73. package/src/components/Axis/RightAxis.tsx +21 -13
  74. package/src/components/BarChart/components/BarChart.Horizontal.tsx +38 -6
  75. package/src/components/BarChart/components/BarChart.StackedHorizontal.tsx +12 -3
  76. package/src/components/BarChart/components/BarChart.StackedVertical.test.ts +28 -0
  77. package/src/components/BarChart/components/BarChart.StackedVertical.tsx +29 -25
  78. package/src/components/BarChart/components/BarChart.Vertical.tsx +37 -26
  79. package/src/components/BarChart/components/PortionPatternOverlay.tsx +61 -0
  80. package/src/components/BarChart/components/context.tsx +6 -0
  81. package/src/components/BarChart/helpers/getPatternUrl.ts +2 -5
  82. package/src/components/BarChart/helpers/index.ts +8 -0
  83. package/src/components/BarChart/helpers/portionPattern.ts +243 -0
  84. package/src/components/BarChart/helpers/tests/addMinimumBarHeights.test.ts +42 -0
  85. package/src/components/BarChart/helpers/tests/getPatternUrl.test.ts +13 -0
  86. package/src/components/BarChart/helpers/tests/portionPattern.test.ts +280 -0
  87. package/src/components/BarChart/helpers/tests/useBarChart.test.tsx +104 -0
  88. package/src/components/BarChart/helpers/useBarChart.ts +60 -59
  89. package/src/components/BarChartRace/BarChartRace.test.tsx +199 -0
  90. package/src/components/BarChartRace/BarChartRace.tsx +230 -0
  91. package/src/components/BarChartRace/BarChartRaceFallback.test.tsx +61 -0
  92. package/src/components/BarChartRace/BarChartRaceFallback.tsx +48 -0
  93. package/src/components/BarChartRace/bar-chart-race.css +160 -0
  94. package/src/components/BarChartRace/helpers.test.ts +114 -0
  95. package/src/components/BarChartRace/helpers.ts +185 -0
  96. package/src/components/BarChartRace/index.ts +3 -0
  97. package/src/components/BoxPlot/helpers/index.ts +11 -82
  98. package/src/components/Brush/BrushSelector.tsx +9 -23
  99. package/src/components/Brush/MiniChartPreview.tsx +33 -1
  100. package/src/components/Dendrogram/components/Dendrogram.tsx +374 -0
  101. package/src/components/Dendrogram/dendrogram.css +113 -0
  102. package/src/components/Dendrogram/helpers/layoutDendrogram.test.ts +95 -0
  103. package/src/components/Dendrogram/helpers/layoutDendrogram.ts +56 -0
  104. package/src/components/Dendrogram/helpers/prepareDendrogramData.test.ts +135 -0
  105. package/src/components/Dendrogram/helpers/prepareDendrogramData.ts +166 -0
  106. package/src/components/Dendrogram/helpers/resolveDendrogramLabels.test.ts +196 -0
  107. package/src/components/Dendrogram/helpers/resolveDendrogramLabels.ts +418 -0
  108. package/src/components/Dendrogram/index.tsx +1 -0
  109. package/src/components/Dendrogram/types/index.ts +66 -0
  110. package/src/components/EditorPanel/EditorPanel.tsx +1005 -760
  111. package/src/components/EditorPanel/components/Panels/Panel.Annotate.tsx +50 -5
  112. package/src/components/EditorPanel/components/Panels/Panel.Dendrogram.css +10 -0
  113. package/src/components/EditorPanel/components/Panels/Panel.Dendrogram.tsx +211 -0
  114. package/src/components/EditorPanel/components/Panels/Panel.ForestPlotSettings.tsx +19 -8
  115. package/src/components/EditorPanel/components/Panels/Panel.General.tsx +88 -54
  116. package/src/components/EditorPanel/components/Panels/Panel.Network.css +9 -0
  117. package/src/components/EditorPanel/components/Panels/Panel.Network.tsx +202 -0
  118. package/src/components/EditorPanel/components/Panels/Panel.PatternSettings.tsx +233 -33
  119. package/src/components/EditorPanel/components/Panels/Panel.Radar.tsx +6 -1
  120. package/src/components/EditorPanel/components/Panels/Panel.Sankey.tsx +89 -105
  121. package/src/components/EditorPanel/components/Panels/Panel.Series.tsx +2 -2
  122. package/src/components/EditorPanel/components/Panels/Panel.SmallMultiples.tsx +1 -1
  123. package/src/components/EditorPanel/components/Panels/Panel.Visual.tsx +8 -66
  124. package/src/components/EditorPanel/components/Panels/RacingControls.test.tsx +131 -0
  125. package/src/components/EditorPanel/components/Panels/RacingControls.tsx +185 -0
  126. package/src/components/EditorPanel/components/Panels/SeriesColorAssignments.tsx +2 -2
  127. package/src/components/EditorPanel/components/Panels/index.tsx +4 -0
  128. package/src/components/EditorPanel/helpers/getVisualizationTypeConfigUpdate.ts +20 -7
  129. package/src/components/EditorPanel/helpers/tests/getVisualizationTypeConfigUpdate.test.ts +25 -2
  130. package/src/components/EditorPanel/helpers/updateFieldRankByValue.ts +2 -1
  131. package/src/components/EditorPanel/useEditorPermissions.test.tsx +62 -0
  132. package/src/components/EditorPanel/useEditorPermissions.ts +70 -24
  133. package/src/components/Forecasting/Forecasting.tsx +15 -6
  134. package/src/components/HeatMap/components/HeatMap.tsx +511 -178
  135. package/src/components/HeatMap/heatmap.constants.ts +7 -3
  136. package/src/components/HeatMap/heatmap.css +101 -2
  137. package/src/components/HeatMap/helpers/layout.ts +80 -0
  138. package/src/components/HeatMap/tests/HeatMap.test.tsx +339 -16
  139. package/src/components/HeatMap/tests/helpers.test.ts +79 -0
  140. package/src/components/Legend/Legend.Component.tsx +110 -90
  141. package/src/components/Legend/LegendGroup/LegendGroup.styles.css +7 -0
  142. package/src/components/Legend/LegendGroup/LegendGroup.tsx +47 -34
  143. package/src/components/Legend/helpers/createFormatLabels.test.ts +226 -0
  144. package/src/components/Legend/helpers/createFormatLabels.tsx +45 -51
  145. package/src/components/LineChart/components/LineChart.Circle.tsx +3 -3
  146. package/src/components/LineChart/helpers.test.ts +126 -38
  147. package/src/components/LineChart/helpers.ts +9 -4
  148. package/src/components/LineChart/index.tsx +69 -24
  149. package/src/components/LineChart/tests/LineChart.test.tsx +630 -0
  150. package/src/components/LineChartRace/LineChartRace.test.tsx +275 -0
  151. package/src/components/LineChartRace/LineChartRace.tsx +134 -0
  152. package/src/components/LineChartRace/LineChartRaceFallback.tsx +28 -0
  153. package/src/components/LineChartRace/helpers.test.ts +88 -0
  154. package/src/components/LineChartRace/helpers.ts +157 -0
  155. package/src/components/LineChartRace/index.ts +3 -0
  156. package/src/components/LineChartRace/line-chart-race.css +16 -0
  157. package/src/components/LinearChart/ValueAxisAnchors.tsx +58 -0
  158. package/src/components/LinearChart/VisualizationRenderer.tsx +18 -23
  159. package/src/components/LinearChart/tests/LinearChart.test.tsx +412 -13
  160. package/src/components/LinearChart/tests/VisualizationRenderer.test.tsx +141 -0
  161. package/src/components/LinearChart/tests/mockConfigContext.ts +2 -1
  162. package/src/components/LinearChart.tsx +81 -51
  163. package/src/components/Network/components/Network.tsx +372 -0
  164. package/src/components/Network/helpers/layoutNetwork.test.ts +68 -0
  165. package/src/components/Network/helpers/layoutNetwork.ts +87 -0
  166. package/src/components/Network/helpers/prepareNetworkData.test.ts +116 -0
  167. package/src/components/Network/helpers/prepareNetworkData.ts +101 -0
  168. package/src/components/Network/helpers/resolveNetworkLabels.test.ts +112 -0
  169. package/src/components/Network/helpers/resolveNetworkLabels.ts +206 -0
  170. package/src/components/Network/index.tsx +3 -0
  171. package/src/components/Network/network.css +107 -0
  172. package/src/components/Network/types/index.ts +56 -0
  173. package/src/components/PairedBarChart.jsx +5 -10
  174. package/src/components/PairedBarChart.test.tsx +71 -0
  175. package/src/components/PieChart/PieChart.tsx +9 -8
  176. package/src/components/RacingChartRenderer.tsx +44 -0
  177. package/src/components/Regions/components/Regions.test.tsx +179 -0
  178. package/src/components/Regions/components/Regions.tsx +104 -69
  179. package/src/components/Regions/index.tsx +2 -3
  180. package/src/components/Sankey/components/Sankey.tsx +264 -437
  181. package/src/components/Sankey/helpers/getSankeyTooltip.ts +12 -0
  182. package/src/components/Sankey/helpers/prepareSankeyData.test.ts +71 -0
  183. package/src/components/Sankey/helpers/prepareSankeyData.ts +90 -0
  184. package/src/components/Sankey/sankey.scss +57 -116
  185. package/src/components/Sankey/types/index.ts +41 -4
  186. package/src/components/ScatterPlot/ScatterPlot.jsx +28 -4
  187. package/src/components/ScatterPlot/ScatterPlot.test.tsx +60 -0
  188. package/src/components/SmallMultiples/SmallMultiples.tsx +12 -12
  189. package/src/components/SmallMultiples/tests/SmallMultipleTile.test.tsx +7 -5
  190. package/src/components/raceTiming.ts +18 -0
  191. package/src/data/initial-state.js +77 -31
  192. package/src/helpers/applyChartTypeContract.ts +71 -0
  193. package/src/helpers/axisLabelFontSize.ts +2 -2
  194. package/src/helpers/boxPlotStats.ts +60 -0
  195. package/src/helpers/bumpChartTooltip.ts +2 -1
  196. package/src/helpers/calculateHorizontalBarCategoryLabelWidth.test.ts +37 -0
  197. package/src/helpers/calculateHorizontalBarCategoryLabelWidth.ts +3 -2
  198. package/src/helpers/calculateRightYAxisWidth.ts +60 -0
  199. package/src/helpers/colorAssignmentHelpers.ts +2 -2
  200. package/src/helpers/createNewChartConfig.ts +56 -0
  201. package/src/helpers/dataDrivenYAxisCategories.ts +18 -0
  202. package/src/helpers/forecastLegend.ts +88 -0
  203. package/src/helpers/getBoxPlotConfig.ts +18 -37
  204. package/src/helpers/getChartTypeDefaultPalette.ts +29 -0
  205. package/src/helpers/getColorCodeCategoryColorMap.ts +26 -0
  206. package/src/helpers/getColorScale.ts +31 -22
  207. package/src/helpers/getDynamicYAxisCategories.ts +69 -0
  208. package/src/helpers/getMinMax.ts +9 -7
  209. package/src/helpers/getNewRuntime.ts +5 -2
  210. package/src/helpers/getStackedSeriesMax.ts +51 -0
  211. package/src/helpers/getV21ChartDistributionColors.ts +57 -0
  212. package/src/helpers/handleRankByValue.ts +15 -15
  213. package/src/helpers/seriesColumnSettings.ts +10 -0
  214. package/src/helpers/sizeHelpers.ts +4 -3
  215. package/src/helpers/smallMultiplesHelpers.ts +10 -13
  216. package/src/helpers/tests/applyChartTypeContract.test.ts +37 -0
  217. package/src/helpers/tests/boxPlotStats.test.ts +31 -0
  218. package/src/helpers/tests/bumpChartTooltip.test.ts +29 -0
  219. package/src/helpers/tests/calculateRightYAxisWidth.test.ts +105 -0
  220. package/src/helpers/tests/countNumOfTicks.test.ts +11 -0
  221. package/src/helpers/tests/createNewChartConfig.test.ts +182 -0
  222. package/src/helpers/tests/getBoxPlotConfig.test.ts +70 -0
  223. package/src/helpers/tests/getColorCodeCategoryColorMap.test.ts +113 -0
  224. package/src/helpers/tests/getColorScale.test.ts +226 -1
  225. package/src/helpers/tests/getDynamicYAxisCategories.test.ts +61 -0
  226. package/src/helpers/tests/getMinMax.test.ts +41 -0
  227. package/src/helpers/tests/getStackedSeriesMax.test.ts +26 -0
  228. package/src/helpers/tests/handleRankByValue.test.ts +55 -37
  229. package/src/helpers/tests/seriesColumnSettings.test.ts +23 -0
  230. package/src/helpers/tests/smallMultiplesHelpers.test.ts +37 -1
  231. package/src/helpers/tests/tooltipHelpers.test.ts +80 -0
  232. package/src/helpers/tooltipHelpers.ts +16 -0
  233. package/src/hooks/tests/useTooltip.test.tsx +353 -1
  234. package/src/hooks/usePrefersReducedMotion.ts +22 -0
  235. package/src/hooks/useReduceData.ts +4 -36
  236. package/src/hooks/useScales.ts +15 -0
  237. package/src/hooks/useTooltip.tsx +95 -64
  238. package/src/scss/main.scss +74 -2
  239. package/src/store/chart.reducer.ts +4 -3
  240. package/src/test/CdcChart.dataTable.test.tsx +490 -16
  241. package/src/test/CdcChart.dendrogram.test.tsx +277 -0
  242. package/src/test/CdcChart.finalization.test.tsx +143 -0
  243. package/src/test/CdcChart.network.test.tsx +271 -0
  244. package/src/types/ChartConfig.ts +91 -54
  245. package/src/types/ChartContext.ts +5 -0
  246. package/src/types/Horizon.ts +1 -1
  247. package/LICENSE +0 -201
  248. package/dist/cdcchart-BWVIUcAF.es.js +0 -4802
  249. package/src/_stories/Chart.Sankey.smoke.stories.tsx +0 -62
  250. package/src/components/Sankey/components/ColumnList.tsx +0 -19
  251. package/src/components/Sankey/helpers/getSankeyTooltip.tsx +0 -34
  252. package/src/components/Sankey/useSankeyAlert.tsx +0 -60
  253. package/src/data/legacy-defaults.ts +0 -18
  254. package/src/helpers/ensureSpecialChartAxisTypes.ts +0 -11
  255. package/src/helpers/tests/ensureSpecialChartAxisTypes.test.ts +0 -30
@@ -9,6 +9,7 @@ import Accordion from '@cdc/core/components/ui/Accordion'
9
9
  import Button from '@cdc/core/components/elements/Button'
10
10
  import GroupedList from '@cdc/core/components/EditorPanel/GroupedList'
11
11
  import Icon from '@cdc/core/components/ui/Icon'
12
+ import Tooltip from '@cdc/core/components/ui/Tooltip'
12
13
  import { CheckBox, Select } from '@cdc/core/components/EditorPanel/Inputs'
13
14
  import cloneDeep from 'lodash/cloneDeep'
14
15
  import {
@@ -74,11 +75,6 @@ const PanelAnnotate: React.FC<PanelProps> = props => {
74
75
  mobile: true
75
76
  },
76
77
  connectorType: 'line',
77
- colors: {
78
- label: 'black',
79
- connector: 'black',
80
- marker: 'black'
81
- },
82
78
  selected: true,
83
79
  anchor: {
84
80
  vertical: false,
@@ -94,6 +90,7 @@ const PanelAnnotate: React.FC<PanelProps> = props => {
94
90
  y: 50,
95
91
  dx: 20,
96
92
  dy: -20,
93
+ autoSide: 'right',
97
94
  opacity: '100',
98
95
  connectionType: 'line'
99
96
  }
@@ -237,6 +234,9 @@ const PanelAnnotate: React.FC<PanelProps> = props => {
237
234
 
238
235
  if (value === 'event-line') {
239
236
  target.anchorMode = 'data'
237
+ if (target.labelPosition === 'above' || target.labelPosition === 'below') {
238
+ target.labelPosition = 'auto'
239
+ }
240
240
  if (!target.dataX) {
241
241
  target.dataX = transformedData?.[0]?.[config.xAxis.dataKey] || ''
242
242
  }
@@ -256,6 +256,51 @@ const PanelAnnotate: React.FC<PanelProps> = props => {
256
256
  }}
257
257
  />
258
258
 
259
+ <Select
260
+ label='Label Side:'
261
+ tooltip={
262
+ <Tooltip style={{ textTransform: 'none' }}>
263
+ <Tooltip.Target>
264
+ <Icon display='question' style={{ marginLeft: '0.5rem' }} />
265
+ </Tooltip.Target>
266
+ <Tooltip.Content>
267
+ <p>The side of the annotation target where the label appears.</p>
268
+ </Tooltip.Content>
269
+ </Tooltip>
270
+ }
271
+ value={annotation.labelPosition || 'auto'}
272
+ options={
273
+ annotation.style === 'event-line'
274
+ ? [
275
+ { value: 'auto', label: 'Automatic' },
276
+ { value: 'left', label: 'Left' },
277
+ { value: 'right', label: 'Right' }
278
+ ]
279
+ : [
280
+ { value: 'auto', label: 'Automatic' },
281
+ { value: 'left', label: 'Left' },
282
+ { value: 'right', label: 'Right' },
283
+ { value: 'above', label: 'Above' },
284
+ { value: 'below', label: 'Below' }
285
+ ]
286
+ }
287
+ section='annotations'
288
+ subsection={null}
289
+ fieldName='labelPosition'
290
+ updateField={(section, subsection, fieldName, value) => {
291
+ const updatedAnnotations = cloneDeep(config?.annotations)
292
+ const target = updatedAnnotations[index]
293
+ target.labelPosition = value
294
+ if (target.style === 'event-line' && value === 'left') {
295
+ target.dx = -EVENT_LINE_LABEL_OFFSET
296
+ }
297
+ if (target.style === 'event-line' && value === 'right') {
298
+ target.dx = EVENT_LINE_LABEL_OFFSET
299
+ }
300
+ updateConfig({ ...config, annotations: updatedAnnotations })
301
+ }}
302
+ />
303
+
259
304
  {visSupportsDataAnnotations() && annotation.style !== 'event-line' && (
260
305
  <Select
261
306
  label='Position Mode:'
@@ -0,0 +1,10 @@
1
+ .dendrogram-settings__range {
2
+ display: block;
3
+ margin-bottom: 1rem;
4
+ width: 100%;
5
+ }
6
+
7
+ .dendrogram-settings__range input[type='range'] {
8
+ display: block;
9
+ width: 100%;
10
+ }
@@ -0,0 +1,211 @@
1
+ import { useContext, type FC } from 'react'
2
+ import {
3
+ AccordionItem,
4
+ AccordionItemButton,
5
+ AccordionItemHeading,
6
+ AccordionItemPanel
7
+ } from 'react-accessible-accordion'
8
+ import { Select, TextField } from '@cdc/core/components/EditorPanel/Inputs'
9
+
10
+ import ConfigContext from '../../../../ConfigContext'
11
+ import type { ChartContext } from '../../../../types/ChartContext'
12
+ import { useEditorPanelContext } from '../../EditorPanelContext'
13
+ import type { PanelProps } from '../PanelProps'
14
+ import WarningImage from '../../../../images/warning.svg'
15
+ import './Panel.Dendrogram.css'
16
+
17
+ const DendrogramSettings: FC<PanelProps> = ({ name }) => {
18
+ const { config, updateConfig } = useContext<ChartContext>(ConfigContext)
19
+ const { getColumns } = useEditorPanelContext()
20
+
21
+ if (config.visualizationType !== 'Dendrogram') return null
22
+
23
+ const dendrogram = config.dendrogram || ({} as NonNullable<typeof config.dendrogram>)
24
+ const columns = dendrogram.columns || { node: '', parent: '', style: '', nodeColor: '' }
25
+ const columnOptions = getColumns?.(false) || []
26
+ const isMissingColumn = (column: unknown) =>
27
+ !column || (columnOptions.length > 0 && !columnOptions.includes(String(column)))
28
+
29
+ const updateColumn = (_section: string, _subsection: string, fieldName: string, value: string) => {
30
+ updateConfig?.({
31
+ ...config,
32
+ dendrogram: { ...dendrogram, columns: { ...columns, [fieldName]: value } }
33
+ })
34
+ }
35
+
36
+ const updateLinkStyleLabel = (_section: string, _subsection: string, fieldName: string, value: string) => {
37
+ updateConfig?.({
38
+ ...config,
39
+ dendrogram: {
40
+ ...dendrogram,
41
+ linkStyleLabels: {
42
+ solid: dendrogram.linkStyleLabels?.solid ?? 'Solid',
43
+ dashed: dendrogram.linkStyleLabels?.dashed ?? 'Dashed',
44
+ [fieldName]: value
45
+ }
46
+ }
47
+ })
48
+ }
49
+
50
+ const updateDendrogramField = (_section: string, _subsection: string, fieldName: string, value: string | boolean) => {
51
+ const numericFields = ['height', 'nodeRadius', 'leafSpacing', 'depthSpacing']
52
+ const numericDefaults: Record<string, number> = { height: 500, nodeRadius: 6, leafSpacing: 40, depthSpacing: 140 }
53
+ updateConfig?.({
54
+ ...config,
55
+ dendrogram: {
56
+ ...dendrogram,
57
+ [fieldName]: numericFields.includes(fieldName)
58
+ ? value === ''
59
+ ? numericDefaults[fieldName]
60
+ : Number(value)
61
+ : value
62
+ }
63
+ })
64
+ }
65
+
66
+ return (
67
+ <AccordionItem>
68
+ <AccordionItemHeading>
69
+ <AccordionItemButton data-required-field-section='dendrogram-columns'>
70
+ {name}
71
+ {(isMissingColumn(columns.node) || isMissingColumn(columns.parent)) && (
72
+ <WarningImage width='25' className='warning-icon' />
73
+ )}
74
+ </AccordionItemButton>
75
+ </AccordionItemHeading>
76
+ <AccordionItemPanel>
77
+ <Select
78
+ value={columns.node || ''}
79
+ section='dendrogram'
80
+ subsection='columns'
81
+ fieldName='node'
82
+ label='Node ID Column'
83
+ data-required-field-control='dendrogram-node'
84
+ initial='Select'
85
+ required
86
+ updateField={updateColumn}
87
+ options={columnOptions}
88
+ />
89
+ <Select
90
+ value={columns.parent || ''}
91
+ section='dendrogram'
92
+ subsection='columns'
93
+ fieldName='parent'
94
+ label='Parent ID Column'
95
+ data-required-field-control='dendrogram-parent'
96
+ initial='Select'
97
+ required
98
+ updateField={updateColumn}
99
+ options={columnOptions}
100
+ />
101
+ <Select
102
+ value={columns.style || ''}
103
+ section='dendrogram'
104
+ subsection='columns'
105
+ fieldName='style'
106
+ label='Link Style Column (Optional)'
107
+ initial='None'
108
+ updateField={updateColumn}
109
+ options={columnOptions}
110
+ />
111
+ <TextField
112
+ value={dendrogram.linkStyleLabels?.solid ?? 'Solid'}
113
+ section='dendrogram'
114
+ subsection='linkStyleLabels'
115
+ fieldName='solid'
116
+ label='Solid Link Legend Label'
117
+ updateField={updateLinkStyleLabel}
118
+ />
119
+ <TextField
120
+ value={dendrogram.linkStyleLabels?.dashed ?? 'Dashed'}
121
+ section='dendrogram'
122
+ subsection='linkStyleLabels'
123
+ fieldName='dashed'
124
+ label='Dashed Link Legend Label'
125
+ updateField={updateLinkStyleLabel}
126
+ />
127
+ <Select
128
+ value={columns.nodeColor || ''}
129
+ section='dendrogram'
130
+ subsection='columns'
131
+ fieldName='nodeColor'
132
+ label='Node Color Column (Optional)'
133
+ initial='None'
134
+ updateField={updateColumn}
135
+ options={columnOptions}
136
+ />
137
+ <Select
138
+ value={dendrogram.orientation || 'horizontal'}
139
+ section='dendrogram'
140
+ fieldName='orientation'
141
+ label='Orientation'
142
+ updateField={updateDendrogramField}
143
+ options={[
144
+ { value: 'horizontal', label: 'Horizontal' },
145
+ { value: 'vertical', label: 'Vertical' }
146
+ ]}
147
+ />
148
+ <Select
149
+ value={['curve', 'line', 'elbow'].includes(dendrogram.connectionType) ? dendrogram.connectionType : 'curve'}
150
+ section='dendrogram'
151
+ fieldName='connectionType'
152
+ label='Connection Type'
153
+ updateField={updateDendrogramField}
154
+ options={[
155
+ { value: 'curve', label: 'Curved' },
156
+ { value: 'line', label: 'Straight' },
157
+ { value: 'elbow', label: 'Elbow' }
158
+ ]}
159
+ />
160
+ <TextField
161
+ value={dendrogram.height ?? 500}
162
+ type='number'
163
+ section='dendrogram'
164
+ fieldName='height'
165
+ label='Height'
166
+ min={160}
167
+ updateField={updateDendrogramField}
168
+ />
169
+ <TextField
170
+ value={dendrogram.nodeRadius ?? 6}
171
+ type='number'
172
+ section='dendrogram'
173
+ fieldName='nodeRadius'
174
+ label='Node Radius'
175
+ min={2}
176
+ updateField={updateDendrogramField}
177
+ />
178
+ <label className='dendrogram-settings__range'>
179
+ <span className='edit-label column-heading'>
180
+ Leaf Spacing: <output>{dendrogram.leafSpacing ?? 40}</output>
181
+ </span>
182
+ <input
183
+ type='range'
184
+ aria-label='Leaf Spacing'
185
+ min={20}
186
+ max={120}
187
+ step={5}
188
+ value={dendrogram.leafSpacing ?? 40}
189
+ onChange={event => updateDendrogramField('dendrogram', '', 'leafSpacing', event.target.value)}
190
+ />
191
+ </label>
192
+ <label className='dendrogram-settings__range'>
193
+ <span className='edit-label column-heading'>
194
+ Depth Spacing: <output>{dendrogram.depthSpacing ?? 140}</output>
195
+ </span>
196
+ <input
197
+ type='range'
198
+ aria-label='Depth Spacing'
199
+ min={60}
200
+ max={300}
201
+ step={10}
202
+ value={dendrogram.depthSpacing ?? 140}
203
+ onChange={event => updateDendrogramField('dendrogram', '', 'depthSpacing', event.target.value)}
204
+ />
205
+ </label>
206
+ </AccordionItemPanel>
207
+ </AccordionItem>
208
+ )
209
+ }
210
+
211
+ export default DendrogramSettings
@@ -26,6 +26,10 @@ const ForestPlotSettings: FC<PanelProps> = ({ name }) => {
26
26
  const { getColumns } = useEditorPanelContext()
27
27
  if (config.visualizationType !== 'Forest Plot') return
28
28
 
29
+ const columnOptions = getColumns(false)
30
+ const isMissingColumn = (column: unknown) =>
31
+ !column || (columnOptions.length > 0 && !columnOptions.includes(String(column)))
32
+
29
33
  const enforceRestrictions = updatedConfig => {
30
34
  if (updatedConfig.orientation === 'horizontal') {
31
35
  updatedConfig.labels = false
@@ -130,11 +134,13 @@ const ForestPlotSettings: FC<PanelProps> = ({ name }) => {
130
134
  return (
131
135
  <AccordionItem>
132
136
  <AccordionItemHeading>
133
- <AccordionItemButton>
137
+ <AccordionItemButton data-required-field-section='forest-plot-settings'>
134
138
  {name}
135
- {(!config.forestPlot.estimateField || !config.forestPlot.upper || !config.forestPlot.lower) && (
136
- <WarningImage width='25' className='warning-icon' />
137
- )}
139
+ {(isMissingColumn(config.xAxis?.dataKey) ||
140
+ !config.forestPlot.type ||
141
+ isMissingColumn(config.forestPlot.estimateField) ||
142
+ isMissingColumn(config.forestPlot.upper) ||
143
+ isMissingColumn(config.forestPlot.lower)) && <WarningImage width='25' className='warning-icon' />}
138
144
  </AccordionItemButton>
139
145
  </AccordionItemHeading>
140
146
  <AccordionItemPanel>
@@ -143,10 +149,11 @@ const ForestPlotSettings: FC<PanelProps> = ({ name }) => {
143
149
  section='xAxis'
144
150
  fieldName='dataKey'
145
151
  label='Study Column'
152
+ data-required-field-control='forest-study'
146
153
  initial='Select'
147
154
  required={true}
148
155
  updateField={updateField}
149
- options={getColumns(false)}
156
+ options={columnOptions}
150
157
  tooltip={
151
158
  <Tooltip style={{ textTransform: 'none' }}>
152
159
  <Tooltip.Target>
@@ -161,6 +168,7 @@ const ForestPlotSettings: FC<PanelProps> = ({ name }) => {
161
168
  <Select
162
169
  value={config.forestPlot.type}
163
170
  label='Forest Plot Type'
171
+ data-required-field-control='forest-type'
164
172
  initial={'Select'}
165
173
  required={true}
166
174
  onChange={e => {
@@ -209,6 +217,7 @@ const ForestPlotSettings: FC<PanelProps> = ({ name }) => {
209
217
  <Select
210
218
  value={config.forestPlot.estimateField}
211
219
  label='Point Estimate Column'
220
+ data-required-field-control='forest-estimate'
212
221
  initial={config.forestPlot.estimateField || 'Select'}
213
222
  required={true}
214
223
  onChange={e => {
@@ -223,7 +232,7 @@ const ForestPlotSettings: FC<PanelProps> = ({ name }) => {
223
232
  }
224
233
  e.target.value = ''
225
234
  }}
226
- options={getColumns(false)}
235
+ options={columnOptions}
227
236
  />
228
237
 
229
238
  <Select
@@ -247,6 +256,7 @@ const ForestPlotSettings: FC<PanelProps> = ({ name }) => {
247
256
  <Select
248
257
  value={config.forestPlot.lower}
249
258
  label='Lower CI Column'
259
+ data-required-field-control='forest-lower'
250
260
  required={true}
251
261
  initial={config.forestPlot.lower || 'Select'}
252
262
  onChange={e => {
@@ -261,12 +271,13 @@ const ForestPlotSettings: FC<PanelProps> = ({ name }) => {
261
271
  }
262
272
  e.target.value = ''
263
273
  }}
264
- options={getColumns(false)}
274
+ options={columnOptions}
265
275
  />
266
276
 
267
277
  <Select
268
278
  value={config.forestPlot.upper}
269
279
  label='Upper CI Column'
280
+ data-required-field-control='forest-upper'
270
281
  initial={config.forestPlot.upper || 'Select'}
271
282
  required={true}
272
283
  onChange={e => {
@@ -281,7 +292,7 @@ const ForestPlotSettings: FC<PanelProps> = ({ name }) => {
281
292
  }
282
293
  e.target.value = ''
283
294
  }}
284
- options={getColumns(false)}
295
+ options={columnOptions}
285
296
  />
286
297
 
287
298
  <label>
@@ -22,6 +22,7 @@ import ConfigContext from '../../../../ConfigContext.js'
22
22
  import { PanelProps } from '../PanelProps'
23
23
  import { getVisualizationTypeConfigUpdate } from '../../helpers/getVisualizationTypeConfigUpdate'
24
24
  import { type VisualizationType } from '../../../../types/ChartConfig'
25
+ import RacingControls from './RacingControls'
25
26
 
26
27
  const PanelGeneral: FC<PanelProps> = props => {
27
28
  const { config, updateConfig } = useContext(ConfigContext)
@@ -66,6 +67,34 @@ const PanelGeneral: FC<PanelProps> = props => {
66
67
  })
67
68
  }
68
69
 
70
+ const handleOrientationChange = event => {
71
+ const orientation = event.target.value
72
+ const isHorizontal = orientation === 'horizontal'
73
+ const prevXAnchors = config.xAxis?.anchors?.length > 0 ? config.xAxis.anchors : []
74
+ const prevYAnchors = config.yAxis?.anchors?.length > 0 ? config.yAxis.anchors : []
75
+
76
+ updateConfig({
77
+ ...config,
78
+ orientation,
79
+ ...(orientation === 'horizontal' ? { labels: false } : {}),
80
+ xAxis: {
81
+ ...config.xAxis,
82
+ anchors: prevYAnchors,
83
+ hideAxis: isHorizontal,
84
+ hideTicks: isHorizontal
85
+ },
86
+ yAxis: {
87
+ ...config.yAxis,
88
+ anchors: prevXAnchors,
89
+ hideAxis: !isHorizontal,
90
+ hideTicks: !isHorizontal,
91
+ ...(orientation === 'horizontal' && !config.yAxis?.labelPlacement
92
+ ? { labelPlacement: 'On Date/Category Axis' }
93
+ : {})
94
+ }
95
+ })
96
+ }
97
+
69
98
  return (
70
99
  <AccordionItem>
71
100
  {' '}
@@ -74,7 +103,7 @@ const PanelGeneral: FC<PanelProps> = props => {
74
103
  <AccordionItemButton>General</AccordionItemButton>
75
104
  </AccordionItemHeading>
76
105
  <AccordionItemPanel>
77
- {config?.visualizationType !== 'Sankey' && (
106
+ {!['Sankey', 'Network', 'Dendrogram'].includes(config?.visualizationType) && (
78
107
  <Select
79
108
  value={visualizationType}
80
109
  fieldName='visualizationType'
@@ -140,14 +169,8 @@ const PanelGeneral: FC<PanelProps> = props => {
140
169
  )}
141
170
  </div>
142
171
  )}
143
- {(visualizationType === 'Bar' || visualizationType === 'Combo') && (
144
- <Select
145
- value={visualizationSubType || 'Regular'}
146
- fieldName='visualizationSubType'
147
- label='Chart Subtype'
148
- updateField={updateField}
149
- options={['regular', 'stacked']}
150
- />
172
+ {(visualizationType === 'Bar' || visualizationType === 'Combo' || visualizationType === 'Line') && (
173
+ <RacingControls />
151
174
  )}
152
175
  {visualizationType === 'Area Chart' && visualizationSubType === 'stacked' && (
153
176
  <Select
@@ -158,56 +181,61 @@ const PanelGeneral: FC<PanelProps> = props => {
158
181
  options={Object.keys(approvedCurveTypes)}
159
182
  />
160
183
  )}
161
- {(visualizationType === 'Bar' || visualizationType === 'Box Plot') && (
184
+ {(visualizationType === 'Bar' || visualizationType === 'Box Plot') && visualizationSubType !== 'racing' && (
162
185
  <Select
163
186
  value={config.orientation || 'vertical'}
164
187
  fieldName='orientation'
165
188
  label='Orientation'
166
- updateField={updateField}
189
+ onChange={handleOrientationChange}
167
190
  options={['vertical', 'horizontal']}
168
191
  />
169
192
  )}
170
193
  {visualizationType === 'Deviation Bar' && <Select label='Orientation' options={['horizontal']} />}
171
- {(visualizationType === 'Bar' || visualizationType === 'Deviation Bar') && (
172
- <Select
173
- value={config.isLollipopChart ? 'lollipop' : barStyle || 'flat'}
174
- fieldName='barStyle'
175
- label='bar style'
176
- updateField={updateField}
177
- options={showBarStyleOptions()}
178
- tooltip={
179
- <Tooltip style={{ textTransform: 'none' }}>
180
- <Tooltip.Target>
181
- <Icon display='question' style={{ marginLeft: '0.5rem' }} />
182
- </Tooltip.Target>
183
- <Tooltip.Content>
184
- <p>Consider using the 'Flat' bar style when presenting data that includes '0' values.</p>
185
- </Tooltip.Content>
186
- </Tooltip>
187
- }
188
- />
189
- )}
190
- {(visualizationType === 'Bar' || visualizationType === 'Deviation Bar') && barStyle === 'rounded' && (
191
- <Select
192
- value={config.tipRounding || 'top'}
193
- fieldName='tipRounding'
194
- label='tip rounding'
195
- updateField={updateField}
196
- options={['top', 'full']}
197
- />
198
- )}
199
- {(visualizationType === 'Bar' || visualizationType === 'Deviation Bar') && barStyle === 'rounded' && (
200
- <Select
201
- value={config.roundingStyle || 'standard'}
202
- fieldName='roundingStyle'
203
- label='rounding style'
204
- updateField={updateField}
205
- options={['standard', 'shallow', 'finger']}
206
- />
207
- )}
194
+ {(visualizationType === 'Bar' || visualizationType === 'Deviation Bar') &&
195
+ visualizationSubType !== 'racing' && (
196
+ <Select
197
+ value={config.isLollipopChart ? 'lollipop' : barStyle || 'flat'}
198
+ fieldName='barStyle'
199
+ label='bar style'
200
+ updateField={updateField}
201
+ options={showBarStyleOptions()}
202
+ tooltip={
203
+ <Tooltip style={{ textTransform: 'none' }}>
204
+ <Tooltip.Target>
205
+ <Icon display='question' style={{ marginLeft: '0.5rem' }} />
206
+ </Tooltip.Target>
207
+ <Tooltip.Content>
208
+ <p>Consider using the 'Flat' bar style when presenting data that includes '0' values.</p>
209
+ </Tooltip.Content>
210
+ </Tooltip>
211
+ }
212
+ />
213
+ )}
214
+ {(visualizationType === 'Bar' || visualizationType === 'Deviation Bar') &&
215
+ visualizationSubType !== 'racing' &&
216
+ barStyle === 'rounded' && (
217
+ <Select
218
+ value={config.tipRounding || 'top'}
219
+ fieldName='tipRounding'
220
+ label='tip rounding'
221
+ updateField={updateField}
222
+ options={['top', 'full']}
223
+ />
224
+ )}
225
+ {(visualizationType === 'Bar' || visualizationType === 'Deviation Bar') &&
226
+ visualizationSubType !== 'racing' &&
227
+ barStyle === 'rounded' && (
228
+ <Select
229
+ value={config.roundingStyle || 'standard'}
230
+ fieldName='roundingStyle'
231
+ label='rounding style'
232
+ updateField={updateField}
233
+ options={['standard', 'shallow', 'finger']}
234
+ />
235
+ )}
208
236
  {(visualizationType === 'Bar' || visualizationType === 'Box Plot') && config.orientation === 'horizontal' && (
209
237
  <Select
210
- value={config.yAxis.labelPlacement || 'Below Bar'}
238
+ value={config.yAxis.labelPlacement || 'On Date/Category Axis'}
211
239
  section='yAxis'
212
240
  fieldName='labelPlacement'
213
241
  label='Label Placement'
@@ -449,7 +477,7 @@ const PanelGeneral: FC<PanelProps> = props => {
449
477
  {visualizationType === 'Pie' && (
450
478
  <Select fieldName='pieType' label='Pie Chart Type' updateField={updateField} options={['Regular', 'Donut']} />
451
479
  )}
452
- {visualizationType === 'Line' && (
480
+ {visualizationType === 'Line' && visualizationSubType !== 'racing' && (
453
481
  <CheckBox
454
482
  value={config.allowLineToBarGraph}
455
483
  fieldName='allowLineToBarGraph'
@@ -529,7 +557,11 @@ const PanelGeneral: FC<PanelProps> = props => {
529
557
  <Icon display='question' style={{ marginLeft: '0.5rem' }} />
530
558
  </Tooltip.Target>
531
559
  <Tooltip.Content>
532
- <p>Super Title</p>
560
+ <p>
561
+ To keep the main title as short as possible, consider adding extra details in a super title, which
562
+ displays in small font just above the main title in the visualization’s title bar. (If you hide the
563
+ regular title, the super title does not display.)
564
+ </p>
533
565
  </Tooltip.Content>
534
566
  </Tooltip>
535
567
  }
@@ -548,7 +580,10 @@ const PanelGeneral: FC<PanelProps> = props => {
548
580
  <Icon display='question' style={{ marginLeft: '0.5rem' }} />
549
581
  </Tooltip.Target>
550
582
  <Tooltip.Content>
551
- <p>Intro Text</p>
583
+ <p>
584
+ Explain how to use the chart, introduce any special concepts, etc. This text displays above the
585
+ visualization (and below the title bar, if displayed).
586
+ </p>
552
587
  </Tooltip.Content>
553
588
  </Tooltip>
554
589
  }
@@ -589,8 +624,7 @@ const PanelGeneral: FC<PanelProps> = props => {
589
624
  </Tooltip.Target>
590
625
  <Tooltip.Content>
591
626
  <p>
592
- Consider adding footnotes when displaying 'suppressed,' 'no data,' and 'zero values' to ensure
593
- accurate interpretation of the data.
627
+ Use this text element for any supplemental information that should display below the data table.
594
628
  </p>
595
629
  </Tooltip.Content>
596
630
  </Tooltip>
@@ -0,0 +1,9 @@
1
+ .network-settings__range {
2
+ display: block;
3
+ width: 100%;
4
+ }
5
+
6
+ .network-settings__range input[type='range'] {
7
+ display: block;
8
+ width: 100%;
9
+ }