When using chart.js, custom tooltips disappear immediately after rendering - javascript

I'm using chart js 2 to display several Line graphs. I want to set a custom tooltip to allow me to view additional data when the user hovers over a point on the graph. However, every time I add a callback function (no matter what the function returns), it causes the tooltip to disappear. It properly renders my custom text for a brief moment, but then it disappears. I have to move my mouse around constantly to be able to read the tooltips. Here's the documentation on this function https://www.chartjs.org/docs/latest/configuration/tooltip.html#label-callback
I've tried changing virtually every chart option I can. I'm currently using the callback function 'label', but I've tried beforeLabel and afterLabel as well. One thing that I noticed had an effect is when I changed the value of "animation: { duration } ". It's currently set to 0 because I don't want any of the other animations when the charts change, because they update frequently. I set it to 1000 and I noticed that the tooltip persisted for slightly longer and had a darker background, but the overall chart rendering seemed to slow down. I've also changed the callback function's format from an arrow function to a regular function.
Here are my chart options, with the relevant portion spaced out more towards the end:
const chartOptions = {
legend: {
labels: {
fontColor: NUMBER_COLOR,
fontSize: 12
}
},
scales: {
xAxes: [{
scaleLabel: {
display: true,
labelString: "Frame",
fontColor: SCALE_LABEL_COLOR,
fontSize: 14
},
stepSize: ystep,
ticks: {
min: XMIN,
max: XMAX,
stepSize: (XMAX - XMIN) / TICK_NUMS,
maxRotation: 0,
minRotation: 0,
fontColor: NUMBER_COLOR,
fontSize: 12
},
type: "linear"
}],
yAxes: [{
scaleLabel: {
display: true,
labelString: this.props.yAxisUnits,
fontColor: SCALE_LABEL_COLOR,
fontSize: 14
},
ticks: {
id: "0",
min: yChartMin,
max: yChartMax,
stepSize: Number(((yChartMax - yChartMin) / TICK_NUMS).toFixed(DECIMAL_NUM)),
maxRotation: 0,
minRotation: 0,
display: true,
fontColor: NUMBER_COLOR,
fontSize: 13
}
}]
},
animation: {
duration: 0
},
tooltips: {
intersect: true,
mode: "nearest",
enabled: true,
callbacks: {
label: (tooltipItems, data) => {
const labelText = [
data.datasets[tooltipItems.datasetIndex].label + ": " + data.datasets[tooltipItems.datasetIndex].data[tooltipItems.index].y,
"Time: " + data.datasets[tooltipItems.datasetIndex].data[tooltipItems.index].time
];
return labelText;
}
}
}
};
The data points themselves each follow the format:
{
x: xValue,
y: yValue,
time: timeValue
}
and my chart is displayed via:
<Line
data={chartData}
options={chartOptions}
width={DEFAULT_WIDTH}
height={DEFAULT_HEIGHT}
getElementAtEvent={(e: any) => this.clickedElement(e)}
/>
When I delete the callback function "label", the tooltip persists and displays as expected. Please let me know if you can offer help in any way.
Thanks!

Related

How to clear/destroy Chart.js canvas when the chart is represented as a react JSX element

I am running into this issue with chart.js where I have a chart on a specific report. When I switch pages to another page that contains chartjs elements and switch back the chart is showing data labels on the charts data points as "x: number, y: number".
After reading a bit about this I believe it's because the canvas is not being correctly reset when I switch back to the original chart.
the examples of fixes using the clear() or destroy() command that I've found reference the charts canvas.
example: Destroy chart.js bar graph to redraw other graph in same <canvas>
However in react that's a bit more tricky to get to.
My question is, how can I clear the canvas before drawing my graph. Below is the chart component used to draw the graph.
cont Chart: FunctionComponent<Props> = ({data}) => {
const options = (): ChartOptions => ({
responsive: true,
maintainAspectRatio: false,
legend: {
display: false
},
tooltips: chartTooltips,
elements: chartElementsNoLines,
scales: {
xAxes: [
{
display: true,
id: 'x-axis-0',
ticks: {
suggestedMin: minMax.min,
suggestedMax: minMax.max,
maxTicksLimit: 7,
maxRotation: 0,
fontFamily: 'Roboto, sans-serif',
fontSize: 10,
autoSkip: true,
callback: value => currency(value, { precision: 0 }).format()
},
gridLines: {
display: false
}
}
],
yAxes: [
{
type: 'linear',
display: false,
ticks: {
min: 0,
max: maxY
},
id: 'y-axis-0',
gridLines: {
display: false
}
}
]
}
})
return (
<section>
<div className={classes.chartContainer}>
<HorizontalBar
data-cy="limit-chart"
data={data}
options={{ ...options(), ...annotationPlugin() }}
redraw={true}
height={80}
/>
</div>
</section>
)
}
I had problems with data and size changes on rerendering, and i found a way to force updating it using ref (profitChartRef.current.chartInstance.destroy();) to destroy chartInstance and then render completely new instance reflecting exactly what has been updated
export const ProfitReportChart = () => {
const profitChartRef = useRef();
if (profitChartRef?.current) {
profitChartRef.current.chartInstance.destroy();
}
return <Bar ref={profitChartRef} data={data} options={options} redraw/>;
}

Chartjs-plugin-zoom plugin does not change x axis labels

I am working with the chart.js module in order to plot some data and am using the chartjs-plugin-zoom in order to enable zooming and panning however although the zooming works the labels on the x axis will not change for whatever reason.
I have seen similar questions but they all dealt with time series data and therefore the advice was unhelpful.
Here is the plot zoomed out:
and here is it zoomed in:
The key thing to notice is how the labels on the y axis have changed but the x axis labels have not changed. Here is the relevant config variable of the chart:
const config3 = {
type: 'line',
data: {
labels: [I ran out of chars but this is just a very long list of numbers in this format: 1,2,3,4,5],
datasets: [
{
label: "",
backgroundColor: '#'+Math.floor(Math.random()*16777215).toString(16),
borderColor: '#0071BC',
data: [I ran out of chars but this is just a very long list of numbers in this format: 1,2,3,4,5],
fill: false,
borderWidth: 1,
},
],
},
options: {
responsive: true,
title: {
display: true,
text: 'Peak: -1.2188'
},
tooltips: {
mode: 'index',
intersect: false,
},
hover: {
mode: 'nearest',
intersect: true
},
scales: {
xAxes: [{
display: true,
scaleLabel: {
display: true,
labelString: 'Frequency (Hz)'
},
ticks:{
autoSkip: true,
maxTicksLimit: 20
},
}],
yAxes: [{
display: true,
scaleLabel: {
display: true,
labelString: 'Amplitude'
}
}],
},
plugins:{
zoom: {
pan: {
enabled: true,
mode: 'xy',
speed: 20,
threshold: 10,
},
zoom: {
enabled: true,
drag: false,
mode: "xy",
speed: 0.1,
// sensitivity: 0.1,
}
}
},
elements: {
point:{
radius: 0
}
}
}
};
If needed I can provide more code but I imagine the mistake is probably contained in the config. I tried changing zoom.mode to be 'x' but that did not work.
In case someone else comes along this I figured out a solution that is pretty unintuitive.
The first problem is the way that labels are dealt with in chart.js and because they are treated as categories not x data the way that I thought they were. Therfore first you must pass your data in as coordinates in this format:
(as shown in this documentation: https://www.chartjs.org/docs/latest/charts/line.html)
data: [{
x: 10,
y: 20
}, {
x: 15,
y: 10
}]
And delete the labels variable.
However this will not work with line charts despite what the documentation says. To get around this you can set: type: 'scatter' and inside the dataset write showLine: true
This will generate a line plot where the x labels are auto generated and zooming will work perfectly.
I also think there was a performance boost which is a nice bonus.

ChartJS - How to increase the maximum degree of label rotation on x-axis?

I have a line chart, and at first, all the labels on x-axis are fully horizontal. Something like this:
Now if add more data, the labels start to rotate:
Until comes a point where it seems to have reached the maximum degree to which it can rotate:
By the looks of it, I think the maximum degree is 45. So now, if I add a little more data, instead of rotating the labels more, it removes every one in two labels, and becomes like this:
How can I increase this degree to 90, so that the labels rotate as much as becoming fully vertical?
Here's the code I used for the chart:
new Chart(chart, {
type: 'line',
data: chart_data,
options: {
scales: {
yAxes: [{
ticks: {
beginAtZero: false
}
}]
},
legend: {
position: 'top',
labels: {
boxWidth: 5,
usePointStyle: true
}
},
events: ['click', 'mousemove'],
onClick: clicked,
pan: {
enabled: true,
mode: 'x',
onPanComplete: function(event) {
console.log(event)
}
},
zoom: {
enabled: true,
mode: 'x'
}
}
});
You can configure this using the maxRotation property of the common tick configuration object.
Your code needs to be modified like so:
options: {
scales: {
xAxes: [{
ticks: {
maxRotation: 90
}
}],
yAxes: [{
...
The keyword of the issue is not rotation i think, it is Tick on xAxes.
I think this link can help you :
https://www.chartjs.org/docs/latest/axes/styling.html#tick-configuration
also
Chart.js: evenly distribute ticks when using maxTicksLimit
xAxes: [{
ticks: {
autoSkip: false, // Skip or not?
maxTicksLimit: 30 // How much?
}
}]
and rotation just can help as #timclutton said here : https://stackoverflow.com/a/58275468/7514010

Bar chart with one dataset but multiple labels

I'm trying to create a graph based on data from database using Chart.js, and I'm running into issues with making multiple labels for the data. One label is the month that the data is a part of, and the second label is the type of visit.
Here's what I have at the moment.
I'm doing this by adding in another label just for this one case:
xAxes: [{
position: 'top',
offset: 1,
ticks: {
fontColor: 'black',
beginAtZero: true,
fontSize: 35,
},
gridLines: {
display: false
},
},
{
labels: ["M SP W/I B", "M SP W/I B"],
position: 'bottom',
offset: 1,
ticks: {
fontColor: 'black',
beginAtZero: true,
fontSize: 35,
},
gridLines: {
display: false
},
}
]
Problem is it's too McGyvery. My plan is to add another Label for the dataset, besides the Month/Year and put the visit types there. This will deal with the problem where there's more or less than two months on the graph.
What I would really like to do is make it so that each bar has the label underneath it (I've already tried with the label on the bar next to the number, and it does not look good). And also I would like to get rid of the empty spaces left by the 0 value bars that would be amazing, which has already been asked.
Here is an example of what I'm trying to get at.
Is there any way to do this with Chart.js?

How To Customize a Flotr2 Radar Chart

http://www.humblesoftware.com/flotr2
I am trying to modify the default font size, weight, and color for the Flotr2 radar chart. I could change this in the flotr2.js file but I want to leave the source file alone.
Currently when I set a larger fontSize in the Flotr.draw call it just spaces out the labels further.
function drawGraph(container, series, ticks)
{
Flotr.draw(container, series, {
colors: colors,
HtmlText: true,
fontSize: 30,
radar: {
show: true
},
grid: {
circular: true,
minorHorizontalLines: true
},
yaxis: {
min: 0,
max: 7,
minorTickFreq: 1,
showLabels: false
},
xaxis: {
ticks: ticks,
titleAlign: 'right'
},
legend: {
position: 'ss',
container: document.getElementById("legendItems")
}
});
}
I'm not sure what else to try...
Accessing the variables from the window object before drawing the graph seems to work well.
window.Flotr.defaultOptions.fontSize = 8;
window.Flotr.defaultOptions.xaxis.color = '#000000';
Couldn't find a way to change the font weight.

Categories

Resources