Multiple Range Highlighting of Background in Chart.js - javascript

From this question I'm looking to turn into a multiple range highlight
But there 1 annoying bug I didn't succeed to solve
background is superposing, if you uncheck a dataset on the top, background alpha change
Here my work so far: https://jsfiddle.net/742zut83/588/
Why the custom draw function executed for each dataset? Once highlights done originalLineDraw is returned
draw : function() {
var chart = this.chart;
// Get the object that determines the region to highlight.
var yHighlightRanges = chart.config.data.yHighlightRanges;
let ctx = chart.chart.ctx;
yHighlightRanges.forEach(function(Range) {
var yRangeBegin = Range.begin;
var yRangeEnd = Range.end;
var xaxis = chart.scales['x-axis-0'];
var yaxis = chart.scales['y-axis-0'];
var yRangeBeginPixel = yaxis.getPixelForValue(yRangeBegin);
var yRangeEndPixel = yaxis.getPixelForValue(yRangeEnd);
ctx.save();
// The fill style of the rectangle we are about to fill.
ctx.fillStyle = Range.rgb;
// Fill the rectangle that represents the highlight region. The parameters are the closest-to-starting-point pixel's x-coordinate,
// the closest-to-starting-point pixel's y-coordinate, the width of the rectangle in pixels, and the height of the rectangle in pixels, respectively.
ctx.fillRect(xaxis.left, Math.min(yRangeBeginPixel, yRangeEndPixel), xaxis.right - xaxis.left, Math.max(yRangeBeginPixel, yRangeEndPixel) - Math.min(yRangeBeginPixel, yRangeEndPixel));
ctx.restore();
});
// Apply the original draw function for the line chart.
originalLineDraw.apply(this, arguments);
}
var ctx = document.getElementById("myChart");
// The original draw function for the line chart. This will be applied after we have drawn our highlight range (as a rectangle behind the line chart).
var originalLineDraw = Chart.controllers.line.prototype.draw;
// Extend the line chart, in order to override the draw function.
Chart.helpers.extend(Chart.controllers.line.prototype, {
draw : function() {
var chart = this.chart;
// Get the object that determines the region to highlight.
var yHighlightRanges = chart.config.data.yHighlightRanges;
let ctx = chart.chart.ctx;
yHighlightRanges.forEach(function(Range) {
var yRangeBegin = Range.begin;
var yRangeEnd = Range.end;
var xaxis = chart.scales['x-axis-0'];
var yaxis = chart.scales['y-axis-0'];
var yRangeBeginPixel = yaxis.getPixelForValue(yRangeBegin);
var yRangeEndPixel = yaxis.getPixelForValue(yRangeEnd);
ctx.save();
// The fill style of the rectangle we are about to fill.
ctx.fillStyle = Range.rgb;
// Fill the rectangle that represents the highlight region. The parameters are the closest-to-starting-point pixel's x-coordinate,
// the closest-to-starting-point pixel's y-coordinate, the width of the rectangle in pixels, and the height of the rectangle in pixels, respectively.
ctx.fillRect(xaxis.left, Math.min(yRangeBeginPixel, yRangeEndPixel), xaxis.right - xaxis.left, Math.max(yRangeBeginPixel, yRangeEndPixel) - Math.min(yRangeBeginPixel, yRangeEndPixel));
ctx.restore();
});
// Apply the original draw function for the line chart.
originalLineDraw.apply(this, arguments);
}
});
var myChart = new Chart(ctx, {
type: 'line',
data: {
labels: ["Red", "Blue", "Yellow", "Green", "Purple", "Orange"],
datasets: [
{
label: 'Season 1',
data: [12, 17, 3, 5, 9, 3],
fill: false,
borderColor: 'rgba(0, 200, 0, 1)'
},
{
label: 'Season 2',
data: [5, 14, 3, 15, 9, 13],
fill: false,
borderColor: 'rgba(200, 0, 0, 1)'
}
],
// This, if it exists at all, defines the highlight region.
yHighlightRanges : [
{
begin: 0,
end: 6,
rgb: 'rgba(100, 100, 100, 0.2)'
},
{
begin: 6,
end: 12,
rgb: 'rgba(200, 100, 200, 0.2)'
},
{
begin: 12,
end: 18,
rgb: 'rgba(0, 100, 200, 0.2)'
}
]
},
options: {
scales: {
yAxes: [{
ticks: {
beginAtZero:true
}
}]
}
}
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/Chart.js/2.7.2/Chart.min.js"></script>
<canvas id="myChart" width="400" height="400"></canvas>

Why not using simply the annotation plugin?
Here is your example with annotation plugin, using Box annotations:
var ctx = document.getElementById("myChart");
var myChart = new Chart(ctx, {
type: 'line',
data: {
labels: ["Red", "Blue", "Yellow", "Green", "Purple", "Orange"],
datasets: [
{
label: 'Season 1',
data: [12, 17, 3, 5, 9, 3],
fill: false,
borderColor: 'rgba(0, 200, 0, 1)'
},
{
label: 'Season 2',
data: [5, 14, 3, 15, 9, 13],
fill: false,
borderColor: 'rgba(200, 0, 0, 1)'
}
]
},
options: {
scales: {
yAxes: [{
id: 'y-axis-1',
ticks: {
beginAtZero:true
}
}]
},
annotation: {
drawTime: "afterDraw",
annotations: [{
id: 'box1',
type: 'box',
yScaleID: 'y-axis-1',
yMin: 0,
yMax: 6,
backgroundColor: 'rgba(100, 100, 100, 0.2)',
borderColor: 'rgba(100, 100, 100, 0.2)',
},{
id: 'box2',
type: 'box',
yScaleID: 'y-axis-1',
yMin: 6,
yMax: 12,
backgroundColor: 'rgba(200, 100, 200, 0.2)',
borderColor: 'rgba(200, 100, 200, 0.2)',
},{
id: 'box3',
type: 'box',
yScaleID: 'y-axis-1',
yMin: 12,
yMax: 18,
backgroundColor: 'rgba(0, 100, 200, 0.2)',
borderColor: 'rgba(0, 100, 200, 0.2)',
}]
}
}
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/Chart.js/2.7.2/Chart.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/chartjs-plugin-annotation/0.5.7/chartjs-plugin-annotation.min.js"></script>
<canvas id="myChart" width="400" height="400"></canvas>
And this is your fiddle updated: https://jsfiddle.net/beaver71/50L21shp/

Related

Hover text of canvas in other div

I want to put text beside the canvas doughnut. This text is based on the hover information of each slide, but instead of appear on the top pf the image i want it to be next to it. (2 images as example)
https://jsfiddle.net/jak2e4zr/
HTML
<canvas id="myChart" ></canvas>
<script src="https://code.jquery.com/jquery-3.5.1.min.js"></script>
<script src="https://cdn.jsdelivr.net/npm/chart.js"></script>
JS
var ctx = document.getElementById("myChart");
var data = {
labels: ['Residential', 'Non-Residential', 'Utility'],
datasets: [
{
data: [19, 26, 55],
weight: 2,
spacing : 5,
borderWidth : 0,
backgroundColor: [
"#FF6384",
"#36A2EB",
"#FFCE56"
],
hoverBackgroundColor: [
"#FF6384",
"#36A2EB",
"#FFCE56"
]
}]
};
var myDoughnutChart = new Chart(ctx, {
type: 'doughnut',
data: data,
options: {
circumference: 180,
rotation: -180,
plugins: {
legend: {
display: false
},
tooltip: {
backgroundColor: 'rgba(0, 0, 0, 0)',
borderColor: 'rgba(0, 0, 0, 0)',
displayColors: false,
titleAlign: 'center',
xAling: 'center'
}
},
hoverOffset: 15,
}
}); `
Image 1
Image 2
THANKS
The chart.js tooltip object accepts an additional property called position which, well, affects the position of the tooltip. By default it only accepts two strings for setting the mode being either "average" or "nearest". Luckily you're able to define your own mode by extending the Chart.Tooltip.positioners object.
As you want your tooltip to be somewhere in the middle, we can make something like this:
Chart.Tooltip.positioners.middle = function(elements, eventPosition) {
const chart = this._chart;
return {
x: chart.chartArea.width/2,
y: chart.chartArea.height/2
};
}
...so simply querying the chart's current dimensions and take the half of it. This mode can then be used by it's name "middle".
Here's a complete example:
var ctx = document.getElementById("myChart");
Chart.Tooltip.positioners.middle = function(elements, eventPosition) {
const chart = this._chart;
return {
x: chart.chartArea.width / 2,
y: chart.chartArea.height / 2
};
}
var data = {
labels: ['Residential', 'Non-Residential', 'Utility'],
datasets: [{
data: [19, 26, 55],
weight: 2,
spacing: 5,
borderWidth: 0,
backgroundColor: [
"#FF6384",
"#36A2EB",
"#FFCE56"
],
hoverBackgroundColor: [
"#FF6384",
"#36A2EB",
"#FFCE56"
]
}]
};
var myDoughnutChart = new Chart(ctx, {
type: 'doughnut',
data: data,
options: {
responsive: false,
circumference: 180,
rotation: -180,
plugins: {
legend: {
display: false
},
tooltip: {
position: 'middle',
backgroundColor: '#ff0000',
titleColor: '#000000',
displayColors: false,
titleAlign: 'center',
xAlign: 'left'
}
},
hoverOffset: 15,
}
});
<script src="https://code.jquery.com/jquery-3.5.1.min.js"></script>
<script src="https://cdn.jsdelivr.net/npm/chart.js"></script>
<canvas id="myChart"></canvas>

How to show values on top of bars in a PDF using chart.js and chartjs-node-canvas?

I need to show the values on the top of bars using chartjs-node-canvas to create a PDF in Node
I have been able to recreate what I am looking in HTML but the plugin has the limitation of not accepting the "animation" property, for this reason I am looking to know if there is another way to do it in Node without the need for another external plugin. This is my current code
var ctx = document.getElementById("myChart");
var chart = new Chart(ctx, {
type: "bar",
data: {
labels: ["a", "b", "c", "d", "e", "f"],
datasets: [
{
type: "bar",
backgroundColor: "blue",
borderColor: "blue",
borderWidth: 1,
label: "promedio",
order: 1,
data: [60, 49, 72, 90, 100, 60]
},
{
type: "bar",
backgroundColor: "orange",
borderColor: "orange",
borderWidth: 1,
label: "promedio",
order: 1,
data: [40, 5, 20, 30, 10, 6]
},
{
type: "line",
label: "casos",
data: [25, 13, 30, 35, 25, 40],
lineTension: 0,
backgroundColor: "red",
borderColor: "red",
order: 0,
fill: false
}
]
},
options: {
scales: {
yAxes: [{
ticks: {
beginAtZero: true
}
}]
},
animation: {
duration: 1,
onComplete: function () {
var chartInstance = this.chart,
ctx = chartInstance.ctx;
ctx.font = Chart.helpers.fontString(16, 20, Chart.defaults.global.defaultFontFamily);
ctx.textAlign = 'center';
ctx.textBaseline = 'bottom';
this.data.datasets.forEach(function (dataset, i) {
var meta = chartInstance.controller.getDatasetMeta(i);
meta.data.forEach(function (bar, index) {
var data = dataset.data[index];
ctx.fillText(data, bar._model.x, bar._model.y - 2);
});
});
}
},
legend: {
display: false
}
}
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/Chart.js/2.9.3/Chart.min.js"></script>
<body>
<canvas id="myChart" width="400" height="200"></canvas>
</body>
Short answer is no, you either have to implement your own external inline plugin or use the datalabels plugin (https://chartjs-plugin-datalabels.netlify.app/samples/charts/bar.html) since there is no build in way to achieve this

How to apply to different bground color for each area in Chart.js

In react-chartjs-2
In Line chart every grid should have different background colors.
Is this achievable with this library?
This is how LineChart should looks:
This is my Code/configuration:
const options = {
responsive: true,
scales: {
y: {
grid: {
backgroundColor: [
'rgba(36, 206, 0, 0.8)',
'rgba(255, 255, 0, .8)',
'rgba(255, 162, 0, 0.8)',
'rgba(36, 206, 0, 0.8)',
],
},
};
Thanks for reading.
You can use an inline plugin to achieve it:
var GradientBgPlugin = {
beforeDraw: function(chart, args, options) {
const ctx = chart.ctx;
const canvas = chart.canvas;
const chartArea = chart.chartArea;
// Chart background
var gradientBack = canvas.getContext("2d").createLinearGradient(0, 250, 0, 0);
gradientBack.addColorStop(0, "rgba(213,235,248,1)");
gradientBack.addColorStop(0.16, "rgba(213,235,248,1)");
gradientBack.addColorStop(0.17, "rgba(226,245,234,1)");
gradientBack.addColorStop(0.25, "rgba(226,245,234,1)");
gradientBack.addColorStop(0.26, "rgba(252,244,219,1)");
gradientBack.addColorStop(0.5, "rgba(252,244,219,1)");
gradientBack.addColorStop(0.51, "rgba(251,221,221,1)");
gradientBack.addColorStop(1, "rgba(251,221,221,1)");
ctx.fillStyle = gradientBack;
ctx.fillRect(chartArea.left, chartArea.bottom,
chartArea.right - chartArea.left, chartArea.top - chartArea.bottom);
}
};
Than just include it in your Chart options:
plugins: [GradientBgPlugin]
The result should be similar to this JSFiddle.
EDIT
For Reach Charts JS 2, you need small changes in setup. You define plugin this way:
const plugins = [{
beforeDraw: function(chart) {
const ctx = chart.ctx;
const canvas = chart.canvas;
const chartArea = chart.chartArea;
// Chart background
var gradientBack = canvas.getContext("2d").createLinearGradient(0, 250, 0, 0);
gradientBack.addColorStop(0, "rgba(213,235,248,1)");
gradientBack.addColorStop(0.16, "rgba(213,235,248,1)");
gradientBack.addColorStop(0.17, "rgba(226,245,234,1)");
gradientBack.addColorStop(0.25, "rgba(226,245,234,1)");
gradientBack.addColorStop(0.26, "rgba(252,244,219,1)");
gradientBack.addColorStop(0.5, "rgba(252,244,219,1)");
gradientBack.addColorStop(0.51, "rgba(251,221,221,1)");
gradientBack.addColorStop(1, "rgba(251,221,221,1)");
ctx.fillStyle = gradientBack;
ctx.fillRect(chartArea.left, chartArea.bottom,
chartArea.right - chartArea.left, chartArea.top - chartArea.bottom);
}
}];
Than you plug it this way:
<Line data={data} plugins={plugins} />
You can see it working fine on CodeSandbox here.
You can write a custom inline plugin, that draws the colors on the chart Area. In the options section you can put an object with all the sections you want, from where to where and which color they need to be
Example:
var options = {
type: 'line',
data: {
labels: ["Red", "Blue", "Yellow", "Green", "Purple", "Orange"],
datasets: [{
label: '# of Votes',
data: [100, 19, 3, 5, 2, 3],
borderWidth: 1
},
{
label: '# of Points',
data: [7, 11, 5, 8, 3, 7],
borderWidth: 1
}
]
},
options: {
plugins: {
backgrounds: {
hbars: [{
from: 28,
to: 100,
color: "rgb(195, 230, 195)"
},
{
from: 20,
to: 28,
color: "rgb(230, 220, 195)"
},
{
from: 0,
to: 20,
color: "rgb(230, 195, 195)"
}
]
}
}
},
plugins: [{
id: 'backgrounds',
beforeDraw: (chart, args, options) => {
const {
ctx,
chartArea,
scales: {
y
}
} = chart;
options.hbars.forEach((hBar) => {
ctx.save();
ctx.fillStyle = hBar.color;
ctx.fillRect(chartArea.left, y.getPixelForValue(hBar.from), chartArea.right - chartArea.left, y.getPixelForValue(hBar.to) - y.getPixelForValue(hBar.from));
ctx.restore();
})
}
}]
}
var ctx = document.getElementById('chartJSContainer').getContext('2d');
new Chart(ctx, options);
<body>
<canvas id="chartJSContainer" width="600" height="400"></canvas>
<script src="https://cdnjs.cloudflare.com/ajax/libs/Chart.js/3.2.0/chart.js"></script>
</body>
Detailed explanation can be found here: https://medium.com/#omi10859/alternative-background-lines-in-chartjs-a626ce4d3bcb
We can use annotaion plugin with chartjs to create custom elements.
we can use annotation plugin to do this
import annotationPlugin from "chartjs-plugin-annotation";
import {Chart} from 'chart.js';
Chart.register(annotationPlugin);
this code will add a box to our chart
{
type: 'box', #type of draw
drawTime: 'beforeDraw', #this will decide background or foreground
yMin: 5, #value min on y axis
yMax: 10, #value max on y axis
borderColor: 'rgb(242, 244, 248, 0.9)', #border color of the box
borderWidth: 1, #boarder width for box
backgroundColor: '#F2F4F8', #colour of the box
}
# add option while rendering
const options = {
plugins: {annotation: {annotations: background_annotation}
}
this code render this

Chartjs Line Color Between Two Points

Is there any way to set line color of specific sections in between two points in chart.js?
I would like to color the section 00-07 gray, 07-15 red, and 15-23 blue.
Here is what I am passing as the data attribute in the options object to initialize the chart:
var chartData = {
labels: [/* a single dimensional array of strings */],
datasets: [
{
label: '',
data: [/* a single dimensional array of totals */],
fill: false,
backgroundColor: '#e7eaeb',
borderColor: red
}
]
};
I think this is where I need to add the graph section points and colors, but I do not know how.
HI Michael Hurley I think you should use:
interpolation:
https://www.chartjs.org/docs/latest/samples/line/interpolation.html
or
Multi-axis: https://www.chartjs.org/docs/latest/samples/line/multi-axis.html
My idea is we have 3 datasets with multi-color,
End of dataset1 is first of dataset2.
Here my Example:
window.chartColors = { red: 'rgb(255, 99, 132)', orange: 'rgb(255, 159, 64)', yellow: 'rgb(255, 205, 86)', green: 'rgb(75, 192, 192)', blue: 'rgb(54, 162, 235)', purple: 'rgb(153, 102, 255)', grey: 'rgb(201, 203, 207)' };
var randomScalingFactor = function() {
return Math.round(Math.random() * 100);
};
var config = {
type: 'line',
data: {
labels: ['0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '10', '11', '12'],
datasets: [{
label: 'Cubic interpolation (monotone)',
data: [0, 20, 20, 60, 60, NaN, NaN, NaN, NaN, NaN, NaN, NaN, NaN],
borderColor: window.chartColors.red,
backgroundColor: 'rgba(0, 0, 0, 0)',
fill: false,
cubicInterpolationMode: 'monotone'
}, {
label: 'Cubic interpolation (default)',
data: [NaN, NaN, NaN, NaN, 60, 120, 140, 180, 120, NaN, NaN, NaN, NaN],
borderColor: window.chartColors.blue,
backgroundColor: 'rgba(0, 0, 0, 0)',
fill: false,
}, {
label: 'Linear interpolation',
data: [NaN, NaN, NaN, NaN, NaN, NaN, NaN, NaN, 120, 125, 105, 110, 170],
borderColor: window.chartColors.green,
backgroundColor: 'rgba(0, 0, 0, 0)',
fill: false,
lineTension: 0
}]
},
options: {
responsive: true,
title: {
display: true,
text: 'Chart.js Line Chart - Cubic interpolation mode'
},
tooltips: {
mode: 'index'
},
scales: {
xAxes: [{
display: true,
scaleLabel: {
display: true
}
}],
yAxes: [{
display: true,
scaleLabel: {
display: true,
labelString: 'Value'
},
ticks: {
suggestedMin: -10,
suggestedMax: 200,
}
}]
}
}
};
var ctx = document.getElementById('canvas').getContext('2d');
window.myLine = new Chart(ctx, config);
canvas {
-moz-user-select: none;
-webkit-user-select: none;
-ms-user-select: none;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/Chart.js/2.7.2/Chart.bundle.js"></script>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div style="width:75%;">
<canvas id="canvas"></canvas>
</div>
Latest versions of ChartJS allow you to customize line segments individually, which can be used to change the color and also the style (dashed etc) of a specific segment.
const config = {
type: 'line',
data: {
labels: Utils.months({count: 7}),
datasets: [{
label: 'My First Dataset',
data: [65, 59, NaN, 48, 56, 57, 40],
borderColor: 'rgb(75, 192, 192)',
segment: {
borderColor: ctx => skipped(ctx, 'rgb(0,0,0,0.2)') || down(ctx, 'rgb(192,75,75)'),
borderDash: ctx => skipped(ctx, [6, 6]),
}
}]
},
options: genericOptions
};
See https://www.chartjs.org/docs/master/samples/line/segments.html for more info.
The Plugin Core API offers a range of hooks that may be used for performing custom code. You can use the afterLayout hook to create a linear gradient through CanvasRenderingContext2D.createLinearGradient().
In the following example, the linear gradient is created from the colors defined in data.dataset.colors.
new Chart('myChart', {
type: 'line',
plugins: [{
afterLayout: chart => {
var ctx = chart.chart.ctx;
var xAxis = chart.scales['x-axis-0'];
var gradientStroke = ctx.createLinearGradient(xAxis.left, 0, xAxis.right, 0);
var dataset = chart.data.datasets[0];
dataset.colors.forEach((c, i) => {
var stop = 1 / (dataset.colors.length - 1) * i;
gradientStroke.addColorStop(stop, dataset.colors[i]);
});
dataset.backgroundColor = gradientStroke;
dataset.borderColor = gradientStroke;
dataset.pointBorderColor = gradientStroke;
dataset.pointBackgroundColor = gradientStroke;
dataset.pointHoverBorderColor = gradientStroke;
dataset.pointHoverBackgroundColor = gradientStroke;
}
}],
data: {
labels: [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20],
datasets: [{
label: 'My Dataset',
data: [101, 122, 103, 115, 95, 94, 100, 108, 112, 115, 119, 120, 109, 108, 105, 116, 117, 108, 109, 114],
fill: false,
colors: ['gray', 'gray', 'gray', 'gray','gray', 'gray', 'red', 'red', 'red', 'red', 'red', 'red', 'red', 'blue', 'blue', 'blue', 'blue', 'blue', 'blue', 'blue']
}]
},
options: {
scales: {
yAxes: [{
ticks: {
min: 0
}
}]
}
}
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/Chart.js/2.9.3/Chart.bundle.min.js"></script>
<canvas id="myChart" height="70"></canvas>
In V3 you can make use of the segment option in the dataset to style specific line parts:
new Chart('myChart', {
type: 'line',
data: {
labels: [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20],
datasets: [{
label: 'My Dataset',
data: [101, 122, 103, 115, 95, 94, 100, 108, 112, 115, 119, 120, 109, 108, 105, 116, 117, 108, 109, 114],
segment: {
borderColor: (ctx) => {
const xVal = ctx.p1.parsed.x;
if (xVal <= 7) {
return 'gray';
} else if (xVal <= 15) {
return 'red'
} else {
return 'blue'
}
},
},
}]
},
options: {}
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/Chart.js/3.7.1/chart.js"></script>
<canvas id="myChart" height="70"></canvas>
I've been wanting to let everyone know a way for react chart.
import React from "react";
import { LineController } from 'chart.js';
import Chart from 'chart.js/auto';
class MultiLineController extends LineController {
draw() {
const ctx = this.chart.ctx;
const meta = this.getMeta();
const points = meta.data || [];
const colors = this.getDataset().colors || [];
const area = this.chart.chartArea;
colors.forEach((color, idx) => {
meta.dataset.options.borderColor = color;
meta.dataset.draw(ctx, area, idx, 2);
});
meta.dataset.draw(ctx, area, colors.length, points.length - colors.length);
}
}
MultiLineController.id = "multicolorLine";
MultiLineController.defaults = LineController.defaults;
Chart.register(MultiLineController);
export default function App() {
React.useEffect(() => {
const ctx = document.getElementById("line-chart").getContext("2d");
window.lineChart = new Chart(ctx, {
type: 'multicolorLine',
data: {
labels: ["January", "February", "March", "April", "May", "June", "July"],
datasets: [{
label: "My First dataset",
borderColor: 'rgb(255, 99, 132)',
data: [0, 10, 5, 2, 20, 30, 45],
colors: ['red', 'green', 'blue', 'yellow']
}]
},
options: {}
});
return () => window.lineChart.destroy();
}, []);
return (
<div style={{width: '100%', height: 300}}>
<canvas id="line-chart" />
</div>
);
}
Here is screenshot of this chart.
React Chart Component implemented by chart.js

Chart JS — Conditional horizontal row background colours

I'm a bit stuck on adding conditional background colours to a row in ChartJS, based on numbers on the vertical axis.
Eg.
If the vertical axis is between 0 - 6, background colour for those rows is green.
If the vertical axis is between 6 - 12 background colour for those rows is grey
If the vertical axis is > 12 background colour for those rows is red
Has anyone done something like this before?
I've attached a picture that roughly describes the functionality.
Cheers!
There is no option to do this with chartjs. However you can write your own plugin and draw the background by yourself in the beforeDraw hook for example.
var chart = new Chart(ctx, {
plugins: [{
beforeDraw: function(chart) {
//..
}
}]
});
You can get all the information to calculate the height of an y-axis-segment from the chart parameter.
I've included a snippet below how this could be implemented. Note however that this is more a proof of concept than a proper implementation:
var canvas = document.getElementById('myChart');
window.chartColors = {
red: 'rgb(255, 99, 132)',
orange: 'rgb(255, 159, 64)',
yellow: 'rgb(255, 205, 86)',
green: 'rgb(51, 204, 51)',
blue: 'rgb(54, 162, 235)',
purple: 'rgb(153, 102, 255)',
grey: 'rgb(201, 203, 207)'
};
var myLineChart = new Chart(canvas,
{
type: 'line',
data: {
labels: ['1', '2', '3', '4', '5'],
datasets: [
{
label: '# of Votes',
fill: false,
backgroundColor: window.chartColors.blue,
borderColor: window.chartColors.blue,
data: [2, 5, 12.5, 9, 6.3]
}
]
},
options: {
responsive: true,
title: {
display: true,
text: 'Conditional Background'
},
backgroundRules: [{
backgroundColor: window.chartColors.green,
yAxisSegement: 6
}, {
backgroundColor: window.chartColors.grey,
yAxisSegement: 12
}, {
backgroundColor: window.chartColors.red,
yAxisSegement: Infinity
}],
scales: {
yAxes: [{
ticks: {
beginAtZero: true,
stepSize: 1
}
}]
}
},
plugins: [{
beforeDraw: function (chart) {
var ctx = chart.chart.ctx;
var ruleIndex = 0;
var rules = chart.chart.options.backgroundRules;
var yaxis = chart.chart.scales["y-axis-0"];
var xaxis = chart.chart.scales["x-axis-0"];
var partPercentage = 1 / (yaxis.ticksAsNumbers.length - 1);
for (var i = yaxis.ticksAsNumbers.length - 1; i > 0; i--) {
if (yaxis.ticksAsNumbers[i] < rules[ruleIndex].yAxisSegement) {
ctx.fillStyle = rules[ruleIndex].backgroundColor;
ctx.fillRect(xaxis.left, yaxis.top + ((i - 1) * (yaxis.height * partPercentage)), xaxis.width, yaxis.height * partPercentage);
} else {
ruleIndex++;
i++;
}
}
}
}]
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/Chart.js/2.7.1/Chart.min.js"></script>
<canvas id="myChart" width="400" height="250"></canvas>
Shiffty's answer is right on point, however it only works if the background values are present on the yAxis, which is not always the case... depends on what fits. A more generic solution is to calculate the actual values:
var canvas = document.getElementById('myChart');
window.chartColors = {
red: 'rgb(255, 99, 132)',
orange: 'rgb(255, 159, 64)',
yellow: 'rgb(255, 205, 86)',
green: 'rgb(51, 204, 51)',
blue: 'rgb(54, 162, 235)',
purple: 'rgb(153, 102, 255)',
grey: 'rgb(201, 203, 207)'
};
var myLineChart = new Chart(canvas,
{
type: 'line',
data: {
labels: ['1', '2', '3', '4', '5'],
datasets: [
{
label: '# of Votes',
fill: false,
backgroundColor: window.chartColors.blue,
borderColor: window.chartColors.blue,
data: [2, 5, 12.5, 9, 6.3]
}
]
},
options: {
responsive: true,
title: {
display: true,
text: 'Conditional Background'
},
backgroundRules: [{
backgroundColor: window.chartColors.green,
yAxisSegement: 6
}, {
backgroundColor: window.chartColors.grey,
yAxisSegement: 12
}, {
backgroundColor: window.chartColors.red,
yAxisSegement: 999999
}],
scales: {
yAxes: [{
ticks: {
beginAtZero: true,
stepSize: 1
}
}]
}
},
plugins: [{
beforeDraw: function (chart) {
var rules = chart.chart.options.backgroundRules;
var ctx = chart.chart.ctx;
var yAxis = chart.chart.scales["y-axis-0"];
var xaxis = chart.chart.scales["x-axis-0"];
for (var i = 0; i < rules.length; ++i) {
var yAxisSegement = (rules[i].yAxisSegement > yAxis.ticksAsNumbers[0] ? yAxis.ticksAsNumbers[0] : rules[i].yAxisSegement);
var yAxisPosStart = yAxis.height - ((yAxisSegement * yAxis.height) / yAxis.ticksAsNumbers[0]) + chart.chart.controller.chartArea.top;
var yAxisPosEnd = (i === 0 ? yAxis.height : yAxis.height - ((rules[i - 1].yAxisSegement * yAxis.height) / yAxis.ticksAsNumbers[0]));
ctx.fillStyle = rules[i].backgroundColor;
ctx.fillRect(xaxis.left, yAxisPosStart, xaxis.width, yAxisPosEnd - yAxisPosStart + chart.chart.controller.chartArea.top);
}
}
}]
});

Categories

Resources