feat: use generic, add better color
This commit is contained in:
parent
eff7d65f78
commit
475c0e0e95
|
|
@ -1,28 +1,73 @@
|
|||
<script setup lang="ts">
|
||||
<script setup lang="ts" generic="T extends Record<string, any>">
|
||||
import type { BulletLegendItemInterface } from '@unovis/ts'
|
||||
import { VisArea, VisAxis, VisLine, VisXYContainer } from '@unovis/vue'
|
||||
import { Area, Axis, Line } from '@unovis/ts'
|
||||
import { ref } from 'vue'
|
||||
import { computed, ref } from 'vue'
|
||||
import { useMounted } from '@vueuse/core'
|
||||
import { ChartCrosshair, ChartLegend, defaultColors } from '@/lib/registry/default/ui/chart'
|
||||
import { cn } from '@/lib/utils'
|
||||
|
||||
const props = withDefaults(defineProps<{
|
||||
data: any[]
|
||||
/**
|
||||
* The source data, in which each entry is a dictionary.
|
||||
*/
|
||||
data: T[]
|
||||
/**
|
||||
* Select the categories from your data. Used to populate the legend and toolip.
|
||||
*/
|
||||
categories: string[]
|
||||
/**
|
||||
* Sets the key to map the data to the axis.
|
||||
*/
|
||||
index: string
|
||||
/**
|
||||
* Change the default colors.
|
||||
*/
|
||||
colors?: string[]
|
||||
/**
|
||||
* Change the opacity of the non-selected field
|
||||
* @default 0.2
|
||||
*/
|
||||
filterOpacity?: number
|
||||
/**
|
||||
* Function to format X label
|
||||
*/
|
||||
xFormatter?: (tick: number | Date, i: number, ticks: number[] | Date[]) => string
|
||||
/**
|
||||
* Function to format Y label
|
||||
*/
|
||||
yFormatter?: (tick: number | Date, i: number, ticks: number[] | Date[]) => string
|
||||
/**
|
||||
* Controls the visibility of the X axis.
|
||||
* @default true
|
||||
*/
|
||||
showXAxis?: boolean
|
||||
/**
|
||||
* Controls the visibility of the Y axis.
|
||||
* @default true
|
||||
*/
|
||||
showYAxis?: boolean
|
||||
/**
|
||||
* Controls the visibility of tooltip.
|
||||
* @default true
|
||||
*/
|
||||
showTooltip?: boolean
|
||||
/**
|
||||
* Controls the visibility of legend.
|
||||
* @default true
|
||||
*/
|
||||
showLegend?: boolean
|
||||
/**
|
||||
* Controls the visibility of gridline.
|
||||
* @default true
|
||||
*/
|
||||
showGridLine?: boolean
|
||||
/**
|
||||
* Controls the visibility of gradient.
|
||||
* @default true
|
||||
*/
|
||||
showGradiant?: boolean
|
||||
}>(), {
|
||||
colors: () => defaultColors,
|
||||
filterOpacity: 0.2,
|
||||
showXAxis: true,
|
||||
showYAxis: true,
|
||||
|
|
@ -33,10 +78,11 @@ const props = withDefaults(defineProps<{
|
|||
})
|
||||
|
||||
type Data = typeof props.data[number]
|
||||
const colors = computed(() => props.colors?.length ? props.colors : defaultColors(props.categories.length))
|
||||
|
||||
const legendItems = ref<BulletLegendItemInterface[]>(props.categories.map((category, i) => ({
|
||||
name: category,
|
||||
color: props.colors[i],
|
||||
color: colors.value[i],
|
||||
inactive: false,
|
||||
})))
|
||||
|
||||
|
|
@ -118,14 +164,3 @@ function handleLegendItemClick(d: BulletLegendItemInterface, i: number) {
|
|||
</VisXYContainer>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<style>
|
||||
:root {
|
||||
--vis-tooltip-background-color: none;
|
||||
--vis-tooltip-border-color: none;
|
||||
--vis-tooltip-text-color: none;
|
||||
--vis-tooltip-shadow-color: none;
|
||||
--vis-tooltip-backdrop-filter: none;
|
||||
--vis-tooltip-padding: none;
|
||||
}
|
||||
</style>
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
<script setup lang="ts">
|
||||
<script setup lang="ts" generic="T extends Record<string, any>">
|
||||
import type { BulletLegendItemInterface } from '@unovis/ts'
|
||||
import { VisAxis, VisGroupedBar, VisStackedBar, VisXYContainer } from '@unovis/vue'
|
||||
import { Axis, GroupedBar, StackedBar } from '@unovis/ts'
|
||||
|
|
@ -8,21 +8,66 @@ import { ChartCrosshair, ChartLegend, defaultColors } from '@/lib/registry/defau
|
|||
import { cn } from '@/lib/utils'
|
||||
|
||||
const props = withDefaults(defineProps<{
|
||||
data: any[]
|
||||
/**
|
||||
* The source data, in which each entry is a dictionary.
|
||||
*/
|
||||
data: T[]
|
||||
/**
|
||||
* Select the categories from your data. Used to populate the legend and toolip.
|
||||
*/
|
||||
categories: string[]
|
||||
/**
|
||||
* Sets the key to map the data to the axis.
|
||||
*/
|
||||
index: string
|
||||
/**
|
||||
* Change the default colors.
|
||||
*/
|
||||
colors?: string[]
|
||||
/**
|
||||
* Change the opacity of the non-selected field
|
||||
* @default 0.2
|
||||
*/
|
||||
filterOpacity?: number
|
||||
/**
|
||||
* Change the type of the chart
|
||||
* @default "grouped"
|
||||
*/
|
||||
type?: 'stacked' | 'grouped'
|
||||
/**
|
||||
* Function to format X label
|
||||
*/
|
||||
xFormatter?: (tick: number | Date, i: number, ticks: number[] | Date[]) => string
|
||||
/**
|
||||
* Function to format Y label
|
||||
*/
|
||||
yFormatter?: (tick: number | Date, i: number, ticks: number[] | Date[]) => string
|
||||
/**
|
||||
* Controls the visibility of the X axis.
|
||||
* @default true
|
||||
*/
|
||||
showXAxis?: boolean
|
||||
/**
|
||||
* Controls the visibility of the Y axis.
|
||||
* @default true
|
||||
*/
|
||||
showYAxis?: boolean
|
||||
/**
|
||||
* Controls the visibility of tooltip.
|
||||
* @default true
|
||||
*/
|
||||
showTooltip?: boolean
|
||||
/**
|
||||
* Controls the visibility of legend.
|
||||
* @default true
|
||||
*/
|
||||
showLegend?: boolean
|
||||
/**
|
||||
* Controls the visibility of gridline.
|
||||
* @default true
|
||||
*/
|
||||
showGridLine?: boolean
|
||||
}>(), {
|
||||
colors: () => defaultColors,
|
||||
type: 'grouped',
|
||||
filterOpacity: 0.2,
|
||||
showXAxis: true,
|
||||
|
|
@ -32,11 +77,10 @@ const props = withDefaults(defineProps<{
|
|||
showGridLine: true,
|
||||
})
|
||||
|
||||
type Data = typeof props.data[number]
|
||||
|
||||
const colors = computed(() => props.colors?.length ? props.colors : defaultColors(props.categories.length))
|
||||
const legendItems = ref<BulletLegendItemInterface[]>(props.categories.map((category, i) => ({
|
||||
name: category,
|
||||
color: props.colors[i],
|
||||
color: colors.value[i],
|
||||
inactive: false,
|
||||
})))
|
||||
|
||||
|
|
@ -58,14 +102,14 @@ const selectorsBar = computed(() => props.type === 'grouped' ? GroupedBar.select
|
|||
<ChartCrosshair v-if="showTooltip" :colors="colors" :items="legendItems" :index="index" />
|
||||
|
||||
<VisBarComponent
|
||||
:x="(d: Data, i: number) => i"
|
||||
:y="categories.map(category => (d: Data) => d[category]) "
|
||||
:x="(d: T, i: number) => i"
|
||||
:y="categories.map(category => (d: T) => d[category]) "
|
||||
:color="colors"
|
||||
:rounded-corners="4"
|
||||
:bar-padding="0.1"
|
||||
:attributes="{
|
||||
[selectorsBar]: {
|
||||
opacity: (d: Data, i:number) => {
|
||||
opacity: (d: T, i:number) => {
|
||||
const pos = i % categories.length
|
||||
return legendItems[pos]?.inactive ? filterOpacity : 1
|
||||
},
|
||||
|
|
@ -98,14 +142,3 @@ const selectorsBar = computed(() => props.type === 'grouped' ? GroupedBar.select
|
|||
</VisXYContainer>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<style>
|
||||
:root {
|
||||
--vis-tooltip-background-color: none;
|
||||
--vis-tooltip-border-color: none;
|
||||
--vis-tooltip-text-color: none;
|
||||
--vis-tooltip-shadow-color: none;
|
||||
--vis-tooltip-backdrop-filter: none;
|
||||
--vis-tooltip-padding: none;
|
||||
}
|
||||
</style>
|
||||
|
|
|
|||
|
|
@ -1,23 +1,59 @@
|
|||
<script setup lang="ts">
|
||||
<script setup lang="ts" generic="T extends Record<string, any>">
|
||||
import { VisDonut, VisSingleContainer } from '@unovis/vue'
|
||||
import { Donut } from '@unovis/ts'
|
||||
import { computed, ref } from 'vue'
|
||||
import { useMounted } from '@vueuse/core'
|
||||
import { ChartSingleTooltip, defaultColors } from '@/lib/registry/new-york/ui/chart'
|
||||
import { ChartSingleTooltip, defaultColors } from '@/lib/registry/default/ui/chart'
|
||||
import { cn } from '@/lib/utils'
|
||||
|
||||
const props = withDefaults(defineProps<{
|
||||
data: any[]
|
||||
/**
|
||||
* The source data, in which each entry is a dictionary.
|
||||
*/
|
||||
data: T[]
|
||||
/**
|
||||
* Sets the key to map the data to the chart.
|
||||
*/
|
||||
index: string
|
||||
/**
|
||||
* Sets the name of the key containing the quantitative chart values.
|
||||
*/
|
||||
category: string
|
||||
/**
|
||||
* Change the default colors.
|
||||
*/
|
||||
colors?: string[]
|
||||
/**
|
||||
* Change the type of the chart
|
||||
* @default "donut"
|
||||
*/
|
||||
type?: 'donut' | 'pie'
|
||||
/**
|
||||
* Change the opacity of the non-selected field
|
||||
* @default 0.2
|
||||
*/
|
||||
filterOpacity?: number
|
||||
valueFormatter?: (tick: number | Date, i: number, ticks: number[] | Date[]) => string
|
||||
/**
|
||||
* 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
|
||||
/**
|
||||
* Controls the visibility of tooltip.
|
||||
* @default true
|
||||
*/
|
||||
showTooltip?: boolean
|
||||
/**
|
||||
* Controls the visibility of legend.
|
||||
* @default true
|
||||
*/
|
||||
showLegend?: boolean
|
||||
}>(), {
|
||||
colors: () => defaultColors,
|
||||
sortFunction: () => undefined,
|
||||
valueFormatter: (tick: number) => `${tick}`,
|
||||
type: 'donut',
|
||||
filterOpacity: 0.2,
|
||||
showTooltip: true,
|
||||
|
|
@ -27,29 +63,39 @@ const props = withDefaults(defineProps<{
|
|||
type Data = typeof props.data[number]
|
||||
|
||||
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: props.colors[i],
|
||||
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" />
|
||||
<ChartSingleTooltip
|
||||
:selector="Donut.selectors.segment"
|
||||
:index="category"
|
||||
:items="legendItems"
|
||||
:value-formatter="valueFormatter"
|
||||
/>
|
||||
|
||||
<VisDonut
|
||||
:value="(d: Data) => d[category]"
|
||||
:sort-function="(a: Data, b: Data) => (a[category] - b[category])"
|
||||
:sort-function="sortFunction"
|
||||
:color="colors"
|
||||
:arc-width="type === 'donut' ? 20 : 0"
|
||||
:show-background="false"
|
||||
:central-label="valueFormatter(totalValue)"
|
||||
:events="{
|
||||
[Donut.selectors.segment]: {
|
||||
click: (d: any, ev: PointerEvent, i: number, elements: HTMLElement[]) => {
|
||||
click: (d: Data, ev: PointerEvent, i: number, elements: HTMLElement[]) => {
|
||||
if (d?.data?.[index] === activeSegmentKey) {
|
||||
activeSegmentKey = undefined
|
||||
elements.forEach(el => el.style.opacity = '1')
|
||||
|
|
@ -66,14 +112,3 @@ const legendItems = computed(() => props.data.map((item, i) => ({
|
|||
</VisSingleContainer>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<style>
|
||||
:root {
|
||||
--vis-tooltip-background-color: none;
|
||||
--vis-tooltip-border-color: none;
|
||||
--vis-tooltip-text-color: none;
|
||||
--vis-tooltip-shadow-color: none;
|
||||
--vis-tooltip-backdrop-filter: none;
|
||||
--vis-tooltip-padding: none;
|
||||
}
|
||||
</style>
|
||||
|
|
|
|||
|
|
@ -1,27 +1,68 @@
|
|||
<script setup lang="ts">
|
||||
<script setup lang="ts" generic="T extends Record<string, any>">
|
||||
import type { BulletLegendItemInterface } from '@unovis/ts'
|
||||
import { VisAxis, VisLine, VisXYContainer } from '@unovis/vue'
|
||||
import { Axis, Line } from '@unovis/ts'
|
||||
import { ref } from 'vue'
|
||||
import { computed, ref } from 'vue'
|
||||
import { useMounted } from '@vueuse/core'
|
||||
import { ChartCrosshair, ChartLegend, defaultColors } from '@/lib/registry/default/ui/chart'
|
||||
import { cn } from '@/lib/utils'
|
||||
|
||||
const props = withDefaults(defineProps<{
|
||||
data: any[]
|
||||
/**
|
||||
* The source data, in which each entry is a dictionary.
|
||||
*/
|
||||
data: T[]
|
||||
/**
|
||||
* Select the categories from your data. Used to populate the legend and toolip.
|
||||
*/
|
||||
categories: string[]
|
||||
/**
|
||||
* Sets the key to map the data to the axis.
|
||||
*/
|
||||
index: string
|
||||
/**
|
||||
* Change the default colors.
|
||||
*/
|
||||
colors?: string[]
|
||||
/**
|
||||
* Change the opacity of the non-selected field
|
||||
* @default 0.2
|
||||
*/
|
||||
filterOpacity?: number
|
||||
/**
|
||||
* Function to format X label
|
||||
*/
|
||||
xFormatter?: (tick: number | Date, i: number, ticks: number[] | Date[]) => string
|
||||
/**
|
||||
* Function to format Y label
|
||||
*/
|
||||
yFormatter?: (tick: number | Date, i: number, ticks: number[] | Date[]) => string
|
||||
/**
|
||||
* Controls the visibility of the X axis.
|
||||
* @default true
|
||||
*/
|
||||
showXAxis?: boolean
|
||||
/**
|
||||
* Controls the visibility of the Y axis.
|
||||
* @default true
|
||||
*/
|
||||
showYAxis?: boolean
|
||||
/**
|
||||
* Controls the visibility of tooltip.
|
||||
* @default true
|
||||
*/
|
||||
showTooltip?: boolean
|
||||
/**
|
||||
* Controls the visibility of legend.
|
||||
* @default true
|
||||
*/
|
||||
showLegend?: boolean
|
||||
/**
|
||||
* Controls the visibility of gridline.
|
||||
* @default true
|
||||
*/
|
||||
showGridLine?: boolean
|
||||
}>(), {
|
||||
colors: () => defaultColors,
|
||||
filterOpacity: 0.2,
|
||||
showXAxis: true,
|
||||
showYAxis: true,
|
||||
|
|
@ -31,10 +72,11 @@ const props = withDefaults(defineProps<{
|
|||
})
|
||||
|
||||
type Data = typeof props.data[number]
|
||||
const colors = computed(() => props.colors?.length ? props.colors : defaultColors(props.categories.length))
|
||||
|
||||
const legendItems = ref<BulletLegendItemInterface[]>(props.categories.map((category, i) => ({
|
||||
name: category,
|
||||
color: props.colors[i],
|
||||
color: colors.value[i],
|
||||
inactive: false,
|
||||
})))
|
||||
|
||||
|
|
@ -94,14 +136,3 @@ function handleLegendItemClick(d: BulletLegendItemInterface, i: number) {
|
|||
</VisXYContainer>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<style>
|
||||
:root {
|
||||
--vis-tooltip-background-color: none;
|
||||
--vis-tooltip-border-color: none;
|
||||
--vis-tooltip-text-color: none;
|
||||
--vis-tooltip-shadow-color: none;
|
||||
--vis-tooltip-backdrop-filter: none;
|
||||
--vis-tooltip-padding: none;
|
||||
}
|
||||
</style>
|
||||
|
|
|
|||
|
|
@ -3,8 +3,14 @@ export { default as ChartSingleTooltip } from './ChartSingleTooltip.vue'
|
|||
export { default as ChartLegend } from './ChartLegend.vue'
|
||||
export { default as ChartCrosshair } from './ChartCrosshair.vue'
|
||||
|
||||
const COLOR_COUNT = 3
|
||||
export const defaultColors = [
|
||||
...Array.from(Array(COLOR_COUNT).keys()).map(i => `hsl(var(--primary) / ${1 - (1 / COLOR_COUNT) * i})`),
|
||||
...Array.from(Array(COLOR_COUNT).keys()).map(i => `hsl(var(--secondary) / ${1 - (1 / COLOR_COUNT) * i})`),
|
||||
]
|
||||
export function defaultColors(count: number = 3) {
|
||||
const quotient = Math.floor(count / 2)
|
||||
const remainder = count % 2
|
||||
|
||||
const primaryCount = quotient + remainder
|
||||
const secondaryCount = quotient
|
||||
return [
|
||||
...Array.from(Array(primaryCount).keys()).map(i => `hsl(var(--primary) / ${1 - (1 / primaryCount) * i})`),
|
||||
...Array.from(Array(secondaryCount).keys()).map(i => `hsl(var(--border) / ${1 - (1 / secondaryCount) * i})`),
|
||||
]
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,28 +1,73 @@
|
|||
<script setup lang="ts">
|
||||
<script setup lang="ts" generic="T extends Record<string, any>">
|
||||
import type { BulletLegendItemInterface } from '@unovis/ts'
|
||||
import { VisArea, VisAxis, VisLine, VisXYContainer } from '@unovis/vue'
|
||||
import { Area, Axis, Line } from '@unovis/ts'
|
||||
import { ref } from 'vue'
|
||||
import { computed, ref } from 'vue'
|
||||
import { useMounted } from '@vueuse/core'
|
||||
import { ChartCrosshair, ChartLegend, defaultColors } from '@/lib/registry/new-york/ui/chart'
|
||||
import { cn } from '@/lib/utils'
|
||||
|
||||
const props = withDefaults(defineProps<{
|
||||
data: any[]
|
||||
/**
|
||||
* The source data, in which each entry is a dictionary.
|
||||
*/
|
||||
data: T[]
|
||||
/**
|
||||
* Select the categories from your data. Used to populate the legend and toolip.
|
||||
*/
|
||||
categories: string[]
|
||||
/**
|
||||
* Sets the key to map the data to the axis.
|
||||
*/
|
||||
index: string
|
||||
/**
|
||||
* Change the default colors.
|
||||
*/
|
||||
colors?: string[]
|
||||
/**
|
||||
* Change the opacity of the non-selected field
|
||||
* @default 0.2
|
||||
*/
|
||||
filterOpacity?: number
|
||||
/**
|
||||
* Function to format X label
|
||||
*/
|
||||
xFormatter?: (tick: number | Date, i: number, ticks: number[] | Date[]) => string
|
||||
/**
|
||||
* Function to format Y label
|
||||
*/
|
||||
yFormatter?: (tick: number | Date, i: number, ticks: number[] | Date[]) => string
|
||||
/**
|
||||
* Controls the visibility of the X axis.
|
||||
* @default true
|
||||
*/
|
||||
showXAxis?: boolean
|
||||
/**
|
||||
* Controls the visibility of the Y axis.
|
||||
* @default true
|
||||
*/
|
||||
showYAxis?: boolean
|
||||
/**
|
||||
* Controls the visibility of tooltip.
|
||||
* @default true
|
||||
*/
|
||||
showTooltip?: boolean
|
||||
/**
|
||||
* Controls the visibility of legend.
|
||||
* @default true
|
||||
*/
|
||||
showLegend?: boolean
|
||||
/**
|
||||
* Controls the visibility of gridline.
|
||||
* @default true
|
||||
*/
|
||||
showGridLine?: boolean
|
||||
/**
|
||||
* Controls the visibility of gradient.
|
||||
* @default true
|
||||
*/
|
||||
showGradiant?: boolean
|
||||
}>(), {
|
||||
colors: () => defaultColors,
|
||||
filterOpacity: 0.2,
|
||||
showXAxis: true,
|
||||
showYAxis: true,
|
||||
|
|
@ -33,10 +78,11 @@ const props = withDefaults(defineProps<{
|
|||
})
|
||||
|
||||
type Data = typeof props.data[number]
|
||||
const colors = computed(() => props.colors?.length ? props.colors : defaultColors(props.categories.length))
|
||||
|
||||
const legendItems = ref<BulletLegendItemInterface[]>(props.categories.map((category, i) => ({
|
||||
name: category,
|
||||
color: props.colors[i],
|
||||
color: colors.value[i],
|
||||
inactive: false,
|
||||
})))
|
||||
|
||||
|
|
@ -118,14 +164,3 @@ function handleLegendItemClick(d: BulletLegendItemInterface, i: number) {
|
|||
</VisXYContainer>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<style>
|
||||
:root {
|
||||
--vis-tooltip-background-color: none;
|
||||
--vis-tooltip-border-color: none;
|
||||
--vis-tooltip-text-color: none;
|
||||
--vis-tooltip-shadow-color: none;
|
||||
--vis-tooltip-backdrop-filter: none;
|
||||
--vis-tooltip-padding: none;
|
||||
}
|
||||
</style>
|
||||
|
|
|
|||
|
|
@ -8,21 +8,66 @@ import { ChartCrosshair, ChartLegend, defaultColors } from '@/lib/registry/new-y
|
|||
import { cn } from '@/lib/utils'
|
||||
|
||||
const props = withDefaults(defineProps<{
|
||||
/**
|
||||
* The source data, in which each entry is a dictionary.
|
||||
*/
|
||||
data: T[]
|
||||
/**
|
||||
* Select the categories from your data. Used to populate the legend and toolip.
|
||||
*/
|
||||
categories: string[]
|
||||
/**
|
||||
* Sets the key to map the data to the axis.
|
||||
*/
|
||||
index: string
|
||||
/**
|
||||
* Change the default colors.
|
||||
*/
|
||||
colors?: string[]
|
||||
/**
|
||||
* Change the opacity of the non-selected field
|
||||
* @default 0.2
|
||||
*/
|
||||
filterOpacity?: number
|
||||
/**
|
||||
* Change the type of the chart
|
||||
* @default "grouped"
|
||||
*/
|
||||
type?: 'stacked' | 'grouped'
|
||||
/**
|
||||
* Function to format X label
|
||||
*/
|
||||
xFormatter?: (tick: number | Date, i: number, ticks: number[] | Date[]) => string
|
||||
/**
|
||||
* Function to format Y label
|
||||
*/
|
||||
yFormatter?: (tick: number | Date, i: number, ticks: number[] | Date[]) => string
|
||||
/**
|
||||
* Controls the visibility of the X axis.
|
||||
* @default true
|
||||
*/
|
||||
showXAxis?: boolean
|
||||
/**
|
||||
* Controls the visibility of the Y axis.
|
||||
* @default true
|
||||
*/
|
||||
showYAxis?: boolean
|
||||
/**
|
||||
* Controls the visibility of tooltip.
|
||||
* @default true
|
||||
*/
|
||||
showTooltip?: boolean
|
||||
/**
|
||||
* Controls the visibility of legend.
|
||||
* @default true
|
||||
*/
|
||||
showLegend?: boolean
|
||||
/**
|
||||
* Controls the visibility of gridline.
|
||||
* @default true
|
||||
*/
|
||||
showGridLine?: boolean
|
||||
}>(), {
|
||||
colors: () => defaultColors,
|
||||
type: 'grouped',
|
||||
filterOpacity: 0.2,
|
||||
showXAxis: true,
|
||||
|
|
@ -32,9 +77,11 @@ const props = withDefaults(defineProps<{
|
|||
showGridLine: true,
|
||||
})
|
||||
|
||||
type Data = typeof props.data[number]
|
||||
const colors = computed(() => props.colors?.length ? props.colors : defaultColors(props.categories.length))
|
||||
const legendItems = ref<BulletLegendItemInterface[]>(props.categories.map((category, i) => ({
|
||||
name: category,
|
||||
color: props.colors[i],
|
||||
color: colors.value[i],
|
||||
inactive: false,
|
||||
})))
|
||||
|
||||
|
|
@ -56,14 +103,14 @@ const selectorsBar = computed(() => props.type === 'grouped' ? GroupedBar.select
|
|||
<ChartCrosshair v-if="showTooltip" :colors="colors" :items="legendItems" :index="index" />
|
||||
|
||||
<VisBarComponent
|
||||
:x="(d: T, i: number) => i"
|
||||
:y="categories.map(category => (d: T) => d[category]) "
|
||||
:x="(d: Data, i: number) => i"
|
||||
:y="categories.map(category => (d: Data) => d[category]) "
|
||||
:color="colors"
|
||||
:rounded-corners="4"
|
||||
:bar-padding="0.1"
|
||||
:attributes="{
|
||||
[selectorsBar]: {
|
||||
opacity: (d: T, i:number) => {
|
||||
opacity: (d: Data, i:number) => {
|
||||
const pos = i % categories.length
|
||||
return legendItems[pos]?.inactive ? filterOpacity : 1
|
||||
},
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
<script setup lang="ts">
|
||||
<script setup lang="ts" generic="T extends Record<string, any>">
|
||||
import { VisDonut, VisSingleContainer } from '@unovis/vue'
|
||||
import { Donut } from '@unovis/ts'
|
||||
import { computed, ref } from 'vue'
|
||||
|
|
@ -7,18 +7,51 @@ import { ChartSingleTooltip, defaultColors } from '@/lib/registry/new-york/ui/ch
|
|||
import { cn } from '@/lib/utils'
|
||||
|
||||
const props = withDefaults(defineProps<{
|
||||
data: any[]
|
||||
/**
|
||||
* The source data, in which each entry is a dictionary.
|
||||
*/
|
||||
data: T[]
|
||||
/**
|
||||
* Sets the key to map the data to the chart.
|
||||
*/
|
||||
index: string
|
||||
/**
|
||||
* Sets the name of the key containing the quantitative chart values.
|
||||
*/
|
||||
category: string
|
||||
/**
|
||||
* Change the default colors.
|
||||
*/
|
||||
colors?: string[]
|
||||
/**
|
||||
* Change the type of the chart
|
||||
* @default "donut"
|
||||
*/
|
||||
type?: 'donut' | 'pie'
|
||||
/**
|
||||
* Change the opacity of the non-selected field
|
||||
* @default 0.2
|
||||
*/
|
||||
filterOpacity?: number
|
||||
/**
|
||||
* 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
|
||||
/**
|
||||
* Controls the visibility of tooltip.
|
||||
* @default true
|
||||
*/
|
||||
showTooltip?: boolean
|
||||
/**
|
||||
* Controls the visibility of legend.
|
||||
* @default true
|
||||
*/
|
||||
showLegend?: boolean
|
||||
}>(), {
|
||||
colors: () => defaultColors,
|
||||
sortFunction: () => undefined,
|
||||
valueFormatter: (tick: number) => `${tick}`,
|
||||
type: 'donut',
|
||||
|
|
@ -30,11 +63,11 @@ const props = withDefaults(defineProps<{
|
|||
type Data = typeof props.data[number]
|
||||
|
||||
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: props.colors[i],
|
||||
color: colors.value[i],
|
||||
inactive: false,
|
||||
})))
|
||||
|
||||
|
|
@ -62,7 +95,7 @@ const totalValue = computed(() => props.data.reduce((prev, curr) => {
|
|||
:central-label="valueFormatter(totalValue)"
|
||||
:events="{
|
||||
[Donut.selectors.segment]: {
|
||||
click: (d: any, ev: PointerEvent, i: number, elements: HTMLElement[]) => {
|
||||
click: (d: Data, ev: PointerEvent, i: number, elements: HTMLElement[]) => {
|
||||
if (d?.data?.[index] === activeSegmentKey) {
|
||||
activeSegmentKey = undefined
|
||||
elements.forEach(el => el.style.opacity = '1')
|
||||
|
|
@ -79,14 +112,3 @@ const totalValue = computed(() => props.data.reduce((prev, curr) => {
|
|||
</VisSingleContainer>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<style>
|
||||
:root {
|
||||
--vis-tooltip-background-color: none;
|
||||
--vis-tooltip-border-color: none;
|
||||
--vis-tooltip-text-color: none;
|
||||
--vis-tooltip-shadow-color: none;
|
||||
--vis-tooltip-backdrop-filter: none;
|
||||
--vis-tooltip-padding: none;
|
||||
}
|
||||
</style>
|
||||
|
|
|
|||
|
|
@ -1,27 +1,68 @@
|
|||
<script setup lang="ts">
|
||||
<script setup lang="ts" generic="T extends Record<string, any>">
|
||||
import type { BulletLegendItemInterface } from '@unovis/ts'
|
||||
import { VisAxis, VisLine, VisXYContainer } from '@unovis/vue'
|
||||
import { Axis, Line } from '@unovis/ts'
|
||||
import { ref } from 'vue'
|
||||
import { computed, ref } from 'vue'
|
||||
import { useMounted } from '@vueuse/core'
|
||||
import { ChartCrosshair, ChartLegend, defaultColors } from '@/lib/registry/new-york/ui/chart'
|
||||
import { cn } from '@/lib/utils'
|
||||
|
||||
const props = withDefaults(defineProps<{
|
||||
data: any[]
|
||||
/**
|
||||
* The source data, in which each entry is a dictionary.
|
||||
*/
|
||||
data: T[]
|
||||
/**
|
||||
* Select the categories from your data. Used to populate the legend and toolip.
|
||||
*/
|
||||
categories: string[]
|
||||
/**
|
||||
* Sets the key to map the data to the axis.
|
||||
*/
|
||||
index: string
|
||||
/**
|
||||
* Change the default colors.
|
||||
*/
|
||||
colors?: string[]
|
||||
/**
|
||||
* Change the opacity of the non-selected field
|
||||
* @default 0.2
|
||||
*/
|
||||
filterOpacity?: number
|
||||
/**
|
||||
* Function to format X label
|
||||
*/
|
||||
xFormatter?: (tick: number | Date, i: number, ticks: number[] | Date[]) => string
|
||||
/**
|
||||
* Function to format Y label
|
||||
*/
|
||||
yFormatter?: (tick: number | Date, i: number, ticks: number[] | Date[]) => string
|
||||
/**
|
||||
* Controls the visibility of the X axis.
|
||||
* @default true
|
||||
*/
|
||||
showXAxis?: boolean
|
||||
/**
|
||||
* Controls the visibility of the Y axis.
|
||||
* @default true
|
||||
*/
|
||||
showYAxis?: boolean
|
||||
/**
|
||||
* Controls the visibility of tooltip.
|
||||
* @default true
|
||||
*/
|
||||
showTooltip?: boolean
|
||||
/**
|
||||
* Controls the visibility of legend.
|
||||
* @default true
|
||||
*/
|
||||
showLegend?: boolean
|
||||
/**
|
||||
* Controls the visibility of gridline.
|
||||
* @default true
|
||||
*/
|
||||
showGridLine?: boolean
|
||||
}>(), {
|
||||
colors: () => defaultColors,
|
||||
filterOpacity: 0.2,
|
||||
showXAxis: true,
|
||||
showYAxis: true,
|
||||
|
|
@ -31,10 +72,11 @@ const props = withDefaults(defineProps<{
|
|||
})
|
||||
|
||||
type Data = typeof props.data[number]
|
||||
const colors = computed(() => props.colors?.length ? props.colors : defaultColors(props.categories.length))
|
||||
|
||||
const legendItems = ref<BulletLegendItemInterface[]>(props.categories.map((category, i) => ({
|
||||
name: category,
|
||||
color: props.colors[i],
|
||||
color: colors.value[i],
|
||||
inactive: false,
|
||||
})))
|
||||
|
||||
|
|
@ -94,14 +136,3 @@ function handleLegendItemClick(d: BulletLegendItemInterface, i: number) {
|
|||
</VisXYContainer>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<style>
|
||||
:root {
|
||||
--vis-tooltip-background-color: none;
|
||||
--vis-tooltip-border-color: none;
|
||||
--vis-tooltip-text-color: none;
|
||||
--vis-tooltip-shadow-color: none;
|
||||
--vis-tooltip-backdrop-filter: none;
|
||||
--vis-tooltip-padding: none;
|
||||
}
|
||||
</style>
|
||||
|
|
|
|||
|
|
@ -38,14 +38,3 @@ defineProps<{
|
|||
</CardContent>
|
||||
</Card>
|
||||
</template>
|
||||
|
||||
<style>
|
||||
:root {
|
||||
--vis-tooltip-background-color: none;
|
||||
--vis-tooltip-border-color: none;
|
||||
--vis-tooltip-text-color: none;
|
||||
--vis-tooltip-shadow-color: none;
|
||||
--vis-tooltip-backdrop-filter: none;
|
||||
--vis-tooltip-padding: none;
|
||||
}
|
||||
</style>
|
||||
|
|
|
|||
|
|
@ -3,8 +3,14 @@ export { default as ChartSingleTooltip } from './ChartSingleTooltip.vue'
|
|||
export { default as ChartLegend } from './ChartLegend.vue'
|
||||
export { default as ChartCrosshair } from './ChartCrosshair.vue'
|
||||
|
||||
const COLOR_COUNT = 3
|
||||
export const defaultColors = [
|
||||
...Array.from(Array(COLOR_COUNT).keys()).map(i => `hsl(var(--primary) / ${1 - (1 / COLOR_COUNT) * i})`),
|
||||
...Array.from(Array(COLOR_COUNT).keys()).map(i => `hsl(var(--secondary) / ${1 - (1 / COLOR_COUNT) * i})`),
|
||||
]
|
||||
export function defaultColors(count: number = 3) {
|
||||
const quotient = Math.floor(count / 2)
|
||||
const remainder = count % 2
|
||||
|
||||
const primaryCount = quotient + remainder
|
||||
const secondaryCount = quotient
|
||||
return [
|
||||
...Array.from(Array(primaryCount).keys()).map(i => `hsl(var(--primary) / ${1 - (1 / primaryCount) * i})`),
|
||||
...Array.from(Array(secondaryCount).keys()).map(i => `hsl(var(--border) / ${1 - (1 / secondaryCount) * i})`),
|
||||
]
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in New Issue
Block a user