I want to add a background color or a cirle with color inside doghnut chart using chartjs.
I have already added text in the center of doghnut chart.
However I am not able to add the background colour.
I also want to remove padding and margin chart.js inserts in the chart
I want a chart like this
I am able to acheive following using below code
This my code to render chart
data = {
labels: [
'performance'
],
datasets: [{
label: 'performance;,
data: [90, 10],
backgroundColor: [
'#27AE60',
'#3333331A'
]
}]
};
config = {
type: 'doughnut',
data,
options: {
cutout: 200,
legend: {
display: false,
},
plugins: {
legend: {
display: false
}
},
responsive: true,
rotation: 210, // start angle in degrees
circumference: 300,
radius: "50%"
},
plugins: [{
id: 'text',
beforeDraw: function (chart, a, b) {
let width = chart.width,
height = chart.height,
ctx = chart.ctx;
ctx.restore();
let fontSize = (height / 200).toFixed(2);
ctx.font = fontSize + "em sans-serif";
ctx.textBaseline = "middle";
let text = '90%',
textX = Math.round((width - ctx.measureText(text).width) / 2),
textY = height / 2;
ctx.fillText(text, textX, textY);
ctx.save();
}
}],
centerText: {
display: true,
text: "280"
}
};
new Chart('performance', config);
You can mimic this design by using a pie chart with specific configuration options.
Here is a working example, including the posted plugin code for drawing text in the middle (note that the plugin is changed from beforeDraw to afterDraw to keep the text above the fill segment):
const data = {
datasets: [{
label: 'outer',
data: [1, 2],
backgroundColor: [
'#27AE60',
'#3333331A'
],
rotation: 210,
circumference: 300,
cutout: '50%',
borderWidth: 0
}, {
// dummy dataset to fill middle.
label: 'inner',
data: [1],
backgroundColor: '#27AE60',
weight: 3,
borderWidth: 0
}]
};
new Chart('chart', {
type: 'pie',
data: data,
options: {
borderAlign: 'inner'
},
plugins: [{
id: 'text',
afterDraw: function(chart, a, b) {
let width = chart.width,
height = chart.height,
ctx = chart.ctx;
ctx.restore();
let fontSize = (height / 200).toFixed(2);
ctx.font = fontSize + "em sans-serif";
ctx.textBaseline = "middle";
let text = '90%',
textX = Math.round((width - ctx.measureText(text).width) / 2),
textY = height / 2;
ctx.fillText(text, textX, textY);
ctx.save();
}
}],
});
<div style="width:200px;height:200px"><canvas id="chart"></canvas></div>
<script src="https://cdn.jsdelivr.net/npm/chart.js#4.2.1"></script>
I'm using react-chartjs-2 as the chart library for my data visualization.
I need to show one vertical line on a distribution graph. Example:
I have tried to implement as below. I have tried to draw the vertical line by a small math calculation.
Can anyone suggest a better solution than to draw a vertical line on selected X value on the graph?
line_chart_1 = {
datasets: [
{
label: 'My First dataset',
backgroundColor: '#99000022',
borderColor: '#990000',
pointHoverBackgroundColor: '#fff',
borderWidth: 2,
data: data_array,
}
]
}
line_chart_1_opt = {
tooltips: {
enabled: false
},
maintainAspectRatio: false,
legend: {
display: false,
},
scales: {
xAxes: [
{
gridLines: {
drawOnChartArea: false,
},
type: 'linear'
}],
yAxes: [
{
ticks: {
beginAtZero: true,
maxTicksLimit: 5,
stepSize: Math.ceil(250 / 5)
},
}],
},
elements: {
point: {
radius: 0,
hitRadius: 10,
hoverRadius: 4,
hoverBorderWidth: 3,
},
},
title: {
text: 'chart_one'
},
options: {
plugins: {
labels: false
}
}
};
Chart.pluginService.register({
afterDraw: function (chart, easing) {
var margin = 46;
var margin_end = 5;
if (chart.config.options.title.text == 'chart_one') {
var diff = chart.scales['x-axis-0'].end - chart.scales['x-axis-0'].start;
var val = b_amount - chart.scales['x-axis-0'].start;
const ctx = chart.ctx;
const x = (val / diff) * (chart.width - (margin + margin_end)) + margin;
const topY = chart.scales['y-axis-0'].top;
const bottomY = chart.scales['y-axis-0'].bottom;
ctx.save();
ctx.beginPath();
ctx.moveTo(x, topY);
ctx.lineTo(x, bottomY);
ctx.lineWidth = 2;
ctx.strokeStyle = '#ff0000';
ctx.stroke();
}
<Line data={line_chart_1} options={line_chart_1_opt} height={200} />
I'm using ChartJS V2 to create a chart. Chartjs V2 supports the fill color feature. But I would like to fill overlap area with different color.
Please see screenshot below. I have two line. A represents overlap area for two lines.
I would like to fill with 3 different color for 2 lines.
When the Line1 and Line2 overlaps, fill color should be A
If Line1 does not overlap Line2, fill color should be B
If Line2 does not overlap Line1, fill color should be C
I added a fiddle for this.
See Fiddle http://jsfiddle.net/qcs1t9ag/
Thanks!
var lineChartData = {
labels: ["January", "February", "March", "April", "May", "June", "July"],
datasets: [{
label: "My First dataset",
data: [50, 85, 56, 50, 60, 70, 80],
yAxisID: "y-axis-1",
borderColor: "#0ad4e6"
}, {
label: "My Second dataset",
data: [35, 45, 75, 40, 55, 50, 62],
yAxisID: "y-axis-2",
borderColor: "#f6c63e"
}]
};
var ctx = document.getElementById("canvas").getContext("2d");
window.myLine = Chart.Line(ctx, {
data: lineChartData,
options: {
responsive: true,
hoverMode: 'label',
stacked: false,
title: {
display: false,
text: 'Chart.js Line Chart - Multi Axis'
},
animation: {
duration: 0
},
legend: {
display: false,
position: 'top',
},
scales: {
xAxes: [{
display: true,
gridLines: {
offsetGridLines: false
}
}],
yAxes: [{
type: "linear", // only linear but allow scale type registration. This allows extensions to exist solely for log scale for instance
display: true,
position: "left",
id: "y-axis-1",
scaleLabel: {
display: true,
labelString: "Cost"
}
}, {
type: "linear", // only linear but allow scale type registration. This allows extensions to exist solely for log scale for instance
display: true,
position: "right",
id: "y-axis-2",
scaleLabel: {
display: true,
labelString: "Students",
},
// grid line settings
gridLines: {
drawOnChartArea: false, // only want the grid lines for one axis to show up
},
}],
}
}
});
JueDoe, Here's an example below of how you could do this.
Fiddle: Charts intersection example
var ORDER_STATS = {
"2016": [10, 181, 194, -56, 130, 181, 179, 189, 30, 60, 193, 154],
"2015": [124, -50, 152, 187, 10, 164, 129, -16, 115, 119, 129, 171],
"2014": [-90, 80, 30, 59, 100, -30, 60, 116, 191, 181, -60, 106]
};
var colors = ['206,191,26', '119,206,26', '26,200,206', '236,124,98', '206,26,140', '26,77,206'];
// Definning X
var ordersChartData = {
labels: ["Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"],
datasets: []
}
Object.keys(ORDER_STATS).forEach(function(key) {
color = colors.shift();
ordersChartData.datasets.push({
label: key,
lineTension: 0,
type: 'line',
backgroundColor: "rgba(" + color + ",0.1)",
borderColor: "rgba(" + color + ",1)",
borderWidth: 2,
pointBackgroundColor: "rgba(" + color + ",1)",
pointBorderColor: "#fff",
pointBorderWidth: 1,
pointRadius: 4,
pointHoverBackgroundColor: "#fff",
pointHoverBorderColor: "rgba(" + color + ",1)",
pointHoverBorderWidth: 1,
data: ORDER_STATS[key]
});
});
var ctx = document.getElementById("myChart").getContext("2d");
Chart.defaults.global.defaultFontColor = 'grey';
Chart.defaults.global.defaultFontFamily = "Tahoma";
Chart.defaults.global.defaultFontSize = 11;
Chart.defaults.global.defaultFontStyle = 'normal';
var myChart = new Chart(ctx, {
type: 'line',
data: ordersChartData,
defaultFontSize: 11,
options: {
responsive: true,
title: {
display: true,
text: 'Intersection realization',
fontColor: "#444",
fontFamily: 'Tahoma',
padding: 0
},
legend: {
display: true,
labels: {
fontColor: 'grey',
usePointStyle: true
}
},
tooltips: {
mode: "index",
intersect: true,
position: 'nearest',
bodySpacing: 4
}
}
});
Chart.plugins.register({
afterDatasetsDraw: function(chartInstance, easing) {
var intersects = findIntersects(ORDER_STATS['2015'], ORDER_STATS['2014']);
var context = chartInstance.chart.ctx;
var Y = chartInstance.scales['y-axis-0'];
var X = chartInstance.scales['x-axis-0'];
zeroPointY = Y.top + ((Y.bottom - Y.top) / (Y.ticks.length - 1) * Y.zeroLineIndex);
zeroPointX = Y.right;
yScale = (Y.bottom - Y.top) / (Y.end - Y.start);
xScale = (X.right - X.left) / (X.ticks.length - 1);
intersects.forEach(function(result, idx) {
context.fillStyle = 'red';
context.beginPath();
context.arc((result.x * xScale) + zeroPointX, (Y.end - Y.start) - (result.y * yScale) - ((Y.end - Y.start) - zeroPointY), 3, 0, 2 * Math.PI, true);
context.fill();
});
}
});
function findIntersects(line1, line2) {
var intersects = [];
line1.forEach(function(val, idx) {
var line1StartX = idx;
var line1StartY = line1[idx];
var line1EndX = idx + 1;
var line1EndY = line1[idx + 1];
var line2StartX = idx;
var line2StartY = line2[idx];
var line2EndX = idx + 1;
var line2EndY = line2[idx + 1];
result = checkLineIntersection(line1StartX, line1StartY, line1EndX, line1EndY, line2StartX, line2StartY, line2EndX, line2EndY);
if (result.onLine1 && result.onLine2) {
intersects.push(result);
}
});
return intersects;
}
function checkLineIntersection(line1StartX, line1StartY, line1EndX, line1EndY, line2StartX, line2StartY, line2EndX, line2EndY) {
// if the lines intersect, the result contains the x and y of the intersection (treating the lines as infinite) and booleans for whether line segment 1 or line segment 2 contain the point
var denominator, a, b, numerator1, numerator2, result = {
x: null,
y: null,
onLine1: false,
onLine2: false
};
denominator = ((line2EndY - line2StartY) * (line1EndX - line1StartX)) - ((line2EndX - line2StartX) * (line1EndY - line1StartY));
if (denominator == 0) {
return result;
}
a = line1StartY - line2StartY;
b = line1StartX - line2StartX;
numerator1 = ((line2EndX - line2StartX) * a) - ((line2EndY - line2StartY) * b);
numerator2 = ((line1EndX - line1StartX) * a) - ((line1EndY - line1StartY) * b);
a = numerator1 / denominator;
b = numerator2 / denominator;
// if we cast these lines infinitely in both directions, they intersect here:
result.x = line1StartX + (a * (line1EndX - line1StartX));
result.y = line1StartY + (a * (line1EndY - line1StartY));
/*
// it is worth noting that this should be the same as:
x = line2StartX + (b * (line2EndX - line2StartX));
y = line2StartX + (b * (line2EndY - line2StartY));
*/
// if line1 is a segment and line2 is infinite, they intersect if:
if (a > 0 && a < 1) {
result.onLine1 = true;
}
// if line2 is a segment and line1 is infinite, they intersect if:
if (b > 0 && b < 1) {
result.onLine2 = true;
}
// if line1 and line2 are segments, they intersect if both of the above are true
return result;
};
If it is not what you want, I recommend you draw the third line with the difference between the first and second line... or draw another graph with only the third line (calculate the difference between line A and line B).
Fiddle: Third Line
Official documentation.
Here (official) you have several graph examples.
Fiddle :https://jsfiddle.net/jfft219g/
You can see here I have 3 datasets i.e Hospital, Referral, Total. I am displaying the the dataindexes on top of each bar.
But now when I disable one dataset the dataIndexes are still there for the disabled dataset. How to manage this. Please check the fiddle for the running codes.
Any help will be appreciated.
<div id="patientsBarGraphDiv" style="border: 1px solid black">
<canvas id="patientsBarGraph"></canvas>
</div>
var paitentData = {
labels: ["Today", "Week", "Month", "Year"],
datasets: [{
label: "Hospital Patients",
fillColor: "#79D1CF",
strokeColor: "#79D1CF",
data:[ 24, 20, 30, 40] // adding data for the hospital section
}, {
label: "Referral Patients",
fillColor: "#79D1CF",
strokeColor: "#79D1CF",
data:[ 14, 24, 34, 44] // adding data for referral section
},
{
label: "Total Patients",
fillColor: "#79D1CF",
strokeColor: "#79D1CF",
data:[ 22, 32, 43, 52] // adding data for Total section
} ]
};
var opt = {
responsive: true,
legend: {
position: 'top',
},
title: {
display: true,
text: 'Patients Graph'
},
hover: {
animationDuration: 1
},
animation: {
duration: 1,
onComplete: function () {
var chartInstance = this.chart,
ctx = chartInstance.ctx;
ctx.textAlign = 'center';
ctx.fillStyle = "rgba(0, 0, 0, 1)";
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 - 5);
});
});
}
}
};
var ctx = document.getElementById("patientsBarGraph").getContext("2d");// getting the id of canvas
var MyNewChart = new Chart(ctx,{
type: 'bar',
data: paitentData,
options:opt
});
Add the following lines of code inside your forEach loop, that will take care of the dataIndex updating issue :
var isDatasetVisible = chartInstance.controller.isDatasetVisible(i);
if (!isDatasetVisible) return;
Here is the working example on JSFiddle
Problem
There are very small numbers that appear atop a bar chart in Flot that I think are being drawn using canvas. As a result, I'm having difficulty trying to change it to match the styles of the labels on my x and y-axis.
scripts.js
<script type="text/JavaScript">
var d1 = [
[2013, {{ school.apr_2013 }}],
[2014, {{ school.apr_2014 }}],
[2015, {{ school.apr_2015 }}],
[2016, {{ school.apr_2016 }}]
];
$(document).ready(function() {
aprPlot = $.plot($("#apr-chart"), [d1], {
series: {
bars: {
show: true,
fill: true,
// Determines the color of the bar in the chart
fillColor: '#c62828',
barWidth: 0.5,
align: "center"
},
valueLabels: { show: true },
color: "#c62828"
},
xaxis: {
min: 2012.5,
max: 2016.5,
ticks:
[[2013, '2013'],
[2014, '2014'],
[2015, '2015'],
[2016, '2016']]},
yaxis: {
min: 0,
max: 105,
tickSize: 10
},
grid: {
borderWidth: 0.5,
borderColor: 'AAA',
color: '#AAA',
labelMargin: 10
}
});
// Add data value labels at top of bar
var ctx = aprPlot.getCanvas().getContext("2d");
var data = aprPlot.getData()[0].data;
var xaxis = aprPlot.getXAxes()[0];
var yaxis = aprPlot.getYAxes()[0];
var offset = aprPlot.getPlotOffset();
for (var i = 0; i < data.length; i++){
var text = data[i][1] + '';
var metrics = ctx.measureText(text);
var xPos = (xaxis.p2c(data[i][0])+offset.left) - metrics.width/2;
var yPos = yaxis.p2c(data[i][1]) + offset.top - 5;
ctx.fillText(text, xPos, yPos);
}
});
</script>
style.scss
.flot-text {
font-family: "Lato", sans-serif;
color: $color-black !important;
font-size: 12px !important;
}
You can set the font style for the canvas before you draw the text:
ctx.font = '12px Lato';
ctx.fillText(text, xPos, yPos);