@mui/x-charts 9.12.0 → 9.13.0

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 (78) hide show
  1. package/BarChart/BarChart.js +1 -1
  2. package/BarChart/BarChart.mjs +1 -1
  3. package/CHANGELOG.md +152 -0
  4. package/ChartsContainer/ChartsContainer.js +1 -1
  5. package/ChartsContainer/ChartsContainer.mjs +1 -1
  6. package/ChartsXAxis/useAxisTicksProps.js +2 -1
  7. package/ChartsXAxis/useAxisTicksProps.mjs +2 -1
  8. package/ChartsYAxis/shortenLabels.js +16 -26
  9. package/ChartsYAxis/shortenLabels.mjs +17 -27
  10. package/ChartsYAxis/useAxisTicksProps.js +2 -1
  11. package/ChartsYAxis/useAxisTicksProps.mjs +2 -1
  12. package/LineChart/LineChart.js +1 -1
  13. package/LineChart/LineChart.mjs +1 -1
  14. package/LineChart/MarkElement.js +13 -6
  15. package/LineChart/MarkElement.mjs +13 -6
  16. package/RadarChart/RadarAxis/RadarAxis.utils.d.mts +1 -1
  17. package/RadarChart/RadarAxis/RadarAxis.utils.d.ts +1 -1
  18. package/RadarChart/RadarChart.js +1 -1
  19. package/RadarChart/RadarChart.mjs +1 -1
  20. package/RadarChart/RadarSeriesPlot/RadarSeriesMarks.js +6 -2
  21. package/RadarChart/RadarSeriesPlot/RadarSeriesMarks.mjs +6 -2
  22. package/RadarChart/RadarSeriesPlot/RadarSeriesPlot.js +2 -1
  23. package/RadarChart/RadarSeriesPlot/RadarSeriesPlot.mjs +2 -1
  24. package/ScatterChart/ScatterChart.js +1 -1
  25. package/ScatterChart/ScatterChart.mjs +1 -1
  26. package/SparkLineChart/SparkLineChart.js +1 -1
  27. package/SparkLineChart/SparkLineChart.mjs +1 -1
  28. package/constants/index.d.mts +3 -1
  29. package/constants/index.d.ts +3 -1
  30. package/constants/index.js +5 -2
  31. package/constants/index.mjs +4 -1
  32. package/hooks/animation/index.d.mts +1 -0
  33. package/hooks/animation/index.d.ts +1 -0
  34. package/hooks/animation/index.js +11 -0
  35. package/hooks/animation/index.mjs +1 -0
  36. package/hooks/animation/useAnimateMark.d.mts +25 -0
  37. package/hooks/animation/useAnimateMark.d.ts +25 -0
  38. package/hooks/animation/useAnimateMark.js +45 -0
  39. package/hooks/animation/useAnimateMark.mjs +39 -0
  40. package/index.js +1 -1
  41. package/index.mjs +1 -1
  42. package/internals/domUtils.js +17 -16
  43. package/internals/domUtils.mjs +17 -15
  44. package/internals/ellipsize.d.mts +30 -0
  45. package/internals/ellipsize.d.ts +30 -0
  46. package/internals/ellipsize.js +60 -0
  47. package/internals/ellipsize.mjs +59 -0
  48. package/internals/index.d.mts +1 -0
  49. package/internals/index.d.ts +1 -0
  50. package/internals/index.js +8 -0
  51. package/internals/index.mjs +1 -0
  52. package/internals/plugins/featurePlugins/useChartCartesianAxis/computeAxisAutoSize.d.mts +3 -0
  53. package/internals/plugins/featurePlugins/useChartCartesianAxis/computeAxisAutoSize.d.ts +3 -0
  54. package/internals/plugins/featurePlugins/useChartCartesianAxis/computeAxisAutoSize.js +9 -5
  55. package/internals/plugins/featurePlugins/useChartCartesianAxis/computeAxisAutoSize.mjs +9 -5
  56. package/internals/plugins/featurePlugins/useChartCartesianAxis/useChartAxisAutoSize.selectors.js +9 -4
  57. package/internals/plugins/featurePlugins/useChartCartesianAxis/useChartAxisAutoSize.selectors.mjs +9 -4
  58. package/internals/plugins/featurePlugins/useChartCartesianAxis/useChartCartesianAxis.js +75 -3
  59. package/internals/plugins/featurePlugins/useChartCartesianAxis/useChartCartesianAxis.mjs +76 -3
  60. package/internals/plugins/featurePlugins/useChartCartesianAxis/useChartCartesianAxis.types.d.mts +6 -2
  61. package/internals/plugins/featurePlugins/useChartCartesianAxis/useChartCartesianAxis.types.d.ts +6 -2
  62. package/internals/plugins/featurePlugins/useChartCartesianAxis/useChartCartesianAxisLayout.selectors.d.mts +1 -0
  63. package/internals/plugins/featurePlugins/useChartCartesianAxis/useChartCartesianAxisLayout.selectors.d.ts +1 -0
  64. package/internals/plugins/featurePlugins/useChartKeyboardNavigation/useChartKeyboardNavigation.js +44 -11
  65. package/internals/plugins/featurePlugins/useChartKeyboardNavigation/useChartKeyboardNavigation.mjs +44 -11
  66. package/internals/plugins/featurePlugins/useChartKeyboardNavigation/utils/getItemAtRotationIndex.d.mts +18 -0
  67. package/internals/plugins/featurePlugins/useChartKeyboardNavigation/utils/getItemAtRotationIndex.d.ts +18 -0
  68. package/internals/plugins/featurePlugins/useChartKeyboardNavigation/utils/getItemAtRotationIndex.js +65 -0
  69. package/internals/plugins/featurePlugins/useChartKeyboardNavigation/utils/getItemAtRotationIndex.mjs +60 -0
  70. package/internals/plugins/featurePlugins/useChartPolarAxis/useChartPolarAxis.js +43 -1
  71. package/internals/plugins/featurePlugins/useChartPolarAxis/useChartPolarAxis.mjs +43 -1
  72. package/internals/plugins/featurePlugins/useChartPolarAxis/useChartPolarAxis.types.d.mts +3 -2
  73. package/internals/plugins/featurePlugins/useChartPolarAxis/useChartPolarAxis.types.d.ts +3 -2
  74. package/internals/useDefaultTickLabelStyle.d.mts +7 -0
  75. package/internals/useDefaultTickLabelStyle.d.ts +7 -0
  76. package/internals/useDefaultTickLabelStyle.js +34 -0
  77. package/internals/useDefaultTickLabelStyle.mjs +28 -0
  78. package/package.json +6 -6
@@ -280,7 +280,7 @@ process.env.NODE_ENV !== "production" ? ScatterChart.propTypes /* remove-proptyp
280
280
  /**
281
281
  * The function called for onClick events.
282
282
  * The second argument contains information about all line/bar elements at the current mouse position.
283
- * @param {MouseEvent} event The mouse event recorded on the `<svg/>` element.
283
+ * @param {ChartsActivationEvent} event The event recorded on the `<svg/>` element.
284
284
  * @param {null | ChartsAxisData} data The data about the clicked axis and items associated with it.
285
285
  */
286
286
  onAxisClick: _propTypes.default.func,
@@ -273,7 +273,7 @@ process.env.NODE_ENV !== "production" ? ScatterChart.propTypes /* remove-proptyp
273
273
  /**
274
274
  * The function called for onClick events.
275
275
  * The second argument contains information about all line/bar elements at the current mouse position.
276
- * @param {MouseEvent} event The mouse event recorded on the `<svg/>` element.
276
+ * @param {ChartsActivationEvent} event The event recorded on the `<svg/>` element.
277
277
  * @param {null | ChartsAxisData} data The data about the clicked axis and items associated with it.
278
278
  */
279
279
  onAxisClick: PropTypes.func,
@@ -460,7 +460,7 @@ process.env.NODE_ENV !== "production" ? SparkLineChart.propTypes /* remove-propt
460
460
  /**
461
461
  * The function called for onClick events.
462
462
  * The second argument contains information about all line/bar elements at the current mouse position.
463
- * @param {MouseEvent} event The mouse event recorded on the `<svg/>` element.
463
+ * @param {ChartsActivationEvent} event The event recorded on the `<svg/>` element.
464
464
  * @param {null | ChartsAxisData} data The data about the clicked axis and items associated with it.
465
465
  */
466
466
  onAxisClick: _propTypes.default.func,
@@ -453,7 +453,7 @@ process.env.NODE_ENV !== "production" ? SparkLineChart.propTypes /* remove-propt
453
453
  /**
454
454
  * The function called for onClick events.
455
455
  * The second argument contains information about all line/bar elements at the current mouse position.
456
- * @param {MouseEvent} event The mouse event recorded on the `<svg/>` element.
456
+ * @param {ChartsActivationEvent} event The event recorded on the `<svg/>` element.
457
457
  * @param {null | ChartsAxisData} data The data about the clicked axis and items associated with it.
458
458
  */
459
459
  onAxisClick: PropTypes.func,
@@ -10,4 +10,6 @@ export declare const DEFAULT_MARGINS: {
10
10
  };
11
11
  export declare const DEFAULT_AXIS_SIZE_WIDTH = 45;
12
12
  export declare const DEFAULT_AXIS_SIZE_HEIGHT = 25;
13
- export declare const AXIS_LABEL_DEFAULT_HEIGHT = 20;
13
+ export declare const AXIS_LABEL_DEFAULT_HEIGHT = 20;
14
+ /** Font size the axes render their tick labels with, unless `tickLabelStyle` overrides it. */
15
+ export declare const DEFAULT_TICK_LABEL_FONT_SIZE = 12;
@@ -10,4 +10,6 @@ export declare const DEFAULT_MARGINS: {
10
10
  };
11
11
  export declare const DEFAULT_AXIS_SIZE_WIDTH = 45;
12
12
  export declare const DEFAULT_AXIS_SIZE_HEIGHT = 25;
13
- export declare const AXIS_LABEL_DEFAULT_HEIGHT = 20;
13
+ export declare const AXIS_LABEL_DEFAULT_HEIGHT = 20;
14
+ /** Font size the axes render their tick labels with, unless `tickLabelStyle` overrides it. */
15
+ export declare const DEFAULT_TICK_LABEL_FONT_SIZE = 12;
@@ -3,7 +3,7 @@
3
3
  Object.defineProperty(exports, "__esModule", {
4
4
  value: true
5
5
  });
6
- exports.DEFAULT_Y_AXIS_KEY = exports.DEFAULT_X_AXIS_KEY = exports.DEFAULT_ROTATION_AXIS_KEY = exports.DEFAULT_RADIUS_AXIS_KEY = exports.DEFAULT_MARGINS = exports.DEFAULT_AXIS_SIZE_WIDTH = exports.DEFAULT_AXIS_SIZE_HEIGHT = exports.AXIS_LABEL_DEFAULT_HEIGHT = void 0;
6
+ exports.DEFAULT_Y_AXIS_KEY = exports.DEFAULT_X_AXIS_KEY = exports.DEFAULT_TICK_LABEL_FONT_SIZE = exports.DEFAULT_ROTATION_AXIS_KEY = exports.DEFAULT_RADIUS_AXIS_KEY = exports.DEFAULT_MARGINS = exports.DEFAULT_AXIS_SIZE_WIDTH = exports.DEFAULT_AXIS_SIZE_HEIGHT = exports.AXIS_LABEL_DEFAULT_HEIGHT = void 0;
7
7
  const DEFAULT_X_AXIS_KEY = exports.DEFAULT_X_AXIS_KEY = 'DEFAULT_X_AXIS_KEY';
8
8
  const DEFAULT_Y_AXIS_KEY = exports.DEFAULT_Y_AXIS_KEY = 'DEFAULT_Y_AXIS_KEY';
9
9
  const DEFAULT_ROTATION_AXIS_KEY = exports.DEFAULT_ROTATION_AXIS_KEY = 'DEFAULT_ROTATION_AXIS_KEY';
@@ -16,4 +16,7 @@ const DEFAULT_MARGINS = exports.DEFAULT_MARGINS = {
16
16
  };
17
17
  const DEFAULT_AXIS_SIZE_WIDTH = exports.DEFAULT_AXIS_SIZE_WIDTH = 45;
18
18
  const DEFAULT_AXIS_SIZE_HEIGHT = exports.DEFAULT_AXIS_SIZE_HEIGHT = 25;
19
- const AXIS_LABEL_DEFAULT_HEIGHT = exports.AXIS_LABEL_DEFAULT_HEIGHT = 20;
19
+ const AXIS_LABEL_DEFAULT_HEIGHT = exports.AXIS_LABEL_DEFAULT_HEIGHT = 20;
20
+
21
+ /** Font size the axes render their tick labels with, unless `tickLabelStyle` overrides it. */
22
+ const DEFAULT_TICK_LABEL_FONT_SIZE = exports.DEFAULT_TICK_LABEL_FONT_SIZE = 12;
@@ -10,4 +10,7 @@ export const DEFAULT_MARGINS = {
10
10
  };
11
11
  export const DEFAULT_AXIS_SIZE_WIDTH = 45;
12
12
  export const DEFAULT_AXIS_SIZE_HEIGHT = 25;
13
- export const AXIS_LABEL_DEFAULT_HEIGHT = 20;
13
+ export const AXIS_LABEL_DEFAULT_HEIGHT = 20;
14
+
15
+ /** Font size the axes render their tick labels with, unless `tickLabelStyle` overrides it. */
16
+ export const DEFAULT_TICK_LABEL_FONT_SIZE = 12;
@@ -3,5 +3,6 @@ export * from "./useAnimateArea.mjs";
3
3
  export * from "./useAnimateBar.mjs";
4
4
  export * from "./useAnimateBarLabel.mjs";
5
5
  export * from "./useAnimateLine.mjs";
6
+ export * from "./useAnimateMark.mjs";
6
7
  export * from "./useAnimatePieArc.mjs";
7
8
  export * from "./useAnimatePieArcLabel.mjs";
@@ -3,5 +3,6 @@ export * from "./useAnimateArea.js";
3
3
  export * from "./useAnimateBar.js";
4
4
  export * from "./useAnimateBarLabel.js";
5
5
  export * from "./useAnimateLine.js";
6
+ export * from "./useAnimateMark.js";
6
7
  export * from "./useAnimatePieArc.js";
7
8
  export * from "./useAnimatePieArcLabel.js";
@@ -58,6 +58,17 @@ Object.keys(_useAnimateLine).forEach(function (key) {
58
58
  }
59
59
  });
60
60
  });
61
+ var _useAnimateMark = require("./useAnimateMark");
62
+ Object.keys(_useAnimateMark).forEach(function (key) {
63
+ if (key === "default" || key === "__esModule") return;
64
+ if (key in exports && exports[key] === _useAnimateMark[key]) return;
65
+ Object.defineProperty(exports, key, {
66
+ enumerable: true,
67
+ get: function () {
68
+ return _useAnimateMark[key];
69
+ }
70
+ });
71
+ });
61
72
  var _useAnimatePieArc = require("./useAnimatePieArc");
62
73
  Object.keys(_useAnimatePieArc).forEach(function (key) {
63
74
  if (key === "default" || key === "__esModule") return;
@@ -3,5 +3,6 @@ export * from "./useAnimateArea.mjs";
3
3
  export * from "./useAnimateBar.mjs";
4
4
  export * from "./useAnimateBarLabel.mjs";
5
5
  export * from "./useAnimateLine.mjs";
6
+ export * from "./useAnimateMark.mjs";
6
7
  export * from "./useAnimatePieArc.mjs";
7
8
  export * from "./useAnimatePieArcLabel.mjs";
@@ -0,0 +1,25 @@
1
+ import type * as React from 'react';
2
+ type UseAnimateMarkParams = {
3
+ x: number;
4
+ y: number;
5
+ skipAnimation?: boolean;
6
+ ref?: React.Ref<SVGPathElement>;
7
+ };
8
+ type UseAnimateMarkReturn = {
9
+ ref: React.Ref<SVGPathElement>;
10
+ transform: string;
11
+ };
12
+ /**
13
+ * Animates the position of a line chart mark.
14
+ *
15
+ * The mark is placed with the SVG `transform` attribute, in `viewBox` units, because Safari resolves CSS pixel
16
+ * transforms of SVG children against the viewport instead of the scaled `viewBox`, which moves the mark away from the
17
+ * line under browser zoom. See https://github.com/mui/mui-x/issues/23377.
18
+ *
19
+ * Safari cannot transition the `transform` attribute with CSS, so the animation runs in JavaScript.
20
+ *
21
+ * The props object also accepts a `ref` which will be merged with the ref returned from this hook. This means you can
22
+ * pass the ref returned by this hook to the `path` element and the `ref` provided as argument will also be called.
23
+ */
24
+ export declare function useAnimateMark(props: UseAnimateMarkParams): UseAnimateMarkReturn;
25
+ export {};
@@ -0,0 +1,25 @@
1
+ import type * as React from 'react';
2
+ type UseAnimateMarkParams = {
3
+ x: number;
4
+ y: number;
5
+ skipAnimation?: boolean;
6
+ ref?: React.Ref<SVGPathElement>;
7
+ };
8
+ type UseAnimateMarkReturn = {
9
+ ref: React.Ref<SVGPathElement>;
10
+ transform: string;
11
+ };
12
+ /**
13
+ * Animates the position of a line chart mark.
14
+ *
15
+ * The mark is placed with the SVG `transform` attribute, in `viewBox` units, because Safari resolves CSS pixel
16
+ * transforms of SVG children against the viewport instead of the scaled `viewBox`, which moves the mark away from the
17
+ * line under browser zoom. See https://github.com/mui/mui-x/issues/23377.
18
+ *
19
+ * Safari cannot transition the `transform` attribute with CSS, so the animation runs in JavaScript.
20
+ *
21
+ * The props object also accepts a `ref` which will be merged with the ref returned from this hook. This means you can
22
+ * pass the ref returned by this hook to the `path` element and the `ref` provided as argument will also be called.
23
+ */
24
+ export declare function useAnimateMark(props: UseAnimateMarkParams): UseAnimateMarkReturn;
25
+ export {};
@@ -0,0 +1,45 @@
1
+ "use strict";
2
+
3
+ Object.defineProperty(exports, "__esModule", {
4
+ value: true
5
+ });
6
+ exports.useAnimateMark = useAnimateMark;
7
+ var _d3Interpolate = require("@mui/x-charts-vendor/d3-interpolate");
8
+ var _useAnimate = require("./useAnimate");
9
+ function markPropsInterpolator(from, to) {
10
+ const interpolateX = (0, _d3Interpolate.interpolateNumber)(from.x, to.x);
11
+ const interpolateY = (0, _d3Interpolate.interpolateNumber)(from.y, to.y);
12
+ return t => ({
13
+ x: interpolateX(t),
14
+ y: interpolateY(t)
15
+ });
16
+ }
17
+
18
+ /**
19
+ * Animates the position of a line chart mark.
20
+ *
21
+ * The mark is placed with the SVG `transform` attribute, in `viewBox` units, because Safari resolves CSS pixel
22
+ * transforms of SVG children against the viewport instead of the scaled `viewBox`, which moves the mark away from the
23
+ * line under browser zoom. See https://github.com/mui/mui-x/issues/23377.
24
+ *
25
+ * Safari cannot transition the `transform` attribute with CSS, so the animation runs in JavaScript.
26
+ *
27
+ * The props object also accepts a `ref` which will be merged with the ref returned from this hook. This means you can
28
+ * pass the ref returned by this hook to the `path` element and the `ref` provided as argument will also be called.
29
+ */
30
+ function useAnimateMark(props) {
31
+ return (0, _useAnimate.useAnimate)({
32
+ x: props.x,
33
+ y: props.y
34
+ }, {
35
+ createInterpolator: markPropsInterpolator,
36
+ transformProps: p => ({
37
+ transform: `translate(${p.x} ${p.y})`
38
+ }),
39
+ applyProps(element, animatedProps) {
40
+ element.setAttribute('transform', animatedProps.transform);
41
+ },
42
+ skip: props.skipAnimation,
43
+ ref: props.ref
44
+ });
45
+ }
@@ -0,0 +1,39 @@
1
+ import { interpolateNumber } from '@mui/x-charts-vendor/d3-interpolate';
2
+ import { useAnimate } from "./useAnimate.mjs";
3
+ function markPropsInterpolator(from, to) {
4
+ const interpolateX = interpolateNumber(from.x, to.x);
5
+ const interpolateY = interpolateNumber(from.y, to.y);
6
+ return t => ({
7
+ x: interpolateX(t),
8
+ y: interpolateY(t)
9
+ });
10
+ }
11
+
12
+ /**
13
+ * Animates the position of a line chart mark.
14
+ *
15
+ * The mark is placed with the SVG `transform` attribute, in `viewBox` units, because Safari resolves CSS pixel
16
+ * transforms of SVG children against the viewport instead of the scaled `viewBox`, which moves the mark away from the
17
+ * line under browser zoom. See https://github.com/mui/mui-x/issues/23377.
18
+ *
19
+ * Safari cannot transition the `transform` attribute with CSS, so the animation runs in JavaScript.
20
+ *
21
+ * The props object also accepts a `ref` which will be merged with the ref returned from this hook. This means you can
22
+ * pass the ref returned by this hook to the `path` element and the `ref` provided as argument will also be called.
23
+ */
24
+ export function useAnimateMark(props) {
25
+ return useAnimate({
26
+ x: props.x,
27
+ y: props.y
28
+ }, {
29
+ createInterpolator: markPropsInterpolator,
30
+ transformProps: p => ({
31
+ transform: `translate(${p.x} ${p.y})`
32
+ }),
33
+ applyProps(element, animatedProps) {
34
+ element.setAttribute('transform', animatedProps.transform);
35
+ },
36
+ skip: props.skipAnimation,
37
+ ref: props.ref
38
+ });
39
+ }
package/index.js CHANGED
@@ -1,5 +1,5 @@
1
1
  /**
2
- * @mui/x-charts v9.12.0
2
+ * @mui/x-charts v9.13.0
3
3
  *
4
4
  * @license MIT
5
5
  * This source code is licensed under the MIT license found in the
package/index.mjs CHANGED
@@ -1,5 +1,5 @@
1
1
  /**
2
- * @mui/x-charts v9.12.0
2
+ * @mui/x-charts v9.13.0
3
3
  *
4
4
  * @license MIT
5
5
  * This source code is licensed under the MIT license found in the
@@ -1,6 +1,5 @@
1
1
  "use strict";
2
2
 
3
- var _interopRequireDefault = require("@babel/runtime/helpers/interopRequireDefault").default;
4
3
  Object.defineProperty(exports, "__esModule", {
5
4
  value: true
6
5
  });
@@ -8,7 +7,6 @@ exports.batchMeasureStrings = batchMeasureStrings;
8
7
  exports.clearStringMeasurementCache = clearStringMeasurementCache;
9
8
  exports.getStringSize = void 0;
10
9
  exports.getStyleString = getStyleString;
11
- var _extends2 = _interopRequireDefault(require("@babel/runtime/helpers/extends"));
12
10
  // DOM utils adapted from
13
11
  // https://github.com/recharts/recharts/blob/master/src/util/DOMUtils.ts
14
12
 
@@ -64,6 +62,17 @@ function getStyleString(style) {
64
62
  return result;
65
63
  }
66
64
 
65
+ /**
66
+ * Applies a style to a measurement element.
67
+ * Uses the CSS Object Model (CSSOM) to comply with Content Security Policy (CSP).
68
+ * https://en.wikipedia.org/wiki/Content_Security_Policy
69
+ */
70
+ function applyStyle(element, style) {
71
+ for (const styleKey of Object.keys(style)) {
72
+ element.style[camelCaseToDashCase(styleKey)] = convertPixelValue(styleKey, style[styleKey]);
73
+ }
74
+ }
75
+
67
76
  /**
68
77
  *
69
78
  * @param text The string to estimate
@@ -87,13 +96,7 @@ const getStringSize = (text, style = {}) => {
87
96
  try {
88
97
  const measurementSpanContainer = getMeasurementContainer();
89
98
  const measurementElem = document.createElementNS('http://www.w3.org/2000/svg', 'text');
90
-
91
- // Need to use CSS Object Model (CSSOM) to be able to comply with Content Security Policy (CSP)
92
- // https://en.wikipedia.org/wiki/Content_Security_Policy
93
- Object.keys(style).map(styleKey => {
94
- measurementElem.style[camelCaseToDashCase(styleKey)] = convertPixelValue(styleKey, style[styleKey]);
95
- return styleKey;
96
- });
99
+ applyStyle(measurementElem, style);
97
100
  measurementElem.textContent = str;
98
101
  measurementSpanContainer.replaceChildren(measurementElem);
99
102
  const result = measureSVGTextElement(measurementElem);
@@ -134,16 +137,14 @@ function batchMeasureStrings(texts, style = {}) {
134
137
  }
135
138
  }
136
139
  const measurementContainer = getMeasurementContainer();
137
- // Need to use CSS Object Model (CSSOM) to be able to comply with Content Security Policy (CSP)
138
- // https://en.wikipedia.org/wiki/Content_Security_Policy
139
- const measurementSpanStyle = (0, _extends2.default)({}, style);
140
- Object.keys(measurementSpanStyle).map(styleKey => {
141
- measurementContainer.style[camelCaseToDashCase(styleKey)] = convertPixelValue(styleKey, measurementSpanStyle[styleKey]);
142
- return styleKey;
143
- });
140
+
141
+ // The style goes on each text element rather than on the shared container. Styling the container
142
+ // leaks into every later measurement, because a call that omits one of those properties keeps the
143
+ // previous call's value and measures the wrong font.
144
144
  const measurementElements = [];
145
145
  for (const string of textToMeasure) {
146
146
  const measurementElem = document.createElementNS('http://www.w3.org/2000/svg', 'text');
147
+ applyStyle(measurementElem, style);
147
148
  measurementElem.textContent = `${string}`;
148
149
  measurementElements.push(measurementElem);
149
150
  }
@@ -1,4 +1,3 @@
1
- import _extends from "@babel/runtime/helpers/esm/extends";
2
1
  // DOM utils adapted from
3
2
  // https://github.com/recharts/recharts/blob/master/src/util/DOMUtils.ts
4
3
 
@@ -54,6 +53,17 @@ export function getStyleString(style) {
54
53
  return result;
55
54
  }
56
55
 
56
+ /**
57
+ * Applies a style to a measurement element.
58
+ * Uses the CSS Object Model (CSSOM) to comply with Content Security Policy (CSP).
59
+ * https://en.wikipedia.org/wiki/Content_Security_Policy
60
+ */
61
+ function applyStyle(element, style) {
62
+ for (const styleKey of Object.keys(style)) {
63
+ element.style[camelCaseToDashCase(styleKey)] = convertPixelValue(styleKey, style[styleKey]);
64
+ }
65
+ }
66
+
57
67
  /**
58
68
  *
59
69
  * @param text The string to estimate
@@ -77,13 +87,7 @@ export const getStringSize = (text, style = {}) => {
77
87
  try {
78
88
  const measurementSpanContainer = getMeasurementContainer();
79
89
  const measurementElem = document.createElementNS('http://www.w3.org/2000/svg', 'text');
80
-
81
- // Need to use CSS Object Model (CSSOM) to be able to comply with Content Security Policy (CSP)
82
- // https://en.wikipedia.org/wiki/Content_Security_Policy
83
- Object.keys(style).map(styleKey => {
84
- measurementElem.style[camelCaseToDashCase(styleKey)] = convertPixelValue(styleKey, style[styleKey]);
85
- return styleKey;
86
- });
90
+ applyStyle(measurementElem, style);
87
91
  measurementElem.textContent = str;
88
92
  measurementSpanContainer.replaceChildren(measurementElem);
89
93
  const result = measureSVGTextElement(measurementElem);
@@ -123,16 +127,14 @@ export function batchMeasureStrings(texts, style = {}) {
123
127
  }
124
128
  }
125
129
  const measurementContainer = getMeasurementContainer();
126
- // Need to use CSS Object Model (CSSOM) to be able to comply with Content Security Policy (CSP)
127
- // https://en.wikipedia.org/wiki/Content_Security_Policy
128
- const measurementSpanStyle = _extends({}, style);
129
- Object.keys(measurementSpanStyle).map(styleKey => {
130
- measurementContainer.style[camelCaseToDashCase(styleKey)] = convertPixelValue(styleKey, measurementSpanStyle[styleKey]);
131
- return styleKey;
132
- });
130
+
131
+ // The style goes on each text element rather than on the shared container. Styling the container
132
+ // leaks into every later measurement, because a call that omits one of those properties keeps the
133
+ // previous call's value and measures the wrong font.
133
134
  const measurementElements = [];
134
135
  for (const string of textToMeasure) {
135
136
  const measurementElem = document.createElementNS('http://www.w3.org/2000/svg', 'text');
137
+ applyStyle(measurementElem, style);
136
138
  measurementElem.textContent = `${string}`;
137
139
  measurementElements.push(measurementElem);
138
140
  }
@@ -1,3 +1,4 @@
1
+ import type { ChartsTextAnchor, ChartsTextBaseline } from "./getWordsByLines.mjs";
1
2
  interface EllipsizeConfig {
2
3
  width: number;
3
4
  height: number;
@@ -9,6 +10,35 @@ interface EllipsizeConfig {
9
10
  };
10
11
  }
11
12
  export declare function doesTextFitInRect(text: string, config: EllipsizeConfig): boolean;
13
+ export interface RotatedTextBoundsConfig {
14
+ /** Angle, in degrees, in which the text is displayed. */
15
+ angle: number;
16
+ textAnchor?: ChartsTextAnchor;
17
+ dominantBaseline?: ChartsTextBaseline;
18
+ isRtl?: boolean;
19
+ }
20
+ export interface RotatedTextBounds {
21
+ /** Width of the text bounding box once rotated. */
22
+ width: number;
23
+ /** How far the text extends above its anchor point. */
24
+ above: number;
25
+ /** How far the text extends below its anchor point. */
26
+ below: number;
27
+ }
28
+ /**
29
+ * Returns the size of a rotated text, and how far it extends on each side of its anchor point.
30
+ *
31
+ * Which side of the anchor the text is drawn on depends on both the text anchoring and the rotation,
32
+ * so `above` and `below` are not necessarily equal. Either of them is negative when the whole text
33
+ * sits on the other side of the anchor point.
34
+ *
35
+ * @param textSize The size of the text before rotation.
36
+ * @param config How the text is anchored and rotated.
37
+ */
38
+ export declare function getRotatedTextBounds(textSize: {
39
+ width: number;
40
+ height: number;
41
+ }, config: RotatedTextBoundsConfig): RotatedTextBounds;
12
42
  /** This function finds the best place to clip the text to add an ellipsis.
13
43
  * This function assumes that the {@link doesTextFit} never returns true for longer text after returning false for
14
44
  * shorter text.
@@ -1,3 +1,4 @@
1
+ import type { ChartsTextAnchor, ChartsTextBaseline } from "./getWordsByLines.js";
1
2
  interface EllipsizeConfig {
2
3
  width: number;
3
4
  height: number;
@@ -9,6 +10,35 @@ interface EllipsizeConfig {
9
10
  };
10
11
  }
11
12
  export declare function doesTextFitInRect(text: string, config: EllipsizeConfig): boolean;
13
+ export interface RotatedTextBoundsConfig {
14
+ /** Angle, in degrees, in which the text is displayed. */
15
+ angle: number;
16
+ textAnchor?: ChartsTextAnchor;
17
+ dominantBaseline?: ChartsTextBaseline;
18
+ isRtl?: boolean;
19
+ }
20
+ export interface RotatedTextBounds {
21
+ /** Width of the text bounding box once rotated. */
22
+ width: number;
23
+ /** How far the text extends above its anchor point. */
24
+ above: number;
25
+ /** How far the text extends below its anchor point. */
26
+ below: number;
27
+ }
28
+ /**
29
+ * Returns the size of a rotated text, and how far it extends on each side of its anchor point.
30
+ *
31
+ * Which side of the anchor the text is drawn on depends on both the text anchoring and the rotation,
32
+ * so `above` and `below` are not necessarily equal. Either of them is negative when the whole text
33
+ * sits on the other side of the anchor point.
34
+ *
35
+ * @param textSize The size of the text before rotation.
36
+ * @param config How the text is anchored and rotated.
37
+ */
38
+ export declare function getRotatedTextBounds(textSize: {
39
+ width: number;
40
+ height: number;
41
+ }, config: RotatedTextBoundsConfig): RotatedTextBounds;
12
42
  /** This function finds the best place to clip the text to add an ellipsis.
13
43
  * This function assumes that the {@link doesTextFit} never returns true for longer text after returning false for
14
44
  * shorter text.
@@ -5,6 +5,7 @@ Object.defineProperty(exports, "__esModule", {
5
5
  });
6
6
  exports.doesTextFitInRect = doesTextFitInRect;
7
7
  exports.ellipsize = ellipsize;
8
+ exports.getRotatedTextBounds = getRotatedTextBounds;
8
9
  var _getGraphemeCount = require("./getGraphemeCount");
9
10
  var _degToRad = require("./degToRad");
10
11
  var _sliceUntil = require("./sliceUntil");
@@ -22,6 +23,65 @@ function doesTextFitInRect(text, config) {
22
23
  return angledWidth <= width && angledHeight <= height;
23
24
  }
24
25
 
26
+ /**
27
+ * Position of the text bounding box relative to its anchor point, as a fraction of the text width.
28
+ * `0` means the box starts at the anchor, `-1` that it ends there.
29
+ */
30
+ function getHorizontalAnchorOffset(textAnchor, isRtl) {
31
+ const anchor = textAnchor ?? 'middle';
32
+ if (anchor === 'middle') {
33
+ return -1 / 2;
34
+ }
35
+ const startsAtAnchor = isRtl ? anchor === 'end' : anchor === 'start';
36
+ return startsAtAnchor ? 0 : -1;
37
+ }
38
+
39
+ /**
40
+ * Position of the text bounding box relative to its anchor point, as a fraction of the text height.
41
+ * `0` means the box starts at the anchor, `-1` that it ends there.
42
+ */
43
+ function getVerticalAnchorOffset(dominantBaseline) {
44
+ switch (dominantBaseline ?? 'central') {
45
+ case 'hanging':
46
+ case 'text-before-edge':
47
+ return 0;
48
+ case 'central':
49
+ return -1 / 2;
50
+ default:
51
+ return -1;
52
+ }
53
+ }
54
+ /**
55
+ * Returns the size of a rotated text, and how far it extends on each side of its anchor point.
56
+ *
57
+ * Which side of the anchor the text is drawn on depends on both the text anchoring and the rotation,
58
+ * so `above` and `below` are not necessarily equal. Either of them is negative when the whole text
59
+ * sits on the other side of the anchor point.
60
+ *
61
+ * @param textSize The size of the text before rotation.
62
+ * @param config How the text is anchored and rotated.
63
+ */
64
+ function getRotatedTextBounds(textSize, config) {
65
+ const angle = (0, _degToRad.degToRad)(config.angle);
66
+ const sin = Math.sin(angle);
67
+ const cos = Math.cos(angle);
68
+ const left = getHorizontalAnchorOffset(config.textAnchor, config.isRtl ?? false) * textSize.width;
69
+ const right = left + textSize.width;
70
+ const top = getVerticalAnchorOffset(config.dominantBaseline) * textSize.height;
71
+ const bottom = top + textSize.height;
72
+
73
+ /* A rotation by `angle` maps a point to `(x * cos - y * sin, x * sin + y * cos)`. Both terms of
74
+ * the vertical coordinate are independent, so the extrema of their sum are the sums of their
75
+ * extrema. */
76
+ const fromWidth = [left * sin, right * sin];
77
+ const fromHeight = [top * cos, bottom * cos];
78
+ return {
79
+ width: Math.abs(textSize.width * cos) + Math.abs(textSize.height * sin),
80
+ above: -(Math.min(...fromWidth) + Math.min(...fromHeight)),
81
+ below: Math.max(...fromWidth) + Math.max(...fromHeight)
82
+ };
83
+ }
84
+
25
85
  /** This function finds the best place to clip the text to add an ellipsis.
26
86
  * This function assumes that the {@link doesTextFit} never returns true for longer text after returning false for
27
87
  * shorter text.
@@ -15,6 +15,65 @@ export function doesTextFitInRect(text, config) {
15
15
  return angledWidth <= width && angledHeight <= height;
16
16
  }
17
17
 
18
+ /**
19
+ * Position of the text bounding box relative to its anchor point, as a fraction of the text width.
20
+ * `0` means the box starts at the anchor, `-1` that it ends there.
21
+ */
22
+ function getHorizontalAnchorOffset(textAnchor, isRtl) {
23
+ const anchor = textAnchor ?? 'middle';
24
+ if (anchor === 'middle') {
25
+ return -1 / 2;
26
+ }
27
+ const startsAtAnchor = isRtl ? anchor === 'end' : anchor === 'start';
28
+ return startsAtAnchor ? 0 : -1;
29
+ }
30
+
31
+ /**
32
+ * Position of the text bounding box relative to its anchor point, as a fraction of the text height.
33
+ * `0` means the box starts at the anchor, `-1` that it ends there.
34
+ */
35
+ function getVerticalAnchorOffset(dominantBaseline) {
36
+ switch (dominantBaseline ?? 'central') {
37
+ case 'hanging':
38
+ case 'text-before-edge':
39
+ return 0;
40
+ case 'central':
41
+ return -1 / 2;
42
+ default:
43
+ return -1;
44
+ }
45
+ }
46
+ /**
47
+ * Returns the size of a rotated text, and how far it extends on each side of its anchor point.
48
+ *
49
+ * Which side of the anchor the text is drawn on depends on both the text anchoring and the rotation,
50
+ * so `above` and `below` are not necessarily equal. Either of them is negative when the whole text
51
+ * sits on the other side of the anchor point.
52
+ *
53
+ * @param textSize The size of the text before rotation.
54
+ * @param config How the text is anchored and rotated.
55
+ */
56
+ export function getRotatedTextBounds(textSize, config) {
57
+ const angle = degToRad(config.angle);
58
+ const sin = Math.sin(angle);
59
+ const cos = Math.cos(angle);
60
+ const left = getHorizontalAnchorOffset(config.textAnchor, config.isRtl ?? false) * textSize.width;
61
+ const right = left + textSize.width;
62
+ const top = getVerticalAnchorOffset(config.dominantBaseline) * textSize.height;
63
+ const bottom = top + textSize.height;
64
+
65
+ /* A rotation by `angle` maps a point to `(x * cos - y * sin, x * sin + y * cos)`. Both terms of
66
+ * the vertical coordinate are independent, so the extrema of their sum are the sums of their
67
+ * extrema. */
68
+ const fromWidth = [left * sin, right * sin];
69
+ const fromHeight = [top * cos, bottom * cos];
70
+ return {
71
+ width: Math.abs(textSize.width * cos) + Math.abs(textSize.height * sin),
72
+ above: -(Math.min(...fromWidth) + Math.min(...fromHeight)),
73
+ below: Math.max(...fromWidth) + Math.max(...fromHeight)
74
+ };
75
+ }
76
+
18
77
  /** This function finds the best place to clip the text to add an ellipsis.
19
78
  * This function assumes that the {@link doesTextFit} never returns true for longer text after returning false for
20
79
  * shorter text.
@@ -83,6 +83,7 @@ export { processLineLikeSeries } from "./processLineLikeSeries.mjs";
83
83
  export { getLineLikeTooltip } from "./getLineLikeTooltip.mjs";
84
84
  export { checkBarChartScaleErrors } from "../BarChart/checkBarChartScaleErrors.mjs";
85
85
  export { getBandSize } from "./getBandSize.mjs";
86
+ export { useDefaultTickLabelStyle } from "./useDefaultTickLabelStyle.mjs";
86
87
  export * from "./plugins/utils/defaultSeriesConfig.mjs";
87
88
  export { EPSILON } from "../utils/epsilon.mjs";
88
89
  export { useUtilityClasses as useChartsTooltipUtilityClasses, getChartsTooltipUtilityClass } from "../ChartsTooltip/chartsTooltipClasses.mjs";
@@ -83,6 +83,7 @@ export { processLineLikeSeries } from "./processLineLikeSeries.js";
83
83
  export { getLineLikeTooltip } from "./getLineLikeTooltip.js";
84
84
  export { checkBarChartScaleErrors } from "../BarChart/checkBarChartScaleErrors.js";
85
85
  export { getBandSize } from "./getBandSize.js";
86
+ export { useDefaultTickLabelStyle } from "./useDefaultTickLabelStyle.js";
86
87
  export * from "./plugins/utils/defaultSeriesConfig.js";
87
88
  export { EPSILON } from "../utils/epsilon.js";
88
89
  export { useUtilityClasses as useChartsTooltipUtilityClasses, getChartsTooltipUtilityClass } from "../ChartsTooltip/chartsTooltipClasses.js";