KoolReport's Forum

Official Support Area, Q&As, Discussions, Suggestions and Bug reports.
Forum's Guidelines

ChartJs onClick event - is it possible? #2614

Open Nick Hartt opened this topic on on Mar 14, 2022 - 9 comments

Nick Hartt commented on Mar 14, 2022

Hi, I need to make the labels on a few ChartJs charts clickable (and later bars on a stacked bar charts), but all of the examples I have found to do this require that the onClick event is accessible. I cannot however find a way to do this. I have numerous ways searching various other sites, and all of them use the onClick event handler which should be enabled by default. Does KoolReport not handle this correctly?

From what I've read the following should enable it (have tried with an without the "events" array as well)

"options" => array(

"events" => array(
    "click"
),
"onClick" => "function(e) debugger;"

)

I'm expecting my debugger (F12 in Chrome) to stop when I click on the chart, but nothing happens. If I can get the click event to trigger then the rest of the code I have to make labels clickable will be easy, as I've already tested it in a JS fiddle.

Looking at the script block that KoolReport creates after the chart canvas, the onClick is never passed back to the output as a linked event.

Sebastian Morales commented on Mar 15, 2022

Hi, pls try this client event:

\chartjs\BarChart::create(array(
    ...
    'clientEvents' => [
        'itemSelect' => "function (args) {
            console.log('chart item clicked', args);
        }"
    ]
))l

Let us know if it works for you. Tks,

Nick Hartt commented on Mar 15, 2022

Hi,

This triggers only on clicking a bar on the chart (which I was going to look at next, so that is still useful, thank you), but I need to also handle clicking a label on the axes - this event does not fire when clicking a label. I'm replacing an existing application that used a HTML based horizontal bar graph and the labels on the left side were used as links to the item being displayed, and need to replicate this.

ChartJS itself has onClick handler option that can be used to handle a click anywhere on the canvas, not just on the data bars/points of the chart, but this isn't being attached by KoolReport when it creates the chart using my settings so I'm assuming that the wrapper code is ignoring unknown options and that KoolReport has added the clientEvents setting itself to ChartJS?

Sebastian Morales commented on Mar 16, 2022

Ok, I see that KoolReport's chartjs wrapper object does change the general onClick event to work on item select only. If you want to catch the general click event as well pls follow these steps:

1 . Open the file koolreport/chartjs/clients/chartjs.js

2 . Replace the following line:

        settings.options.onClick = function (e, items) {

with these ones:

        var onClick = settings.options.onClick;
        settings.options.onClick = function (e, items) {
            if (typeof onClick === 'function') onClick(e);

After this you can catch both the general onClick and itemSelect events:

    BarChart::create(array(
        ...
        "options" => [
            "events" => ["click"],
            "onClick" => "function(e, items) {
                console.log('onclick', e);
            }"
        ],
        "clientEvents" => [
            "itemSelect" => "function(args) {
                console.log('itemSelect', args);
            }"
        ]
    ));

Note that in this case the general onClick event would be fired before itemSelect one since we call it right at the beginning of the listener function.

Nick Hartt commented on Mar 18, 2022

Hi,

I think there's a bug in your suggestion, as the onClick function has two parameters of e and items, but the mod to chartjs.js only passes in e. I changed it to onClick(e, items) so solve this.

Is there a way I can define this change so that a future version of KoolReport won't remove this change? Will Koolreport add in support for the onClick event as defined in ChartJS itself - it appears to have the event and activeElements as the parameters, so would this be e and items as I've already done?

However, this doesn't give access to the labels, so I've also had to add the chart variable, so it's now onClick(e, items, this.chart) as otherwise I can't see any way to determine which chart has triggered the onClick call. Is there a way to get the chart reference in the function call without resorting to the modification I've made? In the debugger I can't see any simple way to access the current chart object from the function itself.

I was hoping that chart.getElementAtEvent(e) would help with figuring out the label that was clicked, but this always returns a empty array.

What I've come up with is the following, which seems to work for me (I'm using right aligned labels on a horizontal chart, hence the way the calculations are done). It assumes that the labels are all the same height, which they are in my case. The links are a PHP array of URLs, which are then encoded into a variable inside the function - each chart gets it's own copy of the function with it's own links array as this is generated from an included PHP script for each chart on the page.

$settings["options"]["onClick"] = "function(e, items, chart) {
	var links = ".json_encode($textlink).";

	var lx = e.offsetX;
	var ly = e.offsetY;
	let index = -1;

	var height = chart.scales['y-axis-0']._labelSizes.first.height;
	var width = chart.scales['y-axis-0'].width;

	for (let i = 0; i < chart.scales['y-axis-0']._labelItems.length; i++) {
	const {
	  x,
	  y
	} = chart.scales['y-axis-0']._labelItems[i];

	if (lx >= x - width && lx <= x && ly >= y - height/2 && ly <= y + height/2 ) {
	  index = i;
	  break;
	}
	}

	if (index !== -1)
	  if (links[index])														  
		window.open(links[index], '_self');

	return false;
}";

Sebastian Morales commented on Mar 18, 2022

We will incorporate this change to the next version of Chartjs. As for the chart object, did you mean you want access to the Chartjs js object as in?

var chart = new Chart(ctx, settings);
...
Nick Hartt commented on Mar 18, 2022

Hi,

Yes we'd need a way to access each chart object from the onClick function. As we're using KoolReport to create them via PHP libraries rather than direct via Javascript there isn't a unique chart object per chart created in the page. For example one of the pages I'm currently working with has 11 charts (7 bar charts and 4 line charts) but could have many more depending on the configuration options.

Sebastian Morales commented on Mar 21, 2022

I see your point. In the next version of Chartjs package you will be able to access the chartjs object in onClick event with this.chart like this:

    BarChart::create(array(
        ...
        "options" => [
            "events" => ["click"],
            "onClick" => "function(e, items) {
                console.log('barchart onclick');
                console.log('event = ', e);
                console.log('items = ', items);
                console.log('this.chart = ', this.chart);
            }"
        ],
        "clientEvents" => [
            "itemSelect" => "function(args) {
                console.log('itemSelect', args);
            }"
        ]
    )); 

If you don't want to wait for the next release, pls apply this change by opening the file koolreport/chartjs/clients/chartjs.js and replace this line:

        settings.options.onClick = function (e, items) {

with these ones:

        var onClick = settings.options.onClick;
        if (typeof onClick === 'function') onClick = onClick.bind(this); // to enable onClick access to this.chart object 
        settings.options.onClick = function (e, items) {
            if (typeof onClick === 'function') onClick(e, items);
Nick Hartt commented on Mar 21, 2022

Hi,

Thanks, that works great.

eMaX commented on Jul 8, 2023

Piggy-Backing on this one, I try to not only get the bar that I clicked on, but in a stacked bar chart scenario, the segment I clicked on. Is that possible?

Build Your Excellent Data Report

Let KoolReport help you to make great reports. It's free & open-source released under MIT license.

Download KoolReport View demo
solved

None