High chart on click event listening - highcharts

I am creating my high chart object from a json_encoded array passed in from a data id on the containing div.
$('div.filter_pie_chart').each(function( index ) {
$(this).highcharts($(this).data("params"));
});
I would like to listen for click events of a pie chart using the following notation. Is this possible?
$(document).on('click','.high_chart_point_object', function (event) {
return false;
});

I think this documentation link is what you need.
Here is a JsFiddle.
$(function () {
// create the chart
var mychart = $('#container').highcharts({
chart: {
events: {
click: function(event) {
alert ('x: '+ event.xAxis[0].value +', y: '+
event.yAxis[0].value);
}
}
},
xAxis: {
},
series: [{
data: [29.9, 71.5, 106.4, 129.2, 144.0, 176.0, 135.6, 148.5, 216.4, 194.1, 95.6, 54.4]
}]
});
});
And I think these lines should work too (not tested, but it is similar to your notation) :
$('.high_chart_point_object').highcharts({
chart: {
events: {
click: function(event) {
return false;
}
}
}
});
If you want to change options dynamically, here is the solution :
var options = mychart.options;
options.chart.events.click = function () {alert('do what you want')};
mychart = new Highcharts.Chart(options);
Here is another JsFiddle.

Yes, this should possible in three ways:
one is to use plotOpttions.pie.point.events.click ant there call function you need to. Reference.
another one is to Element.on() function from Highcharts after digging for DOM elements - it's the same as using $().on(), reference.
if you really need that $().on(), you can use is on point.element, sample for you: http://jsfiddle.net/UWZAe/
And code for third case:
chart: {
events: {
load: function() {
var chart = this,
pie = chart.series[0],
pieData = pie.data,
dLen = pieData.length;
for(var i = 0; i < dLen; i++){
var slice = pieData[i];
console.log(slice, $(slice.graphic));
}
}
}
}

Related

Make only one point draggable on highcharts

I would like to have a series of data points displayed on my chart but only a specific one that would be "displayed" and draggable. Is this possible ? I'm using Highcharts javascript
Thanks for the help
You can return false from drag and drop event callback functions to prevent dragging.
series: [{
dragDrop: {
draggableY: true
},
point: {
events: {
drag: function() {
if (this.color !== 'red') {
return false;
}
},
drop: function() {
if (this.color !== 'red') {
return false;
}
}
}
},
data: [0, 71.5, {
y: 106.4,
color: 'red'
}, ...
]
}]
Live demo: https://jsfiddle.net/BlackLabel/rx1s73va/
API Reference: https://api.highcharts.com/highcharts/series.line.point.events

Highcharts event handler after finishing redraw

I am trying to show the total of the Y axis as a subtitle for a HighStock chart.
This is initially accomplished by summing up the point.y value of all the series, inside the "load" event like so:
chart: {
events: {
load: function () {
var chart = this,
series = chart.series,
seriesSum = 0;
series.forEach(function (series) {
series.data.forEach(function (point) {
seriesSum += point.y
})
})
this.update({
subtitle: { text: 'TOTAL: ' + seriesSum }
});
},
}
}
Now I need to update the TOTAL amount after the chart has been redrawn after changing the timeframe using either the Navigator or the Range Selector. I know there is a "redraw" event, but that will end me up in an infinite loop. Which event should I be tack onto?
You can use the redraw event, and just not redraw within a pending redraw. For example:
chart: {
events: {
redraw: function () {
this.update({
subtitle: { text: 'TOTAL: ' + seriesSum }
}, false);
}
}
}
Note the false parameter to the Chart.update function to prevent further redrawing (infinite loop).
See this JSFiddle demonstration using Highcharts and the redraw event.
You can use update method with redraw flag in redraw event, but you must set right conditions to not to fall into an infinite loop:
var redrawEnabled = true;
var chart = Highcharts.chart('container', {
chart: {
zoomType: 'x',
events: {
redraw: function() {
if (redrawEnabled) {
var sum = 0;
redrawEnabled = false;
Highcharts.each(this.series[0].points, function(point) {
if (point.isInside) {
sum += point.y;
}
});
this.update({
subtitle: {
text: sum
}
});
redrawEnabled = true;
}
}
}
},
series: [{
data: [29.9, 71.5, 106.4, 129.2, 144.0, 176.0, 135.6, 148.5, 216.4, 194.1, 95.6, 54.4]
}]
});
Live demo: http://jsfiddle.net/BlackLabel/dewumkz6/

HighCharts - destroy before writing a new chart (to prevent memory leak)

from http://api.highcharts.com/highstock/Chart.destroy
destroy () - Removes the chart and purges memory. This method should be called before writing a new chart into the same container. It is called internally on window unload to prevent leaks.
Here is how I call destroy on button click
http://jsfiddle.net/ihtus/20Ld7hg8/
var hc_options = {
chart: {
renderTo: 'container'
},
series: [{
name: 'USD to EUR',
data: usdeur
}]
};
var chart=new Highcharts.Chart(hc_options);
$('#button').click(function () {
chart.destroy();
$(this).attr('disabled', true);
});
In my project I am redrawing the chart many times in setInterval (using updated data).
Here is the code with setInterval http://jsfiddle.net/ihtus/teg540zh/
function init_graph() {
var hc_options = {
chart: {
renderTo: 'container'
},
series: [{
name: 'USD to EUR',
data: usdeur
}]
};
var chart=new Highcharts.Chart(hc_options);
}
var sint = setInterval(function(){
init_graph();
}, 4000);
My question is: how can I destroy the chart before writing a new chart into the same container (as it's suggested in official documentation)?
Thanks
From discussion in comments:
It should be possible to use Highcharts.charts array and inside this array find specific chart (if exist) for destroy:
function init_graph() {
var hc_options = {
chart: {
renderTo: 'container'
},
series: [{
name: 'USD to EUR',
data: usdeur
}]
};
var chart=new Highcharts.Chart(hc_options);
}
var sint = setInterval(function(){
Highcharts.charts[0] && Highcharts.charts[0].destroy();
init_graph();
}, 4000);
Example: http://jsfiddle.net/teg540zh/1/

Put highchart on the very start of the graphic

I am using highcharts to make some graphics. There are 3 graphics inside the same highchart, but my problem is that the highchart start with some padding at the left, like this:
I want it to look like this: (Edited with photoshop)
Help please
That question has been asked several times (I don't remember link), but in general don't use categorized xAxis, but use standard linear with specific label formatter, for example: http://jsfiddle.net/3bQne/266/
var categories = ['01/02/2012','01/03/2012','01/04/2012','01/05/2012','01/06/2012','01/07/2012'];
var chart2 = new Highcharts.Chart({
chart: {
renderTo: 'container2'
},
xAxis: {
labels: {
formatter: function() {
return categories[this.value];
}
}
},
series: [{
data: [29.9, 71.5, 106.4, 129.2, 144.0, 176.0]
}]
});
Now you can play around with startOnTick and minPadding. For categorized axis this is not possible to change space distribution - it's always evenly divided between all points.

Highcharts Series - want to show/hide all EXCEPT selected series (reversal of default logic)

By default Highcharts allows you to click on a data series set to hide it / unhide it.
A much more useful approach would be to do the reverse logic - ie to show only the selected series and hide/unhide the non-selected.
Looking at the example here ( http://jsfiddle.net/t2MxW/14/ ), it is clear one can 'intercept' the the 'legendItemClick' event, I am just not sure how to implement the require logic
One can replace the below script to obtain 3 data sets.
DESIRED SCENARIO: to be able to click on 'apples' and show/hide 'pears' and 'oranges' for example.
================= PASTE START =======================================
var chart = new Highcharts.Chart({
chart: {
renderTo: 'container'
},
xAxis: {
categories: ['Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec']
},
plotOptions: {
series: {
events: {
legendItemClick: function(event) {
var visibility = this.visible ? 'visible' : 'hidden';
if (!confirm('The series is currently '+
visibility +'. Do you want to change that?')) {
return false;
}
}
}
}
},
series:[{name: 'apples',
data: [29.9, 71.5, 106.4, 129.2, 144.0, 176.0, 135.6, 148.5, 216.4, 194.1, 95.6, 54.4]},
{name:'pears',
data: [19.9, 81.5, 96.4, 119.2, 124.0, 166.0, 155.6, 138.5, 116.4, 144.1, 95.6, 54.4]},
{name:'oranges',
data: [119.9, 181.5, 46.4, 219.2, 24.0, 66.0, 255.6, 238.5, 16.4, 44.1, 95.6, 54.4]}
]
});
Every event in HighCharts contains this value which contains current element (series in this case). You can select all series using this.chart.series and handle them in any way you want. Try this function.
legendItemClick: function(event) {
if (!this.visible)
return false;
var seriesIndex = this.index;
var series = this.chart.series;
for (var i = 0; i < series.length; i++)
{
if (series[i].index != seriesIndex)
{
series[i].visible ?
series[i].hide() :
series[i].show();
}
}
return false;
}
fiddle: https://jsfiddle.net/t2MxW/21971/
I wanted to do something similar... I wanted to have it so that if you control-click (or cmd-click) a legend item, it would hide ALL OTHER items. (But leave normal clicks as their default behavior).
plotOptions: {
series: {
events: {
legendItemClick: function(e) {
// Upon cmd-click of a legend item, rather than toggling visibility, we want to hide all other items.
var hideAllOthers = e.browserEvent.metaKey;
if (hideAllOthers) {
var seriesIndex = this.index;
var series = this.chart.series;
for (var i = 0; i < series.length; i++) {
// rather than calling 'show()' and 'hide()' on the series', we use setVisible and then
// call chart.redraw --- this is significantly faster since it involves fewer chart redraws
if (series[i].index === seriesIndex) {
if (!series[i].visible) series[i].setVisible(true, false);
} else {
if (series[i].visible) series[i].setVisible(false, false);
}
}
this.chart.redraw();
return false;
}
}
}
}
}
Just sharing cause #igor's answer doesn't work on me, so I made adjustments, here's the fiddle (forked from the #igor's answer)
http://jsfiddle.net/index/Nkeep/
Forked index's answer and added functionality to have individual toggles for each series. http://jsfiddle.net/c4Zd8/1/
$.each(allSeries, function(index, series) {
if (selected == index) {
if (series.visible == true) {
series.hide();
}
else {
series.show();
}
}
});
If you want to keep the normal functionality but also be able to show/hide all then create a button or a link for a show_all()/hide_all() javascript method.
this method initializes a counter and starts the showing/hiding:
counter = 0;
setTimeout(process_hide, 1);
function process_hide()
{
your_chart.series[counter].hide();
counter+=1;
if (counter < read_chart.series.length) {
setTimeout(process_hide, 1);
}
}
The reason you do this instead of just doing $.each(your_chart, function(i,v){v.hide()}) is that it locks up the UI - using the timeout you'll actually see the series being hidden one by one - and if you want to modify something else - like a process meter, it'll actually work.
Forked because I wanted behavior to change. Originally when a user selected two series and then tried to unselect one ... the whole series would swap visibility. I check to see if all other series are "all else visibile" or "all else not visible" first before swapping the visibility for the series.
http://jsfiddle.net/nd0dcdmz/3/
legendItemClick: function(e) {
var seriesIndex = this.index;
var series = this.chart.series;
// test for if all other series besides one selected are visible or not visible
var allElseVisible = series.every(
s => (s.index == seriesIndex ? true : s.visible),
);
var allElseNotVisible = series.every(
s => (s.index == seriesIndex ? true : !s.visible),
);
// if everything else is deselected or selected ... swap visibility
// else swap the visibility of selected object.
if (allElseVisible || allElseNotVisible) {
series.map(s => {
if (s.index != seriesIndex) {
s.visible ? s.hide() : s.show();
}
});
} else {
return true;
}
return false; // overrides default behavior
},

Resources