Doughnutchart add a simple '%' to the hover tooltip [duplicate] - reactjs

I am trying to add percentage to pie chart in ChartJS 3.2.1
All the answers and code I have found from extensive searching reference ChartJS version 1 or 2.
Including This question and This question and this question which all fail or do not actually change any tooltip display.
There is numerous reference to https://cdn.jsdelivr.net/npm/chartjs-plugin-datalabels#0.7.0 but this doesn't work on ChartJS v3; I have installed the ChartJS Datalabels for Version 3 from here:
https://github.com/chartjs/chartjs-plugin-datalabels/releases/tag/v2.0.0
but using This answer still does not work.
I can not see on the ChartJS Datalabels Plugin documentation how to implement what I'm looking for.
I am looking for the percentage for each piece of the pie to be shown on the tooltip hover OR on the pie piece itself, but not on the label/legend.
I can't see anything on the ChartJS Tooltip documentation about how to actually edit the textual content of the tooltip.
So, my code:
JS:
var dnct1 = document.getElementById('DoeNut1');
var myChart1 = new Chart(dnct1, {
type: 'doughnut',
data: {
labels: ["Scotland and Northern Ireland","North East England","North West","Midlands","East Anglia","South England"],
datasets: [{
label: ["Scotland and Northern Ireland","North East England","North West","Midlands","East Anglia","South England"],
data: ["510","887","720","837","993","774","977"],
borderWidth: 0,
hoverOffset: 5,
backgroundColor: ['#F3AC16','#9F9F9F','#FF3355', '#55EE22','#354D73','#553FCF'],
cutout: 0
}]
},
options: {
tooltips: {
enabled: true,
},
layout: {
padding: {
bottom: 25
}
},
plugins: {
/** Imported from a question linked above.
Apparently Works for ChartJS V2 **/
datalabels: {
formatter: (value, dnct1) => {
let sum = 0;
let dataArr = dnct1.chart.data.datasets[0].data;
dataArr.map(data => {
sum += data;
});
let percentage = (value*100 / sum).toFixed(2)+'%';
return percentage;
},
color: '#ff3'
}
}
}
});
HTML:
<div class='chartBox'>
<h2>Title</h2>
<canvas id='DoeNut1'></canvas>
</div>
The above no browser console errors are returned and all charts display correctly but the tooltips don't show any percentages. I can't see what's wrong.

If you are using ChartJS v3 then I got it to work without any additional plugins. I overrode the tooltip at the dataset level.
datasets: [{
label: 'Industries',
data: [1, 5, 10, 14, 15],
tooltip: {
callbacks: {
label: function(context) {
let label = context.label;
let value = context.formattedValue;
if (!label)
label = 'Unknown'
let sum = 0;
let dataArr = context.chart.data.datasets[0].data;
dataArr.map(data => {
sum += Number(data);
});
let percentage = (value * 100 / sum).toFixed(2) + '%';
return label + ": " + percentage;
}
}
}
}]

To use the datalabels plugin you will need to register it also please read the migration guide (https://www.chartjs.org/docs/master/getting-started/v3-migration.html) first because you are using v2 syntax for your tooltip for example which wont work.
To get the percentage in the tooltip you can use any of the callbacks (https://www.chartjs.org/docs/master/configuration/tooltip.html#tooltip-callbacks) see example below for datalabels and the footer callback to display the percentages:
var dnct1 = document.getElementById('DoeNut1');
var myChart1 = new Chart(dnct1, {
type: 'doughnut',
data: {
labels: ["Scotland and Northern Ireland", "North East England", "North West England", "North Wales and West Midlands", "East Midlands and East Anglia", "South Wales and South West England", "South East England"],
datasets: [{
label: ["Scotland and Northern Ireland", "North East England", "North West England", "North Wales and West Midlands", "East Midlands and East Anglia", "South Wales and South West England", "South East England"],
data: ["510", "887", "720", "837", "993", "774", "977"],
borderWidth: 0,
hoverOffset: 5,
backgroundColor: ['#F3AC16', '#9F9F9F', '#FF3355', '#55EE22', '#354D73', '#666633', '#553FCF'],
cutout: 0
}]
},
options: {
layout: {
padding: {
bottom: 25
}
},
plugins: {
tooltip: {
enabled: true,
callbacks: {
footer: (ttItem) => {
let sum = 0;
let dataArr = ttItem[0].dataset.data;
dataArr.map(data => {
sum += Number(data);
});
let percentage = (ttItem[0].parsed * 100 / sum).toFixed(2) + '%';
return `Percentage of data: ${percentage}`;
}
}
},
/** Imported from a question linked above.
Apparently Works for ChartJS V2 **/
datalabels: {
formatter: (value, dnct1) => {
let sum = 0;
let dataArr = dnct1.chart.data.datasets[0].data;
dataArr.map(data => {
sum += Number(data);
});
let percentage = (value * 100 / sum).toFixed(2) + '%';
return percentage;
},
color: '#ff3',
}
}
},
plugins: [ChartDataLabels]
});
<body>
<canvas id="DoeNut1" width="600" height="400"></canvas>
<script src="https://cdnjs.cloudflare.com/ajax/libs/Chart.js/3.4.0/chart.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/chartjs-plugin-datalabels/2.0.0-rc.1/chartjs-plugin-datalabels.js" ></script>
</body>

Related

How can I generate a custom legend in chart.js in React [duplicate]

I need the value of chart show after name of data for example ([colour of data] Car 50, [colour of data] Motorcycle 200). I've tried change the value of legend title but it doesn't work at all
Here is it my code:
var ctx = document.getElementById('top-five').getContext('2d');
var myChartpie = new Chart(ctx, {
type: 'pie',
data: {
labels: {!! $top->pluck('name') !!},
datasets: [{
label: 'Statistics',
data: {!! $top->pluck('m_count') !!},
backgroundColor: {!! $top->pluck('colour') !!},
borderColor: {!! $top->pluck('colour') !!},
}]
},
options: {
plugins: {
legend: {
display: true,
title: {
text: function(context) {//I've tried to override this but doesn't work
var value = context.dataset.data[context.dataIndex];
var label = context.label[context.dataIndex];
return label + ' ' + value;
},
}
},
},
responsive: true,
}
});
You can use a custom generateLabels function for this:
var options = {
type: 'doughnut',
data: {
labels: ["Red", "Blue", "Yellow", "Green", "Purple", "Orange"],
datasets: [{
label: '# of Votes',
data: [12, 19, 3, 5, 2, 3],
backgroundColor: ["Red", "Blue", "Yellow", "Green", "Purple", "Orange"],
}]
},
options: {
plugins: {
legend: {
labels: {
generateLabels: (chart) => {
const datasets = chart.data.datasets;
return datasets[0].data.map((data, i) => ({
text: `${chart.data.labels[i]} ${data}`,
fillStyle: datasets[0].backgroundColor[i],
index: i
}))
}
}
}
}
}
}
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.5.1/chart.js"></script>
</body>
The below is a direct over ride of the default label generation found in the controller here. I have made one change on the text property within the generateLabels function in order to append the data value. It preserves the data toggling and strikethrough styling when a label is toggled.
plugins: {
legend: {
labels: {
generateLabels(chart) {
const data = chart.data;
if (data.labels.length && data.datasets.length) {
const {labels: {pointStyle}} = chart.legend.options;
return data.labels.map((label, i) => {
const meta = chart.getDatasetMeta(0);
const style = meta.controller.getStyle(i);
return {
text: `${label}: ${data['datasets'][0].data[i]}`,
fillStyle: style.backgroundColor,
strokeStyle: style.borderColor,
lineWidth: style.borderWidth,
pointStyle: pointStyle,
hidden: !chart.getDataVisibility(i),
// Extra data used for toggling the correct item
index: i
};
});
}
return [];
}
},
onClick(e, legendItem, legend) {
legend.chart.toggleDataVisibility(legendItem.index);
legend.chart.update();
}
}
//...
}
[1]: https://github.com/chartjs/Chart.js/blob/master/docs/samples/legend/html.md
You can also use the base implementation to reduce the amount of copied code. Note that some chart types (like donut) already overrides the default label generation.
plugins: {
legend: {
labels: {
generateLabels: function (chart) {
return Chart.defaults.plugins.legend.labels.generateLabels(chart).map(function (label) {
var dataset = chart.data.datasets[label.datasetIndex];
var total = 0;
for (var j = 0; j < dataset.data.length; j++)
total += dataset.data[j].y;
label.text = dataset.label + ': ' + total;
return label;
});
}
}
}
}

How Can I display tooltip on legend of chartjs [duplicate]

I'm trying to find the way how to show tooltip when user hovers the legend in Chart.js library. I have found several issues but none of them was solved.
https://github.com/chartjs/Chart.js/issues/4023
Chart.js - show tooltip when hovering on legend
Does anybody have any idea how to manage that? Thank you
This is quite straightforward using the onHover callback.
Below is a snippet with a crude implementation but it is illustrative of the technique required.
let hovering = false,
tooltip = document.getElementById("tooltip"),
tooltips = ["such tooltip", "blah blah"],
mychart = new Chart(document.getElementById("chart"), {
type: "bar",
data: {
labels: ['a', 'b', 'c'],
datasets: [{
label: "series 1",
data: [1, 2, 3]
}, {
label: "series 2",
data: [1, 2, 3]
}]
},
options: {
legend: {
onHover: function(event, legendItem) {
if (hovering) {
return;
}
hovering = true;
tooltip.innerHTML = tooltips[legendItem.datasetIndex];
tooltip.style.left = event.x + "px";
tooltip.style.top = event.y + "px";
},
onLeave: function() {
hovering = false;
tooltip.innerHTML = "";
}
}
}
});
#tooltip {
background-color: #000;
color: #fff;
position: absolute;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/Chart.js/2.8.0/Chart.min.js"></script>
<canvas id="chart"></canvas>
<div id="tooltip"></div>

ECharts: Force XAxis Labels to show all the values for type=time without any duplicate values

I am facing some issues with Echarts-Line Charts while trying to render the label data on the X-Axis.
Scenario 1 – Plotting XAxis Labels when only single quarter information is available
Expected Output: Only a single label should appear on XAxis.
Expected Output
Actual Output [Echarts] – Duplicate xAxis labels
Echart Output
I want to have one to one mapping between data and xAxis label.
Scenario 2 – Plotting XAxis labels when there is a huge dataset
Expected Output :- The labels on xAxis has all the quarter information.
Expected Output when dataset is large
Actual Output [Echarts]- Some XAxis labels are skipped automatically by Echarts library, I have tried rotation but it still skips the datapoints.
Actual: xAxis Labels got skipped
I want to force Echart to show all the labels irrespective of the overlapping of values.
Sample Code:
import React from 'react';
import ReactEcharts from 'echarts-for-react';
const LineChart : React.FC = (props) => {
var option2={
title: {
text: ''
},
tooltip: {
trigger: 'item'
},
legend: {
x: 'left',
padding: [0, 0, 0, 40],
data: ['Plot this']
},
// Impacts the grid lines, LRBT are kind of a padding which moves the chart
grid: {
show: true,
left: '3%',
containLabel: true,
borderColor: 'white'
},
xAxis: {
name: "Category",
nameLocation: "middle",
nameTextStyle: {
padding: [10, 0, 0, 0]
},
type: 'time',
boundaryGap: false,
splitNumber: 0,
axisLabel: {
interval:0,
showMinLabel: true,
showMaxLabel:true,
formatter: (function (value:any, index:any) {
const date = new Date(value * 1);
const month = (date.getMonth() + 1);
// to ignore duplicate values
if (!([1,4,7,10].includes(month))){
return null;
}
const quarter = `Q${Math.ceil(month / 3)}`
const year = date.getFullYear()
const xAxisData = `${quarter}-${year}`
return xAxisData
})
// formatter:'Q{Q}-{yyyy}'
}
},
yAxis: {
name: "",
nameLocation: "middle",
nameTextStyle: {
padding: [0, 0, 30, 0]
},
splitArea:{
show:true,
areaStyle:{
color:["white", "#FAFBFC"]
}
},
type: 'value'
},
series: [
{
name: 'Plot This',
type: 'line',
symbol: 'emptyCircle',
color: '#00A3E0',
symbolSize: 10,
lineStyle: {
type: 'solid'
},
emphasis: {
focus: 'series',
blurScope: 'coordinateSystem'
},
data: [
[1506816000000, 509680038.04382974],
[1514764800000, 791155276.2344121],
[1522540800000, 799123227.7082155],
[1530403200000, 802979755.202323],
[1538352000000, 808190497.8038454],
[1546300800000, 948760339.9516863],
[1554076800000, 1042540676.5278728],
[1561939200000, 875160118.2571102],
[1569888000000, 712878628.868768],
[1577836800000, 735685154.726105],
[1585699200000, 820177866.0564957],
[1593561600000, 818982140.8503832],
[1601510400000, 815904376.9750341],
[1609459200000, 836625579.7082175],
[1617235200000, 832549982.9206431],
[1625097600000, 828002503.802811],
[1633046400000, 821488484.2030047],
[1640995200000, 823540791.742887],
[1648771200000, 818621496.9663928],
[1656633600000, 813346336.6927732],
[1664582400000, 808353924.8521348],
[1672531200000, 804944324.4562442],
[1680307200000, 799921655.5844442]
]
},
]
}
return (
<div>
<p> </p>
<ReactEcharts
option = {option2}
/>
</div>
);
}
export default LineChart;
Output of the above code:
XAxis with Missing Quarters
Replace the data of the series with below to get the Scenario 1:
data: [
[1506816000000, 509680038.04382974],
]
Output:
Duplicate Quarters
Thanks in advance.

Chart.js how to highlight a part of a label

i am trying to highlight part of a label from the axis labels based on what the user has searched for.
However the label is being rendered as text so the html tags are shown like plain text. any ideas on how to achieve this?
You can use the Plugin Core API. It offers different hooks that may be used for executing custom code. In below code snippet, I use the afterDraw hook to draw text of different styles underneath each bar.
When drawing your own tick labels, probably want to define the text rotation. Further you need to instruct Chart.js not to display the default labels. This can be done through the following definition inside the chart options.
scales: {
xAxes: [{
ticks: {
display: false,
rotation: 40
}
}],
You also need to define some padding for the bottom of the chart, otherwise you won't see your custom tick labels.
layout: {
padding: {
bottom: 60
}
},
Please take a look at below code sample and see how it works. Tick labels that need to be drawn with two different styles are separated with a semicolon inside data.labels.
new Chart(document.getElementById('myChart'), {
type: 'bar',
plugins: [{
afterDraw: chart => {
let ctx = chart.chart.ctx;
let xAxis = chart.scales['x-axis-0'];
let yAxis = chart.scales['y-axis-0'];
chart.data.labels.forEach((l, i) => {
let labelTokens = l.split(';');
let rotation = xAxis.options.ticks.rotation * -Math.PI / 180;
let x = xAxis.getPixelForValue(l);
if (labelTokens.length == 2) {
ctx.save();
let width = ctx.measureText(labelTokens.join(' ')).width;
ctx.translate(x, yAxis.bottom + 10);
ctx.rotate(rotation);
ctx.font = 'italic 12px Arial';
ctx.fillStyle = 'blue';
ctx.fillText(labelTokens[0], -width, 0);
ctx.restore();
}
ctx.save();
let labelEnd = labelTokens[labelTokens.length - 1];
let width = ctx.measureText(labelEnd).width;
ctx.translate(x, yAxis.bottom + 10);
ctx.rotate(rotation);
ctx.font = '12px Arial';
ctx.fillText(labelEnd, -width, 0);
ctx.restore();
});
}
}],
data: {
labels: ['NASTY!!;Errors', 'Warnings'],
datasets: [{
label: 'Result',
data: [30, 59],
fill: false,
backgroundColor: ['rgba(255, 99, 132, 0.2)', 'rgba(255, 159, 64, 0.2)'],
borderColor: ['rgb(255, 99, 132)', 'rgb(255, 159, 64)'],
borderWidth: 1
}]
},
options: {
layout: {
padding: {
bottom: 60
}
},
legend: {
display: false
},
tooltips: {
callbacks: {
title: tooltipItem => tooltipItem[0].xLabel.split(';').join(' ')
}
},
scales: {
xAxes: [{
ticks: {
display: false,
rotation: 40
}
}],
yAxes: [{
ticks: {
beginAtZero: true
}
}]
}
}
});
canvas {
max-width: 250px;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/Chart.js/2.9.4/Chart.min.js"></script>
<canvas id="myChart" width="10" height="8"></canvas>

Get generated bar colour dynamically

Is there any way to generate bar colours dynamically in ZingChart?
in screen-shot there is two colours generated in bar chart, i want to get list of colors used in bar chart.
html file
<zingchart id="timesheet-bar-chart" zc-values="barValues" zc- json="myObj"></zingchart>
controller
$scope.myObj = {
"type": "bar",
"plot":{
"stacked":true,
"stack-type":"normal" /* Optional specification */
},
"scale-x":{
"transform":{
"type":"date",
"all":"%d %M",
"item": {
"visible":false
}
},
"values":$scope.bar_x_axis,
},
};
and barValues is a list of integer values.
Since your question is asking how to get the bar colors, not set the bar colors. I thought my answer would be appropriate as well.
You can use the API to getobjectinfo from the chart.
demo here
$scope.myRender = {
events : {
complete : function(p) {
var info1 = zingchart.exec(p.id, 'getobjectinfo', {
object : 'plot',
plotindex: 0
});
var info2 = zingchart.exec(p.id, 'getobjectinfo', {
object : 'plot',
plotindex: 1
});
console.log(info1, info2);
}
}
}
If youre confused on the $scope.myRender variable you can read up more on the angular directive here.
You can set the colors like this,
$scope.myJson = {
'plot': {
'styles': ['#yellow', 'red', 'blue']
},
'scale-x': {
'values': ['white', 'red', 'pink']
},
'type': 'bar',
'series': [{
'text': 'Product History Color',
'values': [2, 6, 8]
}]
}
DEMO
You can specify the colors, fonts etc by yourself.
e.g.
scaleX: {
labels: ['Facebook','Apple', 'Microsoft', 'Intel','Google', 'Amazon'],
item: {
fontFamily: "Roboto",
fontSize: 14
},
lineColor: "#DDD",
tick:{
visible: false
}
},

Resources