Chartjs - Doughnut chart with multi layer and running value - charts

I have doughnut chart using chartsjs, and also I used multi layer with cutoutPercentage.
The First Layer (Black color) is the Total and the second layer (Red Color) complete is the running value.
type: 'doughnut',
data: {
datasets: [
{
data: Total,
fill: true,
backgroundColor:'rbg(242, 133, 0)',
borderWidth: 3,
weight:1,
},{
data: complete,
fill: true,
backgroundColor:'rgb(255,36,0)',
borderWidth: 3,
weight:1,
}
]
},
options: {
responsive: true,
rotation: 1 * Math.PI,
circumference: 1 * Math.PI,
legend: {
display: false
},
tooltip: {
enabled: false
},
cutoutPercentage: 70,
},
This is what I need,2nd layer is running until reach the total.

In case you need a generic solution, you can use the Plugin Core API and define a beforeInit hook that modifies the chart configuration to fit your needs.
Please take a look at below runnable code and see how it could be done.
new Chart('runningValue', {
type: 'doughnut',
plugins: [{
beforeInit: chart => {
chart.data.datasets = [{
data: [chart.data.total],
backgroundColor: chart.data.totalColor,
borderWidth: 3
},
{
data: [chart.data.complete, chart.data.total - chart.data.complete],
backgroundColor: [chart.data.completeColor, '#fff'],
borderWidth: 3
}
]
}
}],
data: {
total: 50,
complete: 35,
totalColor: 'rbg(242, 133, 0)',
completeColor: 'rgb(255,36,0)'
},
options: {
rotation: -90,
circumference: 180,
plugins: {
legend: {
display: false
},
tooltip: {
enabled: false
}
},
cutout: '70%'
}
});
canvas {
max-height: 100px;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/Chart.js/3.7.1/chart.js"></script>
<canvas id="runningValue"></canvas>

Simply define two values and two background colors on the second dataset as shown in the runnable code below.
const total = 50;
const complete = 35;
new Chart('runningValue', {
type: 'doughnut',
data: {
datasets: [{
data: [total],
backgroundColor: 'rbg(242, 133, 0)',
borderWidth: 3
},
{
data: [complete, total - complete],
backgroundColor: ['rgb(255,36,0)', '#fff'],
borderWidth: 3
}
]
},
options: {
rotation: -90,
circumference: 180,
plugins: {
legend: {
display: false
},
tooltip: {
enabled: false
}
},
cutout: '70%'
}
});
canvas {
max-height: 100px;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/Chart.js/3.7.1/chart.js"></script>
<canvas id="runningValue"></canvas>

Related

In Apache Echarts, can inside piechart labels switch automatically to outside if they overlap?

I have a nested pie chart (two pie chart series, one an outer "doughnut" around the other). The inner pie chart needs to mainly use inner-positioned labels, but sometimes there isn't enough room and they overlap:
How can I get this to not overlap? Is there a way to switch the overlapping labels or those that can't fit inside their slices to be outer-positioned instead? Or some other strategy to make these readable? Using 100% outer positioned labels works, but because of the outer pie chart there isn't much room and it's much harder to read because the outer pie chart also has its own set of outer-positioned labels.
Series def:
seriesOpt = [{
encode: {
value: "value",
itemName: "name"
},
type: "pie",
startAngle: 90,
//minShowLabelAngle: 0.05, // buggy, throws internal javascript error
avoidLabelOverlap: true,
datasetIndex: 0,
name: "inner",
radius: [0, insideRadius??"40%"],
label: {
show: true,
position: "inside"
distanceToLabelLine: 10,
alignTo: "none",
overflow: "truncate",
formatter: '{name|{b}}\n{pct|{d}%}',
rich: {
pct: {
color: '#999'
}
},
labelLine: {
show: false
}
},{
encode: {
value: "value",
itemName: "name"
},
type: "pie",
startAngle: 90,
//minShowLabelAngle: 0.05, // buggy, throws internal javascript error
avoidLabelOverlap: true,
datasetIndex: 1,
name: "outer",
radius: [outsideInnerRadius??"60%",outsideOuterRadius??"75%"],
label: {
show: true,
position: "outside",
distanceToLabelLine: 10,
alignTo: "none",
overflow: "truncate",
formatter: '{name|{b}}\n{pct|{d}%}',
rich: {
pct: {
color: '#999'
}
},
labelLine: {
show: true,
length: 60,
length2: 15
}
}]
You should tweak series-pie.labelLayout.
Here is an example:
const data = [
{
name: 'Foo',
value: 10
},
{
name: 'Bar',
value: 20
},
{
name: 'Baz',
value: 15
},
{
name: 'Qux',
value: 500
}
];
let option = {
series: [
{
type: 'pie',
radius: ['120px', '90px'],
center: ['50%', '50%'],
data,
label: {
position: 'inner'
},
labelLayout: {
moveOverlap: 'shiftY' // <--- HERE
}
},
{
type: 'pie',
radius: '42px',
center: ['50%', '50%'],
data,
label: {
position: 'inner'
},
labelLine: {
showAbove: true
},
// ========== THERE ==========
labelLayout: {
x: 131,
moveOverlap: 'shiftY'
}
// ====================
}
]
};
let myChart = echarts.init(document.getElementById('main'));
myChart.setOption(option);
#main {
width: 300px;
height: 300px;
}
<script src="https://cdn.jsdelivr.net/npm/echarts#5.4.1/dist/echarts.min.js"></script>
<div id="main"></div>

How to create tooltips with intersect = false?

I created a chart with two y-axis and one x-axis and struggle to create tooltips with intersect = false, so it will start the tooltip when hovering over the line and not only the point of the chart
However, the whole settings for the tooltip, described on
https://www.chartjs.org/docs/latest/configuration/tooltip.html
Does not seem to have any effect for me. My code see below
I am using this code inside a NodeRed template node
\<canvas id="myChart" width=912 height =370\>\</canvas\>
\<script\>
var textcolor = getComputedStyle(document.documentElement).getPropertyValue('--nr-dashboard-widgetTextColor');
var gridcolor = '#E6E6E6';
var linecolors = \['#333F50','#B55A11', '#90C050'\]
var backgroundColor = \['#999FA7','#DAAC88', '#C7DFA7'\]
var ctx = document.getElementById('myChart').getContext('2d');
var chart = new Chart(ctx, {
// The type of chart we want to create
type: 'line',
// The data for our dataset
data: {
labels: {{{payload.labels}}},
datasets: [
{
label: 'Folie Länge Ist',
backgroundColor: backgroundColor[0],
borderColor: linecolors[0],
data: {{{payload.eins}}},
yAxisID: 'left-y-axis',
},
{
label: 'Folie Länge Soll',
backgroundColor: backgroundColor[1],
borderColor: linecolors[1],
data: {{{payload.zwei}}},
yAxisID: 'left-y-axis',
},
{
label: 'Aufwickler Durchmesser',
backgroundColor: backgroundColor[2],
borderColor: linecolors[2],
data: {{{payload.drei}}},
yAxisID: 'right-y-axis',
}
]
},
// Configuration options
options: {
animation: false,
legend: {
display: true,
position: "top"
},
elements: {
point: {
pointStyle: 'circle',
radius: 0
},
line: {
tension: 0,
fill: false
}
},
plugins: {
tooltip: {
mode: 'index',
intersect: false
}
},
scales: {
yAxes: [
{
gridLines :{display:false},
id: 'left-y-axis',
type: 'linear',
position: 'left',
ticks: {
fontColor: linecolors[0],
callback: function(value, index, ticks) {
return new Intl.NumberFormat('de-DE').format(value);
}
}
},
{
gridLines :{zeroLineColor:gridcolor,color:gridcolor,lineWidth:1},
id: 'right-y-axis',
type: 'linear',
position: 'right',
ticks: {
fontColor:linecolors[2],
callback: function(value, index, ticks) {
return new Intl.NumberFormat('de-DE').format(value);
}
}
}
],
xAxes: [
{
ticks: {
autoSkip: true,
autoSkipPadding: 10,
maxRotation: 0,
minRotation: 0
}
}
]
}
}
});
\</script\>
Tried setting intersect = false, also enable = false just to test if these settings have an effect

Using ChartJS to create a multiple grouped bar chart - see picture below

I am testing out HighCharts and ChartJS to see which to use. For Highcharts, I was able to find a hack to create a bar chart that had double grouping on the x-axis.
This is what I want to look like:
I am new to both charting JS options and wonder if there is a way to do this in ChartJS.
I have the datasets something like this:
xAxis: {
categories: [{
name: "Total",
categories: ["2004", "2008", "2012"]
}, {
name: "Lower than 2.50",
categories: ["2004", "2008", "2012"]
}]
},
yAxis: {
min: 0,
title: {
text: 'Percent (%)'
}
},
series: [{
name: 'Male',
data: [42.4, 43.0, 43.0, 50.3, 49.4, 48.4]
}, {
name: 'Female',
data: [57.6, 57.0, 57.0, 49.7, 50.6, 51.6]
}]
Essentially I need a nest series on the x-axis and I am open to plugins or code from Github to do this.
You can make use of the Plugin Core API. It offers different hooks that may be used for executing custom code. In below code, I use the afterDraw hook to draw the category labels and the delimiter lines.
new Chart('myChart', {
type: 'bar',
plugins: [{
afterDraw: chart => {
let ctx = chart.chart.ctx;
ctx.save();
let xAxis = chart.scales['x-axis-0'];
let xCenter = (xAxis.left + xAxis.right) / 2;
let yBottom = chart.scales['y-axis-0'].bottom;
ctx.textAlign = 'center';
ctx.font = '12px Arial';
ctx.fillText(chart.data.categories[0], (xAxis.left + xCenter) / 2, yBottom + 40);
ctx.fillText(chart.data.categories[1], (xCenter + xAxis.right) / 2, yBottom + 40);
ctx.strokeStyle = 'lightgray';
[xAxis.left, xCenter, xAxis.right].forEach(x => {
ctx.beginPath();
ctx.moveTo(x, yBottom);
ctx.lineTo(x, yBottom + 40);
ctx.stroke();
});
ctx.restore();
}
}],
data: {
labels: ['2004', '2008', '2012', '2016', '2004', '2008', '2012', '2016'],
categories: ['Total', 'Lower than 2.50'],
datasets: [{
label: 'Male',
data: [42.4, 43.0, 43.0, 50.3, 49.4, 48.4, 51.2, 51.8],
backgroundColor: 'rgba(124, 181, 236, 0.9)',
borderColor: 'rgb(124, 181, 236)',
borderWidth: 1
},
{
label: 'Female',
data: [57.6, 57.0, 57.0, 49.7, 50.6, 51.6, 53.7, 54.6],
backgroundColor: 'rgba(67, 67, 72, 0.9)',
borderColor: 'rgb(67, 67, 72)',
borderWidth: 1
}
]
},
options: {
legend: {
position: 'bottom',
labels: {
padding: 30,
usePointStyle: true
}
},
scales: {
yAxes: [{
ticks: {
min: 0,
max: 80,
stepSize: 20
},
scaleLabel: {
display: true,
labelString: 'Percent (%)'
}
}],
xAxes: [{
gridLines: {
drawOnChartArea: false
}
}]
}
}
});
canvas {
max-width: 400px;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/Chart.js/2.9.4/Chart.min.js"></script>
<canvas id="myChart" height="200"></canvas>
You have to define a second x-axis and play around with the many ticks and gridLines options.
Please take a look at below runnable code and see how it could be done. This is obviously only a draft and needs to optimized and made more generic.
new Chart(document.getElementById('myChart'), {
type: 'bar',
data: {
labels: ['2004', '2008', '2012', '2004', '2008', '2012'],
datasets: [{
label: 'Male',
data: [42.4, 43.0, 43.0, 50.3, 49.4, 48.4],
backgroundColor: 'rgba(124, 181, 236, 0.9)',
borderColor: 'rgb(124, 181, 236)',
borderWidth: 1
},
{
label: 'Female',
data: [57.6, 57.0, 57.0, 49.7, 50.6, 51.6],
backgroundColor: 'rgba(67, 67, 72, 0.9)',
borderColor: 'rgb(67, 67, 72)',
borderWidth: 1
}
]
},
options: {
legend: {
position: 'bottom',
labels: {
usePointStyle: true
}
},
scales: {
yAxes: [{
ticks: {
min: 0,
max: 80,
stepSize: 20
},
scaleLabel: {
display: true,
labelString: 'Percent (%)'
}
}],
xAxes: [{
gridLines: {
drawOnChartArea: false
}
},
{
offset: true,
ticks: {
autoSkip: false,
maxRotation: 0,
padding: -15,
callback: (v, i) => {
if (i == 1) {
return 'Total';
} else if (i == 4) {
return 'Lower than 2.50';
} else {
return '';
}
}
},
gridLines: {
drawOnChartArea: false,
offsetGridLines: true,
tickMarkLength: 20,
color: ['white', 'white', 'white', 'lightgray', 'white', 'white', 'lightgray']
}
}
]
}
}
});
canvas {
max-width: 400px;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/Chart.js/2.9.4/Chart.min.js"></script>
<canvas id="myChart" height="200"></canvas>

Chart.js specific label next to point

I'm trying to get chartjs to show a specific label next to each point, for example in this script it should display "TRALALA" in the label as well as mouse hover, but instead it shows the coordinates.
How to have the specific label instead ?
https://jsfiddle.net/z0eLygwx/
thanks
var valuedata = [{
x: 3,
y: 5
}];
var valuelabel = ['TRALALA'];
var chartData = {
labels: valuelabel,
datasets: [{
label: 'Distance',
borderColor: '#2196f3', // Add custom color border
backgroundColor: '#2196f3', // Add custom color background (Points and Fill)
data: valuedata,
pointRadius: 10,
pointHoverRadius: 12
}]
};
var myBarChart = new Chart(document.getElementById("myChart1"), {
type: 'scatter',
data: {
labels: valuelabel,
datasets: [{
label: 'Distance',
borderColor: '#2196f3', // Add custom color border
backgroundColor: '#2196f3', // Add custom color background (Points and Fill)
data: valuedata,
pointRadius: 10,
pointHoverRadius: 12
}]
},
options: {
legend: {
display: true
},
title: {
display: true,
text: 'Distance of JDPT kanji compared to the equivalent JLPT level'
},
scales: {
yAxes: [{
type: 'logarithmic',
display: true,
scaleLabel: {
display: true,
labelString: 'Count',
fontSize: 16
}
}],
xAxes: [{
type: 'linear',
position: 'bottom',
display: true,
scaleLabel: {
display: true,
labelString: 'Distance',
fontSize: 16
},
gridLines: {
display: true
}
}]
},
plugins: {
datalabels: {
color: '#d6621e',
align: 'right',
offset: 16,
font: {
weight: 'bold'
}
}
}
}
});
myBarChart.update();
Ok I got it with
formatter: function(value, context) {
context.chart.data.labels[context.dataIndex];
}
For example
var myBarChart = new Chart(document.getElementById("bar-chart"), {
type: 'line',
data: {
labels: ['a', 'b'],
datasets: [{
data: [10, 20]
}]
},
options: {
plugins: {
datalabels: {
formatter: function(value, context) {
return context.chart.data.labels[context.dataIndex];
}
}
}
}
});

Chart.js ignore options

I'm trying to create a line chart with chart.js but when I try to style my chart.
Everything from options is ignored.
Here is my code:
<canvas id="myChart" width="400" height="400"></canvas>
<script type="text/javascript" src="https://cdnjs.cloudflare.com/ajax/libs/Chart.js/2.8.0/Chart.min.js"></script>
<script>
var ctx = document.getElementById('myChart').getContext('2d');
let ChartOptions = {
responsive: true,
layout: { padding: { top: 12, left: 12, bottom: 12 } },
title: {
display: true,
text: 'Chart.js Line Chart - Cubic interpolation mode'
},
scales: {
xAxes: [{ gridLines: { color: '#22364e', borderDash: [9, 7] } }],
yAxes: [{ gridLines: { display: false } }]
},
plugins: { datalabels: { display: false } },
legend: { display: false },
elements: {
point: { radius: 5 },
line: { tension: 0.4, fill: false },
},
//tooltips: {},
hover: { mode: 'nearest', animationDuration: 400 },
};
var myChart = new Chart(ctx, {
type: 'line',
data: {
labels: ["Fri", "Sun", "Wed", "Thu", "Fri"],
datasets: [
{
fill: false,
borderColor: '#6ebffe',
pointBackgroundColor: '#6ebffe',
pointBorderColor: '#8cff00',
data: [320, 325, 300, 350, 340],
}
],
options: ChartOptions
}
});
</script>
I tried to copy the code from https://www.chartjs.org/samples/latest/charts/line/interpolation-modes.html but it's the same. I can't add options to my chart.
Even the title is not showing. This is not a cache problem because I run it with chrome devtools open and tried with a different browser.
the options are in the wrong place,
they should be placed after the data object
data: {
},
options: ChartOptions
you had them as part of the data object...
data: {
options: ChartOptions
},
see following working snippet...
<canvas id="myChart" width="400" height="400"></canvas>
<script type="text/javascript" src="https://cdnjs.cloudflare.com/ajax/libs/Chart.js/2.8.0/Chart.min.js"></script>
<script>
var ctx = document.getElementById('myChart').getContext('2d');
let ChartOptions = {
responsive: true,
layout: { padding: { top: 12, left: 12, bottom: 12 } },
title: {
display: true,
text: 'Chart.js Line Chart - Cubic interpolation mode'
},
scales: {
xAxes: [{ gridLines: { color: '#22364e', borderDash: [9, 7] } }],
yAxes: [{ gridLines: { display: false } }]
},
plugins: { datalabels: { display: false } },
legend: { display: false },
elements: {
point: { radius: 5 },
line: { tension: 0.4, fill: false },
},
//tooltips: {},
hover: { mode: 'nearest', animationDuration: 400 },
};
var myChart = new Chart(ctx, {
type: 'line',
data: {
labels: ["Fri", "Sun", "Wed", "Thu", "Fri"],
datasets: [
{
fill: false,
borderColor: '#6ebffe',
pointBackgroundColor: '#6ebffe',
pointBorderColor: '#8cff00',
data: [320, 325, 300, 350, 340],
}
]
},
options: ChartOptions
});
</script>