getElementsAtEventForMode() of chartJS 3.0 - chart.js

I'm trying to get elements on click event.
Both line and bar data can be null.
My question is getElementsAtEventForMode() is not working as expected When line data is null.
// Same result.
const elements = myChart.getElementsAtEventForMode(e, 'index', { intersect: false }, false);
const element1 = myChart.getElementsAtEventForMode(e, 'nearest', { intersect: false, axis: 'x' }, false);
Please check attached image for detail (where I clicked on chart area).
Can I get some help for this issue?
https://codepen.io/wsjraphael/pen/VwyOXdL

Related

Chart.JS 2 automatic horizontal scroll upon changes on xAxis range not working anymore on Chart.JS 3?

I previously had a scatter graph in Chart.js 2 with the zoom plugin, in which I just had to add data and change the xAxis ticks' min/max to see a nice animated horizontal scroll from my old xAxis range to my new xAxis range.
For some reason I now use Chart.js 3.24 and the zoom plugin 1.1.1. Now the same graph with nearly the same options became quite ugly when animated:
newly added points e.g. at position (X,Y) have an animation going from (X,0) to (X,Y), instead of appearing directly at (X,Y).
when a point from a dataset is at the same position than a line from another dataset, they move at a different speed.
if many points and line are added, sometimes the lines are only shown after the "scrolling animation" ended.
sometimes a point appear at its correct final position before the "scrolling animation" even started.
The only solution I found was to disable animation when updating my graph, then use window.requestAnimationFrame to manually pan the graph myself with the zoom plugin.
Are you aware of a better/simpler recommended way to achieve this ?
Thanks in advance,
My old Chart.js options:
let zoom_options = {
pan: {
enabled: true,
mode: 'x',
rangeMin: { x: 0, y: null},
rangeMax: { x: null, y: null}
},
zoom: {
enabled: true,
drag: false,
mode: 'x',
rangeMin: { x: 0, y: null },
rangeMax: { x: null, y: null },
speed: 0.1
}
};
var ctx = graph.getContext('2d');
this._chartjs = new Chart(ctx, {
type: 'scatter',
data: {
datasets: []
},
options: {
legend: {
//display: false
},
scales: {
xAxes: [{
type: 'linear',
position: 'bottom',
}]
},
plugins: {
zoom: zoom_options // https://github.com/chartjs/chartjs-plugin-zoom
}
}
});
My old line options :
{
label: name,
showLine: false,
fill:false,
spanGaps: false, // I have some NaN values in my datasets.
backgroundColor: color.points_borders,
borderColor: color.line,
borderWidth:5,
pointRadius:5,
pointBorderWidth:2,
pointBorderColor: color.points_borders,
pointBackgroundColor: color.points,
data: []
}
My old update function:
this._chartjs.options.scales.xAxes[0].ticks.min = min;
this._chartjs.options.scales.xAxes[0].ticks.max = length;
this._chartjs.update();

how to show text inside a chart - pie and doughnut?

I have tried a lot of it, but nothing seems to be working as expected.
I need to show the text inside the pie chart.
For the above, I tried using chartjs-plugin-datalabels but then used a formatter to change a value to a value with a percentage.
formatter: function(value:any, context:Context) {
return Math.floor(value) + '%';
},
But that affected both the data point (i.e: [11,200] is by data, I only need to add a percentage to the first data point and not to the second. Show 11% and 200.)
Code:
import ChartDataLabels,{Context} from 'chartjs-plugin-datalabels';
ChartJS.register(ArcElement, Tooltip, Legend, ChartDataLabels);
export const options = {
responsive: true,
maintainAspectRatio: false,
plugins: {
datalabels: {
formatter: function(value:any, context:Context) {
return Math.floor(value) + '%';
},
color:"white",
font: {
size: 16,
weight:'bold'
}
},
title: {
display: true,
},
legend: {
display: false,
},
},
};
function MyChart(){
return(
<Pie data={dataChart} options={options} />
)
}
In the above code options in the Pie, the component shows a typescript error while using chartjs-plugin-datalabels library.
The expected type comes from property 'options' which is declared here on type 'IntrinsicAttributes & Omit<ChartProps<"doughnut", number[], unknown>, "type"> & { ref?: ForwardedRef<ChartJSOrUndefined<"doughnut", number[], unknown>> | undefined; }'
2: I need to show text in the center of a Doughnut chart but seems impossible with the library and reactchartjs2 don't have a feature to show text in charts. Tried a possible solution at Add text inside the Doughnut chart of the React-Chartjs-2 box to react but none helped.

How to limit chart JS hover to take only one value from each line chart when zoomed out?

I'm using chart.js 3.6.1 with VueJS. These are options for particular data I'm having trouble:
hover: {
mode: 'x',
intersect: false
},
scales: {
y: {
// not relevant
},
x: {
type: 'time',
min: minRangeDate.value,
max: maxRangeDate.value,
time: {
displayFormats: {
day: 'dd.MM.',
hour: 'HH:mm',
minute: 'HH:mm',
second: 'HH:mm:ss'
}
},
grid: {
display: true
},
ticks: {
color: 'white'
}
}
plugins: {
zoom: {
pan: {
enabled: true,
mode: 'x',
modifierKey: 'ctrl'
},
zoom: {
mode: 'x',
wheel: {
enabled: true,
speed: 0.2
},
pinch: {
enabled: true
}
},
limits: {
x: {
min: minRangeDate.value,
max: maxRangeDate.value,
minRange: 20000 // minimum zoom to seconds
}
}
}
}
}
When the graph is zoomed everything looks fine like in the picture below:
but when the graph is zoomed out hover is picking multiple points which is not desired behavior, pic below:
And as far as zoom is, the more points hover is picking.
Any idea how to overcome this. I've tried using 'point' and 'nearest' but then I get only one data in the tooltip as it is the default behavior.
Also, using 'index' is not possible because two datasets are not always the same length and it is not logical and desired to compare values by index.
Ok, here is the solution I came up with, followed by this ChartJS issue on GitHub. I've made a filter for tooltip and it looks like this now:
plugins: {
tooltip: {
mode: 'x',
displayColors: false,
intersect: false,
filter: function (tooltipItem, currentIndex, tooltipItems) {
// On zoomed out graph, hovering mouse picks a lot of data for x-axis and displays them all in tooltip.
// This filter returns only first item from each dataSet from hover picked items passed
// to tooltip, so it can be correctly displayed in tooltip for different line charts(datasets)
return tooltipItems[currentIndex].datasetIndex !== tooltipItems[currentIndex - 1]?.datasetIndex
},
.
.
.
}
Hover still selects multiple data, but the tooltip shows only one for each dataset.

Age pyramid chart using chart.js

I'm trying to create a chart using chart.js like this one (for example):
https://thebreadoflifeblog.files.wordpress.com/2013/01/uk-age-pyramid.png
I tried multiple possibilities and so far, the best one I found is using a simple trick of merging two horizontalBar charts:
But there are actually some problems.
As I said, this is actually two different charts. I would like to have only one object.
I removed the yAxis. I could leave one to display the yAxis labels, but in that case, one of the two graphics will be smaller than the other one. I would like the labels to be displayed between both charts.
The chart on the left is using negative value to achieve the right to left bars. Is there a way to 'revert' an axis ? I saw there is a 'Scale' method, but it seems complicated for just reverting the axis...
I would like to know if there is something I can do to create such chart easier and, most important, as one unique chart.
I ran up against the same problems as you, and managed to fix it using React ChartJS' HorizontalBarChart: but only one ;-)
Try stacking the yAxis and adding two datasets, using the options property
const populationPyramidOptions = {
scales: {
yAxes: [{
stacked: true
}],
xAxes: [{
stacked: false
}]
}
<HorizontalBar data={chartData} options={populationPyramidOptions} />
You can get a pretty good result:
if you use directly chartjs check about the solution here:
https://github.com/nknganda/pyramid_chart_example
The syntax for the options is not compatible with chartjs > 3.x
Below the updated code:
options = {
plugins: {
tooltip: {
intersect: true,
callbacks: {
label: function(context) {
var label = context.dataset.label || '';
var value = context.formattedValue;
var positiveOnly = value < 0 ? -value : value;
if (label) {
label += ': ';
}
if (context.parsed.y !== null) {
label += positiveOnly
}
return label;
},
},
},
legend: {
position: "bottom",
},
},
responsive: true,
scales: {
x: {
stacked: false,
ticks: {
beginAtZero: true,
callback: (v) => {
return v < 0 ? -v : v;
},
},
},
y: {
stacked: true,
ticks: {
beginAtZero: true,
},
position: "left",
},
},
indexAxis: 'y'
}
Note that tooltips is now tooltip and inside plugins, alongside with legend.
xAxies and yAxies are x and y and no more a list.
You may find more in the official chartjs doc.
Dataset don't change as you only need to make your values negative.

I want to hide the label in a tooltip because it shows undefined

I am using chart.js to show a line chart. How can I hide a tooltip label for a chart.js line chart? The label in the tooltip is showing undefined so I want to hide the label (please see the screenshot)?
Perhaps there is a way to modify tooltip where I can show only the legends value in tooltip? My code is as follows:
myLine = new Chart(ctx).Line(lineChartData, {
type: 'line',
responsive: true,
scaleShowGridLines : false,
bezierCurve : false,
animationEasing: "linear",
tooltipEvents: ["mousemove", "touchstart", "touchmove"],
showTooltips: true,
scaleLineColor: "rgba(0,0,0,.8)",
});
Just set the tooltipTitleFontSize to 0 in your options.
Preview
Script
myLine = new Chart(ctx).Line(lineChartData, {
...
tooltipTitleFontSize: 0
});
I know I am late, but I guess it still has merit to add this one.
check this : https://stackoverflow.com/a/44632748/12061669
It uses a function to hide the title:
options:{
tooltips:{
callbacks:{
title: ()=>{}
}
}
}
Setting the title's font size to zero is not ideal as you will still see an (ugly) extra space on top of the tooltip, as if the title line is still there - which honestly is what you'd expect.
Instead, I used Yumin Gui's answer but had to return null for it to work:
`
tooltips: {
callbacks: {
title: () => null,
},
},
The result is exactly as in the pie charts (which does not have a title in its default tooltips).
To hide the tooltip title/label, it should be added in the options object for that chart as follows:
options: {
plugins: {
tooltip: {
callbacks: {
title : () => null // or function () { return null; }
}
}
}
}
Do refer to the documentation to understand better that it should be handled with a custom callback function, and it is not a config that can be set in options directly.
The accepted answer won't work in newer versions of chart.js, as Aman said in comments, what you can use now is this:
tooltips: { titleFontSize: 0 }
Example:
var bar_chart = document.getElementById('bar_canvas').getContext('2d');
window.myBar = new Chart(bar_chart, {
type: 'bar',
data: bar_chart_data,
options: {
tooltips: {
titleFontSize: 0,
bodyFontSize: 14,
}
}
});