diff --git a/docs/.vitepress/config.ts b/docs/.vitepress/config.ts new file mode 100644 index 0000000..9119649 --- /dev/null +++ b/docs/.vitepress/config.ts @@ -0,0 +1,61 @@ +import { defineConfig } from 'vitepress'; +import { name, description, repository, license, author } from '../../package.json'; +import typedocSidebar from '../api/typedoc-sidebar.json'; + +const cleanName = name.replace('@sgratzl/', ''); + +// https://vitepress.dev/reference/site-config +export default defineConfig({ + title: cleanName, + description, + base: `/${cleanName}/`, + useWebFonts: false, + themeConfig: { + // https://vitepress.dev/reference/default-theme-config + nav: [ + { text: 'Home', link: '/' }, + { text: 'Getting Started', link: '/getting-started' }, + { text: 'Examples', link: '/examples/' }, + { text: 'API', link: '/api/' }, + { text: 'Related Plugins', link: '/related' }, + ], + + sidebar: [ + { + text: 'Examples', + items: [ + { text: 'Basic', link: '/examples/' }, + { text: 'Funnel Alignment', link: '/examples/align' }, + { text: 'Shrink Options', link: '/examples/shrink' }, + { text: 'Gradient', link: '/examples/gradient' }, + { text: 'Hierarchical Funnel', link: '/examples/hierarchical' }, + { text: 'Horizontal Funnel', link: '/examples/horizontal' }, + { text: 'Direct Numbers', link: '/examples/numbers' }, + ], + }, + { + text: 'API', + collapsed: true, + items: typedocSidebar, + }, + ], + + socialLinks: [{ icon: 'github', link: repository.url.replace('.git', '') }], + + footer: { + message: `Released under the ${license} license.`, + copyright: `Copyright © 2019-present ${author.name}`, + }, + + editLink: { + pattern: `${repository.url.replace('.git', '')}/edit/main/docs/:path`, + }, + + search: { + provider: 'local', + }, + }, +}); diff --git a/docs/.vitepress/theme/index.ts b/docs/.vitepress/theme/index.ts new file mode 100644 index 0000000..302c2c2 --- /dev/null +++ b/docs/.vitepress/theme/index.ts @@ -0,0 +1,24 @@ +import Theme from 'vitepress/theme'; +import { createTypedChart } from 'vue-chartjs'; +import { LinearScale, CategoryScale, Tooltip } from 'chart.js'; +import { FunnelController, TrapezoidElement } from '../../../src'; +import ChartDataLabels from 'chartjs-plugin-datalabels'; +import { HierarchicalScale } from 'chartjs-plugin-hierarchical'; + +export default { + ...Theme, + enhanceApp({ app }) { + app.component( + 'FunnelChart', + createTypedChart('funnel', [ + LinearScale, + CategoryScale, + FunnelController, + TrapezoidElement, + Tooltip, + ChartDataLabels, + HierarchicalScale, + ]) + ); + }, +}; diff --git a/docs/examples/align.md b/docs/examples/align.md new file mode 100644 index 0000000..4b05d2e --- /dev/null +++ b/docs/examples/align.md @@ -0,0 +1,42 @@ +--- +title: Funnel Alignment +--- + +# Funnel Alignment + + + +## Center (default) + + + +### Code + +<<< ./align.ts#center + +## Left + + + +### Code + +<<< ./align.ts#left + +## Right + + + +### Code + +<<< ./align.ts#right diff --git a/docs/examples/align.ts b/docs/examples/align.ts new file mode 100644 index 0000000..447d126 --- /dev/null +++ b/docs/examples/align.ts @@ -0,0 +1,50 @@ +import type { ChartConfiguration } from 'chart.js'; +import type {} from '../../src'; +import ChartDataLabels from 'chartjs-plugin-datalabels'; + +// #region center +export const center: ChartConfiguration<'funnel'> = { + type: 'funnel', + data: { + labels: ['Step 1', 'Step 2', 'Step 3', 'Step 4'], + datasets: [ + { + data: [0.7, 0.66, 0.61, 0.01], + }, + ], + }, + plugins: [ChartDataLabels], +}; +// #endregion center + +// #region left +export const left: ChartConfiguration<'funnel'> = { + type: 'funnel', + data: { + labels: ['Step 1', 'Step 2', 'Step 3', 'Step 4'], + datasets: [ + { + data: [0.7, 0.66, 0.61, 0.01], + align: 'left', + }, + ], + }, + plugins: [ChartDataLabels], +}; +// #endregion left + +// #region right +export const right: ChartConfiguration<'funnel'> = { + type: 'funnel', + data: { + labels: ['Step 1', 'Step 2', 'Step 3', 'Step 4'], + datasets: [ + { + data: [0.7, 0.66, 0.61, 0.01], + align: 'right', + }, + ], + }, + plugins: [ChartDataLabels], +}; +// #endregion right diff --git a/docs/examples/basic.ts b/docs/examples/basic.ts new file mode 100644 index 0000000..c76eb04 --- /dev/null +++ b/docs/examples/basic.ts @@ -0,0 +1,43 @@ +import type { ChartConfiguration } from 'chart.js'; +import type {} from '../../src'; +import ChartDataLabels from 'chartjs-plugin-datalabels'; + +// #region config +export const config: ChartConfiguration<'funnel'> = { + type: 'funnel', + data: { + labels: ['Step 1', 'Step 2', 'Step 3', 'Step 4'], + datasets: [ + { + data: [0.7, 0.66, 0.61, 0.01], + datalabels: { + // anchor: (context) => { + // const value = context.dataset.data[context.dataIndex]; + // return value < 0.02 ? 'end': 'start'; + // }, + // align: (context) => { + // const value = context.dataset.data[context.dataIndex]; + // return value < 0.02 ? 'end': 'center'; + // }, + // textAlign: 'center', + // // color: (context) => { + // // return '#FFCE56'; + // // }, + // font: { + // size: 20, + // }, + // formatter: (value, context) => { + // const label = context.chart.data.labels[context.dataIndex]; + // return `${label}\n${(value * 100).toLocaleString()}%`; + // } + }, + // backgroundColor: ChartFunnel.schemeBlues[9], + }, + ], + }, + options: { + indexAxis: 'y', + }, + plugins: [ChartDataLabels], +}; +// #endregion config diff --git a/docs/examples/gradient.md b/docs/examples/gradient.md new file mode 100644 index 0000000..549e8a4 --- /dev/null +++ b/docs/examples/gradient.md @@ -0,0 +1,18 @@ +--- +title: Gradient +--- + +# Gradient Color + + + + + +### Code + +<<< ./gradient.ts#config diff --git a/docs/examples/gradient.ts b/docs/examples/gradient.ts new file mode 100644 index 0000000..92e6719 --- /dev/null +++ b/docs/examples/gradient.ts @@ -0,0 +1,23 @@ +import type { ChartConfiguration } from 'chart.js'; +import type {} from '../../src'; +import ChartDataLabels from 'chartjs-plugin-datalabels'; +import chroma from 'chroma-js'; + +// #region config +export const config: ChartConfiguration<'funnel'> = { + type: 'funnel', + data: { + labels: ['Step 1', 'Step 2', 'Step 3', 'Step 4'], + datasets: [ + { + data: [0.7, 0.66, 0.61, 0.01], + backgroundColor: chroma.scale('Greens').colors(4), + }, + ], + }, + options: { + indexAxis: 'y', + }, + plugins: [ChartDataLabels], +}; +// #endregion config diff --git a/docs/examples/hierarchical.md b/docs/examples/hierarchical.md new file mode 100644 index 0000000..fd34f7c --- /dev/null +++ b/docs/examples/hierarchical.md @@ -0,0 +1,18 @@ +--- +title: Hierarchical Funnel +--- + +# Hierarchical Funnel + + + + + +### Code + +<<< ./hierarchical.ts#config diff --git a/docs/examples/hierarchical.ts b/docs/examples/hierarchical.ts new file mode 100644 index 0000000..5656345 --- /dev/null +++ b/docs/examples/hierarchical.ts @@ -0,0 +1,53 @@ +import type { ChartConfiguration } from 'chart.js'; +import type {} from '../../src'; +import ChartDataLabels from 'chartjs-plugin-datalabels'; + +// #region config +export const config: ChartConfiguration<'funnel'> = { + type: 'funnel', + data: { + labels: [ + { + label: 'Step 1', + children: ['A', 'B'], + }, + 'Step 2', + ], + datasets: [ + { + tree: [ + { + value: 0.9, + children: [0.9, 0.8], + }, + 0.7, + ], + datalabels: { + // formatter: (v) => v.toLocaleString(), + }, + } as any, + ], + }, + options: { + indexAxis: 'y', + layout: { + padding: { + // add more space at the bottom for the hierarchy + left: 100, + }, + }, + scales: { + y: { + display: true, + type: 'hierarchical', + padding: 25, + levelPercentage: 1, + }, + x: { + // display: true, + }, + }, + }, + plugins: [ChartDataLabels], +}; +// #endregion config diff --git a/docs/examples/horizontal.md b/docs/examples/horizontal.md new file mode 100644 index 0000000..5698e51 --- /dev/null +++ b/docs/examples/horizontal.md @@ -0,0 +1,18 @@ +--- +title: Horizontal Funnel +--- + +# Horizontal Funnel + + + + + +### Code + +<<< ./horizontal.ts#config diff --git a/docs/examples/horizontal.ts b/docs/examples/horizontal.ts new file mode 100644 index 0000000..1940093 --- /dev/null +++ b/docs/examples/horizontal.ts @@ -0,0 +1,19 @@ +import type { ChartConfiguration } from 'chart.js'; +import type {} from '../../src'; +import ChartDataLabels from 'chartjs-plugin-datalabels'; + +// #region config +export const config: ChartConfiguration<'funnel'> = { + type: 'funnel', + data: { + labels: ['Step 1', 'Step 2', 'Step 3', 'Step 4'], + datasets: [ + { + data: [0.7, 0.66, 0.61, 0.01], + shrinkAnchor: 'top', + }, + ], + }, + plugins: [ChartDataLabels], +}; +// #endregion config diff --git a/docs/examples/index.md b/docs/examples/index.md new file mode 100644 index 0000000..385f4bd --- /dev/null +++ b/docs/examples/index.md @@ -0,0 +1,18 @@ +--- +title: Examples +--- + +# Examples + + + + + +### Code + +<<< ./basic.ts#config diff --git a/docs/examples/numbers.md b/docs/examples/numbers.md new file mode 100644 index 0000000..2a003d2 --- /dev/null +++ b/docs/examples/numbers.md @@ -0,0 +1,18 @@ +--- +title: Numbers +--- + +# Numbers + + + + + +### Code + +<<< ./numbers.ts#config diff --git a/docs/examples/numbers.ts b/docs/examples/numbers.ts new file mode 100644 index 0000000..f9e3a70 --- /dev/null +++ b/docs/examples/numbers.ts @@ -0,0 +1,24 @@ +import type { ChartConfiguration } from 'chart.js'; +import type {} from '../../src'; +import ChartDataLabels from 'chartjs-plugin-datalabels'; + +// #region config +export const config: ChartConfiguration<'funnel'> = { + type: 'funnel', + data: { + labels: ['Step 1', 'Step 2', 'Step 3'], + datasets: [ + { + data: [2000, 1500, 300], + datalabels: { + formatter: (v) => v.toLocaleString(), + }, + }, + ], + }, + options: { + indexAxis: 'y', + }, + plugins: [ChartDataLabels], +}; +// #endregion config diff --git a/docs/examples/shrink.md b/docs/examples/shrink.md new file mode 100644 index 0000000..e532a6f --- /dev/null +++ b/docs/examples/shrink.md @@ -0,0 +1,75 @@ +--- +title: Funnel Shrinking +--- + +# Funnel Shrinking + + + +## Top (default) + + + +### Code + +<<< ./shrink.ts#top + +## Top (0.5 fraction) + + + +### Code + +<<< ./shrink.ts#top5 + +## Top (0.25 fraction) + + + +### Code + +<<< ./shrink.ts#top25 + +## Middle + + + +### Code + +<<< ./shrink.ts#middle + +## Bottom + + + +### Code + +<<< ./shrink.ts#bottom + +## None + + + +### Code + +<<< ./shrink.ts#none diff --git a/docs/examples/shrink.ts b/docs/examples/shrink.ts new file mode 100644 index 0000000..1d1c9fd --- /dev/null +++ b/docs/examples/shrink.ts @@ -0,0 +1,101 @@ +import type { ChartConfiguration } from 'chart.js'; +import type {} from '../../src'; +import ChartDataLabels from 'chartjs-plugin-datalabels'; + +// #region top +export const top: ChartConfiguration<'funnel'> = { + type: 'funnel', + data: { + labels: ['Step 1', 'Step 2', 'Step 3', 'Step 4'], + datasets: [ + { + data: [0.7, 0.66, 0.61, 0.01], + shrinkAnchor: 'top', + }, + ], + }, + plugins: [ChartDataLabels], +}; +// #endregion top + +// #region top5 +export const top5: ChartConfiguration<'funnel'> = { + type: 'funnel', + data: { + labels: ['Step 1', 'Step 2', 'Step 3', 'Step 4'], + datasets: [ + { + data: [0.7, 0.66, 0.61, 0.01], + shrinkAnchor: 'top', + shrinkFraction: 0.5, + }, + ], + }, + plugins: [ChartDataLabels], +}; +// #endregion top5 + +// #region top25 +export const top25: ChartConfiguration<'funnel'> = { + type: 'funnel', + data: { + labels: ['Step 1', 'Step 2', 'Step 3', 'Step 4'], + datasets: [ + { + data: [0.7, 0.66, 0.61, 0.01], + shrinkAnchor: 'top', + shrinkFraction: 0.25, + }, + ], + }, + plugins: [ChartDataLabels], +}; +// #endregion top25 + +// #region middle +export const middle: ChartConfiguration<'funnel'> = { + type: 'funnel', + data: { + labels: ['Step 1', 'Step 2', 'Step 3', 'Step 4'], + datasets: [ + { + data: [0.7, 0.66, 0.61, 0.01], + shrinkAnchor: 'middle', + }, + ], + }, + plugins: [ChartDataLabels], +}; +// #endregion middle + +// #region bottom +export const bottom: ChartConfiguration<'funnel'> = { + type: 'funnel', + data: { + labels: ['Step 1', 'Step 2', 'Step 3', 'Step 4'], + datasets: [ + { + data: [0.7, 0.66, 0.61, 0.01], + shrinkAnchor: 'bottom', + }, + ], + }, + plugins: [ChartDataLabels], +}; +// #endregion bottom + +// #region none +export const none: ChartConfiguration<'funnel'> = { + type: 'funnel', + data: { + labels: ['Step 1', 'Step 2', 'Step 3', 'Step 4'], + datasets: [ + { + data: [0.7, 0.66, 0.61, 0.01], + shrinkAnchor: 'none', + }, + ], + }, + plugins: [ChartDataLabels], +}; +// #endregion none diff --git a/docs/getting-started.md b/docs/getting-started.md new file mode 100644 index 0000000..c290452 --- /dev/null +++ b/docs/getting-started.md @@ -0,0 +1,33 @@ +--- +title: Getting Started +--- + +Chart.js module for charting funnel plots. This plugin extends with a new char type `funnel`. + +A Funnel chart is a variant of a bar chart where the bar shrinks on one side to the size of the next bar. In addition, they are usually centered giving the visual impression of a funnel. + +![funnel chart](https://user-images.githubusercontent.com/4129778/212717664-b3c63b7f-022b-4a39-953c-9d6e45265f7c.png) + +## Install + +```sh +npm install chart.js chartjs-chart-funnel +``` + +## Usage + +see [Examples](./examples/) + +and [CodePen](https://codepen.io/sgratzl/pen/eYjEXQW) + +## Configuration + +### Data Structure + +you can either provide percentages (values between 0 and 1) or absolute values (> 1) + +### Styling + +Trapezoid Elements are Bar elements and provide the same coloring options. In addition, see [TrapezoidElementOptions](/api/interfaces/interface.TrapezoidElementOptions.md) custom option with respect to shrinking behavior. + +In addition, the FunnelController has the following options [FunnelController](/api/interfaces/interface.FunnelChartOptions.md) to customize the alignment of the chart. diff --git a/docs/index.md b/docs/index.md new file mode 100644 index 0000000..b9f8725 --- /dev/null +++ b/docs/index.md @@ -0,0 +1,22 @@ +--- +# https://vitepress.dev/reference/default-theme-home-page +layout: home + +hero: + name: 'chartjs-chart-funnel' + text: 'chart.js plugin' + tagline: Chart.js module for charting funnel charts + actions: + - theme: brand + text: Getting Started + link: /getting-started + - theme: alt + text: Examples + link: /examples/ + - theme: alt + text: API + link: /api/ +# features: +# - title: Feature A +# details: Lorem ipsum dolor sit amet, consectetur adipiscing elit +--- diff --git a/docs/related.md b/docs/related.md new file mode 100644 index 0000000..bf01c2d --- /dev/null +++ b/docs/related.md @@ -0,0 +1,15 @@ +--- +title: Related Plugins +--- + +There are several related chart.js plugins providing additional functionality and chart types: + +- [chartjs-chart-boxplot](https://github.com/sgratzl/chartjs-chart-boxplot) for rendering boxplots and violin charts +- [chartjs-chart-error-bars](https://github.com/sgratzl/chartjs-chart-error-bars) for rendering errors bars to bars and line charts +- [chartjs-chart-funnel](https://github.com/sgratzl/chartjs-chart-funnel) for rendering funnel charts +- [chartjs-chart-geo](https://github.com/sgratzl/chartjs-chart-geo) for rendering map, bubble maps, and choropleth charts +- [chartjs-chart-graph](https://github.com/sgratzl/chartjs-chart-graph) for rendering graphs, trees, and networks +- [chartjs-chart-pcp](https://github.com/sgratzl/chartjs-chart-pcp) for rendering parallel coordinate plots +- [chartjs-chart-venn](https://github.com/sgratzl/chartjs-chart-venn) for rendering venn and euler diagrams +- [chartjs-chart-wordcloud](https://github.com/sgratzl/chartjs-chart-wordcloud) for rendering word clouds +- [chartjs-plugin-hierarchical](https://github.com/sgratzl/chartjs-plugin-hierarchical) for rendering hierarchical categorical axes which can be expanded and collapsed