feat: add more props
This commit is contained in:
parent
bfccb78a4f
commit
91c7d0fbd0
|
|
@ -8,7 +8,6 @@ const data = [
|
||||||
{ name: 'Apr', total: Math.floor(Math.random() * 2000) + 500, predicted: Math.floor(Math.random() * 2000) + 500 },
|
{ name: 'Apr', total: Math.floor(Math.random() * 2000) + 500, predicted: Math.floor(Math.random() * 2000) + 500 },
|
||||||
{ name: 'May', total: Math.floor(Math.random() * 2000) + 500, predicted: Math.floor(Math.random() * 2000) + 500 },
|
{ name: 'May', total: Math.floor(Math.random() * 2000) + 500, predicted: Math.floor(Math.random() * 2000) + 500 },
|
||||||
{ name: 'Jun', total: Math.floor(Math.random() * 2000) + 500, predicted: Math.floor(Math.random() * 2000) + 500 },
|
{ name: 'Jun', total: Math.floor(Math.random() * 2000) + 500, predicted: Math.floor(Math.random() * 2000) + 500 },
|
||||||
{ name: 'Jul', total: Math.floor(Math.random() * 2000) + 500, predicted: Math.floor(Math.random() * 2000) + 500 },
|
|
||||||
]
|
]
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -96,7 +96,6 @@ function handleLegendItemClick(d: BulletLegendItemInterface, i: number) {
|
||||||
<VisAxis
|
<VisAxis
|
||||||
v-if="showXAxis"
|
v-if="showXAxis"
|
||||||
type="x"
|
type="x"
|
||||||
:num-ticks="data.length"
|
|
||||||
:tick-format="xFormatter ?? ((v: number) => data[v]?.[index])"
|
:tick-format="xFormatter ?? ((v: number) => data[v]?.[index])"
|
||||||
:grid-line="false"
|
:grid-line="false"
|
||||||
:tick-line="false"
|
:tick-line="false"
|
||||||
|
|
@ -105,7 +104,6 @@ function handleLegendItemClick(d: BulletLegendItemInterface, i: number) {
|
||||||
<VisAxis
|
<VisAxis
|
||||||
v-if="showYAxis"
|
v-if="showYAxis"
|
||||||
type="y"
|
type="y"
|
||||||
:num-ticks="data.length"
|
|
||||||
:tick-line="false"
|
:tick-line="false"
|
||||||
:tick-format="yFormatter"
|
:tick-format="yFormatter"
|
||||||
:domain-line="false"
|
:domain-line="false"
|
||||||
|
|
|
||||||
|
|
@ -76,7 +76,6 @@ const selectorsBar = computed(() => props.type === 'grouped' ? GroupedBar.select
|
||||||
<VisAxis
|
<VisAxis
|
||||||
v-if="showXAxis"
|
v-if="showXAxis"
|
||||||
type="x"
|
type="x"
|
||||||
:num-ticks="data.length"
|
|
||||||
:tick-format="xFormatter ?? ((v: number) => data[v]?.[index])"
|
:tick-format="xFormatter ?? ((v: number) => data[v]?.[index])"
|
||||||
:grid-line="false"
|
:grid-line="false"
|
||||||
:tick-line="false"
|
:tick-line="false"
|
||||||
|
|
@ -85,7 +84,6 @@ const selectorsBar = computed(() => props.type === 'grouped' ? GroupedBar.select
|
||||||
<VisAxis
|
<VisAxis
|
||||||
v-if="showYAxis"
|
v-if="showYAxis"
|
||||||
type="y"
|
type="y"
|
||||||
:num-ticks="data.length"
|
|
||||||
:tick-line="false"
|
:tick-line="false"
|
||||||
:tick-format="yFormatter"
|
:tick-format="yFormatter"
|
||||||
:domain-line="false"
|
:domain-line="false"
|
||||||
|
|
|
||||||
|
|
@ -4,7 +4,7 @@ import { VisAxis, VisLine, VisXYContainer } from '@unovis/vue'
|
||||||
import { Axis, Line } from '@unovis/ts'
|
import { Axis, Line } from '@unovis/ts'
|
||||||
import { ref } from 'vue'
|
import { ref } from 'vue'
|
||||||
import { useMounted } from '@vueuse/core'
|
import { useMounted } from '@vueuse/core'
|
||||||
import { ChartCrosshair, ChartLegend, defaultColors } from '@/lib/registry/new-york/ui/chart'
|
import { ChartCrosshair, ChartLegend, defaultColors } from '@/lib/registry/default/ui/chart'
|
||||||
import { cn } from '@/lib/utils'
|
import { cn } from '@/lib/utils'
|
||||||
|
|
||||||
const props = withDefaults(defineProps<{
|
const props = withDefaults(defineProps<{
|
||||||
|
|
@ -49,7 +49,11 @@ function handleLegendItemClick(d: BulletLegendItemInterface, i: number) {
|
||||||
<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" @legend-item-click="handleLegendItemClick" />
|
||||||
|
|
||||||
<VisXYContainer :style="{ height: isMounted ? '100%' : 'auto' }" :margin="{ left: 20, right: 20 }" :data="data">
|
<VisXYContainer
|
||||||
|
:margin="{ left: 20, right: 20 }"
|
||||||
|
:data="data"
|
||||||
|
: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" />
|
||||||
|
|
||||||
<template v-for="(category, i) in categories" :key="category">
|
<template v-for="(category, i) in categories" :key="category">
|
||||||
|
|
@ -68,7 +72,6 @@ function handleLegendItemClick(d: BulletLegendItemInterface, i: number) {
|
||||||
<VisAxis
|
<VisAxis
|
||||||
v-if="showXAxis"
|
v-if="showXAxis"
|
||||||
type="x"
|
type="x"
|
||||||
:num-ticks="data.length"
|
|
||||||
:tick-format="xFormatter ?? ((v: number) => data[v]?.[index])"
|
:tick-format="xFormatter ?? ((v: number) => data[v]?.[index])"
|
||||||
:grid-line="false"
|
:grid-line="false"
|
||||||
:tick-line="false"
|
:tick-line="false"
|
||||||
|
|
@ -77,7 +80,6 @@ function handleLegendItemClick(d: BulletLegendItemInterface, i: number) {
|
||||||
<VisAxis
|
<VisAxis
|
||||||
v-if="showYAxis"
|
v-if="showYAxis"
|
||||||
type="y"
|
type="y"
|
||||||
:num-ticks="data.length"
|
|
||||||
:tick-line="false"
|
:tick-line="false"
|
||||||
:tick-format="yFormatter"
|
:tick-format="yFormatter"
|
||||||
:domain-line="false"
|
:domain-line="false"
|
||||||
|
|
|
||||||
|
|
@ -9,7 +9,10 @@ const props = withDefaults(defineProps<{
|
||||||
selector: string
|
selector: string
|
||||||
index: string
|
index: string
|
||||||
items?: BulletLegendItemInterface[]
|
items?: BulletLegendItemInterface[]
|
||||||
}>(), {})
|
valueFormatter?: (tick: number, i?: number, ticks?: number[]) => string
|
||||||
|
}>(), {
|
||||||
|
valueFormatter: (tick: number) => `${tick}`,
|
||||||
|
})
|
||||||
|
|
||||||
// Use weakmap to store reference to each datapoint for Tooltip
|
// Use weakmap to store reference to each datapoint for Tooltip
|
||||||
const wm = new WeakMap()
|
const wm = new WeakMap()
|
||||||
|
|
@ -22,7 +25,7 @@ function template(d: any, i: number, elements: (HTMLElement | SVGElement)[]) {
|
||||||
const componentDiv = document.createElement('div')
|
const componentDiv = document.createElement('div')
|
||||||
const omittedData = Object.entries(omit(d, [props.index])).map(([key, value]) => {
|
const omittedData = Object.entries(omit(d, [props.index])).map(([key, value]) => {
|
||||||
const legendReference = props.items?.find(i => i.name === key)
|
const legendReference = props.items?.find(i => i.name === key)
|
||||||
return { ...legendReference, value }
|
return { ...legendReference, value: props.valueFormatter(value) }
|
||||||
})
|
})
|
||||||
createApp(ChartTooltip, { title: d[props.index], data: omittedData }).mount(componentDiv)
|
createApp(ChartTooltip, { title: d[props.index], data: omittedData }).mount(componentDiv)
|
||||||
wm.set(d, componentDiv.innerHTML)
|
wm.set(d, componentDiv.innerHTML)
|
||||||
|
|
@ -37,7 +40,7 @@ function template(d: any, i: number, elements: (HTMLElement | SVGElement)[]) {
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
const style = getComputedStyle(elements[i])
|
const style = getComputedStyle(elements[i])
|
||||||
const omittedData = [{ name: data.name, value: 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)
|
createApp(ChartTooltip, { title: d[props.index], data: omittedData }).mount(componentDiv)
|
||||||
wm.set(d, componentDiv.innerHTML)
|
wm.set(d, componentDiv.innerHTML)
|
||||||
|
|
|
||||||
|
|
@ -8,8 +8,9 @@ const data = [
|
||||||
{ name: 'Apr', total: Math.floor(Math.random() * 2000) + 500, predicted: Math.floor(Math.random() * 2000) + 500 },
|
{ name: 'Apr', total: Math.floor(Math.random() * 2000) + 500, predicted: Math.floor(Math.random() * 2000) + 500 },
|
||||||
{ name: 'May', total: Math.floor(Math.random() * 2000) + 500, predicted: Math.floor(Math.random() * 2000) + 500 },
|
{ name: 'May', total: Math.floor(Math.random() * 2000) + 500, predicted: Math.floor(Math.random() * 2000) + 500 },
|
||||||
{ name: 'Jun', total: Math.floor(Math.random() * 2000) + 500, predicted: Math.floor(Math.random() * 2000) + 500 },
|
{ name: 'Jun', total: Math.floor(Math.random() * 2000) + 500, predicted: Math.floor(Math.random() * 2000) + 500 },
|
||||||
{ name: 'Jul', total: Math.floor(Math.random() * 2000) + 500, predicted: Math.floor(Math.random() * 2000) + 500 },
|
|
||||||
]
|
]
|
||||||
|
|
||||||
|
const valueFormatter = (tick: number | Date) => typeof tick === 'number' ? `$ ${new Intl.NumberFormat('us').format(tick).toString()}` : ''
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
|
|
@ -17,5 +18,6 @@ const data = [
|
||||||
index="name"
|
index="name"
|
||||||
:category="'total'"
|
:category="'total'"
|
||||||
:data="data"
|
:data="data"
|
||||||
|
:value-formatter="valueFormatter"
|
||||||
/>
|
/>
|
||||||
</template>
|
</template>
|
||||||
|
|
|
||||||
|
|
@ -2,22 +2,275 @@
|
||||||
import { LineChart } from '@/lib/registry/new-york/ui/chart-line'
|
import { LineChart } from '@/lib/registry/new-york/ui/chart-line'
|
||||||
|
|
||||||
const data = [
|
const data = [
|
||||||
{ name: 'Jan', total: Math.floor(Math.random() * 2000) + 500 },
|
{
|
||||||
{ name: 'Feb', total: Math.floor(Math.random() * 2000) + 500 },
|
'year': 1970,
|
||||||
{ name: 'Mar', total: Math.floor(Math.random() * 2000) + 500 },
|
'Export Growth Rate': 2.04,
|
||||||
{ name: 'Apr', total: Math.floor(Math.random() * 2000) + 500 },
|
'Import Growth Rate': 1.53,
|
||||||
{ name: 'May', total: Math.floor(Math.random() * 2000) + 500 },
|
},
|
||||||
{ name: 'Jun', total: Math.floor(Math.random() * 2000) + 500 },
|
{
|
||||||
{ name: 'Jul', total: Math.floor(Math.random() * 2000) + 500 },
|
'year': 1971,
|
||||||
|
'Export Growth Rate': 1.96,
|
||||||
|
'Import Growth Rate': 1.58,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
'year': 1972,
|
||||||
|
'Export Growth Rate': 1.96,
|
||||||
|
'Import Growth Rate': 1.61,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
'year': 1973,
|
||||||
|
'Export Growth Rate': 1.93,
|
||||||
|
'Import Growth Rate': 1.61,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
'year': 1974,
|
||||||
|
'Export Growth Rate': 1.88,
|
||||||
|
'Import Growth Rate': 1.67,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
'year': 1975,
|
||||||
|
'Export Growth Rate': 1.79,
|
||||||
|
'Import Growth Rate': 1.64,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
'year': 1976,
|
||||||
|
'Export Growth Rate': 1.77,
|
||||||
|
'Import Growth Rate': 1.62,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
'year': 1977,
|
||||||
|
'Export Growth Rate': 1.74,
|
||||||
|
'Import Growth Rate': 1.69,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
'year': 1978,
|
||||||
|
'Export Growth Rate': 1.74,
|
||||||
|
'Import Growth Rate': 1.7,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
'year': 1979,
|
||||||
|
'Export Growth Rate': 1.77,
|
||||||
|
'Import Growth Rate': 1.67,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
'year': 1980,
|
||||||
|
'Export Growth Rate': 1.79,
|
||||||
|
'Import Growth Rate': 1.7,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
'year': 1981,
|
||||||
|
'Export Growth Rate': 1.81,
|
||||||
|
'Import Growth Rate': 1.72,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
'year': 1982,
|
||||||
|
'Export Growth Rate': 1.84,
|
||||||
|
'Import Growth Rate': 1.73,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
'year': 1983,
|
||||||
|
'Export Growth Rate': 1.77,
|
||||||
|
'Import Growth Rate': 1.73,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
'year': 1984,
|
||||||
|
'Export Growth Rate': 1.78,
|
||||||
|
'Import Growth Rate': 1.78,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
'year': 1985,
|
||||||
|
'Export Growth Rate': 1.78,
|
||||||
|
'Import Growth Rate': 1.81,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
'year': 1986,
|
||||||
|
'Export Growth Rate': 1.82,
|
||||||
|
'Import Growth Rate': 1.89,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
'year': 1987,
|
||||||
|
'Export Growth Rate': 1.82,
|
||||||
|
'Import Growth Rate': 1.91,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
'year': 1988,
|
||||||
|
'Export Growth Rate': 1.77,
|
||||||
|
'Import Growth Rate': 1.94,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
'year': 1989,
|
||||||
|
'Export Growth Rate': 1.76,
|
||||||
|
'Import Growth Rate': 1.94,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
'year': 1990,
|
||||||
|
'Export Growth Rate': 1.75,
|
||||||
|
'Import Growth Rate': 1.97,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
'year': 1991,
|
||||||
|
'Export Growth Rate': 1.62,
|
||||||
|
'Import Growth Rate': 1.99,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
'year': 1992,
|
||||||
|
'Export Growth Rate': 1.56,
|
||||||
|
'Import Growth Rate': 2.12,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
'year': 1993,
|
||||||
|
'Export Growth Rate': 1.5,
|
||||||
|
'Import Growth Rate': 2.13,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
'year': 1994,
|
||||||
|
'Export Growth Rate': 1.46,
|
||||||
|
'Import Growth Rate': 2.15,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
'year': 1995,
|
||||||
|
'Export Growth Rate': 1.43,
|
||||||
|
'Import Growth Rate': 2.17,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
'year': 1996,
|
||||||
|
'Export Growth Rate': 1.4,
|
||||||
|
'Import Growth Rate': 2.2,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
'year': 1997,
|
||||||
|
'Export Growth Rate': 1.37,
|
||||||
|
'Import Growth Rate': 2.15,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
'year': 1998,
|
||||||
|
'Export Growth Rate': 1.34,
|
||||||
|
'Import Growth Rate': 2.07,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
'year': 1999,
|
||||||
|
'Export Growth Rate': 1.32,
|
||||||
|
'Import Growth Rate': 2.05,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
'year': 2000,
|
||||||
|
'Export Growth Rate': 1.33,
|
||||||
|
'Import Growth Rate': 2.07,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
'year': 2001,
|
||||||
|
'Export Growth Rate': 1.31,
|
||||||
|
'Import Growth Rate': 2.08,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
'year': 2002,
|
||||||
|
'Export Growth Rate': 1.29,
|
||||||
|
'Import Growth Rate': 2.1,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
'year': 2003,
|
||||||
|
'Export Growth Rate': 1.27,
|
||||||
|
'Import Growth Rate': 2.15,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
'year': 2004,
|
||||||
|
'Export Growth Rate': 1.27,
|
||||||
|
'Import Growth Rate': 2.21,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
'year': 2005,
|
||||||
|
'Export Growth Rate': 1.26,
|
||||||
|
'Import Growth Rate': 2.23,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
'year': 2006,
|
||||||
|
'Export Growth Rate': 1.26,
|
||||||
|
'Import Growth Rate': 2.29,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
'year': 2007,
|
||||||
|
'Export Growth Rate': 1.27,
|
||||||
|
'Import Growth Rate': 2.34,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
'year': 2008,
|
||||||
|
'Export Growth Rate': 1.26,
|
||||||
|
'Import Growth Rate': 2.36,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
'year': 2009,
|
||||||
|
'Export Growth Rate': 1.26,
|
||||||
|
'Import Growth Rate': 2.36,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
'year': 2010,
|
||||||
|
'Export Growth Rate': 1.25,
|
||||||
|
'Import Growth Rate': 2.35,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
'year': 2011,
|
||||||
|
'Export Growth Rate': 1.24,
|
||||||
|
'Import Growth Rate': 2.34,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
'year': 2012,
|
||||||
|
'Export Growth Rate': 1.25,
|
||||||
|
'Import Growth Rate': 2.39,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
'year': 2013,
|
||||||
|
'Export Growth Rate': 1.22,
|
||||||
|
'Import Growth Rate': 2.3,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
'year': 2014,
|
||||||
|
'Export Growth Rate': 1.2,
|
||||||
|
'Import Growth Rate': 2.35,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
'year': 2015,
|
||||||
|
'Export Growth Rate': 1.17,
|
||||||
|
'Import Growth Rate': 2.39,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
'year': 2016,
|
||||||
|
'Export Growth Rate': 1.16,
|
||||||
|
'Import Growth Rate': 2.41,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
'year': 2017,
|
||||||
|
'Export Growth Rate': 1.13,
|
||||||
|
'Import Growth Rate': 2.44,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
'year': 2018,
|
||||||
|
'Export Growth Rate': 1.07,
|
||||||
|
'Import Growth Rate': 2.45,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
'year': 2019,
|
||||||
|
'Export Growth Rate': 1.03,
|
||||||
|
'Import Growth Rate': 2.47,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
'year': 2020,
|
||||||
|
'Export Growth Rate': 0.92,
|
||||||
|
'Import Growth Rate': 2.48,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
'year': 2021,
|
||||||
|
'Export Growth Rate': 0.82,
|
||||||
|
'Import Growth Rate': 2.51,
|
||||||
|
},
|
||||||
]
|
]
|
||||||
|
|
||||||
const categories = ['total']
|
const categories = ['Export Growth Rate', 'Import Growth Rate']
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
<LineChart
|
<LineChart
|
||||||
:data="data"
|
:data="data"
|
||||||
index="name"
|
index="year"
|
||||||
:categories="categories"
|
:categories="categories"
|
||||||
:y-formatter="(tick, i) => {
|
:y-formatter="(tick, i) => {
|
||||||
return typeof tick === 'number'
|
return typeof tick === 'number'
|
||||||
|
|
|
||||||
|
|
@ -96,7 +96,6 @@ function handleLegendItemClick(d: BulletLegendItemInterface, i: number) {
|
||||||
<VisAxis
|
<VisAxis
|
||||||
v-if="showXAxis"
|
v-if="showXAxis"
|
||||||
type="x"
|
type="x"
|
||||||
:num-ticks="data.length"
|
|
||||||
:tick-format="xFormatter ?? ((v: number) => data[v]?.[index])"
|
:tick-format="xFormatter ?? ((v: number) => data[v]?.[index])"
|
||||||
:grid-line="false"
|
:grid-line="false"
|
||||||
:tick-line="false"
|
:tick-line="false"
|
||||||
|
|
@ -105,7 +104,6 @@ function handleLegendItemClick(d: BulletLegendItemInterface, i: number) {
|
||||||
<VisAxis
|
<VisAxis
|
||||||
v-if="showYAxis"
|
v-if="showYAxis"
|
||||||
type="y"
|
type="y"
|
||||||
:num-ticks="data.length"
|
|
||||||
:tick-line="false"
|
:tick-line="false"
|
||||||
:tick-format="yFormatter"
|
:tick-format="yFormatter"
|
||||||
:domain-line="false"
|
:domain-line="false"
|
||||||
|
|
|
||||||
|
|
@ -76,7 +76,6 @@ const selectorsBar = computed(() => props.type === 'grouped' ? GroupedBar.select
|
||||||
<VisAxis
|
<VisAxis
|
||||||
v-if="showXAxis"
|
v-if="showXAxis"
|
||||||
type="x"
|
type="x"
|
||||||
:num-ticks="data.length"
|
|
||||||
:tick-format="xFormatter ?? ((v: number) => data[v]?.[index])"
|
:tick-format="xFormatter ?? ((v: number) => data[v]?.[index])"
|
||||||
:grid-line="false"
|
:grid-line="false"
|
||||||
:tick-line="false"
|
:tick-line="false"
|
||||||
|
|
@ -85,7 +84,6 @@ const selectorsBar = computed(() => props.type === 'grouped' ? GroupedBar.select
|
||||||
<VisAxis
|
<VisAxis
|
||||||
v-if="showYAxis"
|
v-if="showYAxis"
|
||||||
type="y"
|
type="y"
|
||||||
:num-ticks="data.length"
|
|
||||||
:tick-line="false"
|
:tick-line="false"
|
||||||
:tick-format="yFormatter"
|
:tick-format="yFormatter"
|
||||||
:domain-line="false"
|
:domain-line="false"
|
||||||
|
|
|
||||||
|
|
@ -13,11 +13,14 @@ const props = withDefaults(defineProps<{
|
||||||
colors?: string[]
|
colors?: string[]
|
||||||
type?: 'donut' | 'pie'
|
type?: 'donut' | 'pie'
|
||||||
filterOpacity?: number
|
filterOpacity?: number
|
||||||
valueFormatter?: (tick: number | Date, i: number, ticks: number[] | Date[]) => string
|
sortFunction?: (a: any, b: any) => number | undefined
|
||||||
|
valueFormatter?: (tick: number, i?: number, ticks?: number[]) => string
|
||||||
showTooltip?: boolean
|
showTooltip?: boolean
|
||||||
showLegend?: boolean
|
showLegend?: boolean
|
||||||
}>(), {
|
}>(), {
|
||||||
colors: () => defaultColors,
|
colors: () => defaultColors,
|
||||||
|
sortFunction: () => undefined,
|
||||||
|
valueFormatter: (tick: number) => `${tick}`,
|
||||||
type: 'donut',
|
type: 'donut',
|
||||||
filterOpacity: 0.2,
|
filterOpacity: 0.2,
|
||||||
showTooltip: true,
|
showTooltip: true,
|
||||||
|
|
@ -34,19 +37,29 @@ const legendItems = computed(() => props.data.map((item, i) => ({
|
||||||
color: props.colors[i],
|
color: props.colors[i],
|
||||||
inactive: false,
|
inactive: false,
|
||||||
})))
|
})))
|
||||||
|
|
||||||
|
const totalValue = computed(() => props.data.reduce((prev, curr) => {
|
||||||
|
return prev + curr[props.category]
|
||||||
|
}, 0))
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
<div :class="cn('w-full h-48 flex flex-col items-end', $attrs.class ?? '')">
|
<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">
|
<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
|
<VisDonut
|
||||||
:value="(d: Data) => d[category]"
|
:value="(d: Data) => d[category]"
|
||||||
:sort-function="(a: Data, b: Data) => (a[category] - b[category])"
|
:sort-function="sortFunction"
|
||||||
:color="colors"
|
:color="colors"
|
||||||
:arc-width="type === 'donut' ? 20 : 0"
|
:arc-width="type === 'donut' ? 20 : 0"
|
||||||
:show-background="false"
|
:show-background="false"
|
||||||
|
:central-label="valueFormatter(totalValue)"
|
||||||
:events="{
|
:events="{
|
||||||
[Donut.selectors.segment]: {
|
[Donut.selectors.segment]: {
|
||||||
click: (d: any, ev: PointerEvent, i: number, elements: HTMLElement[]) => {
|
click: (d: any, ev: PointerEvent, i: number, elements: HTMLElement[]) => {
|
||||||
|
|
|
||||||
|
|
@ -49,7 +49,11 @@ function handleLegendItemClick(d: BulletLegendItemInterface, i: number) {
|
||||||
<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" @legend-item-click="handleLegendItemClick" />
|
||||||
|
|
||||||
<VisXYContainer :style="{ height: isMounted ? '100%' : 'auto' }" :margin="{ left: 20, right: 20 }" :data="data">
|
<VisXYContainer
|
||||||
|
:margin="{ left: 20, right: 20 }"
|
||||||
|
:data="data"
|
||||||
|
: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" />
|
||||||
|
|
||||||
<template v-for="(category, i) in categories" :key="category">
|
<template v-for="(category, i) in categories" :key="category">
|
||||||
|
|
@ -68,7 +72,6 @@ function handleLegendItemClick(d: BulletLegendItemInterface, i: number) {
|
||||||
<VisAxis
|
<VisAxis
|
||||||
v-if="showXAxis"
|
v-if="showXAxis"
|
||||||
type="x"
|
type="x"
|
||||||
:num-ticks="data.length"
|
|
||||||
:tick-format="xFormatter ?? ((v: number) => data[v]?.[index])"
|
:tick-format="xFormatter ?? ((v: number) => data[v]?.[index])"
|
||||||
:grid-line="false"
|
:grid-line="false"
|
||||||
:tick-line="false"
|
:tick-line="false"
|
||||||
|
|
@ -77,7 +80,6 @@ function handleLegendItemClick(d: BulletLegendItemInterface, i: number) {
|
||||||
<VisAxis
|
<VisAxis
|
||||||
v-if="showYAxis"
|
v-if="showYAxis"
|
||||||
type="y"
|
type="y"
|
||||||
:num-ticks="data.length"
|
|
||||||
:tick-line="false"
|
:tick-line="false"
|
||||||
:tick-format="yFormatter"
|
:tick-format="yFormatter"
|
||||||
:domain-line="false"
|
:domain-line="false"
|
||||||
|
|
|
||||||
|
|
@ -9,7 +9,10 @@ const props = withDefaults(defineProps<{
|
||||||
selector: string
|
selector: string
|
||||||
index: string
|
index: string
|
||||||
items?: BulletLegendItemInterface[]
|
items?: BulletLegendItemInterface[]
|
||||||
}>(), {})
|
valueFormatter?: (tick: number, i?: number, ticks?: number[]) => string
|
||||||
|
}>(), {
|
||||||
|
valueFormatter: (tick: number) => `${tick}`,
|
||||||
|
})
|
||||||
|
|
||||||
// Use weakmap to store reference to each datapoint for Tooltip
|
// Use weakmap to store reference to each datapoint for Tooltip
|
||||||
const wm = new WeakMap()
|
const wm = new WeakMap()
|
||||||
|
|
@ -22,7 +25,7 @@ function template(d: any, i: number, elements: (HTMLElement | SVGElement)[]) {
|
||||||
const componentDiv = document.createElement('div')
|
const componentDiv = document.createElement('div')
|
||||||
const omittedData = Object.entries(omit(d, [props.index])).map(([key, value]) => {
|
const omittedData = Object.entries(omit(d, [props.index])).map(([key, value]) => {
|
||||||
const legendReference = props.items?.find(i => i.name === key)
|
const legendReference = props.items?.find(i => i.name === key)
|
||||||
return { ...legendReference, value }
|
return { ...legendReference, value: props.valueFormatter(value) }
|
||||||
})
|
})
|
||||||
createApp(ChartTooltip, { title: d[props.index], data: omittedData }).mount(componentDiv)
|
createApp(ChartTooltip, { title: d[props.index], data: omittedData }).mount(componentDiv)
|
||||||
wm.set(d, componentDiv.innerHTML)
|
wm.set(d, componentDiv.innerHTML)
|
||||||
|
|
@ -37,7 +40,7 @@ function template(d: any, i: number, elements: (HTMLElement | SVGElement)[]) {
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
const style = getComputedStyle(elements[i])
|
const style = getComputedStyle(elements[i])
|
||||||
const omittedData = [{ name: data.name, value: 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)
|
createApp(ChartTooltip, { title: d[props.index], data: omittedData }).mount(componentDiv)
|
||||||
wm.set(d, componentDiv.innerHTML)
|
wm.set(d, componentDiv.innerHTML)
|
||||||
|
|
|
||||||
|
|
@ -3,4 +3,8 @@ export { default as ChartSingleTooltip } from './ChartSingleTooltip.vue'
|
||||||
export { default as ChartLegend } from './ChartLegend.vue'
|
export { default as ChartLegend } from './ChartLegend.vue'
|
||||||
export { default as ChartCrosshair } from './ChartCrosshair.vue'
|
export { default as ChartCrosshair } from './ChartCrosshair.vue'
|
||||||
|
|
||||||
export const defaultColors = ['hsl(var(--primary))', 'hsl(var(--muted))']
|
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})`),
|
||||||
|
]
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue
Block a user