How to add an on click event to my Line chart using Chart.js
Asked Answered
R

6

18

I am trying to add an on click event to my Line chart using Chart.js. I already have my tool tips enabled to show the information from my line charts, but I would also like to add an on click method that will let me know where the user clicked on the x axis. For now I would just like an alert to pop up, giving me the value on the x axis where the user clicked.

RESEARCH:

I looked through the documentation of Chart.js and I came across this method: .getPointsAtEvent(event)

Calling getPointsAtEvent(event) on your Chart instance passing an argument of an event, or jQuery event, will return the point elements that are at that the same position of that event.

canvas.onclick = function(evt){
    var activePoints = myLineChart.getPointsAtEvent(evt);
    // => activePoints is an array of points on the canvas that are at the same position as the click event. };

I just can't figure out how to use or where to place the function in my code. If anyone could help me figure out where I can add this to my code, it would be greatly appreciated!

MY CODE: (in javascript)

  //NOTE: the div 'roomForChart' has been already declared as <div id="roomForChart"></div>


 //creating html code inside of javascript to display the canvas used for the graph
 htmlForGraph = "<canvas id='myChart' width ='500' height='400'>";
 document.getElementById('roomForChart').innerHTML += htmlForGraph;

 //NOW TO CREATE DATA

   //the data for my line chart
    var data = {
         labels: ["Aug 1", "Aug 2", "Aug 3","Aug 4","Aug 5"], //the x axis
          datasets: [
            {   //my red line
                label: "Usage Plan",
                fillColor: "rgba(255,255,255,0.2)", //adds the color below the line
                strokeColor: "rgba(224,0,0,1)",//creates the line
                pointColor: "rgba(244,0,0,1)",
                pointStrokeColor: "#fff",
                pointHighlightFill: "#fff",
                pointHighlightStroke: "rgba(220,220,220,1)",
                data: [1024, 1024, 1024, 1024, 1024]
           },

       {    //my green line
            label: "Overall Usage",
            fillColor: "rgba(48,197,83,0.2)",
            strokeColor: "rgba(48,197,83,1)",
            pointColor: "rgba(48,197,83,1)",
            pointStrokeColor: "#fff",
            pointHighlightFill: "#fff",
            pointHighlightStroke: "rgba(48,197,83,1)",
            data: [15, 25, 45, 45, 1500]
       },
        {  //my blue line
            label: "Daily Usage",
            fillColor: "rgba(151,187,205,0.2)",
            strokeColor: "rgba(151,187,205,1)",
            pointColor: "rgba(151,187,205,1)",
            pointStrokeColor: "#fff",
            pointHighlightFill: "#fff",
            pointHighlightStroke: "rgba(151,187,205,1)",
            data: [15, 10, 20, 0, 5]
       }

     ] //ending the datasets
     }; //ending data


    //creating a variable for my chart
    var ctx = document.getElementById("myChart").getContext("2d");




//code to create a maximum y value on the chart
var maxUsage = 1024;
var maxSteps = 5;
var myLineChart = new Chart(ctx).Line(data, {
    pointDot: false,
    scaleOverride: true,
    scaleSteps: maxSteps,
    scaleStepWidth: Math.ceil(maxUsage / maxSteps),
    scaleStartValue: 0

});

 //what I have tried but it doesn't show an alert message
ctx.onclick = function(evt){
    var activePoints = myLineChart.getPointsAtEvent(evt);
    // => activePoints is an array of points on the canvas that are at the same position as the click event.
   alert("See me?");
};

To those of you who have a hard time visualizing the chart here you go:

enter image description here

Hopefully I have provided enough information to get some help. Please let me know if I need to explain myself. Thank you in advance!!! :)

Replication answered 26/8, 2014 at 20:42 Comment(0)
L
7

Change this line

document.getElementById('roomForChart').innerHTML += htmlForGraph;

to this

holder = document.getElementById('roomForChart');
holder.innerHTML += htmlForGraph;

and further you'll have your snippet, modified a bit

holder.onclick = function(evt){
    var activePoints = myLineChart.getPointsAtEvent(evt);
    // => activePoints is an array of points on the canvas that are at the same position as the click event.
   alert("See me?");
};

Add console.log(activePoints); within onclick handler to see the content of the activePoints variable. As I can see, there are three objects. For instance these are values for activePoints[0]

datasetLabel: "Usage Plan"
fillColor: "rgba(244,0,0,1)"
highlightFill: "#fff"
highlightStroke: "rgba(220,220,220,1)"
label: "Aug 4"
strokeColor: "#fff"
value: 1024
x: 371
y: 12.356097560975627

And they may be accessed as following

activePoints[0].label
activePoints[0].x
activePoints[0].y
activePoints[0].value

It will be good to check if the property is undefined first, since there are no data behind every click event.

Livi answered 26/8, 2014 at 21:34 Comment(7)
You rock! I knew I was close! Thank you for suggesting I use a holder. I never even thought of that!Replication
Quick question! When I write alert(activePoints); An alert pops up with no information inside of it (I am guessing it is empty or null). How do I get/pull out that information?Replication
@Replication I just was reading that part; I'll drop you a note in a couple of minutes; just to figure out the format of output.Livi
@Replication The point is that there are no data for every pixel on the chart and that's why I was getting undefined error on a certain click event. So, just check if the property is undefined before you alert or show it ;) And check the last update.Livi
I added a console log to activePoints[0]. I kept getting [Information] as a result until by some miracle when I clicked on the graph just right I got: [Information] (JavaScript.KKJSObject) { value : 1024d, label : "Aug 5", datasetLabel : "Usage Plan", strokeColor : "#fff", fillColor : "rgba(244,0,0,1)", ... } Why can't the chart round the label to the nearest value like the tool tip?Replication
@Replication Well, as you may know, we see a curve as a result of interpolation of a few given data. So I'm not sure if chart calculates data for every point. I was working on a similar problem using highcharts a few weeks ago and couldn't get to have a (let's say) rounded value on every click. I'll let you know if I menage to find a workaround.Livi
Thank you so much for your insight on this. Good luck on your progress and please let me know if you get any closer. Thank you!Replication
H
8

if youre using the new ChartJs version use this:

canvas.onclick = function(evt){
   var activePoints = myLineChart.getElementsAtEvent(evt);
};
Haematocele answered 25/7, 2016 at 6:1 Comment(1)
thanks bro, u saved my time ^_^ ! It perfectly works for new charjs version.Reorganize
L
7

Change this line

document.getElementById('roomForChart').innerHTML += htmlForGraph;

to this

holder = document.getElementById('roomForChart');
holder.innerHTML += htmlForGraph;

and further you'll have your snippet, modified a bit

holder.onclick = function(evt){
    var activePoints = myLineChart.getPointsAtEvent(evt);
    // => activePoints is an array of points on the canvas that are at the same position as the click event.
   alert("See me?");
};

Add console.log(activePoints); within onclick handler to see the content of the activePoints variable. As I can see, there are three objects. For instance these are values for activePoints[0]

datasetLabel: "Usage Plan"
fillColor: "rgba(244,0,0,1)"
highlightFill: "#fff"
highlightStroke: "rgba(220,220,220,1)"
label: "Aug 4"
strokeColor: "#fff"
value: 1024
x: 371
y: 12.356097560975627

And they may be accessed as following

activePoints[0].label
activePoints[0].x
activePoints[0].y
activePoints[0].value

It will be good to check if the property is undefined first, since there are no data behind every click event.

Livi answered 26/8, 2014 at 21:34 Comment(7)
You rock! I knew I was close! Thank you for suggesting I use a holder. I never even thought of that!Replication
Quick question! When I write alert(activePoints); An alert pops up with no information inside of it (I am guessing it is empty or null). How do I get/pull out that information?Replication
@Replication I just was reading that part; I'll drop you a note in a couple of minutes; just to figure out the format of output.Livi
@Replication The point is that there are no data for every pixel on the chart and that's why I was getting undefined error on a certain click event. So, just check if the property is undefined before you alert or show it ;) And check the last update.Livi
I added a console log to activePoints[0]. I kept getting [Information] as a result until by some miracle when I clicked on the graph just right I got: [Information] (JavaScript.KKJSObject) { value : 1024d, label : "Aug 5", datasetLabel : "Usage Plan", strokeColor : "#fff", fillColor : "rgba(244,0,0,1)", ... } Why can't the chart round the label to the nearest value like the tool tip?Replication
@Replication Well, as you may know, we see a curve as a result of interpolation of a few given data. So I'm not sure if chart calculates data for every point. I was working on a similar problem using highcharts a few weeks ago and couldn't get to have a (let's say) rounded value on every click. I'll let you know if I menage to find a workaround.Livi
Thank you so much for your insight on this. Good luck on your progress and please let me know if you get any closer. Thank you!Replication
A
6

I couldn't get the onclick method to work.

But I finally managed to run it using the click method:

$("#canvas_id").click(function(e) {
   var activeBars = myBarChart.getBarsAtEvent(e); 
   console.log(activeBars[0]);
});

Note: this example if for the Bar chart - other charts have slightly different methods to retrieve the points (see the documentation).

Adiel answered 26/3, 2015 at 16:49 Comment(1)
I tried to use this approach but it didnt work for me and I am note sure why. The click event is attached I also debuged the function getBarsAtEvent but the retrieved bar is not the one I just clicked or sometimes just doesnt retrieve any data. The getPointsAtEvent is the method which you can pass in a click event, and it will a return an array of points at the location of that event but in my case sometimes retrieves an empty array.Spermatic
S
5

The answers provided to date are close to the correct solution(s), but are incomplete. You need to use the getElementsAtEvent() to get the correct elements, but this gives you a collection of elements that are at the clicked x-index. In the even that you are using more than one dataset, this could be several values, one from each data set.

To figure out the correct data set to pull from, call the getDatasetAtEvent() method. This will return a list of the elements that contains the clicked dataset element. Pick the dataset Id from any of them, they are all the same Id.

Put the two together and you have the call you need to figure out the data contained in the clicked element. Passing in more than just and x and y value when you init your data set will let you do all sorts of neat tricks with this event. (For example, trigger a popup with more detailed info about the event)

There might be a more succinct way of getting this data, but I didn't find it mucking around the chart docs and tickets. Perhaps they will add it in a future release.

// chart_name is whatever your chart object is named. here I am using a
// jquery selector to attach the click event.
$('#' + chart_name).click(function (e)
{
    var activePoints = myChart.getElementsAtEvent(event);
    var activeDataSet = myChart.getDatasetAtEvent(event);

    if (activePoints.length > 0)
    {
         var clickedDatasetIndex = activeDataSet[0]._datasetIndex;
         var clickedElementIndex = activePoints[0]._index;
         var value = myChart.data.datasets[clickedDatasetIndex].data[clickedElementIndex];
    }
    // todo: add code to do something with value.
});
Schenk answered 24/10, 2017 at 0:32 Comment(1)
You are a hero!Mordvin
A
2

V3

You can also use the build in onClick option which gets the following paramters: (event, activeElements, chartInstance)

So you can just read the array you get as second element to see which elements have been active. By default this array contains only 1 item but if you change your interaction modes multiple items could be in here.

var options = {
  type: 'bar',
  data: {
    labels: ["Red", "Blue", "Yellow", "Green", "Purple", "Orange"],
    datasets: [{
        label: '# of Votes',
        data: [12, 19, 3, 5, 2, 3],
        backgroundColor: 'pink'
      },
      {
        label: '# of Points',
        data: [7, 11, 5, 8, 3, 7],
        backgroundColor: 'orange'
      }
    ]
  },
  options: {
    onClick: (evt, activeElements, chart) => {
      console.log(`DatasetIndex: ${activeElements[0].datasetIndex} DataIndex: ${activeElements[0].index}`)
    }
  }
}

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.6.0/chart.js"></script>
</body>

In v3 the getElementsAtEvent has been removed and now you have to use: chart.getElementsAtEventForMode(event, 'index', { intersect: true }, false)

If you want to use getDatasetAtEvent you now have to use: chart.getElementsAtEventForMode(e, 'dataset', { intersect: true }, false)

Abana answered 29/10, 2021 at 14:30 Comment(0)
S
0

In current version(3.9.1) i could not find .getPointsAtEvent(event) no more. As a workaround that worked for me I found in Chart.js GitHub code sample

 var selectedPoint;
        ....
        options: {
            plugins: {
                tooltip: {
                    callbacks: {
                        afterBody: function(context) {
                           if(context && context[0])
                            selectedPoint = context[0];
                            return [''];
                        }
                    }
                }
            },
            .....
            onClick: (e) => {
                console.log(selectedPoint);
            }
        }

Basicaly on tooltip generation you save data to variable selectedPoint and in onClick event you start using it.

Specter answered 12/10, 2022 at 8:27 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.