Highcharts how to create legends based on the value of points - javascript

I know exactly how to enable legend in Highcharts, but the problem is how to create legends based on the value of the points from the same series since every legend is used to symbolize a series(a collection of points).
There's is a picture(chart type: waterfall) I draw in excel below illustrating what I want, you can see clearly that orange color legend stands for gaining, while blue one stands for loss, but how do I achieve this in Highcharts?
I've searched a lot but ended with disappointment, please help.

One way to do this is with a dummy series.
Create an extra series, with the name and color that you want, with an empty data array:
series: [{
name: 'Actual Series',
data: [...data, with points colored as needed...]
}, {
grouping: false,
name: 'Dummy Series',
color: 'chosen color',
data: []
}]
You'll also want to set grouping to false, so that the dummy series does not take up extra blank space on the plot.
Fiddle:
http://jsfiddle.net/jlbriggs/vjd3p4s0/
(also, the same thing using the Waterfall demo: http://jsfiddle.net/jlbriggs/7vtbzh53/ )
Another way to do this would be to create your own legend, outside of the chart.
Either way, you will lose the functionality of clicking the legend to show/hide the series of for the orange columns. You would have to build a more complex function to edit the data on legendItemClick if you that ability is important to you.

Solution for edited question. You can map your data to two series and set stacking to 'normal'.
const data = [10, 20, -10, 20, 10, -10];
const dataPositive = data.map(v => v >= 0 ? v : 0);
const dataNegative = data.map(v => v < 0 ? v : 0);
const options = {
chart: {
type: 'column'
},
series: [{
color: 'blue',
data: dataPositive,
stacking: 'normal'
}, {
color: 'orange',
data: dataNegative,
stacking: 'normal'
}]
}
const chart = Highcharts.chart('container', options);
Live example:
https://jsfiddle.net/j2o5bdgs/
[EDIT]
Solution for waterfall chart:
const data = [10, 20, -30];
const colors = Highcharts.getOptions().colors;
const options = {
chart: {
type: 'waterfall'
},
series: [{
// Single series simulating 2 series
data: data.map(v => v < 0 ? {
y: v,
color: colors[0]
} : {
y: v,
color: colors[3]
}),
stacking: 'normal',
showInLegend: false
}, {
// Positive data serie
color: colors[3],
data: [10, 20, 0],
visible: false,
stacking: 'normal',
showInLegend: false
}, {
// Negative data serie
color: colors[0],
data: [0, 0, -30],
visible: false,
stacking: 'normal',
showInLegend: false
}, {
// Empty serie for legend item
name: 'Series 1',
color: colors[3],
stacking: 'normal',
events: {
legendItemClick: function(e) {
const series = this.chart.series;
const invisibleCount = document.querySelectorAll('.highcharts-legend-item-hidden').length;
if (this.visible) {
if (invisibleCount === 1) {
series[0].hide();
series[1].hide();
series[2].hide();
} else {
series[0].hide();
series[2].show();
}
} else if (invisibleCount === 2) {
series[0].hide();
series[1].show();
} else {
series[0].show();
series[2].hide();
}
}
}
}, {
// Empty serie for legend item
name: 'Series 2',
color: colors[0],
stacking: 'normal',
events: {
legendItemClick: function(e) {
const series = this.chart.series;
const invisibleCount = document.querySelectorAll('.highcharts-legend-item-hidden').length;
if (this.visible) {
if (invisibleCount === 1) {
// hide all
series[0].hide();
series[1].hide();
series[2].hide();
return;
}
series[0].hide();
series[1].show();
} else {
if (invisibleCount === 2) {
series[0].hide();
series[2].show();
return;
}
series[0].show();
series[1].hide();
}
}
}
}]
}
const chart = Highcharts.chart('container', options);
Live example:
https://jsfiddle.net/2uszoLop/

Related

Highligligh particular areas based on X-axis data

SO What I am trying to do is that I am trying to fetch data from CSV File, and from other CSV file I am trying to Highlight a particular area from the Chart.
For Eg.:
This is the Chart I am getting .
By adding the Following Code.
$.get('abc.csv', function(data) {
var lines = []
lines = data.split('\n');
console.log(lines);
var ecgData=[];
$.each(lines, function(lineNo, lineContent){
if(lineNo >= 0)
{
ecgData[lineNo-0] = parseFloat(lineContent.substring(lineContent.lastIndexOf(",")+1) );
//gibber=500;
//m=m+500;
}//console.log('PPG Data', ppgData[ppgNo-0])
});
featurex = [5,10,14,34,56,78,90,95] ;
featurey = [0,0,1,0,0,3,0,2];
zip = (xs, ys) => xs.reduce((acc, x, i) => (acc.push([x, ys[i]]), acc), []);
//console.log(ecg);
console.log(ecgData);
Highcharts.chart('ecg', {
chart: {
type: 'line',
zoomType: 'xy',
panning: true,
panKey: 'shift'
},
credits: {
enabled: false
},
title: {
text: 'ECG Data'
},
subtitle: {
text: ''
},
xAxis: {
crosshair: false
},
yAxis: {
title: {
text: 'ECG Peaks'
}
},
tooltip: {
enabled: false
},
plotOptions: {
column: {
pointPadding: 0.2,
borderWidth: 0
}
},
series: [{
name: '',
lineWidth: 1,
data: ecgData,
animation: {
duration: 14000
}
},
{ type: 'column',
name: 'Features',
data: zip(featurex, featurey),
animation: {
duration: 14000
}
}
]
});
});
My Chart :
Now as you can see from the Chart. I am getting the features data as bars in the chart.
featurex = [5,10,14,34,56,78,90,95] ;
featurey = [0,0,1,0,0,3,0,2];
but that is not what I want what I want is that where the features x value is 1, I want to highlight that area with a particular color, where it is 2, it should be filled with other color Like an example below:
Note: its just an example how the data should look don't math the data with the above image data.
I hope my question is clear.
In the load event you can check if a point meets your condition and add plotBands to your chart.
chart: {
events: {
load: function() {
var xAxis = this.xAxis[0],
points = this.series[0].points,
from,
to,
plotBands = [];
points.forEach(function(point, i) {
from = points[i - 1] ? points[i - 1].x : point.x;
to = points[i + 1] ? points[i + 1].x : point.x;
if (point.y === 1) {
plotBands.push({
color: 'blue',
from: from,
to: to
});
} else if (point.y === 2) {
plotBands.push({
color: 'green',
from: from,
to: to
});
}
});
xAxis.update({
plotBands: plotBands
});
}
}
}
Live demo: http://jsfiddle.net/BlackLabel/vm0ouwp5/
API Reference: https://api.highcharts.com/highcharts/xAxis.plotBands

Highcharts Line Chart, display series name at the end of line series

We have requirement for line chart as below. We are using highcharts. Our requirement is that chart should display series name at the end of line as displayed in below images.
How can we achieve this?
As an alternative to the renderer(), I find it convenient to use the dataLabels for this purpose.
The idea being to disable dataLabels in the plotOptions, but define the position and format anyway.
Then enable the dataLabels for the last point in each series' data array.
Example:
plotOptions: {
series: {
dataLabels: {
enabled: false,
crop: false,
overflow: 'none',
align: 'left',
verticalAlign: 'middle',
formatter: function() {
return '<span style="color:'+this.series.color+'">'+this.series.name+'</span>';
}
}
}
}
Fiddle:
http://jsfiddle.net/jlbriggs/pgo7pedn/
Output example:
Get last point, which has plotX and plotY properties, then draw your labels with render.
const options = {
chart: {
events: {
load() {
const chart = this
const series = chart.series
series.forEach((s) => {
const len = s.data.length
const point = s.data[len - 1]
console.log(point)
chart.renderer.text(
point.series.name,
point.plotX + chart.plotLeft + 10,
point.plotY + chart.plotTop - 10
)
.attr({
zIndex: 5
})
.add()
})
}
}
},
xAxis: {
max: 5
},
series: [{
data: [30, 70, 50, 90]
}, {
data: [60, 100, 80, 120]
}, {
data: [80, 150, 90, 180]
}]
}
const chart = Highcharts.chart('container', options)
Live example:
https://jsfiddle.net/479vdhm3/

Customize Stacked column chart in highChart

I am trying to customize stacked column chart like this
Here i did all the remaining things but i Don't know how to give that bar lines above every column........I need that bar lines in both positive and negative axis
My code
$(document).ready(function () {
$('#div1').highcharts({
chart: { type: 'column', backgroundColor: 'transparent' },
title: { text: null },
subtitle: { text: null },
credits: {
enabled: false
},
xAxis: {
categories: categories,
labels: {
rotation: 0,
style: {
fontWeight: 'normal',
fontSize: '0.9vw',
fontFamily: 'Verdana, sans-serif',
color: "black"
}
}
},
yAxis: {
title: {
enabled: false
},
lineWidth: 0,
gridLineWidth: 1,
labels: {
enabled: true
},
// gridLineColor: 'transparent',
plotLines: [{
color: '#ddd',
width: 1,
value: 0
}],
},
plotOptions: {
series: {
stacking: 'normal'
}
},
series:seriesforSeniorUPT
});
});
});
Link
Fiddle
To elaborate on Sebastian Bochan's helpful comment, here's an updated version of your fiddle with two "dummy" series to serve as the patterned background: https://jsfiddle.net/brightmatrix/hc8rLy18/2/
A few items to note:
There are two "dummy" series: one for the positive numbers and one for the negative numbers.
Both series have showInLegend and enableMouseTracking set to false so the user cannot interact with them.
Both series have stacking set to false so they will not be part of the "real" data you want to show.
Both series have zIndex set to 0. I explain why below the code block.
The code for the "dummy" series is as follows.
// background for positive values
obj = {};
obj["name"] = 'patternFill';
obj["data"] = [120, 120];
obj["color"] = 'url(#highcharts-default-pattern-3)';
obj["grouping"] = false;
obj["zIndex"] = 0;
obj["enableMouseTracking"] = false;
obj["stacking"] = false;
obj["showInLegend"] = false;
seriesforSeniorUPT.push(obj);
// background for negative values
obj = {};
obj["name"] = 'patternFill';
obj["data"] = [-80, -80];
obj["color"] = 'url(#highcharts-default-pattern-3)';
obj["grouping"] = false;
obj["zIndex"] = 0;
obj["enableMouseTracking"] = false;
obj["stacking"] = false;
obj["showInLegend"] = false;
seriesforSeniorUPT.push(obj);
For the three "real" data series, I set zIndex to 10 to they will appear over the "dummy" series we're using for our patterend backgrounds.
For all of the series, I set grouping to false so they will appear one atop the other, not next to one another.
Here's a screenshot of the output. I hope this is helpful!

Chart.js: hiding series by clicking on legend

I'm developing a site that uses chart.js (www.chartjs.org).
I have to make a line chart that shows multiple series of data, that users can hide or show by clicking on the respective legend symbol (similar to this http://js.syncfusion.com/demos/web/#!/azure/chart/linechart).
Is there any way to do it with chartjs?
You can try this
Create store for hidden datasets
window.chartName = new Chart(...
window.chartName.store = new Array();
Then use this function to update chart, must be handled by click on legend item
function updateDataset(legendLi, chart, label) {
var store = chart.store;
var exists = false;
for (var i = 0; i < store.length; i++) {
if (store[i][0] === label) {
exists = true;
chart.datasets.push(store.splice(i, 1)[0][1]);
legendLi.fadeTo("slow", 1);
}
}
if (!exists) {
for (var i = 0; i < chart.datasets.length; i++) {
if (chart.datasets[i].label === label) {
chart.store.push([label, chart.datasets.splice(i, 1)[0]]);
legendLi.fadeTo("slow", 0.33);
}
}
}
chart.update();
}
Don't forget updated legend template in chart options
legendTemplate : "<ul class=\"<%=name.toLowerCase()%>-legend\"><% for (var i=0; i<datasets.length; i++){%><li class=\"legend-item\" onclick=\"updateDataset($(this), window.chartName, '<%=datasets[i].label%>')\"><span style=\"background-color:<%=datasets[i].strokeColor%>\"></span><%if(datasets[i].label){%><%=datasets[i].label%><%}%></li><%}%></ul>"
Shortly, i added this onclick handler for li component
<li class=\"legend-item\" onclick=\"updateDataset($(this), window.chartName , '<%=datasets[i].label%>')\"><
For example fiddle
This is now available in Charts.js
From the documentation http://www.chartjs.org/docs/#chart-configuration-legend-configuration
Legend Configuration
The legend configuration is passed into the options.legend namespace.
The global options for the chart legend is defined in
Chart.defaults.global.legend.
onClick function(event, legendItem) {} A callback that is called when a 'click' event is registered on top of a label item
onHover function(event, legendItem) {} A callback that is
called when a 'mousemove' event is registered on top of a label item
An update to #benallansmith answer, the link to the documentation is now :
https://www.chartjs.org/docs/latest/configuration/legend.html
My version of the example code, to have datasets 2 and 3 hidden while clicking on legend for dataset 1 (datasets 2 and 3 have their legends hidden with the filter function):
public static readonly myChart: Chart.ChartConfiguration = {
type: 'line',
data: {
datasets: [
{
label: 'A',
borderColor: 'red',
fill: false,
lineTension: 0
},
{
label: 'B',
borderColor: 'blue',
fill: false,
lineTension: 0,
pointRadius: 0
},
{
borderColor: 'blue',
borderDash: [5, 10],
borderWidth: 1,
fill: false,
lineTension: 0,
pointRadius: 0
},
{
borderColor: 'blue',
borderDash: [5, 10],
borderWidth: 1,
fill: false,
lineTension: 0,
pointRadius: 0
}
]
},
options: {
legend: {
labels: {
filter: function(legendItem, chartData) {
if (legendItem.datasetIndex > 1) {
return false;
}
return true;
}
},
onClick: function(e, legendItem) {
const index = legendItem.datasetIndex;
if (index === 1) {
const ci = this.chart;
[
ci.getDatasetMeta(1),
ci.getDatasetMeta(2),
ci.getDatasetMeta(3)
].forEach(function(meta) {
meta.hidden = meta.hidden === null ? !ci.data.datasets[1].hidden : null;
});
ci.update();
} else {
// Do the original logic
Chart.defaults.global.legend.onClick.call(this, e, legendItem);
}
}
},
responsive: false,
animation: {
duration: 0
},
}
...
};
my version is v2.8.0
I find a work way, try it.
add
legend : {
}
into option
var donutOptions = {
maintainAspectRatio : false,
responsive : true,
animation: {
animateScale: true,
animateRotate: true
},
tooltips: {
intersect: false,
callbacks: {
label: function (tooltipItem, data) {
...
}
},
},
plugins: {
datalabels: {
...
},
},
},
legend : {
}
};
and use this
donutChart.chart.getDatasetMeta(0).data[index].hidden = true;
donutChart.update();
I've found no way to do this. It's easy to put some onclick behaviour on the legend template, and you can easily change the series stroke and colors alpha channel to 0 so that the area and stroke disappear but I've found no way to do this on points.
I've decided to use google charts for this particular chart, and chart.js whenever I do not need that behavior, hoping that the good creators of chart.js will add it in the future.
onLegendClick: function (e) {
var series = e.target;
series.isVisible() ? series.hide() : series.show();
},
dxcharts have a function called onLegendClick, a few others are onSeriesClick and onPointClick. I hope this helps.

Highstocks: How to define the span colors of a line instead of the individual line color

I am creating a Gantt Chart using Highstocks(compare multiple series).
1. I want to have the First span color to be Red, the second Blue and third Green.
How can I do the same?
2. how can i set the tooltip to show the values of all the points on the line instead of all points at the time.
3. How to fix y-axis and it should add scroll as values increase.
Please check the Gantt Chart Fiddle here.
var partNumber="2724070125R Planned,2724070125RActual,5511822432R Planned,5511822432RActual";
var partNum = partNumber.split(",");
var ganttData = [
[[Date.UTC(2013,11-1,07),1], [Date.UTC(2013,11-1,29),1], [Date.UTC(2013,11-1,30),1]],
[[Date.UTC(2013,11-1,20),1.25],Date.UTC(2013,11-1,21),1.25],Date.UTC(2013,12-1,21),1.25]],
[[Date.UTC(2013,11-1,13),2],[Date.UTC(2013,12-1,10),2],[Date.UTC(2014,02-1,14),2]],
[[Date.UTC(2013,11-1,21),2.25],[Date.UTC(2013,11-1,21),2.25],[Date.UTC(2013,11-1,30),2.25]]];
$( document ).ready(function(){
$(function() {
var seriesOptions = [],
yAxisOptions = [],
seriesCounter = 0,
names = partNum,
colors = Highcharts.getOptions().colors;
var data=ganttData;
$(function () {
$.each(names, function(i, name) {
seriesOptions[i] = {
// name: data[i][1],
name:name,
step:true,
data: data[i]
};
// As we're loading the data asynchronously, we don't know what order it will arrive. So
// we keep a counter and create the chart when all the data is loaded.
seriesCounter++;
if (seriesCounter == names.length) {
createChart();
}
});
});
// create the chart when all data is loaded
function createChart() {
Highcharts.setOptions({
global: {
useUTC: false
}
});
$('#ganttChart').highcharts('StockChart', {
chart: {
},
title: {
text: 'PPAP Cumulative Status'
},
rangeSelector: {
selected: 4
},
xAxis: {
type: 'datetime', ordinal: false //this sets the fixed time formats
},
yAxis: {
plotLines: [{
value: 0,
width: 2,
color: 'silver'
}],
min:0 },
plotOptions: {
series: {
lineWidth: 3,
states: {
hover: {
enabled: true,
lineWidth: 3
}
}
}
},
tooltip: {
pointFormat: '<span style="color:{series.color}">{series.name}</span>: <b>{point.y}</b><br/>',
valueDecimals: 0
},
series: seriesOptions,
exporting: {
enabled: false
}
});
}
});
});
1) You can set for series only one color. Here:
$.each(names, function(i, name) {
seriesOptions[i] = {
name: name,
step: true,
data: data[i],
color: 'yourColor'
};
...
});
2) In tooltip, you have access to series via this.points[0].series.data etc. So you can get all points.
3) Scroll is not supported.

Categories