],
[
'vuepress-plugin-typedoc',
-
{
entryPoints: ['../../types/index.esm.d.ts'],
hideInPageTOC: true,
imports: [
['scripts/register.js'],
['scripts/utils.js', 'Utils'],
+ ['scripts/helpers.js', 'helpers'],
+ ['scripts/components.js', 'components']
]
},
nav: [
{text: 'Home', link: '/'},
{text: 'API', link: '/api/'},
// TODO: Make local when samples moved to vuepress
- {text: 'Samples', link: `https://www.chartjs.org/samples/${docsVersion}/`},
+ {text: 'Samples', link: `/samples/`},
{
text: 'Ecosystem',
ariaLabel: 'Community Menu',
'/api/': {
title: 'API'
},
+ '/samples/': [
+ '',
+ {
+ title: 'Bar Charts',
+ children: [
+ 'bar/vertical',
+ 'bar/horizontal',
+ 'bar/stacked',
+ 'bar/stacked-groups',
+ 'bar/floating',
+ 'bar/border-radius',
+ ]
+ },
+ {
+ title: 'Line Charts',
+ children: [
+ 'line/line',
+ 'line/multi-axis',
+ 'line/stepped',
+ 'line/interpolation',
+ 'line/styling',
+ // 'line/point-styling',
+ ]
+ },
+ {
+ title: 'Other charts',
+ children: [
+ 'other-charts/bubble',
+ 'other-charts/scatter',
+ 'other-charts/scatter-multi-axis',
+ 'other-charts/doughnut',
+ 'other-charts/pie',
+ 'other-charts/multi-series-pie',
+ 'other-charts/polar-area',
+ 'other-charts/radar',
+ 'other-charts/radar-skip-points',
+ 'other-charts/combo-bar-line',
+ ]
+ },
+ {
+ title: 'Area charts',
+ children: [
+ 'area/line-boundaries',
+ 'area/line-datasets',
+ 'area/line-stacked',
+ 'area/radar'
+ ]
+ },
+ {
+ title: 'Scales',
+ children: [
+ 'scales/linear-min-max',
+ 'scales/linear-min-max-suggested',
+ 'scales/linear-step-size',
+ 'scales/log',
+ 'scales/time-line',
+ 'scales/time-max-span',
+ 'scales/time-combo',
+ ]
+ },
+ {
+ title: 'Scale Options',
+ children: [
+ 'scale-options/grid',
+ 'scale-options/ticks',
+ 'scale-options/titles',
+ 'scale-options/center'
+ ]
+ },
+ {
+ title: 'Legend',
+ children: [
+ 'legend/position',
+ 'legend/title',
+ 'legend/point-style',
+ ]
+ },
+ {
+ title: 'Title',
+ children: [
+ 'title/alignment',
+ ]
+ },
+ {
+ title: 'Tooltip',
+ children: [
+ 'tooltip/position',
+ 'tooltip/interactions',
+ 'tooltip/point-style',
+ 'tooltip/content',
+ 'tooltip/html',
+ ]
+ },
+ {
+ title: 'Scriptable Options',
+ children: [
+ 'scriptable/bar',
+ 'scriptable/bubble',
+ 'scriptable/pie',
+ 'scriptable/line',
+ 'scriptable/polar',
+ 'scriptable/radar',
+ ]
+ },
+ {
+ title: 'Animations',
+ children: [
+ 'animations/delay',
+ 'animations/drop',
+ 'animations/loop',
+ 'animations/progressive-line',
+ ]
+ },
+ {
+ title: 'Advanced',
+ children: [
+ 'advanced/progress-bar',
+ 'advanced/radial-gradient',
+ 'advanced/linear-gradient',
+ 'advanced/programmatic-events',
+ 'advanced/derived-axis-type',
+ 'advanced/derived-chart-type',
+ ]
+ },
+ ],
'/': [
'',
{
--- /dev/null
+# Derived Axis Type
+
+```js chart-editor
+// <block:setup:1>
+const DATA_COUNT = 12;
+const NUMBER_CFG = {count: DATA_COUNT, min: 0, max: 1000};
+const labels = Utils.months({count: DATA_COUNT});
+const data = {
+ labels: labels,
+ datasets: [
+ {
+ label: 'My First dataset',
+ data: Utils.numbers(NUMBER_CFG),
+ borderColor: Utils.CHART_COLORS.red,
+ backgroundColor: Utils.transparentize(Utils.CHART_COLORS.red, 0.5),
+ fill: false,
+ }
+ ],
+};
+// </block:setup>
+
+// <block:config:0>
+const config = {
+ type: 'line',
+ data,
+ options: {
+ responsive: true,
+ scales: {
+ x: {
+ display: true,
+ },
+ y: {
+ display: true,
+ type: 'log2',
+ }
+ }
+ }
+};
+
+// </block:config>
+
+module.exports = {
+ actions: [],
+ config: config,
+};
+```
+
+## Log2 axis implementation
+
+<<< @/docs/scripts/log2.js
--- /dev/null
+# Derived Chart Type
+
+```js chart-editor
+// <block:setup:1>
+const DATA_COUNT = 7;
+const NUMBER_CFG = {count: DATA_COUNT, min: -100, max: 100, rmin: 1, rmax: 20};
+const data = {
+ datasets: [
+ {
+ label: 'My First dataset',
+ backgroundColor: Utils.transparentize(Utils.CHART_COLORS.blue, 0.5),
+ borderColor: Utils.CHART_COLORS.blue,
+ borderWidth: 1,
+ boxStrokeStyle: 'red',
+ data: Utils.bubbles(NUMBER_CFG)
+ }
+ ],
+};
+// </block:setup>
+
+// <block:config:0>
+const config = {
+ type: 'derivedBubble',
+ data: data,
+ options: {
+ responsive: true,
+ plugins: {
+ title: {
+ display: true,
+ text: 'Derived Chart Type'
+ },
+ }
+ }
+};
+
+// </block:config>
+
+module.exports = {
+ actions: [],
+ config: config,
+};
+```
+
+## DerivedBubble Implementation
+
+<<< @/docs/scripts/derived-bubble.js
--- /dev/null
+# Linear Gradient
+
+```js chart-editor
+// <block:actions:3>
+const actions = [
+ {
+ name: 'Randomize',
+ handler(chart) {
+ chart.data.datasets.forEach(dataset => {
+ dataset.data = Utils.numbers({count: chart.data.labels.length, min: -100, max: 100});
+ });
+ chart.update();
+ }
+ },
+ {
+ name: 'Add Data',
+ handler(chart) {
+ const data = chart.data;
+ if (data.datasets.length > 0) {
+ data.labels = Utils.months({count: data.labels.length + 1});
+
+ for (var index = 0; index < data.datasets.length; ++index) {
+ data.datasets[index].data.push(Utils.rand(-100, 100));
+ }
+
+ chart.update();
+ }
+ }
+ },
+ {
+ name: 'Remove Data',
+ handler(chart) {
+ chart.data.labels.splice(-1, 1); // remove the label first
+
+ chart.data.datasets.forEach(dataset => {
+ dataset.data.pop();
+ });
+
+ chart.update();
+ }
+ }
+];
+// </block:actions>
+
+// <block:getGradient:0>
+let width, height, gradient;
+function getGradient(ctx, chartArea) {
+ const chartWidth = chartArea.right - chartArea.left;
+ const chartHeight = chartArea.bottom - chartArea.top;
+ if (gradient === null || width !== chartWidth || height !== chartHeight) {
+ // Create the gradient because this is either the first render
+ // or the size of the chart has changed
+ width = chartWidth;
+ height = chartHeight;
+ gradient = ctx.createLinearGradient(0, chartArea.bottom, 0, chartArea.top);
+ gradient.addColorStop(0, Utils.CHART_COLORS.blue);
+ gradient.addColorStop(0.5, Utils.CHART_COLORS.yellow);
+ gradient.addColorStop(1, Utils.CHART_COLORS.red);
+ }
+
+ return gradient;
+}
+// </block:getGradient>
+
+// <block:setup:2>
+const DATA_COUNT = 7;
+const NUMBER_CFG = {count: DATA_COUNT, min: -100, max: 100};
+const labels = Utils.months({count: 7});
+
+const data = {
+ labels: labels,
+ datasets: [
+ {
+ label: 'Dataset 1',
+ data: Utils.numbers(NUMBER_CFG),
+ borderColor: function(context) {
+ const chart = context.chart;
+ const {ctx, chartArea} = chart;
+
+ if (!chartArea) {
+ // This case happens on initial chart load
+ return null;
+ }
+ return getGradient(ctx, chartArea);
+ },
+ },
+ ]
+};
+// </block:setup>
+
+// <block:config:1>
+const config = {
+ type: 'line',
+ data: data,
+ options: {
+ responsive: true,
+ plugins: {
+ legend: {
+ position: 'top',
+ },
+ }
+ },
+};
+// </block:config>
+
+module.exports = {
+ actions: actions,
+ config: config,
+};
+```
--- /dev/null
+# Programmatic Event Triggers
+
+```js chart-editor
+// <block:hover:0>
+function triggerHover(chart) {
+ if (chart.getActiveElements().length > 0) {
+ chart.setActiveElements([]);
+ } else {
+ chart.setActiveElements([
+ {
+ datasetIndex: 0,
+ index: 0,
+ }, {
+ datasetIndex: 1,
+ index: 0,
+ }
+ ]);
+ }
+ chart.update();
+}
+// </block:hover>
+
+// <block:tooltip:1>
+function triggerTooltip(chart) {
+ const tooltip = chart.tooltip;
+ if (tooltip.getActiveElements().length > 0) {
+ tooltip.setActiveElements([], {x: 0, y: 0});
+ } else {
+ const chartArea = chart.chartArea;
+ tooltip.setActiveElements([
+ {
+ datasetIndex: 0,
+ index: 2,
+ }, {
+ datasetIndex: 1,
+ index: 2,
+ }
+ ],
+ {
+ x: (chartArea.left + chartArea.right) / 2,
+ y: (chartArea.top + chartArea.bottom) / 2,
+ });
+ }
+
+ chart.update();
+}
+// </block:tooltip>
+
+// <block:actions:2>
+const actions = [
+ {
+ name: 'Trigger Hover',
+ handler: triggerHover
+ },
+ {
+ name: 'Trigger Tooltip',
+ handler: triggerTooltip
+ }
+];
+// </block:actions>
+
+// <block:setup:4>
+const DATA_COUNT = 7;
+const NUMBER_CFG = {count: DATA_COUNT, min: -100, max: 100};
+
+const labels = Utils.months({count: 7});
+const data = {
+ labels: labels,
+ datasets: [
+ {
+ label: 'Dataset 1',
+ data: Utils.numbers(NUMBER_CFG),
+ borderColor: Utils.CHART_COLORS.red,
+ backgroundColor: Utils.transparentize(Utils.CHART_COLORS.red, 0.5),
+ hoverBorderWidth: 5,
+ hoverBorderColor: 'green',
+ },
+ {
+ label: 'Dataset 2',
+ data: Utils.numbers(NUMBER_CFG),
+ borderColor: Utils.CHART_COLORS.blue,
+ backgroundColor: Utils.transparentize(Utils.CHART_COLORS.blue, 0.5),
+ hoverBorderWidth: 5,
+ hoverBorderColor: 'green',
+ }
+ ]
+};
+// </block:setup>
+
+// <block:config:3>
+const config = {
+ type: 'bar',
+ data: data,
+ options: {
+ },
+};
+// </block:config>
+
+module.exports = {
+ actions: actions,
+ config: config,
+};
+```
--- /dev/null
+# Animation Progress Bar
+
+<progress id="animationProgress" max="1" value="0" style="width: 100%"></progress>
+
+```js chart-editor
+// <block:actions:2>
+const actions = [
+ {
+ name: 'Randomize',
+ handler(chart) {
+ chart.data.datasets.forEach(dataset => {
+ dataset.data = Utils.numbers({count: chart.data.labels.length, min: -100, max: 100});
+ });
+ chart.update();
+ }
+ },
+ {
+ name: 'Add Dataset',
+ handler(chart) {
+ const data = chart.data;
+ const dsColor = Utils.namedColor(chart.data.datasets.length);
+ const newDataset = {
+ label: 'Dataset ' + (data.datasets.length + 1),
+ backgroundColor: Utils.transparentize(dsColor, 0.5),
+ borderColor: dsColor,
+ borderWidth: 1,
+ data: Utils.numbers({count: data.labels.length, min: -100, max: 100}),
+ };
+ chart.data.datasets.push(newDataset);
+ chart.update();
+ }
+ },
+ {
+ name: 'Add Data',
+ handler(chart) {
+ const data = chart.data;
+ if (data.datasets.length > 0) {
+ data.labels = Utils.months({count: data.labels.length + 1});
+
+ for (var index = 0; index < data.datasets.length; ++index) {
+ data.datasets[index].data.push(Utils.rand(-100, 100));
+ }
+
+ chart.update();
+ }
+ }
+ },
+ {
+ name: 'Remove Dataset',
+ handler(chart) {
+ chart.data.datasets.pop();
+ chart.update();
+ }
+ },
+ {
+ name: 'Remove Data',
+ handler(chart) {
+ chart.data.labels.splice(-1, 1); // remove the label first
+
+ chart.data.datasets.forEach(dataset => {
+ dataset.data.pop();
+ });
+
+ chart.update();
+ }
+ }
+];
+// </block:actions>
+
+// <block:setup:1>
+const progress = document.getElementById('animationProgress');
+
+const DATA_COUNT = 7;
+const NUMBER_CFG = {count: DATA_COUNT, min: -100, max: 100};
+
+const labels = Utils.months({count: 7});
+const data = {
+ labels: labels,
+ datasets: [
+ {
+ label: 'Dataset 1',
+ data: Utils.numbers(NUMBER_CFG),
+ borderColor: Utils.CHART_COLORS.red,
+ backgroundColor: Utils.transparentize(Utils.CHART_COLORS.red, 0.5),
+ },
+ {
+ label: 'Dataset 2',
+ data: Utils.numbers(NUMBER_CFG),
+ borderColor: Utils.CHART_COLORS.blue,
+ backgroundColor: Utils.transparentize(Utils.CHART_COLORS.blue, 0.5),
+ }
+ ]
+};
+// </block:setup>
+
+// <block:config:0>
+const config = {
+ type: 'line',
+ data: data,
+ options: {
+ animation: {
+ duration: 2000,
+ onProgress: function(animation) {
+ progress.value = animation.currentStep / animation.numSteps;
+ },
+ onComplete: function() {
+ //
+ }
+ },
+ interaction: {
+ mode: 'nearest',
+ axis: 'x',
+ intersect: false
+ },
+ plugins: {
+ title: {
+ display: true,
+ text: 'Chart.js Line Chart - Animation Progress Bar'
+ }
+ },
+ },
+};
+// </block:config>
+
+module.exports = {
+ actions: actions,
+ config: config,
+};
+```
--- /dev/null
+# Radial Gradient
+
+```js chart-editor
+// <block:setup:3>
+const DATA_COUNT = 5;
+Utils.srand(110);
+
+const chartColors = Utils.CHART_COLORS;
+const colors = [chartColors.red, chartColors.orange, chartColors.yellow, chartColors.green, chartColors.blue];
+
+const cache = new Map();
+let width = null;
+let height = null;
+
+const actions = [
+ {
+ name: 'Randomize',
+ handler(chart) {
+ chart.data.datasets.forEach(dataset => {
+ dataset.data = generateData();
+ });
+ chart.update();
+ }
+ },
+];
+// </block:setup>
+
+// <block:createRadialGradient3:0>
+function createRadialGradient3(context, c1, c2, c3) {
+ const chartArea = context.chart.chartArea;
+ if (!chartArea) {
+ // This case happens on initial chart load
+ return null;
+ }
+
+ const chartWidth = chartArea.right - chartArea.left;
+ const chartHeight = chartArea.bottom - chartArea.top;
+ if (width !== chartWidth || height !== chartHeight) {
+ cache.clear();
+ }
+ var gradient = cache.get(c1 + c2 + c3);
+ if (!gradient) {
+ // Create the gradient because this is either the first render
+ // or the size of the chart has changed
+ width = chartWidth;
+ height = chartHeight;
+ const centerX = (chartArea.left + chartArea.right) / 2;
+ const centerY = (chartArea.top + chartArea.bottom) / 2;
+ const r = Math.min(
+ (chartArea.right - chartArea.left) / 2,
+ (chartArea.bottom - chartArea.top) / 2
+ );
+ var ctx = context.chart.ctx;
+ gradient = ctx.createRadialGradient(centerX, centerY, 0, centerX, centerY, r);
+ gradient.addColorStop(0, c1);
+ gradient.addColorStop(0.5, c2);
+ gradient.addColorStop(1, c3);
+ cache.set(c1 + c2 + c3, gradient);
+ }
+
+ return gradient;
+}
+// </block:createRadialGradient3>
+
+// <block:data:2>
+function generateData() {
+ return Utils.numbers({
+ count: DATA_COUNT,
+ min: 0,
+ max: 100
+ });
+}
+
+const data = {
+ labels: Utils.months({count: DATA_COUNT}),
+ datasets: [{
+ data: generateData()
+ }]
+};
+// </block:data>
+
+// <block:config:1>
+const config = {
+ type: 'polarArea',
+ data: data,
+ options: {
+ plugins: {
+ legend: false,
+ tooltip: false,
+ },
+ elements: {
+ arc: {
+ backgroundColor: function(context) {
+ let c = colors[context.dataIndex];
+ if (!c) {
+ return;
+ }
+ if (context.active) {
+ c = helpers.getHoverColor(c);
+ }
+ const mid = helpers.color(c).desaturate(0.2).darken(0.2).rgbString();
+ const start = helpers.color(c).lighten(0.2).rotate(270).rgbString();
+ const end = helpers.color(c).lighten(0.1).rgbString();
+ return createRadialGradient3(context, start, mid, end);
+ },
+ }
+ }
+ }
+};
+// </block:config>
+
+module.exports = {
+ actions,
+ config,
+};
+```
--- /dev/null
+# Delay
+
+```js chart-editor
+// <block:actions:2>
+const actions = [
+ {
+ name: 'Randomize',
+ handler(chart) {
+ chart.data.datasets.forEach(dataset => {
+ dataset.data = Utils.numbers({count: chart.data.labels.length, min: -100, max: 100});
+ });
+ chart.update();
+ }
+ },
+];
+// </block:actions>
+
+// <block:setup:1>
+const DATA_COUNT = 7;
+const NUMBER_CFG = {count: DATA_COUNT, min: -100, max: 100};
+
+const labels = Utils.months({count: 7});
+const data = {
+ labels: labels,
+ datasets: [
+ {
+ label: 'Dataset 1',
+ data: Utils.numbers(NUMBER_CFG),
+ backgroundColor: Utils.CHART_COLORS.red,
+ },
+ {
+ label: 'Dataset 2',
+ data: Utils.numbers(NUMBER_CFG),
+ backgroundColor: Utils.CHART_COLORS.blue,
+ },
+ {
+ label: 'Dataset 3',
+ data: Utils.numbers(NUMBER_CFG),
+ backgroundColor: Utils.CHART_COLORS.green,
+ },
+ ]
+};
+// </block:setup>
+
+// <block:config:0>
+var delayed;
+const config = {
+ type: 'bar',
+ data: data,
+ options: {
+ animation: {
+ onComplete: () => {
+ delayed = true;
+ },
+ delay: (context) => {
+ let delay = 0;
+ if (context.type === 'data' && context.mode === 'default' && !delayed) {
+ delay = context.dataIndex * 300 + context.datasetIndex * 100;
+ }
+ return delay;
+ },
+ },
+ scales: {
+ x: {
+ stacked: true,
+ },
+ y: {
+ stacked: true
+ }
+ }
+ }
+};
+// </block:config>
+
+module.exports = {
+ actions: actions,
+ config: config,
+};
+```
--- /dev/null
+# Drop
+
+```js chart-editor
+// <block:actions:2>
+const actions = [
+ {
+ name: 'Randomize',
+ handler(chart) {
+ chart.data.datasets.forEach(dataset => {
+ dataset.data = Utils.numbers({count: chart.data.labels.length, min: -100, max: 100});
+ });
+ chart.update();
+ }
+ },
+ {
+ name: 'Add Dataset',
+ handler(chart) {
+ const data = chart.data;
+ const dsColor = Utils.namedColor(chart.data.datasets.length);
+ const newDataset = {
+ label: 'Dataset ' + (data.datasets.length + 1),
+ backgroundColor: Utils.transparentize(dsColor, 0.5),
+ borderColor: dsColor,
+ borderWidth: 1,
+ data: Utils.numbers({count: data.labels.length, min: -100, max: 100}),
+ };
+ chart.data.datasets.push(newDataset);
+ chart.update();
+ }
+ },
+ {
+ name: 'Add Data',
+ handler(chart) {
+ const data = chart.data;
+ if (data.datasets.length > 0) {
+ data.labels = Utils.months({count: data.labels.length + 1});
+
+ for (var index = 0; index < data.datasets.length; ++index) {
+ data.datasets[index].data.push(Utils.rand(-100, 100));
+ }
+
+ chart.update();
+ }
+ }
+ },
+ {
+ name: 'Remove Dataset',
+ handler(chart) {
+ chart.data.datasets.pop();
+ chart.update();
+ }
+ },
+ {
+ name: 'Remove Data',
+ handler(chart) {
+ chart.data.labels.splice(-1, 1); // remove the label first
+
+ chart.data.datasets.forEach(dataset => {
+ dataset.data.pop();
+ });
+
+ chart.update();
+ }
+ }
+];
+// </block:actions>
+
+// <block:setup:1>
+const DATA_COUNT = 7;
+const NUMBER_CFG = {count: DATA_COUNT, min: -100, max: 100};
+
+const labels = Utils.months({count: 7});
+const data = {
+ labels: labels,
+ datasets: [
+ {
+ label: 'Dataset 1',
+ animations: {
+ y: {
+ duration: 2000,
+ delay: 500
+ }
+ },
+ data: Utils.numbers(NUMBER_CFG),
+ borderColor: Utils.CHART_COLORS.red,
+ backgroundColor: Utils.transparentize(Utils.CHART_COLORS.red, 0.5),
+ fill: 1,
+ tension: 0.5
+ },
+ {
+ label: 'Dataset 2',
+ data: Utils.numbers(NUMBER_CFG),
+ borderColor: Utils.CHART_COLORS.blue,
+ backgroundColor: Utils.transparentize(Utils.CHART_COLORS.blue, 0.5),
+ }
+ ]
+};
+// </block:setup>
+
+// <block:config:0>
+const config = {
+ type: 'line',
+ data: data,
+ options: {
+ animations: {
+ y: {
+ easing: 'easeInOutElastic',
+ from: (ctx) => {
+ if (ctx.type === 'data') {
+ if (ctx.mode === 'default' && !ctx.dropped) {
+ ctx.dropped = true;
+ return 0;
+ }
+ }
+ }
+ }
+ },
+ },
+};
+// </block:config>
+
+module.exports = {
+ actions: actions,
+ config: config,
+};
+```
--- /dev/null
+# Loop
+
+```js chart-editor
+// <block:actions:2>
+const actions = [
+ {
+ name: 'Randomize',
+ handler(chart) {
+ chart.data.datasets.forEach(dataset => {
+ dataset.data = Utils.numbers({count: chart.data.labels.length, min: -100, max: 100});
+ });
+ chart.update();
+ }
+ },
+ {
+ name: 'Add Dataset',
+ handler(chart) {
+ const data = chart.data;
+ const dsColor = Utils.namedColor(chart.data.datasets.length);
+ const newDataset = {
+ label: 'Dataset ' + (data.datasets.length + 1),
+ backgroundColor: Utils.transparentize(dsColor, 0.5),
+ borderColor: dsColor,
+ borderWidth: 1,
+ data: Utils.numbers({count: data.labels.length, min: -100, max: 100}),
+ };
+ chart.data.datasets.push(newDataset);
+ chart.update();
+ }
+ },
+ {
+ name: 'Add Data',
+ handler(chart) {
+ const data = chart.data;
+ if (data.datasets.length > 0) {
+ data.labels = Utils.months({count: data.labels.length + 1});
+
+ for (var index = 0; index < data.datasets.length; ++index) {
+ data.datasets[index].data.push(Utils.rand(-100, 100));
+ }
+
+ chart.update();
+ }
+ }
+ },
+ {
+ name: 'Remove Dataset',
+ handler(chart) {
+ chart.data.datasets.pop();
+ chart.update();
+ }
+ },
+ {
+ name: 'Remove Data',
+ handler(chart) {
+ chart.data.labels.splice(-1, 1); // remove the label first
+
+ chart.data.datasets.forEach(dataset => {
+ dataset.data.pop();
+ });
+
+ chart.update();
+ }
+ }
+];
+// </block:actions>
+
+// <block:setup:1>
+const DATA_COUNT = 7;
+const NUMBER_CFG = {count: DATA_COUNT, min: -100, max: 100};
+
+const labels = Utils.months({count: DATA_COUNT});
+const data = {
+ labels: labels,
+ datasets: [
+ {
+ label: 'Dataset 1',
+ data: Utils.numbers(NUMBER_CFG),
+ borderColor: Utils.CHART_COLORS.red,
+ backgroundColor: Utils.transparentize(Utils.CHART_COLORS.red, 0.5),
+ tension: 0.4,
+ },
+ {
+ label: 'Dataset 2',
+ data: Utils.numbers(NUMBER_CFG),
+ borderColor: Utils.CHART_COLORS.blue,
+ backgroundColor: Utils.transparentize(Utils.CHART_COLORS.blue, 0.5),
+ tension: 0.2,
+ }
+ ]
+};
+// </block:setup>
+
+// <block:config:0>
+const config = {
+ type: 'line',
+ data: data,
+ options: {
+ animations: {
+ radius: {
+ duration: 400,
+ easing: 'linear',
+ loop: (context) => context.active
+ }
+ },
+ hoverRadius: 12,
+ hoverBackgroundColor: 'yellow',
+ interaction: {
+ mode: 'nearest',
+ intersect: false,
+ axis: 'x'
+ },
+ plugins: {
+ tooltip: {
+ enabled: false
+ }
+ }
+ },
+};
+// </block:config>
+
+module.exports = {
+ actions: actions,
+ config: config,
+};
+```
--- /dev/null
+# Progressive Line
+
+```js chart-editor
+
+// <block:data:2>
+const data = [];
+const data2 = [];
+let prev = 100;
+let prev2 = 80;
+for (let i = 0; i < 1000; i++) {
+ prev += 5 - Math.random() * 10;
+ data.push({x: i, y: prev});
+ prev2 += 5 - Math.random() * 10;
+ data2.push({x: i, y: prev2});
+}
+// </block:data>
+
+// <block:animation:1>
+const totalDuration = 10000;
+const delayBetweenPoints = totalDuration / data.length;
+const previousY = (ctx) => ctx.index === 0 ? ctx.chart.scales.y.getPixelForValue(100) : ctx.chart.getDatasetMeta(ctx.datasetIndex).data[ctx.index - 1].getProps(['y'], true).y;
+const animation = {
+ x: {
+ type: 'number',
+ easing: 'linear',
+ duration: delayBetweenPoints,
+ from: NaN, // the point is initially skipped
+ delay(ctx) {
+ if (ctx.type !== 'data' || ctx.xStarted) {
+ return 0;
+ }
+ ctx.xStarted = true;
+ return ctx.index * delayBetweenPoints;
+ }
+ },
+ y: {
+ type: 'number',
+ easing: 'linear',
+ duration: delayBetweenPoints,
+ from: previousY,
+ delay(ctx) {
+ if (ctx.type !== 'data' || ctx.yStarted) {
+ return 0;
+ }
+ ctx.yStarted = true;
+ return ctx.index * delayBetweenPoints;
+ }
+ }
+};
+// </block:animation>
+
+// <block:config:0>
+const config = {
+ type: 'line',
+ data: {
+ datasets: [{
+ borderColor: Utils.CHART_COLORS.red,
+ borderWidth: 1,
+ radius: 0,
+ data: data,
+ },
+ {
+ borderColor: Utils.CHART_COLORS.blue,
+ borderWidth: 1,
+ radius: 0,
+ data: data2,
+ }]
+ },
+ options: {
+ animation,
+ interaction: {
+ intersect: false
+ },
+ plugins: {
+ legend: false
+ },
+ scales: {
+ x: {
+ type: 'linear'
+ }
+ }
+ }
+};
+// </block:config>
+
+module.exports = {
+ config
+};
+
+```
--- /dev/null
+# Line Chart Boundaries
+
+:::: tabs
+
+::: tab "Fill: false"
+
+```js chart-editor
+// <block:setup:2>
+const inputs = {
+ min: -100,
+ max: 100,
+ count: 8,
+ decimals: 2,
+ continuity: 1
+};
+
+const generateLabels = () => {
+ return Utils.months({count: inputs.count});
+};
+
+const generateData = () => (Utils.numbers(inputs));
+// </block:setup>
+
+// <block:data:0>
+const data = {
+ labels: generateLabels(),
+ datasets: [
+ {
+ label: 'Dataset',
+ data: generateData(),
+ borderColor: Utils.CHART_COLORS.red,
+ backgroundColor: Utils.transparentize(Utils.CHART_COLORS.red),
+ fill: false
+ }
+ ]
+};
+// </block:data>
+
+// <block:actions:3>
+let smooth = false;
+
+const actions = [
+ {
+ name: 'Randomize',
+ handler(chart) {
+ // Utils.srand(Utils.rand())
+ chart.data.datasets.forEach(dataset => {
+ dataset.data = generateData();
+ });
+ chart.update();
+ }
+ },
+ {
+ name: 'Smooth',
+ handler(chart) {
+ smooth = !smooth;
+ chart.options.elements.line.tension = smooth ? 0.4 : 0;
+ chart.update();
+ }
+ }
+];
+// </block:actions>
+
+// <block:config:1>
+const config = {
+ type: 'line',
+ data: data,
+ options: {
+ plugins: {
+ filler: {
+ propagate: false,
+ }
+ },
+ interaction: {
+ intersect: false,
+ }
+ },
+};
+// </block:config>
+
+module.exports = {
+ actions: actions,
+ config: config,
+};
+```
+
+:::
+
+::: tab "Fill: origin"
+
+```js chart-editor
+// <block:setup:2>
+const inputs = {
+ min: -100,
+ max: 100,
+ count: 8,
+ decimals: 2,
+ continuity: 1
+};
+
+const generateLabels = () => {
+ return Utils.months({count: inputs.count});
+};
+
+const generateData = () => (Utils.numbers(inputs));
+// </block:setup>
+
+// <block:data:0>
+const data = {
+ labels: generateLabels(),
+ datasets: [
+ {
+ label: 'Dataset',
+ data: generateData(),
+ borderColor: Utils.CHART_COLORS.red,
+ backgroundColor: Utils.transparentize(Utils.CHART_COLORS.red),
+ fill: 'origin'
+ }
+ ]
+};
+// </block:data>
+
+// <block:actions:3>
+let smooth = false;
+
+const actions = [
+ {
+ name: 'Randomize',
+ handler(chart) {
+ // Utils.srand(Utils.rand())
+ chart.data.datasets.forEach(dataset => {
+ dataset.data = generateData();
+ });
+ chart.update();
+ }
+ },
+ {
+ name: 'Smooth',
+ handler(chart) {
+ smooth = !smooth;
+ chart.options.elements.line.tension = smooth ? 0.4 : 0;
+ chart.update();
+ }
+ }
+];
+// </block:actions>
+
+// <block:config:1>
+const config = {
+ type: 'line',
+ data: data,
+ options: {
+ plugins: {
+ filler: {
+ propagate: false,
+ }
+ },
+ interaction: {
+ intersect: false
+ },
+ },
+};
+// </block:config>
+
+module.exports = {
+ actions: actions,
+ config: config,
+};
+```
+
+:::
+
+::: tab "Fill: start"
+
+```js chart-editor
+// <block:setup:1>
+const inputs = {
+ min: -100,
+ max: 100,
+ count: 8,
+ decimals: 2,
+ continuity: 1
+};
+
+const generateLabels = () => {
+ return Utils.months({count: inputs.count});
+};
+
+const generateData = () => (Utils.numbers(inputs));
+// </block:setup>
+
+// <block:data:0>
+const data = {
+ labels: generateLabels(),
+ datasets: [
+ {
+ label: 'Dataset',
+ data: generateData(),
+ borderColor: Utils.CHART_COLORS.red,
+ backgroundColor: Utils.transparentize(Utils.CHART_COLORS.red),
+ fill: 'start'
+ }
+ ]
+};
+// </block:data>
+
+// <block:actions:2>
+let smooth = false;
+
+const actions = [
+ {
+ name: 'Randomize',
+ handler(chart) {
+ // Utils.srand(Utils.rand())
+ chart.data.datasets.forEach(dataset => {
+ dataset.data = generateData();
+ });
+ chart.update();
+ }
+ },
+ {
+ name: 'Smooth',
+ handler(chart) {
+ smooth = !smooth;
+ chart.options.elements.line.tension = smooth ? 0.4 : 0;
+ chart.update();
+ }
+ }
+];
+// </block:actions>
+
+// <block:config:0>
+const config = {
+ type: 'line',
+ data: data,
+ options: {
+ plugins: {
+ filler: {
+ propagate: false,
+ }
+ },
+ interaction: {
+ intersect: false,
+ },
+ },
+};
+// </block:config>
+
+module.exports = {
+ actions: actions,
+ config: config,
+};
+```
+
+:::
+
+::: tab "Fill: end"
+
+```js chart-editor
+// <block:setup:2>
+const inputs = {
+ min: -100,
+ max: 100,
+ count: 8,
+ decimals: 2,
+ continuity: 1
+};
+
+const generateLabels = () => {
+ return Utils.months({count: inputs.count});
+};
+
+const generateData = () => (Utils.numbers(inputs));
+// </block:setup>
+
+// <block:data:0>
+const data = {
+ labels: generateLabels(),
+ datasets: [
+ {
+ label: 'Dataset',
+ data: generateData(),
+ borderColor: Utils.CHART_COLORS.red,
+ backgroundColor: Utils.transparentize(Utils.CHART_COLORS.red),
+ fill: 'end'
+ }
+ ]
+};
+// </block:data>
+
+// <block:actions:3>
+let smooth = false;
+
+const actions = [
+ {
+ name: 'Randomize',
+ handler(chart) {
+ // Utils.srand(Utils.rand())
+ chart.data.datasets.forEach(dataset => {
+ dataset.data = generateData();
+ });
+ chart.update();
+ }
+ },
+ {
+ name: 'Smooth',
+ handler(chart) {
+ smooth = !smooth;
+ chart.options.elements.line.tension = smooth ? 0.4 : 0;
+ chart.update();
+ }
+ }
+];
+// </block:actions>
+
+// <block:config:1>
+const config = {
+ type: 'line',
+ data: data,
+ options: {
+ plugins: {
+ filler: {
+ propagate: false,
+ }
+ },
+ interaction: {
+ intersect: false,
+ },
+ },
+};
+// </block:config>
+
+module.exports = {
+ actions: actions,
+ config: config,
+};
+```
+
+:::
+
+::::
--- /dev/null
+# Line Chart Datasets
+
+```js chart-editor
+// <block:setup:2>
+const inputs = {
+ min: 20,
+ max: 80,
+ count: 8,
+ decimals: 2,
+ continuity: 1
+};
+
+const generateLabels = () => {
+ return Utils.months({count: inputs.count});
+};
+
+const generateData = () => (Utils.numbers(inputs));
+
+Utils.srand(42);
+// </block:setup>
+
+// <block:data:0>
+const data = {
+ labels: generateLabels(),
+ datasets: [
+ {
+ label: 'D0',
+ data: generateData(),
+ borderColor: Utils.CHART_COLORS.red,
+ backgroundColor: Utils.transparentize(Utils.CHART_COLORS.red),
+ hidden: true
+ },
+ {
+ label: 'D1',
+ data: generateData(),
+ borderColor: Utils.CHART_COLORS.orange,
+ backgroundColor: Utils.transparentize(Utils.CHART_COLORS.orange),
+ fill: '-1'
+ },
+ {
+ label: 'D2',
+ data: generateData(),
+ borderColor: Utils.CHART_COLORS.yellow,
+ backgroundColor: Utils.transparentize(Utils.CHART_COLORS.yellow),
+ hidden: true,
+ fill: 1
+ },
+ {
+ label: 'D3',
+ data: generateData(),
+ borderColor: Utils.CHART_COLORS.green,
+ backgroundColor: Utils.transparentize(Utils.CHART_COLORS.green),
+ fill: '-1'
+ },
+ {
+ label: 'D4',
+ data: generateData(),
+ borderColor: Utils.CHART_COLORS.blue,
+ backgroundColor: Utils.transparentize(Utils.CHART_COLORS.blue),
+ fill: '-1'
+ },
+ {
+ label: 'D5',
+ data: generateData(),
+ borderColor: Utils.CHART_COLORS.grey,
+ backgroundColor: Utils.transparentize(Utils.CHART_COLORS.grey),
+ fill: '+2'
+ },
+ {
+ label: 'D6',
+ data: generateData(),
+ borderColor: Utils.CHART_COLORS.purple,
+ backgroundColor: Utils.transparentize(Utils.CHART_COLORS.purple),
+ fill: false
+ },
+ {
+ label: 'D7',
+ data: generateData(),
+ borderColor: Utils.CHART_COLORS.red,
+ backgroundColor: Utils.transparentize(Utils.CHART_COLORS.red),
+ fill: 8
+ },
+ {
+ label: 'D8',
+ data: generateData(),
+ borderColor: Utils.CHART_COLORS.orange,
+ backgroundColor: Utils.transparentize(Utils.CHART_COLORS.orange),
+ fill: 'end',
+ hidden: true
+ },
+ {
+ label: 'D9',
+ data: generateData(),
+ borderColor: Utils.CHART_COLORS.yellow,
+ backgroundColor: Utils.transparentize(Utils.CHART_COLORS.yellow),
+ fill: {above: 'blue', below: 'red', target: {value: 350}}
+ }
+ ]
+};
+// </block:data>
+
+// <block:actions:3>
+let smooth = false;
+let propagate = false;
+
+const actions = [
+ {
+ name: 'Randomize',
+ handler(chart) {
+ chart.data.datasets.forEach(dataset => {
+ dataset.data = generateData();
+ });
+ chart.update();
+ }
+ },
+ {
+ name: 'Propagate',
+ handler(chart) {
+ propagate = !propagate;
+ chart.options.plugins.filler.propagate = propagate;
+ chart.update();
+ }
+ },
+ {
+ name: 'Smooth',
+ handler(chart) {
+ smooth = !smooth;
+ chart.options.elements.line.tension = smooth ? 0.4 : 0;
+ chart.update();
+ }
+ }
+];
+// </block:actions>
+
+// <block:config:1>
+const config = {
+ type: 'line',
+ data: data,
+ options: {
+ scales: {
+ y: {
+ stacked: true
+ }
+ },
+ plugins: {
+ filler: {
+ propagate: false
+ },
+ 'samples-filler-analyser': {
+ target: 'chart-analyser'
+ }
+ },
+ interaction: {
+ intersect: false,
+ },
+ },
+};
+// </block:config>
+
+module.exports = {
+ actions: actions,
+ config: config,
+};
+```
+
+<div id="chart-analyser" class="analyser"></div>
--- /dev/null
+# Line Chart Stacked
+
+:::: tabs
+
+::: tab Stacked
+
+```js chart-editor
+// <block:actions:2>
+const actions = [
+ {
+ name: 'Randomize',
+ handler(chart) {
+ chart.data.datasets.forEach(dataset => {
+ dataset.data = Utils.numbers({count: chart.data.labels.length, min: -100, max: 100});
+ });
+ chart.update();
+ }
+ },
+ {
+ name: 'Add Dataset',
+ handler(chart) {
+ const data = chart.data;
+ const dsColor = Utils.namedColor(chart.data.datasets.length);
+ const newDataset = {
+ label: 'Dataset ' + (data.datasets.length + 1),
+ backgroundColor: dsColor,
+ borderColor: dsColor,
+ fill: true,
+ data: Utils.numbers({count: data.labels.length, min: -100, max: 100}),
+ };
+ chart.data.datasets.push(newDataset);
+ chart.update();
+ }
+ },
+ {
+ name: 'Add Data',
+ handler(chart) {
+ const data = chart.data;
+ if (data.datasets.length > 0) {
+ data.labels = Utils.months({count: data.labels.length + 1});
+
+ for (var index = 0; index < data.datasets.length; ++index) {
+ data.datasets[index].data.push(Utils.rand(-100, 100));
+ }
+
+ chart.update();
+ }
+ }
+ },
+ {
+ name: 'Remove Dataset',
+ handler(chart) {
+ chart.data.datasets.pop();
+ chart.update();
+ }
+ },
+ {
+ name: 'Remove Data',
+ handler(chart) {
+ chart.data.labels.splice(-1, 1); // remove the label first
+
+ chart.data.datasets.forEach(dataset => {
+ dataset.data.pop();
+ });
+
+ chart.update();
+ }
+ }
+];
+// </block:actions>
+
+// <block:setup:1>
+const DATA_COUNT = 7;
+const NUMBER_CFG = {count: DATA_COUNT, min: -100, max: 100};
+
+const labels = Utils.months({count: 7});
+const data = {
+ labels: labels,
+ datasets: [
+ {
+ label: 'My First dataset',
+ data: Utils.numbers(NUMBER_CFG),
+ borderColor: Utils.CHART_COLORS.red,
+ backgroundColor: Utils.CHART_COLORS.red,
+ fill: true
+ },
+ {
+ label: 'My Second dataset',
+ data: Utils.numbers(NUMBER_CFG),
+ borderColor: Utils.CHART_COLORS.blue,
+ backgroundColor: Utils.CHART_COLORS.blue,
+ fill: true
+ },
+ {
+ label: 'My Third dataset',
+ data: Utils.numbers(NUMBER_CFG),
+ borderColor: Utils.CHART_COLORS.green,
+ backgroundColor: Utils.CHART_COLORS.green,
+ fill: true
+ },
+ {
+ label: 'My Fourth dataset',
+ data: Utils.numbers(NUMBER_CFG),
+ borderColor: Utils.CHART_COLORS.yellow,
+ backgroundColor: Utils.CHART_COLORS.yellow,
+ fill: true
+ }
+ ]
+};
+// </block:setup>
+
+// <block:config:0>
+const config = {
+ type: 'line',
+ data: data,
+ options: {
+ responsive: true,
+ plugins: {
+ title: {
+ display: true,
+ text: 'Chart.js Line Chart - stacked=true'
+ },
+ tooltip: {
+ mode: 'index'
+ },
+ },
+ interaction: {
+ mode: 'nearest',
+ axis: 'x',
+ intersect: false
+ },
+ scales: {
+ x: {
+ title: {
+ display: true,
+ text: 'Month'
+ }
+ },
+ y: {
+ stacked: true,
+ title: {
+ display: true,
+ text: 'Value'
+ }
+ }
+ }
+ }
+};
+// </block:config>
+
+module.exports = {
+ actions: actions,
+ config: config
+};
+```
+
+:::
+
+::: tab "Stacked single"
+
+```js chart-editor
+// <block:actions:2>
+const actions = [
+ {
+ name: 'Randomize',
+ handler(chart) {
+ chart.data.datasets.forEach(dataset => {
+ dataset.data = Utils.numbers({count: chart.data.labels.length, min: -100, max: 100});
+ });
+ chart.update();
+ }
+ },
+ {
+ name: 'Add Dataset',
+ handler(chart) {
+ const data = chart.data;
+ const dsColor = Utils.namedColor(chart.data.datasets.length);
+ const newDataset = {
+ label: 'Dataset ' + (data.datasets.length + 1),
+ backgroundColor: dsColor,
+ borderColor: dsColor,
+ fill: true,
+ data: Utils.numbers({count: data.labels.length, min: -100, max: 100}),
+ };
+ chart.data.datasets.push(newDataset);
+ chart.update();
+ }
+ },
+ {
+ name: 'Add Data',
+ handler(chart) {
+ const data = chart.data;
+ if (data.datasets.length > 0) {
+ data.labels = Utils.months({count: data.labels.length + 1});
+
+ for (var index = 0; index < data.datasets.length; ++index) {
+ data.datasets[index].data.push(Utils.rand(-100, 100));
+ }
+
+ chart.update();
+ }
+ }
+ },
+ {
+ name: 'Remove Dataset',
+ handler(chart) {
+ chart.data.datasets.pop();
+ chart.update();
+ }
+ },
+ {
+ name: 'Remove Data',
+ handler(chart) {
+ chart.data.labels.splice(-1, 1); // remove the label first
+
+ chart.data.datasets.forEach(dataset => {
+ dataset.data.pop();
+ });
+
+ chart.update();
+ }
+ }
+];
+// </block:actions>
+
+// <block:setup:1>
+const DATA_COUNT = 7;
+const NUMBER_CFG = {count: DATA_COUNT, min: -100, max: 100};
+
+const labels = Utils.months({count: 7});
+const data = {
+ labels: labels,
+ datasets: [
+ {
+ label: 'My First dataset',
+ data: Utils.numbers(NUMBER_CFG),
+ borderColor: Utils.CHART_COLORS.red,
+ backgroundColor: Utils.CHART_COLORS.red,
+ fill: true
+ },
+ {
+ label: 'My Second dataset',
+ data: Utils.numbers(NUMBER_CFG),
+ borderColor: Utils.CHART_COLORS.blue,
+ backgroundColor: Utils.CHART_COLORS.blue,
+ fill: true
+ },
+ {
+ label: 'My Third dataset',
+ data: Utils.numbers(NUMBER_CFG),
+ borderColor: Utils.CHART_COLORS.green,
+ backgroundColor: Utils.CHART_COLORS.green,
+ fill: true
+ },
+ {
+ label: 'My Fourth dataset',
+ data: Utils.numbers(NUMBER_CFG),
+ borderColor: Utils.CHART_COLORS.yellow,
+ backgroundColor: Utils.CHART_COLORS.yellow,
+ fill: true
+ }
+ ]
+};
+// </block:setup>
+
+// <block:config:0>
+const config = {
+ type: 'line',
+ data: data,
+ options: {
+ responsive: true,
+ plugins: {
+ title: {
+ display: true,
+ text: 'Chart.js Line Chart - stacked=single'
+ },
+ tooltip: {
+ mode: 'index'
+ },
+ },
+ interaction: {
+ mode: 'nearest',
+ axis: 'x',
+ intersect: false
+ },
+ scales: {
+ x: {
+ title: {
+ display: true,
+ text: 'Month'
+ }
+ },
+ y: {
+ stacked: 'single',
+ title: {
+ display: true,
+ text: 'Value'
+ }
+ }
+ }
+ }
+};
+// </block:config>
+
+module.exports = {
+ actions: actions,
+ config: config
+};
+```
+
+:::
+
+::::
--- /dev/null
+# Radar Chart Stacked
+
+```js chart-editor
+// <block:setup:1>
+const inputs = {
+ min: 8,
+ max: 16,
+ count: 8,
+ decimals: 2,
+ continuity: 1
+};
+
+const generateLabels = () => {
+ return Utils.months({count: inputs.count});
+};
+
+const generateData = () => {
+ const values = Utils.numbers(inputs);
+ inputs.from = values;
+ return values;
+};
+
+const labels = Utils.months({count: 8});
+const data = {
+ labels: generateLabels(),
+ datasets: [
+ {
+ label: 'D0',
+ data: generateData(),
+ borderColor: Utils.CHART_COLORS.red,
+ backgroundColor: Utils.transparentize(Utils.CHART_COLORS.red),
+ },
+ {
+ label: 'D1',
+ data: generateData(),
+ borderColor: Utils.CHART_COLORS.orange,
+ hidden: true,
+ backgroundColor: Utils.transparentize(Utils.CHART_COLORS.orange),
+ fill: '-1'
+ },
+ {
+ label: 'D2',
+ data: generateData(),
+ borderColor: Utils.CHART_COLORS.yellow,
+ backgroundColor: Utils.transparentize(Utils.CHART_COLORS.yellow),
+ fill: 1
+ },
+ {
+ label: 'D3',
+ data: generateData(),
+ borderColor: Utils.CHART_COLORS.green,
+ backgroundColor: Utils.transparentize(Utils.CHART_COLORS.green),
+ fill: false
+ },
+ {
+ label: 'D4',
+ data: generateData(),
+ borderColor: Utils.CHART_COLORS.blue,
+ backgroundColor: Utils.transparentize(Utils.CHART_COLORS.blue),
+ fill: '-1'
+ },
+ {
+ label: 'D5',
+ data: generateData(),
+ borderColor: Utils.CHART_COLORS.purple,
+ backgroundColor: Utils.transparentize(Utils.CHART_COLORS.purple),
+ fill: '-1'
+ },
+ {
+ label: 'D6',
+ data: generateData(),
+ borderColor: Utils.CHART_COLORS.grey,
+ backgroundColor: Utils.transparentize(Utils.CHART_COLORS.grey),
+ fill: {value: 85}
+ }
+ ]
+};
+// </block:setup>
+
+// <block:actions:2>
+let smooth = false;
+let propagate = false;
+
+const actions = [
+ {
+ name: 'Randomize',
+ handler(chart) {
+ inputs.from = [];
+ chart.data.datasets.forEach(dataset => {
+ dataset.data = generateData();
+ });
+ chart.update();
+ }
+ },
+ {
+ name: 'Propagate',
+ handler(chart) {
+ propagate = !propagate;
+ chart.options.plugins.filler.propagate = propagate;
+ chart.update();
+
+ }
+ },
+ {
+ name: 'Smooth',
+ handler(chart) {
+ smooth = !smooth;
+ chart.options.elements.line.tension = smooth ? 0.4 : 0;
+ chart.update();
+ }
+ }
+];
+// </block:actions>
+
+// <block:config:0>
+const config = {
+ type: 'radar',
+ data: data,
+ options: {
+ plugins: {
+ filler: {
+ propagate: false
+ },
+ 'samples-filler-analyser': {
+ target: 'chart-analyser'
+ }
+ },
+ interaction: {
+ intersect: false
+ }
+ }
+};
+// </block:config>
+
+module.exports = {
+ actions: actions,
+ config: config
+};
+```
+
+<div id="chart-analyser" class="analyser"></div>
--- /dev/null
+# Bar Chart Border Radius
+
+```js chart-editor
+// <block:actions:2>
+const actions = [
+ {
+ name: 'Randomize',
+ handler(chart) {
+ chart.data.datasets.forEach(dataset => {
+ dataset.data = Utils.numbers({count: chart.data.labels.length, min: -100, max: 100});
+ });
+ chart.update();
+ }
+ },
+];
+// </block:actions>
+
+// <block:setup:1>
+const DATA_COUNT = 7;
+const NUMBER_CFG = {count: DATA_COUNT, min: -100, max: 100};
+
+const labels = Utils.months({count: 7});
+const data = {
+ labels: labels,
+ datasets: [
+ {
+ label: 'Fully Rounded',
+ data: Utils.numbers(NUMBER_CFG),
+ borderColor: Utils.CHART_COLORS.red,
+ backgroundColor: Utils.transparentize(Utils.CHART_COLORS.red, 0.5),
+ borderWidth: 2,
+ borderRadius: Number.MAX_VALUE,
+ borderSkipped: false,
+ },
+ {
+ label: 'Small Radius',
+ data: Utils.numbers(NUMBER_CFG),
+ borderColor: Utils.CHART_COLORS.blue,
+ backgroundColor: Utils.transparentize(Utils.CHART_COLORS.blue, 0.5),
+ borderWidth: 2,
+ borderRadius: 5,
+ borderSkipped: false,
+ }
+ ]
+};
+// </block:setup>
+
+// <block:config:0>
+const config = {
+ type: 'bar',
+ data: data,
+ options: {
+ responsive: true,
+ plugins: {
+ legend: {
+ position: 'top',
+ },
+ title: {
+ display: true,
+ text: 'Chart.js Bar Chart'
+ }
+ }
+ },
+};
+// </block:config>
+
+module.exports = {
+ actions: actions,
+ config: config,
+};
+```
--- /dev/null
+# Floating Bars
+
+```js chart-editor
+// <block:actions:2>
+const actions = [
+ {
+ name: 'Randomize',
+ handler(chart) {
+ chart.data.datasets.forEach(dataset => {
+ dataset.data = chart.data.labels.map(() => {
+ return [Utils.rand(-100, 100), Utils.rand(-100, 100)];
+ });
+ });
+ chart.update();
+ }
+ },
+];
+// </block:actions>
+
+// <block:setup:1>
+const DATA_COUNT = 7;
+const NUMBER_CFG = {count: DATA_COUNT, min: -100, max: 100};
+
+const labels = Utils.months({count: 7});
+const data = {
+ labels: labels,
+ datasets: [
+ {
+ label: 'Dataset 1',
+ data: labels.map(() => {
+ return [Utils.rand(-100, 100), Utils.rand(-100, 100)];
+ }),
+ backgroundColor: Utils.CHART_COLORS.red,
+ },
+ {
+ label: 'Dataset 2',
+ data: labels.map(() => {
+ return [Utils.rand(-100, 100), Utils.rand(-100, 100)];
+ }),
+ backgroundColor: Utils.CHART_COLORS.blue,
+ },
+ ]
+};
+// </block:setup>
+
+// <block:config:0>
+const config = {
+ type: 'bar',
+ data: data,
+ options: {
+ responsive: true,
+ plugins: {
+ legend: {
+ position: 'top',
+ },
+ title: {
+ display: true,
+ text: 'Chart.js Floating Bar Chart'
+ }
+ }
+ }
+};
+// </block:config>
+
+module.exports = {
+ actions: actions,
+ config: config,
+};
+```
--- /dev/null
+# Horizontal Bar Chart
+
+```js chart-editor
+// <block:actions:2>
+const actions = [
+ {
+ name: 'Randomize',
+ handler(chart) {
+ chart.data.datasets.forEach(dataset => {
+ dataset.data = Utils.numbers({count: chart.data.labels.length, min: -100, max: 100});
+ });
+ chart.update();
+ }
+ },
+ {
+ name: 'Add Dataset',
+ handler(chart) {
+ const data = chart.data;
+ const dsColor = Utils.namedColor(chart.data.datasets.length);
+ const newDataset = {
+ label: 'Dataset ' + (data.datasets.length + 1),
+ backgroundColor: Utils.transparentize(dsColor, 0.5),
+ borderColor: dsColor,
+ borderWidth: 1,
+ data: Utils.numbers({count: data.labels.length, min: -100, max: 100}),
+ };
+ chart.data.datasets.push(newDataset);
+ chart.update();
+ }
+ },
+ {
+ name: 'Add Data',
+ handler(chart) {
+ const data = chart.data;
+ if (data.datasets.length > 0) {
+ data.labels = Utils.months({count: data.labels.length + 1});
+
+ for (var index = 0; index < data.datasets.length; ++index) {
+ data.datasets[index].data.push(Utils.rand(-100, 100));
+ }
+
+ chart.update();
+ }
+ }
+ },
+ {
+ name: 'Remove Dataset',
+ handler(chart) {
+ chart.data.datasets.pop();
+ chart.update();
+ }
+ },
+ {
+ name: 'Remove Data',
+ handler(chart) {
+ chart.data.labels.splice(-1, 1); // remove the label first
+
+ chart.data.datasets.forEach(dataset => {
+ dataset.data.pop();
+ });
+
+ chart.update();
+ }
+ }
+];
+// </block:actions>
+
+// <block:setup:1>
+const DATA_COUNT = 7;
+const NUMBER_CFG = {count: DATA_COUNT, min: -100, max: 100};
+
+const labels = Utils.months({count: 7});
+const data = {
+ labels: labels,
+ datasets: [
+ {
+ label: 'Dataset 1',
+ data: Utils.numbers(NUMBER_CFG),
+ borderColor: Utils.CHART_COLORS.red,
+ backgroundColor: Utils.transparentize(Utils.CHART_COLORS.red, 0.5),
+ },
+ {
+ label: 'Dataset 2',
+ data: Utils.numbers(NUMBER_CFG),
+ borderColor: Utils.CHART_COLORS.blue,
+ backgroundColor: Utils.transparentize(Utils.CHART_COLORS.blue, 0.5),
+ }
+ ]
+};
+// </block:setup>
+
+// <block:config:0>
+const config = {
+ type: 'bar',
+ data: data,
+ options: {
+ indexAxis: 'y',
+ // Elements options apply to all of the options unless overridden in a dataset
+ // In this case, we are setting the border of each horizontal bar to be 2px wide
+ elements: {
+ bar: {
+ borderWidth: 2,
+ }
+ },
+ responsive: true,
+ plugins: {
+ legend: {
+ position: 'right',
+ },
+ title: {
+ display: true,
+ text: 'Chart.js Horizontal Bar Chart'
+ }
+ }
+ },
+};
+// </block:config>
+
+module.exports = {
+ actions: actions,
+ config: config,
+};
+```
--- /dev/null
+# Stacked Bar Chart with Groups
+
+```js chart-editor
+// <block:actions:2>
+const actions = [
+ {
+ name: 'Randomize',
+ handler(chart) {
+ chart.data.datasets.forEach(dataset => {
+ dataset.data = Utils.numbers({count: chart.data.labels.length, min: -100, max: 100});
+ });
+ chart.update();
+ }
+ },
+];
+// </block:actions>
+
+// <block:setup:1>
+const DATA_COUNT = 7;
+const NUMBER_CFG = {count: DATA_COUNT, min: -100, max: 100};
+
+const labels = Utils.months({count: 7});
+const data = {
+ labels: labels,
+ datasets: [
+ {
+ label: 'Dataset 1',
+ data: Utils.numbers(NUMBER_CFG),
+ backgroundColor: Utils.CHART_COLORS.red,
+ stack: 'Stack 0',
+ },
+ {
+ label: 'Dataset 2',
+ data: Utils.numbers(NUMBER_CFG),
+ backgroundColor: Utils.CHART_COLORS.blue,
+ stack: 'Stack 0',
+ },
+ {
+ label: 'Dataset 3',
+ data: Utils.numbers(NUMBER_CFG),
+ backgroundColor: Utils.CHART_COLORS.green,
+ stack: 'Stack 1',
+ },
+ ]
+};
+// </block:setup>
+
+// <block:config:0>
+const config = {
+ type: 'bar',
+ data: data,
+ options: {
+ plugins: {
+ title: {
+ display: true,
+ text: 'Chart.js Bar Chart - Stacked'
+ },
+ },
+ responsive: true,
+ interaction: {
+ intersect: false,
+ },
+ scales: {
+ x: {
+ stacked: true,
+ },
+ y: {
+ stacked: true
+ }
+ }
+ }
+};
+// </block:config>
+
+module.exports = {
+ actions: actions,
+ config: config,
+};
+```
--- /dev/null
+# Stacked Bar Chart
+
+```js chart-editor
+// <block:actions:2>
+const actions = [
+ {
+ name: 'Randomize',
+ handler(chart) {
+ chart.data.datasets.forEach(dataset => {
+ dataset.data = Utils.numbers({count: chart.data.labels.length, min: -100, max: 100});
+ });
+ chart.update();
+ }
+ },
+];
+// </block:actions>
+
+// <block:setup:1>
+const DATA_COUNT = 7;
+const NUMBER_CFG = {count: DATA_COUNT, min: -100, max: 100};
+
+const labels = Utils.months({count: 7});
+const data = {
+ labels: labels,
+ datasets: [
+ {
+ label: 'Dataset 1',
+ data: Utils.numbers(NUMBER_CFG),
+ backgroundColor: Utils.CHART_COLORS.red,
+ },
+ {
+ label: 'Dataset 2',
+ data: Utils.numbers(NUMBER_CFG),
+ backgroundColor: Utils.CHART_COLORS.blue,
+ },
+ {
+ label: 'Dataset 3',
+ data: Utils.numbers(NUMBER_CFG),
+ backgroundColor: Utils.CHART_COLORS.green,
+ },
+ ]
+};
+// </block:setup>
+
+// <block:config:0>
+const config = {
+ type: 'bar',
+ data: data,
+ options: {
+ plugins: {
+ title: {
+ display: true,
+ text: 'Chart.js Bar Chart - Stacked'
+ },
+ },
+ responsive: true,
+ scales: {
+ x: {
+ stacked: true,
+ },
+ y: {
+ stacked: true
+ }
+ }
+ }
+};
+// </block:config>
+
+module.exports = {
+ actions: actions,
+ config: config,
+};
+```
--- /dev/null
+# Vertical Bar Chart
+
+```js chart-editor
+// <block:actions:2>
+const actions = [
+ {
+ name: 'Randomize',
+ handler(chart) {
+ chart.data.datasets.forEach(dataset => {
+ dataset.data = Utils.numbers({count: chart.data.labels.length, min: -100, max: 100});
+ });
+ chart.update();
+ }
+ },
+ {
+ name: 'Add Dataset',
+ handler(chart) {
+ const data = chart.data;
+ const dsColor = Utils.namedColor(chart.data.datasets.length);
+ const newDataset = {
+ label: 'Dataset ' + (data.datasets.length + 1),
+ backgroundColor: Utils.transparentize(dsColor, 0.5),
+ borderColor: dsColor,
+ borderWidth: 1,
+ data: Utils.numbers({count: data.labels.length, min: -100, max: 100}),
+ };
+ chart.data.datasets.push(newDataset);
+ chart.update();
+ }
+ },
+ {
+ name: 'Add Data',
+ handler(chart) {
+ const data = chart.data;
+ if (data.datasets.length > 0) {
+ data.labels = Utils.months({count: data.labels.length + 1});
+
+ for (var index = 0; index < data.datasets.length; ++index) {
+ data.datasets[index].data.push(Utils.rand(-100, 100));
+ }
+
+ chart.update();
+ }
+ }
+ },
+ {
+ name: 'Remove Dataset',
+ handler(chart) {
+ chart.data.datasets.pop();
+ chart.update();
+ }
+ },
+ {
+ name: 'Remove Data',
+ handler(chart) {
+ chart.data.labels.splice(-1, 1); // remove the label first
+
+ chart.data.datasets.forEach(dataset => {
+ dataset.data.pop();
+ });
+
+ chart.update();
+ }
+ }
+];
+// </block:actions>
+
+// <block:setup:1>
+const DATA_COUNT = 7;
+const NUMBER_CFG = {count: DATA_COUNT, min: -100, max: 100};
+
+const labels = Utils.months({count: 7});
+const data = {
+ labels: labels,
+ datasets: [
+ {
+ label: 'Dataset 1',
+ data: Utils.numbers(NUMBER_CFG),
+ borderColor: Utils.CHART_COLORS.red,
+ backgroundColor: Utils.transparentize(Utils.CHART_COLORS.red, 0.5),
+ },
+ {
+ label: 'Dataset 2',
+ data: Utils.numbers(NUMBER_CFG),
+ borderColor: Utils.CHART_COLORS.blue,
+ backgroundColor: Utils.transparentize(Utils.CHART_COLORS.blue, 0.5),
+ }
+ ]
+};
+// </block:setup>
+
+// <block:config:0>
+const config = {
+ type: 'bar',
+ data: data,
+ options: {
+ responsive: true,
+ plugins: {
+ legend: {
+ position: 'top',
+ },
+ title: {
+ display: true,
+ text: 'Chart.js Bar Chart'
+ }
+ }
+ },
+};
+// </block:config>
+
+module.exports = {
+ actions: actions,
+ config: config,
+};
+```
--- /dev/null
+# Point Style
+
+This sample show how to use the dataset point style in the legend instead of a rectangle to identify each dataset..
+
+```js chart-editor
+// <block:actions:2>
+const actions = [
+ {
+ name: 'Toggle Point Style',
+ handler(chart) {
+ chart.options.plugins.legend.labels.usePointStyle = !chart.options.plugins.legend.labels.usePointStyle;
+ chart.update();
+ }
+ },
+];
+// </block:actions>
+
+// <block:setup:1>
+const DATA_COUNT = 7;
+const NUMBER_CFG = {count: DATA_COUNT, min: -100, max: 100};
+const data = {
+ labels: Utils.months({count: DATA_COUNT}),
+ datasets: [
+ {
+ label: 'Dataset 1',
+ data: Utils.numbers(NUMBER_CFG),
+ fill: false,
+ borderColor: Utils.CHART_COLORS.red,
+ backgroundColor: Utils.transparentize(Utils.CHART_COLORS.red, 0.5),
+ borderWidth: 1,
+ pointStyle: 'rectRot',
+ pointRadius: 5,
+ pointBorderColor: 'rgb(0, 0, 0)'
+ },
+ ]
+};
+// </block:setup>
+
+// <block:config:0>
+const config = {
+ type: 'line',
+ data: data,
+ options: {
+ plugins: {
+ legend: {
+ labels: {
+ usePointStyle: true,
+ },
+ }
+ }
+ }
+};
+// </block:config>
+
+module.exports = {
+ actions: actions,
+ config: config,
+};
+```
\ No newline at end of file
--- /dev/null
+# Position
+
+This sample show how to change the position of the chart legend.
+
+```js chart-editor
+// <block:actions:2>
+const actions = [
+ {
+ name: 'Position: top',
+ handler(chart) {
+ chart.options.plugins.legend.position = 'top';
+ chart.update();
+ }
+ },
+ {
+ name: 'Position: right',
+ handler(chart) {
+ chart.options.plugins.legend.position = 'right';
+ chart.update();
+ }
+ },
+ {
+ name: 'Position: bottom',
+ handler(chart) {
+ chart.options.plugins.legend.position = 'bottom';
+ chart.update();
+ }
+ },
+ {
+ name: 'Position: left',
+ handler(chart) {
+ chart.options.plugins.legend.position = 'left';
+ chart.update();
+ }
+ },
+];
+// </block:actions>
+
+
+// <block:setup:1>
+const DATA_COUNT = 7;
+const NUMBER_CFG = {count: DATA_COUNT, min: -100, max: 100};
+const data = {
+ labels: Utils.months({count: DATA_COUNT}),
+ datasets: [
+ {
+ label: 'Dataset 1',
+ data: Utils.numbers(NUMBER_CFG),
+ fill: false,
+ borderColor: Utils.CHART_COLORS.red,
+ backgroundColor: Utils.transparentize(Utils.CHART_COLORS.red, 0.5),
+ },
+ ]
+};
+// </block:setup>
+
+// <block:config:0>
+const config = {
+ type: 'line',
+ data: data,
+};
+// </block:config>
+
+module.exports = {
+ actions: actions,
+ config: config,
+};
+```
\ No newline at end of file
--- /dev/null
+# Alignment and Title Position
+
+This sample show how to configure the alignment and title position of the chart legend.
+
+```js chart-editor
+// <block:actions:2>
+const actions = [
+ {
+ name: 'Title Position: start',
+ handler(chart) {
+ chart.options.plugins.legend.align = 'start';
+ chart.options.plugins.legend.title.position = 'start';
+ chart.update();
+ }
+ },
+ {
+ name: 'Title Position: center (default)',
+ handler(chart) {
+ chart.options.plugins.legend.align = 'center';
+ chart.options.plugins.legend.title.position = 'center';
+ chart.update();
+ }
+ },
+ {
+ name: 'Title Position: end',
+ handler(chart) {
+ chart.options.plugins.legend.align = 'end';
+ chart.options.plugins.legend.title.position = 'end';
+ chart.update();
+ }
+ },
+];
+// </block:actions>
+
+
+// <block:setup:1>
+const DATA_COUNT = 7;
+const NUMBER_CFG = {count: DATA_COUNT, min: -100, max: 100};
+const data = {
+ labels: Utils.months({count: DATA_COUNT}),
+ datasets: [
+ {
+ label: 'Dataset 1',
+ data: Utils.numbers(NUMBER_CFG),
+ fill: false,
+ borderColor: Utils.CHART_COLORS.red,
+ backgroundColor: Utils.transparentize(Utils.CHART_COLORS.red, 0.5),
+ },
+ ]
+};
+// </block:setup>
+
+// <block:config:0>
+const config = {
+ type: 'line',
+ data: data,
+ options: {
+ plugins: {
+ legend: {
+ title: {
+ display: true,
+ text: 'Legend Title',
+ }
+ }
+ }
+ }
+};
+// </block:config>
+
+module.exports = {
+ actions: actions,
+ config: config,
+};
+```
\ No newline at end of file
--- /dev/null
+# Interpolation Modes
+
+```js chart-editor
+// <block:setup:1>
+const DATA_COUNT = 12;
+const labels = [];
+for (let i = 0; i < DATA_COUNT; ++i) {
+ labels.push(i.toString());
+}
+const datapoints = [0, 20, 20, 60, 60, 120, NaN, 180, 120, 125, 105, 110, 170];
+const data = {
+ labels: labels,
+ datasets: [
+ {
+ label: 'Cubic interpolation (monotone)',
+ data: datapoints,
+ borderColor: Utils.CHART_COLORS.red,
+ fill: false,
+ cubicInterpolationMode: 'monotone',
+ tension: 0.4
+ }, {
+ label: 'Cubic interpolation',
+ data: datapoints,
+ borderColor: Utils.CHART_COLORS.blue,
+ fill: false,
+ tension: 0.4
+ }, {
+ label: 'Linear interpolation (default)',
+ data: datapoints,
+ borderColor: Utils.CHART_COLORS.green,
+ fill: false
+ }
+ ]
+};
+// </block:setup>
+
+// <block:config:0>
+const config = {
+ type: 'line',
+ data: data,
+ options: {
+ responsive: true,
+ plugins: {
+ title: {
+ display: true,
+ text: 'Chart.js Line Chart - Cubic interpolation mode'
+ },
+ },
+ interaction: {
+ intersect: false,
+ },
+ scales: {
+ x: {
+ display: true,
+ title: {
+ display: true
+ }
+ },
+ y: {
+ display: true,
+ title: {
+ display: true,
+ text: 'Value'
+ },
+ suggestedMin: -10,
+ suggestedMax: 200
+ }
+ }
+ },
+};
+// </block:config>
+
+module.exports = {
+ actions: [],
+ config: config,
+};
+```
--- /dev/null
+# Line Chart
+
+```js chart-editor
+// <block:actions:2>
+const actions = [
+ {
+ name: 'Randomize',
+ handler(chart) {
+ chart.data.datasets.forEach(dataset => {
+ dataset.data = Utils.numbers({count: chart.data.labels.length, min: -100, max: 100});
+ });
+ chart.update();
+ }
+ },
+ {
+ name: 'Add Dataset',
+ handler(chart) {
+ const data = chart.data;
+ const dsColor = Utils.namedColor(chart.data.datasets.length);
+ const newDataset = {
+ label: 'Dataset ' + (data.datasets.length + 1),
+ backgroundColor: Utils.transparentize(dsColor, 0.5),
+ borderColor: dsColor,
+ borderWidth: 1,
+ data: Utils.numbers({count: data.labels.length, min: -100, max: 100}),
+ };
+ chart.data.datasets.push(newDataset);
+ chart.update();
+ }
+ },
+ {
+ name: 'Add Data',
+ handler(chart) {
+ const data = chart.data;
+ if (data.datasets.length > 0) {
+ data.labels = Utils.months({count: data.labels.length + 1});
+
+ for (var index = 0; index < data.datasets.length; ++index) {
+ data.datasets[index].data.push(Utils.rand(-100, 100));
+ }
+
+ chart.update();
+ }
+ }
+ },
+ {
+ name: 'Remove Dataset',
+ handler(chart) {
+ chart.data.datasets.pop();
+ chart.update();
+ }
+ },
+ {
+ name: 'Remove Data',
+ handler(chart) {
+ chart.data.labels.splice(-1, 1); // remove the label first
+
+ chart.data.datasets.forEach(dataset => {
+ dataset.data.pop();
+ });
+
+ chart.update();
+ }
+ }
+];
+// </block:actions>
+
+// <block:setup:1>
+const DATA_COUNT = 7;
+const NUMBER_CFG = {count: DATA_COUNT, min: -100, max: 100};
+
+const labels = Utils.months({count: 7});
+const data = {
+ labels: labels,
+ datasets: [
+ {
+ label: 'Dataset 1',
+ data: Utils.numbers(NUMBER_CFG),
+ borderColor: Utils.CHART_COLORS.red,
+ backgroundColor: Utils.transparentize(Utils.CHART_COLORS.red, 0.5),
+ },
+ {
+ label: 'Dataset 2',
+ data: Utils.numbers(NUMBER_CFG),
+ borderColor: Utils.CHART_COLORS.blue,
+ backgroundColor: Utils.transparentize(Utils.CHART_COLORS.blue, 0.5),
+ }
+ ]
+};
+// </block:setup>
+
+// <block:config:0>
+const config = {
+ type: 'line',
+ data: data,
+ options: {
+ responsive: true,
+ plugins: {
+ legend: {
+ position: 'top',
+ },
+ title: {
+ display: true,
+ text: 'Chart.js Line Chart'
+ }
+ }
+ },
+};
+// </block:config>
+
+module.exports = {
+ actions: actions,
+ config: config,
+};
+```
--- /dev/null
+# Multi Axis Line Chart
+
+```js chart-editor
+// <block:actions:2>
+const actions = [
+ {
+ name: 'Randomize',
+ handler(chart) {
+ chart.data.datasets.forEach(dataset => {
+ dataset.data = Utils.numbers({count: chart.data.labels.length, min: -100, max: 100});
+ });
+ chart.update();
+ }
+ },
+];
+// </block:actions>
+
+// <block:setup:1>
+const DATA_COUNT = 7;
+const NUMBER_CFG = {count: DATA_COUNT, min: -100, max: 100};
+
+const labels = Utils.months({count: 7});
+const data = {
+ labels: labels,
+ datasets: [
+ {
+ label: 'Dataset 1',
+ data: Utils.numbers(NUMBER_CFG),
+ borderColor: Utils.CHART_COLORS.red,
+ backgroundColor: Utils.transparentize(Utils.CHART_COLORS.red, 0.5),
+ yAxisID: 'y',
+ },
+ {
+ label: 'Dataset 2',
+ data: Utils.numbers(NUMBER_CFG),
+ borderColor: Utils.CHART_COLORS.blue,
+ backgroundColor: Utils.transparentize(Utils.CHART_COLORS.blue, 0.5),
+ yAxisID: 'y1',
+ }
+ ]
+};
+// </block:setup>
+
+// <block:config:0>
+const config = {
+ type: 'line',
+ data: data,
+ options: {
+ responsive: true,
+ interaction: {
+ mode: 'index',
+ intersect: false,
+ },
+ stacked: false,
+ plugins: {
+ title: {
+ display: true,
+ text: 'Chart.js Line Chart - Multi Axis'
+ }
+ },
+ scales: {
+ y: {
+ type: 'linear',
+ display: true,
+ position: 'left',
+ },
+ y1: {
+ type: 'linear',
+ display: true,
+ position: 'right',
+
+ // grid line settings
+ grid: {
+ drawOnChartArea: false, // only want the grid lines for one axis to show up
+ },
+ },
+ }
+ },
+};
+// </block:config>
+
+module.exports = {
+ actions: actions,
+ config: config,
+};
+```
--- /dev/null
+# Stepped Line Charts
+
+```js chart-editor
+// <block:setup:1>
+const data = {
+ labels: ['Day 1', 'Day 2', 'Day 3', 'Day 4', 'Day 5', 'Day 6'],
+ datasets: [
+ {
+ label: 'Dataset',
+ data: Utils.numbers({count: 6, min: -100, max: 100}),
+ borderColor: Utils.CHART_COLORS.red,
+ fill: false,
+
+ // Change the stepped mode to explore different stepped chart options
+ // false: no stepping
+ // true: stepped before interpolation
+ // 'before': step before interpolation
+ // 'after': step after interpolation
+ // 'middle': step middle interpolation
+ stepped: true,
+ }
+ ]
+};
+// </block:setup>
+
+// <block:config:0>
+const config = {
+ type: 'line',
+ data: data,
+ options: {
+ responsive: true,
+ interaction: {
+ intersect: false,
+ axis: 'x'
+ },
+ plugins: {
+ title: {
+ display: true,
+ text: (ctx) => 'Step ' + ctx.chart.data.datasets[0].stepped + ' Interpolation',
+ }
+ }
+ }
+};
+// </block:config>
+
+module.exports = {
+ actions: [],
+ config: config,
+};
+```
--- /dev/null
+# Line Styling
+
+```js chart-editor
+// <block:setup:1>
+const DATA_COUNT = 7;
+const NUMBER_CFG = {count: DATA_COUNT, min: -100, max: 100};
+
+const labels = Utils.months({count: DATA_COUNT});
+const data = {
+ labels: labels,
+ datasets: [
+ {
+ label: 'Unfilled',
+ fill: false,
+ backgroundColor: Utils.CHART_COLORS.blue,
+ borderColor: Utils.CHART_COLORS.blue,
+ data: Utils.numbers(NUMBER_CFG),
+ }, {
+ label: 'Dashed',
+ fill: false,
+ backgroundColor: Utils.CHART_COLORS.green,
+ borderColor: Utils.CHART_COLORS.green,
+ borderDash: [5, 5],
+ data: Utils.numbers(NUMBER_CFG),
+ }, {
+ label: 'Filled',
+ backgroundColor: Utils.CHART_COLORS.red,
+ borderColor: Utils.CHART_COLORS.red,
+ data: Utils.numbers(NUMBER_CFG),
+ fill: true,
+ }
+ ]
+};
+// </block:setup>
+
+// <block:config:0>
+const config = {
+ type: 'line',
+ data: data,
+ options: {
+ responsive: true,
+ plugins: {
+ title: {
+ display: true,
+ text: 'Chart.js Line Chart'
+ },
+ },
+ interaction: {
+ mode: 'index',
+ intersect: false
+ },
+ scales: {
+ x: {
+ display: true,
+ title: {
+ display: true,
+ text: 'Month'
+ }
+ },
+ y: {
+ display: true,
+ title: {
+ display: true,
+ text: 'Value'
+ }
+ }
+ }
+ },
+};
+// </block:config>
+
+module.exports = {
+ actions: [],
+ config: config,
+};
+```
--- /dev/null
+# Bubble
+
+```js chart-editor
+// <block:actions:2>
+const actions = [
+ {
+ name: 'Randomize',
+ handler(chart) {
+ chart.data.datasets.forEach(dataset => {
+ dataset.data = Utils.bubbles({count: chart.data.labels.length, rmin: 5, rmax: 15, min: 0, max: 100});
+ });
+ chart.update();
+ }
+ },
+ {
+ name: 'Add Dataset',
+ handler(chart) {
+ const data = chart.data;
+ const dsColor = Utils.namedColor(chart.data.datasets.length);
+ const newDataset = {
+ label: 'Dataset ' + (data.datasets.length + 1),
+ backgroundColor: Utils.transparentize(dsColor, 0.5),
+ borderColor: dsColor,
+ data: Utils.bubbles({count: data.labels.length, rmin: 5, rmax: 15, min: 0, max: 100}),
+ };
+ chart.data.datasets.push(newDataset);
+ chart.update();
+ }
+ },
+ {
+ name: 'Add Data',
+ handler(chart) {
+ const data = chart.data;
+ if (data.datasets.length > 0) {
+
+ for (var index = 0; index < data.datasets.length; ++index) {
+ data.datasets[index].data.push(Utils.bubbles({count: 1, rmin: 5, rmax: 15, min: 0, max: 100})[0]);
+ }
+
+ chart.update();
+ }
+ }
+ },
+ {
+ name: 'Remove Dataset',
+ handler(chart) {
+ chart.data.datasets.pop();
+ chart.update();
+ }
+ },
+ {
+ name: 'Remove Data',
+ handler(chart) {
+ chart.data.labels.splice(-1, 1); // remove the label first
+
+ chart.data.datasets.forEach(dataset => {
+ dataset.data.pop();
+ });
+
+ chart.update();
+ }
+ }
+];
+// </block:actions>
+
+// <block:setup:1>
+const DATA_COUNT = 7;
+const NUMBER_CFG = {count: DATA_COUNT, rmin: 5, rmax: 15, min: 0, max: 100};
+
+const labels = Utils.months({count: 7});
+const data = {
+ labels: labels,
+ datasets: [
+ {
+ label: 'Dataset 1',
+ data: Utils.bubbles(NUMBER_CFG),
+ borderColor: Utils.CHART_COLORS.red,
+ backgroundColor: Utils.transparentize(Utils.CHART_COLORS.red, 0.5),
+ },
+ {
+ label: 'Dataset 2',
+ data: Utils.bubbles(NUMBER_CFG),
+ borderColor: Utils.CHART_COLORS.orange,
+ backgroundColor: Utils.transparentize(Utils.CHART_COLORS.orange, 0.5),
+ }
+ ]
+};
+// </block:setup>
+
+// <block:config:0>
+const config = {
+ type: 'bubble',
+ data: data,
+ options: {
+ responsive: true,
+ plugins: {
+ legend: {
+ position: 'top',
+ },
+ title: {
+ display: true,
+ text: 'Chart.js Bubble Chart'
+ }
+ }
+ },
+};
+// </block:config>
+
+module.exports = {
+ actions: actions,
+ config: config,
+};
+```
--- /dev/null
+# Combo bar/line
+
+```js chart-editor
+// <block:actions:2>
+const actions = [
+ {
+ name: 'Randomize',
+ handler(chart) {
+ chart.data.datasets.forEach(dataset => {
+ dataset.data = Utils.numbers({count: chart.data.labels.length, min: -100, max: 100});
+ });
+ chart.update();
+ }
+ },
+ {
+ name: 'Add Dataset',
+ handler(chart) {
+ const data = chart.data;
+ const dsColor = Utils.namedColor(chart.data.datasets.length);
+ const newDataset = {
+ label: 'Dataset ' + (data.datasets.length + 1),
+ backgroundColor: Utils.transparentize(dsColor, 0.5),
+ borderColor: dsColor,
+ borderWidth: 1,
+ data: Utils.numbers({count: data.labels.length, min: -100, max: 100}),
+ };
+ chart.data.datasets.push(newDataset);
+ chart.update();
+ }
+ },
+ {
+ name: 'Add Data',
+ handler(chart) {
+ const data = chart.data;
+ if (data.datasets.length > 0) {
+ data.labels = Utils.months({count: data.labels.length + 1});
+
+ for (var index = 0; index < data.datasets.length; ++index) {
+ data.datasets[index].data.push(Utils.rand(-100, 100));
+ }
+
+ chart.update();
+ }
+ }
+ },
+ {
+ name: 'Remove Dataset',
+ handler(chart) {
+ chart.data.datasets.pop();
+ chart.update();
+ }
+ },
+ {
+ name: 'Remove Data',
+ handler(chart) {
+ chart.data.labels.splice(-1, 1); // remove the label first
+
+ chart.data.datasets.forEach(dataset => {
+ dataset.data.pop();
+ });
+
+ chart.update();
+ }
+ }
+];
+// </block:actions>
+
+// <block:setup:1>
+const DATA_COUNT = 7;
+const NUMBER_CFG = {count: DATA_COUNT, min: -100, max: 100};
+
+const labels = Utils.months({count: 7});
+const data = {
+ labels: labels,
+ datasets: [
+ {
+ label: 'Dataset 1',
+ data: Utils.numbers(NUMBER_CFG),
+ borderColor: Utils.CHART_COLORS.red,
+ backgroundColor: Utils.transparentize(Utils.CHART_COLORS.red, 0.5),
+ order: 1
+ },
+ {
+ label: 'Dataset 2',
+ data: Utils.numbers(NUMBER_CFG),
+ borderColor: Utils.CHART_COLORS.blue,
+ backgroundColor: Utils.transparentize(Utils.CHART_COLORS.blue, 0.5),
+ type: 'line',
+ order: 0
+ }
+ ]
+};
+// </block:setup>
+
+// <block:config:0>
+const config = {
+ type: 'bar',
+ data: data,
+ options: {
+ responsive: true,
+ plugins: {
+ legend: {
+ position: 'top',
+ },
+ title: {
+ display: true,
+ text: 'Chart.js Combined Line/Bar Chart'
+ }
+ }
+ },
+};
+// </block:config>
+
+module.exports = {
+ actions: actions,
+ config: config,
+};
+```
--- /dev/null
+# Doughnut
+
+```js chart-editor
+// <block:actions:2>
+const actions = [
+ {
+ name: 'Randomize',
+ handler(chart) {
+ chart.data.datasets.forEach(dataset => {
+ dataset.data = Utils.numbers({count: chart.data.labels.length, min: 0, max: 100});
+ });
+ chart.update();
+ }
+ },
+ {
+ name: 'Add Dataset',
+ handler(chart) {
+ const data = chart.data;
+ const newDataset = {
+ label: 'Dataset ' + (data.datasets.length + 1),
+ backgroundColor: [],
+ data: [],
+ };
+
+ for (let i = 0; i < data.labels.length; i++) {
+ newDataset.data.push(Utils.numbers({count: 1, min: 0, max: 100}));
+
+ const colorIndex = i % Object.keys(Utils.CHART_COLORS).length;
+ newDataset.backgroundColor.push(Object.values(Utils.CHART_COLORS)[colorIndex]);
+ }
+
+ chart.data.datasets.push(newDataset);
+ chart.update();
+ }
+ },
+ {
+ name: 'Add Data',
+ handler(chart) {
+ const data = chart.data;
+ if (data.datasets.length > 0) {
+ data.labels.push('data #' + (data.labels.length + 1));
+
+ for (var index = 0; index < data.datasets.length; ++index) {
+ data.datasets[index].data.push(Utils.rand(0, 100));
+ }
+
+ chart.update();
+ }
+ }
+ },
+ {
+ name: 'Remove Dataset',
+ handler(chart) {
+ chart.data.datasets.pop();
+ chart.update();
+ }
+ },
+ {
+ name: 'Remove Data',
+ handler(chart) {
+ chart.data.labels.splice(-1, 1); // remove the label first
+
+ chart.data.datasets.forEach(dataset => {
+ dataset.data.pop();
+ });
+
+ chart.update();
+ }
+ }
+];
+// </block:actions>
+
+// <block:setup:1>
+const DATA_COUNT = 5;
+const NUMBER_CFG = {count: DATA_COUNT, min: 0, max: 100};
+
+const data = {
+ labels: ['Red', 'Orange', 'Yellow', 'Green', 'Blue'],
+ datasets: [
+ {
+ label: 'Dataset 1',
+ data: Utils.numbers(NUMBER_CFG),
+ backgroundColor: Object.values(Utils.CHART_COLORS),
+ }
+ ]
+};
+// </block:setup>
+
+// <block:config:0>
+const config = {
+ type: 'doughnut',
+ data: data,
+ options: {
+ responsive: true,
+ plugins: {
+ legend: {
+ position: 'top',
+ },
+ title: {
+ display: true,
+ text: 'Chart.js Doughnut Chart'
+ }
+ }
+ },
+};
+// </block:config>
+
+module.exports = {
+ actions: actions,
+ config: config,
+};
+```
--- /dev/null
+# Multi Series Pie
+
+```js chart-editor
+// <block:setup:1>
+const DATA_COUNT = 5;
+const NUMBER_CFG = {count: DATA_COUNT, min: 0, max: 100};
+
+const labels = Utils.months({count: 7});
+const data = {
+ labels: ['Overall Yay', 'Overall Nay', 'Group A Yay', 'Group A Nay', 'Group B Yay', 'Group B Nay', 'Group C Yay', 'Group C Nay'],
+ datasets: [
+ {
+ backgroundColor: ['#AAA', '#777'],
+ data: [21, 79]
+ },
+ {
+ backgroundColor: ['hsl(0, 100%, 60%)', 'hsl(0, 100%, 35%)'],
+ data: [33, 67]
+ },
+ {
+ backgroundColor: ['hsl(100, 100%, 60%)', 'hsl(100, 100%, 35%)'],
+ data: [20, 80]
+ },
+ {
+ backgroundColor: ['hsl(180, 100%, 60%)', 'hsl(180, 100%, 35%)'],
+ data: [10, 90]
+ }
+ ]
+};
+// </block:setup>
+
+// <block:config:0>
+const config = {
+ type: 'pie',
+ data: data,
+ options: {
+ responsive: true,
+ plugins: {
+ legend: {
+ labels: {
+ generateLabels: function(chart) {
+ // Get the default label list
+ const original = Chart.overrides.pie.plugins.legend.labels.generateLabels;
+ const labelsOriginal = original.call(this, chart);
+
+ // Build an array of colors used in the datasets of the chart
+ var datasetColors = chart.data.datasets.map(function(e) {
+ return e.backgroundColor;
+ });
+ datasetColors = datasetColors.flat();
+
+ // Modify the color and hide state of each label
+ labelsOriginal.forEach(label => {
+ // There are twice as many labels as there are datasets. This converts the label index into the corresponding dataset index
+ label.datasetIndex = (label.index - label.index % 2) / 2;
+
+ // The hidden state must match the dataset's hidden state
+ label.hidden = !chart.isDatasetVisible(label.datasetIndex);
+
+ // Change the color to match the dataset
+ label.fillStyle = datasetColors[label.index];
+ });
+
+ return labelsOriginal;
+ }
+ },
+ onClick: function(mouseEvent, legendItem, legend) {
+ // toggle the visibility of the dataset from what it currently is
+ legend.chart.getDatasetMeta(
+ legendItem.datasetIndex
+ ).hidden = legend.chart.isDatasetVisible(legendItem.datasetIndex);
+ legend.chart.update();
+ }
+ },
+ tooltip: {
+ callbacks: {
+ label: function(context) {
+ const labelIndex = (context.datasetIndex * 2) + context.dataIndex;
+ return context.chart.data.labels[labelIndex] + ': ' + context.formattedValue;
+ }
+ }
+ }
+ }
+ },
+};
+// </block:config>
+
+module.exports = {
+ config: config,
+};
+```
--- /dev/null
+# Pie
+
+```js chart-editor
+// <block:actions:2>
+const actions = [
+ {
+ name: 'Randomize',
+ handler(chart) {
+ chart.data.datasets.forEach(dataset => {
+ dataset.data = Utils.numbers({count: chart.data.labels.length, min: 0, max: 100});
+ });
+ chart.update();
+ }
+ },
+ {
+ name: 'Add Dataset',
+ handler(chart) {
+ const data = chart.data;
+ const newDataset = {
+ label: 'Dataset ' + (data.datasets.length + 1),
+ backgroundColor: [],
+ data: [],
+ };
+
+ for (let i = 0; i < data.labels.length; i++) {
+ newDataset.data.push(Utils.numbers({count: 1, min: 0, max: 100}));
+
+ const colorIndex = i % Object.keys(Utils.CHART_COLORS).length;
+ newDataset.backgroundColor.push(Object.values(Utils.CHART_COLORS)[colorIndex]);
+ }
+
+ chart.data.datasets.push(newDataset);
+ chart.update();
+ }
+ },
+ {
+ name: 'Add Data',
+ handler(chart) {
+ const data = chart.data;
+ if (data.datasets.length > 0) {
+ data.labels.push('data #' + (data.labels.length + 1));
+
+ for (var index = 0; index < data.datasets.length; ++index) {
+ data.datasets[index].data.push(Utils.rand(0, 100));
+ }
+
+ chart.update();
+ }
+ }
+ },
+ {
+ name: 'Remove Dataset',
+ handler(chart) {
+ chart.data.datasets.pop();
+ chart.update();
+ }
+ },
+ {
+ name: 'Remove Data',
+ handler(chart) {
+ chart.data.labels.splice(-1, 1); // remove the label first
+
+ chart.data.datasets.forEach(dataset => {
+ dataset.data.pop();
+ });
+
+ chart.update();
+ }
+ }
+];
+// </block:actions>
+
+// <block:setup:1>
+const DATA_COUNT = 5;
+const NUMBER_CFG = {count: DATA_COUNT, min: 0, max: 100};
+
+const data = {
+ labels: ['Red', 'Orange', 'Yellow', 'Green', 'Blue'],
+ datasets: [
+ {
+ label: 'Dataset 1',
+ data: Utils.numbers(NUMBER_CFG),
+ backgroundColor: Object.values(Utils.CHART_COLORS),
+ }
+ ]
+};
+// </block:setup>
+
+// <block:config:0>
+const config = {
+ type: 'pie',
+ data: data,
+ options: {
+ responsive: true,
+ plugins: {
+ legend: {
+ position: 'top',
+ },
+ title: {
+ display: true,
+ text: 'Chart.js Pie Chart'
+ }
+ }
+ },
+};
+// </block:config>
+
+module.exports = {
+ actions: actions,
+ config: config,
+};
+```
--- /dev/null
+# Polar area
+
+```js chart-editor
+// <block:actions:2>
+const actions = [
+ {
+ name: 'Randomize',
+ handler(chart) {
+ chart.data.datasets.forEach(dataset => {
+ dataset.data = Utils.numbers({count: chart.data.labels.length, min: 0, max: 100});
+ });
+ chart.update();
+ }
+ },
+ {
+ name: 'Add Data',
+ handler(chart) {
+ const data = chart.data;
+ if (data.datasets.length > 0) {
+ data.labels.push('data #' + (data.labels.length + 1));
+
+ for (var index = 0; index < data.datasets.length; ++index) {
+ data.datasets[index].data.push(Utils.rand(0, 100));
+ }
+
+ chart.update();
+ }
+ }
+ },
+ {
+ name: 'Remove Data',
+ handler(chart) {
+ chart.data.labels.splice(-1, 1); // remove the label first
+
+ chart.data.datasets.forEach(dataset => {
+ dataset.data.pop();
+ });
+
+ chart.update();
+ }
+ }
+];
+// </block:actions>
+
+// <block:setup:1>
+const DATA_COUNT = 5;
+const NUMBER_CFG = {count: DATA_COUNT, min: 0, max: 100};
+
+const labels = ['Red', 'Orange', 'Yellow', 'Green', 'Blue'];
+const data = {
+ labels: labels,
+ datasets: [
+ {
+ label: 'Dataset 1',
+ data: Utils.numbers(NUMBER_CFG),
+ backgroundColor: [
+ Utils.transparentize(Utils.CHART_COLORS.red, 0.5),
+ Utils.transparentize(Utils.CHART_COLORS.orange, 0.5),
+ Utils.transparentize(Utils.CHART_COLORS.yellow, 0.5),
+ Utils.transparentize(Utils.CHART_COLORS.green, 0.5),
+ Utils.transparentize(Utils.CHART_COLORS.blue, 0.5),
+ ]
+ }
+ ]
+};
+// </block:setup>
+
+// <block:config:0>
+const config = {
+ type: 'polarArea',
+ data: data,
+ options: {
+ responsive: true,
+ plugins: {
+ legend: {
+ position: 'top',
+ },
+ title: {
+ display: true,
+ text: 'Chart.js Polar Area Chart'
+ }
+ }
+ },
+};
+// </block:config>
+
+module.exports = {
+ actions: actions,
+ config: config,
+};
+```
--- /dev/null
+# Radar skip points
+
+```js chart-editor
+// <block:actions:2>
+const actions = [
+ {
+ name: 'Randomize',
+ handler(chart) {
+ chart.data.datasets.forEach((dataset, i) => {
+ const data = Utils.numbers({count: chart.data.labels.length, min: 0, max: 100});
+
+ if (i === 0) {
+ data[0] = null;
+ } else if (i === 1) {
+ data[Number.parseInt(data.length / 2, 10)] = null;
+ } else {
+ data[data.length - 1] = null;
+ }
+
+ dataset.data = data;
+ });
+ chart.update();
+ }
+ }
+];
+// </block:actions>
+
+// <block:setup:1>
+const DATA_COUNT = 7;
+const NUMBER_CFG = {count: DATA_COUNT, min: 0, max: 100};
+
+const labels = Utils.months({count: 7});
+const dataFirstSkip = Utils.numbers(NUMBER_CFG);
+const dataMiddleSkip = Utils.numbers(NUMBER_CFG);
+const dataLastSkip = Utils.numbers(NUMBER_CFG);
+
+dataFirstSkip[0] = null;
+dataMiddleSkip[Number.parseInt(dataMiddleSkip.length / 2, 10)] = null;
+dataLastSkip[dataLastSkip.length - 1] = null;
+
+const data = {
+ labels: labels,
+ datasets: [
+ {
+ label: 'Skip first dataset',
+ data: dataFirstSkip,
+ borderColor: Utils.CHART_COLORS.red,
+ backgroundColor: Utils.transparentize(Utils.CHART_COLORS.red, 0.5),
+ },
+ {
+ label: 'Skip mid dataset',
+ data: dataMiddleSkip,
+ borderColor: Utils.CHART_COLORS.blue,
+ backgroundColor: Utils.transparentize(Utils.CHART_COLORS.blue, 0.5),
+ },
+ {
+ label: 'Skip last dataset',
+ data: dataLastSkip,
+ borderColor: Utils.CHART_COLORS.green,
+ backgroundColor: Utils.transparentize(Utils.CHART_COLORS.green, 0.5),
+ }
+ ]
+};
+// </block:setup>
+
+// <block:config:0>
+const config = {
+ type: 'radar',
+ data: data,
+ options: {
+ responsive: true,
+ plugins: {
+ title: {
+ display: true,
+ text: 'Chart.js Radar Skip Points Chart'
+ }
+ }
+ },
+};
+// </block:config>
+
+module.exports = {
+ actions: actions,
+ config: config
+};
+```
+
--- /dev/null
+# Radar
+
+```js chart-editor
+// <block:actions:2>
+const actions = [
+ {
+ name: 'Randomize',
+ handler(chart) {
+ chart.data.datasets.forEach(dataset => {
+ dataset.data = Utils.numbers({count: chart.data.labels.length, min: 0, max: 100});
+ });
+ chart.update();
+ }
+ },
+ {
+ name: 'Add Dataset',
+ handler(chart) {
+ const data = chart.data;
+ const dsColor = Utils.namedColor(chart.data.datasets.length);
+ const newDataset = {
+ label: 'Dataset ' + (data.datasets.length + 1),
+ backgroundColor: Utils.transparentize(dsColor, 0.5),
+ borderColor: dsColor,
+ data: Utils.numbers({count: data.labels.length, min: 0, max: 100}),
+ };
+ chart.data.datasets.push(newDataset);
+ chart.update();
+ }
+ },
+ {
+ name: 'Add Data',
+ handler(chart) {
+ const data = chart.data;
+ if (data.datasets.length > 0) {
+ data.labels = Utils.months({count: data.labels.length + 1});
+
+ for (var index = 0; index < data.datasets.length; ++index) {
+ data.datasets[index].data.push(Utils.rand(0, 100));
+ }
+
+ chart.update();
+ }
+ }
+ },
+ {
+ name: 'Remove Dataset',
+ handler(chart) {
+ chart.data.datasets.pop();
+ chart.update();
+ }
+ },
+ {
+ name: 'Remove Data',
+ handler(chart) {
+ chart.data.labels.splice(-1, 1); // remove the label first
+
+ chart.data.datasets.forEach(dataset => {
+ dataset.data.pop();
+ });
+
+ chart.update();
+ }
+ }
+];
+// </block:actions>
+
+// <block:setup:1>
+const DATA_COUNT = 7;
+const NUMBER_CFG = {count: DATA_COUNT, min: 0, max: 100};
+
+const labels = Utils.months({count: 7});
+const data = {
+ labels: labels,
+ datasets: [
+ {
+ label: 'Dataset 1',
+ data: Utils.numbers(NUMBER_CFG),
+ borderColor: Utils.CHART_COLORS.red,
+ backgroundColor: Utils.transparentize(Utils.CHART_COLORS.red, 0.5),
+ },
+ {
+ label: 'Dataset 2',
+ data: Utils.numbers(NUMBER_CFG),
+ borderColor: Utils.CHART_COLORS.blue,
+ backgroundColor: Utils.transparentize(Utils.CHART_COLORS.blue, 0.5),
+ }
+ ]
+};
+// </block:setup>
+
+// <block:config:0>
+const config = {
+ type: 'radar',
+ data: data,
+ options: {
+ responsive: true,
+ plugins: {
+ title: {
+ display: true,
+ text: 'Chart.js Radar Chart'
+ }
+ }
+ },
+};
+// </block:config>
+
+module.exports = {
+ actions: actions,
+ config: config,
+};
+```
--- /dev/null
+# Scatter - Multi axis
+
+```js chart-editor
+// <block:actions:2>
+const actions = [
+ {
+ name: 'Randomize',
+ handler(chart) {
+ chart.data.datasets.forEach(dataset => {
+ dataset.data = Utils.bubbles({count: chart.data.labels.length, rmin: 1, rmax: 1, min: -100, max: 100});
+ });
+ chart.update();
+ }
+ },
+ {
+ name: 'Add Dataset',
+ handler(chart) {
+ const data = chart.data;
+ const dsColor = Utils.namedColor(chart.data.datasets.length);
+ const newDataset = {
+ label: 'Dataset ' + (data.datasets.length + 1),
+ backgroundColor: Utils.transparentize(dsColor, 0.5),
+ borderColor: dsColor,
+ data: Utils.bubbles({count: data.labels.length, rmin: 1, rmax: 1, min: -100, max: 100}),
+ };
+ chart.data.datasets.push(newDataset);
+ chart.update();
+ }
+ },
+ {
+ name: 'Add Data',
+ handler(chart) {
+ const data = chart.data;
+ if (data.datasets.length > 0) {
+
+ for (var index = 0; index < data.datasets.length; ++index) {
+ data.datasets[index].data.push(Utils.bubbles({count: 1, rmin: 1, rmax: 1, min: -100, max: 100})[0]);
+ }
+
+ chart.update();
+ }
+ }
+ },
+ {
+ name: 'Remove Dataset',
+ handler(chart) {
+ chart.data.datasets.pop();
+ chart.update();
+ }
+ },
+ {
+ name: 'Remove Data',
+ handler(chart) {
+ chart.data.labels.splice(-1, 1); // remove the label first
+
+ chart.data.datasets.forEach(dataset => {
+ dataset.data.pop();
+ });
+
+ chart.update();
+ }
+ }
+];
+// </block:actions>
+
+// <block:setup:1>
+const DATA_COUNT = 7;
+const NUMBER_CFG = {count: DATA_COUNT, rmin: 1, rmax: 1, min: -100, max: 100};
+
+const labels = Utils.months({count: 7});
+const data = {
+ labels: labels,
+ datasets: [
+ {
+ label: 'Dataset 1',
+ data: Utils.bubbles(NUMBER_CFG),
+ borderColor: Utils.CHART_COLORS.red,
+ backgroundColor: Utils.transparentize(Utils.CHART_COLORS.red, 0.5),
+ yAxisID: 'y',
+ },
+ {
+ label: 'Dataset 2',
+ data: Utils.bubbles(NUMBER_CFG),
+ borderColor: Utils.CHART_COLORS.orange,
+ backgroundColor: Utils.transparentize(Utils.CHART_COLORS.orange, 0.5),
+ yAxisID: 'y2',
+ }
+ ]
+};
+// </block:setup>
+
+// <block:config:0>
+const config = {
+ type: 'scatter',
+ data: data,
+ options: {
+ responsive: true,
+ plugins: {
+ legend: {
+ position: 'top',
+ },
+ title: {
+ display: true,
+ text: 'Chart.js Scatter Multi Axis Chart'
+ }
+ },
+ scales: {
+ y: {
+ type: 'linear', // only linear but allow scale type registration. This allows extensions to exist solely for log scale for instance
+ position: 'left',
+ ticks: {
+ color: Utils.CHART_COLORS.red
+ }
+ },
+ y2: {
+ type: 'linear', // only linear but allow scale type registration. This allows extensions to exist solely for log scale for instance
+ position: 'right',
+ reverse: true,
+ ticks: {
+ color: Utils.CHART_COLORS.blue
+ },
+ grid: {
+ drawOnChartArea: false // only want the grid lines for one axis to show up
+ }
+ }
+ }
+ },
+};
+// </block:config>
+
+module.exports = {
+ actions: actions,
+ config: config,
+};
+```
--- /dev/null
+# Scatter
+
+```js chart-editor
+// <block:actions:2>
+const actions = [
+ {
+ name: 'Randomize',
+ handler(chart) {
+ chart.data.datasets.forEach(dataset => {
+ dataset.data = Utils.bubbles({count: chart.data.labels.length, rmin: 1, rmax: 1, min: 0, max: 100});
+ });
+ chart.update();
+ }
+ },
+ {
+ name: 'Add Dataset',
+ handler(chart) {
+ const data = chart.data;
+ const dsColor = Utils.namedColor(chart.data.datasets.length);
+ const newDataset = {
+ label: 'Dataset ' + (data.datasets.length + 1),
+ backgroundColor: Utils.transparentize(dsColor, 0.5),
+ borderColor: dsColor,
+ data: Utils.bubbles({count: data.labels.length, rmin: 1, rmax: 1, min: 0, max: 100}),
+ };
+ chart.data.datasets.push(newDataset);
+ chart.update();
+ }
+ },
+ {
+ name: 'Add Data',
+ handler(chart) {
+ const data = chart.data;
+ if (data.datasets.length > 0) {
+
+ for (var index = 0; index < data.datasets.length; ++index) {
+ data.datasets[index].data.push(Utils.bubbles({count: 1, rmin: 1, rmax: 1, min: 0, max: 100})[0]);
+ }
+
+ chart.update();
+ }
+ }
+ },
+ {
+ name: 'Remove Dataset',
+ handler(chart) {
+ chart.data.datasets.pop();
+ chart.update();
+ }
+ },
+ {
+ name: 'Remove Data',
+ handler(chart) {
+ chart.data.labels.splice(-1, 1); // remove the label first
+
+ chart.data.datasets.forEach(dataset => {
+ dataset.data.pop();
+ });
+
+ chart.update();
+ }
+ }
+];
+// </block:actions>
+
+// <block:setup:1>
+const DATA_COUNT = 7;
+const NUMBER_CFG = {count: DATA_COUNT, rmin: 1, rmax: 1, min: 0, max: 100};
+
+const labels = Utils.months({count: 7});
+const data = {
+ labels: labels,
+ datasets: [
+ {
+ label: 'Dataset 1',
+ data: Utils.bubbles(NUMBER_CFG),
+ borderColor: Utils.CHART_COLORS.red,
+ backgroundColor: Utils.transparentize(Utils.CHART_COLORS.red, 0.5),
+ },
+ {
+ label: 'Dataset 2',
+ data: Utils.bubbles(NUMBER_CFG),
+ borderColor: Utils.CHART_COLORS.orange,
+ backgroundColor: Utils.transparentize(Utils.CHART_COLORS.orange, 0.5),
+ }
+ ]
+};
+// </block:setup>
+
+// <block:config:0>
+const config = {
+ type: 'scatter',
+ data: data,
+ options: {
+ responsive: true,
+ plugins: {
+ legend: {
+ position: 'top',
+ },
+ title: {
+ display: true,
+ text: 'Chart.js Scatter Chart'
+ }
+ }
+ },
+};
+// </block:config>
+
+module.exports = {
+ actions: actions,
+ config: config,
+};
+```
--- /dev/null
+# Center Positioning
+
+This sample show how to place the axis in the center of the chart area, instead of at the edges.
+
+```js chart-editor
+// <block:actions:2>
+const actions = [
+ {
+ name: 'Default Positions',
+ handler(chart) {
+ chart.options.scales.x.position = 'bottom';
+ chart.options.scales.y.position = 'left';
+ chart.update();
+ }
+ },
+ {
+ name: 'Position: center',
+ handler(chart) {
+ chart.options.scales.x.position = 'center';
+ chart.options.scales.y.position = 'center';
+ chart.update();
+ }
+ },
+ {
+ name: 'Position: Vertical: x=-60, Horizontal: y=30',
+ handler(chart) {
+ chart.options.scales.x.position = {y: 30};
+ chart.options.scales.y.position = {x: -60};
+ chart.update();
+ }
+ },
+];
+// </block:actions>
+
+
+// <block:setup:1>
+const DATA_COUNT = 6;
+const NUMBER_CFG = {count: DATA_COUNT, min: -100, max: 100};
+const data = {
+ datasets: [
+ {
+ label: 'Dataset 1',
+ data: Utils.points(NUMBER_CFG),
+ fill: false,
+ borderColor: Utils.CHART_COLORS.red,
+ backgroundColor: Utils.transparentize(Utils.CHART_COLORS.red, 0.5),
+ },
+ {
+ label: 'Dataset 2',
+ data: Utils.points(NUMBER_CFG),
+ fill: false,
+ borderColor: Utils.CHART_COLORS.blue,
+ backgroundColor: Utils.transparentize(Utils.CHART_COLORS.blue, 0.5),
+ }
+ ]
+};
+// </block:setup>
+
+// <block:config:0>
+const config = {
+ type: 'scatter',
+ data: data,
+ options: {
+ responsive: true,
+ plugins: {
+ title: {
+ display: true,
+ text: 'Axis Center Positioning'
+ }
+ },
+ scales: {
+ x: {
+ min: -100,
+ max: 100,
+ },
+ y: {
+ min: -100,
+ max: 100,
+ }
+ }
+ },
+};
+// </block:config>
+
+module.exports = {
+ actions: actions,
+ config: config,
+};
+```
\ No newline at end of file
--- /dev/null
+# Grid Configuration
+
+This sample shows how to use scriptable grid options for an axis to control styling. In this case, the Y axis grid lines are colored based on their value. In addition, booleans are provided to toggle different parts of the X axis grid visibility.
+
+```js chart-editor
+// <block:actions:2>
+const actions = [
+ {
+ name: 'Randomize',
+ handler(chart) {
+ chart.data.datasets.forEach(dataset => {
+ dataset.data = Utils.numbers({count: chart.data.labels.length, min: -100, max: 100});
+ });
+ chart.update();
+ }
+ },
+];
+// </block:actions>
+
+// <block:setup:1>
+const DATA_COUNT = 7;
+const data = {
+ labels: Utils.months({count: DATA_COUNT}),
+ datasets: [
+ {
+ label: 'Dataset 1',
+ data: [10, 30, 39, 20, 25, 34, -10],
+ fill: false,
+ borderColor: Utils.CHART_COLORS.red,
+ backgroundColor: Utils.transparentize(Utils.CHART_COLORS.red, 0.5),
+ },
+ {
+ label: 'Dataset 2',
+ data: [18, 33, 22, 19, 11, -39, 30],
+ fill: false,
+ borderColor: Utils.CHART_COLORS.blue,
+ backgroundColor: Utils.transparentize(Utils.CHART_COLORS.blue, 0.5),
+ }
+ ]
+};
+// </block:setup>
+
+// <block:config:0>
+// Change these settings to change the display for different parts of the X axis
+// grid configuiration
+const DISPLAY = true;
+const BORDER = true;
+const CHART_AREA = true;
+const TICKS = true;
+
+const config = {
+ type: 'line',
+ data: data,
+ options: {
+ responsive: true,
+ plugins: {
+ title: {
+ display: true,
+ text: 'Grid Line Settings'
+ }
+ },
+ scales: {
+ x: {
+ grid: {
+ display: DISPLAY,
+ drawBorder: BORDER,
+ drawOnChartArea: CHART_AREA,
+ drawTicks: TICKS,
+ }
+ },
+ y: {
+ grid: {
+ drawBorder: false,
+ color: function(context) {
+ if (context.tick.value > 0) {
+ return Utils.CHART_COLORS.green;
+ } else if (context.tick.value < 0) {
+ return Utils.CHART_COLORS.red;
+ }
+
+ return '#000000';
+ },
+ },
+ }
+ }
+ },
+};
+// </block:config>
+
+module.exports = {
+ actions: actions,
+ config: config,
+};
+```
--- /dev/null
+# Tick Configuration
+
+This sample shows how to use different tick features to control how tick labels are shown on the X axis. These features include:
+
+* Multi-line labels
+* Filtering labels
+* Changing the tick color
+* Changing the tick alignment for the X axis
+
+```js chart-editor
+// <block:actions:2>
+const actions = [
+ {
+ name: 'Alignment: start',
+ handler(chart) {
+ chart.options.scales.x.ticks.align = 'start';
+ chart.update();
+ }
+ },
+ {
+ name: 'Alignment: center (default)',
+ handler(chart) {
+ chart.options.scales.x.ticks.align = 'center';
+ chart.update();
+ }
+ },
+ {
+ name: 'Alignment: end',
+ handler(chart) {
+ chart.options.scales.x.ticks.align = 'end';
+ chart.update();
+ }
+ },
+];
+// </block:actions>
+
+
+// <block:setup:1>
+const DATA_COUNT = 12;
+const NUMBER_CFG = {count: DATA_COUNT, min: 0, max: 100};
+const data = {
+ labels: [['June', '2015'], 'July', 'August', 'September', 'October', 'November', 'December', ['January', '2016'], 'February', 'March', 'April', 'May'],
+ datasets: [
+ {
+ label: 'Dataset 1',
+ data: Utils.numbers(NUMBER_CFG),
+ fill: false,
+ borderColor: Utils.CHART_COLORS.red,
+ backgroundColor: Utils.transparentize(Utils.CHART_COLORS.red, 0.5),
+ },
+ {
+ label: 'Dataset 2',
+ data: Utils.numbers(NUMBER_CFG),
+ fill: false,
+ borderColor: Utils.CHART_COLORS.blue,
+ backgroundColor: Utils.transparentize(Utils.CHART_COLORS.blue, 0.5),
+ }
+ ]
+};
+// </block:setup>
+
+// <block:config:0>
+const config = {
+ type: 'line',
+ data: data,
+ options: {
+ responsive: true,
+ plugins: {
+ title: {
+ display: true,
+ text: 'Chart with Tick Configuration'
+ }
+ },
+ scales: {
+ x: {
+ ticks: {
+ // For a category axis, the val is the index so the lookup via getLabelForValue is needed
+ callback: function(val, index) {
+ // Hide the label of every 2nd dataset
+ return index % 2 === 0 ? this.getLabelForValue(val) : '';
+ },
+ color: 'red',
+ }
+ }
+ }
+ },
+};
+// </block:config>
+
+module.exports = {
+ actions: actions,
+ config: config,
+};
+```
--- /dev/null
+# Title Configuration
+
+This sample shows how to configure the title of an axis including alignment, font, and color.
+
+```js chart-editor
+// <block:setup:1>
+const DATA_COUNT = 7;
+const NUMBER_CFG = {count: DATA_COUNT, min: 0, max: 100};
+const data = {
+ labels: Utils.months({count: DATA_COUNT}),
+ datasets: [
+ {
+ label: 'Dataset 1',
+ data: Utils.numbers(NUMBER_CFG),
+ fill: false,
+ borderColor: Utils.CHART_COLORS.red,
+ backgroundColor: Utils.transparentize(Utils.CHART_COLORS.red, 0.5),
+ },
+ {
+ label: 'Dataset 2',
+ data: Utils.numbers(NUMBER_CFG),
+ fill: false,
+ borderColor: Utils.CHART_COLORS.blue,
+ backgroundColor: Utils.transparentize(Utils.CHART_COLORS.blue, 0.5),
+ }
+ ]
+};
+// </block:setup>
+
+// <block:config:0>
+const config = {
+ type: 'line',
+ data: data,
+ options: {
+ responsive: true,
+ scales: {
+ x: {
+ display: true,
+ title: {
+ display: true,
+ text: 'Month',
+ color: '#911',
+ font: {
+ family: 'Comic Sans MS',
+ size: 20,
+ style: 'bold',
+ lineHeight: 1.2,
+ },
+ padding: {top: 20, left: 0, right: 0, bottom: 0}
+ }
+ },
+ y: {
+ display: true,
+ title: {
+ display: true,
+ text: 'Value',
+ color: '#191',
+ font: {
+ family: 'Times',
+ size: 20,
+ style: 'normal',
+ lineHeight: 1.2,
+ },
+ padding: {top: 30, left: 0, right: 0, bottom: 0}
+ }
+ }
+ }
+ },
+};
+// </block:config>
+
+module.exports = {
+ actions: [],
+ config: config,
+};
+```
--- /dev/null
+# Linear Scale - Suggested Min-Max
+
+```js chart-editor
+// <block:setup:1>
+const DATA_COUNT = 7;
+const NUMBER_CFG = {count: DATA_COUNT, min: 0, max: 100};
+
+const labels = Utils.months({count: 7});
+const data = {
+ labels: labels,
+ datasets: [
+ {
+ label: 'Dataset 1',
+ data: [10, 30, 39, 20, 25, 34, -10],
+ borderColor: Utils.CHART_COLORS.red,
+ backgroundColor: Utils.CHART_COLORS.red,
+ },
+ {
+ label: 'Dataset 2',
+ data: [18, 33, 22, 19, 11, 39, 30],
+ borderColor: Utils.CHART_COLORS.blue,
+ backgroundColor: Utils.CHART_COLORS.blue,
+ }
+ ]
+};
+// </block:setup>
+
+// <block:config:0>
+const config = {
+ type: 'line',
+ data: data,
+ options: {
+ responsive: true,
+ plugins: {
+ title: {
+ display: true,
+ text: 'Suggested Min and Max Settings'
+ }
+ },
+ scales: {
+ y: {
+ // the data minimum used for determining the ticks is Math.min(dataMin, suggestedMin)
+ suggestedMin: 30,
+
+ // the data maximum used for determining the ticks is Math.max(dataMax, suggestedMax)
+ suggestedMax: 50,
+ }
+ }
+ },
+};
+// </block:config>
+
+module.exports = {
+ config: config,
+};
+```
--- /dev/null
+# Linear Scale - Min-Max
+
+```js chart-editor
+// <block:setup:1>
+const DATA_COUNT = 7;
+const NUMBER_CFG = {count: DATA_COUNT, min: 0, max: 100};
+
+const labels = Utils.months({count: 7});
+const data = {
+ labels: labels,
+ datasets: [
+ {
+ label: 'Dataset 1',
+ data: [10, 30, 50, 20, 25, 44, -10],
+ borderColor: Utils.CHART_COLORS.red,
+ backgroundColor: Utils.CHART_COLORS.red,
+ },
+ {
+ label: 'Dataset 2',
+ data: [100, 33, 22, 19, 11, 49, 30],
+ borderColor: Utils.CHART_COLORS.blue,
+ backgroundColor: Utils.CHART_COLORS.blue,
+ }
+ ]
+};
+// </block:setup>
+
+// <block:config:0>
+const config = {
+ type: 'line',
+ data: data,
+ options: {
+ responsive: true,
+ plugins: {
+ title: {
+ display: true,
+ text: 'Min and Max Settings'
+ }
+ },
+ scales: {
+ y: {
+ min: 10,
+ max: 50,
+ }
+ }
+ },
+};
+// </block:config>
+
+module.exports = {
+ config: config,
+};
+```
--- /dev/null
+# Linear Scale - Step Size
+
+```js chart-editor
+// <block:actions:2>
+const actions = [
+ {
+ name: 'Randomize',
+ handler(chart) {
+ chart.data.datasets.forEach(dataset => {
+ dataset.data = Utils.numbers({count: chart.data.labels.length, min: 0, max: 100});
+ });
+ chart.update();
+ }
+ },
+ {
+ name: 'Add Dataset',
+ handler(chart) {
+ const data = chart.data;
+ const dsColor = Utils.namedColor(chart.data.datasets.length);
+ const newDataset = {
+ label: 'Dataset ' + (data.datasets.length + 1),
+ backgroundColor: dsColor,
+ borderColor: dsColor,
+ data: Utils.numbers({count: data.labels.length, min: 0, max: 100}),
+ };
+ chart.data.datasets.push(newDataset);
+ chart.update();
+ }
+ },
+ {
+ name: 'Add Data',
+ handler(chart) {
+ const data = chart.data;
+ if (data.datasets.length > 0) {
+ data.labels = Utils.months({count: data.labels.length + 1});
+
+ for (var index = 0; index < data.datasets.length; ++index) {
+ data.datasets[index].data.push(Utils.rand(0, 100));
+ }
+
+ chart.update();
+ }
+ }
+ },
+ {
+ name: 'Remove Dataset',
+ handler(chart) {
+ chart.data.datasets.pop();
+ chart.update();
+ }
+ },
+ {
+ name: 'Remove Data',
+ handler(chart) {
+ chart.data.labels.splice(-1, 1); // remove the label first
+
+ chart.data.datasets.forEach(dataset => {
+ dataset.data.pop();
+ });
+
+ chart.update();
+ }
+ }
+];
+// </block:actions>
+
+// <block:setup:1>
+const DATA_COUNT = 7;
+const NUMBER_CFG = {count: DATA_COUNT, min: 0, max: 100};
+
+const labels = Utils.months({count: 7});
+const data = {
+ labels: labels,
+ datasets: [
+ {
+ label: 'Dataset 1',
+ data: Utils.numbers(NUMBER_CFG),
+ borderColor: Utils.CHART_COLORS.red,
+ backgroundColor: Utils.CHART_COLORS.red,
+ },
+ {
+ label: 'Dataset 2',
+ data: Utils.numbers(NUMBER_CFG),
+ borderColor: Utils.CHART_COLORS.blue,
+ backgroundColor: Utils.CHART_COLORS.blue,
+ }
+ ]
+};
+// </block:setup>
+
+// <block:config:0>
+const config = {
+ type: 'line',
+ data: data,
+ options: {
+ responsive: true,
+ plugins: {
+ tooltip: {
+ mode: 'index',
+ intersect: false
+ },
+ title: {
+ display: true,
+ text: 'Chart.js Line Chart'
+ }
+ },
+ hover: {
+ mode: 'index',
+ intersec: false
+ },
+ scales: {
+ x: {
+ title: {
+ display: true,
+ text: 'Month'
+ }
+ },
+ y: {
+ title: {
+ display: true,
+ text: 'Value'
+ },
+ min: 0,
+ max: 100,
+ ticks: {
+ // forces step size to be 50 units
+ stepSize: 50
+ }
+ }
+ }
+ },
+};
+// </block:config>
+
+module.exports = {
+ actions: actions,
+ config: config,
+};
+```
--- /dev/null
+# Log Scale
+
+```js chart-editor
+// <block:actions:2>
+const logNumbers = (num) => {
+ const data = [];
+
+ for (let i = 0; i < num; ++i) {
+ data.push(Math.ceil(Math.random() * 10.0) * Math.pow(10, Math.ceil(Math.random() * 5)));
+ }
+
+ return data;
+};
+
+const actions = [
+ {
+ name: 'Randomize',
+ handler(chart) {
+ chart.data.datasets.forEach(dataset => {
+ dataset.data = logNumbers(chart.data.labels.length);
+ });
+ chart.update();
+ }
+ },
+];
+// </block:actions>
+
+// <block:setup:1>
+const DATA_COUNT = 7;
+const NUMBER_CFG = {count: DATA_COUNT, min: 0, max: 100};
+
+const labels = Utils.months({count: 7});
+const data = {
+ labels: labels,
+ datasets: [
+ {
+ label: 'Dataset 1',
+ data: logNumbers(DATA_COUNT),
+ borderColor: Utils.CHART_COLORS.red,
+ backgroundColor: Utils.CHART_COLORS.red,
+ fill: false,
+ },
+ ]
+};
+// </block:setup>
+
+// <block:config:0>
+const config = {
+ type: 'line',
+ data: data,
+ options: {
+ responsive: true,
+ plugins: {
+ title: {
+ display: true,
+ text: 'Chart.js Line Chart - Logarithmic'
+ }
+ },
+ scales: {
+ x: {
+ display: true,
+ },
+ y: {
+ display: true,
+ type: 'logarithmic',
+ }
+ }
+ },
+};
+// </block:config>
+
+module.exports = {
+ actions: actions,
+ config: config,
+};
+```
--- /dev/null
+# Time Scale - Combo Chart
+
+```js chart-editor
+// <block:actions:2>
+const actions = [
+ {
+ name: 'Randomize',
+ handler(chart) {
+ chart.data.datasets.forEach(dataset => {
+ dataset.data = Utils.numbers({count: chart.data.labels.length, min: 0, max: 100});
+ });
+ chart.update();
+ }
+ },
+];
+// </block:actions>
+
+// <block:setup:1>
+const DATA_COUNT = 7;
+const NUMBER_CFG = {count: DATA_COUNT, min: 0, max: 100};
+
+const labels = [];
+
+for (let i = 0; i < DATA_COUNT; ++i) {
+ labels.push(Utils.newDate(i));
+}
+
+const data = {
+ labels: labels,
+ datasets: [{
+ type: 'bar',
+ label: 'Dataset 1',
+ backgroundColor: Utils.transparentize(Utils.CHART_COLORS.red, 0.5),
+ borderColor: Utils.CHART_COLORS.red,
+ data: Utils.numbers(NUMBER_CFG),
+ }, {
+ type: 'bar',
+ label: 'Dataset 2',
+ backgroundColor: Utils.transparentize(Utils.CHART_COLORS.blue, 0.5),
+ borderColor: Utils.CHART_COLORS.blue,
+ data: Utils.numbers(NUMBER_CFG),
+ }, {
+ type: 'line',
+ label: 'Dataset 3',
+ backgroundColor: Utils.transparentize(Utils.CHART_COLORS.green, 0.5),
+ borderColor: Utils.CHART_COLORS.green,
+ fill: false,
+ data: Utils.numbers(NUMBER_CFG),
+ }]
+};
+// </block:setup>
+
+// <block:config:0>
+const config = {
+ type: 'line',
+ data: data,
+ options: {
+ plugins: {
+ title: {
+ text: 'Chart.js Combo Time Scale',
+ display: true
+ }
+ },
+ scales: {
+ x: {
+ type: 'time',
+ display: true,
+ offset: true,
+ time: {
+ unit: 'day'
+ }
+ },
+ },
+ },
+};
+// </block:config>
+
+module.exports = {
+ actions: actions,
+ config: config,
+};
+```
--- /dev/null
+# Time Scale
+
+```js chart-editor
+// <block:actions:2>
+const actions = [
+ {
+ name: 'Randomize',
+ handler(chart) {
+ chart.data.datasets.forEach(dataset => {
+ dataset.data.forEach(function(dataObj, j) {
+ const newVal = Utils.rand(0, 100);
+
+ if (typeof dataObj === 'object') {
+ dataObj.y = newVal;
+ } else {
+ dataset.data[j] = newVal;
+ }
+ });
+ });
+ chart.update();
+ }
+ },
+];
+// </block:actions>
+
+// <block:setup:1>
+const DATA_COUNT = 7;
+const NUMBER_CFG = {count: DATA_COUNT, min: 0, max: 100};
+
+const data = {
+ labels: [ // Date Objects
+ Utils.newDate(0),
+ Utils.newDate(1),
+ Utils.newDate(2),
+ Utils.newDate(3),
+ Utils.newDate(4),
+ Utils.newDate(5),
+ Utils.newDate(6)
+ ],
+ datasets: [{
+ label: 'My First dataset',
+ backgroundColor: Utils.transparentize(Utils.CHART_COLORS.red, 0.5),
+ borderColor: Utils.CHART_COLORS.red,
+ fill: false,
+ data: Utils.numbers(NUMBER_CFG),
+ }, {
+ label: 'My Second dataset',
+ backgroundColor: Utils.transparentize(Utils.CHART_COLORS.blue, 0.5),
+ borderColor: Utils.CHART_COLORS.blue,
+ fill: false,
+ data: Utils.numbers(NUMBER_CFG),
+ }, {
+ label: 'Dataset with point data',
+ backgroundColor: Utils.transparentize(Utils.CHART_COLORS.green, 0.5),
+ borderColor: Utils.CHART_COLORS.green,
+ fill: false,
+ data: [{
+ x: Utils.newDateString(0),
+ y: Utils.rand(0, 100)
+ }, {
+ x: Utils.newDateString(5),
+ y: Utils.rand(0, 100)
+ }, {
+ x: Utils.newDateString(7),
+ y: Utils.rand(0, 100)
+ }, {
+ x: Utils.newDateString(15),
+ y: Utils.rand(0, 100)
+ }],
+ }]
+};
+// </block:setup>
+
+// <block:config:0>
+const config = {
+ type: 'line',
+ data: data,
+ options: {
+ plugins: {
+ title: {
+ text: 'Chart.js Time Scale',
+ display: true
+ }
+ },
+ scales: {
+ x: {
+ type: 'time',
+ time: {
+ // Luxon format string
+ tooltipFormat: 'DD T'
+ },
+ title: {
+ display: true,
+ text: 'Date'
+ }
+ },
+ y: {
+ title: {
+ display: true,
+ text: 'value'
+ }
+ }
+ },
+ },
+};
+// </block:config>
+
+module.exports = {
+ actions: actions,
+ config: config,
+};
+```
--- /dev/null
+# Time Scale - Max Span
+
+```js chart-editor
+// <block:actions:2>
+const actions = [
+ {
+ name: 'Randomize',
+ handler(chart) {
+ chart.data.datasets.forEach(dataset => {
+ dataset.data.forEach(function(dataObj, j) {
+ const newVal = Utils.rand(0, 100);
+
+ if (typeof dataObj === 'object') {
+ dataObj.y = newVal;
+ } else {
+ dataset.data[j] = newVal;
+ }
+ });
+ });
+ chart.update();
+ }
+ },
+];
+// </block:actions>
+
+// <block:setup:1>
+const data = {
+ datasets: [{
+ label: 'Dataset with string point data',
+ backgroundColor: Utils.transparentize(Utils.CHART_COLORS.red, 0.5),
+ borderColor: Utils.CHART_COLORS.red,
+ fill: false,
+ data: [{
+ x: Utils.newDateString(0),
+ y: Utils.rand(0, 100)
+ }, {
+ x: Utils.newDateString(2),
+ y: Utils.rand(0, 100)
+ }, {
+ x: Utils.newDateString(4),
+ y: Utils.rand(0, 100)
+ }, {
+ x: Utils.newDateString(6),
+ y: Utils.rand(0, 100)
+ }],
+ }, {
+ label: 'Dataset with date object point data',
+ backgroundColor: Utils.transparentize(Utils.CHART_COLORS.blue, 0.5),
+ borderColor: Utils.CHART_COLORS.blue,
+ fill: false,
+ data: [{
+ x: Utils.newDate(0),
+ y: Utils.rand(0, 100)
+ }, {
+ x: Utils.newDate(2),
+ y: Utils.rand(0, 100)
+ }, {
+ x: Utils.newDate(5),
+ y: Utils.rand(0, 100)
+ }, {
+ x: Utils.newDate(6),
+ y: Utils.rand(0, 100)
+ }]
+ }]
+};
+// </block:setup>
+
+// <block:config:0>
+const config = {
+ type: 'line',
+ data: data,
+ options: {
+ spanGaps: 1000 * 60 * 60 * 24 * 2, // 2 days
+ responsive: true,
+ interaction: {
+ mode: 'nearest',
+ },
+ plugins: {
+ title: {
+ display: true,
+ text: 'Chart.js Time - spanGaps: 172800000 (2 days in ms)'
+ },
+ },
+ scales: {
+ x: {
+ type: 'time',
+ display: true,
+ title: {
+ display: true,
+ text: 'Date'
+ },
+ ticks: {
+ autoSkip: false,
+ maxRotation: 0,
+ major: {
+ enabled: true
+ },
+ // color: function(context) {
+ // return context.tick && context.tick.major ? '#FF0000' : 'rgba(0,0,0,0.1)';
+ // },
+ font: function(context) {
+ if (context.tick && context.tick.major) {
+ return {
+ style: 'bold',
+ };
+ }
+ }
+ }
+ },
+ y: {
+ display: true,
+ title: {
+ display: true,
+ text: 'value'
+ }
+ }
+ }
+ },
+};
+// </block:config>
+
+module.exports = {
+ actions: [],
+ config: config,
+};
+```
--- /dev/null
+# Bar Chart
+
+```js chart-editor
+// <block:setup:2>
+var DATA_COUNT = 16;
+Utils.srand(110);
+
+const actions = [
+ {
+ name: 'Randomize',
+ handler(chart) {
+ chart.data.datasets.forEach(dataset => {
+ dataset.data = generateData();
+ });
+ chart.update();
+ }
+ },
+];
+// </block:setup>
+
+// <block:data:1>
+function generateData() {
+ return Utils.numbers({
+ count: DATA_COUNT,
+ min: -100,
+ max: 100
+ });
+}
+
+const data = {
+ labels: Utils.months({count: DATA_COUNT}),
+ datasets: [{
+ data: generateData(),
+ }]
+};
+// </block:data>
+
+// <block:options:0>
+function colorize(opaque) {
+ return (ctx) => {
+ var v = ctx.parsed.y;
+ var c = v < -50 ? '#D60000'
+ : v < 0 ? '#F46300'
+ : v < 50 ? '#0358B6'
+ : '#44DE28';
+
+ return opaque ? c : Utils.transparentize(c, 1 - Math.abs(v / 150));
+ };
+}
+
+const config = {
+ type: 'bar',
+ data: data,
+ options: {
+ plugins: {
+ legend: false,
+ },
+ elements: {
+ bar: {
+ backgroundColor: colorize(false),
+ borderColor: colorize(true),
+ borderWidth: 2
+ }
+ }
+ }
+};
+// </block:options>
+
+module.exports = {
+ actions,
+ config,
+};
+```
--- /dev/null
+# Bubble Chart
+
+```js chart-editor
+// <block:setup:2>
+const DATA_COUNT = 16;
+const MIN_XY = -150;
+const MAX_XY = 100;
+Utils.srand(110);
+
+const actions = [
+ {
+ name: 'Randomize',
+ handler(chart) {
+ chart.data.datasets.forEach(dataset => {
+ dataset.data = generateData();
+ });
+ chart.update();
+ }
+ },
+];
+// </block:setup>
+
+// <block:data:1>
+function generateData() {
+ var data = [];
+ var i;
+
+ for (i = 0; i < DATA_COUNT; ++i) {
+ data.push({
+ x: Utils.rand(MIN_XY, MAX_XY),
+ y: Utils.rand(MIN_XY, MAX_XY),
+ v: Utils.rand(0, 1000)
+ });
+ }
+
+ return data;
+}
+
+const data = {
+ datasets: [{
+ data: generateData()
+ }, {
+ data: generateData()
+ }]
+};
+// </block:data>
+
+// <block:options:0>
+function channelValue(x, y, values) {
+ return x < 0 && y < 0 ? values[0] : x < 0 ? values[1] : y < 0 ? values[2] : values[3];
+}
+
+function colorize(opaque, context) {
+ var value = context.raw;
+ var x = value.x / 100;
+ var y = value.y / 100;
+ var r = channelValue(x, y, [250, 150, 50, 0]);
+ var g = channelValue(x, y, [0, 50, 150, 250]);
+ var b = channelValue(x, y, [0, 150, 150, 250]);
+ var a = opaque ? 1 : 0.5 * value.v / 1000;
+
+ return 'rgba(' + r + ',' + g + ',' + b + ',' + a + ')';
+}
+
+const config = {
+ type: 'bubble',
+ data: data,
+ options: {
+ aspectRatio: 1,
+ plugins: {
+ legend: false,
+ tooltip: false,
+ },
+ elements: {
+ point: {
+ backgroundColor: colorize.bind(null, false),
+
+ borderColor: colorize.bind(null, true),
+
+ borderWidth: function(context) {
+ return Math.min(Math.max(1, context.datasetIndex + 1), 8);
+ },
+
+ hoverBackgroundColor: 'transparent',
+
+ hoverBorderColor: function(context) {
+ return Utils.color(context.datasetIndex);
+ },
+
+ hoverBorderWidth: function(context) {
+ return Math.round(8 * context.raw.v / 1000);
+ },
+
+ radius: function(context) {
+ var size = context.chart.width;
+ var base = Math.abs(context.raw.v) / 1000;
+ return (size / 24) * base;
+ }
+ }
+ }
+ }
+};
+// </block:options>
+
+module.exports = {
+ actions,
+ config,
+};
+```
--- /dev/null
+# Line Chart
+
+```js chart-editor
+// <block:setup:2>
+const DATA_COUNT = 12;
+Utils.srand(110);
+
+const actions = [
+ {
+ name: 'Randomize',
+ handler(chart) {
+ chart.data.datasets.forEach(dataset => {
+ dataset.data = generateData();
+ });
+ chart.update();
+ }
+ },
+];
+// </block:setup>
+
+// <block:data:1>
+function generateData() {
+ return Utils.numbers({
+ count: DATA_COUNT,
+ min: 0,
+ max: 100
+ });
+}
+
+const data = {
+ labels: Utils.months({count: DATA_COUNT}),
+ datasets: [{
+ data: generateData()
+ }]
+};
+// </block:data>
+
+// <block:options:0>
+function getLineColor(ctx) {
+ return Utils.color(ctx.datasetIndex);
+}
+
+function alternatePointStyles(ctx) {
+ var index = ctx.dataIndex;
+ return index % 2 === 0 ? 'circle' : 'rect';
+}
+
+function makeHalfAsOpaque(ctx) {
+ return Utils.transparentize(getLineColor(ctx));
+}
+
+function adjustRadiusBasedOnData(ctx) {
+ var v = ctx.parsed.y;
+ return v < 10 ? 5
+ : v < 25 ? 7
+ : v < 50 ? 9
+ : v < 75 ? 11
+ : 15;
+}
+
+const config = {
+ type: 'line',
+ data: data,
+ options: {
+ plugins: {
+ legend: false,
+ tooltip: true,
+ },
+ elements: {
+ line: {
+ fill: false,
+ backgroundColor: getLineColor,
+ borderColor: getLineColor,
+ },
+ point: {
+ backgroundColor: getLineColor,
+ hoverBackgroundColor: makeHalfAsOpaque,
+ radius: adjustRadiusBasedOnData,
+ pointStyle: alternatePointStyles,
+ hoverRadius: 15,
+ }
+ }
+ }
+};
+// </block:options>
+
+module.exports = {
+ actions,
+ config,
+};
+```
--- /dev/null
+# Pie Chart
+
+```js chart-editor
+// <block:setup:2>
+const DATA_COUNT = 5;
+Utils.srand(110);
+
+const actions = [
+ {
+ name: 'Randomize',
+ handler(chart) {
+ chart.data.datasets.forEach(dataset => {
+ dataset.data = generateData();
+ });
+ chart.update();
+ }
+ },
+ {
+ name: 'Toggle Doughnut View',
+ handler(chart) {
+ if (chart.options.cutout) {
+ chart.options.cutout = 0;
+ } else {
+ chart.options.cutout = '50%';
+ }
+ chart.update();
+ }
+ }
+];
+// </block:setup>
+
+// <block:data:1>
+function generateData() {
+ return Utils.numbers({
+ count: DATA_COUNT,
+ min: -100,
+ max: 100
+ });
+}
+
+const data = {
+ datasets: [{
+ data: generateData()
+ }]
+};
+// </block:data>
+
+// <block:options:0>
+function colorize(opaque, hover, ctx) {
+ var v = ctx.parsed;
+ var c = v < -50 ? '#D60000'
+ : v < 0 ? '#F46300'
+ : v < 50 ? '#0358B6'
+ : '#44DE28';
+
+ var opacity = hover ? 1 - Math.abs(v / 150) - 0.2 : 1 - Math.abs(v / 150);
+
+ return opaque ? c : Utils.transparentize(c, opacity);
+}
+
+function hoverColorize(ctx) {
+ return colorize(false, true, ctx);
+}
+
+const config = {
+ type: 'pie',
+ data: data,
+ options: {
+ plugins: {
+ legend: false,
+ tooltip: false,
+ },
+ elements: {
+ arc: {
+ backgroundColor: colorize.bind(null, false, false),
+ hoverBackgroundColor: hoverColorize
+ }
+ }
+ }
+};
+// </block:options>
+
+module.exports = {
+ actions,
+ config,
+};
+```
--- /dev/null
+# Polar Area Chart
+
+```js chart-editor
+// <block:setup:2>
+const DATA_COUNT = 7;
+Utils.srand(110);
+
+const actions = [
+ {
+ name: 'Randomize',
+ handler(chart) {
+ chart.data.datasets.forEach(dataset => {
+ dataset.data = generateData();
+ });
+ chart.update();
+ }
+ },
+];
+// </block:setup>
+
+// <block:data:1>
+function generateData() {
+ return Utils.numbers({
+ count: DATA_COUNT,
+ min: 0,
+ max: 100
+ });
+}
+
+const data = {
+ labels: Utils.months({count: DATA_COUNT}),
+ datasets: [{
+ data: generateData()
+ }]
+};
+// </block:data>
+
+// <block:options:0>
+function colorize(opaque, hover, ctx) {
+ var v = ctx.raw;
+ var c = v < 35 ? '#D60000'
+ : v < 55 ? '#F46300'
+ : v < 75 ? '#0358B6'
+ : '#44DE28';
+
+ var opacity = hover ? 1 - Math.abs(v / 150) - 0.2 : 1 - Math.abs(v / 150);
+
+ return opaque ? c : Utils.transparentize(c, opacity);
+}
+
+function hoverColorize(ctx) {
+ return colorize(false, true, ctx);
+}
+
+const config = {
+ type: 'polarArea',
+ data: data,
+ options: {
+ plugins: {
+ legend: false,
+ tooltip: false,
+ },
+ elements: {
+ arc: {
+ backgroundColor: colorize.bind(null, false, false),
+ hoverBackgroundColor: hoverColorize
+ }
+ }
+ }
+};
+// </block:options>
+
+module.exports = {
+ actions,
+ config,
+};
+```
--- /dev/null
+# Radar Chart
+
+```js chart-editor
+// <block:setup:2>
+const DATA_COUNT = 7;
+Utils.srand(110);
+
+const actions = [
+ {
+ name: 'Randomize',
+ handler(chart) {
+ chart.data.datasets.forEach(dataset => {
+ dataset.data = generateData();
+ });
+ chart.update();
+ }
+ },
+];
+// </block:setup>
+
+// <block:data:1>
+function generateData() {
+ return Utils.numbers({
+ count: DATA_COUNT,
+ min: 0,
+ max: 100
+ });
+}
+
+const data = {
+ labels: [['Eating', 'Dinner'], ['Drinking', 'Water'], 'Sleeping', ['Designing', 'Graphics'], 'Coding', 'Cycling', 'Running'],
+ datasets: [{
+ data: generateData()
+ }]
+};
+// </block:data>
+
+// <block:options:0>
+function getLineColor(ctx) {
+ return Utils.color(ctx.datasetIndex);
+}
+
+function alternatePointStyles(ctx) {
+ var index = ctx.dataIndex;
+ return index % 2 === 0 ? 'circle' : 'rect';
+}
+
+function makeHalfAsOpaque(ctx) {
+ return Utils.transparentize(getLineColor(ctx));
+}
+
+function make20PercentOpaque(ctx) {
+ return Utils.transparentize(getLineColor(ctx), 0.8);
+}
+
+function adjustRadiusBasedOnData(ctx) {
+ var v = ctx.parsed.y;
+ return v < 10 ? 5
+ : v < 25 ? 7
+ : v < 50 ? 9
+ : v < 75 ? 11
+ : 15;
+}
+
+const config = {
+ type: 'radar',
+ data: data,
+ options: {
+ plugins: {
+ legend: false,
+ tooltip: false,
+ },
+ elements: {
+ line: {
+ backgroundColor: make20PercentOpaque,
+ borderColor: getLineColor,
+ },
+ point: {
+ backgroundColor: getLineColor,
+ hoverBackgroundColor: makeHalfAsOpaque,
+ radius: adjustRadiusBasedOnData,
+ pointStyle: alternatePointStyles,
+ hoverRadius: 15,
+ }
+ }
+ }
+};
+// </block:options>
+
+module.exports = {
+ actions,
+ config,
+};
+```
--- /dev/null
+# Alignment
+
+This sample show how to configure the alignment of the chart title
+
+```js chart-editor
+// <block:actions:2>
+const actions = [
+ {
+ name: 'Title Alignment: start',
+ handler(chart) {
+ chart.options.plugins.title.align = 'start';
+ chart.update();
+ }
+ },
+ {
+ name: 'Title Alignment: center (default)',
+ handler(chart) {
+ chart.options.plugins.title.align = 'center';
+ chart.update();
+ }
+ },
+ {
+ name: 'Title Alignment: end',
+ handler(chart) {
+ chart.options.plugins.title.align = 'end';
+ chart.update();
+ }
+ },
+];
+// </block:actions>
+
+
+// <block:setup:1>
+const DATA_COUNT = 7;
+const NUMBER_CFG = {count: DATA_COUNT, min: -100, max: 100};
+const data = {
+ labels: Utils.months({count: DATA_COUNT}),
+ datasets: [
+ {
+ label: 'Dataset 1',
+ data: Utils.numbers(NUMBER_CFG),
+ fill: false,
+ borderColor: Utils.CHART_COLORS.red,
+ backgroundColor: Utils.transparentize(Utils.CHART_COLORS.red, 0.5),
+ },
+ ]
+};
+// </block:setup>
+
+// <block:config:0>
+const config = {
+ type: 'line',
+ data: data,
+ options: {
+ plugins: {
+ title: {
+ display: true,
+ text: 'Chart Title',
+ }
+ }
+ }
+};
+// </block:config>
+
+module.exports = {
+ actions: actions,
+ config: config,
+};
+```
\ No newline at end of file
--- /dev/null
+# Custom Tooltip Content
+
+This sample shows how to use the tooltip callbacks to add additional content to the tooltip.
+
+```js chart-editor
+// <block:footer:2>
+const footer = (tooltipItems) => {
+ let sum = 0;
+
+ tooltipItems.forEach(function(tooltipItem) {
+ sum += tooltipItem.parsed.y;
+ });
+ return 'Sum: ' + sum;
+};
+
+// </block:footer>
+
+// <block:setup:1>
+const DATA_COUNT = 7;
+const NUMBER_CFG = {count: DATA_COUNT, min: -100, max: 100, decimals: 0};
+const data = {
+ labels: Utils.months({count: DATA_COUNT}),
+ datasets: [
+ {
+ label: 'Dataset 1',
+ data: Utils.numbers(NUMBER_CFG),
+ fill: false,
+ borderColor: Utils.CHART_COLORS.red,
+ backgroundColor: Utils.transparentize(Utils.CHART_COLORS.red, 0.5),
+ },
+ {
+ label: 'Dataset 2',
+ data: Utils.numbers(NUMBER_CFG),
+ fill: false,
+ borderColor: Utils.CHART_COLORS.blue,
+ backgroundColor: Utils.transparentize(Utils.CHART_COLORS.blue, 0.5),
+ },
+ ]
+};
+// </block:setup>
+
+// <block:config:0>
+const config = {
+ type: 'line',
+ data: data,
+ options: {
+ interaction: {
+ intersect: false,
+ mode: 'index',
+ },
+ plugins: {
+ tooltip: {
+ callbacks: {
+ footer: footer,
+ }
+ }
+ }
+ }
+};
+// </block:config>
+
+module.exports = {
+ actions: [],
+ config: config,
+};
+```
\ No newline at end of file
--- /dev/null
+# External HTML Tooltip
+
+This sample shows how to use the external tooltip functionality to generate an HTML tooltip.
+
+```js chart-editor
+// <block:external:2>
+const getOrCreateTooltip = (chart) => {
+ let tooltipEl = chart.canvas.parentNode.querySelector('div');
+
+ if (!tooltipEl) {
+ tooltipEl = document.createElement('div');
+ tooltipEl.style.background = 'rgba(0, 0, 0, 0.7)';
+ tooltipEl.style.borderRadius = '3px';
+ tooltipEl.style.color = 'white';
+ tooltipEl.style.opacity = 1;
+ tooltipEl.style.pointerEvents = 'none';
+ tooltipEl.style.position = 'absolute';
+ tooltipEl.style.transform = 'translate(-50%, 0)';
+ tooltipEl.style.transition = 'all .1s ease';
+
+ const table = document.createElement('table');
+ table.style.margin = '0px';
+
+ tooltipEl.appendChild(table);
+ chart.canvas.parentNode.appendChild(tooltipEl);
+ }
+
+ return tooltipEl;
+};
+
+const externalTooltipHandler = (context) => {
+ // Tooltip Element
+ const {chart, tooltip} = context;
+ const tooltipEl = getOrCreateTooltip(chart);
+
+ // Hide if no tooltip
+ if (tooltip.opacity === 0) {
+ tooltipEl.style.opacity = 0;
+ return;
+ }
+
+ // Set Text
+ if (tooltip.body) {
+ const titleLines = tooltip.title || [];
+ const bodyLines = tooltip.body.map(b => b.lines);
+
+ const tableHead = document.createElement('thead');
+
+ titleLines.forEach(title => {
+ const tr = document.createElement('tr');
+ tr.style.borderWidth = 0;
+
+ const th = document.createElement('th');
+ th.style.borderWidth = 0;
+ const text = document.createTextNode(title);
+
+ th.appendChild(text);
+ tr.appendChild(th);
+ tableHead.appendChild(tr);
+ });
+
+ const tableBody = document.createElement('tbody');
+ bodyLines.forEach((body, i) => {
+ const colors = tooltip.labelColors[i];
+
+ const span = document.createElement('span');
+ span.style.background = colors.backgroundColor;
+ span.style.borderColor = colors.borderColor;
+ span.style.borderWidth = '2px';
+ span.style.marginRight = '10px';
+ span.style.height = '10px';
+ span.style.width = '10px';
+ span.style.display = 'inline-block';
+
+ const tr = document.createElement('tr');
+ tr.style.backgroundColor = 'inherit';
+ tr.style.borderWidth = 0;
+
+ const td = document.createElement('td');
+ td.style.borderWidth = 0;
+
+ const text = document.createTextNode(body);
+
+ td.appendChild(span);
+ td.appendChild(text);
+ tr.appendChild(td);
+ tableBody.appendChild(tr);
+ });
+
+ const tableRoot = tooltipEl.querySelector('table');
+
+ // Remove old children
+ while (tableRoot.firstChild) {
+ tableRoot.firstChild.remove();
+ }
+
+ // Add new children
+ tableRoot.appendChild(tableHead);
+ tableRoot.appendChild(tableBody);
+ }
+
+ const {offsetLeft: positionX, offsetTop: positionY} = chart.canvas;
+
+ // Display, position, and set styles for font
+ tooltipEl.style.opacity = 1;
+ tooltipEl.style.left = positionX + tooltip.caretX + 'px';
+ tooltipEl.style.top = positionY + tooltip.caretY + 'px';
+ tooltipEl.style.font = tooltip.options.bodyFont.string;
+ tooltipEl.style.padding = tooltip.padding + 'px ' + tooltip.padding + 'px';
+};
+// </block:external>
+
+// <block:setup:1>
+const DATA_COUNT = 7;
+const NUMBER_CFG = {count: DATA_COUNT, min: -100, max: 100, decimals: 0};
+const data = {
+ labels: Utils.months({count: DATA_COUNT}),
+ datasets: [
+ {
+ label: 'Dataset 1',
+ data: Utils.numbers(NUMBER_CFG),
+ fill: false,
+ borderColor: Utils.CHART_COLORS.red,
+ backgroundColor: Utils.transparentize(Utils.CHART_COLORS.red, 0.5),
+ },
+ {
+ label: 'Dataset 2',
+ data: Utils.numbers(NUMBER_CFG),
+ fill: false,
+ borderColor: Utils.CHART_COLORS.blue,
+ backgroundColor: Utils.transparentize(Utils.CHART_COLORS.blue, 0.5),
+ },
+ ]
+};
+// </block:setup>
+
+// <block:config:0>
+const config = {
+ type: 'line',
+ data: data,
+ options: {
+ interaction: {
+ mode: 'index',
+ intersect: false,
+ },
+ plugins: {
+ title: {
+ display: true,
+ text: 'Chart.js Line Chart - External Tooltips'
+ },
+ tooltip: {
+ enabled: false,
+ position: 'nearest',
+ external: externalTooltipHandler
+ }
+ }
+ }
+};
+// </block:config>
+
+module.exports = {
+ actions: [],
+ config: config,
+};
+```
--- /dev/null
+# Interaction Modes
+
+This sample shows how to use the tooltip position mode setting.
+
+```js chart-editor
+// <block:actions:2>
+const actions = [
+ {
+ name: 'Mode: index',
+ handler(chart) {
+ chart.options.interaction.mode = 'index';
+ chart.update();
+ }
+ },
+ {
+ name: 'Mode: dataset',
+ handler(chart) {
+ chart.options.interaction.mode = 'dataset';
+ chart.update();
+ }
+ },
+ {
+ name: 'Mode: point',
+ handler(chart) {
+ chart.options.interaction.mode = 'point';
+ chart.update();
+ }
+ },
+ {
+ name: 'Mode: nearest',
+ handler(chart) {
+ chart.options.interaction.mode = 'nearest';
+ chart.update();
+ }
+ },
+ {
+ name: 'Mode: x',
+ handler(chart) {
+ chart.options.interaction.mode = 'x';
+ chart.update();
+ }
+ },
+ {
+ name: 'Mode: y',
+ handler(chart) {
+ chart.options.interaction.mode = 'y';
+ chart.update();
+ }
+ },
+ {
+ name: 'Toggle Intersect',
+ handler(chart) {
+ chart.options.interaction.intersect = !chart.options.interaction.intersect;
+ chart.update();
+ }
+ },
+];
+// </block:actions>
+
+// <block:setup:1>
+const DATA_COUNT = 7;
+const NUMBER_CFG = {count: DATA_COUNT, min: -100, max: 100};
+const data = {
+ labels: Utils.months({count: DATA_COUNT}),
+ datasets: [
+ {
+ label: 'Dataset 1',
+ data: Utils.numbers(NUMBER_CFG),
+ fill: false,
+ borderColor: Utils.CHART_COLORS.red,
+ backgroundColor: Utils.transparentize(Utils.CHART_COLORS.red, 0.5),
+ },
+ {
+ label: 'Dataset 2',
+ data: Utils.numbers(NUMBER_CFG),
+ fill: false,
+ borderColor: Utils.CHART_COLORS.blue,
+ backgroundColor: Utils.transparentize(Utils.CHART_COLORS.blue, 0.5),
+ },
+ ]
+};
+// </block:setup>
+
+// <block:config:0>
+const config = {
+ type: 'line',
+ data: data,
+ options: {
+ interaction: {
+ intersect: false,
+ mode: 'index',
+ },
+ plugins: {
+ title: {
+ display: true,
+ text: (ctx) => {
+ const {intersect, mode} = ctx.chart.options.interaction;
+ return 'Mode: ' + mode + ', intersect: ' + intersect;
+ }
+ },
+ }
+ }
+};
+// </block:config>
+
+module.exports = {
+ actions: actions,
+ config: config,
+};
+```
\ No newline at end of file
--- /dev/null
+# Point Style
+
+This sample shows how to use the dataset point style in the tooltip instead of a rectangle to identify each dataset.
+
+```js chart-editor
+// <block:actions:2>
+const actions = [
+ {
+ name: 'Toggle Tooltip Point Style',
+ handler(chart) {
+ chart.options.plugins.tooltip.usePointStyle = !chart.options.plugins.tooltip.usePointStyle;
+ chart.update();
+ }
+ },
+];
+// </block:actions>
+
+// <block:setup:1>
+const DATA_COUNT = 7;
+const NUMBER_CFG = {count: DATA_COUNT, min: -100, max: 100};
+const data = {
+ labels: Utils.months({count: DATA_COUNT}),
+ datasets: [
+ {
+ label: 'Triangles',
+ data: Utils.numbers(NUMBER_CFG),
+ fill: false,
+ borderColor: Utils.CHART_COLORS.red,
+ backgroundColor: Utils.transparentize(Utils.CHART_COLORS.red, 0.5),
+ pointStyle: 'triangle',
+ pointRadius: 6,
+ },
+ {
+ label: 'Circles',
+ data: Utils.numbers(NUMBER_CFG),
+ fill: false,
+ borderColor: Utils.CHART_COLORS.blue,
+ backgroundColor: Utils.transparentize(Utils.CHART_COLORS.blue, 0.5),
+ pointStyle: 'circle',
+ pointRadius: 6,
+ },
+ {
+ label: 'Stars',
+ data: Utils.numbers(NUMBER_CFG),
+ fill: false,
+ borderColor: Utils.CHART_COLORS.green,
+ backgroundColor: Utils.transparentize(Utils.CHART_COLORS.green, 0.5),
+ pointStyle: 'star',
+ pointRadius: 6,
+ }
+ ]
+};
+// </block:setup>
+
+// <block:config:0>
+const config = {
+ type: 'line',
+ data: data,
+ options: {
+ interaction: {
+ mode: 'index',
+ },
+ plugins: {
+ title: {
+ display: true,
+ text: (ctx) => 'Tooltip point style: ' + ctx.chart.options.plugins.tooltip.usePointStyle,
+ },
+ tooltip: {
+ usePointStyle: true,
+ }
+ }
+ }
+};
+// </block:config>
+
+module.exports = {
+ actions: actions,
+ config: config,
+};
+```
\ No newline at end of file
--- /dev/null
+# Position
+
+This sample shows how to use the tooltip position mode setting.
+
+```js chart-editor
+// <block:actions:3>
+const actions = [
+ {
+ name: 'Position: average',
+ handler(chart) {
+ chart.options.plugins.tooltip.position = 'average';
+ chart.update();
+ }
+ },
+ {
+ name: 'Position: nearest',
+ handler(chart) {
+ chart.options.plugins.tooltip.position = 'nearest';
+ chart.update();
+ }
+ },
+ {
+ name: 'Position: bottom (custom)',
+ handler(chart) {
+ chart.options.plugins.tooltip.position = 'bottom';
+ chart.update();
+ }
+ },
+];
+// </block:actions>
+
+// <block:setup:2>
+const DATA_COUNT = 7;
+const NUMBER_CFG = {count: DATA_COUNT, min: -100, max: 100};
+const data = {
+ labels: Utils.months({count: DATA_COUNT}),
+ datasets: [
+ {
+ label: 'Dataset 1',
+ data: Utils.numbers(NUMBER_CFG),
+ fill: false,
+ borderColor: Utils.CHART_COLORS.red,
+ backgroundColor: Utils.transparentize(Utils.CHART_COLORS.red, 0.5),
+ },
+ {
+ label: 'Dataset 2',
+ data: Utils.numbers(NUMBER_CFG),
+ fill: false,
+ borderColor: Utils.CHART_COLORS.blue,
+ backgroundColor: Utils.transparentize(Utils.CHART_COLORS.blue, 0.5),
+ },
+ ]
+};
+// </block:setup>
+
+// <block:positioner:1>
+// Create a custom tooltip positioner to put at the bottom of the chart area
+components.Tooltip.positioners.bottom = function(items) {
+ const pos = components.Tooltip.positioners.average(items);
+ const chart = this._chart;
+
+ return {
+ x: pos.x,
+ y: chart.chartArea.bottom,
+ };
+};
+
+// </block:positioner>
+
+// <block:config:0>
+const config = {
+ type: 'line',
+ data: data,
+ options: {
+ interaction: {
+ intersect: false,
+ mode: 'index',
+ },
+ plugins: {
+ title: {
+ display: true,
+ text: (ctx) => 'Tooltip position mode: ' + ctx.chart.options.plugins.tooltip.position,
+ },
+ }
+ }
+};
+// </block:config>
+
+module.exports = {
+ actions: actions,
+ config: config,
+};
+```
\ No newline at end of file
--- /dev/null
+export default {
+ id: 'samples-filler-analyser',
+
+ beforeInit: function(chart, args, options) {
+ this.element = document.getElementById(options.target);
+ },
+
+ afterUpdate: function(chart) {
+ var datasets = chart.data.datasets;
+ var element = this.element;
+ var stats = [];
+ var meta, i, ilen, dataset;
+
+ if (!element) {
+ return;
+ }
+
+ for (i = 0, ilen = datasets.length; i < ilen; ++i) {
+ meta = chart.getDatasetMeta(i).$filler;
+ if (meta) {
+ dataset = datasets[i];
+ stats.push({
+ fill: dataset.fill,
+ target: meta.fill,
+ visible: meta.visible,
+ index: i
+ });
+ }
+ }
+
+ this.element.innerHTML = '<table>' +
+ '<tr>' +
+ '<th>Dataset</th>' +
+ '<th>Fill</th>' +
+ '<th>Target (visibility)</th>' +
+ '</tr>' +
+ stats.map(function(stat) {
+ var target = stat.target;
+ var row =
+ '<td><b>' + stat.index + '</b></td>' +
+ '<td>' + JSON.stringify(stat.fill) + '</td>';
+
+ if (target === false) {
+ target = 'none';
+ } else if (isFinite(target)) {
+ target = 'dataset ' + target;
+ } else {
+ target = 'boundary "' + target + '"';
+ }
+
+ if (stat.visible) {
+ row += '<td>' + target + '</td>';
+ } else {
+ row += '<td>(hidden)</td>';
+ }
+
+ return '<tr>' + row + '</tr>';
+ }).join('') + '</table>';
+ }
+};
--- /dev/null
+// Add Chart components needed in samples here.
+// Usable through `components[name]`.
+export {Tooltip} from '../../dist/chart.esm';
--- /dev/null
+import {Chart, BubbleController} from 'chart.js';
+
+class Custom extends BubbleController {
+ draw() {
+ // Call bubble controller method to draw all the points
+ super.draw(arguments);
+
+ // Now we can do some custom drawing for this dataset.
+ // Here we'll draw a box around the first point in each dataset,
+ // using `boxStrokeStyle` dataset option for color
+ var meta = this.getMeta();
+ var pt0 = meta.data[0];
+
+ const {x, y} = pt0.getProps(['x', 'y']);
+ const {radius} = pt0.options;
+
+ var ctx = this.chart.ctx;
+ ctx.save();
+ ctx.strokeStyle = this.options.boxStrokeStyle;
+ ctx.lineWidth = 1;
+ ctx.strokeRect(x - radius, y - radius, 2 * radius, 2 * radius);
+ ctx.restore();
+ }
+}
+Custom.id = 'derivedBubble';
+Custom.defaults = {
+ // Custom defaults. Bubble defaults are inherited.
+ boxStrokeStyle: 'red'
+};
+// Overrides are only inherited, but not merged if defined
+// Custom.overrides = Chart.overrides.bubble;
+
+// Stores the controller so that the chart initialization routine can look it up
+Chart.register(Custom);
--- /dev/null
+// Add helpers needed in samples here.
+// Usable through `helpers[name]`.
+export {color, getHoverColor} from '../../dist/helpers.esm';
+
--- /dev/null
+import {Scale, LinearScale} from 'chart.js';
+
+export default class Log2Axis extends Scale {
+ constructor(cfg) {
+ super(cfg);
+ this._startValue = undefined;
+ this._valueRange = 0;
+ }
+
+ parse(raw, index) {
+ const value = LinearScale.prototype.parse.apply(this, [raw, index]);
+ return isFinite(value) && value > 0 ? value : null;
+ }
+
+ determineDataLimits() {
+ const {min, max} = this.getMinMax(true);
+ this.min = isFinite(min) ? Math.max(0, min) : null;
+ this.max = isFinite(max) ? Math.max(0, max) : null;
+ }
+
+ buildTicks() {
+ const ticks = [];
+
+ let power = Math.floor(Math.log2(this.min));
+ let maxPower = Math.ceil(Math.log2(this.max));
+ while (power <= maxPower) {
+ ticks.push({value: Math.pow(2, power)});
+ power += 1;
+ }
+
+ this.min = ticks[0].value;
+ this.max = ticks[ticks.length - 1].value;
+ return ticks;
+ }
+
+ /**
+ * @protected
+ */
+ configure() {
+ const start = this.min;
+
+ super.configure();
+
+ this._startValue = Math.log2(start);
+ this._valueRange = Math.log2(this.max) - Math.log2(start);
+ }
+
+ getPixelForValue(value) {
+ if (value === undefined || value === 0) {
+ value = this.min;
+ }
+
+ return this.getPixelForDecimal(value === this.min ? 0
+ : (Math.log2(value) - this._startValue) / this._valueRange);
+ }
+
+ getValueForPixel(pixel) {
+ const decimal = this.getDecimalForPixel(pixel);
+ return Math.pow(2, this._startValue + decimal * this._valueRange);
+ }
+}
+
+Log2Axis.id = 'log2';
+Log2Axis.defaults = {};
+
+// The derived axis is registered like this:
+// Chart.register(Log2Axis);
import {Chart, registerables} from '../../dist/chart.esm';
+import Log2Axis from './log2';
+import './derived-bubble';
+import analyzer from './analyzer';
Chart.register(...registerables);
+Chart.register(Log2Axis);
+Chart.register(analyzer);
+import colorLib from '@kurkle/color';
+import {DateTime} from 'luxon';
+import 'chartjs-adapter-luxon';
import {valueOrDefault} from '../../dist/helpers.esm';
// Adapted from http://indiegamr.com/generate-repeatable-random-numbers-in-js/
return xs.map((x, i) => ({x, y: ys[i]}));
}
+export function bubbles(config) {
+ return this.points(config).map(pt => {
+ pt.r = this.rand(config.rmin, config.rmax);
+ return pt;
+ });
+}
+
export function labels(config) {
var cfg = config || {};
var min = cfg.min || 0;
return COLORS[index % COLORS.length];
}
-export function transparentize(color, opacity) {
+export function transparentize(value, opacity) {
var alpha = opacity === undefined ? 0.5 : 1 - opacity;
- return Color(color).alpha(alpha).rgbString();
+ return colorLib(value).alpha(alpha).rgbString();
}
-export const chartColors = {
+export const CHART_COLORS = {
red: 'rgb(255, 99, 132)',
orange: 'rgb(255, 159, 64)',
yellow: 'rgb(255, 205, 86)',
purple: 'rgb(153, 102, 255)',
grey: 'rgb(201, 203, 207)'
};
+
+const NAMED_COLORS = [
+ CHART_COLORS.red,
+ CHART_COLORS.orange,
+ CHART_COLORS.yellow,
+ CHART_COLORS.green,
+ CHART_COLORS.blue,
+ CHART_COLORS.purple,
+ CHART_COLORS.grey,
+];
+
+export function namedColor(index) {
+ return NAMED_COLORS[index % NAMED_COLORS.length];
+}
+
+export function newDate(days) {
+ return DateTime.now().plus({days}).toJSDate();
+}
+
+export function newDateString(days) {
+ return DateTime.now().plus({days}).toISO();
+}
"integrity": "sha512-mKKUkUbhPpQlCOfIuZkvSEgktjPFIsZKRRbC6KWVEMvlzblj3i3asQv5ODsrwt0N3pHAEvjP8KTQPHkp0+6jOg==",
"dev": true
},
+ "chartjs-adapter-luxon": {
+ "version": "1.0.0-beta.2",
+ "resolved": "https://registry.npmjs.org/chartjs-adapter-luxon/-/chartjs-adapter-luxon-1.0.0-beta.2.tgz",
+ "integrity": "sha512-1DKxf5jMXs5b1n+NPtzkeM7iAWCSCwCOVI6mmh1/U4rTzprxDRyWQcA9SOdScdZQNFHuij/VbmerQpnrKEHUJA==",
+ "dev": true
+ },
"chartjs-adapter-moment": {
"version": "0.1.2",
"resolved": "https://registry.npmjs.org/chartjs-adapter-moment/-/chartjs-adapter-moment-0.1.2.tgz",
"integrity": "sha512-zTU3DaZaF3Rt9rhN3uBMGQD3dD2/vFQqnvZCDv4dl5iOzq2IZQqTxu90r4E5J+nP70J3ilqVCrbho2eWaeW8Ow==",
"dev": true
},
+ "luxon": {
+ "version": "1.26.0",
+ "resolved": "https://registry.npmjs.org/luxon/-/luxon-1.26.0.tgz",
+ "integrity": "sha512-+V5QIQ5f6CDXQpWNICELwjwuHdqeJM1UenlZWx5ujcRMc9venvluCjFb4t5NYLhb6IhkbMVOxzVuOqkgMxee2A==",
+ "dev": true
+ },
"magic-string": {
"version": "0.25.7",
"resolved": "https://registry.npmjs.org/magic-string/-/magic-string-0.25.7.tgz",
"@typescript-eslint/eslint-plugin": "^4.18.0",
"@typescript-eslint/parser": "^4.18.0",
"@vuepress/plugin-google-analytics": "1.8.2",
+ "chartjs-adapter-luxon": "^1.0.0-beta.2",
"chartjs-adapter-moment": "^0.1.2",
"chartjs-test-utils": "^0.2.2",
"concurrently": "^6.0.0",
"karma-rollup-preprocessor": "^7.0.7",
"karma-safari-private-launcher": "^1.0.0",
"karma-spec-reporter": "0.0.32",
+ "luxon": "^1.26.0",
"markdown-it-include": "^2.0.0",
"moment": "^2.29.1",
"pixelmatch": "^5.2.1",