Highcharts Stacked Column chart change legendItemClick function - javascript

On legendItemClick, how do I prevent subtraction of legend item value from total and instead add the value to another legend item.
E.g. I would like the 'Other Fruit' series to contain all switched off fruit series (the same with 'Other Veg' series).
Here is the Fiddle
$(function () {
$('#container').highcharts({
chart: {
type: 'column'
},
title: {
text: 'Stacked column chart'
},
xAxis: {
categories: ['Then', 'Now']
},
yAxis: {
min: 0,
title: {
text: 'Total consumption'
},
stackLabels: {
enabled: true,
style: {
fontWeight: 'bold',
color: (Highcharts.theme && Highcharts.theme.textColor) || 'gray'
}
}
},
legend: {
align: 'right',
x: -30,
verticalAlign: 'top',
y: 25,
floating: true,
backgroundColor: (Highcharts.theme && Highcharts.theme.background2) || 'white',
borderColor: '#CCC',
borderWidth: 1,
shadow: false
},
tooltip: {
headerFormat: '<b>{point.x}</b><br/>',
pointFormat: '{series.name}: {point.y}<br/>Total: {point.stackTotal}'
},
plotOptions: {
series: {
events: {
legendItemClick: function () {
//if fruit/veg is clicked then add value to other fruit/veg and keep the total unchanged
// return false;
}
}
},
column: {
stacking: 'normal',
dataLabels: {
enabled: true,
formatter:function() {
return this.series.name+' '+this.point.y;
},
color: (Highcharts.theme && Highcharts.theme.dataLabelsColor) || 'white',
style: {
textShadow: '0 0 3px black'
}
}
}
},
series: [{
name: 'Other Fruit',
data: [8, 13]
},{
name: 'Other Veg',
data: [16, 10]
},{
name: 'Tomatoes',
data: [3, 7]
},{
name: 'Cucumbers',
data: [5, 4]
},{
name: 'Apples',
data: [5, 3]
}, {
name: 'Bananas',
data: [3, 6]
}, {
name: 'Oranges',
data: [3, 4]
}]
});
});

Things we need to do
Series should be categorized as fruit and vegetables, so that we know which others series("Other Fruit" or "Other Veg") to add/subtract value from.
When the legend item is clicked, check if it's a fruit or a veggie and add the value to others.
When clicked again, subtract the values from others.
We should not be able to hide the others series.
series: [{
name: 'Other Fruit',
data: [{y:8}, {y:13}],
},{
name: 'Other Veg',
data: [{y:16}, {y:10}]
},{
name: 'Tomatoes',
data: [{y:3}, {y:7}],
fruit: false
},{
name: 'Cucumbers',
data: [{y:5}, {y:4}],
fruit: false
},{
name: 'Apples',
data: [{y:5}, {y:3}],
fruit: true
},{
name: 'Bananas',
data: [{y:3}, {y:6}],
fruit: true
},{
name: 'Oranges',
data: [{y:3}, {y:4}],
fruit: true
}]
Added a property "fruit" to all series except "Other Fruit" and "Other Veg".
legendItemClick: function () {
var isFruit = this.options.fruit;
if(isFruit == undefined){ //property undefined for "Other fruit" and "Other Veg"
return false; //returning false prevents hiding the series
}
var chart = this.chart;
var othersSeries;
if(isFruit){
othersSeries = chart.series[0]; //if it's a fruit, get "Other Fruit" series
}
else{
othersSeries = chart.series[1]; //else get "Other Veg" series
}
updateOthersData(this, othersSeries);
}
function updateOthersData(currentSeries, othersSeries){
var othersData = othersSeries.options.data;
if(currentSeries.visible){ //add values only when the series is already visible and is to be hidden
othersData[0].y += currentSeries.options.data[0].y;
othersData[1].y += currentSeries.options.data[1].y;
}
else{ //subtract values only when data is already hidden and is to be shown
othersData[0].y -= currentSeries.options.data[0].y;
othersData[1].y -= currentSeries.options.data[1].y;
}
othersSeries.update({data:othersData}); //update the series
}
Here is the fiddle.

Related

how to add tooltip on hover over the stacked Labels in highcarts

is there any way to add tooltip to the stackedLabels in highcharts, like in the below example:
I have male, female as my stack names and I am dispalying them at the bottom of the chart..however in case they are long names, I'm adding ellipsis, in such case is there a way to see the entire name on hover inside tooltip?
fiddle:
http://jsfiddle.net/rq8m7e0v/
code:
Highcharts.chart('container', {
chart: {
type: 'column'
},
title: {
text: 'Stacked column chart'
},
xAxis: {
categories: ['Apples', 'Oranges', 'Pears', 'Grapes', 'Bananas', "getete"]
},
yAxis: {
min: 0,
title: {
text: 'Total fruit consumption'
},
stackLabels: {
verticalAlign: 'bottom',
y:90,
enabled: true,
formatter: function() {
return this.stack;
}
}
},
plotOptions: {
column: {
stacking: 'normal',
dataLabels: {
enabled: true
}
}
},
series: [{
name: 'John',
data: [53, 33, 43,63,7,83],
stack: 'male'
}, {
name: 'Joe',
data: [33, 43,43,63,73,8],
stack: 'female'
}, {
name: 'Jane',
data: [42, 54,43,62,74,84],
stack: 'male',
}, {
name: 'Janet',
data: [34, 40, 42,36,74,83],
stack: 'female',
}]
});
Highcharts doesn't have built-in tooltip for stack label, but still you can create your own tooltip for that. It's simple to add custom events to legendItem (mouseover and mouseout for example) and show that tooltip.
events: {
load: function() {
var stackLabels = this.yAxis[0].stacking.stackTotalGroup.element.children,
somePoint = this.series[0].points[0],
chart = this;
for (let i = 0; i < stackLabels.length; i++) {
stackLabels[i].addEventListener('mouseover', function() {
// show custom tooltip
});
}
}
}
Live demo: http://jsfiddle.net/BlackLabel/orqyLjct/
API: https://www.highcharts.com/docs/extending-highcharts/extending-highcharts

Render charts based on type with AngularJS components

I got a really strange problem with Highcharts in combination with Angularjs 1.6. I am using components to render graphs based on the chart type. This is a example of my json data:
"Widgets":[
{
"Id":1,
"description":"Test test",
"datasource":"Risk",
"charttype":"Bar",
"x":0,
"y":0,
"width":3,
"height":2
},
{
"Id":2,
"description":"test test 2",
"datasource":"KRI",
"charttype":"Area",
"x":3,
"y":0,
"width":3,
"height":2
},
{
"Id":3,
"description":"Some cool data",
"datasource":"KRI",
"charttype":"Heatmap",
"x":6,
"y":0,
"width":3,
"height":2
}
]
Based on Charttype I want to render the charts and I am using angular components for this. This is my angular component for a Bar chart:
angular.module("generalApp").component("chartType", {
template: "<div class=Bar></div>",
bindings: {
data: "=",
charttype: "="
},
controller: function () {
$('.Bar').highcharts({
chart: {
type: 'column'
},
title: {
text: 'Stacked column chart'
},
xAxis: {
categories: ['Apples', 'Oranges', 'Pears', 'Grapes', 'Bananas']
},
yAxis: {
min: 0,
title: {
text: 'Total fruit consumption'
},
stackLabels: {
enabled: true,
style: {
fontWeight: 'bold',
color: (Highcharts.theme && Highcharts.theme.textColor) || 'gray'
}
}
},
legend: {
align: 'right',
x: -30,
verticalAlign: 'top',
y: 25,
floating: true,
backgroundColor: (Highcharts.theme && Highcharts.theme.background2) || 'white',
borderColor: '#CCC',
borderWidth: 1,
shadow: false
},
tooltip: {
headerFormat: '<b>{point.x}</b><br/>',
pointFormat: '{series.name}: {point.y}<br/>Total: {point.stackTotal}'
},
plotOptions: {
column: {
stacking: 'normal',
dataLabels: {
enabled: true,
color: (Highcharts.theme && Highcharts.theme.dataLabelsColor) || 'white'
}
}
},
series: [{
name: 'John',
data: [5, 3, 4, 7, 2]
}, {
name: 'Jane',
data: [2, 2, 3, 2, 1]
}, {
name: 'Joe',
data: [3, 4, 4, 2, 5]
}]
})
}
});
And this is a component for my Area chart
angular.module("generalApp").component("chartType", {
template: "<div class=Area></div>",
bindings: {
data: "=",
charttype: "="
},
controller: function () {
$('.Area').highcharts({
chart: {
type: 'bar'
},
title: {
text: 'Stacked bar chart'
},
xAxis: {
categories: ['Apples', 'Oranges', 'Pears', 'Grapes', 'Bananas']
},
yAxis: {
min: 0,
title: {
text: 'Total fruit consumption'
}
},
legend: {
reversed: true
},
plotOptions: {
series: {
stacking: 'normal'
}
},
series: [{
name: 'John',
data: [5, 3, 4, 7, 2]
}, {
name: 'Jane',
data: [2, 2, 3, 2, 1]
}, {
name: 'Joe',
data: [3, 4, 4, 2, 5]
}]
});
}
});
On the HTML page I use the custom tag to use the component:
<chart-type data="w.datasource" charttype="w.charttype"></chart-type>
I want to bind the charttype on the widgets and based on that it must render a chart:
Condition
ng-repeat="w in dashboard.Widgets track by $index"
When I only use one chart it's working fine but when I use a more then component I get the following error in my console.
Can someone point me to the right direction?
Kind regards
It seems that the problem is that all of your components are registered using the name chartType.
They all should have a unique name, for instance: BarComponent and AreaComponent.
In your container template you can include all of the chart type components. And with a control flow directive you can specify what component should be displayed to the user. For example:
<div ng-switch="currentComponent">
<area-component ng-switch-when="area"></area-component>
<bar-component ng-switch-when="bar"></bar-component>
<div ng-switch-default>Please select a chart type</div>
</div>

highchart stacked column total data per categories

I want to get the total data per categories. The point.stackTotal only gives the total of the active data.
From the code example I pasted, I would like to know the total consumption per fruit. So even if I clicked Joe's name on the legend on upper right part (that makes all Joe's information on stacked chart inactive), I'd still know the total consumption of Apple (and any other fruits) of John, Jane, and Joe on mouseover each bar categories so apparently, what I am looking for is not the point.stackTotal.
$(function () {
Highcharts.chart('container', {
chart: {
type: 'column'
},
title: {
text: 'Stacked column chart'
},
xAxis: {
categories: ['Apples', 'Oranges', 'Pears', 'Grapes', 'Bananas']
},
yAxis: {
min: 0,
title: {
text: 'Total fruit consumption'
},
stackLabels: {
enabled: true,
style: {
fontWeight: 'bold',
color: (Highcharts.theme && Highcharts.theme.textColor) || 'gray'
}
}
},
legend: {
align: 'right',
x: -30,
verticalAlign: 'top',
y: 25,
floating: true,
backgroundColor: (Highcharts.theme && Highcharts.theme.background2) || 'white',
borderColor: '#CCC',
borderWidth: 1,
shadow: false
},
tooltip: {
headerFormat: '<b>{point.x}</b><br/>',
pointFormat: '{series.name}: {point.y}<br/>Total: {point.stackTotal}'
},
plotOptions: {
column: {
stacking: 'normal',
dataLabels: {
enabled: true,
color: (Highcharts.theme && Highcharts.theme.dataLabelsColor) || 'white'
}
}
},
series: [{
name: 'John',
data: [5, 3, 4, 7, 2]
}, {
name: 'Jane',
data: [2, 2, 3, 2, 1]
}, {
name: 'Joe',
data: [3, 4, 4, 2, 5]
}]
});
});
I think that you should be able to show the total value for all visible and hidden columns for your category using stackLabels.formatter function. You can get more information about stackLabels in Highcharts API:
http://api.highcharts.com/highcharts/yAxis.stackLabels.formatter
stackLabels: {
enabled: true,
style: {
fontWeight: 'bold',
color: (Highcharts.theme && Highcharts.theme.textColor) || 'gray'
},
formatter: function() {
var x = this.x,
value = 0;
series = this.axis.series;
Highcharts.each(series, function(s) {
value += s.userOptions.data[x];
});
return value;
}
}
Here you can see very simple example how you can achieve something similar to required chart:
http://jsfiddle.net/h8f30uwo/
Best,

Dynamic values above column + jQuery Highcharts

I'm working with a stacked column chart from jQuery HighCharts like this. (fiddle link)
$(function () {
$('#container').highcharts({
chart: {
type: 'column'
},
title: {
text: 'Stacked column chart'
},
xAxis: {
categories: ['Apples', 'Oranges', 'Pears', 'Grapes', 'Bananas']
},
yAxis: {
min: 0,
title: {
text: 'Total fruit consumption'
},
stackLabels: {
enabled: true,
style: {
fontWeight: 'bold',
color: (Highcharts.theme && Highcharts.theme.textColor) || 'gray'
}
}
},
legend: {
align: 'right',
x: -70,
verticalAlign: 'top',
y: 20,
floating: true,
backgroundColor: (Highcharts.theme && Highcharts.theme.legendBackgroundColorSolid) || 'white',
borderColor: '#CCC',
borderWidth: 1,
shadow: false
},
tooltip: {
formatter: function() {
return '<b>'+ this.x +'</b><br/>'+
this.series.name +': '+ this.y +'<br/>'+
'Total: '+ this.point.stackTotal;
}
},
plotOptions: {
column: {
stacking: 'normal',
dataLabels: {
enabled: true,
color: (Highcharts.theme && Highcharts.theme.dataLabelsColor) || 'white',
style: {
textShadow: '0 0 3px black, 0 0 3px black'
}
}
}
},
series: [{
name: 'John',
data: [null, null, 4, 7, 2]
}, {
name: 'Jane',
data: [null,null, 3, 2, 1]
}, {
name: 'Joe',
data: [3, 4, 4, 2, 5]
}]
});
});
As you can see there's the total number above each column of the total of the number. But I need something else. I want my first bar to be 100%. And then I need to calculate the percentage of the other 2 columns and place those numbers above the column. How can I make them dynamic?
What you can do here is extend the point properties and add in a new field that gets shown in the dataLabels. You would need to preprocess what these percentages would be of course. The following example assumes you have already calculated the percentage values:
plotOptions: {
series: {
dataLabels: {
enabled: true,
format: '{point.perc} %'
}
}
}
The point.perc is the point's perc property we made up and it contains the percentage values you calculated already.
In the data array you can have this format:
series: [{
data: [{y: 29.9, perc: 100}, {y:71., perc: 50}, {y:106.4, perc: 30}, {y:129.2, perc: 20}]
}]
Live demo here.

set different colors for each column in highcharts

I need to set different colors for each column in Highcharts graph dynamically. My Highcharts graph is:
options = {
chart: {
renderTo: 'chart',
type: 'column',
width: 450
},
title: {
text: 'A glance overview at your contest’s status'
},
xAxis: {
categories: ['Approved Photos', 'Pending Approval Photos',
'Votes', 'Entrants'],
labels: {
//rotation: -45,
style: {
font: 'normal 9px Verdana, sans-serif, arial'
}
}
},
yAxis: {
allowDecimals: false,
min: 0,
title: {
text: 'Amount'
}
},
legend: {
enabled: false
},
series: []
};
series = {
name: "Amount",
data: [],
dataLabels: {
enabled: true,
color: '#000000',
align: 'right',
x: -10,
y: 20,
formatter: function () {
return this.y;
},
style: {
font: 'normal 13px Verdana, sans-serif'
}
}
};
The data is set this way:
for (var i in Data) {
if (parseInt(Data[i]) != 0) {
series.data.push(parseInt(Data[i]));
} else {
series.data.push(null);
}
}
options.series.push(series);
chart = new Highcharts.Chart(options);
How can I dynamically set different colors for each data point in this loop?
Here is another solution with the latest version of Highcharts (currently 3.0).
Set the colorByPoint option to true and define the color sequence that you want.
options = {
chart: {...},
plotOptions: {
column: {
colorByPoint: true
}
},
colors: [
'#ff0000',
'#00ff00',
'#0000ff'
]
}
Here is an example based upon Highcharts Column with rotated labels demo
When you add the value to the series.data you can also set the color using the point options e.g
series.data.push({ y: parseInt(Data[i]), color: '#FF0000' });
For more details about the point options see https://api.highcharts.com/class-reference/Highcharts.Point#color
Try either of these approaches:
Approach 1:
Highcharts.setOptions({ colors: ['#3B97B2', '#67BC42', '#FF56DE', '#E6D605', '#BC36FE'] });
Approach 2:
var colors = ['#3B97B2', '#67BC42', '#FF56DE', '#E6D605', '#BC36FE', '#000'];
$('#bar_chart').highcharts({
chart: {
type: 'column'
},
title: {
text: ''
},
subtitle: {
text: ''
},
xAxis: {
type: 'category'
},
yAxis: {
title: {
text: ''
}
},
legend: {
enabled: false
},
plotOptions: {
series: {
borderWidth: 0,
dataLabels: {
enabled: false
}
}
},
series: [{
name: '',
colorByPoint: true,
data: [{
name: 'Blue',
y: 5.78,
color: colors[0]
}, {
name: 'Green',
y: 5.19,
color: colors[1]
}, {
name: 'Pink',
y: 32.11,
color: colors[2]
}, {
name: 'Yellow',
y: 10.04,
color: colors[3]
}, {
name: 'Purple',
y: 19.33,
color: colors[4]
}]
}]
});
i had colors from API response and 2 series. second series with dynamic colors.
following is sample to set dynamic colors while series mapping.
const response = [{
'id': 1,
'name': 'Mango',
'color': '#83d8b6',
'stock': 12.0,
'demand': 28,
},
{
id ': 2,
'name': 'Banana',
'color': '#d7e900',
'stock': 12.0,
'demand': 28,
}
];
let chartData: {
categories: [],
series: []
};
chartData.categories = response.map(x => x.name);
chartData.series.push({
name: 'Series 1',
type: 'column',
data: response.map(x => x.demand)
});
chartData.series.push({
name: 'Series 2',
type: 'column',
data: response.map(x => ({
y: x.stock,
color: x.color // set color here dynamically
}))
});
console.log('chartData: ', chartData);
you could also read more about Highcharts series Point and Marker

Categories

Resources