Files
better-auth/examples/nuxt-example/components/ui/chart-bar/BarChart.vue
Bereket Engida 9f2e45b8c7 chore: cleanup
2025-01-06 14:30:39 +03:00

130 lines
3.4 KiB
Vue

<script setup lang="ts" generic="T extends Record<string, any>">
import type { BulletLegendItemInterface } from "@unovis/ts";
import { VisGroupedBar, VisStackedBar } from "@unovis/vue";
import { GroupedBar, StackedBar } from "@unovis/ts";
import { type Component, computed, ref } from "vue";
import { useMounted } from "@vueuse/core";
import type { BaseChartProps } from ".";
import { defaultColors } from "@/components/ui/chart";
const props = withDefaults(
defineProps<
BaseChartProps<T> & {
/**
* Render custom tooltip component.
*/
customTooltip?: Component;
/**
* Change the type of the chart
* @default "grouped"
*/
type?: "stacked" | "grouped";
/**
* Rounded bar corners
* @default 0
*/
roundedCorners?: number;
}
>(),
{
type: "grouped",
margin: () => ({ top: 0, bottom: 0, left: 0, right: 0 }),
filterOpacity: 0.2,
roundedCorners: 0,
showXAxis: true,
showYAxis: true,
showTooltip: true,
showLegend: true,
showGridLine: true,
},
);
const emits = defineEmits<{
legendItemClick: [d: BulletLegendItemInterface, i: number];
}>();
type KeyOfT = Extract<keyof T, string>;
type Data = (typeof props.data)[number];
const index = computed(() => props.index as KeyOfT);
const colors = computed(() =>
props.colors?.length ? props.colors : defaultColors(props.categories.length),
);
const legendItems = ref<BulletLegendItemInterface[]>(
props.categories.map((category, i) => ({
name: category,
color: colors.value[i],
inactive: false,
})),
);
const isMounted = useMounted();
function handleLegendItemClick(d: BulletLegendItemInterface, i: number) {
emits("legendItemClick", d, i);
}
const VisBarComponent = computed(() =>
props.type === "grouped" ? VisGroupedBar : VisStackedBar,
);
const selectorsBar = computed(() =>
props.type === "grouped"
? GroupedBar.selectors.bar
: StackedBar.selectors.bar,
);
</script>
<template>
<div :class="cn('w-full h-[400px] flex flex-col items-end', $attrs.class ?? '')">
<ChartLegend v-if="showLegend" v-model:items="legendItems" @legend-item-click="handleLegendItemClick" />
<VisXYContainer
:data="data"
:style="{ height: isMounted ? '100%' : 'auto' }"
:margin="margin"
>
<ChartCrosshair v-if="showTooltip" :colors="colors" :items="legendItems" :custom-tooltip="customTooltip" :index="index" />
<VisBarComponent
:x="(d: Data, i: number) => i"
:y="categories.map(category => (d: Data) => d[category]) "
:color="colors"
:rounded-corners="roundedCorners"
:bar-padding="0.05"
:attributes="{
[selectorsBar]: {
opacity: (d: Data, i:number) => {
const pos = i % categories.length
return legendItems[pos]?.inactive ? filterOpacity : 1
},
},
}"
/>
<VisAxis
v-if="showXAxis"
type="x"
:tick-format="xFormatter ?? ((v: number) => data[v]?.[index])"
:grid-line="false"
:tick-line="false"
tick-text-color="hsl(var(--vis-text-color))"
/>
<VisAxis
v-if="showYAxis"
type="y"
:tick-line="false"
:tick-format="yFormatter"
:domain-line="false"
:grid-line="showGridLine"
:attributes="{
[Axis.selectors.grid]: {
class: 'text-muted',
},
}"
tick-text-color="hsl(var(--vis-text-color))"
/>
<slot />
</VisXYContainer>
</div>
</template>