Highcharts on click show larger graph - javascript

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)

Related

amCharts 4 chart not updating with switchbutton, slider

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

How to catch an onClick event on bubble chart?

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

chart.getSelection() does not work properly with google bar 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
});

How to properly detect pages in DataTable?

I am using DataTables.
What I am trying to do is: by using one of the columns values, get page number, where this value is located.
I have tried this: jumpToData()
BUT this didn't work out. The reason is that
var pos = this.column(column, { order: 'current' }).data().indexOf(data);
in jQuery.fn.dataTable.Api.register('page.jumpToData()' returns value >=0 ONLY if I was placed on page where value was.
For example, I want to detect page where needed value is, but I am staying on another page, so to detect value on... page 3, I need to go to this page and only then I can detect it, which makes no sence at all.
What I need to do, is: by staying on pirst page, using value from another pages, detect those pages numbers and then navigate to them:
$('#Grid_grid').DataTable().page(PageNumber).draw(false);
How can I accomplish that?
EDIT:
Got some idea (several changes in jumpToData()):
jQuery.fn.dataTable.Api.register('page.jumpToData()', function (data, column) {
for (var i = 0; i < this.page.info().pages; i++) {
var test = this.page(i).column(column, { order: 'current' }).data().indexOf(data);
if (test >= 0) {
this.page(i).draw(false);
return this;
}
}
return this;
});
(EDIT 2: idea didn't paid off, no difference)
BUT now I got second issue:
None methods of datatable works in .cshtml page.
For example I need to get overall page count. I doing this:
$('#Grid_grid').DataTable().page.info().pages;
and this return me 0;
Meanwhile, putting it in to console (Chrome F12) works fine (returns 5). Whats the matter?
EDIT 3:
Came up with this:
function LoadPage(value) {
var table = $('#Grid_grid').DataTable();
var pageNumber = table.search(value).page();
table.page(pageNumber).draw(false);
}
Looks promising BUT, I still cant validate it because in console DataTable methods are working, but in .cshtml no. (search() or page() returns nothing).
EDIT 4:
Moved issue to another question
CAUSE
Your new API method page.jumpToData() tries to query all pages data because second argument selector-modifier in column() API method has property page: 'all' by default. As written it will always stay on first page.
SOLUTION
There is original page.jumpToData() plug-in posted by Allan Jardine, creator of DataTables. It works as intended and can be used instead of your modification to avoid unnecessary iterations.
$.fn.dataTable.Api.register('page.jumpToData()', function (data, column) {
var pos = this.column(column, {
order: 'current'
}).data().indexOf(data);
if (pos >= 0) {
var page = Math.floor(pos / this.page.info().length);
this.page(page).draw(false);
}
return this;
});
DEMO
See this jsFiddle for code and demonstration.
NOTES
In the demo above I added console.log("Number of pages", table.page.info().pages); just to demonstrate that API method works. However they may work because I have HTML-sourced data.
If you have Ajax-sourced data, you need to query number of pages only when data has been loaded. Use initComplete option to define a callback function that will be called when your table has fully been initialised, data loaded and drawn.

jquery extension return $.each confusion

I am trying to use a jQuery extension I came across (handsontable). I am having no problem creating the table
var spreadsheet = $("#dataTable").handsontable({
rows: 3,
cols: 15,
minSpareRows: 2
});
However after I create the table I want to call various helper functions I see declared in the javascript for the Handsontable object. The problem is the extension seems to return this.each(function() { ... }); and I don't understand how I can access the underlaying Handsontable object from this. The js for the extension can be found here and I put a small demo together on the following link
http://jsfiddle.net/7JTG2/7/
as you can see I would like get the data of one of the cells when I click a button.
The relevant code is in the end:
$.fn.handsontable = function (action, options) {
if (typeof action !== 'string') { //init
options = action;
return this.each(function () {
if($(this).data("handsontable")) {
instance = $(this).data("handsontable");
...
} else {
...
instance = new Handsontable($(this), currentSettings);
$(this).data("handsontable", instance);
}
});
}
}
That means, the code sets the Handsontable instances as a data attribute to the elements (and returns the selected set to be chainable). Having one element, you can easily extract it with instance = $el.data("handsontable"). If you have a set of elements, you will need to loop over it - e.g. with each().
Looks like you could just use the onChange method of the plugin to capture data every time it is entered automatically. No need for a button. A simple example to add to your code above.
onChange: function(data) {
$("#data").append(JSON.stringify(data));
}

Categories