Identify which chartJs chart was clicked on - javascript

I have several charts on a page.
They are created dynamically.
I need to identify in the click event, or somehow, which chartwas clicked on.
Maybe it's parent element?
The canvas 'canvas1' or 'canvas2' or ..'canvas10',is in a bootstrap column of id 'col1' or 'col2' or ..'col10'
I can't get to pass a parameter via the click function
onClick: OnDrillDownClick(evt, canvasIdParam)
Each chart of course has a different canvas but all are defined as demoChart.
var canvasChart = $("#canvas" + canvasId).get(0).getContext("2d");
demoChart = new Chart(canvasChart,
Using the 'OnClick' function provided, e.g.
function OnDrillDownClick(evt)
{
var activePoints = demoChart.getElementsAtEvent(evt);
...etc
}
I just need to identify which chart was clicked on as I keep an array of the created charts i.e.
var chartRec = {
CanvasId: canvasId,
Chart: demoChart
};
chartsArray.push(chartRec);
Many thanks

You can get the canvas id from the click event like this:
var options = {
type: 'line',
data: {
labels: ["Red", "Blue", "Yellow", "Green", "Purple", "Orange"],
datasets: [{
label: '# of Votes',
data: [12, 19, 3, 5, 2, 3],
borderWidth: 1
},
{
label: '# of Points',
data: [7, 11, 5, 8, 3, 7],
borderWidth: 1
}
]
},
options: {
onClick: (evt) => {
console.log(evt.target.getAttribute('id'))
}
}
}
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/2.9.4/Chart.js" integrity="sha512-hZf9Qhp3rlDJBvAKvmiG+goaaKRZA6LKUO35oK6EsM0/kjPK32Yw7URqrq3Q+Nvbbt8Usss+IekL7CRn83dYmw==" crossorigin="anonymous"></script>
</body>

Related

How to use 2 different versions of chart.js in same html source tag

I've plots build with 2 different versions of chart.js. one is with 3.8.0 & other is with 2.8.0. So, I'm including both the versions in tags like this.
<script src="https://cdn.jsdelivr.net/npm/chart.js#3.8.0"></script> #For plot1
<script src="https://cdn.jsdelivr.net/npm/chart.js#2.8.0"></script> #for plot2
-->Both are color plots. so whenever i use js#3.8.0 first It's plotting plot1 as color. But, plot2 I'm getting with no color's.
-->Similarly when I use js#2.8.0 as first src
<script src="https://cdn.jsdelivr.net/npm/chart.js#2.8.0"></script> #for plot2
<script src="https://cdn.jsdelivr.net/npm/chart.js#3.8.0"></script> #For plot1
plot1I'm getting withno color&plot2withcolor` 😐
I get it that in Html executes script src line by line. is there is any way to use different chartjs versions at a time?. Any reference pls?
You guys want to upload the code?. It's a very big source code. So, I just want to get thoughts for my issue from the community people
Chart.js #3.8.0 version code I'm using
Fiddle https://jsfiddle.net/rnsbhargav/x10qjr5k/3/
graph2() {
const options = {
type: 'line',
data: {
labels: ["Red", "Blue", "Yellow", "Green", "Purple", "Orange"],
datasets: [{
label: '# of Votes',
data: [12, 19, 3, 5, 2, 3],
segment: {
borderColor: (ctx) => (ctx.p0.parsed.y < ctx.p1.parsed.y ? 'green' : 'red')
}
}]
},
options: {}
}
const ctx = document.getElementById('mychart').getContext('2d');
new Chart(ctx, options);
},
So this in chartjs 3.8.0. Should I need to downgrade syntax?. If so how to make this code work on chartjs 2.0 version...
I found After digging some documentation I came to know that syntax migrated for #chartjs2 to chartjs3 is different...
so is there is anyway
I can modify the code & get same output with chartjs#2 version?
Is there is any way we can use .noconflict method we use normally on Jquery? so that i can use 2 different versions on source tags
https://www.chartjs.org/docs/master/getting-started/v3-migration.html
You can load the old version of chart.js, store it in a variable, then load the new version also store it and then you can use both, as you can see in the example below old version filled by default and had beziercurves enabled, v3 does not fill by default and has sharp lines:
<body>
<canvas id="chartJSContainer" width="600" height="400"></canvas>
<canvas id="chartJSContainer2" width="600" height="400"></canvas>
<script src="https://cdnjs.cloudflare.com/ajax/libs/Chart.js/2.9.4/Chart.js"></script>
<script>
const chartOld = Chart;
</script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/Chart.js/3.8.0/chart.js"></script>
<script>
const chartNew = Chart;
const options = {
type: 'line',
data: {
labels: ["Red", "Blue", "Yellow", "Green", "Purple", "Orange"],
datasets: [{
label: '# of Votes',
data: [12, 19, 3, 5, 2, 3],
borderColor: 'orange'
},
{
label: '# of Points',
data: [7, 11, 5, 8, 3, 7],
borderColor: 'pink'
}
]
},
options: {}
}
const ctx = document.getElementById('chartJSContainer').getContext('2d');
const ctx2 = document.getElementById('chartJSContainer2').getContext('2d');
new chartNew(ctx, options);
new chartOld(ctx2, options);
</script>
</body>

Chart.js: Change lengend colors to array

I have a chart with three datasets (Svelte REPL with code and result) and would like to change the background colors of the boxes corresponding to each set, for example:
let legendColors = ['#dddddd', '#aaaaaa', '#777777'];
After several attempts the closest I got was changing font color, but not even that as array, only a single one. :(
How do I get the boxes of the legend to be in the 3 colors I want?
Thank you in advance for your help!
Edit: I did find something here: What happened to generateLegend() in chartjs 3.0?, but that removes the functionality of the legend (i.e. removing parts of the data).
Edit: Another answer below has running snippet that is simpler to implement which also answers OP's request. My original answer below is more focused on building the legend completely by oneself.
Live Demo. I've found this is fun...
Some points to note:
You need to build the legend yourself, as your colors are not "relevant" to the data you use (that's why by default it is using the colors from dataset "a") (edited as another answer shows such possibility)
As you are using Svelte, in the Demo I used the <style> which binds with the <div> for the legend for styling of the legend.
For people who ain't using Svelte, or are seeking solutions within Chart.js, they should follow the advice from the StackOverflow answer OP linked -- they need to build the legend using the plugins field of 2nd argument when creating a new Chart()
No matter which route to take, to keep the functionality of the legend as OP mentioned, I added a tweaked version of default behaviour of OnClick.
P.S. For (3) we have to further override generateLabels() (here, but may cause meta.controllers._resolveAnimation having problems, which we may still need to override onClick).
P.P.S. When a legend item is clicked, the label is crossed out (strikethrough) as a default behaviour. That is left as a further exercise or another answer. (For Svelte, use Boolean flags to change styles. Alternatively, hack with CSS checked checkbox labels).
You can achieve this in 2 ways, using a custom generateLabels function or by specifying a backgroundcolor in the dataset.
Custom generateLabels:
let legendColors = ['#dddddd', '#aaaaaa'];
const options = {
type: 'line',
data: {
labels: ["Red", "Blue", "Yellow", "Green", "Purple", "Orange"],
datasets: [{
label: '# of Votes',
data: [12, 19, 3, 5, 2, 3],
borderColor: 'pink'
},
{
label: '# of Points',
data: [7, 11, 5, 8, 3, 7],
borderColor: 'orange'
}
]
},
options: {
plugins: {
legend: {
labels: {
generateLabels: function(chart) {
const datasets = chart.data.datasets;
const {
labels: {
usePointStyle,
pointStyle,
textAlign,
color
}
} = chart.legend.options;
return chart._getSortedDatasetMetas().map((meta, i) => {
const style = meta.controller.getStyle(usePointStyle ? 0 : undefined);
const borderWidth = Chart.helpers.toPadding(style.borderWidth);
return {
text: datasets[meta.index].label,
fillStyle: legendColors[i],
fontColor: color,
hidden: !meta.visible,
lineCap: style.borderCapStyle,
lineDash: style.borderDash,
lineDashOffset: style.borderDashOffset,
lineJoin: style.borderJoinStyle,
lineWidth: (borderWidth.width + borderWidth.height) / 4,
strokeStyle: style.borderColor,
pointStyle: pointStyle || style.pointStyle,
rotation: style.rotation,
textAlign: textAlign || style.textAlign,
borderRadius: 0, // TODO: v4, default to style.borderRadius
// Below is extra data used for toggling the datasets
datasetIndex: meta.index
};
}, this);
}
}
}
}
},
}
const 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.7.1/chart.js"></script>
</body>
Adding background color prop in datasets:
const options = {
type: 'line',
data: {
labels: ["Red", "Blue", "Yellow", "Green", "Purple", "Orange"],
datasets: [{
label: '# of Votes',
data: [12, 19, 3, 5, 2, 3],
borderColor: 'pink',
pointBackgroundColor: 'pink',
backgroundColor: '#dddddd'
},
{
label: '# of Points',
data: [7, 11, 5, 8, 3, 7],
borderColor: 'orange',
pointBackgroundColor: 'orange',
backgroundColor: '#aaaaaa'
}
]
},
options: {},
}
const 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.7.1/chart.js"></script>
</body>

React-Chart.js legend onClick function

I'm working on a bar chart with multiple stacked datasets using the react wrapper for Chart.js(https://github.com/reactchartjs/react-chartjs-2).
I've been trying to make the chart show only one dataset at a time, but I'm having trouble coming up with the right function.
I want the chart to start off with all the datasets hidden(this part was easy) and when you click the legend I want the chart to only show only the selected dataset. So when you click one and then another I want the first one to get hidden.
I know I need to use the legend onClick option but I can't figure out how to set it up.
Any help would be appreciated, thanks!
Edit: Here is the chart in question: https://codesandbox.io/s/lucid-river-xhvtd?file=/src/charts/bar_chart.js
You can set all datasets to hide and then only the one clicked to show:
var options = {
type: 'line',
data: {
labels: ["Red", "Blue", "Yellow", "Green", "Purple", "Orange"],
datasets: [{
label: '# of Votes',
data: [12, 19, 3, 5, 2, 3],
borderColor: 'pink',
hidden: true
},
{
label: '# of Points',
data: [7, 11, 5, 8, 3, 7],
borderColor: 'orange',
hidden: true
},
{
label: '# of People',
data: [3, 1, 15, 4, 9, 12],
borderColor: 'cyan',
hidden: true
}
]
},
options: {
plugins: {
legend: {
onClick: (evt, legendItem, legend) => {
const index = legendItem.datasetIndex;
const ci = legend.chart;
legend.chart.data.datasets.forEach((d, i) => {
ci.hide(i);
d.hidden = true;
})
ci.show(index);
legendItem.hidden = false;
ci.update();
}
}
}
}
}
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>

Chart.js v3: Tooltip callback doesn't identify clicked dataset of stacked bar chart

In Chart.js v2, the datasetIndex property of ChartTooltipItem[] identifies which segment of a stacked bar chart was clicked. This allowed the tooltip content to be customized for each segment of the stacked bar chart.
In v3, TooltipItem[] provides the datasets but does not identify which one was clicked. There is a datasetIndex field for each TooltipItem, but it just matches the index in TooltipItem[] rather than identify the clicked segment.
Has anyone found a field in the V3 tooltip callback to identified which segment of a stacked bar chart was clicked? Or was this functionality lost in the v3 rewrite?
It just works fine, the only thing that is different is that it seems like in v2 it defaulted to the point mode while now it is using index mode, if you change it back to point it works as expected:
var options = {
type: 'bar',
data: {
labels: ["Red", "Blue", "Yellow", "Green", "Purple", "Orange"],
datasets: [{
label: '# of Votes',
data: [12, 19, 3, 5, 2, 3],
backgroundColor: 'red'
},
{
label: '# of Points',
data: [7, 11, 5, 8, 3, 7],
backgroundColor: 'blue'
}
]
},
options: {
plugins: {
tooltip: {
mode: 'point',
callbacks: {
beforeBody: (ttItems, x) => {
ttItems.forEach((ttItem) => {
console.log('BeforeBody: ', ttItem.datasetIndex, ttItem.dataIndex)
})
},
afterBody: (ttItems, x) => {
ttItems.forEach((ttItem) => {
console.log('AfterBody: ', ttItem.datasetIndex, ttItem.dataIndex)
})
}
}
}
},
scales: {
y: {
stacked: true
},
x: {
stacked: true
}
}
}
}
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.4.1/chart.js"></script>
</body>

how to display last x float number value in chartjs

I'm making a Vertical Bar Chart using react-chartjs-2.
and I have array of lots of float numbers stored.
I tried to use chartjs callback option to display only the last value on a graph.
But the value in the callback is an integer, so I can't take the value I want.
for example,
const xAsisData = [ 1.11, 4.23, 7.34, ... , 403.78 ] // includes hundreds
scales: {
x: {
ticks: {
autoSkip: false,
callback: (value) => {
// if value === last ? value : null
// ! but last value is 309, not 403.78
},
},
Is there any other option I can use?
You get the index and ticks array as well in your callback so you can just check if the index is not the final one like so:
var options = {
type: 'line',
data: {
labels: ["Red", "Blue", "Yellow", "Green", "Purple", "Orange"],
datasets: [{
label: '# of Votes',
data: [12, 19, 3, 5, 2, 3],
borderWidth: 1
},
{
label: '# of Points',
data: [7, 11, 5, 8, 3, 7],
borderWidth: 1
}
]
},
options: {
scales: {
y: {
ticks: {
callback: (val, i, ticks) => (i < ticks.length - 1 ? val : null) // Replace null by empty string to still show the gridLine
}
}
}
}
}
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.3.2/chart.js"></script>
</body>

Categories