diff --git a/e2e/screenshots/all.test.ts-snapshots/baselines/axes/tick-label-truncation-chrome-linux.png b/e2e/screenshots/all.test.ts-snapshots/baselines/axes/tick-label-truncation-chrome-linux.png new file mode 100644 index 00000000000..231da0af2de Binary files /dev/null and b/e2e/screenshots/all.test.ts-snapshots/baselines/axes/tick-label-truncation-chrome-linux.png differ diff --git a/e2e/screenshots/all.test.ts-snapshots/baselines/stylings/partition-labels-chrome-linux.png b/e2e/screenshots/all.test.ts-snapshots/baselines/stylings/partition-labels-chrome-linux.png index 6d69c930377..c160270bb7d 100644 Binary files a/e2e/screenshots/all.test.ts-snapshots/baselines/stylings/partition-labels-chrome-linux.png and b/e2e/screenshots/all.test.ts-snapshots/baselines/stylings/partition-labels-chrome-linux.png differ diff --git a/e2e/screenshots/all.test.ts-snapshots/baselines/sunburst/bold-link-value-chrome-linux.png b/e2e/screenshots/all.test.ts-snapshots/baselines/sunburst/bold-link-value-chrome-linux.png index 8c017d5d89d..27a0999eb88 100644 Binary files a/e2e/screenshots/all.test.ts-snapshots/baselines/sunburst/bold-link-value-chrome-linux.png and b/e2e/screenshots/all.test.ts-snapshots/baselines/sunburst/bold-link-value-chrome-linux.png differ diff --git a/e2e/screenshots/all.test.ts-snapshots/baselines/sunburst/counter-clockwise-special-chrome-linux.png b/e2e/screenshots/all.test.ts-snapshots/baselines/sunburst/counter-clockwise-special-chrome-linux.png index e382fcd7163..0879bbf99a7 100644 Binary files a/e2e/screenshots/all.test.ts-snapshots/baselines/sunburst/counter-clockwise-special-chrome-linux.png and b/e2e/screenshots/all.test.ts-snapshots/baselines/sunburst/counter-clockwise-special-chrome-linux.png differ diff --git a/e2e/screenshots/all.test.ts-snapshots/baselines/sunburst/donut-chart-with-fill-labels-chrome-linux.png b/e2e/screenshots/all.test.ts-snapshots/baselines/sunburst/donut-chart-with-fill-labels-chrome-linux.png index b716c6b22de..b153d9e6d2f 100644 Binary files a/e2e/screenshots/all.test.ts-snapshots/baselines/sunburst/donut-chart-with-fill-labels-chrome-linux.png and b/e2e/screenshots/all.test.ts-snapshots/baselines/sunburst/donut-chart-with-fill-labels-chrome-linux.png differ diff --git a/e2e/screenshots/all.test.ts-snapshots/baselines/sunburst/linked-labels-only-chrome-linux.png b/e2e/screenshots/all.test.ts-snapshots/baselines/sunburst/linked-labels-only-chrome-linux.png index 4722d448335..3bdbe02c109 100644 Binary files a/e2e/screenshots/all.test.ts-snapshots/baselines/sunburst/linked-labels-only-chrome-linux.png and b/e2e/screenshots/all.test.ts-snapshots/baselines/sunburst/linked-labels-only-chrome-linux.png differ diff --git a/e2e/screenshots/all.test.ts-snapshots/baselines/sunburst/most-basic-chrome-linux.png b/e2e/screenshots/all.test.ts-snapshots/baselines/sunburst/most-basic-chrome-linux.png index 41d4e82c405..50cdf1effaa 100644 Binary files a/e2e/screenshots/all.test.ts-snapshots/baselines/sunburst/most-basic-chrome-linux.png and b/e2e/screenshots/all.test.ts-snapshots/baselines/sunburst/most-basic-chrome-linux.png differ diff --git a/e2e/screenshots/all.test.ts-snapshots/baselines/sunburst/negative-chrome-linux.png b/e2e/screenshots/all.test.ts-snapshots/baselines/sunburst/negative-chrome-linux.png index d52eb5a7f60..beb1fe2c926 100644 Binary files a/e2e/screenshots/all.test.ts-snapshots/baselines/sunburst/negative-chrome-linux.png and b/e2e/screenshots/all.test.ts-snapshots/baselines/sunburst/negative-chrome-linux.png differ diff --git a/e2e/screenshots/all.test.ts-snapshots/baselines/sunburst/not-a-number-chrome-linux.png b/e2e/screenshots/all.test.ts-snapshots/baselines/sunburst/not-a-number-chrome-linux.png index d52eb5a7f60..beb1fe2c926 100644 Binary files a/e2e/screenshots/all.test.ts-snapshots/baselines/sunburst/not-a-number-chrome-linux.png and b/e2e/screenshots/all.test.ts-snapshots/baselines/sunburst/not-a-number-chrome-linux.png differ diff --git a/e2e/screenshots/all.test.ts-snapshots/baselines/sunburst/some-zero-value-slice-chrome-linux.png b/e2e/screenshots/all.test.ts-snapshots/baselines/sunburst/some-zero-value-slice-chrome-linux.png index 18cb81bf462..db712735bfe 100644 Binary files a/e2e/screenshots/all.test.ts-snapshots/baselines/sunburst/some-zero-value-slice-chrome-linux.png and b/e2e/screenshots/all.test.ts-snapshots/baselines/sunburst/some-zero-value-slice-chrome-linux.png differ diff --git a/e2e/screenshots/all.test.ts-snapshots/baselines/sunburst/value-formatted-with-categorical-color-palette-chrome-linux.png b/e2e/screenshots/all.test.ts-snapshots/baselines/sunburst/value-formatted-with-categorical-color-palette-chrome-linux.png index dcdfe7a4976..0883a169a74 100644 Binary files a/e2e/screenshots/all.test.ts-snapshots/baselines/sunburst/value-formatted-with-categorical-color-palette-chrome-linux.png and b/e2e/screenshots/all.test.ts-snapshots/baselines/sunburst/value-formatted-with-categorical-color-palette-chrome-linux.png differ diff --git a/e2e/screenshots/all.test.ts-snapshots/baselines/sunburst/with-fill-labels-chrome-linux.png b/e2e/screenshots/all.test.ts-snapshots/baselines/sunburst/with-fill-labels-chrome-linux.png index 20b496804eb..687d03bd96e 100644 Binary files a/e2e/screenshots/all.test.ts-snapshots/baselines/sunburst/with-fill-labels-chrome-linux.png and b/e2e/screenshots/all.test.ts-snapshots/baselines/sunburst/with-fill-labels-chrome-linux.png differ diff --git a/e2e/screenshots/all.test.ts-snapshots/baselines/sunburst/with-linked-text-labels-chrome-linux.png b/e2e/screenshots/all.test.ts-snapshots/baselines/sunburst/with-linked-text-labels-chrome-linux.png index 9df01c950a9..0705ca1c3e5 100644 Binary files a/e2e/screenshots/all.test.ts-snapshots/baselines/sunburst/with-linked-text-labels-chrome-linux.png and b/e2e/screenshots/all.test.ts-snapshots/baselines/sunburst/with-linked-text-labels-chrome-linux.png differ diff --git a/e2e/screenshots/partition_stories.test.ts-snapshots/axis-stories/fill-label-textcolor-sunburst/should-show-custom-black-text-color-chrome-linux.png b/e2e/screenshots/partition_stories.test.ts-snapshots/axis-stories/fill-label-textcolor-sunburst/should-show-custom-black-text-color-chrome-linux.png index 7cfca24041c..10d014f77e6 100644 Binary files a/e2e/screenshots/partition_stories.test.ts-snapshots/axis-stories/fill-label-textcolor-sunburst/should-show-custom-black-text-color-chrome-linux.png and b/e2e/screenshots/partition_stories.test.ts-snapshots/axis-stories/fill-label-textcolor-sunburst/should-show-custom-black-text-color-chrome-linux.png differ diff --git a/e2e/screenshots/partition_stories.test.ts-snapshots/axis-stories/fill-label-textcolor-sunburst/should-show-custom-black-translucent-text-color-chrome-linux.png b/e2e/screenshots/partition_stories.test.ts-snapshots/axis-stories/fill-label-textcolor-sunburst/should-show-custom-black-translucent-text-color-chrome-linux.png index a7b094f15de..5f03d0af5b7 100644 Binary files a/e2e/screenshots/partition_stories.test.ts-snapshots/axis-stories/fill-label-textcolor-sunburst/should-show-custom-black-translucent-text-color-chrome-linux.png and b/e2e/screenshots/partition_stories.test.ts-snapshots/axis-stories/fill-label-textcolor-sunburst/should-show-custom-black-translucent-text-color-chrome-linux.png differ diff --git a/e2e/screenshots/partition_stories.test.ts-snapshots/axis-stories/fill-label-textcolor-sunburst/should-show-custom-red-text-color-chrome-linux.png b/e2e/screenshots/partition_stories.test.ts-snapshots/axis-stories/fill-label-textcolor-sunburst/should-show-custom-red-text-color-chrome-linux.png index 5aef68313c9..205092f75b6 100644 Binary files a/e2e/screenshots/partition_stories.test.ts-snapshots/axis-stories/fill-label-textcolor-sunburst/should-show-custom-red-text-color-chrome-linux.png and b/e2e/screenshots/partition_stories.test.ts-snapshots/axis-stories/fill-label-textcolor-sunburst/should-show-custom-red-text-color-chrome-linux.png differ diff --git a/e2e/screenshots/partition_stories.test.ts-snapshots/axis-stories/fill-label-textcolor-sunburst/should-show-custom-white-text-color-chrome-linux.png b/e2e/screenshots/partition_stories.test.ts-snapshots/axis-stories/fill-label-textcolor-sunburst/should-show-custom-white-text-color-chrome-linux.png index bdbe4e59312..914d5ce6eca 100644 Binary files a/e2e/screenshots/partition_stories.test.ts-snapshots/axis-stories/fill-label-textcolor-sunburst/should-show-custom-white-text-color-chrome-linux.png and b/e2e/screenshots/partition_stories.test.ts-snapshots/axis-stories/fill-label-textcolor-sunburst/should-show-custom-white-text-color-chrome-linux.png differ diff --git a/e2e/screenshots/partition_stories.test.ts-snapshots/axis-stories/fill-label-textcolor-sunburst/should-show-custom-white-translucent-text-color-chrome-linux.png b/e2e/screenshots/partition_stories.test.ts-snapshots/axis-stories/fill-label-textcolor-sunburst/should-show-custom-white-translucent-text-color-chrome-linux.png index 53420ec0d79..0a91c548763 100644 Binary files a/e2e/screenshots/partition_stories.test.ts-snapshots/axis-stories/fill-label-textcolor-sunburst/should-show-custom-white-translucent-text-color-chrome-linux.png and b/e2e/screenshots/partition_stories.test.ts-snapshots/axis-stories/fill-label-textcolor-sunburst/should-show-custom-white-translucent-text-color-chrome-linux.png differ diff --git a/e2e/screenshots/partition_stories.test.ts-snapshots/axis-stories/link-label-textcolor-dark-theme/should-show-custom-black-text-color-chrome-linux.png b/e2e/screenshots/partition_stories.test.ts-snapshots/axis-stories/link-label-textcolor-dark-theme/should-show-custom-black-text-color-chrome-linux.png index b48e8abf4aa..8743ba979d9 100644 Binary files a/e2e/screenshots/partition_stories.test.ts-snapshots/axis-stories/link-label-textcolor-dark-theme/should-show-custom-black-text-color-chrome-linux.png and b/e2e/screenshots/partition_stories.test.ts-snapshots/axis-stories/link-label-textcolor-dark-theme/should-show-custom-black-text-color-chrome-linux.png differ diff --git a/e2e/screenshots/partition_stories.test.ts-snapshots/axis-stories/link-label-textcolor-dark-theme/should-show-custom-black-translucent-text-color-chrome-linux.png b/e2e/screenshots/partition_stories.test.ts-snapshots/axis-stories/link-label-textcolor-dark-theme/should-show-custom-black-translucent-text-color-chrome-linux.png index 458171e2888..a43b62426c2 100644 Binary files a/e2e/screenshots/partition_stories.test.ts-snapshots/axis-stories/link-label-textcolor-dark-theme/should-show-custom-black-translucent-text-color-chrome-linux.png and b/e2e/screenshots/partition_stories.test.ts-snapshots/axis-stories/link-label-textcolor-dark-theme/should-show-custom-black-translucent-text-color-chrome-linux.png differ diff --git a/e2e/screenshots/partition_stories.test.ts-snapshots/axis-stories/link-label-textcolor-dark-theme/should-show-custom-red-text-color-chrome-linux.png b/e2e/screenshots/partition_stories.test.ts-snapshots/axis-stories/link-label-textcolor-dark-theme/should-show-custom-red-text-color-chrome-linux.png index 04e1804a77a..1ddef3b08ee 100644 Binary files a/e2e/screenshots/partition_stories.test.ts-snapshots/axis-stories/link-label-textcolor-dark-theme/should-show-custom-red-text-color-chrome-linux.png and b/e2e/screenshots/partition_stories.test.ts-snapshots/axis-stories/link-label-textcolor-dark-theme/should-show-custom-red-text-color-chrome-linux.png differ diff --git a/e2e/screenshots/partition_stories.test.ts-snapshots/axis-stories/link-label-textcolor-dark-theme/should-show-custom-white-text-color-chrome-linux.png b/e2e/screenshots/partition_stories.test.ts-snapshots/axis-stories/link-label-textcolor-dark-theme/should-show-custom-white-text-color-chrome-linux.png index 8ca20dfafc4..aa0e644a09f 100644 Binary files a/e2e/screenshots/partition_stories.test.ts-snapshots/axis-stories/link-label-textcolor-dark-theme/should-show-custom-white-text-color-chrome-linux.png and b/e2e/screenshots/partition_stories.test.ts-snapshots/axis-stories/link-label-textcolor-dark-theme/should-show-custom-white-text-color-chrome-linux.png differ diff --git a/e2e/screenshots/partition_stories.test.ts-snapshots/axis-stories/link-label-textcolor-dark-theme/should-show-custom-white-translucent-text-color-chrome-linux.png b/e2e/screenshots/partition_stories.test.ts-snapshots/axis-stories/link-label-textcolor-dark-theme/should-show-custom-white-translucent-text-color-chrome-linux.png index 06e72b92ed7..340527e05a2 100644 Binary files a/e2e/screenshots/partition_stories.test.ts-snapshots/axis-stories/link-label-textcolor-dark-theme/should-show-custom-white-translucent-text-color-chrome-linux.png and b/e2e/screenshots/partition_stories.test.ts-snapshots/axis-stories/link-label-textcolor-dark-theme/should-show-custom-white-translucent-text-color-chrome-linux.png differ diff --git a/e2e/screenshots/partition_stories.test.ts-snapshots/axis-stories/link-label-textcolor-dark-theme/should-show-default-text-color-chrome-linux.png b/e2e/screenshots/partition_stories.test.ts-snapshots/axis-stories/link-label-textcolor-dark-theme/should-show-default-text-color-chrome-linux.png index c356895658f..bdd95ab1b07 100644 Binary files a/e2e/screenshots/partition_stories.test.ts-snapshots/axis-stories/link-label-textcolor-dark-theme/should-show-default-text-color-chrome-linux.png and b/e2e/screenshots/partition_stories.test.ts-snapshots/axis-stories/link-label-textcolor-dark-theme/should-show-default-text-color-chrome-linux.png differ diff --git a/e2e/screenshots/partition_stories.test.ts-snapshots/axis-stories/link-label-textcolor-light-theme/should-show-custom-black-text-color-chrome-linux.png b/e2e/screenshots/partition_stories.test.ts-snapshots/axis-stories/link-label-textcolor-light-theme/should-show-custom-black-text-color-chrome-linux.png index 4722d448335..3bdbe02c109 100644 Binary files a/e2e/screenshots/partition_stories.test.ts-snapshots/axis-stories/link-label-textcolor-light-theme/should-show-custom-black-text-color-chrome-linux.png and b/e2e/screenshots/partition_stories.test.ts-snapshots/axis-stories/link-label-textcolor-light-theme/should-show-custom-black-text-color-chrome-linux.png differ diff --git a/e2e/screenshots/partition_stories.test.ts-snapshots/axis-stories/link-label-textcolor-light-theme/should-show-custom-black-translucent-text-color-chrome-linux.png b/e2e/screenshots/partition_stories.test.ts-snapshots/axis-stories/link-label-textcolor-light-theme/should-show-custom-black-translucent-text-color-chrome-linux.png index 5c68f96bbb5..72141e509c1 100644 Binary files a/e2e/screenshots/partition_stories.test.ts-snapshots/axis-stories/link-label-textcolor-light-theme/should-show-custom-black-translucent-text-color-chrome-linux.png and b/e2e/screenshots/partition_stories.test.ts-snapshots/axis-stories/link-label-textcolor-light-theme/should-show-custom-black-translucent-text-color-chrome-linux.png differ diff --git a/e2e/screenshots/partition_stories.test.ts-snapshots/axis-stories/link-label-textcolor-light-theme/should-show-custom-red-text-color-chrome-linux.png b/e2e/screenshots/partition_stories.test.ts-snapshots/axis-stories/link-label-textcolor-light-theme/should-show-custom-red-text-color-chrome-linux.png index fbefcc0a973..55255778fee 100644 Binary files a/e2e/screenshots/partition_stories.test.ts-snapshots/axis-stories/link-label-textcolor-light-theme/should-show-custom-red-text-color-chrome-linux.png and b/e2e/screenshots/partition_stories.test.ts-snapshots/axis-stories/link-label-textcolor-light-theme/should-show-custom-red-text-color-chrome-linux.png differ diff --git a/e2e/screenshots/partition_stories.test.ts-snapshots/axis-stories/link-label-textcolor-light-theme/should-show-default-text-color-chrome-linux.png b/e2e/screenshots/partition_stories.test.ts-snapshots/axis-stories/link-label-textcolor-light-theme/should-show-default-text-color-chrome-linux.png index 3a48c019d9e..c5426485d34 100644 Binary files a/e2e/screenshots/partition_stories.test.ts-snapshots/axis-stories/link-label-textcolor-light-theme/should-show-default-text-color-chrome-linux.png and b/e2e/screenshots/partition_stories.test.ts-snapshots/axis-stories/link-label-textcolor-light-theme/should-show-default-text-color-chrome-linux.png differ diff --git a/e2e/screenshots/partition_stories.test.ts-snapshots/axis-stories/should-render-link-labels-with-fallback-text-color-for-dark-theme-chrome-linux.png b/e2e/screenshots/partition_stories.test.ts-snapshots/axis-stories/should-render-link-labels-with-fallback-text-color-for-dark-theme-chrome-linux.png index 324c90ea3a8..a36df22f5ce 100644 Binary files a/e2e/screenshots/partition_stories.test.ts-snapshots/axis-stories/should-render-link-labels-with-fallback-text-color-for-dark-theme-chrome-linux.png and b/e2e/screenshots/partition_stories.test.ts-snapshots/axis-stories/should-render-link-labels-with-fallback-text-color-for-dark-theme-chrome-linux.png differ diff --git a/e2e/screenshots/partition_stories.test.ts-snapshots/axis-stories/should-render-link-labels-with-fallback-text-color-for-light-theme-chrome-linux.png b/e2e/screenshots/partition_stories.test.ts-snapshots/axis-stories/should-render-link-labels-with-fallback-text-color-for-light-theme-chrome-linux.png index dcdfe7a4976..0883a169a74 100644 Binary files a/e2e/screenshots/partition_stories.test.ts-snapshots/axis-stories/should-render-link-labels-with-fallback-text-color-for-light-theme-chrome-linux.png and b/e2e/screenshots/partition_stories.test.ts-snapshots/axis-stories/should-render-link-labels-with-fallback-text-color-for-light-theme-chrome-linux.png differ diff --git a/e2e/screenshots/test_cases_stories.test.ts-snapshots/test-cases-stories/rtl-support/sunburst-chart-type/lang-ar/ltr-text/should-render-with-correct-direction-chrome-linux.png b/e2e/screenshots/test_cases_stories.test.ts-snapshots/test-cases-stories/rtl-support/sunburst-chart-type/lang-ar/ltr-text/should-render-with-correct-direction-chrome-linux.png index d808c76a31c..8cb91eecaa4 100644 Binary files a/e2e/screenshots/test_cases_stories.test.ts-snapshots/test-cases-stories/rtl-support/sunburst-chart-type/lang-ar/ltr-text/should-render-with-correct-direction-chrome-linux.png and b/e2e/screenshots/test_cases_stories.test.ts-snapshots/test-cases-stories/rtl-support/sunburst-chart-type/lang-ar/ltr-text/should-render-with-correct-direction-chrome-linux.png differ diff --git a/e2e/screenshots/test_cases_stories.test.ts-snapshots/test-cases-stories/rtl-support/sunburst-chart-type/lang-ar/ltr-text/should-render-with-correct-direction-clockwise-sectors-chrome-linux.png b/e2e/screenshots/test_cases_stories.test.ts-snapshots/test-cases-stories/rtl-support/sunburst-chart-type/lang-ar/ltr-text/should-render-with-correct-direction-clockwise-sectors-chrome-linux.png index 898d9504d1f..be88ee2e134 100644 Binary files a/e2e/screenshots/test_cases_stories.test.ts-snapshots/test-cases-stories/rtl-support/sunburst-chart-type/lang-ar/ltr-text/should-render-with-correct-direction-clockwise-sectors-chrome-linux.png and b/e2e/screenshots/test_cases_stories.test.ts-snapshots/test-cases-stories/rtl-support/sunburst-chart-type/lang-ar/ltr-text/should-render-with-correct-direction-clockwise-sectors-chrome-linux.png differ diff --git a/e2e/screenshots/test_cases_stories.test.ts-snapshots/test-cases-stories/rtl-support/sunburst-chart-type/lang-ar/mostly-ltr-text/should-render-with-correct-direction-chrome-linux.png b/e2e/screenshots/test_cases_stories.test.ts-snapshots/test-cases-stories/rtl-support/sunburst-chart-type/lang-ar/mostly-ltr-text/should-render-with-correct-direction-chrome-linux.png index 272b9558a90..e8404871e83 100644 Binary files a/e2e/screenshots/test_cases_stories.test.ts-snapshots/test-cases-stories/rtl-support/sunburst-chart-type/lang-ar/mostly-ltr-text/should-render-with-correct-direction-chrome-linux.png and b/e2e/screenshots/test_cases_stories.test.ts-snapshots/test-cases-stories/rtl-support/sunburst-chart-type/lang-ar/mostly-ltr-text/should-render-with-correct-direction-chrome-linux.png differ diff --git a/e2e/screenshots/test_cases_stories.test.ts-snapshots/test-cases-stories/rtl-support/sunburst-chart-type/lang-ar/mostly-ltr-text/should-render-with-correct-direction-clockwise-sectors-chrome-linux.png b/e2e/screenshots/test_cases_stories.test.ts-snapshots/test-cases-stories/rtl-support/sunburst-chart-type/lang-ar/mostly-ltr-text/should-render-with-correct-direction-clockwise-sectors-chrome-linux.png index 99422c3c75a..9bb5c37222b 100644 Binary files a/e2e/screenshots/test_cases_stories.test.ts-snapshots/test-cases-stories/rtl-support/sunburst-chart-type/lang-ar/mostly-ltr-text/should-render-with-correct-direction-clockwise-sectors-chrome-linux.png and b/e2e/screenshots/test_cases_stories.test.ts-snapshots/test-cases-stories/rtl-support/sunburst-chart-type/lang-ar/mostly-ltr-text/should-render-with-correct-direction-clockwise-sectors-chrome-linux.png differ diff --git a/e2e/screenshots/test_cases_stories.test.ts-snapshots/test-cases-stories/rtl-support/sunburst-chart-type/lang-ar/mostly-rtl-text/should-render-with-correct-direction-chrome-linux.png b/e2e/screenshots/test_cases_stories.test.ts-snapshots/test-cases-stories/rtl-support/sunburst-chart-type/lang-ar/mostly-rtl-text/should-render-with-correct-direction-chrome-linux.png index ebc9f42bc87..ac60acb3804 100644 Binary files a/e2e/screenshots/test_cases_stories.test.ts-snapshots/test-cases-stories/rtl-support/sunburst-chart-type/lang-ar/mostly-rtl-text/should-render-with-correct-direction-chrome-linux.png and b/e2e/screenshots/test_cases_stories.test.ts-snapshots/test-cases-stories/rtl-support/sunburst-chart-type/lang-ar/mostly-rtl-text/should-render-with-correct-direction-chrome-linux.png differ diff --git a/e2e/screenshots/test_cases_stories.test.ts-snapshots/test-cases-stories/rtl-support/sunburst-chart-type/lang-ar/mostly-rtl-text/should-render-with-correct-direction-clockwise-sectors-chrome-linux.png b/e2e/screenshots/test_cases_stories.test.ts-snapshots/test-cases-stories/rtl-support/sunburst-chart-type/lang-ar/mostly-rtl-text/should-render-with-correct-direction-clockwise-sectors-chrome-linux.png index 348b3f8214c..8d9df53a525 100644 Binary files a/e2e/screenshots/test_cases_stories.test.ts-snapshots/test-cases-stories/rtl-support/sunburst-chart-type/lang-ar/mostly-rtl-text/should-render-with-correct-direction-clockwise-sectors-chrome-linux.png and b/e2e/screenshots/test_cases_stories.test.ts-snapshots/test-cases-stories/rtl-support/sunburst-chart-type/lang-ar/mostly-rtl-text/should-render-with-correct-direction-clockwise-sectors-chrome-linux.png differ diff --git a/e2e/screenshots/test_cases_stories.test.ts-snapshots/test-cases-stories/rtl-support/sunburst-chart-type/lang-ar/rtl-text/should-render-with-correct-direction-chrome-linux.png b/e2e/screenshots/test_cases_stories.test.ts-snapshots/test-cases-stories/rtl-support/sunburst-chart-type/lang-ar/rtl-text/should-render-with-correct-direction-chrome-linux.png index b4c0f272394..e160c432eec 100644 Binary files a/e2e/screenshots/test_cases_stories.test.ts-snapshots/test-cases-stories/rtl-support/sunburst-chart-type/lang-ar/rtl-text/should-render-with-correct-direction-chrome-linux.png and b/e2e/screenshots/test_cases_stories.test.ts-snapshots/test-cases-stories/rtl-support/sunburst-chart-type/lang-ar/rtl-text/should-render-with-correct-direction-chrome-linux.png differ diff --git a/e2e/screenshots/test_cases_stories.test.ts-snapshots/test-cases-stories/rtl-support/sunburst-chart-type/lang-ar/rtl-text/should-render-with-correct-direction-clockwise-sectors-chrome-linux.png b/e2e/screenshots/test_cases_stories.test.ts-snapshots/test-cases-stories/rtl-support/sunburst-chart-type/lang-ar/rtl-text/should-render-with-correct-direction-clockwise-sectors-chrome-linux.png index 1dac75eede2..dbf6df3e151 100644 Binary files a/e2e/screenshots/test_cases_stories.test.ts-snapshots/test-cases-stories/rtl-support/sunburst-chart-type/lang-ar/rtl-text/should-render-with-correct-direction-clockwise-sectors-chrome-linux.png and b/e2e/screenshots/test_cases_stories.test.ts-snapshots/test-cases-stories/rtl-support/sunburst-chart-type/lang-ar/rtl-text/should-render-with-correct-direction-clockwise-sectors-chrome-linux.png differ diff --git a/e2e/screenshots/test_cases_stories.test.ts-snapshots/test-cases-stories/rtl-support/sunburst-chart-type/lang-he/ltr-text/should-render-with-correct-direction-chrome-linux.png b/e2e/screenshots/test_cases_stories.test.ts-snapshots/test-cases-stories/rtl-support/sunburst-chart-type/lang-he/ltr-text/should-render-with-correct-direction-chrome-linux.png index d808c76a31c..8cb91eecaa4 100644 Binary files a/e2e/screenshots/test_cases_stories.test.ts-snapshots/test-cases-stories/rtl-support/sunburst-chart-type/lang-he/ltr-text/should-render-with-correct-direction-chrome-linux.png and b/e2e/screenshots/test_cases_stories.test.ts-snapshots/test-cases-stories/rtl-support/sunburst-chart-type/lang-he/ltr-text/should-render-with-correct-direction-chrome-linux.png differ diff --git a/e2e/screenshots/test_cases_stories.test.ts-snapshots/test-cases-stories/rtl-support/sunburst-chart-type/lang-he/ltr-text/should-render-with-correct-direction-clockwise-sectors-chrome-linux.png b/e2e/screenshots/test_cases_stories.test.ts-snapshots/test-cases-stories/rtl-support/sunburst-chart-type/lang-he/ltr-text/should-render-with-correct-direction-clockwise-sectors-chrome-linux.png index 898d9504d1f..be88ee2e134 100644 Binary files a/e2e/screenshots/test_cases_stories.test.ts-snapshots/test-cases-stories/rtl-support/sunburst-chart-type/lang-he/ltr-text/should-render-with-correct-direction-clockwise-sectors-chrome-linux.png and b/e2e/screenshots/test_cases_stories.test.ts-snapshots/test-cases-stories/rtl-support/sunburst-chart-type/lang-he/ltr-text/should-render-with-correct-direction-clockwise-sectors-chrome-linux.png differ diff --git a/e2e/screenshots/test_cases_stories.test.ts-snapshots/test-cases-stories/rtl-support/sunburst-chart-type/lang-he/mostly-ltr-text/should-render-with-correct-direction-chrome-linux.png b/e2e/screenshots/test_cases_stories.test.ts-snapshots/test-cases-stories/rtl-support/sunburst-chart-type/lang-he/mostly-ltr-text/should-render-with-correct-direction-chrome-linux.png index e4ae74b86b9..ad109d5c6ae 100644 Binary files a/e2e/screenshots/test_cases_stories.test.ts-snapshots/test-cases-stories/rtl-support/sunburst-chart-type/lang-he/mostly-ltr-text/should-render-with-correct-direction-chrome-linux.png and b/e2e/screenshots/test_cases_stories.test.ts-snapshots/test-cases-stories/rtl-support/sunburst-chart-type/lang-he/mostly-ltr-text/should-render-with-correct-direction-chrome-linux.png differ diff --git a/e2e/screenshots/test_cases_stories.test.ts-snapshots/test-cases-stories/rtl-support/sunburst-chart-type/lang-he/mostly-ltr-text/should-render-with-correct-direction-clockwise-sectors-chrome-linux.png b/e2e/screenshots/test_cases_stories.test.ts-snapshots/test-cases-stories/rtl-support/sunburst-chart-type/lang-he/mostly-ltr-text/should-render-with-correct-direction-clockwise-sectors-chrome-linux.png index 2967e08d19b..a5f71a41140 100644 Binary files a/e2e/screenshots/test_cases_stories.test.ts-snapshots/test-cases-stories/rtl-support/sunburst-chart-type/lang-he/mostly-ltr-text/should-render-with-correct-direction-clockwise-sectors-chrome-linux.png and b/e2e/screenshots/test_cases_stories.test.ts-snapshots/test-cases-stories/rtl-support/sunburst-chart-type/lang-he/mostly-ltr-text/should-render-with-correct-direction-clockwise-sectors-chrome-linux.png differ diff --git a/e2e/screenshots/test_cases_stories.test.ts-snapshots/test-cases-stories/rtl-support/sunburst-chart-type/lang-he/mostly-rtl-text/should-render-with-correct-direction-chrome-linux.png b/e2e/screenshots/test_cases_stories.test.ts-snapshots/test-cases-stories/rtl-support/sunburst-chart-type/lang-he/mostly-rtl-text/should-render-with-correct-direction-chrome-linux.png index 47f2e392be8..064e21c2434 100644 Binary files a/e2e/screenshots/test_cases_stories.test.ts-snapshots/test-cases-stories/rtl-support/sunburst-chart-type/lang-he/mostly-rtl-text/should-render-with-correct-direction-chrome-linux.png and b/e2e/screenshots/test_cases_stories.test.ts-snapshots/test-cases-stories/rtl-support/sunburst-chart-type/lang-he/mostly-rtl-text/should-render-with-correct-direction-chrome-linux.png differ diff --git a/e2e/screenshots/test_cases_stories.test.ts-snapshots/test-cases-stories/rtl-support/sunburst-chart-type/lang-he/mostly-rtl-text/should-render-with-correct-direction-clockwise-sectors-chrome-linux.png b/e2e/screenshots/test_cases_stories.test.ts-snapshots/test-cases-stories/rtl-support/sunburst-chart-type/lang-he/mostly-rtl-text/should-render-with-correct-direction-clockwise-sectors-chrome-linux.png index 43a8f030b58..51f583f5928 100644 Binary files a/e2e/screenshots/test_cases_stories.test.ts-snapshots/test-cases-stories/rtl-support/sunburst-chart-type/lang-he/mostly-rtl-text/should-render-with-correct-direction-clockwise-sectors-chrome-linux.png and b/e2e/screenshots/test_cases_stories.test.ts-snapshots/test-cases-stories/rtl-support/sunburst-chart-type/lang-he/mostly-rtl-text/should-render-with-correct-direction-clockwise-sectors-chrome-linux.png differ diff --git a/e2e/screenshots/test_cases_stories.test.ts-snapshots/test-cases-stories/rtl-support/sunburst-chart-type/lang-he/rtl-text/should-render-with-correct-direction-chrome-linux.png b/e2e/screenshots/test_cases_stories.test.ts-snapshots/test-cases-stories/rtl-support/sunburst-chart-type/lang-he/rtl-text/should-render-with-correct-direction-chrome-linux.png index c7d795fbc66..b683446d0c9 100644 Binary files a/e2e/screenshots/test_cases_stories.test.ts-snapshots/test-cases-stories/rtl-support/sunburst-chart-type/lang-he/rtl-text/should-render-with-correct-direction-chrome-linux.png and b/e2e/screenshots/test_cases_stories.test.ts-snapshots/test-cases-stories/rtl-support/sunburst-chart-type/lang-he/rtl-text/should-render-with-correct-direction-chrome-linux.png differ diff --git a/e2e/screenshots/test_cases_stories.test.ts-snapshots/test-cases-stories/rtl-support/sunburst-chart-type/lang-he/rtl-text/should-render-with-correct-direction-clockwise-sectors-chrome-linux.png b/e2e/screenshots/test_cases_stories.test.ts-snapshots/test-cases-stories/rtl-support/sunburst-chart-type/lang-he/rtl-text/should-render-with-correct-direction-clockwise-sectors-chrome-linux.png index 021f6e73fbd..cd594886563 100644 Binary files a/e2e/screenshots/test_cases_stories.test.ts-snapshots/test-cases-stories/rtl-support/sunburst-chart-type/lang-he/rtl-text/should-render-with-correct-direction-clockwise-sectors-chrome-linux.png and b/e2e/screenshots/test_cases_stories.test.ts-snapshots/test-cases-stories/rtl-support/sunburst-chart-type/lang-he/rtl-text/should-render-with-correct-direction-clockwise-sectors-chrome-linux.png differ diff --git a/packages/charts/api/charts.api.md b/packages/charts/api/charts.api.md index 136c7117475..9be4499017c 100644 --- a/packages/charts/api/charts.api.md +++ b/packages/charts/api/charts.api.md @@ -246,7 +246,7 @@ export interface ArrayNode extends NodeDescriptor { } // @public -export const Axis: FC>; +export const Axis: FC>; // @public (undocumented) export type AxisId = string; @@ -275,6 +275,8 @@ export interface AxisSpec extends Spec { specType: typeof SpecType.Axis; style?: RecursivePartial>; tickFormat?: TickFormatter; + tickLabelMaxLength?: Pixels | string; + tickLabelTruncate?: Truncate; ticks?: number; // @alpha timeAxisLayerCount: number; @@ -3539,6 +3541,9 @@ export interface TreeNode extends AngleFromTo { y1: TreeLevel; } +// @public (undocumented) +export type Truncate = 'start' | 'middle' | 'end'; + // @public export interface UnaryAccessorFn { // (undocumented) diff --git a/packages/charts/src/chart_types/partition_chart/layout/viewmodel/link_text_layout.ts b/packages/charts/src/chart_types/partition_chart/layout/viewmodel/link_text_layout.ts index d5b6969610a..d1cd752b443 100644 --- a/packages/charts/src/chart_types/partition_chart/layout/viewmodel/link_text_layout.ts +++ b/packages/charts/src/chart_types/partition_chart/layout/viewmodel/link_text_layout.ts @@ -179,13 +179,12 @@ function nodeToLinkLabel({ text: valueText, isValue: false, }); - const widthAdjustment = valueWidth + 2 * linkLabel.fontSize; // gap between label and value, plus possibly 2em wide ellipsis // label text removes space allotted for value and gaps, then tries to fit as much as possible const labelText = cutToLength(rawLabelText, maxTextLength); const allottedLabelWidth = Math.max( 0, - rightSide ? rectWidth - diskCenter.x - translateX - widthAdjustment : diskCenter.x + translateX - widthAdjustment, + rightSide ? rectWidth - diskCenter.x - translateX - valueWidth : diskCenter.x + translateX - valueWidth, ); const { text, width } = linkLabel.fontSize / 2 <= cy + diskCenter.y && cy + diskCenter.y <= rectHeight - linkLabel.fontSize / 2 diff --git a/packages/charts/src/chart_types/xy_chart/state/selectors/axis_tick_formatter.test.ts b/packages/charts/src/chart_types/xy_chart/state/selectors/axis_tick_formatter.test.ts new file mode 100644 index 00000000000..e1168b93b30 --- /dev/null +++ b/packages/charts/src/chart_types/xy_chart/state/selectors/axis_tick_formatter.test.ts @@ -0,0 +1,58 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0 and the Server Side Public License, v 1; you may not use this file except + * in compliance with, at your election, the Elastic License 2.0 or the Server + * Side Public License, v 1. + */ + +import { withTickLabelTruncation } from './axis_tick_formatter'; +import * as textUtils from '../../../../common/text_utils'; +import { MockGlobalSpec } from '../../../../mocks/specs'; +import { LIGHT_THEME } from '../../../../utils/themes/light_theme'; + +const { + axes: { tickLabel }, +} = LIGHT_THEME; + +describe('withTickLabelTruncation', () => { + const measure = jest.fn((text: string) => ({ width: text.length, height: tickLabel.fontSize })); + const fitTextSpy = jest.spyOn(textUtils, 'fitText').mockReturnValue({ width: 0, text: 'tickLabel' }); + it('does not call fitText when maxLength is undefined', () => { + const axisSpec = MockGlobalSpec.yAxis({ tickLabelMaxLength: undefined, tickLabelTruncate: 'end' }); + + withTickLabelTruncation(measure, tickLabel, axisSpec, 200)((v: number) => `${v}`); + expect(fitTextSpy).not.toHaveBeenCalled(); + }); + + it("calls fitText with half the container width when maxLength is '50%'", () => { + const containerWidth = 200; + const axisSpec = MockGlobalSpec.yAxis({ tickLabelMaxLength: '50%', tickLabelTruncate: 'end' }); + const format = withTickLabelTruncation(measure, tickLabel, axisSpec, containerWidth)((v) => `${v}`); + format('tickLabel'); + expect(fitTextSpy).toHaveBeenCalledWith( + measure, + 'tickLabel', + containerWidth / 2, + tickLabel.fontSize, + expect.any(Object), + axisSpec.tickLabelTruncate ?? 'end', + ); + }); + + it('calls fitText with the numeric maxLength as maximum width', () => { + const maxLengthPx = 72; + const axisSpec = MockGlobalSpec.yAxis({ tickLabelMaxLength: maxLengthPx, tickLabelTruncate: 'end' }); + const format = withTickLabelTruncation(measure, tickLabel, axisSpec, 400)((v) => `${v}`); + format('tickLabel'); + + expect(fitTextSpy).toHaveBeenCalledWith( + measure, + 'tickLabel', + maxLengthPx, + tickLabel.fontSize, + expect.any(Object), + axisSpec.tickLabelTruncate ?? 'end', + ); + }); +}); diff --git a/packages/charts/src/chart_types/xy_chart/state/selectors/axis_tick_formatter.ts b/packages/charts/src/chart_types/xy_chart/state/selectors/axis_tick_formatter.ts index 1166688dae8..8e25c6fca6f 100644 --- a/packages/charts/src/chart_types/xy_chart/state/selectors/axis_tick_formatter.ts +++ b/packages/charts/src/chart_types/xy_chart/state/selectors/axis_tick_formatter.ts @@ -8,10 +8,14 @@ import { getScaleConfigsFromSpecsSelector } from './get_api_scale_configs'; import { getAxisSpecsSelector, getSeriesSpecsSelector } from './get_specs'; +import type { Font } from '../../../../common/text_utils'; +import { fitText } from '../../../../common/text_utils'; import { createCustomCachedSelector } from '../../../../state/create_selector'; import { getSettingsSpecSelector } from '../../../../state/selectors/get_settings_spec'; -import type { Rotation } from '../../../../utils/common'; +import type { TextMeasure } from '../../../../utils/bbox/canvas_text_bbox_calculator'; +import { getPercentageValue, type Rotation } from '../../../../utils/common'; import type { SpecId } from '../../../../utils/ids'; +import type { AxisStyle } from '../../../../utils/themes/theme'; import { defaultTickFormatter, isXDomain } from '../../utils/axis_utils'; import { groupBy } from '../../utils/group_data_series'; import type { AxisSpec } from '../../utils/specs'; @@ -22,6 +26,30 @@ export type AxisLabelFormatter = (value: V) => string; /** @internal */ export type AxisLabelFormatters = { x: Map; y: Map }; +/** @internal */ +export function withTickLabelTruncation( + measure: TextMeasure, + tickLabel: AxisStyle['tickLabel'], + axisSpec: AxisSpec, + containerWidth: number, +): (formatter: AxisLabelFormatter) => AxisLabelFormatter { + const { fontSize, fontStyle, fontFamily, fill } = tickLabel; + const { tickLabelMaxLength: maxLength, tickLabelTruncate: truncate } = axisSpec; + + const maxWidth = maxLength ? getPercentageValue(maxLength, containerWidth, 0) : undefined; + if (maxWidth === undefined || maxWidth <= 0 || maxWidth > containerWidth) return (formatter) => formatter; + + const font: Font = { + fontStyle: fontStyle ?? 'normal', + fontFamily, + fontWeight: 'normal', + fontVariant: 'normal', + textColor: fill, + }; + + return (formatter) => (value) => fitText(measure, formatter(value), maxWidth, fontSize, font, truncate ?? 'end').text; +} + /** @internal */ export const getAxisTickLabelFormatter = createCustomCachedSelector( [getSeriesSpecsSelector, getAxisSpecsSelector, getSettingsSpecSelector, getScaleConfigsFromSpecsSelector], diff --git a/packages/charts/src/chart_types/xy_chart/state/selectors/compute_axis_ticks_dimensions.ts b/packages/charts/src/chart_types/xy_chart/state/selectors/compute_axis_ticks_dimensions.ts index e5f06953778..c492ed6321b 100644 --- a/packages/charts/src/chart_types/xy_chart/state/selectors/compute_axis_ticks_dimensions.ts +++ b/packages/charts/src/chart_types/xy_chart/state/selectors/compute_axis_ticks_dimensions.ts @@ -7,7 +7,7 @@ */ import type { AxisLabelFormatter } from './axis_tick_formatter'; -import { getAxisTickLabelFormatter } from './axis_tick_formatter'; +import { getAxisTickLabelFormatter, withTickLabelTruncation } from './axis_tick_formatter'; import { computeSeriesDomainsSelector } from './compute_series_domains'; import { countBarsInClusterSelector } from './count_bars_in_cluster'; import { getAxesStylesSelector } from './get_axis_styles'; @@ -16,6 +16,7 @@ import { getAxisSpecsSelector, getSeriesSpecsSelector } from './get_specs'; import { isHistogramModeEnabledSelector } from './is_histogram_mode_enabled'; import type { ScaleBand, ScaleContinuous } from '../../../../scales'; import { createCustomCachedSelector } from '../../../../state/create_selector'; +import { getChartContainerDimensionsSelector } from '../../../../state/selectors/get_chart_container_dimensions'; import { getChartThemeSelector } from '../../../../state/selectors/get_chart_theme'; import { getSettingsSpecSelector } from '../../../../state/selectors/get_settings_spec'; import type { TextMeasure } from '../../../../utils/bbox/canvas_text_bbox_calculator'; @@ -142,16 +143,23 @@ export const getLabelBox = ( /** @internal */ export const computeAxisTicksDimensionsSelector = createCustomCachedSelector( - [getJoinedVisibleAxesData], - (joinedAxesData): AxesTicksDimensions => + [getJoinedVisibleAxesData, getChartContainerDimensionsSelector], + (joinedAxesData, chartContainerDimensions): AxesTicksDimensions => withTextMeasure( (textMeasure): AxesTicksDimensions => [...joinedAxesData].reduce( - (axesTicksDimensions, [id, { axisSpec, scale, axesStyle, gridLine, labelFormatter }]) => - axesTicksDimensions.set( + (axesTicksDimensions, [id, { axisSpec, scale, axesStyle, gridLine, labelFormatter }]) => { + const truncatedLabelFormatter = withTickLabelTruncation( + textMeasure, + axesStyle.tickLabel, + axisSpec, + chartContainerDimensions.width, + )(labelFormatter); + return axesTicksDimensions.set( id, - getLabelBox(axesStyle, scale.ticks(), labelFormatter, textMeasure, axisSpec, gridLine), - ), + getLabelBox(axesStyle, scale.ticks(), truncatedLabelFormatter, textMeasure, axisSpec, gridLine), + ); + }, new Map(), ), ), diff --git a/packages/charts/src/chart_types/xy_chart/state/selectors/visible_ticks.ts b/packages/charts/src/chart_types/xy_chart/state/selectors/visible_ticks.ts index d82710fc723..31e8fa97156 100644 --- a/packages/charts/src/chart_types/xy_chart/state/selectors/visible_ticks.ts +++ b/packages/charts/src/chart_types/xy_chart/state/selectors/visible_ticks.ts @@ -7,6 +7,7 @@ */ import type { AxisLabelFormatter } from './axis_tick_formatter'; +import { withTickLabelTruncation } from './axis_tick_formatter'; import type { JoinedAxisData } from './compute_axis_ticks_dimensions'; import { getJoinedVisibleAxesData, getLabelBox } from './compute_axis_ticks_dimensions'; import { computeSeriesDomainsSelector } from './compute_series_domains'; @@ -24,11 +25,12 @@ import { isContinuousScale } from '../../../../scales/types'; import type { AxisSpec, SettingsSpec } from '../../../../specs'; import { createCustomCachedSelector } from '../../../../state/create_selector'; import { computeSmallMultipleScalesSelector } from '../../../../state/selectors/compute_small_multiple_scales'; +import { getChartContainerDimensionsSelector } from '../../../../state/selectors/get_chart_container_dimensions'; import { getSettingsSpecSelector } from '../../../../state/selectors/get_settings_spec'; import { withTextMeasure } from '../../../../utils/bbox/canvas_text_bbox_calculator'; import type { Position, Rotation } from '../../../../utils/common'; import { isFiniteNumber, isRTLString } from '../../../../utils/common'; -import type { Size } from '../../../../utils/dimensions'; +import type { Dimensions, Size } from '../../../../utils/dimensions'; import type { AxisId } from '../../../../utils/ids'; import { multilayerAxisEntry } from '../../axes/timeslip/multilayer_ticks'; import { isHorizontalAxis, isVerticalAxis } from '../../utils/axis_type_utils'; @@ -232,6 +234,7 @@ export const getVisibleTickSetsSelector = createCustomCachedSelector( getSettingsSpecSelector, getScaleConfigsFromSpecsSelector, getJoinedVisibleAxesData, + getChartContainerDimensionsSelector, computeSeriesDomainsSelector, computeSmallMultipleScalesSelector, countBarsInClusterSelector, @@ -245,6 +248,7 @@ function getVisibleTickSets( { rotation: chartRotation, locale, dow }: Pick, scaleConfigs: ScaleConfigs, joinedAxesData: Map, + chartContainerDimensions: Dimensions, { xDomain, yDomains }: Pick, smScales: SmallMultipleScales, totalGroupsCount: number, @@ -255,6 +259,12 @@ function getVisibleTickSets( const panel = getPanelSize(smScales); return [...joinedAxesData].reduce( (acc, [axisId, { axisSpec, axesStyle, gridLine, isXAxis, labelFormatter: userProvidedLabelFormatter }]) => { + const tickLabelFormatter = withTickLabelTruncation( + textMeasure, + axesStyle.tickLabel, + axisSpec, + chartContainerDimensions.width, + )(userProvidedLabelFormatter); const { groupId, integersOnly, maximumFractionDigits: mfd, timeAxisLayerCount } = axisSpec; const yDomain = yDomains.find((yd) => yd.groupId === groupId); const domain = isXAxis ? xDomain : yDomain; @@ -318,7 +328,7 @@ function getVisibleTickSets( const scale = getScale(triedTickCount); const actualTickCount = scale?.ticks().length ?? 0; if (!scale || actualTickCount === previousActualTickCount || actualTickCount < 2) continue; - const raster = getMeasuredTicks(scale, scale.ticks(), undefined, 0, userProvidedLabelFormatter); + const raster = getMeasuredTicks(scale, scale.ticks(), undefined, 0, tickLabelFormatter); const nonZeroLengthTicks = raster.ticks.filter((tick) => tick.label.length > 0); const uniqueLabels = new Set(raster.ticks.map((tick) => tick.label)); const areLabelsUnique = raster.ticks.length === uniqueLabels.size; @@ -378,8 +388,7 @@ function getVisibleTickSets( // todo dry it up const scale = getScale(adaptiveTickCount ? fallbackAskedTickCount : maxTickCount); - const lastResortCandidate = - scale && getMeasuredTicks(scale, scale.ticks(), undefined, 0, userProvidedLabelFormatter); + const lastResortCandidate = scale && getMeasuredTicks(scale, scale.ticks(), undefined, 0, tickLabelFormatter); return lastResortCandidate ? acc.set(axisId, lastResortCandidate) : acc; }, new Map(), diff --git a/packages/charts/src/chart_types/xy_chart/utils/specs.ts b/packages/charts/src/chart_types/xy_chart/utils/specs.ts index 9c4fbfbe386..d5367d0f9ca 100644 --- a/packages/charts/src/chart_types/xy_chart/utils/specs.ts +++ b/packages/charts/src/chart_types/xy_chart/utils/specs.ts @@ -12,6 +12,7 @@ import type { $Values } from 'utility-types'; import type { XYChartSeriesIdentifier, DataSeriesDatum } from './series'; import type { ChartType } from '../..'; import type { Color } from '../../../common/colors'; +import type { Pixels } from '../../../common/geometry'; import type { TooltipPortalSettings } from '../../../components/portal/types'; import type { LogScaleOptions, ScaleContinuousType } from '../../../scales'; import type { ScaleType } from '../../../scales/constants'; @@ -703,6 +704,9 @@ export const HistogramModeAlignments = Object.freeze({ /** @public */ export type HistogramModeAlignment = 'start' | 'center' | 'end'; +/** @public */ +export type Truncate = 'start' | 'middle' | 'end'; + /** * This spec describe the configuration for a chart axis. * @public @@ -740,6 +744,15 @@ export interface AxisSpec extends Spec { * overrides tickFormat for axis labels */ labelFormat?: TickFormatter; + /** + * The position of the ellipsis when the tick label overflows. Defaults to 'end'. + */ + tickLabelTruncate?: Truncate; + /** + * The maximum size of the tick label. + * If a number, it is in pixels. If a string, it is relative to the container width, e.g. '20%'. + */ + tickLabelMaxLength?: Pixels | string; /** An approximate count of how many ticks will be generated */ ticks?: number; /** The axis title */ diff --git a/packages/charts/src/common/text_utils.test.ts b/packages/charts/src/common/text_utils.test.ts new file mode 100644 index 00000000000..d736ba6798c --- /dev/null +++ b/packages/charts/src/common/text_utils.test.ts @@ -0,0 +1,56 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0 and the Server Side Public License, v 1; you may not use this file except + * in compliance with, at your election, the Elastic License 2.0 or the Server + * Side Public License, v 1. + */ + +import type { Font } from './text_utils'; +import { fitText } from './text_utils'; +import type { TextMeasure } from '../utils/bbox/canvas_text_bbox_calculator'; + +const monospaceMeasure: TextMeasure = (text) => ({ + width: text.length, + height: 12, +}); + +const font: Font = { + fontStyle: 'normal', + fontVariant: 'normal', + fontWeight: 400, + fontFamily: 'sans-serif', + textColor: '#000', +}; + +const fontSize = 12; + +describe('fitText', () => { + it('returns the full string when it already fits (end)', () => { + expect(fitText(monospaceMeasure, 'abc', 10, fontSize, font, 'end')).toEqual({ + width: 3, + text: 'abc', + }); + }); + + it('truncates at the end with an ellipsis when width is constrained', () => { + expect(fitText(monospaceMeasure, 'abcdef', 4, fontSize, font, 'end')).toEqual({ + width: 4, + text: 'abc…', + }); + }); + + it('truncates at the start when position is start', () => { + expect(fitText(monospaceMeasure, 'abcdef', 4, fontSize, font, 'start')).toEqual({ + width: 4, + text: '…def', + }); + }); + + it('truncates in the middle when position is middle', () => { + expect(fitText(monospaceMeasure, 'abcdef', 4, fontSize, font, 'middle')).toEqual({ + width: 4, + text: 'ab…f', + }); + }); +}); diff --git a/packages/charts/src/common/text_utils.ts b/packages/charts/src/common/text_utils.ts index 69c7cc70910..f932ff0a01b 100644 --- a/packages/charts/src/common/text_utils.ts +++ b/packages/charts/src/common/text_utils.ts @@ -15,6 +15,9 @@ import { integerSnap, monotonicHillClimb } from '../solvers/monotonic_hill_climb import type { TextMeasure } from '../utils/bbox/canvas_text_bbox_calculator'; import type { Datum } from '../utils/common'; +/** @internal */ +export type Truncate = 'start' | 'middle' | 'end'; + const FONT_WEIGHTS_NUMERIC = [100, 200, 300, 400, 450, 500, 600, 700, 800, 900] as const; const FONT_WEIGHTS_ALPHA = ['normal', 'bold', 'lighter', 'bolder', 'inherit', 'initial', 'unset'] as const; @@ -72,6 +75,13 @@ export const TEXT_BASELINE = Object.freeze([ 'bottom', ] as const); +/** @internal */ +export const ELLIPSIS = '…'; +/** @internal */ +export const SPACE = ' '; +/** @internal */ +export const DASH = '-'; + /** @internal */ export interface Box extends Font { text: string; @@ -120,22 +130,57 @@ export function cutToLength(s: string, maxLength: number) { return s.length <= maxLength ? s : `${s.slice(0, Math.max(0, maxLength - 1))}…`; // ellipsis is one char } -/** @internal */ -export function fitText( +function truncate( measure: TextMeasure, desiredText: string, allottedWidth: number, fontSize: number, font: Font, + build: (k: number) => string, + min: number, ) { - const desiredLength = desiredText.length; - const response = (v: number) => measure(desiredText.slice(0, Math.max(0, v)), font, fontSize).width; - const visibleLength = monotonicHillClimb(response, desiredLength, allottedWidth, integerSnap); - const text = visibleLength < 2 && desiredLength >= 2 ? '' : cutToLength(desiredText, visibleLength); + if (desiredText.length === 0) return { width: measure('', font, fontSize).width, text: '' }; + + const fullWidth = measure(desiredText, font, fontSize).width; + if (fullWidth <= allottedWidth) return { width: fullWidth, text: desiredText }; + + const response = (k: number) => measure(build(k), font, fontSize).width; + const visible = monotonicHillClimb(response, desiredText.length, allottedWidth, integerSnap, min); + + if (!Number.isFinite(visible) || visible < min) return { width: measure('', font, fontSize).width, text: '' }; + + const text = build(visible); const { width } = measure(text, font, fontSize); + return { width, text }; } +/** @internal */ +export function fitText( + measure: TextMeasure, + desiredText: string, + allottedWidth: number, + fontSize: number, + font: Font, + position: Truncate = 'end', +) { + const truncateText = (build: (k: number) => string, min: number) => { + return truncate(measure, desiredText, allottedWidth, fontSize, font, build, min); + }; + + if (position === 'start') { + return truncateText((k) => `${ELLIPSIS}${desiredText.slice(desiredText.length - k)}`, 1); + } + if (position === 'middle') { + return truncateText((k) => { + const left = desiredText.slice(0, Math.ceil(k / 2)); + const right = desiredText.slice(desiredText.length - Math.floor(k / 2)); + return `${left}${ELLIPSIS}${right}`; + }, 2); + } + return truncateText((v) => cutToLength(desiredText, v), desiredText.length < 2 ? 1 : 2); +} + /** @internal */ export function maximiseFontSize( measure: TextMeasure, diff --git a/packages/charts/src/renderers/canvas/primitives/text.ts b/packages/charts/src/renderers/canvas/primitives/text.ts index 3ca17f1176b..2c8350c99f9 100644 --- a/packages/charts/src/renderers/canvas/primitives/text.ts +++ b/packages/charts/src/renderers/canvas/primitives/text.ts @@ -9,7 +9,7 @@ import { withContext } from '..'; import type { Degrees } from '../../../common/geometry'; import type { Font, TextAlign, TextBaseline } from '../../../common/text_utils'; -import { cssFontShorthand } from '../../../common/text_utils'; +import { cssFontShorthand, DASH, ELLIPSIS, SPACE } from '../../../common/text_utils'; import { measureText } from '../../../utils/bbox/canvas_text_bbox_calculator'; import { degToRad } from '../../../utils/common'; import type { Point } from '../../../utils/point'; @@ -60,10 +60,6 @@ export function renderText( }); } -const SPACE = ' '; -const ELLIPSIS = '…'; -const DASH = '-'; - interface Options { wrapAtWord: boolean; shouldAddEllipsis: boolean; diff --git a/packages/charts/src/utils/text/wrap.ts b/packages/charts/src/utils/text/wrap.ts index 2a6d0a7d9c3..1ee04ce6a41 100644 --- a/packages/charts/src/utils/text/wrap.ts +++ b/packages/charts/src/utils/text/wrap.ts @@ -6,12 +6,10 @@ * Side Public License, v 1. */ -import type { Font } from '../../common/text_utils'; +import { ELLIPSIS, type Font } from '../../common/text_utils'; import { monotonicHillClimb } from '../../solvers/monotonic_hill_climb'; import type { TextMeasure } from '../bbox/canvas_text_bbox_calculator'; -const ELLIPSIS = '…'; - interface WrapTextLines extends Array { meta: { truncated: boolean; diff --git a/storybook/stories/axes/16_tick_label_truncation.story.tsx b/storybook/stories/axes/16_tick_label_truncation.story.tsx new file mode 100644 index 00000000000..b41a557c912 --- /dev/null +++ b/storybook/stories/axes/16_tick_label_truncation.story.tsx @@ -0,0 +1,87 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0 and the Server Side Public License, v 1; you may not use this file except + * in compliance with, at your election, the Elastic License 2.0 or the Server + * Side Public License, v 1. + */ + +import { select, text } from '@storybook/addon-knobs'; +import React from 'react'; + +import { Axis, BarSeries, Chart, Position, ScaleType, Settings } from '@elastic/charts'; + +import type { ChartsStory } from '../../types'; +import { useBaseTheme } from '../../use_base_theme'; +import { customKnobs } from '../utils/knobs'; + +const data = [ + { + x: 'com.example.something.host.23', + y: 12, + }, + { x: 'com.example.something.host.11', y: 8 }, + { x: 'com.example.something.host.07', y: 17 }, + { x: 'com.example.something.host.02', y: 5 }, + { x: 'com.example.something.worker.04', y: 9 }, + { x: 'com.example.something.worker.01', y: 4 }, +]; + +type EllipsisPosition = 'start' | 'middle' | 'end'; + +/** Knob helper: empty → unset; plain number → px; value like `25` or `25.5 %` → percentage string. */ +function parseThemeSize(raw: string): number | string | undefined { + const s = raw.trim(); + if (!s) return undefined; + const pct = s.match(/^([\d.]+)\s*%$/); + if (pct) return `${pct[1]}%`; + const n = Number(s); + if (Number.isFinite(n)) return n; + return s; +} + +export const Example: ChartsStory = (_, { title, description }) => { + const xMaxLength = parseThemeSize(text('Max length (X)', '')); + const xTruncate = select( + 'Truncate (X)', + { end: 'end', start: 'start', middle: 'middle' }, + 'middle', + ); + const yMaxLength = parseThemeSize(text('Max length (Y)', '120')); + const yTruncate = select( + 'Truncate (Y)', + { end: 'end', start: 'start', middle: 'middle' }, + 'middle', + ); + + const rotation = customKnobs.enum.rotation('Chart rotation', 90); + + return ( + + + + + + + + ); +}; diff --git a/storybook/stories/axes/axes.stories.tsx b/storybook/stories/axes/axes.stories.tsx index 80311ac4021..0ced3740058 100644 --- a/storybook/stories/axes/axes.stories.tsx +++ b/storybook/stories/axes/axes.stories.tsx @@ -26,3 +26,4 @@ export { Example as fitDomain } from './11_fit_domain_extent.story'; export { Example as duplicateTicks } from './12_duplicate_ticks.story'; export { Example as labelFormatting } from './13_label_formatting.story'; export { Example as duplicateTicks2 } from './14_duplicate_ticks_2.story'; +export { Example as tickLabelTruncation } from './16_tick_label_truncation.story'; diff --git a/storybook/stories/utils/knobs/special_enums.ts b/storybook/stories/utils/knobs/special_enums.ts index 94c9e55e0cd..bb8e6852c73 100644 --- a/storybook/stories/utils/knobs/special_enums.ts +++ b/storybook/stories/utils/knobs/special_enums.ts @@ -17,7 +17,7 @@ import { getMultiSelectKnob, getNumberSelectKnob } from './custom'; /** * Negative numbers do not behave well with vrt slugified naming */ -const getRotationKnob = (name = 'chartRotation') => +const getRotationKnob = (name = 'chartRotation', value: Rotation = 0) => getNumberSelectKnob( name, { @@ -26,7 +26,7 @@ const getRotationKnob = (name = 'chartRotation') => '-90 deg': -90, '180 deg': 180, }, - 0, + value, ); const boundaryMap: Record = {