chore: add feature
This commit is contained in:
parent
1f6398f8d1
commit
4159f56616
|
|
@ -41,3 +41,36 @@ Add the following tooltip styling to your `tailwind.css` file:
|
||||||
```
|
```
|
||||||
|
|
||||||
</Steps>
|
</Steps>
|
||||||
|
|
||||||
|
## Colors
|
||||||
|
|
||||||
|
By default, we construct the primary theme color, and secondary (`--vis-secondary-color`) color with different opacity for the graph.
|
||||||
|
|
||||||
|
However, you can always pass in the desired `color` into each chart.
|
||||||
|
|
||||||
|
```vue
|
||||||
|
<template>
|
||||||
|
<AreaChart
|
||||||
|
:data="data"
|
||||||
|
:colors="['blue', 'pink', 'orange', 'red']"
|
||||||
|
/>
|
||||||
|
</template>
|
||||||
|
```
|
||||||
|
|
||||||
|
## Custom tooltip
|
||||||
|
|
||||||
|
If you want to customize the `Tooltip` for the chart, you can pass `customTooltip` prop with a custom Vue component.
|
||||||
|
The custom component would receive `title` and `data` props, check out [ChartTooltip.vue component](https://github.com/radix-vue/shadcn-vue/tree/dev/apps/www/src/lib/registry/default/ui/chart/ChartTooltip.vue) for example.
|
||||||
|
|
||||||
|
The expecting prop definition would be
|
||||||
|
|
||||||
|
```ts
|
||||||
|
defineProps<{
|
||||||
|
title?: string
|
||||||
|
data: {
|
||||||
|
name: string
|
||||||
|
color: string
|
||||||
|
value: any
|
||||||
|
}[]
|
||||||
|
}>()
|
||||||
|
```
|
||||||
|
|
|
||||||
|
|
@ -1,19 +1,28 @@
|
||||||
<script setup lang="ts" generic="T extends Record<string, any>">
|
<script setup lang="ts" generic="T extends Record<string, any>">
|
||||||
import type { BulletLegendItemInterface } from '@unovis/ts'
|
import { type BulletLegendItemInterface, CurveType } from '@unovis/ts'
|
||||||
import { VisArea, VisAxis, VisLine, VisXYContainer } from '@unovis/vue'
|
import { VisArea, VisAxis, VisLine, VisXYContainer } from '@unovis/vue'
|
||||||
import { Area, Axis, Line } from '@unovis/ts'
|
import { Area, Axis, Line } from '@unovis/ts'
|
||||||
import { computed, ref } from 'vue'
|
import { type Component, computed, ref } from 'vue'
|
||||||
import { useMounted } from '@vueuse/core'
|
import { useMounted } from '@vueuse/core'
|
||||||
import { type BaseChartProps, ChartCrosshair, ChartLegend, defaultColors } from '@/lib/registry/default/ui/chart'
|
import { type BaseChartProps, ChartCrosshair, ChartLegend, defaultColors } from '@/lib/registry/default/ui/chart'
|
||||||
import { cn } from '@/lib/utils'
|
import { cn } from '@/lib/utils'
|
||||||
|
|
||||||
const props = withDefaults(defineProps<BaseChartProps<T> & {
|
const props = withDefaults(defineProps<BaseChartProps<T> & {
|
||||||
|
/**
|
||||||
|
* Render custom tooltip component.
|
||||||
|
*/
|
||||||
|
customTooltip?: Component
|
||||||
|
/**
|
||||||
|
* Type of curve
|
||||||
|
*/
|
||||||
|
curveType?: CurveType
|
||||||
/**
|
/**
|
||||||
* Controls the visibility of gradient.
|
* Controls the visibility of gradient.
|
||||||
* @default true
|
* @default true
|
||||||
*/
|
*/
|
||||||
showGradiant?: boolean
|
showGradiant?: boolean
|
||||||
}>(), {
|
}>(), {
|
||||||
|
curveType: CurveType.Basis,
|
||||||
filterOpacity: 0.2,
|
filterOpacity: 0.2,
|
||||||
margin: () => ({ top: 0, bottom: 0, left: 0, right: 0 }),
|
margin: () => ({ top: 0, bottom: 0, left: 0, right: 0 }),
|
||||||
showXAxis: true,
|
showXAxis: true,
|
||||||
|
|
@ -66,13 +75,14 @@ function handleLegendItemClick(d: BulletLegendItemInterface, i: number) {
|
||||||
</defs>
|
</defs>
|
||||||
</svg>
|
</svg>
|
||||||
|
|
||||||
<ChartCrosshair v-if="showTooltip" :colors="colors" :items="legendItems" :index="index" />
|
<ChartCrosshair v-if="showTooltip" :colors="colors" :items="legendItems" :index="index" :custom-tooltip="customTooltip" />
|
||||||
|
|
||||||
<template v-for="(category, i) in categories" :key="category">
|
<template v-for="(category, i) in categories" :key="category">
|
||||||
<VisArea
|
<VisArea
|
||||||
:x="(d: Data, i: number) => i"
|
:x="(d: Data, i: number) => i"
|
||||||
:y="(d: Data) => d[category]"
|
:y="(d: Data) => d[category]"
|
||||||
color="auto"
|
color="auto"
|
||||||
|
:curve-type="curveType"
|
||||||
:attributes="{
|
:attributes="{
|
||||||
[Area.selectors.area]: {
|
[Area.selectors.area]: {
|
||||||
fill: `url(#color-${i})`,
|
fill: `url(#color-${i})`,
|
||||||
|
|
@ -87,6 +97,7 @@ function handleLegendItemClick(d: BulletLegendItemInterface, i: number) {
|
||||||
:x="(d: Data, i: number) => i"
|
:x="(d: Data, i: number) => i"
|
||||||
:y="(d: Data) => d[category]"
|
:y="(d: Data) => d[category]"
|
||||||
:color="colors[i]"
|
:color="colors[i]"
|
||||||
|
:curve-type="curveType"
|
||||||
:attributes="{
|
:attributes="{
|
||||||
[Line.selectors.line]: {
|
[Line.selectors.line]: {
|
||||||
opacity: legendItems.find(item => item.name === category)?.inactive ? filterOpacity : 1,
|
opacity: legendItems.find(item => item.name === category)?.inactive ? filterOpacity : 1,
|
||||||
|
|
|
||||||
|
|
@ -2,12 +2,16 @@
|
||||||
import type { BulletLegendItemInterface, Spacing } from '@unovis/ts'
|
import type { BulletLegendItemInterface, Spacing } from '@unovis/ts'
|
||||||
import { VisAxis, VisGroupedBar, VisStackedBar, VisXYContainer } from '@unovis/vue'
|
import { VisAxis, VisGroupedBar, VisStackedBar, VisXYContainer } from '@unovis/vue'
|
||||||
import { Axis, GroupedBar, StackedBar } from '@unovis/ts'
|
import { Axis, GroupedBar, StackedBar } from '@unovis/ts'
|
||||||
import { computed, ref } from 'vue'
|
import { type Component, computed, ref } from 'vue'
|
||||||
import { useMounted } from '@vueuse/core'
|
import { useMounted } from '@vueuse/core'
|
||||||
import { type BaseChartProps, ChartCrosshair, ChartLegend, defaultColors } from '@/lib/registry/default/ui/chart'
|
import { type BaseChartProps, ChartCrosshair, ChartLegend, defaultColors } from '@/lib/registry/default/ui/chart'
|
||||||
import { cn } from '@/lib/utils'
|
import { cn } from '@/lib/utils'
|
||||||
|
|
||||||
const props = withDefaults(defineProps<BaseChartProps<T> & {
|
const props = withDefaults(defineProps<BaseChartProps<T> & {
|
||||||
|
/**
|
||||||
|
* Render custom tooltip component.
|
||||||
|
*/
|
||||||
|
customTooltip?: Component
|
||||||
/**
|
/**
|
||||||
* Change the type of the chart
|
* Change the type of the chart
|
||||||
* @default "grouped"
|
* @default "grouped"
|
||||||
|
|
@ -57,7 +61,7 @@ const selectorsBar = computed(() => props.type === 'grouped' ? GroupedBar.select
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
<div :class="cn('w-full h-[400px] flex flex-col items-end', $attrs.class ?? '')">
|
<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" />
|
<ChartLegend v-if="showLegend" v-model:items="legendItems" :custom-tooltip="customTooltip" @legend-item-click="handleLegendItemClick" />
|
||||||
|
|
||||||
<VisXYContainer
|
<VisXYContainer
|
||||||
:data="data"
|
:data="data"
|
||||||
|
|
|
||||||
|
|
@ -1,7 +1,7 @@
|
||||||
<script setup lang="ts" generic="T extends Record<string, any>">
|
<script setup lang="ts" generic="T extends Record<string, any>">
|
||||||
import { VisDonut, VisSingleContainer } from '@unovis/vue'
|
import { VisDonut, VisSingleContainer } from '@unovis/vue'
|
||||||
import { Donut } from '@unovis/ts'
|
import { Donut } from '@unovis/ts'
|
||||||
import { computed, ref } from 'vue'
|
import { type DefineComponent, computed, ref } from 'vue'
|
||||||
import { useMounted } from '@vueuse/core'
|
import { useMounted } from '@vueuse/core'
|
||||||
import { type BaseChartProps, ChartSingleTooltip, defaultColors } from '@/lib/registry/default/ui/chart'
|
import { type BaseChartProps, ChartSingleTooltip, defaultColors } from '@/lib/registry/default/ui/chart'
|
||||||
import { cn } from '@/lib/utils'
|
import { cn } from '@/lib/utils'
|
||||||
|
|
@ -24,7 +24,10 @@ const props = withDefaults(defineProps<Pick<BaseChartProps<T>, 'data' | 'colors'
|
||||||
* Controls the formatting for the label.
|
* Controls the formatting for the label.
|
||||||
*/
|
*/
|
||||||
valueFormatter?: (tick: number, i?: number, ticks?: number[]) => string
|
valueFormatter?: (tick: number, i?: number, ticks?: number[]) => string
|
||||||
|
/**
|
||||||
|
* Render custom tooltip component.
|
||||||
|
*/
|
||||||
|
customTooltip?: DefineComponent
|
||||||
}>(), {
|
}>(), {
|
||||||
margin: () => ({ top: 0, bottom: 0, left: 0, right: 0 }),
|
margin: () => ({ top: 0, bottom: 0, left: 0, right: 0 }),
|
||||||
sortFunction: () => undefined,
|
sortFunction: () => undefined,
|
||||||
|
|
@ -63,6 +66,7 @@ const totalValue = computed(() => props.data.reduce((prev, curr) => {
|
||||||
:index="category"
|
:index="category"
|
||||||
:items="legendItems"
|
:items="legendItems"
|
||||||
:value-formatter="valueFormatter"
|
:value-formatter="valueFormatter"
|
||||||
|
:custom-tooltip="customTooltip"
|
||||||
/>
|
/>
|
||||||
|
|
||||||
<VisDonut
|
<VisDonut
|
||||||
|
|
|
||||||
|
|
@ -1,13 +1,23 @@
|
||||||
<script setup lang="ts" generic="T extends Record<string, any>">
|
<script setup lang="ts" generic="T extends Record<string, any>">
|
||||||
import type { BulletLegendItemInterface } from '@unovis/ts'
|
import { type BulletLegendItemInterface, CurveType } from '@unovis/ts'
|
||||||
import { VisAxis, VisLine, VisXYContainer } from '@unovis/vue'
|
import { VisAxis, VisLine, VisXYContainer } from '@unovis/vue'
|
||||||
import { Axis, Line } from '@unovis/ts'
|
import { Axis, Line } from '@unovis/ts'
|
||||||
import { computed, ref } from 'vue'
|
import { type Component, computed, ref } from 'vue'
|
||||||
import { useMounted } from '@vueuse/core'
|
import { useMounted } from '@vueuse/core'
|
||||||
import { type BaseChartProps, ChartCrosshair, ChartLegend, defaultColors } from '@/lib/registry/default/ui/chart'
|
import { type BaseChartProps, ChartCrosshair, ChartLegend, defaultColors } from '@/lib/registry/default/ui/chart'
|
||||||
import { cn } from '@/lib/utils'
|
import { cn } from '@/lib/utils'
|
||||||
|
|
||||||
const props = withDefaults(defineProps<BaseChartProps<T>>(), {
|
const props = withDefaults(defineProps<BaseChartProps<T> & {
|
||||||
|
/**
|
||||||
|
* Render custom tooltip component.
|
||||||
|
*/
|
||||||
|
customTooltip?: Component
|
||||||
|
/**
|
||||||
|
* Type of curve
|
||||||
|
*/
|
||||||
|
curveType?: CurveType
|
||||||
|
}>(), {
|
||||||
|
curveType: CurveType.Basis,
|
||||||
filterOpacity: 0.2,
|
filterOpacity: 0.2,
|
||||||
margin: () => ({ top: 0, bottom: 0, left: 0, right: 0 }),
|
margin: () => ({ top: 0, bottom: 0, left: 0, right: 0 }),
|
||||||
showXAxis: true,
|
showXAxis: true,
|
||||||
|
|
@ -49,12 +59,13 @@ function handleLegendItemClick(d: BulletLegendItemInterface, i: number) {
|
||||||
:data="data"
|
:data="data"
|
||||||
:style="{ height: isMounted ? '100%' : 'auto' }"
|
:style="{ height: isMounted ? '100%' : 'auto' }"
|
||||||
>
|
>
|
||||||
<ChartCrosshair v-if="showTooltip" :colors="colors" :items="legendItems" :index="index" />
|
<ChartCrosshair v-if="showTooltip" :colors="colors" :items="legendItems" :index="index" :custom-tooltip="customTooltip" />
|
||||||
|
|
||||||
<template v-for="(category, i) in categories" :key="category">
|
<template v-for="(category, i) in categories" :key="category">
|
||||||
<VisLine
|
<VisLine
|
||||||
:x="(d: Data, i: number) => i"
|
:x="(d: Data, i: number) => i"
|
||||||
:y="(d: Data) => d[category]"
|
:y="(d: Data) => d[category]"
|
||||||
|
:curve-type="curveType"
|
||||||
:color="colors[i]"
|
:color="colors[i]"
|
||||||
:attributes="{
|
:attributes="{
|
||||||
[Line.selectors.line]: {
|
[Line.selectors.line]: {
|
||||||
|
|
|
||||||
|
|
@ -2,13 +2,14 @@
|
||||||
import { VisCrosshair, VisTooltip } from '@unovis/vue'
|
import { VisCrosshair, VisTooltip } from '@unovis/vue'
|
||||||
import type { BulletLegendItemInterface } from '@unovis/ts'
|
import type { BulletLegendItemInterface } from '@unovis/ts'
|
||||||
import { omit } from '@unovis/ts'
|
import { omit } from '@unovis/ts'
|
||||||
import { createApp, watch } from 'vue'
|
import { type Component, createApp } from 'vue'
|
||||||
import { ChartTooltip } from '@/lib/registry/default/ui/chart'
|
import { ChartTooltip } from '@/lib/registry/default/ui/chart'
|
||||||
|
|
||||||
const props = withDefaults(defineProps<{
|
const props = withDefaults(defineProps<{
|
||||||
colors: string[]
|
colors: string[]
|
||||||
index: string
|
index: string
|
||||||
items: BulletLegendItemInterface[]
|
items: BulletLegendItemInterface[]
|
||||||
|
customTooltip?: Component
|
||||||
}>(), {
|
}>(), {
|
||||||
colors: () => [],
|
colors: () => [],
|
||||||
})
|
})
|
||||||
|
|
@ -25,7 +26,8 @@ function template(d: any) {
|
||||||
const legendReference = props.items.find(i => i.name === key)
|
const legendReference = props.items.find(i => i.name === key)
|
||||||
return { ...legendReference, value }
|
return { ...legendReference, value }
|
||||||
})
|
})
|
||||||
createApp(ChartTooltip, { title: d[props.index].toString(), data: omittedData }).mount(componentDiv)
|
const TooltipComponent = props.customTooltip ?? ChartTooltip
|
||||||
|
createApp(TooltipComponent, { title: d[props.index].toString(), data: omittedData }).mount(componentDiv)
|
||||||
wm.set(d, componentDiv.innerHTML)
|
wm.set(d, componentDiv.innerHTML)
|
||||||
return componentDiv.innerHTML
|
return componentDiv.innerHTML
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -2,7 +2,7 @@
|
||||||
import { VisTooltip } from '@unovis/vue'
|
import { VisTooltip } from '@unovis/vue'
|
||||||
import type { BulletLegendItemInterface } from '@unovis/ts'
|
import type { BulletLegendItemInterface } from '@unovis/ts'
|
||||||
import { omit } from '@unovis/ts'
|
import { omit } from '@unovis/ts'
|
||||||
import { createApp } from 'vue'
|
import { type Component, createApp } from 'vue'
|
||||||
import { ChartTooltip } from '@/lib/registry/default/ui/chart'
|
import { ChartTooltip } from '@/lib/registry/default/ui/chart'
|
||||||
|
|
||||||
const props = withDefaults(defineProps<{
|
const props = withDefaults(defineProps<{
|
||||||
|
|
@ -10,6 +10,7 @@ const props = withDefaults(defineProps<{
|
||||||
index: string
|
index: string
|
||||||
items?: BulletLegendItemInterface[]
|
items?: BulletLegendItemInterface[]
|
||||||
valueFormatter?: (tick: number, i?: number, ticks?: number[]) => string
|
valueFormatter?: (tick: number, i?: number, ticks?: number[]) => string
|
||||||
|
customTooltip?: Component
|
||||||
}>(), {
|
}>(), {
|
||||||
valueFormatter: (tick: number) => `${tick}`,
|
valueFormatter: (tick: number) => `${tick}`,
|
||||||
})
|
})
|
||||||
|
|
@ -27,11 +28,13 @@ function template(d: any, i: number, elements: (HTMLElement | SVGElement)[]) {
|
||||||
const legendReference = props.items?.find(i => i.name === key)
|
const legendReference = props.items?.find(i => i.name === key)
|
||||||
return { ...legendReference, value: props.valueFormatter(value) }
|
return { ...legendReference, value: props.valueFormatter(value) }
|
||||||
})
|
})
|
||||||
createApp(ChartTooltip, { title: d[props.index], data: omittedData }).mount(componentDiv)
|
const TooltipComponent = props.customTooltip ?? ChartTooltip
|
||||||
|
createApp(TooltipComponent, { title: d[props.index], data: omittedData }).mount(componentDiv)
|
||||||
wm.set(d, componentDiv.innerHTML)
|
wm.set(d, componentDiv.innerHTML)
|
||||||
return componentDiv.innerHTML
|
return componentDiv.innerHTML
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
else {
|
else {
|
||||||
const data = d.data
|
const data = d.data
|
||||||
|
|
||||||
|
|
@ -42,7 +45,8 @@ function template(d: any, i: number, elements: (HTMLElement | SVGElement)[]) {
|
||||||
const style = getComputedStyle(elements[i])
|
const style = getComputedStyle(elements[i])
|
||||||
const omittedData = [{ name: data.name, value: props.valueFormatter(data[props.index]), color: style.fill }]
|
const omittedData = [{ name: data.name, value: props.valueFormatter(data[props.index]), color: style.fill }]
|
||||||
const componentDiv = document.createElement('div')
|
const componentDiv = document.createElement('div')
|
||||||
createApp(ChartTooltip, { title: d[props.index], data: omittedData }).mount(componentDiv)
|
const TooltipComponent = props.customTooltip ?? ChartTooltip
|
||||||
|
createApp(TooltipComponent, { title: d[props.index], data: omittedData }).mount(componentDiv)
|
||||||
wm.set(d, componentDiv.innerHTML)
|
wm.set(d, componentDiv.innerHTML)
|
||||||
return componentDiv.innerHTML
|
return componentDiv.innerHTML
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,19 +1,28 @@
|
||||||
<script setup lang="ts" generic="T extends Record<string, any>">
|
<script setup lang="ts" generic="T extends Record<string, any>">
|
||||||
import type { BulletLegendItemInterface, Spacing } from '@unovis/ts'
|
import { type BulletLegendItemInterface, CurveType } from '@unovis/ts'
|
||||||
import { VisArea, VisAxis, VisLine, VisXYContainer } from '@unovis/vue'
|
import { VisArea, VisAxis, VisLine, VisXYContainer } from '@unovis/vue'
|
||||||
import { Area, Axis, Line } from '@unovis/ts'
|
import { Area, Axis, Line } from '@unovis/ts'
|
||||||
import { computed, ref } from 'vue'
|
import { type Component, computed, ref } from 'vue'
|
||||||
import { useMounted } from '@vueuse/core'
|
import { useMounted } from '@vueuse/core'
|
||||||
import { type BaseChartProps, ChartCrosshair, ChartLegend, defaultColors } from '@/lib/registry/new-york/ui/chart'
|
import { type BaseChartProps, ChartCrosshair, ChartLegend, defaultColors } from '@/lib/registry/new-york/ui/chart'
|
||||||
import { cn } from '@/lib/utils'
|
import { cn } from '@/lib/utils'
|
||||||
|
|
||||||
const props = withDefaults(defineProps<BaseChartProps<T> & {
|
const props = withDefaults(defineProps<BaseChartProps<T> & {
|
||||||
|
/**
|
||||||
|
* Render custom tooltip component.
|
||||||
|
*/
|
||||||
|
customTooltip?: Component
|
||||||
|
/**
|
||||||
|
* Type of curve
|
||||||
|
*/
|
||||||
|
curveType?: CurveType
|
||||||
/**
|
/**
|
||||||
* Controls the visibility of gradient.
|
* Controls the visibility of gradient.
|
||||||
* @default true
|
* @default true
|
||||||
*/
|
*/
|
||||||
showGradiant?: boolean
|
showGradiant?: boolean
|
||||||
}>(), {
|
}>(), {
|
||||||
|
curveType: CurveType.Basis,
|
||||||
filterOpacity: 0.2,
|
filterOpacity: 0.2,
|
||||||
margin: () => ({ top: 0, bottom: 0, left: 0, right: 0 }),
|
margin: () => ({ top: 0, bottom: 0, left: 0, right: 0 }),
|
||||||
showXAxis: true,
|
showXAxis: true,
|
||||||
|
|
@ -66,13 +75,14 @@ function handleLegendItemClick(d: BulletLegendItemInterface, i: number) {
|
||||||
</defs>
|
</defs>
|
||||||
</svg>
|
</svg>
|
||||||
|
|
||||||
<ChartCrosshair v-if="showTooltip" :colors="colors" :items="legendItems" :index="index" />
|
<ChartCrosshair v-if="showTooltip" :colors="colors" :items="legendItems" :index="index" :custom-tooltip="customTooltip" />
|
||||||
|
|
||||||
<template v-for="(category, i) in categories" :key="category">
|
<template v-for="(category, i) in categories" :key="category">
|
||||||
<VisArea
|
<VisArea
|
||||||
:x="(d: Data, i: number) => i"
|
:x="(d: Data, i: number) => i"
|
||||||
:y="(d: Data) => d[category]"
|
:y="(d: Data) => d[category]"
|
||||||
color="auto"
|
color="auto"
|
||||||
|
:curve-type="curveType"
|
||||||
:attributes="{
|
:attributes="{
|
||||||
[Area.selectors.area]: {
|
[Area.selectors.area]: {
|
||||||
fill: `url(#color-${i})`,
|
fill: `url(#color-${i})`,
|
||||||
|
|
@ -87,6 +97,7 @@ function handleLegendItemClick(d: BulletLegendItemInterface, i: number) {
|
||||||
:x="(d: Data, i: number) => i"
|
:x="(d: Data, i: number) => i"
|
||||||
:y="(d: Data) => d[category]"
|
:y="(d: Data) => d[category]"
|
||||||
:color="colors[i]"
|
:color="colors[i]"
|
||||||
|
:curve-type="curveType"
|
||||||
:attributes="{
|
:attributes="{
|
||||||
[Line.selectors.line]: {
|
[Line.selectors.line]: {
|
||||||
opacity: legendItems.find(item => item.name === category)?.inactive ? filterOpacity : 1,
|
opacity: legendItems.find(item => item.name === category)?.inactive ? filterOpacity : 1,
|
||||||
|
|
|
||||||
|
|
@ -2,12 +2,16 @@
|
||||||
import type { BulletLegendItemInterface, Spacing } from '@unovis/ts'
|
import type { BulletLegendItemInterface, Spacing } from '@unovis/ts'
|
||||||
import { VisAxis, VisGroupedBar, VisStackedBar, VisXYContainer } from '@unovis/vue'
|
import { VisAxis, VisGroupedBar, VisStackedBar, VisXYContainer } from '@unovis/vue'
|
||||||
import { Axis, GroupedBar, StackedBar } from '@unovis/ts'
|
import { Axis, GroupedBar, StackedBar } from '@unovis/ts'
|
||||||
import { computed, ref } from 'vue'
|
import { type Component, computed, ref } from 'vue'
|
||||||
import { useMounted } from '@vueuse/core'
|
import { useMounted } from '@vueuse/core'
|
||||||
import { type BaseChartProps, ChartCrosshair, ChartLegend, defaultColors } from '@/lib/registry/new-york/ui/chart'
|
import { type BaseChartProps, ChartCrosshair, ChartLegend, defaultColors } from '@/lib/registry/new-york/ui/chart'
|
||||||
import { cn } from '@/lib/utils'
|
import { cn } from '@/lib/utils'
|
||||||
|
|
||||||
const props = withDefaults(defineProps<BaseChartProps<T> & {
|
const props = withDefaults(defineProps<BaseChartProps<T> & {
|
||||||
|
/**
|
||||||
|
* Render custom tooltip component.
|
||||||
|
*/
|
||||||
|
customTooltip?: Component
|
||||||
/**
|
/**
|
||||||
* Change the type of the chart
|
* Change the type of the chart
|
||||||
* @default "grouped"
|
* @default "grouped"
|
||||||
|
|
@ -57,7 +61,7 @@ const selectorsBar = computed(() => props.type === 'grouped' ? GroupedBar.select
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
<div :class="cn('w-full h-[400px] flex flex-col items-end', $attrs.class ?? '')">
|
<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" />
|
<ChartLegend v-if="showLegend" v-model:items="legendItems" :custom-tooltip="customTooltip" @legend-item-click="handleLegendItemClick" />
|
||||||
|
|
||||||
<VisXYContainer
|
<VisXYContainer
|
||||||
:data="data"
|
:data="data"
|
||||||
|
|
|
||||||
|
|
@ -1,7 +1,7 @@
|
||||||
<script setup lang="ts" generic="T extends Record<string, any>">
|
<script setup lang="ts" generic="T extends Record<string, any>">
|
||||||
import { VisDonut, VisSingleContainer } from '@unovis/vue'
|
import { VisDonut, VisSingleContainer } from '@unovis/vue'
|
||||||
import { Donut, type Spacing } from '@unovis/ts'
|
import { Donut } from '@unovis/ts'
|
||||||
import { computed, ref } from 'vue'
|
import { type DefineComponent, computed, ref } from 'vue'
|
||||||
import { useMounted } from '@vueuse/core'
|
import { useMounted } from '@vueuse/core'
|
||||||
import { type BaseChartProps, ChartSingleTooltip, defaultColors } from '@/lib/registry/new-york/ui/chart'
|
import { type BaseChartProps, ChartSingleTooltip, defaultColors } from '@/lib/registry/new-york/ui/chart'
|
||||||
import { cn } from '@/lib/utils'
|
import { cn } from '@/lib/utils'
|
||||||
|
|
@ -24,7 +24,10 @@ const props = withDefaults(defineProps<Pick<BaseChartProps<T>, 'data' | 'colors'
|
||||||
* Controls the formatting for the label.
|
* Controls the formatting for the label.
|
||||||
*/
|
*/
|
||||||
valueFormatter?: (tick: number, i?: number, ticks?: number[]) => string
|
valueFormatter?: (tick: number, i?: number, ticks?: number[]) => string
|
||||||
|
/**
|
||||||
|
* Render custom tooltip component.
|
||||||
|
*/
|
||||||
|
customTooltip?: DefineComponent
|
||||||
}>(), {
|
}>(), {
|
||||||
margin: () => ({ top: 0, bottom: 0, left: 0, right: 0 }),
|
margin: () => ({ top: 0, bottom: 0, left: 0, right: 0 }),
|
||||||
sortFunction: () => undefined,
|
sortFunction: () => undefined,
|
||||||
|
|
@ -63,6 +66,7 @@ const totalValue = computed(() => props.data.reduce((prev, curr) => {
|
||||||
:index="category"
|
:index="category"
|
||||||
:items="legendItems"
|
:items="legendItems"
|
||||||
:value-formatter="valueFormatter"
|
:value-formatter="valueFormatter"
|
||||||
|
:custom-tooltip="customTooltip"
|
||||||
/>
|
/>
|
||||||
|
|
||||||
<VisDonut
|
<VisDonut
|
||||||
|
|
@ -75,7 +79,6 @@ const totalValue = computed(() => props.data.reduce((prev, curr) => {
|
||||||
:events="{
|
:events="{
|
||||||
[Donut.selectors.segment]: {
|
[Donut.selectors.segment]: {
|
||||||
click: (d: Data, ev: PointerEvent, i: number, elements: HTMLElement[]) => {
|
click: (d: Data, ev: PointerEvent, i: number, elements: HTMLElement[]) => {
|
||||||
console.log(d, ev, i, elements)
|
|
||||||
if (d?.data?.[index] === activeSegmentKey) {
|
if (d?.data?.[index] === activeSegmentKey) {
|
||||||
activeSegmentKey = undefined
|
activeSegmentKey = undefined
|
||||||
elements.forEach(el => el.style.opacity = '1')
|
elements.forEach(el => el.style.opacity = '1')
|
||||||
|
|
|
||||||
|
|
@ -1,12 +1,23 @@
|
||||||
<script setup lang="ts" generic="T extends Record<string, any>">
|
<script setup lang="ts" generic="T extends Record<string, any>">
|
||||||
import { Axis, type BulletLegendItemInterface, Line, type Spacing } from '@unovis/ts'
|
import { type BulletLegendItemInterface, CurveType } from '@unovis/ts'
|
||||||
import { VisAxis, VisLine, VisXYContainer } from '@unovis/vue'
|
import { VisAxis, VisLine, VisXYContainer } from '@unovis/vue'
|
||||||
import { computed, ref } from 'vue'
|
import { Axis, Line } from '@unovis/ts'
|
||||||
|
import { type Component, computed, ref } from 'vue'
|
||||||
import { useMounted } from '@vueuse/core'
|
import { useMounted } from '@vueuse/core'
|
||||||
import { type BaseChartProps, ChartCrosshair, ChartLegend, defaultColors } from '@/lib/registry/new-york/ui/chart'
|
import { type BaseChartProps, ChartCrosshair, ChartLegend, defaultColors } from '@/lib/registry/new-york/ui/chart'
|
||||||
import { cn } from '@/lib/utils'
|
import { cn } from '@/lib/utils'
|
||||||
|
|
||||||
const props = withDefaults(defineProps<BaseChartProps<T>>(), {
|
const props = withDefaults(defineProps<BaseChartProps<T> & {
|
||||||
|
/**
|
||||||
|
* Render custom tooltip component.
|
||||||
|
*/
|
||||||
|
customTooltip?: Component
|
||||||
|
/**
|
||||||
|
* Type of curve
|
||||||
|
*/
|
||||||
|
curveType?: CurveType
|
||||||
|
}>(), {
|
||||||
|
curveType: CurveType.Basis,
|
||||||
filterOpacity: 0.2,
|
filterOpacity: 0.2,
|
||||||
margin: () => ({ top: 0, bottom: 0, left: 0, right: 0 }),
|
margin: () => ({ top: 0, bottom: 0, left: 0, right: 0 }),
|
||||||
showXAxis: true,
|
showXAxis: true,
|
||||||
|
|
@ -44,16 +55,17 @@ function handleLegendItemClick(d: BulletLegendItemInterface, i: number) {
|
||||||
<ChartLegend v-if="showLegend" v-model:items="legendItems" @legend-item-click="handleLegendItemClick" />
|
<ChartLegend v-if="showLegend" v-model:items="legendItems" @legend-item-click="handleLegendItemClick" />
|
||||||
|
|
||||||
<VisXYContainer
|
<VisXYContainer
|
||||||
:margin="margin"
|
:margin="{ left: 20, right: 20 }"
|
||||||
:data="data"
|
:data="data"
|
||||||
:style="{ height: isMounted ? '100%' : 'auto' }"
|
:style="{ height: isMounted ? '100%' : 'auto' }"
|
||||||
>
|
>
|
||||||
<ChartCrosshair v-if="showTooltip" :colors="colors" :items="legendItems" :index="index" />
|
<ChartCrosshair v-if="showTooltip" :colors="colors" :items="legendItems" :index="index" :custom-tooltip="customTooltip" />
|
||||||
|
|
||||||
<template v-for="(category, i) in categories" :key="category">
|
<template v-for="(category, i) in categories" :key="category">
|
||||||
<VisLine
|
<VisLine
|
||||||
:x="(d: Data, i: number) => i"
|
:x="(d: Data, i: number) => i"
|
||||||
:y="(d: Data) => d[category]"
|
:y="(d: Data) => d[category]"
|
||||||
|
:curve-type="curveType"
|
||||||
:color="colors[i]"
|
:color="colors[i]"
|
||||||
:attributes="{
|
:attributes="{
|
||||||
[Line.selectors.line]: {
|
[Line.selectors.line]: {
|
||||||
|
|
|
||||||
|
|
@ -2,13 +2,14 @@
|
||||||
import { VisCrosshair, VisTooltip } from '@unovis/vue'
|
import { VisCrosshair, VisTooltip } from '@unovis/vue'
|
||||||
import type { BulletLegendItemInterface } from '@unovis/ts'
|
import type { BulletLegendItemInterface } from '@unovis/ts'
|
||||||
import { omit } from '@unovis/ts'
|
import { omit } from '@unovis/ts'
|
||||||
import { createApp, watch } from 'vue'
|
import { type Component, createApp } from 'vue'
|
||||||
import { ChartTooltip } from '@/lib/registry/new-york/ui/chart'
|
import { ChartTooltip } from '@/lib/registry/new-york/ui/chart'
|
||||||
|
|
||||||
const props = withDefaults(defineProps<{
|
const props = withDefaults(defineProps<{
|
||||||
colors: string[]
|
colors: string[]
|
||||||
index: string
|
index: string
|
||||||
items: BulletLegendItemInterface[]
|
items: BulletLegendItemInterface[]
|
||||||
|
customTooltip?: Component
|
||||||
}>(), {
|
}>(), {
|
||||||
colors: () => [],
|
colors: () => [],
|
||||||
})
|
})
|
||||||
|
|
@ -25,7 +26,8 @@ function template(d: any) {
|
||||||
const legendReference = props.items.find(i => i.name === key)
|
const legendReference = props.items.find(i => i.name === key)
|
||||||
return { ...legendReference, value }
|
return { ...legendReference, value }
|
||||||
})
|
})
|
||||||
createApp(ChartTooltip, { title: d[props.index].toString(), data: omittedData }).mount(componentDiv)
|
const TooltipComponent = props.customTooltip ?? ChartTooltip
|
||||||
|
createApp(TooltipComponent, { title: d[props.index].toString(), data: omittedData }).mount(componentDiv)
|
||||||
wm.set(d, componentDiv.innerHTML)
|
wm.set(d, componentDiv.innerHTML)
|
||||||
return componentDiv.innerHTML
|
return componentDiv.innerHTML
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -2,7 +2,7 @@
|
||||||
import { VisTooltip } from '@unovis/vue'
|
import { VisTooltip } from '@unovis/vue'
|
||||||
import type { BulletLegendItemInterface } from '@unovis/ts'
|
import type { BulletLegendItemInterface } from '@unovis/ts'
|
||||||
import { omit } from '@unovis/ts'
|
import { omit } from '@unovis/ts'
|
||||||
import { createApp } from 'vue'
|
import { type Component, createApp } from 'vue'
|
||||||
import { ChartTooltip } from '@/lib/registry/new-york/ui/chart'
|
import { ChartTooltip } from '@/lib/registry/new-york/ui/chart'
|
||||||
|
|
||||||
const props = withDefaults(defineProps<{
|
const props = withDefaults(defineProps<{
|
||||||
|
|
@ -10,6 +10,7 @@ const props = withDefaults(defineProps<{
|
||||||
index: string
|
index: string
|
||||||
items?: BulletLegendItemInterface[]
|
items?: BulletLegendItemInterface[]
|
||||||
valueFormatter?: (tick: number, i?: number, ticks?: number[]) => string
|
valueFormatter?: (tick: number, i?: number, ticks?: number[]) => string
|
||||||
|
customTooltip?: Component
|
||||||
}>(), {
|
}>(), {
|
||||||
valueFormatter: (tick: number) => `${tick}`,
|
valueFormatter: (tick: number) => `${tick}`,
|
||||||
})
|
})
|
||||||
|
|
@ -27,11 +28,13 @@ function template(d: any, i: number, elements: (HTMLElement | SVGElement)[]) {
|
||||||
const legendReference = props.items?.find(i => i.name === key)
|
const legendReference = props.items?.find(i => i.name === key)
|
||||||
return { ...legendReference, value: props.valueFormatter(value) }
|
return { ...legendReference, value: props.valueFormatter(value) }
|
||||||
})
|
})
|
||||||
createApp(ChartTooltip, { title: d[props.index], data: omittedData }).mount(componentDiv)
|
const TooltipComponent = props.customTooltip ?? ChartTooltip
|
||||||
|
createApp(TooltipComponent, { title: d[props.index], data: omittedData }).mount(componentDiv)
|
||||||
wm.set(d, componentDiv.innerHTML)
|
wm.set(d, componentDiv.innerHTML)
|
||||||
return componentDiv.innerHTML
|
return componentDiv.innerHTML
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
else {
|
else {
|
||||||
const data = d.data
|
const data = d.data
|
||||||
|
|
||||||
|
|
@ -42,7 +45,8 @@ function template(d: any, i: number, elements: (HTMLElement | SVGElement)[]) {
|
||||||
const style = getComputedStyle(elements[i])
|
const style = getComputedStyle(elements[i])
|
||||||
const omittedData = [{ name: data.name, value: props.valueFormatter(data[props.index]), color: style.fill }]
|
const omittedData = [{ name: data.name, value: props.valueFormatter(data[props.index]), color: style.fill }]
|
||||||
const componentDiv = document.createElement('div')
|
const componentDiv = document.createElement('div')
|
||||||
createApp(ChartTooltip, { title: d[props.index], data: omittedData }).mount(componentDiv)
|
const TooltipComponent = props.customTooltip ?? ChartTooltip
|
||||||
|
createApp(TooltipComponent, { title: d[props.index], data: omittedData }).mount(componentDiv)
|
||||||
wm.set(d, componentDiv.innerHTML)
|
wm.set(d, componentDiv.innerHTML)
|
||||||
return componentDiv.innerHTML
|
return componentDiv.innerHTML
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue
Block a user