Replies: 2 comments
|
You can absolutely build a custom plugin that internally uses Here is the approach: import annotationPlugin from "chartjs-plugin-annotation";
import { Chart } from "chart.js";
// Make sure annotation plugin is registered
Chart.register(annotationPlugin);
const waterfallPlugin = {
id: "waterfall",
beforeInit(chart) {
const waterfallOpts = chart.options.plugins.waterfall;
if (!waterfallOpts) return;
// Convert simple values into floating bar data + annotations
const values = waterfallOpts.values; // e.g. [100, -20, 30, -10, 50]
const labels = waterfallOpts.labels;
let cumulative = 0;
const floatingData = [];
const annotations = {};
values.forEach((val, i) => {
const start = cumulative;
cumulative += val;
floatingData.push([Math.min(start, cumulative), Math.max(start, cumulative)]);
// Add connector line annotation between bars
if (i < values.length - 1) {
annotations[`connector-${i}`] = {
type: "line",
xMin: i + 0.4,
xMax: i + 0.6,
yMin: cumulative,
yMax: cumulative,
borderColor: "grey",
borderWidth: 1,
borderDash: [4, 4],
};
}
});
// Inject computed data into chart config
chart.data.datasets[0].data = floatingData;
chart.data.labels = labels;
// Merge annotations into existing annotation config
chart.options.plugins.annotation = chart.options.plugins.annotation || {};
chart.options.plugins.annotation.annotations = {
...chart.options.plugins.annotation.annotations,
...annotations,
};
},
};
Chart.register(waterfallPlugin);Then usage becomes: new Chart(ctx, {
type: "bar",
data: { datasets: [{ backgroundColor: ["green", "red", "green", "red", "green"] }] },
options: {
plugins: {
waterfall: {
values: [100, -20, 30, -10, 50],
labels: ["Start", "Loss", "Gain", "Loss", "Gain"],
},
},
},
});The trick is to use One thing to watch: make sure your plugin is registered after the annotation plugin, or use |
|
You can create a custom waterfall chart plugin by extending the bar chart. Here is a complete example: 1. Create the plugin: const waterfallPlugin = {
id: "waterfall",
beforeInit(chart) {
const data = chart.data;
if (data.datasets[0] && data.datasets[0].waterfall) {
// Transform data for waterfall
const values = data.datasets[0].data;
let cumulative = 0;
const minValues = [];
const maxValues = [];
values.forEach((value, i) => {
if (i === 0) {
minValues.push(0);
maxValues.push(value);
cumulative = value;
} else {
if (value >= 0) {
minValues.push(cumulative);
maxValues.push(cumulative + value);
cumulative += value;
} else {
maxValues.push(cumulative);
minValues.push(cumulative + value);
cumulative += value;
}
}
});
// Replace data with floating bar data
data.datasets[0].data = minValues.map((min, i) => [min, maxValues[i]]);
}
}
};2. Register the plugin: Chart.register(waterfallPlugin);3. Use it: const chart = new Chart(ctx, {
type: "bar",
data: {
labels: ["Start", "Revenue", "Costs", "Tax", "Profit"],
datasets: [{
data: [100, 50, -30, -10, null], // null = total bar
waterfall: true,
backgroundColor: (ctx) => {
const value = ctx.dataset.data[ctx.dataIndex];
if (Array.isArray(value)) {
return value[1] > value[0] ? "#4ade80" : "#f87171";
}
return "#60a5fa"; // Total bar
}
}]
},
options: {
plugins: {
tooltip: {
callbacks: {
label: (ctx) => {
const value = ctx.dataset.data[ctx.dataIndex];
if (Array.isArray(value)) {
return `Change: ${value[1] - value[0]}`;
}
return `Total: ${value}`;
}
}
}
}
}
});4. For the annotation plugin approach: If you want to use the annotation plugin, you can create connector lines: const connectorPlugin = {
id: "waterfallConnectors",
afterDraw(chart) {
const meta = chart.getDatasetMeta(0);
const ctx = chart.ctx;
meta.data.forEach((bar, i) => {
if (i < meta.data.length - 1) {
const nextBar = meta.data[i + 1];
ctx.beginPath();
ctx.moveTo(bar.x + bar.width / 2, bar.y);
ctx.lineTo(nextBar.x - nextBar.width / 2, nextBar.y);
ctx.strokeStyle = "#94a3b8";
ctx.setLineDash([4, 4]);
ctx.stroke();
}
});
}
};This creates a waterfall chart where you just pass the values, and the plugin handles the cumulative calculations. |
Uh oh!
There was an error while loading. Please reload this page.
In my case, I would like to write a custom waterfall chart plugin.
I can already simulate it using the annotation plugin.
Now I want to wrap the whole logic into a custom plugin, so all I need to use it is just simply passing the values for each bar (without needing to pass
[minValue, maxValue]like in typical floating bar)How can I achieve this?
All reactions