@cdc/chart 4.24.9 → 4.24.11

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 (95) hide show
  1. package/LICENSE +201 -0
  2. package/dist/cdcchart.js +45911 -41739
  3. package/examples/feature/boxplot/boxplot-data.json +88 -22
  4. package/examples/feature/boxplot/boxplot.json +540 -16
  5. package/examples/feature/boxplot/testing.csv +7 -7
  6. package/examples/feature/sankey/sankey-example-data.json +0 -1
  7. package/examples/private/test.json +20092 -0
  8. package/index.html +4 -4
  9. package/package.json +2 -2
  10. package/src/CdcChart.tsx +209 -188
  11. package/src/_stories/Chart.CustomColors.stories.tsx +19 -0
  12. package/src/_stories/Chart.DynamicSeries.stories.tsx +27 -0
  13. package/src/_stories/Chart.Legend.Gradient.stories.tsx +74 -0
  14. package/src/_stories/Chart.stories.tsx +30 -3
  15. package/src/_stories/ChartAxisLabels.stories.tsx +20 -0
  16. package/src/_stories/ChartAxisTitles.stories.tsx +53 -0
  17. package/src/_stories/ChartEditor.stories.tsx +27 -0
  18. package/src/_stories/ChartLine.Suppression.stories.tsx +25 -0
  19. package/src/_stories/ChartPrefixSuffix.stories.tsx +159 -0
  20. package/src/_stories/_mock/boxplot_multiseries.json +647 -0
  21. package/src/_stories/_mock/dynamic_series_bar_config.json +723 -0
  22. package/src/_stories/_mock/dynamic_series_config.json +979 -0
  23. package/src/_stories/_mock/horizontal_bar.json +257 -0
  24. package/src/_stories/_mock/large_x_axis_labels.json +261 -0
  25. package/src/_stories/_mock/paired-bar.json +262 -0
  26. package/src/_stories/_mock/pie_with_data.json +255 -0
  27. package/{examples/feature/scatterplot/scatterplot.json → src/_stories/_mock/scatterplot_mock.json} +62 -92
  28. package/src/_stories/_mock/simplified_line.json +1510 -0
  29. package/src/_stories/_mock/suppression_mock.json +1549 -0
  30. package/src/components/Annotations/components/AnnotationDraggable.tsx +0 -3
  31. package/src/components/Annotations/components/AnnotationDropdown.tsx +1 -1
  32. package/src/components/Axis/Categorical.Axis.tsx +22 -4
  33. package/src/components/BarChart/components/BarChart.Horizontal.tsx +95 -16
  34. package/src/components/BarChart/components/BarChart.StackedHorizontal.tsx +41 -17
  35. package/src/components/BarChart/components/BarChart.StackedVertical.tsx +43 -9
  36. package/src/components/BarChart/components/BarChart.Vertical.tsx +123 -47
  37. package/src/components/BarChart/helpers/index.ts +23 -5
  38. package/src/components/BoxPlot/BoxPlot.tsx +189 -0
  39. package/src/components/BrushChart.tsx +3 -2
  40. package/src/components/DeviationBar.jsx +58 -8
  41. package/src/components/EditorPanel/EditorPanel.tsx +127 -102
  42. package/src/components/EditorPanel/components/Panels/Panel.Annotate.tsx +11 -28
  43. package/src/components/EditorPanel/components/Panels/Panel.BoxPlot.tsx +51 -6
  44. package/src/components/EditorPanel/components/Panels/Panel.General.tsx +21 -4
  45. package/src/components/EditorPanel/components/Panels/Panel.Regions.tsx +40 -9
  46. package/src/components/EditorPanel/components/Panels/Panel.Sankey.tsx +3 -3
  47. package/src/components/EditorPanel/components/Panels/Panel.Series.tsx +121 -56
  48. package/src/components/EditorPanel/components/Panels/Panel.Visual.tsx +296 -35
  49. package/src/components/EditorPanel/components/panels.scss +4 -6
  50. package/src/components/EditorPanel/editor-panel.scss +0 -8
  51. package/src/components/EditorPanel/helpers/tests/updateFieldRankByValue.test.ts +38 -0
  52. package/src/components/EditorPanel/helpers/updateFieldRankByValue.ts +42 -0
  53. package/src/components/EditorPanel/useEditorPermissions.ts +16 -1
  54. package/src/components/ForestPlot/ForestPlot.tsx +2 -3
  55. package/src/components/ForestPlot/ForestPlotProps.ts +2 -0
  56. package/src/components/Legend/Legend.Component.tsx +23 -24
  57. package/src/components/Legend/Legend.Suppression.tsx +25 -20
  58. package/src/components/Legend/Legend.tsx +16 -18
  59. package/src/components/Legend/helpers/index.ts +16 -19
  60. package/src/components/LegendWrapper.tsx +3 -1
  61. package/src/components/LineChart/components/LineChart.Circle.tsx +10 -0
  62. package/src/components/LineChart/helpers.ts +48 -43
  63. package/src/components/LineChart/index.tsx +88 -82
  64. package/src/components/LinearChart.tsx +747 -562
  65. package/src/components/PairedBarChart.jsx +50 -10
  66. package/src/components/PieChart/PieChart.tsx +1 -6
  67. package/src/components/Regions/components/Regions.tsx +33 -19
  68. package/src/components/Sankey/index.tsx +50 -32
  69. package/src/components/Sankey/sankey.scss +6 -5
  70. package/src/components/Sankey/useSankeyAlert.tsx +60 -0
  71. package/src/components/ScatterPlot/ScatterPlot.jsx +20 -4
  72. package/src/components/ZoomBrush.tsx +25 -6
  73. package/src/coreStyles_chart.scss +3 -0
  74. package/src/data/initial-state.js +8 -10
  75. package/src/helpers/configHelpers.ts +28 -0
  76. package/src/helpers/handleRankByValue.ts +15 -0
  77. package/src/helpers/sizeHelpers.ts +25 -0
  78. package/src/helpers/tests/handleRankByValue.test.ts +37 -0
  79. package/src/helpers/tests/sizeHelpers.test.ts +80 -0
  80. package/src/hooks/useColorPalette.js +10 -2
  81. package/src/hooks/useLegendClasses.ts +13 -22
  82. package/src/hooks/useMinMax.ts +27 -13
  83. package/src/hooks/useReduceData.ts +43 -10
  84. package/src/hooks/useScales.ts +87 -38
  85. package/src/hooks/useTooltip.tsx +62 -53
  86. package/src/index.jsx +1 -0
  87. package/src/scss/DataTable.scss +5 -4
  88. package/src/scss/main.scss +57 -70
  89. package/src/types/ChartConfig.ts +43 -34
  90. package/src/types/ChartContext.ts +22 -15
  91. package/src/types/ForestPlot.ts +8 -0
  92. package/src/_stories/Chart.Legend.Gradient.tsx +0 -19
  93. package/src/_stories/ChartBrush.stories.tsx +0 -19
  94. package/src/components/BoxPlot/BoxPlot.jsx +0 -111
  95. package/src/components/LinearChart.jsx +0 -817
@@ -6,13 +6,30 @@ import { Text } from '@visx/text'
6
6
  import ErrorBoundary from '@cdc/core/components/ErrorBoundary'
7
7
  import useIntersectionObserver from '../hooks/useIntersectionObserver'
8
8
  import { getContrastColor } from '@cdc/core/helpers/cove/accessibility'
9
+ import { getTextWidth } from '@cdc/core/helpers/getTextWidth'
9
10
 
10
11
  export default function DeviationBar({ height, xScale }) {
11
- const { transformedData: data, config, formatNumber, twoColorPalette, getTextWidth, updateConfig, parseDate, formatDate, currentViewport } = useContext(ConfigContext)
12
+ const {
13
+ transformedData: data,
14
+ config,
15
+ formatNumber,
16
+ twoColorPalette,
17
+ updateConfig,
18
+ parseDate,
19
+ formatDate,
20
+ currentViewport
21
+ } = useContext(ConfigContext)
12
22
  const { barStyle, tipRounding, roundingStyle, twoColor } = config
13
23
  const barRefs = useRef([])
14
24
  const [windowWidth, setWindowWidth] = useState(window.innerWidth)
15
- const radius = roundingStyle === 'standard' ? '8px' : roundingStyle === 'shallow' ? '5px' : roundingStyle === 'finger' ? '15px' : '0px'
25
+ const radius =
26
+ roundingStyle === 'standard'
27
+ ? '8px'
28
+ : roundingStyle === 'shallow'
29
+ ? '5px'
30
+ : roundingStyle === 'finger'
31
+ ? '15px'
32
+ : '0px'
16
33
  const fontSize = { small: 16, medium: 18, large: 20 }
17
34
  const isRounded = config.barStyle === 'rounded'
18
35
  const target = Number(config.xAxis.target)
@@ -148,7 +165,10 @@ export default function DeviationBar({ height, xScale }) {
148
165
  config.heights.horizontal = totalheight
149
166
 
150
167
  // text,labels postiions
151
- const textWidth = getTextWidth(formatNumber(barValue, 'left'), `normal ${fontSize[config.fontSize]}px sans-serif`)
168
+ const textWidth = getTextWidth(
169
+ formatNumber(barValue, 'left'),
170
+ `normal ${fontSize[config.fontSize]}px sans-serif`
171
+ )
152
172
  const textFits = textWidth < barWidth - 6
153
173
  const textX = barBaseX
154
174
  const textY = barY + barHeight / 2
@@ -167,7 +187,10 @@ export default function DeviationBar({ height, xScale }) {
167
187
  let textProps = getTextProps(config.isLollipopChart, textFits, lollipopShapeSize, fill)
168
188
  // tooltips
169
189
  const xAxisValue = formatNumber(barValue, 'left')
170
- const yAxisValue = config.runtime.yAxis.type === 'date' ? formatDate(parseDate(data[index][config.runtime.originalXAxis.dataKey])) : data[index][config.runtime.originalXAxis.dataKey]
190
+ const yAxisValue =
191
+ config.runtime.yAxis.type === 'date'
192
+ ? formatDate(parseDate(data[index][config.runtime.originalXAxis.dataKey]))
193
+ : data[index][config.runtime.originalXAxis.dataKey]
171
194
  let yAxisTooltip = config.runtime.yAxis.label ? `${config.runtime.yAxis.label}: ${yAxisValue}` : yAxisValue
172
195
  let xAxisTooltip = config.runtime.xAxis.label ? `${config.runtime.xAxis.label}: ${xAxisValue}` : xAxisValue
173
196
  const tooltip = `<div>
@@ -190,7 +213,15 @@ export default function DeviationBar({ height, xScale }) {
190
213
  data-tooltip-id={`cdc-open-viz-tooltip-${config.runtime.uniqueId}`}
191
214
  tabIndex={-1}
192
215
  >
193
- <div style={{ width: barWidth, height: barHeight, border: `${borderWidth}px solid #333`, backgroundColor: barColor[barPosition], ...borderRadius }}></div>
216
+ <div
217
+ style={{
218
+ width: barWidth,
219
+ height: barHeight,
220
+ border: `${borderWidth}px solid #333`,
221
+ backgroundColor: barColor[barPosition],
222
+ ...borderRadius
223
+ }}
224
+ ></div>
194
225
  </foreignObject>
195
226
  {config.yAxis.displayNumbersOnBar && (
196
227
  <Text verticalAnchor='middle' x={textX} y={textY} {...textProps[barPosition]}>
@@ -198,8 +229,25 @@ export default function DeviationBar({ height, xScale }) {
198
229
  </Text>
199
230
  )}
200
231
 
201
- {config.isLollipopChart && config.lollipopShape === 'circle' && <circle cx={circleX} cy={circleY} r={lollipopShapeSize / 2} fill={barColor[barPosition]} style={{ filter: 'unset', opacity: 1 }} />}
202
- {config.isLollipopChart && config.lollipopShape === 'square' && <rect x={squareX} y={squareY} width={lollipopShapeSize} height={lollipopShapeSize} fill={barColor[barPosition]} style={{ opacity: 1, filter: 'unset' }}></rect>}
232
+ {config.isLollipopChart && config.lollipopShape === 'circle' && (
233
+ <circle
234
+ cx={circleX}
235
+ cy={circleY}
236
+ r={lollipopShapeSize / 2}
237
+ fill={barColor[barPosition]}
238
+ style={{ filter: 'unset', opacity: 1 }}
239
+ />
240
+ )}
241
+ {config.isLollipopChart && config.lollipopShape === 'square' && (
242
+ <rect
243
+ x={squareX}
244
+ y={squareY}
245
+ width={lollipopShapeSize}
246
+ height={lollipopShapeSize}
247
+ fill={barColor[barPosition]}
248
+ style={{ opacity: 1, filter: 'unset' }}
249
+ ></rect>
250
+ )}
203
251
  </Group>
204
252
  )
205
253
  })}
@@ -209,7 +257,9 @@ export default function DeviationBar({ height, xScale }) {
209
257
  </Text>
210
258
  )}
211
259
 
212
- {shouldShowTargetLine && <Line from={{ x: targetX, y: 0 }} to={{ x: targetX, y: height }} stroke='#333' strokeWidth={2} />}
260
+ {shouldShowTargetLine && (
261
+ <Line from={{ x: targetX, y: 0 }} to={{ x: targetX, y: height }} stroke='#333' strokeWidth={2} />
262
+ )}
213
263
  </Group>
214
264
  <foreignObject y={height / 2} ref={targetRef}></foreignObject>
215
265
  </ErrorBoundary>
@@ -43,6 +43,7 @@ import { Anchor } from '@cdc/core/types/Axis'
43
43
  import EditorPanelContext from './EditorPanelContext'
44
44
  import _ from 'lodash'
45
45
  import { adjustedSymbols as symbolCodes } from '@cdc/core/helpers/footnoteSymbols'
46
+ import { updateFieldRankByValue } from './helpers/updateFieldRankByValue'
46
47
 
47
48
  interface PreliminaryProps {
48
49
  config: ChartConfig
@@ -76,7 +77,7 @@ const PreliminaryData: React.FC<PreliminaryProps> = ({ config, updateConfig, dat
76
77
  const getStyleOptions = type => {
77
78
  const options = Object.keys(lineCodes)
78
79
  if (type === 'suppression') {
79
- return options.slice(0, -1)
80
+ return options.slice(0, -2)
80
81
  } else {
81
82
  return options
82
83
  }
@@ -170,7 +171,7 @@ const PreliminaryData: React.FC<PreliminaryProps> = ({ config, updateConfig, dat
170
171
  <p> {type === 'suppression' ? 'Suppressed' : 'Effect'} Data</p>
171
172
  <button
172
173
  type='button'
173
- className='remove-column'
174
+ className='btn btn-danger'
174
175
  onClick={event => {
175
176
  event.preventDefault()
176
177
  removeColumn(i)
@@ -449,7 +450,7 @@ const PreliminaryData: React.FC<PreliminaryProps> = ({ config, updateConfig, dat
449
450
  }
450
451
  )}
451
452
 
452
- <button type='button' onClick={addColumn} className='btn full-width'>
453
+ <button type='button' onClick={addColumn} className='btn btn-primary full-width'>
453
454
  {config.visualizationType === 'Line'
454
455
  ? 'Add Special Line'
455
456
  : config.visualizationType === 'Bar'
@@ -529,7 +530,7 @@ const CategoricalAxis: React.FC<CategoricalAxisProps> = ({ config, updateConfig,
529
530
  <p>Axis Category {i + 1}</p>
530
531
  <button
531
532
  type='button'
532
- className='remove-column'
533
+ className='btn btn-danger'
533
534
  onClick={event => {
534
535
  event.preventDefault()
535
536
  removeColumn(i)
@@ -582,7 +583,7 @@ const CategoricalAxis: React.FC<CategoricalAxisProps> = ({ config, updateConfig,
582
583
  )
583
584
  })}
584
585
 
585
- <button type='button' onClick={addColumn} className='btn full-width'>
586
+ <button type='button' onClick={addColumn} className='btn btn-primary full-width'>
586
587
  Add Axis Category
587
588
  </button>
588
589
  </>
@@ -618,52 +619,35 @@ const EditorPanel = () => {
618
619
  const { leftMax, rightMax } = useMinMax(properties)
619
620
 
620
621
  const {
621
- headerColors,
622
- visSupportsTooltipLines,
623
- visSupportsNonSequentialPallete,
624
- visSupportsSequentialPallete,
625
- visSupportsReverseColorPalette,
626
- visHasLabelOnData,
627
- visHasNumbersOnBars,
628
622
  visHasAnchors,
629
- visHasBarBorders,
630
- visHasDataCutoff,
631
- visHasSelectableLegendValues,
632
- visCanAnimate,
623
+ visHasBrushChart,
624
+ visHasCategoricalAxis,
633
625
  visHasLegend,
634
626
  visHasLegendAxisAlign,
635
627
  visHasLegendColorCategory,
636
- visHasBrushChart,
628
+ visHasSelectableLegendValues,
637
629
  visSupportsDateCategoryAxis,
638
- visSupportsValueAxisMin,
639
- visSupportsValueAxisMax,
640
630
  visSupportsDateCategoryAxisLabel,
641
631
  visSupportsDateCategoryAxisLine,
632
+ visSupportsDateCategoryAxisMax,
633
+ visSupportsDateCategoryAxisMin,
634
+ visSupportsDateCategoryAxisPadding,
642
635
  visSupportsDateCategoryAxisTicks,
643
- visSupportsDateCategoryTickRotation,
636
+ visSupportsDateCategoryHeight,
644
637
  visSupportsDateCategoryNumTicks,
645
- visSupportsDateCategoryAxisPadding,
646
- visSupportsRegions,
638
+ visSupportsDateCategoryTickRotation,
639
+ visSupportsDynamicSeries,
647
640
  visSupportsFilters,
648
- visSupportsPreliminaryData,
649
- visSupportsValueAxisGridLines,
650
- visSupportsValueAxisLine,
651
- visSupportsValueAxisTicks,
652
- visSupportsValueAxisLabels,
653
- visSupportsBarSpace,
654
- visSupportsBarThickness,
655
- visSupportsFootnotes,
656
- visSupportsSuperTitle,
657
- visSupportsDataCutoff,
658
- visSupportsChartHeight,
659
641
  visSupportsLeftValueAxis,
660
- visSupportsTooltipOpacity,
642
+ visSupportsPreliminaryData,
661
643
  visSupportsRankByValue,
662
644
  visSupportsResponsiveTicks,
663
- visSupportsDateCategoryHeight,
664
- visHasDataSuppression,
665
- visHasCategoricalAxis,
666
- visSupportsDynamicSeries
645
+ visSupportsValueAxisGridLines,
646
+ visSupportsValueAxisLabels,
647
+ visSupportsValueAxisLine,
648
+ visSupportsValueAxisMax,
649
+ visSupportsValueAxisMin,
650
+ visSupportsValueAxisTicks
667
651
  } = useEditorPermissions()
668
652
 
669
653
  // when the visualization type changes we
@@ -742,7 +726,7 @@ const EditorPanel = () => {
742
726
  updatedConfig.orientation = 'vertical'
743
727
  }
744
728
  if (isDateScale(updatedConfig.xAxis) && !updatedConfig.xAxis.padding) {
745
- updatedConfig.xAxis.padding = 6
729
+ updatedConfig.xAxis.padding = 0
746
730
  }
747
731
  // DEV-8008 - Remove Bar styling when Line is converted to Bar
748
732
  if (updatedConfig.visualizationType === 'Line') {
@@ -762,21 +746,7 @@ const EditorPanel = () => {
762
746
  newValue
763
747
  ) // eslint-disable-line
764
748
 
765
- if (section === 'boxplot' && subsection === 'legend') {
766
- updateConfig({
767
- ...config,
768
- [section]: {
769
- ...config[section],
770
- [subsection]: {
771
- ...config.boxplot[subsection],
772
- [fieldName]: newValue
773
- }
774
- }
775
- })
776
- return
777
- }
778
-
779
- if (section === 'boxplot' && subsection === 'labels') {
749
+ if (section === 'boxplot' && (subsection === 'legend' || subsection === 'labels')) {
780
750
  updateConfig({
781
751
  ...config,
782
752
  [section]: {
@@ -846,19 +816,6 @@ const EditorPanel = () => {
846
816
  return null
847
817
  }
848
818
 
849
- useEffect(() => {
850
- if (!config.general?.boxplot) return
851
- if (!config.general.boxplot.firstQuartilePercentage) {
852
- updateConfig({
853
- ...config,
854
- boxplot: {
855
- ...config.boxplot,
856
- firstQuartilePercentage: 25
857
- }
858
- })
859
- }
860
- }, [config])
861
-
862
819
  const setLollipopShape = shape => {
863
820
  updateConfig({
864
821
  ...config,
@@ -890,13 +847,6 @@ const EditorPanel = () => {
890
847
  updateConfig({ ...config, series: newSeries }) // left axis series keys
891
848
  }
892
849
 
893
- const sortSeries = e => {
894
- const series = config.series[0].dataKey
895
- const sorted = data.sort((a, b) => a[series] - b[series])
896
- const newData = e === 'asc' ? sorted : sorted.reverse()
897
- updateConfig({ ...config }, newData)
898
- }
899
-
900
850
  const addNewExclusion = exclusionKey => {
901
851
  let newExclusion = [...config.exclusions.keys]
902
852
  newExclusion.push(exclusionKey)
@@ -1407,7 +1357,6 @@ const EditorPanel = () => {
1407
1357
  handleSeriesChange,
1408
1358
  handleAddNewHighlightedBar,
1409
1359
  setCategoryAxis,
1410
- sortSeries,
1411
1360
  updateField,
1412
1361
  warningMsg,
1413
1362
  highlightedBarValues,
@@ -1448,14 +1397,15 @@ const EditorPanel = () => {
1448
1397
  </AccordionItemButton>
1449
1398
  </AccordionItemHeading>
1450
1399
  <AccordionItemPanel>
1451
- {visSupportsDynamicSeries() && (
1400
+ {/* FEATURE to be reintroduced by DEV-9747 */}
1401
+ {/* {visSupportsDynamicSeries() && (
1452
1402
  <CheckBox
1453
1403
  value={config.dynamicSeries}
1454
1404
  fieldName='dynamicSeries'
1455
1405
  label='Dynamically generate series'
1456
1406
  updateField={updateField}
1457
1407
  />
1458
- )}
1408
+ )} */}
1459
1409
  {config.dynamicSeries && config.visualizationType === 'Line' && (
1460
1410
  <Select
1461
1411
  fieldName='dynamicSeriesType'
@@ -1571,10 +1521,14 @@ const EditorPanel = () => {
1571
1521
  )}
1572
1522
  {visSupportsRankByValue() && config.series && config.series.length === 1 && (
1573
1523
  <Select
1574
- fieldName='visualizationType'
1524
+ value={config.rankByValue}
1525
+ fieldName='rankByValue'
1575
1526
  label='Rank by Value'
1576
1527
  initial='Select'
1577
- onChange={e => sortSeries(e.target.value)}
1528
+ updateField={(_section, _subsection, _fieldName, value) => {
1529
+ const [newConfig, newData] = updateFieldRankByValue(config, value, data)
1530
+ updateConfig(newConfig, newData)
1531
+ }}
1578
1532
  options={['asc', 'desc']}
1579
1533
  />
1580
1534
  )}
@@ -1803,6 +1757,17 @@ const EditorPanel = () => {
1803
1757
  updateField={updateField}
1804
1758
  />
1805
1759
  )}
1760
+ {visSupportsValueAxisGridLines() && (
1761
+ <CheckBox
1762
+ value={config.yAxis.labelsAboveGridlines}
1763
+ section='yAxis'
1764
+ fieldName='labelsAboveGridlines'
1765
+ label='Tick labels above gridlines'
1766
+ updateField={updateField}
1767
+ disabled={!config.yAxis.gridLines}
1768
+ title={!config.yAxis.gridLines ? 'Show gridlines to enable' : ''}
1769
+ />
1770
+ )}
1806
1771
  <CheckBox
1807
1772
  value={config.yAxis.enablePadding}
1808
1773
  section='yAxis'
@@ -2007,6 +1972,14 @@ const EditorPanel = () => {
2007
1972
  ) : (
2008
1973
  config.visualizationType !== 'Pie' && (
2009
1974
  <>
1975
+ <CheckBox
1976
+ display={!visHasCategoricalAxis()}
1977
+ value={config.dataFormat.onlyShowTopPrefixSuffix}
1978
+ section='dataFormat'
1979
+ fieldName='onlyShowTopPrefixSuffix'
1980
+ label='Only Show Top Prefix/Suffix'
1981
+ updateField={updateField}
1982
+ />
2010
1983
  <CheckBox
2011
1984
  display={!visHasCategoricalAxis()}
2012
1985
  value={config.yAxis.hideAxis}
@@ -2164,7 +2137,7 @@ const EditorPanel = () => {
2164
2137
  </Accordion>
2165
2138
 
2166
2139
  <button
2167
- className='btn full-width'
2140
+ className='btn btn-primary full-width'
2168
2141
  onClick={e => {
2169
2142
  e.preventDefault()
2170
2143
  const anchors = [...config.yAxis.anchors]
@@ -2290,7 +2263,7 @@ const EditorPanel = () => {
2290
2263
  </Accordion>
2291
2264
 
2292
2265
  <button
2293
- className='btn full-width'
2266
+ className='btn btn-primary full-width'
2294
2267
  onClick={e => {
2295
2268
  e.preventDefault()
2296
2269
  const anchors = [...config.xAxis.anchors]
@@ -2515,7 +2488,6 @@ const EditorPanel = () => {
2515
2488
  )}
2516
2489
  </select>
2517
2490
  </label>
2518
-
2519
2491
  <CheckBox
2520
2492
  value={config.xAxis.manual}
2521
2493
  section='xAxis'
@@ -2523,6 +2495,14 @@ const EditorPanel = () => {
2523
2495
  label='Manual Ticks'
2524
2496
  updateField={updateField}
2525
2497
  />
2498
+ <CheckBox
2499
+ display={config.xAxis.type !== 'categorical'}
2500
+ value={config.xAxis.sortByRecentDate}
2501
+ section='xAxis'
2502
+ fieldName='sortByRecentDate'
2503
+ label='Show dates newest to oldest'
2504
+ updateField={updateField}
2505
+ />
2526
2506
 
2527
2507
  {visSupportsDateCategoryAxisPadding() && (
2528
2508
  <TextField
@@ -2681,11 +2661,7 @@ const EditorPanel = () => {
2681
2661
  <>
2682
2662
  <p style={{ padding: '1.5em 0 0.5em', fontSize: '.9rem', lineHeight: '1rem' }}>
2683
2663
  Format how charts should parse and display your dates using{' '}
2684
- <a
2685
- href='https://github.com/d3/d3-time-format#locale_format'
2686
- target='_blank'
2687
- rel='noreferrer'
2688
- >
2664
+ <a href='https://d3js.org/d3-time-format#locale_format' target='_blank' rel='noreferrer'>
2689
2665
  these guidelines
2690
2666
  </a>
2691
2667
  .
@@ -2816,6 +2792,29 @@ const EditorPanel = () => {
2816
2792
  }
2817
2793
  updateField={updateField}
2818
2794
  />
2795
+ <CheckBox
2796
+ value={config.xAxis.showYearsOnce}
2797
+ section='xAxis'
2798
+ fieldName='showYearsOnce'
2799
+ label='Show years once'
2800
+ tooltip={
2801
+ <Tooltip style={{ textTransform: 'none' }}>
2802
+ <Tooltip.Target>
2803
+ <Icon
2804
+ display='question'
2805
+ style={{ marginLeft: '0.5rem', display: 'inline-block', whiteSpace: 'nowrap' }}
2806
+ />
2807
+ </Tooltip.Target>
2808
+ <Tooltip.Content>
2809
+ <p>
2810
+ When this option is checked and the date format for the axis includes years, each year
2811
+ will only be shown once in the axis.
2812
+ </p>
2813
+ </Tooltip.Content>
2814
+ </Tooltip>
2815
+ }
2816
+ updateField={updateField}
2817
+ />
2819
2818
  {visHasBrushChart() && (
2820
2819
  <CheckBox
2821
2820
  value={config.brush?.active}
@@ -3040,15 +3039,17 @@ const EditorPanel = () => {
3040
3039
  updateField={updateField}
3041
3040
  />
3042
3041
  )}
3043
- <TextField
3044
- value={config.xAxis.labelOffset}
3045
- section='xAxis'
3046
- fieldName='labelOffset'
3047
- label='Label offset'
3048
- type='number'
3049
- className='number-narrow'
3050
- updateField={updateField}
3051
- />
3042
+ {config.orientation === 'horizontal' && (
3043
+ <TextField
3044
+ value={config.xAxis.labelOffset}
3045
+ section='xAxis'
3046
+ fieldName='labelOffset'
3047
+ label='Label offset'
3048
+ type='number'
3049
+ className='number-narrow'
3050
+ updateField={updateField}
3051
+ />
3052
+ )}
3052
3053
 
3053
3054
  {/* Hiding this for now, not interested in moving the axis lines away from chart comp. right now. */}
3054
3055
  {/* <TextField value={config.xAxis.axisPadding} type='number' max={10} min={0} section='xAxis' fieldName='axisPadding' label={'Axis Padding'} className='number-narrow' updateField={updateField} /> */}
@@ -3187,7 +3188,7 @@ const EditorPanel = () => {
3187
3188
  highlightedBarValues.map((highlightedBarValue, i) => (
3188
3189
  <fieldset>
3189
3190
  <div className='edit-block' key={`highlighted-bar-${i}`}>
3190
- <button className='remove-column' onClick={e => handleRemoveHighlightedBar(e, i)}>
3191
+ <button className='btn btn-danger' onClick={e => handleRemoveHighlightedBar(e, i)}>
3191
3192
  Remove
3192
3193
  </button>
3193
3194
  <p>Highlighted Bar {i + 1}</p>
@@ -3245,7 +3246,7 @@ const EditorPanel = () => {
3245
3246
  </div>
3246
3247
  </fieldset>
3247
3248
  ))}
3248
- <button className='btn full-width' onClick={e => handleAddNewHighlightedBar(e)}>
3249
+ <button className='btn btn-primary full-width' onClick={e => handleAddNewHighlightedBar(e)}>
3249
3250
  Add Highlighted Bar
3250
3251
  </button>
3251
3252
  </>
@@ -3305,6 +3306,30 @@ const EditorPanel = () => {
3305
3306
  </>
3306
3307
  )}
3307
3308
 
3309
+ {visSupportsDateCategoryAxisMin() && (
3310
+ <TextField
3311
+ value={config.xAxis.min}
3312
+ section='xAxis'
3313
+ fieldName='min'
3314
+ type='number'
3315
+ label='min value'
3316
+ placeholder='Auto'
3317
+ updateField={updateField}
3318
+ />
3319
+ )}
3320
+
3321
+ {visSupportsDateCategoryAxisMax() && (
3322
+ <TextField
3323
+ value={config.xAxis.max}
3324
+ section='xAxis'
3325
+ fieldName='max'
3326
+ type='number'
3327
+ label='max value'
3328
+ placeholder='Auto'
3329
+ updateField={updateField}
3330
+ />
3331
+ )}
3332
+
3308
3333
  {/* anchors */}
3309
3334
  {visHasAnchors() && config.orientation !== 'horizontal' && (
3310
3335
  <div className='edit-block'>
@@ -3413,7 +3438,7 @@ const EditorPanel = () => {
3413
3438
  </Accordion>
3414
3439
 
3415
3440
  <button
3416
- className='btn full-width'
3441
+ className='btn btn-primary full-width'
3417
3442
  onClick={e => {
3418
3443
  e.preventDefault()
3419
3444
  const anchors = [...config.xAxis.anchors]
@@ -3542,7 +3567,7 @@ const EditorPanel = () => {
3542
3567
  </Accordion>
3543
3568
 
3544
3569
  <button
3545
- className='btn full-width'
3570
+ className='btn btn-primary full-width'
3546
3571
  onClick={e => {
3547
3572
  e.preventDefault()
3548
3573
  const anchors = [...config.yAxis.anchors]
@@ -3789,7 +3814,7 @@ const EditorPanel = () => {
3789
3814
  config.legend.seriesHighlight.map((val, i) => (
3790
3815
  <fieldset className='edit-block' key={`${val}-${i}`}>
3791
3816
  <button
3792
- className='remove-column'
3817
+ className='btn btn-danger'
3793
3818
  onClick={event => {
3794
3819
  event.preventDefault()
3795
3820
  const updatedSeriesHighlight = [...config.legend.seriesHighlight]
@@ -3818,7 +3843,7 @@ const EditorPanel = () => {
3818
3843
  </fieldset>
3819
3844
  ))}
3820
3845
  <button
3821
- className={'btn full-width'}
3846
+ className={'btn btn-primary full-width'}
3822
3847
  onClick={event => {
3823
3848
  event.preventDefault()
3824
3849
  const legendColumns = getLegendColumns()
@@ -12,31 +12,11 @@ import { type PanelProps } from './../PanelProps'
12
12
  import './../panels.scss'
13
13
 
14
14
  const PanelAnnotate: React.FC<PanelProps> = props => {
15
- const { updateConfig, config, unfilteredData, dimensions, isDraggingAnnotation } = useContext(ConfigContext)
16
-
17
- const getColumns = (filter = true) => {
18
- const columns = {}
19
- unfilteredData.forEach(row => {
20
- Object.keys(row).forEach(columnName => (columns[columnName] = true))
21
- })
22
-
23
- if (filter) {
24
- Object.keys(columns).forEach(key => {
25
- if (
26
- (config.series && config.series.filter(series => series.dataKey === key).length > 0) ||
27
- (config.confidenceKeys && Object.keys(config.confidenceKeys).includes(key))
28
- ) {
29
- delete columns[key]
30
- }
31
- })
32
- }
33
-
34
- return Object.keys(columns)
35
- }
15
+ const { updateConfig, config, svgRef } = useContext(ConfigContext)
36
16
 
37
17
  const handleAnnotationUpdate = (value, property, index) => {
38
- const svgContainer = document.querySelector('.chart-container > div > svg')?.getBoundingClientRect()
39
- const newSvgDims = [svgContainer.width, svgContainer.height]
18
+ const svgContainer = document.querySelector('.chart-container > svg')?.getBoundingClientRect()
19
+ const newSvgDims = [svgContainer?.width, svgContainer?.height]
40
20
  const annotations = [...config?.annotations]
41
21
  annotations[index][property] = value
42
22
  annotations[index].savedDimensions = newSvgDims
@@ -48,8 +28,11 @@ const PanelAnnotate: React.FC<PanelProps> = props => {
48
28
  }
49
29
 
50
30
  const handleAddAnnotation = () => {
51
- const svgContainer = document.querySelector('.chart-container svg')?.getBoundingClientRect()
52
- const newSvgDims = [svgContainer.width, svgContainer.height]
31
+ // check if svg is animated svg or standard svg
32
+ const newSvgDims = [
33
+ svgRef?.current?.width?.baseVal?.value || svgRef?.current?.width,
34
+ svgRef?.current?.height?.baseVal?.value || svgRef?.current?.height
35
+ ]
53
36
 
54
37
  const newAnnotation = {
55
38
  text: 'New Annotation',
@@ -300,7 +283,7 @@ const PanelAnnotate: React.FC<PanelProps> = props => {
300
283
  </select>
301
284
  </label>
302
285
 
303
- <Button className='warn btn-warn btn btn-remove delete' onClick={() => handleRemoveAnnotation(index)}>
286
+ <Button className='btn btn-danger full-width' onClick={() => handleRemoveAnnotation(index)}>
304
287
  Delete Annotation
305
288
  </Button>
306
289
  </div>
@@ -308,9 +291,9 @@ const PanelAnnotate: React.FC<PanelProps> = props => {
308
291
  </Accordion>
309
292
  ))}
310
293
  {config?.annotations?.length < 3 && (
311
- <Button onClick={handleAddAnnotation} className='mt-2'>
294
+ <button onClick={handleAddAnnotation} className='btn btn-primary mt-2 full-width'>
312
295
  Add Annotation
313
- </Button>
296
+ </button>
314
297
  )}
315
298
  </Accordion.Section>
316
299
  </Accordion>