@flux-ui/statistics 3.0.0-next.68 → 3.0.0-next.69

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 (119) hide show
  1. package/dist/component/FluxStatisticsLegendScope.vue.d.ts +13 -0
  2. package/dist/component/FluxStatisticsPercentageBar.vue.d.ts +8 -0
  3. package/dist/component/index.d.ts +2 -0
  4. package/dist/composable/index.d.ts +4 -2
  5. package/dist/composable/useChartBaseSetup.d.ts +8 -0
  6. package/dist/composable/{usePieSlicesSetup.d.ts → useChartSlicesSetup.d.ts} +2 -2
  7. package/dist/index.css +67 -32
  8. package/dist/index.js +913 -510
  9. package/dist/index.js.map +1 -1
  10. package/dist/util/index.d.ts +5 -6
  11. package/dist/util/options/buildBaseOptions.d.ts +2 -0
  12. package/dist/util/{baseOptions.d.ts → options/buildCartesianBaseOptions.d.ts} +4 -6
  13. package/dist/util/options/buildCircularBaseOptions.d.ts +2 -0
  14. package/dist/util/options/cartesian/buildAreaChartOptions.d.ts +17 -0
  15. package/dist/util/options/cartesian/buildBarChartOptions.d.ts +17 -0
  16. package/dist/util/options/cartesian/buildBoxPlotChartOptions.d.ts +16 -0
  17. package/dist/util/options/cartesian/buildBubbleChartOptions.d.ts +15 -0
  18. package/dist/util/options/cartesian/buildCandlestickChartOptions.d.ts +17 -0
  19. package/dist/util/options/cartesian/buildHeatmapChartOptions.d.ts +15 -0
  20. package/dist/util/options/cartesian/buildLineChartOptions.d.ts +17 -0
  21. package/dist/util/options/cartesian/buildMixedChartOptions.d.ts +17 -0
  22. package/dist/util/options/cartesian/buildScatterChartOptions.d.ts +15 -0
  23. package/dist/util/options/cartesian/index.d.ts +18 -0
  24. package/dist/util/options/circular/buildDonutChartOptions.d.ts +15 -0
  25. package/dist/util/options/circular/buildGaugeChartOptions.d.ts +14 -0
  26. package/dist/util/options/circular/buildPieChartOptions.d.ts +15 -0
  27. package/dist/util/options/circular/buildPolarAreaChartOptions.d.ts +15 -0
  28. package/dist/util/options/circular/buildRadarChartOptions.d.ts +13 -0
  29. package/dist/util/options/circular/buildTreemapChartOptions.d.ts +12 -0
  30. package/dist/util/options/circular/index.d.ts +12 -0
  31. package/dist/util/options/index.d.ts +6 -0
  32. package/dist/util/series/chartColors.d.ts +3 -0
  33. package/dist/util/{convert.d.ts → series/converters.d.ts} +1 -6
  34. package/dist/util/series/index.d.ts +4 -0
  35. package/dist/util/series/labels.d.ts +5 -0
  36. package/dist/util/tooltips/buildBoxPlotTooltip.d.ts +22 -0
  37. package/dist/util/tooltips/buildCartesianTooltip.d.ts +10 -0
  38. package/dist/util/tooltips/buildGaugeTooltip.d.ts +14 -0
  39. package/dist/util/tooltips/buildHeatmapTooltip.d.ts +17 -0
  40. package/dist/util/tooltips/buildRadarTooltip.d.ts +11 -0
  41. package/dist/util/tooltips/buildSharedItemTooltip.d.ts +10 -0
  42. package/dist/util/tooltips/buildTreemapTooltip.d.ts +12 -0
  43. package/dist/util/tooltips/index.d.ts +15 -0
  44. package/dist/util/tooltips/render.d.ts +4 -0
  45. package/dist/util/tooltips/types.d.ts +24 -0
  46. package/package.json +4 -4
  47. package/src/component/FluxStatisticsAreaChart.vue +15 -19
  48. package/src/component/FluxStatisticsBarChart.vue +15 -19
  49. package/src/component/FluxStatisticsBoxPlotChart.vue +14 -34
  50. package/src/component/FluxStatisticsBubbleChart.vue +13 -23
  51. package/src/component/FluxStatisticsCandlestickChart.vue +14 -45
  52. package/src/component/FluxStatisticsChart.vue +2 -2
  53. package/src/component/FluxStatisticsChartPane.vue +12 -13
  54. package/src/component/FluxStatisticsDonutChart.vue +15 -24
  55. package/src/component/FluxStatisticsHeatmapChart.vue +15 -48
  56. package/src/component/FluxStatisticsLegendScope.vue +16 -0
  57. package/src/component/FluxStatisticsLineChart.vue +15 -19
  58. package/src/component/FluxStatisticsMixedChart.vue +15 -18
  59. package/src/component/FluxStatisticsPercentageBar.vue +90 -0
  60. package/src/component/FluxStatisticsPieChart.vue +15 -24
  61. package/src/component/FluxStatisticsPolarAreaChart.vue +15 -24
  62. package/src/component/FluxStatisticsRadarChart.vue +11 -79
  63. package/src/component/FluxStatisticsRadialBar.vue +11 -20
  64. package/src/component/FluxStatisticsScatterChart.vue +13 -23
  65. package/src/component/FluxStatisticsTreemapChart.vue +11 -15
  66. package/src/component/index.ts +2 -0
  67. package/src/composable/index.ts +4 -2
  68. package/src/composable/useChartBaseSetup.ts +16 -0
  69. package/src/composable/{usePieSlicesSetup.ts → useChartSlicesSetup.ts} +3 -3
  70. package/src/css/Chart.module.scss +10 -15
  71. package/src/css/ChartPane.module.scss +3 -10
  72. package/src/css/Empty.module.scss +2 -2
  73. package/src/css/Legend.module.scss +16 -8
  74. package/src/css/Meter.module.scss +1 -0
  75. package/src/css/PercentageBar.module.scss +36 -0
  76. package/src/util/index.ts +5 -6
  77. package/src/util/options/buildBaseOptions.ts +31 -0
  78. package/src/util/{baseOptions.ts → options/buildCartesianBaseOptions.ts} +15 -22
  79. package/src/util/options/buildCircularBaseOptions.ts +10 -0
  80. package/src/util/options/cartesian/buildAreaChartOptions.ts +44 -0
  81. package/src/util/options/cartesian/buildBarChartOptions.ts +44 -0
  82. package/src/util/options/cartesian/buildBoxPlotChartOptions.ts +63 -0
  83. package/src/util/options/cartesian/buildBubbleChartOptions.ts +48 -0
  84. package/src/util/options/cartesian/buildCandlestickChartOptions.ts +77 -0
  85. package/src/util/options/cartesian/buildHeatmapChartOptions.ts +72 -0
  86. package/src/util/options/cartesian/buildLineChartOptions.ts +44 -0
  87. package/src/util/options/cartesian/buildMixedChartOptions.ts +44 -0
  88. package/src/util/options/cartesian/buildScatterChartOptions.ts +48 -0
  89. package/src/util/options/cartesian/index.ts +18 -0
  90. package/src/util/options/circular/buildDonutChartOptions.ts +31 -0
  91. package/src/util/options/circular/buildGaugeChartOptions.ts +45 -0
  92. package/src/util/options/circular/buildPieChartOptions.ts +31 -0
  93. package/src/util/options/circular/buildPolarAreaChartOptions.ts +31 -0
  94. package/src/util/options/circular/buildRadarChartOptions.ts +52 -0
  95. package/src/util/options/circular/buildTreemapChartOptions.ts +28 -0
  96. package/src/util/options/circular/index.ts +12 -0
  97. package/src/util/options/index.ts +6 -0
  98. package/src/util/series/chartColors.ts +20 -0
  99. package/src/util/{convert.ts → series/converters.ts} +2 -44
  100. package/src/util/series/index.ts +4 -0
  101. package/src/util/series/labels.ts +30 -0
  102. package/src/util/tooltips/buildBoxPlotTooltip.ts +66 -0
  103. package/src/util/tooltips/buildCartesianTooltip.ts +44 -0
  104. package/src/util/tooltips/buildGaugeTooltip.ts +49 -0
  105. package/src/util/tooltips/buildHeatmapTooltip.ts +57 -0
  106. package/src/util/tooltips/buildRadarTooltip.ts +53 -0
  107. package/src/util/tooltips/buildSharedItemTooltip.ts +38 -0
  108. package/src/util/tooltips/buildTreemapTooltip.ts +49 -0
  109. package/src/util/tooltips/index.ts +15 -0
  110. package/src/util/tooltips/render.ts +66 -0
  111. package/src/util/tooltips/types.ts +29 -0
  112. package/dist/util/defaultOptions.d.ts +0 -76
  113. package/src/util/defaultOptions.ts +0 -398
  114. /package/dist/util/{iconSvg.d.ts → icons.d.ts} +0 -0
  115. /package/dist/util/{seriesDefaults.d.ts → series/defaults.d.ts} +0 -0
  116. /package/dist/util/{sparklineOptions.d.ts → sparkline.d.ts} +0 -0
  117. /package/src/util/{iconSvg.ts → icons.ts} +0 -0
  118. /package/src/util/{seriesDefaults.ts → series/defaults.ts} +0 -0
  119. /package/src/util/{sparklineOptions.ts → sparkline.ts} +0 -0
@@ -0,0 +1,90 @@
1
+ <template>
2
+ <div :class="$style.statisticsPercentageBar">
3
+ <div :class="clsx($style.statisticsPercentageBarTrack, hoveredIndex !== null && $style.isHoverActive)">
4
+ <FluxTooltip
5
+ v-for="(item, index) of items"
6
+ :key="index">
7
+ <template #content>
8
+ <div :class="$style.statisticsPercentageBarTooltip">
9
+ <FluxIcon
10
+ v-if="item.icon"
11
+ :name="item.icon"
12
+ :size="16"/>
13
+
14
+ <span>{{ formatPercentage(item.value) }} {{ item.label }}</span>
15
+ </div>
16
+ </template>
17
+
18
+ <div
19
+ :class="clsx($style.statisticsPercentageBarSegment, hoveredIndex === index && $style.isHovered)"
20
+ :style="{
21
+ backgroundColor: resolveColor(item.color),
22
+ flexGrow: item.value
23
+ }"
24
+ @mouseenter="onSegmentEnter(index)"
25
+ @mouseleave="onSegmentLeave"/>
26
+ </FluxTooltip>
27
+ </div>
28
+ </div>
29
+ </template>
30
+
31
+ <script
32
+ lang="ts"
33
+ setup>
34
+ import { formatPercentage } from '@basmilius/utils';
35
+ import { FluxIcon, FluxTooltip } from '@flux-ui/components';
36
+ import type { FluxStatisticsChartColor, FluxStatisticsPercentageBarItemObject } from '@flux-ui/types';
37
+ import { clsx } from 'clsx';
38
+ import { computed, inject, watchEffect } from 'vue';
39
+ import { FluxStatisticsChartLegendInjectionKey, type ChartLegendItem } from '~flux/statistics/composable';
40
+ import $style from '~flux/statistics/css/PercentageBar.module.scss';
41
+
42
+ const SEMANTIC_COLORS = ['gray', 'primary', 'danger', 'info', 'success', 'warning'] as const;
43
+
44
+ const props = defineProps<{
45
+ readonly items: FluxStatisticsPercentageBarItemObject[];
46
+ }>();
47
+
48
+ const legendContext = inject(FluxStatisticsChartLegendInjectionKey, null);
49
+
50
+ const legendItems = computed<ChartLegendItem[]>(() =>
51
+ props.items.map(item => ({
52
+ color: resolveColor(item.color),
53
+ icon: item.icon,
54
+ label: item.label,
55
+ value: item.displayValue
56
+ }))
57
+ );
58
+
59
+ const hoveredIndex = computed<number | null>(() => legendContext?.hoveredIndex.value ?? null);
60
+
61
+ watchEffect(() => {
62
+ if (legendContext) {
63
+ legendContext.items.value = legendItems.value;
64
+ }
65
+ });
66
+
67
+ function resolveColor(color?: FluxStatisticsChartColor): string | undefined {
68
+ if (!color) {
69
+ return;
70
+ }
71
+
72
+ if (SEMANTIC_COLORS.includes(color as typeof SEMANTIC_COLORS[number])) {
73
+ return `var(--${color}-600)`;
74
+ }
75
+
76
+ return color;
77
+ }
78
+
79
+ function onSegmentEnter(index: number): void {
80
+ if (legendContext) {
81
+ legendContext.hoveredIndex.value = index;
82
+ }
83
+ }
84
+
85
+ function onSegmentLeave(): void {
86
+ if (legendContext) {
87
+ legendContext.hoveredIndex.value = null;
88
+ }
89
+ }
90
+ </script>
@@ -8,15 +8,14 @@
8
8
  lang="ts"
9
9
  setup>
10
10
  import type { FluxStatisticsChartPieSlice } from '@flux-ui/types';
11
- import { merge } from 'lodash-es';
12
11
  import { computed } from 'vue';
13
- import { usePieSlicesSetup, type EChartsOption } from '~flux/statistics/composable';
14
- import { buildSharedItemTooltipFormatter, type ChartTooltipValueFormatter, POLAR_BASE_OPTIONS, toPieSeries } from '~flux/statistics/util';
12
+ import { useChartSlicesSetup, type EChartsOption } from '~flux/statistics/composable';
13
+ import { buildPieChartOptions, type ChartTooltipValueFormatter } from '~flux/statistics/util';
15
14
  import Chart from './FluxStatisticsChart.vue';
16
15
  import $style from '~flux/statistics/css/Chart.module.scss';
17
16
 
18
17
  const {
19
- advancedOptions = {},
18
+ advancedOptions,
20
19
  slices,
21
20
  title,
22
21
  tooltip = false,
@@ -29,25 +28,17 @@
29
28
  readonly tooltipValueFormatter?: ChartTooltipValueFormatter;
30
29
  }>();
31
30
 
32
- const { t, palette, tooltipItems } = usePieSlicesSetup(() => slices);
31
+ const { t, palette, tooltipItems } = useChartSlicesSetup(() => slices);
33
32
 
34
- const echartsSeries = computed(() => [toPieSeries(slices, palette.value)]);
35
-
36
- const tooltipOptions = computed<EChartsOption>(() => {
37
- if (!tooltip) {
38
- return { tooltip: { show: false } };
39
- }
40
-
41
- return {
42
- tooltip: {
43
- show: true,
44
- trigger: 'item',
45
- formatter: buildSharedItemTooltipFormatter(t, $style as never, () => tooltipItems.value, () => title, tooltipValueFormatter) as never
46
- }
47
- };
48
- });
49
-
50
- const mergedOptions = computed<EChartsOption>(() =>
51
- merge({}, POLAR_BASE_OPTIONS, tooltipOptions.value, advancedOptions, { series: echartsSeries.value, color: palette.value })
52
- );
33
+ const mergedOptions = computed(() => buildPieChartOptions({
34
+ slices,
35
+ palette: palette.value,
36
+ tooltipItems: tooltipItems.value,
37
+ title,
38
+ t,
39
+ styles: $style,
40
+ tooltip,
41
+ tooltipValueFormatter,
42
+ advancedOptions
43
+ }));
53
44
  </script>
@@ -8,15 +8,14 @@
8
8
  lang="ts"
9
9
  setup>
10
10
  import type { FluxStatisticsChartPieSlice } from '@flux-ui/types';
11
- import { merge } from 'lodash-es';
12
11
  import { computed } from 'vue';
13
- import { usePieSlicesSetup, type EChartsOption } from '~flux/statistics/composable';
14
- import { buildSharedItemTooltipFormatter, type ChartTooltipValueFormatter, POLAR_BASE_OPTIONS, toPolarAreaSeries } from '~flux/statistics/util';
12
+ import { useChartSlicesSetup, type EChartsOption } from '~flux/statistics/composable';
13
+ import { buildPolarAreaChartOptions, type ChartTooltipValueFormatter } from '~flux/statistics/util';
15
14
  import Chart from './FluxStatisticsChart.vue';
16
15
  import $style from '~flux/statistics/css/Chart.module.scss';
17
16
 
18
17
  const {
19
- advancedOptions = {},
18
+ advancedOptions,
20
19
  slices,
21
20
  title,
22
21
  tooltip = false,
@@ -29,25 +28,17 @@
29
28
  readonly tooltipValueFormatter?: ChartTooltipValueFormatter;
30
29
  }>();
31
30
 
32
- const { t, palette, tooltipItems } = usePieSlicesSetup(() => slices);
31
+ const { t, palette, tooltipItems } = useChartSlicesSetup(() => slices);
33
32
 
34
- const echartsSeries = computed(() => [toPolarAreaSeries(slices, palette.value)]);
35
-
36
- const tooltipOptions = computed<EChartsOption>(() => {
37
- if (!tooltip) {
38
- return { tooltip: { show: false } };
39
- }
40
-
41
- return {
42
- tooltip: {
43
- show: true,
44
- trigger: 'item',
45
- formatter: buildSharedItemTooltipFormatter(t, $style as never, () => tooltipItems.value, () => title, tooltipValueFormatter) as never
46
- }
47
- };
48
- });
49
-
50
- const mergedOptions = computed<EChartsOption>(() =>
51
- merge({}, POLAR_BASE_OPTIONS, tooltipOptions.value, advancedOptions, { series: echartsSeries.value, color: palette.value })
52
- );
33
+ const mergedOptions = computed(() => buildPolarAreaChartOptions({
34
+ slices,
35
+ palette: palette.value,
36
+ tooltipItems: tooltipItems.value,
37
+ title,
38
+ t,
39
+ styles: $style,
40
+ tooltip,
41
+ tooltipValueFormatter,
42
+ advancedOptions
43
+ }));
53
44
  </script>
@@ -8,15 +8,14 @@
8
8
  lang="ts"
9
9
  setup>
10
10
  import type { FluxStatisticsChartRadarIndicator, FluxStatisticsChartRadarSeries } from '@flux-ui/types';
11
- import { merge } from 'lodash-es';
12
11
  import { computed } from 'vue';
13
12
  import { useChartSeriesSetup, type EChartsOption } from '~flux/statistics/composable';
14
- import { POLAR_BASE_OPTIONS, type SharedTooltipItem, toRadarSeries, type TooltipParam, type TooltipStyleClasses } from '~flux/statistics/util';
13
+ import { buildRadarChartOptions } from '~flux/statistics/util';
15
14
  import Chart from './FluxStatisticsChart.vue';
16
15
  import $style from '~flux/statistics/css/Chart.module.scss';
17
16
 
18
17
  const {
19
- advancedOptions = {},
18
+ advancedOptions,
20
19
  indicators,
21
20
  series,
22
21
  tooltip = false
@@ -29,80 +28,13 @@
29
28
 
30
29
  const { t, palette } = useChartSeriesSetup(() => series, { mode: 'data' });
31
30
 
32
- const echartsSeries = computed(() => [toRadarSeries(
33
- series.map(s => ({ ...s, name: s.name ? t(String(s.name)) : undefined })),
34
- palette.value
35
- )]);
36
-
37
- const radarConfig = computed(() => ({
38
- radar: {
39
- indicator: indicators.map(i => ({ name: t(String(i.name)), max: i.max })),
40
- splitLine: { lineStyle: { color: 'var(--gray-200)' } },
41
- splitArea: { show: false },
42
- axisLine: { lineStyle: { color: 'var(--gray-200)' } },
43
- axisName: {
44
- color: 'var(--foreground-secondary)',
45
- fontSize: 12,
46
- fontWeight: 500
47
- }
48
- }
49
- } as EChartsOption));
50
-
51
- const tooltipFormatter = (params: TooltipParam | TooltipParam[]): string => {
52
- const param = Array.isArray(params) ? params[0] : params;
53
-
54
- if (!param) {
55
- return '';
56
- }
57
-
58
- const ringIndex = param.dataIndex ?? 0;
59
- const ring = series[ringIndex];
60
-
61
- if (!ring) {
62
- return '';
63
- }
64
-
65
- const styles = $style as unknown as TooltipStyleClasses;
66
- const color = palette.value[ringIndex % palette.value.length];
67
- const title = ring.name ? t(String(ring.name)) : '';
68
-
69
- const tooltipItems: SharedTooltipItem[] = indicators.map((indicator, idx) => ({
70
- name: indicator.name,
71
- value: ring.values[idx] ?? '',
72
- color
73
- }));
74
-
75
- const titleHtml = title
76
- ? `<div class="${styles.statisticsChartTooltipTitle}">${title}</div>`
77
- : '';
78
-
79
- const body = tooltipItems.map(item => {
80
- const translatedName = item.name ? t(String(item.name)) : '';
81
- return `
82
- <div class="${styles.statisticsChartTooltipSeriesColor} ${styles.isActive}" style="background: ${item.color}"></div>
83
- <div class="${styles.statisticsChartTooltipSeriesName} ${styles.isActive}">${translatedName}</div>
84
- <div class="${styles.statisticsChartTooltipSeriesValue} ${styles.isActive}">${item.value}</div>
85
- `;
86
- }).join('');
87
-
88
- return `${titleHtml}<div class="${styles.statisticsChartTooltipBody}">${body}</div>`;
89
- };
90
-
91
- const tooltipOptions = computed<EChartsOption>(() => {
92
- if (!tooltip) {
93
- return { tooltip: { show: false } };
94
- }
95
-
96
- return {
97
- tooltip: {
98
- show: true,
99
- trigger: 'item',
100
- formatter: tooltipFormatter as never
101
- }
102
- };
103
- });
104
-
105
- const mergedOptions = computed<EChartsOption>(() =>
106
- merge({}, POLAR_BASE_OPTIONS, radarConfig.value, tooltipOptions.value, advancedOptions, { series: echartsSeries.value, color: palette.value })
107
- );
31
+ const mergedOptions = computed(() => buildRadarChartOptions({
32
+ series,
33
+ indicators,
34
+ palette: palette.value,
35
+ t,
36
+ styles: $style,
37
+ tooltip,
38
+ advancedOptions
39
+ }));
108
40
  </script>
@@ -8,15 +8,14 @@
8
8
  lang="ts"
9
9
  setup>
10
10
  import type { FluxStatisticsChartGaugeSeries } from '@flux-ui/types';
11
- import { merge } from 'lodash-es';
12
11
  import { computed } from 'vue';
13
12
  import { useChartSeriesSetup, type EChartsOption } from '~flux/statistics/composable';
14
- import { buildGaugeTooltipOptions, POLAR_BASE_OPTIONS, toGaugeSeries } from '~flux/statistics/util';
13
+ import { buildGaugeChartOptions, gaugeLegendItemBuilder } from '~flux/statistics/util';
15
14
  import Chart from './FluxStatisticsChart.vue';
16
15
  import $style from '~flux/statistics/css/Chart.module.scss';
17
16
 
18
17
  const {
19
- advancedOptions = {},
18
+ advancedOptions,
20
19
  series,
21
20
  tooltip = false
22
21
  } = defineProps<{
@@ -26,23 +25,15 @@
26
25
  }>();
27
26
 
28
27
  const { t, palette } = useChartSeriesSetup(() => series, {
29
- getLegendItem: (s, color, _, translate) => ({
30
- color,
31
- icon: s.icon,
32
- label: s.name ? translate(String(s.name)) : '',
33
- value: s.value
34
- })
28
+ getLegendItem: gaugeLegendItemBuilder
35
29
  });
36
30
 
37
- const echartsSeries = computed(() => series.map((s, i) =>
38
- toGaugeSeries({ ...s, name: s.name ? t(String(s.name)) : s.name }, palette.value[i], i, series.length)
39
- ));
40
-
41
- const mergedOptions = computed<EChartsOption>(() => {
42
- const tooltipOptions: EChartsOption = tooltip
43
- ? buildGaugeTooltipOptions(t, $style as never, () => series, () => palette.value)
44
- : { tooltip: { show: false } };
45
-
46
- return merge({}, POLAR_BASE_OPTIONS, tooltipOptions, advancedOptions, { series: echartsSeries.value, color: palette.value });
47
- });
31
+ const mergedOptions = computed(() => buildGaugeChartOptions({
32
+ series,
33
+ palette: palette.value,
34
+ t,
35
+ styles: $style,
36
+ tooltip,
37
+ advancedOptions
38
+ }));
48
39
  </script>
@@ -8,15 +8,14 @@
8
8
  lang="ts"
9
9
  setup>
10
10
  import type { FluxStatisticsChartScatterSeries } from '@flux-ui/types';
11
- import { merge } from 'lodash-es';
12
11
  import { computed } from 'vue';
13
12
  import { useChartSeriesSetup, type EChartsOption } from '~flux/statistics/composable';
14
- import { buildCartesianBaseOptions, buildCartesianTooltipOptions, toScatterSeries } from '~flux/statistics/util';
13
+ import { buildScatterChartOptions } from '~flux/statistics/util';
15
14
  import Chart from './FluxStatisticsChart.vue';
16
15
  import $style from '~flux/statistics/css/Chart.module.scss';
17
16
 
18
17
  const {
19
- advancedOptions = {},
18
+ advancedOptions,
20
19
  series,
21
20
  splitLines = false,
22
21
  tooltip = false,
@@ -33,24 +32,15 @@
33
32
 
34
33
  const { t, palette } = useChartSeriesSetup(() => series);
35
34
 
36
- const echartsSeries = computed(() => series.map((s, i) =>
37
- toScatterSeries({ ...s, name: s.name ? t(String(s.name)) : undefined }, palette.value[i])
38
- ));
39
-
40
- const mergedOptions = computed<EChartsOption>(() => {
41
- const base = buildCartesianBaseOptions({
42
- xAxisType: 'value',
43
- yAxisType: 'value',
44
- scale: true,
45
- xAxisLabels,
46
- yAxisLabels,
47
- splitLines
48
- });
49
-
50
- const tooltipOptions: EChartsOption = tooltip
51
- ? buildCartesianTooltipOptions(t, $style as never, () => series.map(s => s.icon))
52
- : { tooltip: { show: false } };
53
-
54
- return merge({}, base, tooltipOptions, advancedOptions, { series: echartsSeries.value, color: palette.value });
55
- });
35
+ const mergedOptions = computed(() => buildScatterChartOptions({
36
+ series,
37
+ palette: palette.value,
38
+ t,
39
+ styles: $style,
40
+ tooltip,
41
+ xAxisLabels,
42
+ yAxisLabels,
43
+ splitLines,
44
+ advancedOptions
45
+ }));
56
46
  </script>
@@ -7,16 +7,14 @@
7
7
  lang="ts"
8
8
  setup>
9
9
  import type { FluxStatisticsChartTreemapNode } from '@flux-ui/types';
10
- import { merge } from 'lodash-es';
11
10
  import { computed } from 'vue';
12
- import { useI18n } from 'vue-i18n';
13
- import type { EChartsOption } from '~flux/statistics/composable';
14
- import { buildTreemapTooltipOptions, CHART_DEFAULT_COLORS, POLAR_BASE_OPTIONS, toTreemapSeries } from '~flux/statistics/util';
11
+ import { useChartBaseSetup, type EChartsOption } from '~flux/statistics/composable';
12
+ import { buildTreemapChartOptions } from '~flux/statistics/util';
15
13
  import Chart from './FluxStatisticsChart.vue';
16
14
  import $style from '~flux/statistics/css/Chart.module.scss';
17
15
 
18
16
  const {
19
- advancedOptions = {},
17
+ advancedOptions,
20
18
  nodes,
21
19
  tooltip = false
22
20
  } = defineProps<{
@@ -25,15 +23,13 @@
25
23
  readonly tooltip?: boolean;
26
24
  }>();
27
25
 
28
- const {t} = useI18n({useScope: 'parent'});
26
+ const { t } = useChartBaseSetup();
29
27
 
30
- const echartsSeries = computed(() => [toTreemapSeries(nodes, CHART_DEFAULT_COLORS)]);
31
-
32
- const mergedOptions = computed<EChartsOption>(() => {
33
- const tooltipOptions: EChartsOption = tooltip
34
- ? buildTreemapTooltipOptions(t, $style as never)
35
- : { tooltip: { show: false } };
36
-
37
- return merge({}, POLAR_BASE_OPTIONS, tooltipOptions, advancedOptions, { series: echartsSeries.value });
38
- });
28
+ const mergedOptions = computed(() => buildTreemapChartOptions({
29
+ nodes,
30
+ t,
31
+ styles: $style,
32
+ tooltip,
33
+ advancedOptions
34
+ }));
39
35
  </script>
@@ -18,9 +18,11 @@ export { default as FluxStatisticsLineChart } from './FluxStatisticsLineChart.vu
18
18
  export { default as FluxStatisticsKpi } from './FluxStatisticsKpi.vue';
19
19
  export { default as FluxStatisticsLegend } from './FluxStatisticsLegend.vue';
20
20
  export { default as FluxStatisticsLegendItem } from './FluxStatisticsLegendItem.vue';
21
+ export { default as FluxStatisticsLegendScope } from './FluxStatisticsLegendScope.vue';
21
22
  export { default as FluxStatisticsMeter } from './FluxStatisticsMeter.vue';
22
23
  export { default as FluxStatisticsMetric } from './FluxStatisticsMetric.vue';
23
24
  export { default as FluxStatisticsMixedChart } from './FluxStatisticsMixedChart.vue';
25
+ export { default as FluxStatisticsPercentageBar } from './FluxStatisticsPercentageBar.vue';
24
26
  export { default as FluxStatisticsPieChart } from './FluxStatisticsPieChart.vue';
25
27
  export { default as FluxStatisticsPolarAreaChart } from './FluxStatisticsPolarAreaChart.vue';
26
28
  export { default as FluxStatisticsRadarChart } from './FluxStatisticsRadarChart.vue';
@@ -1,10 +1,12 @@
1
+ export type { UseChartBaseSetupReturn } from './useChartBaseSetup';
2
+ export { useChartBaseSetup } from './useChartBaseSetup';
1
3
  export type { ChartLegendContext, ChartLegendItem } from './useChartLegend';
2
4
  export { createChartLegendContext, FluxStatisticsChartLegendInjectionKey } from './useChartLegend';
3
5
  export type { ChartHoverSyncMode, UseChartHoverSyncOptions } from './useChartHoverSync';
4
6
  export { useChartHoverSync } from './useChartHoverSync';
5
7
  export type { ChartLegendItemBuilder, ChartSeriesShape, UseChartSeriesSetupOptions, UseChartSeriesSetupReturn } from './useChartSeriesSetup';
6
8
  export { useChartSeriesSetup } from './useChartSeriesSetup';
7
- export type { UsePieSlicesSetupReturn } from './usePieSlicesSetup';
8
- export { usePieSlicesSetup } from './usePieSlicesSetup';
9
+ export type { UseChartSlicesSetupReturn } from './useChartSlicesSetup';
10
+ export { useChartSlicesSetup } from './useChartSlicesSetup';
9
11
  export type { EChartsInstance, EChartsOption, UseEChartsReturn } from './useECharts';
10
12
  export { useECharts } from './useECharts';
@@ -0,0 +1,16 @@
1
+ import { computed, useTemplateRef, type ComputedRef } from 'vue';
2
+ import { useI18n } from 'vue-i18n';
3
+ import type { EChartsInstance } from './useECharts';
4
+
5
+ export interface UseChartBaseSetupReturn {
6
+ readonly t: ReturnType<typeof useI18n>['t'];
7
+ readonly chartInstance: ComputedRef<EChartsInstance | null>;
8
+ }
9
+
10
+ export function useChartBaseSetup(): UseChartBaseSetupReturn {
11
+ const { t } = useI18n({ useScope: 'parent' });
12
+ const chartRef = useTemplateRef<{ chartInstance: EChartsInstance | null } | null>('chartRef');
13
+ const chartInstance = computed<EChartsInstance | null>(() => chartRef.value?.chartInstance ?? null);
14
+
15
+ return { t, chartInstance };
16
+ }
@@ -6,7 +6,7 @@ import { useChartHoverSync } from './useChartHoverSync';
6
6
  import { type ChartLegendContext, type ChartLegendItem, FluxStatisticsChartLegendInjectionKey } from './useChartLegend';
7
7
  import type { EChartsInstance } from './useECharts';
8
8
 
9
- export interface UsePieSlicesSetupReturn {
9
+ export interface UseChartSlicesSetupReturn {
10
10
  readonly t: ReturnType<typeof useI18n>['t'];
11
11
  readonly palette: ComputedRef<readonly string[]>;
12
12
  readonly tooltipItems: ComputedRef<readonly SharedTooltipItem[]>;
@@ -14,9 +14,9 @@ export interface UsePieSlicesSetupReturn {
14
14
  readonly chartInstance: ComputedRef<EChartsInstance | null>;
15
15
  }
16
16
 
17
- export function usePieSlicesSetup(
17
+ export function useChartSlicesSetup(
18
18
  slicesGetter: () => readonly FluxStatisticsChartPieSlice[]
19
- ): UsePieSlicesSetupReturn {
19
+ ): UseChartSlicesSetupReturn {
20
20
  const { t } = useI18n({ useScope: 'parent' });
21
21
  const legendContext = inject(FluxStatisticsChartLegendInjectionKey, null);
22
22
  const chartRef = useTemplateRef<{ chartInstance: EChartsInstance | null } | null>('chartRef');
@@ -26,6 +26,16 @@
26
26
  --stroke: rgb(from var(--surface-stroke) r g b / .5);
27
27
  }
28
28
 
29
+ .statisticsChartTooltip {
30
+ background: rgb(from var(--surface) r g b / .975);
31
+ background-clip: padding-box;
32
+ backdrop-filter: blur(3px) saturate(180%);
33
+ border: 1px solid var(--surface-stroke-out-hover);
34
+ border-radius: var(--radius-double);
35
+ box-shadow: var(--shadow-lg);
36
+ color: var(--foreground);
37
+ }
38
+
29
39
  .statisticsChartTooltipTitle {
30
40
  padding: 18px 18px 0;
31
41
  color: var(--foreground-prominent);
@@ -110,18 +120,3 @@
110
120
  gap: 6px 15px;
111
121
  grid-template-columns: repeat(3, auto);
112
122
  }
113
-
114
- :global(.flux-statistics-tooltip) {
115
- background: rgb(from var(--surface) r g b / .975) !important;
116
- background-clip: padding-box;
117
- backdrop-filter: blur(3px) saturate(180%);
118
- border: 1px solid var(--surface-stroke-out-hover) !important;
119
- border-radius: var(--radius-double) !important;
120
- box-shadow: var(--shadow-lg) !important;
121
- color: var(--foreground);
122
- contain: paint;
123
-
124
- &:empty {
125
- display: none;
126
- }
127
- }
@@ -5,6 +5,7 @@
5
5
 
6
6
  container: chart-pane / inline-size;
7
7
  max-width: 100%;
8
+ contain: paint;
8
9
  }
9
10
 
10
11
  .statisticsChartPaneBody {
@@ -19,9 +20,11 @@
19
20
  }
20
21
 
21
22
  &:has(.statisticsLegend) {
23
+ align-items: center;
22
24
  grid-template-columns: .4fr .6fr;
23
25
 
24
26
  @container chart-pane (max-width: 390px) {
27
+ align-items: stretch;
25
28
  grid-template-columns: 1fr;
26
29
  grid-template-rows: auto auto;
27
30
  }
@@ -30,16 +33,6 @@
30
33
  height: calc(40cqw / var(--aspect-ratio, 1));
31
34
  }
32
35
  }
33
-
34
- &:first-child :global(canvas) {
35
- border-top-left-radius: var(--radius);
36
- border-top-right-radius: var(--radius);
37
- }
38
-
39
- &:last-child :global(canvas) {
40
- border-bottom-left-radius: var(--radius);
41
- border-bottom-right-radius: var(--radius);
42
- }
43
36
  }
44
37
 
45
38
  .statisticsChartPaneContainer {
@@ -1,7 +1,7 @@
1
1
  .statisticsEmpty {
2
- position: absolute;
3
2
  display: flex;
4
- inset: 0;
3
+ width: 100%;
4
+ height: 100%;
5
5
  padding: 24px 18px;
6
6
  flex-flow: column;
7
7
  align-items: center;
@@ -2,21 +2,24 @@
2
2
 
3
3
  .statisticsLegend {
4
4
  display: flex;
5
- max-height: 360px;
6
5
  min-width: 0;
7
- padding: 15px 18px 15px;
8
- align-self: center;
6
+ padding: 0 9px;
9
7
  flex-flow: column;
10
8
  flex-grow: 1;
11
- overflow: auto;
9
+ gap: 3px;
12
10
  user-select: none;
13
11
  }
14
12
 
13
+ :local(.statisticsChartPaneBody) .statisticsLegend {
14
+ padding: 9px 36px 9px 18px;
15
+ }
16
+
15
17
  .statisticsLegendItem {
16
18
  --color: var(--primary-600);
17
19
 
20
+ position: relative;
18
21
  display: flex;
19
- padding: 6px 9px;
22
+ padding: 6px;
20
23
  margin: 0 -9px;
21
24
  align-items: flex-start;
22
25
  flex-flow: row nowrap;
@@ -24,8 +27,8 @@
24
27
  font-size: 14px;
25
28
  line-height: 20px;
26
29
  white-space: nowrap;
27
- border-radius: var(--radius-small);
28
- transition: background var(--swift-out);
30
+ border-radius: var(--radius-half);
31
+ transition: background 120ms var(--swift-out);
29
32
  }
30
33
 
31
34
  .statisticsLegendItem.isHovered {
@@ -57,6 +60,11 @@
57
60
  text-align: right;
58
61
  }
59
62
 
60
- .statisticsLegendItem + .statisticsLegendItem {
63
+ .statisticsLegendItem + .statisticsLegendItem::before {
64
+ position: absolute;
65
+ top: -2px;
66
+ left: 0;
67
+ right: 0;
68
+ content: '';
61
69
  border-top: 1px dashed var(--surface-stroke);
62
70
  }