I am trying to catch an onlick event on a bubble in bubble chart. I want to log the label of clicked bubble into the console. I have written a function to do the job which actually looks like this
$("#myChart").click(function(evt) {
var activePoints = myBubbleChart.getElementAtEvent(evt);
console.log(activePoints.label);
});
Every time I click on a bubble this function logs "undefined" into console. I have even tried getBarsAtEvent and getSegmentsAtEvent none of them worked. What's wrong in my code? And can anybody please tell me how can I get the label value of bubble which I clicked?
Chart.js options have a built-in onClick property (see documentation).
It works like this :
options: {
onClick: function(e) {
var element = this.getElementAtEvent(e);
// If you click on at least 1 element ...
if (element.length > 0) {
// Logs it
console.log(element[0]);
// Here we get the data linked to the clicked bubble ...
var datasetLabel = this.config.data.datasets[element[0]._datasetIndex].label;
// data gives you `x`, `y` and `r` values
var data = this.config.data.datasets[element[0]._datasetIndex].data[element[0]._index];
}
}
}
Check this jsFiddle for a full example.
Getting the name of the clicked item, the current dataset, or the item in the current dataset is straightforward:
onClick: (e, i) => {
const bubbleSelected = i[0];
console.log(this.widget.data.bubblesData[bubbleSelected.datasetIndex].tooltipData[bubbleSelected.index]);
}
Parameter i contains an array of clicked elements which contains the following:
With these image data, knowing which dataset you have selected and which element of the dataset you have clicked, you can, from an array of data, obtain the data, names or whatever you want from the current dataset of the current position.
In my case I had in bubblesData a list of datasets (datasetIndex) and in each dataset an object called tooltipData with a list of data for each element of the dataset (index).
If you want to see how to also modify the tooltip to show it like this visit this link: Chart JS Show HTML in Tooltip
Documentation:
https://www.chartjs.org/docs/latest/configuration/interactions.html
https://stackoverflow.com/a/44160605/11770490
Related
For a radar chart, I'm trying to toggle (with a switch button) or slide (with a slider) between different sets of data to display. (I'll include the button here first, but I'm eventually try to extend that to a slider later.). 1. Initialize button and keep track of user toggle. 2. Pick which data set to use. both generateRadarData and generateRadarData2 work well on their own if I use chart.data = either one.
The below is the edited attempt:
var chartSwitchButton = chart.chartContainer.createChild(am4core.SwitchButton);
chartSwitchButton.events.on("toggle", function () {chart.data = whichData();})
function whichData() {
var dataToUse = chart.data;
if (chartSwitchButton.isActive) {dataToUse = generateRadarData();
} else {
dataToUse = generateRadarData2();}
return dataToUse};
chart.data = whichData();
I have tried commenting out the last line (since ideally it would have been updated via the event listener), but then no data displays.
Here is a more recent attempt to update the data using invalidateRawData:
chartSwitchButton.events.on("toggle", function (event) {
chart.data = whichData();
chart.invalidateRawData();
});
function whichData() {
var data = [];
if (chartSwitchButton.isActive) {
chart.data = generateRadarData();
} else {
chart.data = generateRadarData2();
}
chart.invalidateRawData(); //also tried invalidateData. tried this command in event listener as well as here.
data.push(chart.data); //attempt to replace/update raw data
//console.log(chart.data);
return chart.data; //this return line is necessary to output data but theoretically shouldn't be.
}
and have tried implementing the if-else w/in the event listener without having to use whichData as a separate function like so:
chartSwitchButton.events.on("toggle", function () {if (chartSwitchButton.isActive) {
chart.data = generateRadarData();
} else {
chart.data = generateRadarData2();
}
chart.invalidateRawData();})
I'm still unable to switch between the two sets of data with user interaction. In fact, if I don't return something for chart.data or declare what chart.data is supposed to be outside of the events.on or whichData(), then none of my data prints at all.
If anybody has suggestions on how to do this with a button (or a slider would be even better) that would be awesome.
Basically, after setting up the button, I tried to (a) keep track of the state of the button (as determined by user), (b) determine which state the button is in, and (c) pick a data set to use based off of that info. This version is edited from a previous attempt as per initial comments below. Thanks for your help.
Documentation is "toggled" not "toggle" in the events listener. The event does not recognize "toggle" but needed "toggled". https://www.amcharts.com/docs/v4/reference/switchbutton/#toggled_event
I implemented this example from dc.js examples here.
Also, I added .brushOn(true) option to my chart. After my brushing, I need to get selected information.
My filter function:
.on('filtered', function(chart){
console.log(runDimension.top(Infinity));
})
Unfortunately, I can't call onFiltered event with brushing.
I added one more listener for brushend event and get here empty object:
var b = chart.brush();
b.on('brushend.custom', function() {
console.log(runDimension.top(Infinity));
});
How can I get selected information with brushOn(true)?
P.S I use this branch of dc.js with version 2.1.0-dev, because I need grouped charts.
drawBarChart = function (data) {
//few statements goes here which sets options which are being passed to chartDraw i.e. t.options.chart.options
gChart = new google.visualization.BarChart(chartingPlace);
//setTimeout(function () {
// t.options.chart.options.height = ((t.chart.size.height) - 40) + "px";
////console.log(JSON.stringify(t.options.chart.options));
//google.visualization.events.addListener(gChart, 'ready', function () {
// grab a few details before redirecting
google.visualization.events.addListener(gChart, 'select', function () {
var selectedItem = gChart.getSelection()[0];
console.log(gChart.getSelection());
if (selectedItem) {
var topping = data.getValue(selectedItem.row, 0);
alert('The user selected ' + topping);
}
// });
});
gChart.draw(data, t.options.chart.options);
}
My app having a number of charts displaying for different scenarios. My requirement is, click on a bar from google bar chart and open a new tab associated with the name of the bar. For this purpose, I tried using direct 'select' event on bar chart as follows:
google.visualization.events.addListener(gChart, 'select', function () {
var selectedItem = gChart.getSelection()[0];
console.log(gChart.getSelection());
if (selectedItem) {
var topping = data.getValue(selectedItem.row, 0);
alert('The user selected ' + topping);
}
});
But I could not get, this returned empty array for gChart.getSelection(), so I tried the code with 'ready' event mentioned in as first code above.
It works, but not output is not consistent. sometimes it gives empty array and sometimes with selected object.
I am still not able to find why it is showing this kind of behavior
More info: my application is having different tabs, showing number of bar,line,area,combo charts on it. getSelection() works well with line chart but not able to get the consistent output with bars.
Any help is appreciable.
Please do not mark it as duplicate, as I have gone through other similar questions but they does not answer my issue, I do not have that privilege so I could not comment in replies asking for more clarification.
Similar question here : google visualization-Click event on barchart isStacked: true
Please help!
Thank you in advance!
Updates :
I could not get any answer or any response from here.
This is really very disappointing.
Solution:
This is how i worked out the solution for this problem :
The getSelection could not work for me so i tried click event on bar text. Through the click event i could get the text on bar and i linked it to opn new tab.
If anyone need solution in code, please let me know.
Thank you.
Please go through below code snippet, I corrected or you can say organised the code in different way. If you need further explanation please let me know.
google.visualization.events.addListener(googleChartObj, 'select', function () {
var selectedBar = googleChartObj.getSelection();
////console.log(selectedBar);
data.getRowLabel(selectedBar[0].row);
/// for Bar charts, normally row-parameters are used
/// manipulate on 'data' which refers to data-table to get desired results
});
I'm setting up a way to be able to enlarge small-ish charts on my webpage by un-hiding a page 'overlay' div and creating a secondary, larger chart inside it with the same data as the chart which was clicked on.
function DrawSmallChart() {
chart_data = [1, 2, 3, 4, 5];
LargeChartOptions = {
series: [{
name: 'Data',
data: chart_data
}],
};
SmallChartOptions = {
series: [{
name: 'Data',
data: chart_data
}],
events: {
click = function (e) { DrawLargeChart(LargeChartOptions); }
}
};
$('#smallchart-div-container').highcharts(SmallChartOptions);
}
function DrawLargeChart(options) {
chart_container_div = document.getElementById("graph-div-id");
chart_container_div.style.display = ""
$('#graph-div-id').off();
$("#graph-overlay-graph").highcharts('StockChart', options);
}
I have another function that hides this div when I click a button.
The first time I click the small graph when the page loads, the big graph shows up fine with all the data. The second time I click it, the graph shows but with no data.
I've used the debugger to flick through what is happening and I've found exactly what the problem is, but I can't figure out how to solve it.
The first time I click the graph, the DrawLargeChart function is called with options.series = <Array containing my series object with chart_data>. The second time, DrawLargeChart is called with options.series = null.
When I refresh the page it is the same - first click works, subsequent clicks don't. I suspect it has something to do with the chart_data variable...
Any help would be greatly appreciated
EDIT 1:
After some more debugging, it is clear that the options object which is passed to DrawLargeChart() is not the same in the first click versus subsequent clicks. There is nothing in my code which is changing the LargeChartOptions structure
EDIT 2:
I figured out that this is a pass by value / pass by reference error. LargeChartOptions is being passed in by reference which no longer exists after the first click. Is there a way to pass it by value? I'd rather not have to type out the LargeChartOptions (much bigger than I've typed up here) into the function parameter in case I change anything in future
EDIT 3 // I've figured it out:
I figured out what the problem is. The $(target).highcharts(options) function actually modifies the options object and sets options.series = null
The solution
I modified the DrawLargeChart function to create a local copy of options by using options_buffer = $.extend(true,{},options);
function DrawLargeChart(options) {
chart_container_div = document.getElementById("graph-div-id");
options_buffer = $(target).highcharts(options);
chart_container_div.style.display = ""
$('#graph-div-id').off();
$("#graph-overlay-graph").highcharts('StockChart', options_buffer);
}
By creating options_buffer, the highcharts function cannot modify LargeChartOptions (because options is just a reference to that variable - yay Javascript)
I found the answer (in original post but copied here):
I modified the DrawLargeChart function to create a local copy of options by using options_buffer = $.extend(true,{},options);
function DrawLargeChart(options) {
chart_container_div = document.getElementById("graph-div-id");
options_buffer = $(target).highcharts(options);
chart_container_div.style.display = ""
$('#graph-div-id').off();
$("#graph-overlay-graph").highcharts('StockChart', options_buffer);
}
By creating options_buffer, the highcharts function cannot modify LargeChartOptions (because options is just a reference to that variable - yay Javascript)
I have a loop that goes through data and creates several google charts. I have added a selectHandler that does something when a bar of a chart is clicked. I have no problem getting the bar selected once I have the chart, but I do not know how to tell the handler which chart was clicked.
Here is the code:
inside the drawChart() which is in a loop:
chart[chart_index] = new google.visualization.BarChart(document.getElementById('chart_div<%= qcount %>'));
chart[chart_index].draw(data, {width: 450, height: 300, title: 'title'});
google.visualization.events.addListener(chart[chart_index], 'select', selectHandler);
chart_index = chart_index+1;
and the selectHandler works like this:
function selectHandler(e) {
var bar_index = chart[HERE_GOES_THE_CHART_INDEX].getSelection()[0].row;
}
Thanks
There's no way to get the specific chart from the event handler, so you have to use another method of passing the chart to the handler. Here's one way you can do it:
function selectHandler(myChart) {
// test to see if anything was selected before you get the index
// otherwise you will get errors when the selection contains 0 elements
var selection = myChart.getSelection();
if (selection.length) {
var bar_index = selection[0].row;
// do something with bar_index
// you should also test bar_index, as the user could have clicked a legend item, which would give a null value for row
}
}
chart[chart_index] = new google.visualization.BarChart(document.getElementById('chart_div<%= qcount %>'));
// generally speaking, you should add event handlers before drawing the chart
google.visualization.events.addListener(chart[chart_index], 'select', (function (x) {
return function () {
selectHandler(chart[x]);
}
})(chart_index));
chart[chart_index].draw(data, {width: 450, height: 300, title: 'title'});
chart_index = chart_index+1;
This closure passes chart_index to the inside of the closure, and assigns it to x:
(function (x) {
return function () {
selectHandler(chart[x]);
}
})(chart_index)
so the value of x is locked inside the closure, even when you increment chart_index later. The closure returns a function which becomes the event handler. This function calls selectHandler, passing in chart[x] when someone clicks on a chart element. If you are iterating over this in a loop, the value of x will be unique inside each closure, giving you the ability to reference specific charts in your selectHandler function.
After reading google visualization event handling...
SELECT Event:
The select event does not pass any properties or objects to the
handler (your function handler should not expect any parameters to be
passed to it).
So although you can use getSelection(), you need another function to determine which chart is has been acted upon. Enters another event handler:
// google.visualization.table exposes a 'page' event.
google.visualization.events.addListener(table, 'page', myPageEventHandler);
...
function myPageEventHandler(e) {
alert('The user is navigating to page ' + e['page']);
}
You need an event handler that has event object passed in param so you can determine which chart is being evented. Once you have the current chart, you can use getSelection() to see the current selection in that chart.
Function binding to the rescue.
google.visualization.events.addListener(chart[chart_index], 'select', selectHandler.bind(chart[chart_index]));
Your handler will receive the chart always as the first argument.
If you're targeting older browsers, here's a great binding polyfill by Mozilla crew:
MDN Function.prototype.bind()