@fluentui/react-charts 0.0.0-nightly-20250813-0406.1 → 0.0.0-nightly-20250815-0407.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.
Files changed (29) hide show
  1. package/CHANGELOG.md +15 -15
  2. package/dist/index.d.ts +16 -9
  3. package/lib/components/CommonComponents/CartesianChart.js +12 -16
  4. package/lib/components/CommonComponents/CartesianChart.js.map +1 -1
  5. package/lib/components/CommonComponents/CartesianChart.types.js.map +1 -1
  6. package/lib/components/DeclarativeChart/DeclarativeChart.js +3 -2
  7. package/lib/components/DeclarativeChart/DeclarativeChart.js.map +1 -1
  8. package/lib/components/DeclarativeChart/PlotlySchemaAdapter.js +41 -9
  9. package/lib/components/DeclarativeChart/PlotlySchemaAdapter.js.map +1 -1
  10. package/lib/components/VerticalStackedBarChart/VerticalStackedBarChart.js +130 -35
  11. package/lib/components/VerticalStackedBarChart/VerticalStackedBarChart.js.map +1 -1
  12. package/lib/components/VerticalStackedBarChart/VerticalStackedBarChart.types.js.map +1 -1
  13. package/lib/types/DataPoint.js.map +1 -1
  14. package/lib/utilities/utilities.js +10 -4
  15. package/lib/utilities/utilities.js.map +1 -1
  16. package/lib-commonjs/components/CommonComponents/CartesianChart.js +12 -15
  17. package/lib-commonjs/components/CommonComponents/CartesianChart.js.map +1 -1
  18. package/lib-commonjs/components/CommonComponents/CartesianChart.types.js.map +1 -1
  19. package/lib-commonjs/components/DeclarativeChart/DeclarativeChart.js +2 -1
  20. package/lib-commonjs/components/DeclarativeChart/DeclarativeChart.js.map +1 -1
  21. package/lib-commonjs/components/DeclarativeChart/PlotlySchemaAdapter.js +46 -9
  22. package/lib-commonjs/components/DeclarativeChart/PlotlySchemaAdapter.js.map +1 -1
  23. package/lib-commonjs/components/VerticalStackedBarChart/VerticalStackedBarChart.js +129 -34
  24. package/lib-commonjs/components/VerticalStackedBarChart/VerticalStackedBarChart.js.map +1 -1
  25. package/lib-commonjs/components/VerticalStackedBarChart/VerticalStackedBarChart.types.js.map +1 -1
  26. package/lib-commonjs/types/DataPoint.js.map +1 -1
  27. package/lib-commonjs/utilities/utilities.js +10 -4
  28. package/lib-commonjs/utilities/utilities.js.map +1 -1
  29. package/package.json +12 -12
@@ -6,8 +6,9 @@ import { scaleLinear as d3ScaleLinear, scaleBand as d3ScaleBand, scaleUtc as d3S
6
6
  import { useId } from '@fluentui/react-utilities';
7
7
  import { tokens } from '@fluentui/react-theme';
8
8
  import { CartesianChart, ChartPopover, Legends } from '../../index';
9
- import { ChartTypes, getAccessibleDataObject, XAxisTypes, getTypeOfAxis, tooltipOfAxislabels, formatScientificLimitWidth, getBarWidth, getScalePadding, isScalePaddingDefined, calculateAppropriateBarWidth, formatDate, areArraysEqual, calculateLongestLabelWidth, useRtl, DataVizPalette, getColorFromToken, findVSBCNumericMinMaxOfY, createNumericYAxis, domainRangeOfDateForAreaLineVerticalBarChart, domainRangeOfVSBCNumeric, domainRangeOfXStringAxis, createStringYAxis, calcTotalWidth, calcBandwidth, calcRequiredWidth } from '../../utilities/index';
9
+ import { ChartTypes, getAccessibleDataObject, XAxisTypes, getTypeOfAxis, tooltipOfAxislabels, formatScientificLimitWidth, getBarWidth, getScalePadding, isScalePaddingDefined, calculateAppropriateBarWidth, formatDate, areArraysEqual, calculateLongestLabelWidth, useRtl, DataVizPalette, getColorFromToken, findVSBCNumericMinMaxOfY, YAxisType, createNumericYAxis, domainRangeOfDateForAreaLineVerticalBarChart, domainRangeOfVSBCNumeric, domainRangeOfXStringAxis, createStringYAxis, calcTotalWidth, calcBandwidth, calcRequiredWidth } from '../../utilities/index';
10
10
  import { toImage } from '../../utilities/image-export-utils';
11
+ import { formatDateToLocaleString } from '@fluentui/chart-utilities';
11
12
  const barGapMultiplier = 0.2;
12
13
  const barGapMin = 1;
13
14
  const MIN_DOMAIN_MARGIN = 8;
@@ -35,6 +36,8 @@ export const VerticalStackedBarChart = (props)=>{
35
36
  const cartesianChartRef = React.useRef(null);
36
37
  const Y_ORIGIN = 0;
37
38
  const _legendsRef = React.useRef(null);
39
+ let _yAxisType;
40
+ let _yAxisLabels = [];
38
41
  const [selectedLegends, setSelectedLegends] = React.useState(((_props_legendProps = props.legendProps) === null || _props_legendProps === void 0 ? void 0 : _props_legendProps.selectedLegends) || []);
39
42
  const [activeLegend, setActiveLegend] = React.useState(undefined);
40
43
  const [dataForHoverCard, setDataForHoverCard] = React.useState(0);
@@ -235,15 +238,22 @@ export const VerticalStackedBarChart = (props)=>{
235
238
  _lineObject = _getFormattedLineData(props.data);
236
239
  _xAxisInnerPadding = getScalePadding(props.xAxisInnerPadding, props.xAxisPadding, _xAxisType === XAxisTypes.StringAxis ? 2 / 3 : 1 / 2);
237
240
  _xAxisOuterPadding = getScalePadding(props.xAxisOuterPadding, props.xAxisPadding, 0);
241
+ _initYAxisParams();
238
242
  }
239
243
  function _createDataSetLayer() {
240
244
  const tempArr = [];
241
245
  const dataset = _points.map((singlePointData)=>{
246
+ tempArr.push(singlePointData.xAxisPoint);
247
+ if (_yAxisType === YAxisType.StringAxis) {
248
+ return {
249
+ x: singlePointData.xAxisPoint,
250
+ y: 0
251
+ };
252
+ }
242
253
  let total = 0;
243
254
  singlePointData.chartData.forEach((point)=>{
244
255
  total = total + point.data;
245
256
  });
246
- tempArr.push(singlePointData.xAxisPoint);
247
257
  return {
248
258
  x: singlePointData.xAxisPoint,
249
259
  y: total
@@ -274,7 +284,7 @@ export const VerticalStackedBarChart = (props)=>{
274
284
  }
275
285
  function _getGraphData(xScale, yScale, containerHeight, containerWidth, xElement) {
276
286
  const { xBarScale, yBarScale } = _getScales(containerHeight, containerWidth);
277
- return _bars = _createBar(xBarScale, yBarScale, containerHeight, xElement);
287
+ return _bars = _createBar(xBarScale, _yAxisType === YAxisType.StringAxis ? yScale : yBarScale, containerHeight, xElement);
278
288
  }
279
289
  function _getAxisData(yAxisData) {
280
290
  if (yAxisData && yAxisData.yAxisDomainValues.length) {
@@ -401,6 +411,7 @@ export const VerticalStackedBarChart = (props)=>{
401
411
  const y1 = useSecondaryYScale ? yScaleSecondary(lineObject[item][i - 1].y) : yScalePrimary(lineObject[item][i - 1].y);
402
412
  const x2 = xScale(lineObject[item][i].xItem.xAxisPoint);
403
413
  const y2 = useSecondaryYScale ? yScaleSecondary(lineObject[item][i].y) : yScalePrimary(lineObject[item][i].y);
414
+ const yScaleBandwidthTranslate = !useSecondaryYScale && _yAxisType === YAxisType.StringAxis ? yScalePrimary.bandwidth() / 2 : 0;
404
415
  if (lineBorderWidth > 0) {
405
416
  borderForLines.push(/*#__PURE__*/ React.createElement("line", {
406
417
  key: `${index}-${i}-BorderLine`,
@@ -413,7 +424,7 @@ export const VerticalStackedBarChart = (props)=>{
413
424
  fill: "transparent",
414
425
  strokeLinecap: "round",
415
426
  stroke: tokens.colorNeutralBackground1,
416
- transform: `translate(${xScaleBandwidthTranslate}, 0)`
427
+ transform: `translate(${xScaleBandwidthTranslate}, ${yScaleBandwidthTranslate})`
417
428
  }));
418
429
  }
419
430
  var _lineObject_item__lineOptions_strokeWidth, _lineObject_item__lineOptions_strokeLinecap;
@@ -428,7 +439,7 @@ export const VerticalStackedBarChart = (props)=>{
428
439
  strokeLinecap: (_lineObject_item__lineOptions_strokeLinecap = (_lineObject_item__lineOptions1 = lineObject[item][0].lineOptions) === null || _lineObject_item__lineOptions1 === void 0 ? void 0 : _lineObject_item__lineOptions1.strokeLinecap) !== null && _lineObject_item__lineOptions_strokeLinecap !== void 0 ? _lineObject_item__lineOptions_strokeLinecap : 'round',
429
440
  strokeDasharray: (_lineObject_item__lineOptions2 = lineObject[item][0].lineOptions) === null || _lineObject_item__lineOptions2 === void 0 ? void 0 : _lineObject_item__lineOptions2.strokeDasharray,
430
441
  stroke: lineObject[item][i].color,
431
- transform: `translate(${xScaleBandwidthTranslate}, 0)`,
442
+ transform: `translate(${xScaleBandwidthTranslate}, ${yScaleBandwidthTranslate})`,
432
443
  onMouseOver: (event)=>_lineHover(lineObject[item][i - 1], event),
433
444
  onMouseLeave: _handleMouseOut
434
445
  }));
@@ -440,6 +451,7 @@ export const VerticalStackedBarChart = (props)=>{
440
451
  refElement: null
441
452
  };
442
453
  const noBarsAndLinesActive = circlePoint.xItem.chartData.filter((dataPoint)=>_noLegendHighlighted() || _isLegendHighlighted(dataPoint.legend)).length === 0;
454
+ const yScaleBandwidthTranslate = !circlePoint.useSecondaryYScale && _yAxisType === YAxisType.StringAxis ? yScalePrimary.bandwidth() / 2 : 0;
443
455
  dots.push(/*#__PURE__*/ React.createElement("circle", {
444
456
  key: `${index}-${subIndex}-dot`,
445
457
  cx: xScale(circlePoint.xItem.xAxisPoint),
@@ -453,7 +465,7 @@ export const VerticalStackedBarChart = (props)=>{
453
465
  // Elements with visibility: hidden cannot receive focus, so use opacity: 0 instead to hide them.
454
466
  // For more information, see https://fuzzbomb.github.io/accessibility-demos/visually-hidden-focus-test.html
455
467
  opacity: _getCircleOpacityAndRadius(circlePoint.xItem.xAxisPoint, circlePoint.legend).opacity,
456
- transform: `translate(${xScaleBandwidthTranslate}, 0)`,
468
+ transform: `translate(${xScaleBandwidthTranslate}, ${yScaleBandwidthTranslate})`,
457
469
  ref: (e)=>circleRef.refElement = e,
458
470
  ...noBarsAndLinesActive ? {
459
471
  tabIndex: !props.hideTooltip ? 0 : undefined,
@@ -525,14 +537,15 @@ export const VerticalStackedBarChart = (props)=>{
525
537
  if ((_calloutAnchorPoint === null || _calloutAnchorPoint === void 0 ? void 0 : _calloutAnchorPoint.chartDataPoint) !== point || (_calloutAnchorPoint === null || _calloutAnchorPoint === void 0 ? void 0 : _calloutAnchorPoint.xAxisDataPoint) !== xAxisPoint) {
526
538
  _calloutAnchorPoint = {
527
539
  chartDataPoint: point,
528
- xAxisDataPoint: `${xAxisPoint}`
540
+ xAxisDataPoint: xAxisPoint instanceof Date ? formatDateToLocaleString(xAxisPoint, props.culture, props.useUTC) : xAxisPoint.toString()
529
541
  };
542
+ const xCalloutValue = point.xAxisCalloutData || (xAxisPoint instanceof Date ? formatDateToLocaleString(xAxisPoint, props.culture, props.useUTC) : xAxisPoint.toString());
530
543
  _updatePosition(clientX, clientY);
531
544
  setPopoverOpen(_noLegendHighlighted() || _isLegendHighlighted(point.legend));
532
545
  setCalloutLegend(point.legend);
533
546
  setDataForHoverCard(point.data);
534
547
  setColor(color);
535
- setXCalloutValue(point.xAxisCalloutData ? point.xAxisCalloutData : `${xAxisPoint}`);
548
+ setXCalloutValue(xCalloutValue);
536
549
  setYCalloutValue(point.yAxisCalloutData);
537
550
  setDataPointCalloutProps(point);
538
551
  setCallOutAccessibilityData(point.callOutAccessibilityData);
@@ -566,22 +579,29 @@ export const VerticalStackedBarChart = (props)=>{
566
579
  }
567
580
  function _getBarGapAndScale(bars, yBarScale, defaultTotalHeight) {
568
581
  const { barGapMax = 0 } = props;
569
- // When displaying gaps between the bars, the height of each bar is
570
- // adjusted so that the total of all bars is not changed by the gaps
571
- const totalData = bars.reduce((iter, value)=>iter + Math.abs(value.data), 0);
572
- const totalHeight = defaultTotalHeight !== null && defaultTotalHeight !== void 0 ? defaultTotalHeight : Math.abs(yBarScale(totalData) - yBarScale(Y_ORIGIN));
582
+ let totalData = 0;
583
+ let totalHeight;
573
584
  let sumOfPercent = 0;
574
- bars.forEach((point)=>{
575
- let value = Math.abs(point.data) / totalData * 100;
576
- if (value < 1 && value !== 0) {
577
- value = 1;
578
- }
579
- sumOfPercent += value;
580
- });
581
- const scalingRatio = sumOfPercent !== 0 ? sumOfPercent / 100 : 1;
585
+ let scalingRatio;
586
+ if (_yAxisType === YAxisType.StringAxis) {
587
+ totalHeight = defaultTotalHeight !== null && defaultTotalHeight !== void 0 ? defaultTotalHeight : bars.reduce((total, bar)=>total + yBarScale(bar.data), 0);
588
+ } else {
589
+ // When displaying gaps between the bars, the height of each bar is
590
+ // adjusted so that the total of all bars is not changed by the gaps
591
+ totalData = bars.reduce((iter, value)=>iter + Math.abs(value.data), 0);
592
+ totalHeight = defaultTotalHeight !== null && defaultTotalHeight !== void 0 ? defaultTotalHeight : Math.abs(yBarScale(totalData) - yBarScale(Y_ORIGIN));
593
+ bars.forEach((point)=>{
594
+ let value = Math.abs(point.data) / totalData * 100;
595
+ if (value < 1 && value !== 0) {
596
+ value = 1;
597
+ }
598
+ sumOfPercent += value;
599
+ });
600
+ scalingRatio = sumOfPercent !== 0 ? sumOfPercent / 100 : 1;
601
+ }
582
602
  const gaps = barGapMax && bars.length - 1;
583
603
  const gapHeight = gaps && Math.max(barGapMin, Math.min(barGapMax, totalHeight * barGapMultiplier / gaps));
584
- const heightValueScale = (totalHeight - gapHeight * gaps) / (totalData * scalingRatio);
604
+ const heightValueScale = _yAxisType === YAxisType.StringAxis ? 0 : (totalHeight - gapHeight * gaps) / (totalData * scalingRatio);
585
605
  return {
586
606
  gapHeight,
587
607
  heightValueScale,
@@ -731,7 +751,7 @@ export const VerticalStackedBarChart = (props)=>{
731
751
  const xPoint = xBarScale(_xAxisType === XAxisTypes.NumericAxis ? singleChartData.xAxisPoint : _xAxisType === XAxisTypes.DateAxis ? singleChartData.xAxisPoint : singleChartData.xAxisPoint);
732
752
  const xScaleBandwidthTranslate = _xAxisType !== XAxisTypes.StringAxis ? -_barWidth / 2 : (xBarScale.bandwidth() - _barWidth) / 2;
733
753
  let barTotalValue = 0;
734
- const barsToDisplay = singleChartData.chartData.filter((point)=>point.data !== 0);
754
+ const barsToDisplay = singleChartData.chartData.filter((point)=>point.data !== 0 && point.data !== '' && !(_yAxisType === YAxisType.StringAxis && typeof yBarScale(point.data) === 'undefined'));
735
755
  if (!barsToDisplay.length) {
736
756
  return undefined;
737
757
  }
@@ -739,7 +759,7 @@ export const VerticalStackedBarChart = (props)=>{
739
759
  if (heightValueScale < 0) {
740
760
  return undefined;
741
761
  }
742
- const yBaseline = containerHeight - _margins.bottom - yBarScale(Y_ORIGIN);
762
+ const yBaseline = containerHeight - _margins.bottom - (_yAxisType === YAxisType.StringAxis ? 0 : yBarScale(Y_ORIGIN));
743
763
  let yPositiveStart = yBaseline;
744
764
  let yNegativeStart = yBaseline;
745
765
  let yPoint = 0;
@@ -759,22 +779,29 @@ export const VerticalStackedBarChart = (props)=>{
759
779
  role: 'img',
760
780
  tabIndex: !props.hideTooltip && shouldHighlight ? 0 : undefined
761
781
  };
762
- let barHeight = Math.abs(heightValueScale * point.data);
763
- // FIXME: The current scaling logic may produce different min and gap heights for each bar stack.
764
- const minHeight = Math.max(heightValueScale * absStackTotal / 100.0, barMinimumHeight);
765
- if (barHeight < minHeight) {
766
- barHeight = minHeight;
767
- }
782
+ let barHeight;
768
783
  const gapOffset = index ? gapHeight : 0;
769
- if (point.data >= Y_ORIGIN) {
784
+ if (_yAxisType === YAxisType.StringAxis) {
785
+ barHeight = Math.max(containerHeight - _margins.bottom - (yBarScale(point.data) + yBarScale.bandwidth() / 2) - gapOffset, barMinimumHeight, 1);
770
786
  yPositiveStart -= barHeight + gapOffset;
771
787
  yPoint = yPositiveStart;
772
788
  } else {
773
- yPoint = yNegativeStart + gapOffset;
774
- yNegativeStart = yPoint + barHeight;
789
+ barHeight = Math.abs(heightValueScale * point.data);
790
+ // FIXME: The current scaling logic may produce different min and gap heights for each bar stack.
791
+ const minHeight = Math.max(heightValueScale * absStackTotal / 100.0, barMinimumHeight);
792
+ if (barHeight < minHeight) {
793
+ barHeight = minHeight;
794
+ }
795
+ if (point.data >= Y_ORIGIN) {
796
+ yPositiveStart -= barHeight + gapOffset;
797
+ yPoint = yPositiveStart;
798
+ } else {
799
+ yPoint = yNegativeStart + gapOffset;
800
+ yNegativeStart = yPoint + barHeight;
801
+ }
802
+ barTotalValue += point.data;
803
+ heightOfLastBar = index === barsToDisplay.length - 1 ? barHeight : 0;
775
804
  }
776
- barTotalValue += point.data;
777
- heightOfLastBar = index === barsToDisplay.length - 1 ? barHeight : 0;
778
805
  if (barCornerRadius && barHeight > barCornerRadius && index === barsToDisplay.length - 1) {
779
806
  return /*#__PURE__*/ React.createElement(React.Fragment, {
780
807
  key: index + indexNumber + `${shouldFocusWholeStack}`
@@ -837,7 +864,7 @@ export const VerticalStackedBarChart = (props)=>{
837
864
  };
838
865
  let showLabel = false;
839
866
  let barLabel = 0;
840
- if (!props.hideLabels) {
867
+ if (!props.hideLabels && _yAxisType !== YAxisType.StringAxis) {
841
868
  if (_noLegendHighlighted()) {
842
869
  showLabel = true;
843
870
  barLabel = barTotalValue;
@@ -907,6 +934,68 @@ export const VerticalStackedBarChart = (props)=>{
907
934
  endValue: d3Max(values)
908
935
  };
909
936
  }
937
+ function _initYAxisParams() {
938
+ if (_points[0].chartData.length > 0) {
939
+ _yAxisType = getTypeOfAxis(_points[0].chartData[0].data, false);
940
+ } else {
941
+ Object.keys(_lineObject).forEach((lineLegend)=>{
942
+ if (!_lineObject[lineLegend][0].useSecondaryYScale) {
943
+ _yAxisType = getTypeOfAxis(_lineObject[lineLegend][0].y, false);
944
+ }
945
+ });
946
+ }
947
+ if (_yAxisType === YAxisType.StringAxis) {
948
+ const legendToYValues = {};
949
+ _points.forEach((xPoint)=>{
950
+ xPoint.chartData.forEach((bar)=>{
951
+ if (!legendToYValues[bar.legend]) {
952
+ legendToYValues[bar.legend] = [
953
+ `${bar.data}`
954
+ ];
955
+ } else {
956
+ legendToYValues[bar.legend].push(`${bar.data}`);
957
+ }
958
+ });
959
+ });
960
+ const yAxisLabels = new Set();
961
+ Object.values(legendToYValues).forEach((yValues)=>{
962
+ yValues.forEach((yVal)=>{
963
+ yAxisLabels.add(yVal);
964
+ });
965
+ });
966
+ Object.values(_lineObject).forEach((linePoints)=>{
967
+ linePoints.forEach((linePoint)=>{
968
+ if (!linePoint.useSecondaryYScale) {
969
+ yAxisLabels.add(`${linePoint.y}`);
970
+ }
971
+ });
972
+ });
973
+ _yAxisLabels = Array.from(yAxisLabels);
974
+ }
975
+ }
976
+ function _getYDomainMargins(containerHeight) {
977
+ /**
978
+ * Specifies the extra top margin to apply above the highest y-axis tick label.
979
+ * Useful when stacked bars extend beyond the combined height of all y-axis labels (or categories).
980
+ */ let yAxisTickMarginTop = 0;
981
+ /** Total height available to render the bars */ const totalHeight = containerHeight - _margins.bottom - _margins.top;
982
+ if (_yAxisType === YAxisType.StringAxis) {
983
+ /** Maximum height of the stacked bars, expressed in multiples of the height of a y-axis label (or category) */ let maxBarHeightInLabels = 0;
984
+ _points.forEach((xPoint)=>{
985
+ /** Height of the stacked bar, expressed in multiples of the height of a y-axis label (or category) */ let barHeightInLabels = 0;
986
+ xPoint.chartData.forEach((bar)=>{
987
+ barHeightInLabels += _yAxisLabels.indexOf(`${bar.data}`) + 1;
988
+ });
989
+ maxBarHeightInLabels = Math.max(maxBarHeightInLabels, barHeightInLabels);
990
+ });
991
+ /** Height of a y-axis label (or category) */ const yAxisLabelHeight = maxBarHeightInLabels === 0 ? 0 : totalHeight / maxBarHeightInLabels;
992
+ yAxisTickMarginTop += yAxisLabelHeight * (maxBarHeightInLabels - _yAxisLabels.length);
993
+ }
994
+ return {
995
+ ..._margins,
996
+ top: _margins.top + yAxisTickMarginTop
997
+ };
998
+ }
910
999
  if (!_isChartEmpty()) {
911
1000
  _adjustProps();
912
1001
  const _isHavingLines = props.data.some((item)=>item.lineData && item.lineData.length > 0);
@@ -962,6 +1051,12 @@ export const VerticalStackedBarChart = (props)=>{
962
1051
  },
963
1052
  componentRef: cartesianChartRef,
964
1053
  showRoundOffXTickValues: !isScalePaddingDefined(props.xAxisInnerPadding, props.xAxisPadding),
1054
+ yAxisType: _yAxisType,
1055
+ stringDatasetForYAxisDomain: [
1056
+ '',
1057
+ ..._yAxisLabels
1058
+ ],
1059
+ getYDomainMargins: _getYDomainMargins,
965
1060
  /* eslint-disable react/jsx-no-bind */ children: (props)=>{
966
1061
  return /*#__PURE__*/ React.createElement(React.Fragment, null, /*#__PURE__*/ React.createElement("g", null, _bars), /*#__PURE__*/ React.createElement("g", null, _isHavingLines && _createLines(props.xScale, props.yScalePrimary, props.containerHeight, props.containerWidth, props.yScaleSecondary)));
967
1062
  }