Skip to content

Commit 0203d6b

Browse files
committed
wip
1 parent cec41cb commit 0203d6b

File tree

10 files changed

+124
-103
lines changed

10 files changed

+124
-103
lines changed

demo/app/Sharp/Dashboard/DemoDashboard.php

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,7 @@ protected function buildWidgets(WidgetsContainer $widgetsContainer): void
4545
->addWidget(
4646
SharpBarGraphWidget::make('authors_bar')
4747
->setTitle('Posts by author')
48+
->setShowAllLabels()
4849
->setShowLegend(false)
4950
// ->setHorizontal(),
5051
)
@@ -58,8 +59,11 @@ protected function buildWidgets(WidgetsContainer $widgetsContainer): void
5859
->setHeight(200)
5960
// ->setShowLegend()
6061
->setDisplayHorizontalAxisAsTimeline()
61-
->setMinimal()
62-
->setFilled(),
62+
// ->setShowAllLabels()
63+
// ->setShowDots()
64+
// ->setFilled()
65+
// ->setMinimal()
66+
6367
)
6468
->addWidget(
6569
SharpFigureWidget::make('draft_panel')

resources/js/components/ui/chart/ChartContainer.vue

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -51,7 +51,9 @@ provideChartContext({
5151
'--vis-tooltip-backdrop-filter': 'none',
5252
'--vis-crosshair-circle-stroke-color': '#0000',
5353
'--vis-crosshair-line-stroke-width': cursor ? '1px' : '0px',
54+
'--vis-crosshair-line-stroke-color': 'var(--border)',
5455
'--vis-font-family': 'var(--font-sans)',
56+
'--vis-donut-background-color': 'var(--muted)'
5557
}"
5658
>
5759
<slot :id="uniqueId" :config="config" />

resources/js/dashboard/components/widgets/graph/Bar.vue

Lines changed: 10 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -15,42 +15,34 @@
1515
XYContainerConfigInterface,
1616
} from '@unovis/ts'
1717
import { Datum, useXYChart } from "@/dashboard/components/widgets/graph/useXYChart";
18-
import { computed } from "vue";
1918
import { ChartContainer, ChartLegendContent, ChartTooltip, ChartCrosshair } from "@/components/ui/chart";
2019
2120
const props = defineProps<DashboardWidgetProps<GraphWidgetData>>();
2221
23-
const { data, x, y, color, tooltipTemplate, chartConfig, tickFormat } = useXYChart(props);
24-
25-
const rotate = computed(() => !props.widget.options.horizontal && props.value?.labels?.length >= 10);
22+
const { data, x, y, color, tooltipTemplate, chartConfig, xAxisConfig, xScale } = useXYChart(props);
2623
</script>
2724

2825
<template>
29-
<ChartContainer :config="chartConfig" class="flex flex-col gap-4">
26+
<ChartContainer :config="chartConfig" class="flex flex-col" cursor>
3027
<VisXYContainer class="flex-1 min-h-0"
31-
v-bind="{ } as XYContainerConfigInterface<Datum>"
28+
v-bind="{
29+
xScale: xScale,
30+
} as XYContainerConfigInterface<Datum>"
3231
:data="data"
3332
>
3433
<template v-if="!props.widget.minimal">
3534
<VisAxis
3635
v-bind="{
37-
type: props.widget.options?.horizontal ? 'x' : 'y',
36+
type: props.widget.options?.horizontal ? 'y' : 'x',
37+
gridLine: false,
3838
domainLine: false,
39+
...xAxisConfig,
3940
} as AxisConfigInterface<Datum>"
4041
/>
4142
<VisAxis
4243
v-bind="{
43-
type: props.widget.options?.horizontal ? 'y' : 'x',
44-
gridLine: false,
45-
domainLine: false,
46-
// tickValues: props.value?.labels.map((_, i) => i),
47-
numTicks: props.value?.labels.length - 1,
48-
tickFormat: tickFormat,
49-
tickTextTrimType: TrimMode.End,
50-
tickTextAlign: rotate ? TextAlign.Left : props.widget.options.horizontal ? TextAlign.Right : TextAlign.Center,
51-
tickTextFitMode: rotate ? FitMode.Wrap : FitMode.Trim,
52-
tickTextAngle: rotate ? 45 : undefined,
53-
tickTextWidth: rotate ? 100 : undefined,
44+
type: props.widget.options?.horizontal ? 'x' : 'y',
45+
domainLine: false,
5446
} as AxisConfigInterface<Datum>"
5547
/>
5648
</template>
@@ -80,13 +72,6 @@
8072

8173
<template v-if="props.widget.showLegend && !props.widget.minimal">
8274
<ChartLegendContent />
83-
<div class="flex justify-center">
84-
<VisBulletLegend
85-
v-bind="{
86-
items: props.value.datasets?.map(dataset => ({ name: dataset.label, color: dataset.color })),
87-
} as BulletLegendConfigInterface"
88-
/>
89-
</div>
9075
</template>
9176
</ChartContainer>
9277
</template>

resources/js/dashboard/components/widgets/graph/Line.vue

Lines changed: 13 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -15,11 +15,8 @@
1515
1616
const props = defineProps<DashboardWidgetProps<GraphWidgetData>>();
1717
18-
// props.value.datasets = props.value?.datasets.toReversed();
18+
const { data, x, y, color, tooltipTemplate, xScale, chartConfig, xAxisConfig } = useXYChart(props);
1919
20-
const { data, x, y, color, tooltipTemplate, xScale, xTickValues, tickFormat, chartConfig } = useXYChart(props);
21-
22-
// const rotate = computed(() => props.value?.labels?.length >= 10);
2320
const svgDefs = computed(() => props.value?.datasets.map((dataset, i) => `
2421
<linearGradient id="fill-${i}" x1="0" y1="0" x2="0" y2="1">
2522
<stop
@@ -37,7 +34,7 @@
3734
</script>
3835

3936
<template>
40-
<ChartContainer class="flex flex-col" :config="chartConfig">
37+
<ChartContainer class="flex flex-col" :config="chartConfig" cursor>
4138
<VisXYContainer class="flex-1 min-h-0"
4239
v-bind="{
4340
xScale: xScale,
@@ -49,10 +46,9 @@
4946
<VisAxis
5047
v-bind="{
5148
type: 'x',
52-
tickFormat: tickFormat,
53-
tickValues: xTickValues,
5449
gridLine: false,
5550
domainLine: false,
51+
...xAxisConfig,
5652
} as AxisConfigInterface<Datum>"
5753
/>
5854
<VisAxis v-bind="{
@@ -66,7 +62,7 @@
6662
x: x,
6763
y: y,
6864
color: color,
69-
lineWidth: 1,
65+
lineWidth: props.widget.options.filled ? 1 : 2,
7066
curveType: props.widget.options.curved ? CurveType.MonotoneX : CurveType.Linear,
7167
} as LineConfigInterface<Datum>"
7268
/>
@@ -94,13 +90,15 @@
9490
/>
9591
<ChartTooltip />
9692

97-
<!-- <template v-if="props.value?.labels.length < 40">-->
98-
<!-- <template v-for="dataset in props.value?.datasets">-->
99-
<!-- <VisScatter-->
100-
<!-- v-bind="{ size: 4, x: x, y: y, strokeColor: color, color: 'var(&#45;&#45;background)' } as ScatterConfigInterface<Datum>"-->
101-
<!-- />-->
102-
<!-- </template>-->
103-
<!-- </template>-->
93+
<template v-if="props.widget.options.showDots">
94+
<template v-for="dataset in props.value?.datasets">
95+
<VisScatter
96+
v-bind="{ size: 6, x: x, y: y,
97+
// strokeColor: color,
98+
color: color } as ScatterConfigInterface<Datum>"
99+
/>
100+
</template>
101+
</template>
104102
</VisXYContainer>
105103
<template v-if="props.widget.showLegend && !props.widget.minimal">
106104
<ChartLegendContent />

resources/js/dashboard/components/widgets/graph/Pie.vue

Lines changed: 10 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -36,33 +36,21 @@
3636

3737
<template>
3838
<ChartContainer class="min-h-[250px] sm:min-h-0 flex flex-col gap-y-2 gap-x-4 sm:gap-4" :config="chartConfig" ref="container">
39-
<UseElementSize class="flex-1 min-h-0 flex flex-col" v-slot="{ width, height }">
40-
<VisSingleContainer class="flex-1 min-h-0">
39+
<!-- <UseElementSize class="flex-1 min-h-0 flex flex-col" v-slot="{ width, height }">-->
40+
<VisSingleContainer class="flex-1 min-h-0 ">
4141
<VisDonut
4242
v-bind="{
43-
data: data,
44-
value: d => d.value,
45-
color: d => d.color,
46-
// arcWidth: 47,
47-
arcWidth: width ? log(Math.round(Math.min(width, height) * .15), width, height) : 20,
48-
showBackground: false,
49-
attributes: {
50-
// [Donut.selectors.segment]: {
51-
// 'class'() {
52-
// return `${Donut.selectors.segment} relative fill-(--color) hover:stroke-10! stroke-(--color)! transition-all [transform-box:fill-box] origin-center`;
53-
// },
54-
// 'style'(data: CallbackData) {
55-
// return `--color:${data.data.color}`;
56-
// // return { '--color': data.color }
57-
// }
58-
// }
59-
}
60-
} as DonutConfigInterface<Datum>"
43+
data: data,
44+
value: d => d.value,
45+
color: d => d.color,
46+
// arcWidth: width ? log(Math.round(Math.min(width, height) * 0), width, height) : 20,
47+
// showBackground: false,
48+
arcWidth: 0,
49+
} as DonutConfigInterface<Datum>"
6150
/>
6251
<ChartTooltip :triggers="{ [Donut.selectors.segment]: tooltipTemplate }" />
6352
</VisSingleContainer>
64-
</UseElementSize>
65-
53+
<!-- </UseElementSize>-->
6654

6755
<template v-if="props.widget.showLegend && !props.widget.minimal">
6856
<ChartLegendContent />

resources/js/dashboard/components/widgets/graph/useXYChart.ts

Lines changed: 47 additions & 38 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,14 @@ import { DashboardWidgetProps } from "@/dashboard/types";
22
import { GraphWidgetData } from "@/types";
33
import { computed, reactive, toRefs } from "vue";
44
import { XYComponentConfigInterface } from "@unovis/ts/core/xy-component/config";
5-
import { AxisConfigInterface, ColorAccessor, CrosshairConfigInterface, Scale } from "@unovis/ts";
5+
import {
6+
AxisConfigInterface,
7+
ColorAccessor,
8+
FitMode,
9+
Scale,
10+
TextAlign,
11+
TrimMode
12+
} from "@unovis/ts";
613
import { timeTickInterval } from 'd3-time';
714
import { ChartConfig, ChartTooltip, ChartTooltipContent, componentToString } from "@/components/ui/chart";
815
export type Datum = number[];
@@ -15,62 +22,65 @@ export function useXYChart(props: DashboardWidgetProps<GraphWidgetData>) {
1522
});
1623
return res;
1724
}, []));
18-
// const timeScale = false;
1925
const timeScale = true;
2026
const x: XYComponentConfigInterface<Datum>['x'] = (d, i) => {
21-
return props.widget.dateLabels && timeScale ? new Date(props.value.labels[i]).getTime(): i;
27+
return props.widget.dateLabels && !props.widget.showAllLabels && timeScale
28+
? new Date(props.value.labels[i]).getTime()
29+
: i;
2230
};
2331
const y = computed((): XYComponentConfigInterface<Datum>['y'] => props.value?.datasets.map((dataset, i) => (d) => d[i]));
2432
const xScale = computed((): XYComponentConfigInterface<Datum>['xScale'] => {
25-
return props.widget.dateLabels && timeScale
33+
return props.widget.dateLabels && !props.widget.showAllLabels && timeScale
2634
? Scale.scaleUtc().domain([new Date(props.value.labels[0]), new Date(props.value.labels.at(-1))]) as any
2735
: undefined
2836
});
29-
const xTickValues = computed((): AxisConfigInterface<Datum>['tickValues'] => {
30-
// return undefined;
31-
if(props.widget.dateLabels && timeScale) {
32-
return props.value.labels.length < 10
33-
? props.value.labels.map((l) => new Date(l))
34-
: xScale.value.ticks(10) as any;
35-
}
36-
});
3737
const color = computed((): ColorAccessor<Datum | Datum[]> => props.value?.datasets.map((dataset, i) => dataset.color));
3838

39-
// const tooltipTemplate = (d: Datum, x: number) => {
40-
// const formattedLabel = props.widget.dateLabels
41-
// ? new Intl.DateTimeFormat(undefined, { day: '2-digit', month: 'short' }).format(timeScale ? x : new Date(props.value.labels[Math.round(x as number)]))
42-
// : props.value.labels[Math.round(x as number)];
43-
// return `<div class="mb-1 text-sm">${formattedLabel}</div>
44-
// ${
45-
// props.value?.datasets.map((dataset, i) =>
46-
// `<div class="flex items-center gap-2 text-sm">
47-
// <span class="size-2 rounded-full bg-(--color)" style="--color: ${dataset.color}"></span>
48-
// ${dataset.label ? `<span class="text-sm">${dataset.label}:</span>` : ''}
49-
// ${d[i]}
50-
// </div>`
51-
// ).join('')
52-
// }`;
53-
// }
54-
5539
const chartConfig = computed((): ChartConfig =>
5640
Object.fromEntries(props.value?.datasets.map((dataset, i) => [i, ({ label: dataset.label, color: dataset.color })]))
5741
);
5842

5943
const tooltipTemplate = componentToString(chartConfig, ChartTooltipContent, {
6044
labelFormatter: (x) => {
6145
return props.widget.dateLabels
62-
? new Intl.DateTimeFormat(undefined, { day: '2-digit', month: 'short' }).format(timeScale ? x : new Date(props.value.labels[Math.round(x as number)]))
46+
? new Intl.DateTimeFormat(undefined, { day: '2-digit', month: 'short' })
47+
.format(x instanceof Date ? x : new Date(props.value.labels[Math.round(x as number)]))
6348
: props.value.labels[Math.round(x as number)];
6449
}
6550
});
6651

67-
const tickFormat: AxisConfigInterface<number[]>['tickFormat'] = (tick, i) => {
68-
if(props.widget.dateLabels) {
69-
return new Intl.DateTimeFormat(undefined, { day: '2-digit', month: 'short' })
70-
.format(timeScale ? tick : new Date(props.value.labels[tick as number]));
71-
}
72-
return props.value?.labels?.[tick as number];
73-
}
52+
const rotate = computed(() =>
53+
!props.widget.options.horizontal
54+
&& props.widget.showAllLabels
55+
&& props.value?.labels?.length >= 10
56+
);
57+
58+
const xAxisConfig = computed((): AxisConfigInterface<Datum> => ({
59+
tickValues: (() => {
60+
if(props.widget.showAllLabels) {
61+
return props.value.labels.map((_, i) => i);
62+
}
63+
if(props.widget.dateLabels && timeScale) {
64+
return props.value.labels.length < 10
65+
? props.value.labels.map((l) => new Date(l))
66+
: xScale.value.ticks(10) as any;
67+
}
68+
})(),
69+
tickFormat: (tick, i) => {
70+
if(props.widget.dateLabels) {
71+
return new Intl.DateTimeFormat(undefined, { day: '2-digit', month: 'short' })
72+
.format(tick instanceof Date ? tick : new Date(props.value.labels[tick as number]));
73+
}
74+
return props.value?.labels?.[tick as number];
75+
},
76+
tickTextTrimType: TrimMode.End,
77+
// tickTextAlign: rotate.value ? TextAlign.Left : props.widget.options.horizontal ? TextAlign.Right : TextAlign.Center,
78+
tickTextAlign: rotate.value ? TextAlign.Right : props.widget.options.horizontal ? TextAlign.Right : TextAlign.Center,
79+
tickTextFitMode: rotate.value ? FitMode.Wrap : FitMode.Trim,
80+
// tickTextAngle: rotate.value ? 45 : undefined,
81+
tickTextAngle: rotate.value ? -45 : undefined,
82+
tickTextWidth: rotate.value ? 100 : undefined,
83+
}));
7484

7585
return {
7686
data,
@@ -80,8 +90,7 @@ export function useXYChart(props: DashboardWidgetProps<GraphWidgetData>) {
8090
tooltipTemplate,
8191
timeScale,
8292
xScale,
83-
xTickValues,
8493
chartConfig,
85-
tickFormat,
94+
xAxisConfig,
8695
};
8796
}

resources/js/types/generated.d.ts

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -661,7 +661,13 @@ export type GraphWidgetData = {
661661
ratioY: number | null;
662662
height: number | null;
663663
dateLabels: boolean;
664-
options: { curved: boolean; horizontal: boolean; filled: boolean };
664+
showAllLabels: boolean;
665+
options: {
666+
curved: boolean;
667+
horizontal: boolean;
668+
filled: boolean;
669+
showDots: boolean;
670+
};
665671
};
666672
export type GraphWidgetDisplay = "bar" | "line" | "pie";
667673
export type IconData = {

src/Dashboard/Widgets/SharpBarGraphWidget.php

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ class SharpBarGraphWidget extends SharpGraphWidget
66
{
77
protected bool $horizontal = false;
88
protected bool $displayHorizontalAxisAsTimeline = false;
9+
protected bool $showAllLabels = false;
910

1011
public static function make(string $key): SharpBarGraphWidget
1112
{
@@ -29,11 +30,19 @@ public function setDisplayHorizontalAxisAsTimeline(bool $displayAsTimeline = tru
2930
return $this;
3031
}
3132

33+
public function setShowAllLabels(bool $showAllLabels = true): self
34+
{
35+
$this->showAllLabels = $showAllLabels;
36+
37+
return $this;
38+
}
39+
3240
public function toArray(): array
3341
{
3442
return array_merge(
3543
parent::toArray(), [
3644
'dateLabels' => $this->displayHorizontalAxisAsTimeline,
45+
'showAllLabels' => $this->showAllLabels,
3746
'options' => [
3847
'horizontal' => $this->horizontal,
3948
],

0 commit comments

Comments
 (0)