dashboard-style page with Highcharts graphs - highcharts

I would like to make something like a dashboard (kinda like the one that you see in many financial site), using Highcharts.
I've got the hang of adding 1 chart to a page, using a container, so I told myself that many containers, duplicating the code for one graph, will do; but I can't get it to work.
I have at least 8 graph, and I would like to organize them either in 2X4 arrangement, or just stacked on top of each other.
Mainly my confusion is coming from the fact that I need a general options section (to group common options), but I also need to customize the graphs, and I need to load data from CSV, so the order in which you do what, is causing me some problems.
I tried to follow an example here, where it was suggested to use setOptions and jQuery.extend, but I was not successful in making it work.
Is there an example that show a skeleton of the webpage, so I can see where to put each function, in which order and what kind of code do I have to put in?

Here you can find example how to add multiple chart like a dashboard: http://www.highcharts.com/demo/sparkline
And copy&paste code:
$(function () {
/**
* Create a constructor for sparklines that takes some sensible defaults and merges in the individual
* chart options. This function is also available from the jQuery plugin as $(element).highcharts('SparkLine').
*/
Highcharts.SparkLine = function (options, callback) {
var defaultOptions = {
chart: {
renderTo: (options.chart && options.chart.renderTo) || this,
backgroundColor: null,
borderWidth: 0,
type: 'area',
margin: [2, 0, 2, 0],
width: 120,
height: 20,
style: {
overflow: 'visible'
},
skipClone: true
},
title: {
text: ''
},
credits: {
enabled: false
},
xAxis: {
labels: {
enabled: false
},
title: {
text: null
},
startOnTick: false,
endOnTick: false,
tickPositions: []
},
yAxis: {
endOnTick: false,
startOnTick: false,
labels: {
enabled: false
},
title: {
text: null
},
tickPositions: [0]
},
legend: {
enabled: false
},
tooltip: {
backgroundColor: null,
borderWidth: 0,
shadow: false,
useHTML: true,
hideDelay: 0,
shared: true,
padding: 0,
positioner: function (w, h, point) {
return { x: point.plotX - w / 2, y: point.plotY - h};
}
},
plotOptions: {
series: {
animation: false,
lineWidth: 1,
shadow: false,
states: {
hover: {
lineWidth: 1
}
},
marker: {
radius: 1,
states: {
hover: {
radius: 2
}
}
},
fillOpacity: 0.25
},
column: {
negativeColor: '#910000',
borderColor: 'silver'
}
}
};
options = Highcharts.merge(defaultOptions, options);
return new Highcharts.Chart(options, callback);
};
var start = +new Date(),
$tds = $("td[data-sparkline]"),
fullLen = $tds.length,
n = 0;
// Creating 153 sparkline charts is quite fast in modern browsers, but IE8 and mobile
// can take some seconds, so we split the input into chunks and apply them in timeouts
// in order avoid locking up the browser process and allow interaction.
function doChunk() {
var time = +new Date(),
i,
len = $tds.length;
for (i = 0; i < len; i++) {
var $td = $($tds[i]),
stringdata = $td.data('sparkline'),
arr = stringdata.split('; '),
data = $.map(arr[0].split(', '), parseFloat),
chart = {};
if (arr[1]) {
chart.type = arr[1];
}
$td.highcharts('SparkLine', {
series: [{
data: data,
pointStart: 1
}],
tooltip: {
headerFormat: '<span style="font-size: 10px">' + $td.parent().find('th').html() + ', Q{point.x}:</span><br/>',
pointFormat: '<b>{point.y}.000</b> USD'
},
chart: chart
});
n++;
// If the process takes too much time, run a timeout to allow interaction with the browser
if (new Date() - time > 500) {
$tds.splice(0, i + 1);
setTimeout(doChunk, 0);
break;
}
// Print a feedback on the performance
if (n === fullLen) {
$('#result').html('Generated ' + fullLen + ' sparklines in ' + (new Date() - start) + ' ms');
}
}
}
doChunk();
});

For a more simplistic start to this problem, take a look at this example:
http://jsfiddle.net/jlbriggs/4GaVj/
It's a very simple set up that defines data arrays first (you can do this as part of your CSV parsing), then defines global options via Highcharts.setOptions(), and then defines the individual charts.
There are several different ways to go about this, from this simple example up to more complex, flexible and dynamic approaches. But if you're looking to start with the basics, this should help.

Related

HighChart data table keeps adding number of tables at bottom on every call

I am using HighChart library to show Pie Chart on my page, I am keeping showTable always true to show every time.
The problem is whenever data binds to charts using JQuery Ajax post dynamically, i see proper data in chart but also it keeps adding new data table everytime at the bottom. E.g. First time there will be only one table, after another call there will be two tables added and so on. Why Hightcharts not updating the same table again or is there a way to kill any existing table.?
hc = Highcharts.chart(chartName, {
chart: {
type: 'pie',
options3d: {
enabled: false,
alpha: 45
},
style: {
color: '#575962'
}
},
title: {
text: title,
style: {
color: '#575962',
fontweight: '400'
}
},
subtitle: {
text: 'Current Month(Top 10)'
},
plotOptions: {
pie: {
innerSize: 100,
depth: 45,
allowPointSelect: true,
cursor: 'pointer',
dataLabels: {
enabled: false
},
showInLegend: true
}
},
credits: {
enabled: false
},
exporting: {
showTable: true
},
series: [{
name: 'Price',
data: [],
dataLabels: {
formatter: function () {
//const point = this.point;
//return '<span style="color: #575962;font-size:11px;font-weight: 400">' +
// point.name + ': $' + point.y + '</span>';
}
}
}]
});
Why Hightcharts not updating the same table again or is there a way to kill any existing table.?
I have achieved this by removing the series on each call and adding them again with new data. Hope this helps if anyone else looking and couldn't find any other answer.
//Removing Series
while (hc.series.length > 0) {
hc.series[0].remove(false);
}
//Adding new Series
hc.addSeries({
name: 'Price',
data: [],
dataLabels: {
formatter: function () {
const point = this.point;
return '<span style="color: #575962;font-size:11px;font-weight: 400">' +
point.name + ': $' + point.y + '</span>';
}
}
});
//Binding Series data
var res = result.Data.slice(0, 10);
res.forEach(function (element, index) {
hc.series[0].addPoint({
name: element.ResourceGroupName,
y: element.TotalMonthlyPrice,
});
});

xAxis Image Disappears in Highcharts After First Refresh

I have a page with a variety of select menus. The select options are used in an ajax call to build a Highcharts bar graph. Every time a filter changes, the graph gets recreated. I did this instead of updating the series data, because in the past I have noticed that destroying and recreating was more efficient than updating.
I want images to show on the x-axis, so I used a nice little trick of creating two x axes, used formatter to return an image on the first axis, and linked the second axis to the first. This works on first refresh. However, every time the chart gets recreated thereafter, the image disappears. I checked my console and I don't see any errors.
And idea of what's going on here?
/**
* Whenselection changes
*/
$(document).on('change', '.filter', function(){
getChartData($params)
})
});
/**
* API call to get data that will populate charts.
* #param {obj} params
*/
function getChartData(params)
{
//Get chart data
$.ajax({
url: apiURL + '/chartdata/',
data: params,
dataType: 'json',
cache: false,
success: function(data) {
initChart(data[0]);
}
});
function initChart(chartData)
{
var chart = Highcharts.chart('container', {
chart: {
type: 'bar',
backgroundColor: 'transparent', //#E8EAF6',
height: '23%',
marginLeft: 35
},
title: {
text: null
},
xAxis: {
categories: [category1, category2],
lineColor: 'transparent',
min: 0,
tickColor: 'transparent',
title: {
text: null
},
labels: {
x: -35,
useHTML: true,
overflow: 'allow',
formatter: function () {
if(this.isFirst == true)
return '<img src="../assets/img/nat-jr-grad-gold.png"><br/>';
else
return '<img src="../assets/img/nat-jr-grad-purple.png"><br/>';
}
}
},
yAxis: {
min: 0,
title: {
useHTML: true,
text: null
},
labels: {
enabled: false
},
lineWidth: 0,
minorGridLineWidth: 0,
gridLineWidth: 0,
lineColor: 'transparent',
gridLineColor: 'transparent',
},
legend: {
enabled: false
},
series: [{
name: category1,
data: [{name: category1, y:Math.round(chartData.p_grad_nongap * 100), {y: null}],
}, {
name: category2,
data: [null, {name: category2, y: Math.round(chartData.p_grad_gap * 100)}]
}]
});
}
I reproduced your problem on a simplified example: http://jsfiddle.net/BlackLabel/sm2r684n/
For the first time, the image is loaded asynchronously and the chart does not take it into account when calculating the margins. Every next time the result is different, so you should wait until the picture is loaded:
var img = new Image();
img.onload = function() {
initChart();
}
img.src = "https://www.highcharts.com/samples/graphics/sun.png";
Live demo: http://jsfiddle.net/BlackLabel/m09ok2cg/
I think ppotaczek had the cortrect root cause of the problem; the image is loaded asynchronously and the chart does not take it into account when calculating the margins. His suggestion used setTimeout function to continuously redraw the graph, which is rather inefficient. My work-around for this was to just add the images as avg elements using chart.renderer after the chart was created.
/* Render X-Axis images */
chart.renderer.image('../assets/img/img1.png', 0, 40, 32, 36)
.css({
class: 'icon-img',
zIndex: 10
})
.add();
chart.renderer.image('../assets/img/img2.png', 0, 130, 32, 36)
.css({
class: 'icon-img',
zIndex: 10
})
.add();

Highcharts (highstock) - hide all markers in the navigator

I have got into little trouble with hiding the markers in the navigator
The problem is that after I set marker.enabled to false. It does nothing. (JS fiddle - line 75)
navigator: {
series: {
lineWidth: 0,
marker: {
enabled: false // this should hide markers
}
}
}
It is doing nothing because I have some condition where if the condition is true I need to insert the marker at that point, like this:(JS fiddle - line 63).
Btw.. in that JSfiddle example I'm setting it for every point, but that doesn't matter.
series: [{
data: {
x: ...,
y: ...,
marker: {
enabled: true
}
}
]}
- so when I set it manually on that point, it will override the global navigator options
PROBLEM - The global navigator option for the marker is overriden by every single point.
GOAL - Hide all markers in the navigator.
JSFiddle
OLD SOLUTION
If you have only 1 serie in the graph - take the Wojciech Smiel answer.
If you have more than 1 serie in the graph - you have to first make an array of the series with the disabled marker, and then set the options like this
navigator: {
series: seriesArray // array with the series and disabled marker
}
NEW SOLUTION
My friend recently discovered better and easier solution, each serie has navigatorOptions property where you can set radius for the marker, if you set it to 0 it will be hidden.
serie.navigatorOptions = { marker: { radius: 0 } };
Quoting the Highcharts navigator documentation:
Unless data is explicitly defined on navigator.series, the data is
borrowed from the first series in the chart.
That's why navigator series has markers despite the fact that you disabled it in navigator options. However, you can add separate data for the navigator where you can disable marker for each point. Check the demo posted below.
Code:
function generateData(markers) {
// generate an array of random data
var data = [],
time = (new Date()).getTime(),
i;
for (i = -999; i <= 0; i += 1) {
data.push({
x: time + i * 1000,
y: Math.round(Math.random() * 100),
marker: {
enabled: markers
}
});
}
return data;
}
// Create the chart
Highcharts.stockChart('container', {
chart: {
events: {
load: function() {
// set up the updating of the chart each second
var chart = this,
series = this.series[0],
seriesNav = this.series[1];
setInterval(function() {
var x = (new Date()).getTime(), // current time
y = Math.round(Math.random() * 100);
series.addPoint([x, y], false);
seriesNav.addPoint([x, y], true, true);
}, 1000);
}
}
},
time: {
useUTC: false
},
rangeSelector: {
buttons: [{
count: 1,
type: 'minute',
text: '1M'
}, {
count: 5,
type: 'minute',
text: '5M'
}, {
type: 'all',
text: 'All'
}],
inputEnabled: false,
selected: 0
},
title: {
text: 'Live random data'
},
exporting: {
enabled: false
},
plotOptions: {
series: {
marker: {
enabled: true
}
}
},
series: [{
name: 'Random data',
showInNavigator: true,
data: generateData(true)
}],
navigator: {
series: {
lineWidth: 0,
marker: {
enabled: false
},
data: generateData(false)
}
}
});
Demo:
https://jsfiddle.net/BlackLabel/1um9gs47/21/

Spiderweb Highcharts with multiple scales on multiple axes

My requirement is to create a spiderweb highchart with values on each axis where each axes have different scales.Is it possible? I have attached a same output of my requirement.
Use multiple yAxis and assign them to the separated panes with startAngle.
Parser
var colors = Highcharts.getOptions().colors,
each = Highcharts.each,
series = [{
yAxis: 0,
data: [10, 20, 30]
}, {
yAxis: 1,
data: [1, 2, 3]
}, {
yAxis: 2,
data: [4, 2, 1]
}, {
yAxis: 3,
data: [5, 1, 3]
}, {
yAxis: 4,
data: [2, 3, 4]
}],
yAxis = [],
panes = [],
startAngle = 0;
each(series, function(serie, i) {
yAxis.push({
pane: i,
showLastLabel: true,
gridLineWidth: i === 0 ? true : false,
labels: {
useHTML: true,
formatter: function() {
return '<span style="color:' + colors[i] + '">' + this.value + '</span>';
}
}
});
panes.push({
startAngle: startAngle
});
startAngle += 72;
});
Chart configuartion
$('#container').highcharts({
/*
chart options
*/
pane: panes,
yAxis: yAxis,
series: series
});
Example:
http://jsfiddle.net/6jmqb1r8/
I believe Sebastian Bochan's answer is rock solid due to his suggestion of the pane attributes. However, I was tinkering around with another method and wanted to share it with you and the community.
My solution makes use of "dummy" series, which are series that the user does not see or interact with, but can help with customized features such as your labels.
I added six "dummy" series that contain the labels for each spoke of the spider chart. The first, for the "zero" value, is blank, but the others will show data labels for the first, second, third, etc. points along the spoke.
After the chart is drawn, I use the addSeries() function to add these "dummy" series to the chart:
// Add "dummy series to control the custom labels.
// We will add one for each spoke, but first will always be
// overriden by y-axis labels; I could not figure out how to
// disable that behavior.
// The color, showInLegend, and enableMouseTracking attributes
// prevent the user from seeing or interacting with the series
// as they are only used for the custom labels.
var chart = $('#container').highcharts();
var labelArray = [
['','1','2','3','4','5'],
['','j','k','l','m','n'],
['','one','two','three','four','five'],
['','u','v','w','x','y'],
['','a','b','c','d','e']
];
for (var i = 0; i<=5; i++) {
chart.addSeries({
name: 'dummy series #' + i + ' for label placement',
data: [
{ name: labelArray[0][i], y: i },
{ name: labelArray[1][i], y: i },
{ name: labelArray[2][i], y: i },
{ name: labelArray[3][i], y: i },
{ name: labelArray[4][i], y: i }
],
dataLabels: {
enabled: true, padding: 0, y: 0,
formatter: function() {
return '<span style="font-weight: normal;">' + this.point.name + '</span>';
}
},
pointPlacement: 'on',
lineWidth: 0,
color: 'transparent',
showInLegend: false,
enableMouseTracking: false
});
}
A few items to note:
lineWidth: 0 and color: 'transparent' makes the "dummy" series lines invisible
showInLegend: false prevents them from showing up in the legend
enableMouseTracking: false prevents the users from interacting with them
Here is the fiddle that shows how this works: http://jsfiddle.net/brightmatrix/944d2p6q/
The result looks like this:
Just on quirk that I noted in my comments: I could not figure out how to override the labels on the first spoke (at the 12-o-clock position). If I set the y-axis labels to "false," it refused to show anything, even the custom data labels I set in the "dummy" series. Therefore, I suggest that your first spoke be the numerical labels in your example.
I realize this is perhaps a more complicated route, but I hope it's helpful to you and others in some way.

Highcharts - remove points from series

Is it possible to remove certain points from a series?
I'm looking for some way to draw a chart with a fixed back period,
something like: the last 1 hour.
I know how to add points using dynamic update:
http://www.highcharts.com/demo/dynamic-update
But in my case the time interval between points is not constant,
so I can't just use the shift option of addPoint.
Thanks,
Omer
If you want to have the same, you can use the same logic as in addPoint, see: http://jsfiddle.net/JKCLx/1/
However, why can't you just use shift argument in addPoint()?
I think I found a partial answer to my own question:
I can iterate over the series datapoints like this:
http://api.highcharts.com/highcharts#Series.data
and then call point.Remove.
The problem with this solution is that it does not draw monitor style like in the example,
but rather it redrwas the entire chart on each change.
http://jsfiddle.net/JKCLx/
$(function () {
$(document).ready(function() {
Highcharts.setOptions({
global: {
useUTC: false
}
});
var chart;
$('#container').highcharts({
chart: {
type: 'spline',
animation: Highcharts.svg, // don't animate in old IE
marginRight: 10,
events: {
load: function() {
// set up the updating of the chart each second
var series = this.series[0];
setInterval(function() {
var x = (new Date()).getTime(), // current time
y = Math.random();
series.addPoint([x, y], true, false);
// series.data[0].remove(false);
series.data[0].remove(true);
}, 1000);
}
}
},
title: {
text: 'Live random data'
},
xAxis: {
type: 'datetime',
tickPixelInterval: 150
},
yAxis: {
title: {
text: 'Value'
},
plotLines: [{
value: 0,
width: 1,
color: '#808080'
}]
},
tooltip: {
formatter: function() {
return '<b>'+ this.series.name +'</b><br/>'+
Highcharts.dateFormat('%Y-%m-%d %H:%M:%S', this.x) +'<br/>'+
Highcharts.numberFormat(this.y, 2);
}
},
legend: {
enabled: false
},
exporting: {
enabled: false
},
series: [{
name: 'Random data',
data: (function() {
// generate an array of random data
var data = [],
time = (new Date()).getTime(),
i;
for (i = -19; i <= 0; i++) {
data.push({
x: time + i * 1000,
y: Math.random()
});
}
return data;
})()
}]
});
});
});

Resources