diff --git a/docs/.vitepress/config.ts b/docs/.vitepress/config.ts
new file mode 100644
index 0000000..bfa7a35
--- /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: 'Dendrogram', link: '/examples/dendrogram' },
+ { text: 'Tree', link: '/examples/tree' },
+ { text: 'Force Directed Graph', link: '/examples/force' },
+ { text: 'Tree with Labels', link: '/examples/label' },
+ { text: 'Directed Tree', link: '/examples/directed' },
+ { text: 'Tree Orientations', link: '/examples/orientation' },
+ ],
+ },
+ {
+ 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..1b67129
--- /dev/null
+++ b/docs/.vitepress/theme/index.ts
@@ -0,0 +1,25 @@
+import Theme from 'vitepress/theme';
+import { createTypedChart } from 'vue-chartjs';
+import { Tooltip, LineElement, PointElement, LinearScale } from 'chart.js';
+import { DendrogramController, ForceDirectedGraphController, EdgeLine, TreeController } from '../../../src';
+import ChartPluginDataLabel from 'chartjs-plugin-datalabels';
+
+export default {
+ ...Theme,
+ enhanceApp({ app }) {
+ const deps = [
+ Tooltip,
+ LineElement,
+ PointElement,
+ DendrogramController,
+ ForceDirectedGraphController,
+ EdgeLine,
+ TreeController,
+ LinearScale,
+ ChartPluginDataLabel,
+ ];
+ app.component('DendrogramChart', createTypedChart('dendrogram', deps));
+ app.component('TreeChart', createTypedChart('tree', deps));
+ app.component('ForceDirectedGraphChart', createTypedChart('forceDirectedGraph', deps));
+ },
+};
diff --git a/docs/examples/dendrogram.md b/docs/examples/dendrogram.md
new file mode 100644
index 0000000..1fd1e55
--- /dev/null
+++ b/docs/examples/dendrogram.md
@@ -0,0 +1,24 @@
+---
+title: Dendrogram
+---
+
+# Dendrogram
+
+
+
+
+
+### Code
+
+:::code-group
+
+<<< ./dendrogram.ts#config [config]
+
+<<< ./dendrogram.ts#data [data]
+
+:::
diff --git a/docs/examples/dendrogram.ts b/docs/examples/dendrogram.ts
new file mode 100644
index 0000000..c2cedd4
--- /dev/null
+++ b/docs/examples/dendrogram.ts
@@ -0,0 +1,31 @@
+import type { ChartConfiguration } from 'chart.js';
+import type {} from '../../src';
+import 'chartjs-plugin-datalabels';
+
+// #region data
+import nodes from './tree.json';
+
+export const data: ChartConfiguration<'dendrogram'>['data'] = {
+ labels: nodes.map((d) => d.name),
+ datasets: [
+ {
+ pointBackgroundColor: 'steelblue',
+ pointRadius: 5,
+ data: nodes.map((d) => Object.assign({}, d)),
+ },
+ ],
+};
+// #endregion data
+// #region config
+export const config: ChartConfiguration<'dendrogram'> = {
+ type: 'dendrogram',
+ data,
+ options: {
+ plugins: {
+ datalabels: {
+ display: false,
+ },
+ },
+ },
+};
+// #endregion config
diff --git a/docs/examples/directed.md b/docs/examples/directed.md
new file mode 100644
index 0000000..d90b040
--- /dev/null
+++ b/docs/examples/directed.md
@@ -0,0 +1,24 @@
+---
+title: Directed Tree
+---
+
+# Directed Tree
+
+
+
+
+
+### Code
+
+:::code-group
+
+<<< ./directed.ts#config [config]
+
+<<< ./directed.ts#data [data]
+
+:::
diff --git a/docs/examples/directed.ts b/docs/examples/directed.ts
new file mode 100644
index 0000000..b40f00f
--- /dev/null
+++ b/docs/examples/directed.ts
@@ -0,0 +1,32 @@
+import type { ChartConfiguration } from 'chart.js';
+import type {} from '../../src';
+import 'chartjs-plugin-datalabels';
+
+// #region data
+import nodes from './tree.json';
+
+export const data: ChartConfiguration<'tree'>['data'] = {
+ labels: nodes.map((d) => d.name),
+ datasets: [
+ {
+ pointBackgroundColor: 'steelblue',
+ pointRadius: 5,
+ directed: true,
+ data: nodes.map((d) => Object.assign({}, d)),
+ },
+ ],
+};
+// #endregion data
+// #region config
+export const config: ChartConfiguration<'tree'> = {
+ type: 'tree',
+ data,
+ options: {
+ plugins: {
+ datalabels: {
+ display: false,
+ },
+ },
+ },
+};
+// #endregion config
diff --git a/docs/examples/force.md b/docs/examples/force.md
new file mode 100644
index 0000000..6dae2a5
--- /dev/null
+++ b/docs/examples/force.md
@@ -0,0 +1,24 @@
+---
+title: Force Directed Graph
+---
+
+# Force Directed Graph
+
+
+
+
+
+### Code
+
+:::code-group
+
+<<< ./force.ts#config [config]
+
+<<< ./force.ts#data [data]
+
+:::
diff --git a/docs/examples/force.ts b/docs/examples/force.ts
new file mode 100644
index 0000000..19d6eb1
--- /dev/null
+++ b/docs/examples/force.ts
@@ -0,0 +1,31 @@
+import type { ChartConfiguration } from 'chart.js';
+import type {} from '../../src';
+import 'chartjs-plugin-datalabels';
+
+// #region data
+import miserables from './miserables.json';
+export const data: ChartConfiguration<'forceDirectedGraph'>['data'] = {
+ labels: miserables.nodes.map((d) => d.id),
+ datasets: [
+ {
+ pointBackgroundColor: 'steelblue',
+ pointRadius: 5,
+ data: miserables.nodes,
+ edges: miserables.links,
+ },
+ ],
+};
+// #endregion data
+// #region config
+export const config: ChartConfiguration<'forceDirectedGraph'> = {
+ type: 'forceDirectedGraph',
+ data,
+ options: {
+ plugins: {
+ datalabels: {
+ display: false,
+ },
+ },
+ },
+};
+// #endregion config
diff --git a/docs/examples/index.md b/docs/examples/index.md
new file mode 100644
index 0000000..6e9db63
--- /dev/null
+++ b/docs/examples/index.md
@@ -0,0 +1,62 @@
+---
+title: Examples
+---
+
+# Examples
+
+
+
+## Force Directed Graph
+
+
+
+### Code
+
+:::code-group
+
+<<< ./force.ts#config [config]
+
+<<< ./force.ts#data [data]
+
+:::
+
+## Dendrogram
+
+
+
+### Code
+
+:::code-group
+
+<<< ./dendrogram.ts#config [config]
+
+<<< ./dendrogram.ts#data [data]
+
+:::
+
+## Tree
+
+
+
+### Code
+
+:::code-group
+
+<<< ./tree.ts#tree [config]
+
+<<< ./tree.ts#data [data]
+
+:::
diff --git a/docs/examples/label.md b/docs/examples/label.md
new file mode 100644
index 0000000..6354735
--- /dev/null
+++ b/docs/examples/label.md
@@ -0,0 +1,41 @@
+---
+title: Tree with Labels
+---
+
+# Tree with Labels
+
+
+
+
+
+### Code
+
+:::code-group
+
+<<< ./label.ts#config [config]
+
+<<< ./label.ts#data [data]
+
+:::
+
+## Radial Tree with Labels
+
+
+
+### Code
+
+:::code-group
+
+<<< ./label.ts#radial [config]
+
+<<< ./label.ts#data [data]
+
+:::
diff --git a/docs/examples/label.ts b/docs/examples/label.ts
new file mode 100644
index 0000000..05c3f25
--- /dev/null
+++ b/docs/examples/label.ts
@@ -0,0 +1,91 @@
+import type { ChartConfiguration } from 'chart.js';
+import type {} from '../../src';
+import ChartDataLabels from 'chartjs-plugin-datalabels';
+// #region data
+import nodes from './tree.json';
+
+export const data: ChartConfiguration<'tree'>['data'] = {
+ labels: nodes.map((d) => d.name),
+ datasets: [
+ {
+ pointBackgroundColor: ['#002838', '#ed7d00', '#395c6b', '#d94d15', '#889da6'],
+ pointRadius: 10,
+ data: nodes.map((d) => Object.assign({}, d)),
+ },
+ ],
+};
+// #endregion data
+// #region config
+export const config: ChartConfiguration<'tree'> = {
+ type: 'tree',
+ data,
+ options: {
+ tree: {
+ orientation: 'radial',
+ },
+ layout: {
+ padding: {
+ left: 20,
+ top: 20,
+ bottom: 20,
+ right: 20,
+ },
+ },
+ plugins: {
+ legend: {
+ display: false,
+ },
+ datalabels: {
+ // display: true,
+ align: 'right',
+ offset: 6,
+ formatter: function (value, context) {
+ return '' + value.name + '';
+ },
+ color: 'black',
+ backgroundColor: 'steelblue',
+ },
+ },
+ },
+ plugins: [ChartDataLabels],
+};
+// #endregion config
+
+// #region radial
+export const radial: ChartConfiguration<'tree'> = {
+ type: 'tree',
+ data,
+ options: {
+ tree: {
+ orientation: 'radial',
+ },
+ layout: {
+ padding: 40,
+ },
+ plugins: {
+ datalabels: {
+ display: (context) => {
+ // const index = context.dataIndex;
+ // const value = context.dataset.data[index];
+ return true; //value.children.length === 0;
+ },
+ align: (context) => {
+ const index = context.dataIndex;
+ const value = context.dataset.data[index] as { angle: number };
+ return (-value.angle / Math.PI) * 180;
+ },
+ rotation: (context) => {
+ const index = context.dataIndex;
+ const value = context.dataset.data[index] as { angle: number };
+ return (-value.angle / Math.PI) * 180;
+ },
+ backgroundColor: 'white',
+ formatter: (v) => {
+ return v.name;
+ },
+ },
+ },
+ },
+ plugins: [ChartDataLabels],
+};
+// #endregion radial
diff --git a/docs/examples/miserables.json b/docs/examples/miserables.json
new file mode 100644
index 0000000..046a058
--- /dev/null
+++ b/docs/examples/miserables.json
@@ -0,0 +1,337 @@
+{
+ "nodes": [
+ { "id": "Myriel", "group": 1 },
+ { "id": "Napoleon", "group": 1 },
+ { "id": "Mlle.Baptistine", "group": 1 },
+ { "id": "Mme.Magloire", "group": 1 },
+ { "id": "CountessdeLo", "group": 1 },
+ { "id": "Geborand", "group": 1 },
+ { "id": "Champtercier", "group": 1 },
+ { "id": "Cravatte", "group": 1 },
+ { "id": "Count", "group": 1 },
+ { "id": "OldMan", "group": 1 },
+ { "id": "Labarre", "group": 2 },
+ { "id": "Valjean", "group": 2 },
+ { "id": "Marguerite", "group": 3 },
+ { "id": "Mme.deR", "group": 2 },
+ { "id": "Isabeau", "group": 2 },
+ { "id": "Gervais", "group": 2 },
+ { "id": "Tholomyes", "group": 3 },
+ { "id": "Listolier", "group": 3 },
+ { "id": "Fameuil", "group": 3 },
+ { "id": "Blacheville", "group": 3 },
+ { "id": "Favourite", "group": 3 },
+ { "id": "Dahlia", "group": 3 },
+ { "id": "Zephine", "group": 3 },
+ { "id": "Fantine", "group": 3 },
+ { "id": "Mme.Thenardier", "group": 4 },
+ { "id": "Thenardier", "group": 4 },
+ { "id": "Cosette", "group": 5 },
+ { "id": "Javert", "group": 4 },
+ { "id": "Fauchelevent", "group": 0 },
+ { "id": "Bamatabois", "group": 2 },
+ { "id": "Perpetue", "group": 3 },
+ { "id": "Simplice", "group": 2 },
+ { "id": "Scaufflaire", "group": 2 },
+ { "id": "Woman1", "group": 2 },
+ { "id": "Judge", "group": 2 },
+ { "id": "Champmathieu", "group": 2 },
+ { "id": "Brevet", "group": 2 },
+ { "id": "Chenildieu", "group": 2 },
+ { "id": "Cochepaille", "group": 2 },
+ { "id": "Pontmercy", "group": 4 },
+ { "id": "Boulatruelle", "group": 6 },
+ { "id": "Eponine", "group": 4 },
+ { "id": "Anzelma", "group": 4 },
+ { "id": "Woman2", "group": 5 },
+ { "id": "MotherInnocent", "group": 0 },
+ { "id": "Gribier", "group": 0 },
+ { "id": "Jondrette", "group": 7 },
+ { "id": "Mme.Burgon", "group": 7 },
+ { "id": "Gavroche", "group": 8 },
+ { "id": "Gillenormand", "group": 5 },
+ { "id": "Magnon", "group": 5 },
+ { "id": "Mlle.Gillenormand", "group": 5 },
+ { "id": "Mme.Pontmercy", "group": 5 },
+ { "id": "Mlle.Vaubois", "group": 5 },
+ { "id": "Lt.Gillenormand", "group": 5 },
+ { "id": "Marius", "group": 8 },
+ { "id": "BaronessT", "group": 5 },
+ { "id": "Mabeuf", "group": 8 },
+ { "id": "Enjolras", "group": 8 },
+ { "id": "Combeferre", "group": 8 },
+ { "id": "Prouvaire", "group": 8 },
+ { "id": "Feuilly", "group": 8 },
+ { "id": "Courfeyrac", "group": 8 },
+ { "id": "Bahorel", "group": 8 },
+ { "id": "Bossuet", "group": 8 },
+ { "id": "Joly", "group": 8 },
+ { "id": "Grantaire", "group": 8 },
+ { "id": "MotherPlutarch", "group": 9 },
+ { "id": "Gueulemer", "group": 4 },
+ { "id": "Babet", "group": 4 },
+ { "id": "Claquesous", "group": 4 },
+ { "id": "Montparnasse", "group": 4 },
+ { "id": "Toussaint", "group": 5 },
+ { "id": "Child1", "group": 10 },
+ { "id": "Child2", "group": 10 },
+ { "id": "Brujon", "group": 4 },
+ { "id": "Mme.Hucheloup", "group": 8 }
+ ],
+ "links": [
+ { "source": "Napoleon", "target": "Myriel", "value": 1 },
+ { "source": "Mlle.Baptistine", "target": "Myriel", "value": 8 },
+ { "source": "Mme.Magloire", "target": "Myriel", "value": 10 },
+ { "source": "Mme.Magloire", "target": "Mlle.Baptistine", "value": 6 },
+ { "source": "CountessdeLo", "target": "Myriel", "value": 1 },
+ { "source": "Geborand", "target": "Myriel", "value": 1 },
+ { "source": "Champtercier", "target": "Myriel", "value": 1 },
+ { "source": "Cravatte", "target": "Myriel", "value": 1 },
+ { "source": "Count", "target": "Myriel", "value": 2 },
+ { "source": "OldMan", "target": "Myriel", "value": 1 },
+ { "source": "Valjean", "target": "Labarre", "value": 1 },
+ { "source": "Valjean", "target": "Mme.Magloire", "value": 3 },
+ { "source": "Valjean", "target": "Mlle.Baptistine", "value": 3 },
+ { "source": "Valjean", "target": "Myriel", "value": 5 },
+ { "source": "Marguerite", "target": "Valjean", "value": 1 },
+ { "source": "Mme.deR", "target": "Valjean", "value": 1 },
+ { "source": "Isabeau", "target": "Valjean", "value": 1 },
+ { "source": "Gervais", "target": "Valjean", "value": 1 },
+ { "source": "Listolier", "target": "Tholomyes", "value": 4 },
+ { "source": "Fameuil", "target": "Tholomyes", "value": 4 },
+ { "source": "Fameuil", "target": "Listolier", "value": 4 },
+ { "source": "Blacheville", "target": "Tholomyes", "value": 4 },
+ { "source": "Blacheville", "target": "Listolier", "value": 4 },
+ { "source": "Blacheville", "target": "Fameuil", "value": 4 },
+ { "source": "Favourite", "target": "Tholomyes", "value": 3 },
+ { "source": "Favourite", "target": "Listolier", "value": 3 },
+ { "source": "Favourite", "target": "Fameuil", "value": 3 },
+ { "source": "Favourite", "target": "Blacheville", "value": 4 },
+ { "source": "Dahlia", "target": "Tholomyes", "value": 3 },
+ { "source": "Dahlia", "target": "Listolier", "value": 3 },
+ { "source": "Dahlia", "target": "Fameuil", "value": 3 },
+ { "source": "Dahlia", "target": "Blacheville", "value": 3 },
+ { "source": "Dahlia", "target": "Favourite", "value": 5 },
+ { "source": "Zephine", "target": "Tholomyes", "value": 3 },
+ { "source": "Zephine", "target": "Listolier", "value": 3 },
+ { "source": "Zephine", "target": "Fameuil", "value": 3 },
+ { "source": "Zephine", "target": "Blacheville", "value": 3 },
+ { "source": "Zephine", "target": "Favourite", "value": 4 },
+ { "source": "Zephine", "target": "Dahlia", "value": 4 },
+ { "source": "Fantine", "target": "Tholomyes", "value": 3 },
+ { "source": "Fantine", "target": "Listolier", "value": 3 },
+ { "source": "Fantine", "target": "Fameuil", "value": 3 },
+ { "source": "Fantine", "target": "Blacheville", "value": 3 },
+ { "source": "Fantine", "target": "Favourite", "value": 4 },
+ { "source": "Fantine", "target": "Dahlia", "value": 4 },
+ { "source": "Fantine", "target": "Zephine", "value": 4 },
+ { "source": "Fantine", "target": "Marguerite", "value": 2 },
+ { "source": "Fantine", "target": "Valjean", "value": 9 },
+ { "source": "Mme.Thenardier", "target": "Fantine", "value": 2 },
+ { "source": "Mme.Thenardier", "target": "Valjean", "value": 7 },
+ { "source": "Thenardier", "target": "Mme.Thenardier", "value": 13 },
+ { "source": "Thenardier", "target": "Fantine", "value": 1 },
+ { "source": "Thenardier", "target": "Valjean", "value": 12 },
+ { "source": "Cosette", "target": "Mme.Thenardier", "value": 4 },
+ { "source": "Cosette", "target": "Valjean", "value": 31 },
+ { "source": "Cosette", "target": "Tholomyes", "value": 1 },
+ { "source": "Cosette", "target": "Thenardier", "value": 1 },
+ { "source": "Javert", "target": "Valjean", "value": 17 },
+ { "source": "Javert", "target": "Fantine", "value": 5 },
+ { "source": "Javert", "target": "Thenardier", "value": 5 },
+ { "source": "Javert", "target": "Mme.Thenardier", "value": 1 },
+ { "source": "Javert", "target": "Cosette", "value": 1 },
+ { "source": "Fauchelevent", "target": "Valjean", "value": 8 },
+ { "source": "Fauchelevent", "target": "Javert", "value": 1 },
+ { "source": "Bamatabois", "target": "Fantine", "value": 1 },
+ { "source": "Bamatabois", "target": "Javert", "value": 1 },
+ { "source": "Bamatabois", "target": "Valjean", "value": 2 },
+ { "source": "Perpetue", "target": "Fantine", "value": 1 },
+ { "source": "Simplice", "target": "Perpetue", "value": 2 },
+ { "source": "Simplice", "target": "Valjean", "value": 3 },
+ { "source": "Simplice", "target": "Fantine", "value": 2 },
+ { "source": "Simplice", "target": "Javert", "value": 1 },
+ { "source": "Scaufflaire", "target": "Valjean", "value": 1 },
+ { "source": "Woman1", "target": "Valjean", "value": 2 },
+ { "source": "Woman1", "target": "Javert", "value": 1 },
+ { "source": "Judge", "target": "Valjean", "value": 3 },
+ { "source": "Judge", "target": "Bamatabois", "value": 2 },
+ { "source": "Champmathieu", "target": "Valjean", "value": 3 },
+ { "source": "Champmathieu", "target": "Judge", "value": 3 },
+ { "source": "Champmathieu", "target": "Bamatabois", "value": 2 },
+ { "source": "Brevet", "target": "Judge", "value": 2 },
+ { "source": "Brevet", "target": "Champmathieu", "value": 2 },
+ { "source": "Brevet", "target": "Valjean", "value": 2 },
+ { "source": "Brevet", "target": "Bamatabois", "value": 1 },
+ { "source": "Chenildieu", "target": "Judge", "value": 2 },
+ { "source": "Chenildieu", "target": "Champmathieu", "value": 2 },
+ { "source": "Chenildieu", "target": "Brevet", "value": 2 },
+ { "source": "Chenildieu", "target": "Valjean", "value": 2 },
+ { "source": "Chenildieu", "target": "Bamatabois", "value": 1 },
+ { "source": "Cochepaille", "target": "Judge", "value": 2 },
+ { "source": "Cochepaille", "target": "Champmathieu", "value": 2 },
+ { "source": "Cochepaille", "target": "Brevet", "value": 2 },
+ { "source": "Cochepaille", "target": "Chenildieu", "value": 2 },
+ { "source": "Cochepaille", "target": "Valjean", "value": 2 },
+ { "source": "Cochepaille", "target": "Bamatabois", "value": 1 },
+ { "source": "Pontmercy", "target": "Thenardier", "value": 1 },
+ { "source": "Boulatruelle", "target": "Thenardier", "value": 1 },
+ { "source": "Eponine", "target": "Mme.Thenardier", "value": 2 },
+ { "source": "Eponine", "target": "Thenardier", "value": 3 },
+ { "source": "Anzelma", "target": "Eponine", "value": 2 },
+ { "source": "Anzelma", "target": "Thenardier", "value": 2 },
+ { "source": "Anzelma", "target": "Mme.Thenardier", "value": 1 },
+ { "source": "Woman2", "target": "Valjean", "value": 3 },
+ { "source": "Woman2", "target": "Cosette", "value": 1 },
+ { "source": "Woman2", "target": "Javert", "value": 1 },
+ { "source": "MotherInnocent", "target": "Fauchelevent", "value": 3 },
+ { "source": "MotherInnocent", "target": "Valjean", "value": 1 },
+ { "source": "Gribier", "target": "Fauchelevent", "value": 2 },
+ { "source": "Mme.Burgon", "target": "Jondrette", "value": 1 },
+ { "source": "Gavroche", "target": "Mme.Burgon", "value": 2 },
+ { "source": "Gavroche", "target": "Thenardier", "value": 1 },
+ { "source": "Gavroche", "target": "Javert", "value": 1 },
+ { "source": "Gavroche", "target": "Valjean", "value": 1 },
+ { "source": "Gillenormand", "target": "Cosette", "value": 3 },
+ { "source": "Gillenormand", "target": "Valjean", "value": 2 },
+ { "source": "Magnon", "target": "Gillenormand", "value": 1 },
+ { "source": "Magnon", "target": "Mme.Thenardier", "value": 1 },
+ { "source": "Mlle.Gillenormand", "target": "Gillenormand", "value": 9 },
+ { "source": "Mlle.Gillenormand", "target": "Cosette", "value": 2 },
+ { "source": "Mlle.Gillenormand", "target": "Valjean", "value": 2 },
+ { "source": "Mme.Pontmercy", "target": "Mlle.Gillenormand", "value": 1 },
+ { "source": "Mme.Pontmercy", "target": "Pontmercy", "value": 1 },
+ { "source": "Mlle.Vaubois", "target": "Mlle.Gillenormand", "value": 1 },
+ { "source": "Lt.Gillenormand", "target": "Mlle.Gillenormand", "value": 2 },
+ { "source": "Lt.Gillenormand", "target": "Gillenormand", "value": 1 },
+ { "source": "Lt.Gillenormand", "target": "Cosette", "value": 1 },
+ { "source": "Marius", "target": "Mlle.Gillenormand", "value": 6 },
+ { "source": "Marius", "target": "Gillenormand", "value": 12 },
+ { "source": "Marius", "target": "Pontmercy", "value": 1 },
+ { "source": "Marius", "target": "Lt.Gillenormand", "value": 1 },
+ { "source": "Marius", "target": "Cosette", "value": 21 },
+ { "source": "Marius", "target": "Valjean", "value": 19 },
+ { "source": "Marius", "target": "Tholomyes", "value": 1 },
+ { "source": "Marius", "target": "Thenardier", "value": 2 },
+ { "source": "Marius", "target": "Eponine", "value": 5 },
+ { "source": "Marius", "target": "Gavroche", "value": 4 },
+ { "source": "BaronessT", "target": "Gillenormand", "value": 1 },
+ { "source": "BaronessT", "target": "Marius", "value": 1 },
+ { "source": "Mabeuf", "target": "Marius", "value": 1 },
+ { "source": "Mabeuf", "target": "Eponine", "value": 1 },
+ { "source": "Mabeuf", "target": "Gavroche", "value": 1 },
+ { "source": "Enjolras", "target": "Marius", "value": 7 },
+ { "source": "Enjolras", "target": "Gavroche", "value": 7 },
+ { "source": "Enjolras", "target": "Javert", "value": 6 },
+ { "source": "Enjolras", "target": "Mabeuf", "value": 1 },
+ { "source": "Enjolras", "target": "Valjean", "value": 4 },
+ { "source": "Combeferre", "target": "Enjolras", "value": 15 },
+ { "source": "Combeferre", "target": "Marius", "value": 5 },
+ { "source": "Combeferre", "target": "Gavroche", "value": 6 },
+ { "source": "Combeferre", "target": "Mabeuf", "value": 2 },
+ { "source": "Prouvaire", "target": "Gavroche", "value": 1 },
+ { "source": "Prouvaire", "target": "Enjolras", "value": 4 },
+ { "source": "Prouvaire", "target": "Combeferre", "value": 2 },
+ { "source": "Feuilly", "target": "Gavroche", "value": 2 },
+ { "source": "Feuilly", "target": "Enjolras", "value": 6 },
+ { "source": "Feuilly", "target": "Prouvaire", "value": 2 },
+ { "source": "Feuilly", "target": "Combeferre", "value": 5 },
+ { "source": "Feuilly", "target": "Mabeuf", "value": 1 },
+ { "source": "Feuilly", "target": "Marius", "value": 1 },
+ { "source": "Courfeyrac", "target": "Marius", "value": 9 },
+ { "source": "Courfeyrac", "target": "Enjolras", "value": 17 },
+ { "source": "Courfeyrac", "target": "Combeferre", "value": 13 },
+ { "source": "Courfeyrac", "target": "Gavroche", "value": 7 },
+ { "source": "Courfeyrac", "target": "Mabeuf", "value": 2 },
+ { "source": "Courfeyrac", "target": "Eponine", "value": 1 },
+ { "source": "Courfeyrac", "target": "Feuilly", "value": 6 },
+ { "source": "Courfeyrac", "target": "Prouvaire", "value": 3 },
+ { "source": "Bahorel", "target": "Combeferre", "value": 5 },
+ { "source": "Bahorel", "target": "Gavroche", "value": 5 },
+ { "source": "Bahorel", "target": "Courfeyrac", "value": 6 },
+ { "source": "Bahorel", "target": "Mabeuf", "value": 2 },
+ { "source": "Bahorel", "target": "Enjolras", "value": 4 },
+ { "source": "Bahorel", "target": "Feuilly", "value": 3 },
+ { "source": "Bahorel", "target": "Prouvaire", "value": 2 },
+ { "source": "Bahorel", "target": "Marius", "value": 1 },
+ { "source": "Bossuet", "target": "Marius", "value": 5 },
+ { "source": "Bossuet", "target": "Courfeyrac", "value": 12 },
+ { "source": "Bossuet", "target": "Gavroche", "value": 5 },
+ { "source": "Bossuet", "target": "Bahorel", "value": 4 },
+ { "source": "Bossuet", "target": "Enjolras", "value": 10 },
+ { "source": "Bossuet", "target": "Feuilly", "value": 6 },
+ { "source": "Bossuet", "target": "Prouvaire", "value": 2 },
+ { "source": "Bossuet", "target": "Combeferre", "value": 9 },
+ { "source": "Bossuet", "target": "Mabeuf", "value": 1 },
+ { "source": "Bossuet", "target": "Valjean", "value": 1 },
+ { "source": "Joly", "target": "Bahorel", "value": 5 },
+ { "source": "Joly", "target": "Bossuet", "value": 7 },
+ { "source": "Joly", "target": "Gavroche", "value": 3 },
+ { "source": "Joly", "target": "Courfeyrac", "value": 5 },
+ { "source": "Joly", "target": "Enjolras", "value": 5 },
+ { "source": "Joly", "target": "Feuilly", "value": 5 },
+ { "source": "Joly", "target": "Prouvaire", "value": 2 },
+ { "source": "Joly", "target": "Combeferre", "value": 5 },
+ { "source": "Joly", "target": "Mabeuf", "value": 1 },
+ { "source": "Joly", "target": "Marius", "value": 2 },
+ { "source": "Grantaire", "target": "Bossuet", "value": 3 },
+ { "source": "Grantaire", "target": "Enjolras", "value": 3 },
+ { "source": "Grantaire", "target": "Combeferre", "value": 1 },
+ { "source": "Grantaire", "target": "Courfeyrac", "value": 2 },
+ { "source": "Grantaire", "target": "Joly", "value": 2 },
+ { "source": "Grantaire", "target": "Gavroche", "value": 1 },
+ { "source": "Grantaire", "target": "Bahorel", "value": 1 },
+ { "source": "Grantaire", "target": "Feuilly", "value": 1 },
+ { "source": "Grantaire", "target": "Prouvaire", "value": 1 },
+ { "source": "MotherPlutarch", "target": "Mabeuf", "value": 3 },
+ { "source": "Gueulemer", "target": "Thenardier", "value": 5 },
+ { "source": "Gueulemer", "target": "Valjean", "value": 1 },
+ { "source": "Gueulemer", "target": "Mme.Thenardier", "value": 1 },
+ { "source": "Gueulemer", "target": "Javert", "value": 1 },
+ { "source": "Gueulemer", "target": "Gavroche", "value": 1 },
+ { "source": "Gueulemer", "target": "Eponine", "value": 1 },
+ { "source": "Babet", "target": "Thenardier", "value": 6 },
+ { "source": "Babet", "target": "Gueulemer", "value": 6 },
+ { "source": "Babet", "target": "Valjean", "value": 1 },
+ { "source": "Babet", "target": "Mme.Thenardier", "value": 1 },
+ { "source": "Babet", "target": "Javert", "value": 2 },
+ { "source": "Babet", "target": "Gavroche", "value": 1 },
+ { "source": "Babet", "target": "Eponine", "value": 1 },
+ { "source": "Claquesous", "target": "Thenardier", "value": 4 },
+ { "source": "Claquesous", "target": "Babet", "value": 4 },
+ { "source": "Claquesous", "target": "Gueulemer", "value": 4 },
+ { "source": "Claquesous", "target": "Valjean", "value": 1 },
+ { "source": "Claquesous", "target": "Mme.Thenardier", "value": 1 },
+ { "source": "Claquesous", "target": "Javert", "value": 1 },
+ { "source": "Claquesous", "target": "Eponine", "value": 1 },
+ { "source": "Claquesous", "target": "Enjolras", "value": 1 },
+ { "source": "Montparnasse", "target": "Javert", "value": 1 },
+ { "source": "Montparnasse", "target": "Babet", "value": 2 },
+ { "source": "Montparnasse", "target": "Gueulemer", "value": 2 },
+ { "source": "Montparnasse", "target": "Claquesous", "value": 2 },
+ { "source": "Montparnasse", "target": "Valjean", "value": 1 },
+ { "source": "Montparnasse", "target": "Gavroche", "value": 1 },
+ { "source": "Montparnasse", "target": "Eponine", "value": 1 },
+ { "source": "Montparnasse", "target": "Thenardier", "value": 1 },
+ { "source": "Toussaint", "target": "Cosette", "value": 2 },
+ { "source": "Toussaint", "target": "Javert", "value": 1 },
+ { "source": "Toussaint", "target": "Valjean", "value": 1 },
+ { "source": "Child1", "target": "Gavroche", "value": 2 },
+ { "source": "Child2", "target": "Gavroche", "value": 2 },
+ { "source": "Child2", "target": "Child1", "value": 3 },
+ { "source": "Brujon", "target": "Babet", "value": 3 },
+ { "source": "Brujon", "target": "Gueulemer", "value": 3 },
+ { "source": "Brujon", "target": "Thenardier", "value": 3 },
+ { "source": "Brujon", "target": "Gavroche", "value": 1 },
+ { "source": "Brujon", "target": "Eponine", "value": 1 },
+ { "source": "Brujon", "target": "Claquesous", "value": 1 },
+ { "source": "Brujon", "target": "Montparnasse", "value": 1 },
+ { "source": "Mme.Hucheloup", "target": "Bossuet", "value": 1 },
+ { "source": "Mme.Hucheloup", "target": "Joly", "value": 1 },
+ { "source": "Mme.Hucheloup", "target": "Grantaire", "value": 1 },
+ { "source": "Mme.Hucheloup", "target": "Bahorel", "value": 1 },
+ { "source": "Mme.Hucheloup", "target": "Courfeyrac", "value": 1 },
+ { "source": "Mme.Hucheloup", "target": "Gavroche", "value": 1 },
+ { "source": "Mme.Hucheloup", "target": "Enjolras", "value": 1 }
+ ]
+}
diff --git a/docs/examples/orientation.md b/docs/examples/orientation.md
new file mode 100644
index 0000000..1c69dde
--- /dev/null
+++ b/docs/examples/orientation.md
@@ -0,0 +1,60 @@
+---
+title: Tree Orientations
+---
+
+# Tree Orientations
+
+
+
+## Horizontal
+
+
+
+### Code
+
+:::code-group
+
+<<< ./tree.ts#horizontal [config]
+
+<<< ./tree.ts#data [data]
+
+:::
+
+## Vertical
+
+
+
+### Code
+
+:::code-group
+
+<<< ./tree.ts#vertical [config]
+
+<<< ./tree.ts#data [data]
+
+:::
+
+## Radial
+
+
+
+### Code
+
+:::code-group
+
+<<< ./tree.ts#radial [config]
+
+<<< ./tree.ts#data [data]
+
+:::
diff --git a/docs/examples/tree.json b/docs/examples/tree.json
new file mode 100644
index 0000000..755b292
--- /dev/null
+++ b/docs/examples/tree.json
@@ -0,0 +1,25 @@
+[
+ { "name": "1" },
+ { "name": "11", "parent": 0 },
+ { "name": "111", "parent": 1 },
+ { "name": "1111", "parent": 2 },
+ { "name": "1112", "parent": 2 },
+ { "name": "112", "parent": 1 },
+ { "name": "1121", "parent": 5 },
+ { "name": "1122", "parent": 5 },
+ { "name": "113", "parent": 1 },
+ { "name": "1131", "parent": 8 },
+ { "name": "1132", "parent": 8 },
+ { "name": "12", "parent": 0 },
+ { "name": "121", "parent": 11 },
+ { "name": "1211", "parent": 12 },
+ { "name": "1212", "parent": 12 },
+ { "name": "122", "parent": 11 },
+ { "name": "1221", "parent": 15 },
+ { "name": "1222", "parent": 15 },
+ { "name": "123", "parent": 11 },
+ { "name": "1231", "parent": 18 },
+ { "name": "1232", "parent": 18 },
+ { "name": "13", "parent": 0 },
+ { "name": "131", "parent": 21 }
+]
diff --git a/docs/examples/tree.md b/docs/examples/tree.md
new file mode 100644
index 0000000..16a66d2
--- /dev/null
+++ b/docs/examples/tree.md
@@ -0,0 +1,24 @@
+---
+title: Tree
+---
+
+# Tree
+
+
+
+
+
+### Code
+
+:::code-group
+
+<<< ./tree.ts#config [config]
+
+<<< ./tree.ts#data [data]
+
+:::
diff --git a/docs/examples/tree.ts b/docs/examples/tree.ts
new file mode 100644
index 0000000..f9f944b
--- /dev/null
+++ b/docs/examples/tree.ts
@@ -0,0 +1,85 @@
+import type { ChartConfiguration } from 'chart.js';
+import type {} from '../../src';
+import 'chartjs-plugin-datalabels';
+
+// #region data
+import nodes from './tree.json';
+
+export const data: ChartConfiguration<'tree'>['data'] = {
+ labels: nodes.map((d) => d.name),
+ datasets: [
+ {
+ pointBackgroundColor: 'steelblue',
+ pointRadius: 5,
+ data: nodes.map((d) => Object.assign({}, d)),
+ edgeLineBorderWidth: (ctx) => {
+ return ctx.dataIndex;
+ },
+ },
+ ],
+};
+// #endregion data
+// #region tree
+export const config: ChartConfiguration<'tree'> = {
+ type: 'tree',
+ data,
+ options: {
+ plugins: {
+ datalabels: {
+ display: false,
+ },
+ },
+ tree: {
+ mode: 'tree',
+ },
+ },
+};
+// #endregion tree
+// #region horizontal
+export const horizontal: ChartConfiguration<'tree'> = {
+ type: 'tree',
+ data,
+ options: {
+ plugins: {
+ datalabels: {
+ display: false,
+ },
+ },
+ tree: {
+ orientation: 'horizontal',
+ },
+ },
+};
+// #endregion horizontal
+// #region vertical
+export const vertical: ChartConfiguration<'tree'> = {
+ type: 'tree',
+ data,
+ options: {
+ plugins: {
+ datalabels: {
+ display: false,
+ },
+ },
+ tree: {
+ orientation: 'vertical',
+ },
+ },
+};
+// #endregion vertical
+// #region radial
+export const radial: ChartConfiguration<'tree'> = {
+ type: 'tree',
+ data,
+ options: {
+ plugins: {
+ datalabels: {
+ display: false,
+ },
+ },
+ tree: {
+ orientation: 'radial',
+ },
+ },
+};
+// #endregion radial
diff --git a/docs/getting-started.md b/docs/getting-started.md
new file mode 100644
index 0000000..d21138b
--- /dev/null
+++ b/docs/getting-started.md
@@ -0,0 +1,41 @@
+---
+title: Getting Started
+---
+
+Chart.js module for charting graphs. Adding new chart types: `graph`, `forceDirectedGraph`, `dendrogram`, and `tree`.
+
+![force](https://user-images.githubusercontent.com/4129778/65398353-9bc03f80-dd84-11e9-8f14-339635c1ba4e.png)
+
+![dend_h](https://user-images.githubusercontent.com/4129778/65398352-9bc03f80-dd84-11e9-9197-ecb66a872736.png)
+
+![tree_v](https://user-images.githubusercontent.com/4129778/65398350-9bc03f80-dd84-11e9-8c94-e93c07040ee7.png)
+
+![radial](https://user-images.githubusercontent.com/4129778/65398354-9bc03f80-dd84-11e9-9633-c4c80bd9c384.png)
+
+Works great with https://github.com/chartjs/chartjs-plugin-datalabels or https://github.com/chrispahm/chartjs-plugin-dragdata
+
+## Install
+
+```sh
+npm install chart.js chartjs-chart-graph
+```
+
+## Usage
+
+see [Examples](./examples/)
+
+CodePens
+
+- [Force Directed Layout](https://codepen.io/sgratzl/pen/mdezvmL)
+- [Tree Layouts](https://codepen.io/sgratzl/pen/jObedwg)
+- [Tree With Data Labels](https://codepen.io/sgratzl/pen/vYNVbgd)
+
+## Configuration
+
+### Data Structure
+
+TODO
+
+### Styling
+
+The new chart types are based on the existing `line` controller. Tho, instead of showing a line per dataset it shows edges as lines. Therefore, the styling options for points and lines are the same. See also https://www.chartjs.org/docs/latest/charts/line.html. However, to avoid confusion, the line options have a default `line` prefix, e..g `lineBorderColor` to specify the edge border color and `pointBorderColor` to specify the node border color.
diff --git a/docs/index.md b/docs/index.md
new file mode 100644
index 0000000..92cd4cd
--- /dev/null
+++ b/docs/index.md
@@ -0,0 +1,22 @@
+---
+# https://vitepress.dev/reference/default-theme-home-page
+layout: home
+
+hero:
+ name: 'chartjs-chart-graph'
+ text: 'chart.js plugin'
+ tagline: Chart.js module for charting graphs
+ 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