Highcharts - hide legend if there is no value - highcharts

I am trying to hide the legend for values that are zero. How can this be done?
[enter link description here][1]
I have tried using
function(chart){
var flag = false;
$.each(chart.series,function(i,serie){
$.each(serie.data,function(j,data){
if(data.y === 0){
flag=true;
}
});
if(flag)
serie.legendGroup.destroy();
});

You can iterate by each serie / points, check if is 0 value and remove legend group in SVG.
http://jsfiddle.net/hz2PN/
var flag = false;
$.each(chart.series,function(i,serie){
$.each(serie.data,function(j,data){
if(data.y === 0){
flag=true;
}
});
if(flag)
serie.legendGroup.destroy();
});

Related

How to disable and enable legend items in highcharts

Trying to disable legend items in highcharts, But not able to working.
Example :
If I click Movie1 or Movie2 legend, only Movie1 and Movie2 should be enabled others Game1 and Game2 should be disabled.
If I click Game1 or Game2 legend, only Game1 and Game2 should be enabled others Movie1 and Movie2 should be disabled.
How to do it? How to use this.visible=false; for legend items?
series: {
events: {
legendItemClick: function(e) { console.log(this.name);
const series = this;
const chart = series.chart;
const hasChangedOpacity = series.hasChangedOpacity;
if(this.name == 'Movie1' || this.name == 'Movie2'){
this.name.Movie1 = true; //enabled
this.name.Movie2 = true; //enabled
this.name.Game1 = false; //disabled
this.name.Game2 = false; //disabled
}
if(this.name == 'Game1' || this.name == 'Game2'){
this.name.Movie1 = false; //disabled
this.name.Movie2 = false; //disabled
this.name.Game1 = true; //enabled
this.name.Game2 = true; //enabled
}
}
}
},
https://www.highcharts.com/demo/column-basic
Demo: https://jsfiddle.net/gd3mz8pf/9/
First of all, you can use linkedTo series property to use one legend item for multiple series.
If you want to have separate legend items, you need to trigger the same operations for all of them. For example:
series: {
events: {
legendItemClick: function(e) {
const series = this;
const chart = series.chart;
const allSeries = chart.series;
const hasChangedOpacity = series.hasChangedOpacity;
const handleItemClick = (s) => {
s.group.attr({
opacity: hasChangedOpacity ? 1 : 0.2
});
chart.legend.colorizeItem(s, hasChangedOpacity);
s.hasChangedOpacity = !hasChangedOpacity;
};
if ([0, 1].includes(series.index)) {
handleItemClick(allSeries[0]);
handleItemClick(allSeries[1]);
} else {
handleItemClick(allSeries[2]);
handleItemClick(allSeries[3]);
}
// prevent default behaviour
return false;
}
}
}
Live demo: https://jsfiddle.net/BlackLabel/vkt6uf5b/
API Reference: https://api.highcharts.com/highcharts/series.column.linkedTo

I have synchronized charts with synch’d zooming. I would like to zoomout in steps (not just back to 1:1). Does anyone have a working example of this?

I am currently synchronizing my charts as below:
$('#container').bind('mousemove touchmove', function (e) {
var chart,
point,
points,
i;
for (i = 0; i < Highcharts.charts.length; i++) {
chart = Highcharts.charts[i];
e = chart.pointer.normalize(e); // Find coordinates within the chart
points = [];
Highcharts.each(chart.series, function(series){
point = series.searchPoint(e, true);
if (point) {
points.push(point);
point.onMouseOver(); // Show the hover marker
}
});
if (points.length > 0) {
chart.tooltip.refresh(points); // Show the tooltip
chart.xAxis[0].drawCrosshair(e, points[0]); // Show the crosshair
}
}
});
// ==================================================================================
// * Override the reset function, we don't need to hide the tooltips and crosshairs.
// * Synchronize zooming through the setExtremes event handler.
Highcharts.Pointer.prototype.reset = function () {};
// ====================================================================
function syncExtremes(e) {
var thisChart = this.chart;
if (e.trigger !== 'syncExtremes') { // Prevent feedback loop
Highcharts.each(Highcharts.charts, function (chart) {
if (chart !== thisChart) {
if (chart.xAxis[0].setExtremes) { // It is null while updating
chart.xAxis[0].setExtremes(e.min, e.max, undefined, false, { trigger: 'syncExtremes' });
}
}
});
}
}
You can calculate intermediate extremes and set them by setExtremes method, for example:
document.getElementById('zoomOut').addEventListener('click', function() {
var chart = Highcharts.charts[0],
yAxis = chart.yAxis[0],
xAxis = chart.xAxis[0],
yDistance = (yAxis.max - yAxis.min) / 2,
xDistance = (xAxis.max - xAxis.min) / 2;
yAxis.setExtremes(yAxis.min - yDistance, yAxis.max + yDistance);
xAxis.setExtremes(xAxis.min - xDistance, xAxis.max + xDistance);
});
Live demo: http://jsfiddle.net/BlackLabel/9vxgpn4z/
API Reference: https://api.highcharts.com/class-reference/Highcharts.Axis#setExtremes

Synchronized charts example with Highstock crashes with "Cannot read property 'category' of undefined"

I want the functionality of the "Synchronized charts" example, but with Highstock. But when trying to accomplish this, I get "highstock.src.js:9991 Uncaught TypeError: Cannot read property 'category' of undefined"
This also holds directly for the example: http://www.highcharts.com/demo/synchronized-charts doesn't work when converted to Highstock: http://jsfiddle.net/9gq47g0w/
(Since StackOverflow demands me to post some code along with the fiddle, here's from Highstock, noting the point where it crashes with **):
/**
* Refresh the tooltip's text and position.
* #param {Object} point
*/
refresh: function (point, mouseEvent) {
...
// shared tooltip, array is sent over
if (shared && !(point.series && point.series.noSharedTooltip)) {
...
textConfig = {
x: ** point[0].category, ** <- here!
y: point[0].y
};
...
}
...
},
Here you can find an example of synchronized highstock charts:
http://jsfiddle.net/vw77cooj/20/
This example is using custom functions for synchronizing extremes and tooltips on charts:
function syncExtremes(e) {
var thisChart = this.chart;
if (e.trigger !== 'syncExtremes') { // Prevent feedback loop
Highcharts.each(Highcharts.charts, function(chart) {
if (chart !== thisChart) {
if (chart.xAxis[0].setExtremes) { // It is null while updating
chart.xAxis[0].setExtremes(e.min, e.max, undefined, false, {
trigger: 'syncExtremes'
});
}
}
});
}
}
$('#container').bind('mousemove touchmove touchstart', function(e) {
Highcharts.each(Highcharts.charts, function(chart) {
event = chart.pointer.normalize(e.originalEvent);
point = chart.series[0].searchPoint(event, true);
if (point) {
point.onMouseOver(); // Show the hover marker
chart.tooltip.refresh(point); // Show the tooltip
chart.xAxis[0].drawCrosshair(event, point); // Show the crosshair
}
});
});
In case of having multiple series on your chart you may change function responsible for synchronizing your tooltip:
function syncTooltip(container, p) {
var i = 0,
j = 0,
data,
series,
points = [];
for (; i < chartSummary.length; i++) {
if (container.id != chartSummary[i].container.id) {
series = chartSummary[i].series
Highcharts.each(series, function(s) {
Highcharts.each(s.data, function(point) {
if (point.x === p && point.series.yAxis.options.index !== 1) {
points.push(point)
}
})
});
chartSummary[i].tooltip.refresh(points);
}
};
}
http://jsfiddle.net/ZArZM/316/
For a nice working example on Highstock, please follow this example with MouseOver and MouseOut:
var onMouseOver = function onMouseOver() {
var x = this.x,
interactedChart = this.series.chart,
points = [],
charts = Highcharts.charts,
each = Highcharts.each;
each(charts, function(chart) {
if (chart !== interactedChart) {
each(chart.series, function(series) {
each(series.data, function(point) {
if (point.x === x && point.series.yAxis.options.index !== 1) {
points.push(point)
}
})
});
each(points, function(p) {
p.setState('hover');
});
chart.tooltip.refresh(points);
}
});
}
http://jsfiddle.net/ska1r5wq/
You can avoid many tooltip issues from examples provided on the web.
Source : https://github.com/highcharts/highcharts/issues/6595

Crispy GridLineDashStyle

The gridlines when set to "ShortDot", or any Dots, are always two pixels tall in SVG, and research says it can be fixed via
a) transform(0.5,0.5) -- moves it half a pixel so drawing is in one pixel,
or
b) add style='shape-rendering:crispEdges' to the element
See demo here:
http://jsfiddle.net/aerialflyer/o2d9w6up/
Here's the SVGElement prototype from Highcharts.js
SVGElement.prototype = {
dashstyleSetter: function (value) {
var i;
value = value && value.toLowerCase();
if (value) {
value = value
.replace('shortdashdotdot', '3,1,1,1,1,1,')
.replace('shortdashdot', '3,1,1,1')
.replace('shortdot', '1,1,')
.replace('shortdash', '3,1,')
.replace('longdash', '8,3,')
.replace(/dot/g, '1,3,')
.replace('dash', '4,3,')
.replace(/,$/, '')
.split(','); // ending comma
i = value.length;
while (i--) {
value[i] = pInt(value[i]) * this['stroke-width'];
}
value = value.join(',')
.replace('NaN', 'none'); // #3226
this.element.setAttribute('stroke-dasharray', value);
}
}
}
How can this be updated to include either the transform, or the 'style' (preferred)??
i.e.
Add
this.element.setAttribute('style', 'shape-rendering:crispEdges');
Can the SVGElement prototype be updated (fails so far)
// Make grid lines crispt to prevent anti-alias
SVGElement.prototype['dashstyleSetter'] = SVGElement.prototype.dashstyleSetter = function (value) {
var i;
value = value && value.toLowerCase();
if (value) {
value = value
.replace('shortdashdotdot', '3,1,1,1,1,1,')
.replace('shortdashdot', '3,1,1,1')
.replace('shortdot', '1,1,')
.replace('shortdash', '3,1,')
.replace('longdash', '8,3,')
.replace(/dot/g, '1,3,')
.replace('dash', '4,3,')
.replace(/,$/, '')
.split(','); // ending comma
i = value.length;
while (i--) {
value[i] = pInt(value[i]) * this['stroke-width'];
}
value = value.join(',')
.replace('NaN', 'none'); // #3226
this.element.setAttribute('stroke-dasharray', value);
this.element.setAttribute('style', 'shape-rendering:crispEdges');
}
};
Highcharts Demo:
http://jsfiddle.net/aerialflyer/yj1s5xps/
See how dot is just a long gray line
It is possible to extend Highcharts and set shape-rendering to crispEdges (because shape-rendering is attribute set directly, not in style - MDN: https://developer.mozilla.org/en-US/docs/Web/SVG/Attribute/shape-rendering) in dashstyleSetter of SVGElement.
Wrapper:
(function (H) {
H.wrap(H.SVGElement.prototype, 'dashstyleSetter', function (proceed) {
// Run original proceed method
proceed.apply(this, [].slice.call(arguments, 1));
if(arguments[1]) {
this.element.setAttribute('shape-rendering', 'crispEdges');
}
});
}(Highcharts));
JSFiddle example: http://jsfiddle.net/yurn5oz5/
Docs reference for extending Highcharts

Add hide all series to line chart

I have a line chart with a number of series elements on it.
The chart does allow me to click each series in the legend to hide it but I would like to add an extra item that when clicked hides all of the series lines from the chart.
Can someone explain how I would achieve this please?
Thanks
add a button or something you like. follow the example fiddle from highcharts own.
http://jsfiddle.net/gh/get/jquery/1.7.2/highslide-software/highcharts.com/tree/master/samples/highcharts/members/series-hide/
var chart = $('#container').highcharts(),
$button = $('#button');
$button.click(function() {
var series = chart.series[0];
if (series.visible) {
series.hide();
$button.html('Show series');
} else {
series.show();
$button.html('Hide series');
}
}
In case when you hide all of series, you can add extra serie by addSeries() function.
You could try this:
$('.selectDeselect input').click(function() {
if (chart.series[0].visible) {
for (var i = 0; i < chart.series.length; i++) {
chart.series[i].hide();
}
} else {
for (var i = 0; i < chart.series.length; i++) {
chart.series[i].show();
}
}
})

Resources