shadcn-vue/apps/www/src/public/registry/styles/default/chart.json
2024-04-26 00:37:50 +08:00

40 lines
9.1 KiB
JSON

{
"name": "chart",
"dependencies": [
"@unovis/vue",
"@unovis/ts"
],
"registryDependencies": [
"chart",
"button",
"card"
],
"files": [
{
"name": "ChartCrosshair.vue",
"content": "<script setup lang=\"ts\">\nimport { VisCrosshair, VisTooltip } from '@unovis/vue'\nimport type { BulletLegendItemInterface } from '@unovis/ts'\nimport { omit } from '@unovis/ts'\nimport { type Component, createApp } from 'vue'\nimport { ChartTooltip } from '@/lib/registry/default/ui/chart'\n\nconst props = withDefaults(defineProps<{\n colors: string[]\n index: string\n items: BulletLegendItemInterface[]\n customTooltip?: Component\n}>(), {\n colors: () => [],\n})\n\n// Use weakmap to store reference to each datapoint for Tooltip\nconst wm = new WeakMap()\nfunction template(d: any) {\n if (wm.has(d)) {\n return wm.get(d)\n }\n else {\n const componentDiv = document.createElement('div')\n const omittedData = Object.entries(omit(d, [props.index])).map(([key, value]) => {\n const legendReference = props.items.find(i => i.name === key)\n return { ...legendReference, value }\n })\n const TooltipComponent = props.customTooltip ?? ChartTooltip\n createApp(TooltipComponent, { title: d[props.index].toString(), data: omittedData }).mount(componentDiv)\n wm.set(d, componentDiv.innerHTML)\n return componentDiv.innerHTML\n }\n}\n\nfunction color(d: unknown, i: number) {\n return props.colors[i] ?? 'transparent'\n}\n</script>\n\n<template>\n <VisTooltip :horizontal-shift=\"20\" :vertical-shift=\"20\" />\n <VisCrosshair :template=\"template\" :color=\"color\" />\n</template>\n"
},
{
"name": "ChartLegend.vue",
"content": "<script setup lang=\"ts\">\nimport { VisBulletLegend } from '@unovis/vue'\nimport type { BulletLegendItemInterface } from '@unovis/ts'\nimport { BulletLegend } from '@unovis/ts'\nimport { nextTick, onMounted, ref } from 'vue'\nimport { buttonVariants } from '@/lib/registry/default/ui/button'\n\nconst props = withDefaults(defineProps<{ items: BulletLegendItemInterface[] }>(), {\n items: () => [],\n})\n\nconst emits = defineEmits<{\n 'legendItemClick': [d: BulletLegendItemInterface, i: number]\n 'update:items': [payload: BulletLegendItemInterface[]]\n}>()\n\nconst elRef = ref<HTMLElement>()\n\nonMounted(() => {\n const selector = `.${BulletLegend.selectors.item}`\n nextTick(() => {\n const elements = elRef.value?.querySelectorAll(selector)\n const classes = buttonVariants({ variant: 'ghost', size: 'xs' }).split(' ')\n elements?.forEach(el => el.classList.add(...classes, '!inline-flex', '!mr-2'))\n })\n})\n\nfunction onLegendItemClick(d: BulletLegendItemInterface, i: number) {\n emits('legendItemClick', d, i)\n const isBulletActive = !props.items[i].inactive\n const isFilterApplied = props.items.some(i => i.inactive)\n if (isFilterApplied && isBulletActive) {\n // reset filter\n emits('update:items', props.items.map(item => ({ ...item, inactive: false })))\n }\n else {\n // apply selection, set other item as inactive\n emits('update:items', props.items.map(item => item.name === d.name ? ({ ...d, inactive: false }) : { ...item, inactive: true }))\n }\n}\n</script>\n\n<template>\n <div ref=\"elRef\" class=\"w-max\">\n <VisBulletLegend\n :items=\"items\"\n :on-legend-item-click=\"onLegendItemClick\"\n />\n </div>\n</template>\n"
},
{
"name": "ChartSingleTooltip.vue",
"content": "<script setup lang=\"ts\">\nimport { VisTooltip } from '@unovis/vue'\nimport type { BulletLegendItemInterface } from '@unovis/ts'\nimport { omit } from '@unovis/ts'\nimport { type Component, createApp } from 'vue'\nimport { ChartTooltip } from '@/lib/registry/default/ui/chart'\n\nconst props = withDefaults(defineProps<{\n selector: string\n index: string\n items?: BulletLegendItemInterface[]\n valueFormatter?: (tick: number, i?: number, ticks?: number[]) => string\n customTooltip?: Component\n}>(), {\n valueFormatter: (tick: number) => `${tick}`,\n})\n\n// Use weakmap to store reference to each datapoint for Tooltip\nconst wm = new WeakMap()\nfunction template(d: any, i: number, elements: (HTMLElement | SVGElement)[]) {\n if (props.index in d) {\n if (wm.has(d)) {\n return wm.get(d)\n }\n else {\n const componentDiv = document.createElement('div')\n const omittedData = Object.entries(omit(d, [props.index])).map(([key, value]) => {\n const legendReference = props.items?.find(i => i.name === key)\n return { ...legendReference, value: props.valueFormatter(value) }\n })\n const TooltipComponent = props.customTooltip ?? ChartTooltip\n createApp(TooltipComponent, { title: d[props.index], data: omittedData }).mount(componentDiv)\n wm.set(d, componentDiv.innerHTML)\n return componentDiv.innerHTML\n }\n }\n\n else {\n const data = d.data\n\n if (wm.has(data)) {\n return wm.get(data)\n }\n else {\n const style = getComputedStyle(elements[i])\n const omittedData = [{ name: data.name, value: props.valueFormatter(data[props.index]), color: style.fill }]\n const componentDiv = document.createElement('div')\n const TooltipComponent = props.customTooltip ?? ChartTooltip\n createApp(TooltipComponent, { title: d[props.index], data: omittedData }).mount(componentDiv)\n wm.set(d, componentDiv.innerHTML)\n return componentDiv.innerHTML\n }\n }\n}\n</script>\n\n<template>\n <VisTooltip\n :horizontal-shift=\"20\" :vertical-shift=\"20\" :triggers=\"{\n [selector]: template,\n }\"\n />\n</template>\n"
},
{
"name": "ChartTooltip.vue",
"content": "<script setup lang=\"ts\">\nimport { Card, CardContent, CardHeader, CardTitle } from '@/lib/registry/default/ui/card'\n\ndefineProps<{\n title?: string\n data: {\n name: string\n color: string\n value: any\n }[]\n}>()\n</script>\n\n<template>\n <Card class=\"text-sm\">\n <CardHeader v-if=\"title\" class=\"p-3 border-b\">\n <CardTitle>\n {{ title }}\n </CardTitle>\n </CardHeader>\n <CardContent class=\"p-3 min-w-[180px] flex flex-col gap-1\">\n <div v-for=\"(item, key) in data\" :key=\"key\" class=\"flex justify-between\">\n <div class=\"flex items-center\">\n <span class=\"w-2.5 h-2.5 mr-2\">\n <svg width=\"100%\" height=\"100%\" viewBox=\"0 0 30 30\">\n <path\n d=\" M 15 15 m -14, 0 a 14,14 0 1,1 28,0 a 14,14 0 1,1 -28,0\"\n :stroke=\"item.color\"\n :fill=\"item.color\"\n stroke-width=\"1\"\n />\n </svg>\n </span>\n <span>{{ item.name }}</span>\n </div>\n <span class=\"font-semibold ml-4\">{{ item.value }}</span>\n </div>\n </CardContent>\n </Card>\n</template>\n"
},
{
"name": "index.ts",
"content": "export { default as ChartTooltip } from './ChartTooltip.vue'\nexport { default as ChartSingleTooltip } from './ChartSingleTooltip.vue'\nexport { default as ChartLegend } from './ChartLegend.vue'\nexport { default as ChartCrosshair } from './ChartCrosshair.vue'\n\nexport function defaultColors(count: number = 3) {\n const quotient = Math.floor(count / 2)\n const remainder = count % 2\n\n const primaryCount = quotient + remainder\n const secondaryCount = quotient\n return [\n ...Array.from(Array(primaryCount).keys()).map(i => `hsl(var(--primary) / ${1 - (1 / primaryCount) * i})`),\n ...Array.from(Array(secondaryCount).keys()).map(i => `hsl(var(--vis-secondary-color) / ${1 - (1 / secondaryCount) * i})`),\n ]\n}\n\nexport * from './interface'\n"
},
{
"name": "interface.ts",
"content": "import type { Spacing } from '@unovis/ts'\n\ntype KeyOf<T extends Record<string, any>> = Extract<keyof T, string>\n\nexport interface BaseChartProps<T extends Record<string, any>> {\n /**\n * The source data, in which each entry is a dictionary.\n */\n data: T[]\n /**\n * Select the categories from your data. Used to populate the legend and toolip.\n */\n categories: KeyOf<T>[]\n /**\n * Sets the key to map the data to the axis.\n */\n index: KeyOf<T>\n /**\n * Change the default colors.\n */\n colors?: string[]\n /**\n * Margin of each the container\n */\n margin?: Spacing\n /**\n * Change the opacity of the non-selected field\n * @default 0.2\n */\n filterOpacity?: number\n /**\n * Function to format X label\n */\n xFormatter?: (tick: number | Date, i: number, ticks: number[] | Date[]) => string\n /**\n * Function to format Y label\n */\n yFormatter?: (tick: number | Date, i: number, ticks: number[] | Date[]) => string\n /**\n * Controls the visibility of the X axis.\n * @default true\n */\n showXAxis?: boolean\n /**\n * Controls the visibility of the Y axis.\n * @default true\n */\n showYAxis?: boolean\n /**\n * Controls the visibility of tooltip.\n * @default true\n */\n showTooltip?: boolean\n /**\n * Controls the visibility of legend.\n * @default true\n */\n showLegend?: boolean\n /**\n * Controls the visibility of gridline.\n * @default true\n */\n showGridLine?: boolean\n}\n"
}
],
"type": "components:ui"
}