✨ feat (ui): add radix vue components library
This commit is contained in:
@@ -0,0 +1,101 @@
|
||||
<script setup lang="ts" generic="T extends Record<string, any>">
|
||||
import type { Component } from 'vue'
|
||||
import type { BaseChartProps } from '.'
|
||||
import { cn } from '@/lib/utils'
|
||||
import { Donut } from '@unovis/ts'
|
||||
import { VisDonut, VisSingleContainer } from '@unovis/vue'
|
||||
import { useMounted } from '@vueuse/core'
|
||||
import { computed, ref } from 'vue'
|
||||
import { ChartSingleTooltip, defaultColors } from '../chart'
|
||||
|
||||
const props = withDefaults(defineProps<Pick<BaseChartProps<T>, 'data' | 'colors' | 'index' | 'margin' | 'showLegend' | 'showTooltip' | 'filterOpacity'> & {
|
||||
/**
|
||||
* Sets the name of the key containing the quantitative chart values.
|
||||
*/
|
||||
category: KeyOfT
|
||||
/**
|
||||
* Change the type of the chart
|
||||
* @default "donut"
|
||||
*/
|
||||
type?: 'donut' | 'pie'
|
||||
/**
|
||||
* Function to sort the segment
|
||||
*/
|
||||
sortFunction?: (a: any, b: any) => number | undefined
|
||||
/**
|
||||
* Controls the formatting for the label.
|
||||
*/
|
||||
valueFormatter?: (tick: number, i?: number, ticks?: number[]) => string
|
||||
/**
|
||||
* Render custom tooltip component.
|
||||
*/
|
||||
customTooltip?: Component
|
||||
}>(), {
|
||||
margin: () => ({ top: 0, bottom: 0, left: 0, right: 0 }),
|
||||
sortFunction: () => undefined,
|
||||
valueFormatter: (tick: number) => `${tick}`,
|
||||
type: 'donut',
|
||||
filterOpacity: 0.2,
|
||||
showTooltip: true,
|
||||
showLegend: true,
|
||||
})
|
||||
|
||||
type KeyOfT = Extract<keyof T, string>
|
||||
type Data = typeof props.data[number]
|
||||
|
||||
const category = computed(() => props.category as KeyOfT)
|
||||
const index = computed(() => props.index as KeyOfT)
|
||||
|
||||
const isMounted = useMounted()
|
||||
const activeSegmentKey = ref<string>()
|
||||
const colors = computed(() => props.colors?.length ? props.colors : defaultColors(props.data.filter(d => d[props.category]).filter(Boolean).length))
|
||||
const legendItems = computed(() => props.data.map((item, i) => ({
|
||||
name: item[props.index],
|
||||
color: colors.value[i],
|
||||
inactive: false,
|
||||
})))
|
||||
|
||||
const totalValue = computed(() => props.data.reduce((prev, curr) => {
|
||||
return prev + curr[props.category]
|
||||
}, 0))
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div :class="cn('w-full h-48 flex flex-col items-end', $attrs.class ?? '')">
|
||||
<VisSingleContainer :style="{ height: isMounted ? '100%' : 'auto' }" :margin="{ left: 20, right: 20 }" :data="data">
|
||||
<ChartSingleTooltip
|
||||
:selector="Donut.selectors.segment"
|
||||
:index="category"
|
||||
:items="legendItems"
|
||||
:value-formatter="valueFormatter"
|
||||
:custom-tooltip="customTooltip"
|
||||
/>
|
||||
|
||||
<VisDonut
|
||||
:value="(d: Data) => d[category]"
|
||||
:sort-function="sortFunction"
|
||||
:color="colors"
|
||||
:arc-width="type === 'donut' ? 20 : 0"
|
||||
:show-background="false"
|
||||
:central-label="type === 'donut' ? valueFormatter(totalValue) : ''"
|
||||
:events="{
|
||||
[Donut.selectors.segment]: {
|
||||
click: (d: Data, ev: PointerEvent, i: number, elements: HTMLElement[]) => {
|
||||
if (d?.data?.[index] === activeSegmentKey) {
|
||||
activeSegmentKey = undefined
|
||||
elements.forEach(el => el.style.opacity = '1')
|
||||
}
|
||||
else {
|
||||
activeSegmentKey = d?.data?.[index]
|
||||
elements.forEach(el => el.style.opacity = `${filterOpacity}`)
|
||||
elements[i].style.opacity = '1'
|
||||
}
|
||||
},
|
||||
},
|
||||
}"
|
||||
/>
|
||||
|
||||
<slot />
|
||||
</VisSingleContainer>
|
||||
</div>
|
||||
</template>
|
||||
@@ -0,0 +1,39 @@
|
||||
import type { Spacing } from '@unovis/ts'
|
||||
|
||||
export { default as DonutChart } from './DonutChart.vue'
|
||||
|
||||
type KeyOf<T extends Record<string, any>> = Extract<keyof T, string>
|
||||
|
||||
export interface BaseChartProps<T extends Record<string, any>> {
|
||||
/**
|
||||
* The source data, in which each entry is a dictionary.
|
||||
*/
|
||||
data: T[]
|
||||
/**
|
||||
* Sets the key to map the data to the axis.
|
||||
*/
|
||||
index: KeyOf<T>
|
||||
/**
|
||||
* Change the default colors.
|
||||
*/
|
||||
colors?: string[]
|
||||
/**
|
||||
* Margin of each the container
|
||||
*/
|
||||
margin?: Spacing
|
||||
/**
|
||||
* Change the opacity of the non-selected field
|
||||
* @default 0.2
|
||||
*/
|
||||
filterOpacity?: number
|
||||
/**
|
||||
* Controls the visibility of tooltip.
|
||||
* @default true
|
||||
*/
|
||||
showTooltip?: boolean
|
||||
/**
|
||||
* Controls the visibility of legend.
|
||||
* @default true
|
||||
*/
|
||||
showLegend?: boolean
|
||||
}
|
||||
Reference in New Issue
Block a user