I am trying to add/delete yAxis dynamically but I observe performance issues. It takes more than a second (sometimes it goes upto 4 seconds) to dynamically add or remove a series into a new yAxis. I need to load end of day data (price point for each day) for 10 or more years in the chart.
Any advice in improving the performance will be much appreciated.
Few points to note -
I can use different type of charts (line, ohlc, candlestick, area etc.)
I need mouse tracking to be enabled as I am using click events on the series.
User will have option to either choose to apply data grouping or to not.
Below is my code sample to illustrate the problem.
var chart;
var index = 2;
var groupingUnitsD = {units:[['day',[1]]], enabled:true};
var groupingUnitsWM = [[
'week', // unit name
[1] // allowed multiples
], [
'month',
[1, 2, 3, 4, 6]
]];
$(function () {
var ohlc = [];
$.getJSON('http://www.highcharts.com/samples/data/jsonp.php?filename=aapl-ohlcv.json&callback=?', function (data) {
// split the data set into ohlc
var volume = [],
dataLength = data.length,
i = 0;
for (i; i < dataLength; i++) {
ohlc.push([
data[i][0], // the date
data[i][1], // open
data[i][2], // high
data[i][3], // low
data[i][4] // close
]);
}
loadChart(data);
});
function loadChart(cdata){
var highchartOptions = {
plotOptions:{
line: {
enableMouseTracking: true,
animation:false,
marker: {
enabled: false
}
},
series:{
cursor: 'pointer',
}
},
chart:{
renderTo:'container'
},
navigator: {
outlineColor: '#0066DD',
outlineWidth: 1
},
xAxis: [{
gridLineWidth: 1,
gridLineColor: "#eaf5ff",
lineColor: '#FF0000',
lineWidth: 1
}],
yAxis:[{
title:{
text:"initial data"
},
id:'myaxis-1',
height:'14%',
top:'0%'
}],
series: [{
data: cdata,
turboThreshold:0,
dataGrouping:groupingUnitsD
}]
};
chart = new Highcharts.StockChart(highchartOptions);
}
$button = $('#button');
$delButton = $('#delbutton');
$button.click(function () {
var axisObj = {
title: {
text: "axis-" + index,
},
id:'myaxis-'+ index
};
chart.addAxis(axisObj, false);
console.log("Added axis:" + 'myaxis-'+ index);
$('#axisList').append($('<option></option>').text('myaxis-'+ index));
var seriesData = new Object();
seriesData.name = 'axis-' + index;
seriesData.id = 'myaxis-' + index;
seriesData.yAxis = 'myaxis-'+ index;
seriesData.data = ohlc;
seriesData.type = 'line';
seriesData.dataGrouping = groupingUnitsD;
chart.addSeries(seriesData);
updateAxisHeight();
index++;
});
$delButton.click(function () {
var $select = $('#axisList');
console.log($select.val());
console.log(chart.get($select.val()));
var selId = $select.val();
chart.get(selId).remove();
$('option:selected', $select).remove();
var i=0;
updateAxisHeight();
});
updateAxisHeight = function(){
var i=0;
$("#axisList > option").each(function() {
chart.get(this.value).update({ height: '14%',top: (i*15) + '%',offset:0 });
i++;
});
}
});
<script src="https://code.jquery.com/jquery-2.1.4.min.js"></script>
<script src="http://code.highcharts.com/stock/highstock.js"></script>
<script src="http://code.highcharts.com/stock/highcharts-more.js"></script>
<script src="http://code.highcharts.com/modules/exporting.js"></script>
<button id="button" class="autocompare">Add yAxis</button><br>
<!--Entrt yAxis index to delete:<input type='text' id="delAxis"/> -->
<select id="axisList" name="axisList">
<option value="myaxis-1" selected="selected">myaxis-1</option>
</select>
<button id="delbutton" class="autocompare">Delete yAxis</button>
<div id="container" style="height: 800px"></div>
You can significantly improve the performance in this case with one trick: when performing several consecutive operations that each require a redraw (add series, add axis, update axis height), don't redraw until you've told Highcharts about all the operations.
On my machine, this improves the performance of your add axis function by 5x-6x. See code and comments below.
var chart;
var index = 2;
var groupingUnitsD = {units:[['day',[1]]], enabled:true};
var groupingUnitsWM = [[
'week', // unit name
[1] // allowed multiples
], [
'month',
[1, 2, 3, 4, 6]
]];
$(function () {
var ohlc = [];
$.getJSON('http://www.highcharts.com/samples/data/jsonp.php?filename=aapl-ohlcv.json&callback=?', function (data) {
// split the data set into ohlc
var volume = [],
dataLength = data.length,
i = 0;
for (i; i < dataLength; i++) {
ohlc.push([
data[i][0], // the date
data[i][1], // open
data[i][2], // high
data[i][3], // low
data[i][4] // close
]);
}
loadChart(data);
});
function loadChart(cdata){
console.time("chart load");
var highchartOptions = {
plotOptions:{
line: {
enableMouseTracking: true,
animation: false,
marker: {
enabled: false
}
},
series:{
cursor: 'pointer',
}
},
chart:{
alignTicks: false,
events: {
load: function () {
console.timeEnd("chart load");
}
},
renderTo:'container'
},
yAxis:[{
title:{
text:"initial data"
},
id:'myaxis-1',
height:'14%',
top:'0%'
}],
series: [{
data: cdata,
turboThreshold:0,
dataGrouping:groupingUnitsD
}]
};
chart = new Highcharts.StockChart(highchartOptions);
}
$button = $('#button');
$delButton = $('#delbutton');
$button.click(function () {
var startTime = new Date().getTime();
var axisObj = {
title: {
text: "axis-" + index,
},
id:'myaxis-'+ index
};
chart.addAxis(axisObj, false, false); // don't redraw yet
console.log("Added axis:" + 'myaxis-'+ index);
$('#axisList').append($('<option></option>').text('myaxis-'+ index));
var seriesData = new Object();
seriesData.name = 'axis-' + index;
seriesData.id = 'myaxis-' + index;
seriesData.yAxis = 'myaxis-'+ index;
seriesData.data = ohlc;
seriesData.type = 'line';
seriesData.dataGrouping = groupingUnitsD;
chart.addSeries(seriesData, false); // don't redraw yet
updateAxisHeight(false); // don't redraw yet
index++;
// finally, redraw now
chart.redraw();
var endTime = new Date().getTime();
console.log("add axis took " + (endTime - startTime) + " msec");
});
$delButton.click(function () {
var $select = $('#axisList');
console.log($select.val());
console.log(chart.get($select.val()));
var selId = $select.val();
chart.get(selId).remove();
$('option:selected', $select).remove();
var i=0;
updateAxisHeight();
});
updateAxisHeight = function(redraw){
// set redraw to true by default, like Highcharts does
if (typeof redraw === 'undefined') {
redraw = true;
}
var i=0;
$("#axisList > option").each(function() {
// don't redraw in every iteration
chart.get(this.value).update({ height: '14%',top: (i*15) + '%',offset:0 }, false);
i++;
});
// redraw if caller asked to, or if the redraw parameter was not specified
if (redraw) {
chart.redraw();
}
}
});
<script src="https://code.jquery.com/jquery-2.1.4.min.js"></script>
<script src="http://code.highcharts.com/stock/highstock.js"></script>
<script src="http://code.highcharts.com/stock/highcharts-more.js"></script>
<script src="http://code.highcharts.com/modules/exporting.js"></script>
<button id="button" class="autocompare">Add yAxis</button><br>
<!--Entrt yAxis index to delete:<input type='text' id="delAxis"/> -->
<select id="axisList" name="axisList">
<option value="myaxis-1" selected="selected">myaxis-1</option>
</select>
<button id="delbutton" class="autocompare">Delete yAxis</button>
<div id="container" style="height: 800px"></div>
Related
Please refer the image. I need to show datalabels name over on each color of the progress.
var markers = JSON.parse('<%=ConvertDataTabletoString("uspTaskProgress1","",null,1,10) %>');
var colors = ['skyblue', 'orange', 'red','blue'];
var statusprogress = ['Overall Subtask Percentage'];
var Arrayset = [];
var starts1 = [];
var ends1 = [];
var val1 = [];
var val2 = [];
var categories = [];
if (markers != null) {
if (markers.length > 0) {
var prj=document.getElementById("param1").value;
for (var i = 0; i < markers.length; i++) {
var syearval = parseInt(markers[i].ActualStart.substr(0, 4));
var smonthval = parseInt(markers[i].ActualStart.substr(5, 2))-1;
var sdateval = parseInt(markers[i].ActualStart.substr(8, 2));
var eyearval = parseInt(markers[i].ActualEnd.substr(0, 4));
var emonthval = parseInt(markers[i].ActualEnd.substr(5, 2))-1;
var edateval = parseInt(markers[i].ActualEnd.substr(8, 2));
val1 = [Date.UTC(syearval, smonthval, sdateval)];
val2 = [Date.UTC(eyearval, emonthval, edateval)];
starts1.push(val1[0]);
ends1.push(val2[0]);
Arrayset.push({ color:colors[i],name: markers[i].Task, start: starts1[i], end: ends1[i], completed: markers[i].OverallSubtaskPercentage, y:0});
}
for (var j = 0; j < markers.length; j++) {
categories.push(markers[j].Task);
}
MainLoadChart(Arrayset, categories);
}
}
function MainLoadChart(array,categories) {
var dta = array;
Highcharts.ganttChart('container8', {
chart: {
type: 'xrange'
},
xAxis: {
type: 'datetime'
},
yAxis: {
categories: categories,
},
title: {
text: 'Task Progress Indicator Status'
},
tooltip: {
formatter() {
let output = ` <span style="font-size: 20px;color:green">${prj}</span><br>
<span><b>${this.key}(Overall Subtask Percentage):${this.point.completed}% </b></span><br>
<span>Start: ${Highcharts.dateFormat('%A, %e. %b, %Y', this.x)}</span><br>
<span>End: ${Highcharts.dateFormat('%A, %e. %b, %Y', this.x2)}</span>`
return output
}
},
series: [{
data:dta,
dataLabels: {
formatter() {
let output1 = ` <span style="font-size: 10px">${this.point.completed}%</span>`
return output1
}
}
}]
});
}
I added datalabels property in series.data but it's not showing in the output. Can let us know how to add the data labels name on each color of the task progress. Image attached. It's a highcharts gantt chart.Code is attached please have a review on the code
You can set the dataLabels options, like formatter to set what data label should display, for each point in the data config.
Like this:
data: [{
name: 'test1',
start: Date.UTC(2014, 10, 18),
end: Date.UTC(2014, 10, 25),
completed: 0.25,
y: 0,
dataLabels: {
enabled: true,
x: 150,
formatter() {
return 'test1'
}
}
}, ...]
Demo: https://jsfiddle.net/BlackLabel/am0w5Lkr/
In the above demo I set the x to some fixed value because I am not sure if your chart should be responsive or not. In case of the responsive chart, I encourage to use the render callback https://api.highcharts.com/highcharts/chart.events.render to calculate datalabels position after each resizes.
API: https://api.highcharts.com/highcharts/series.line.dataLabels.x
API: https://api.highcharts.com/highcharts/series.line.dataLabels.formatter
I am plotting a 3D line chart over time. Each time the count changes at the end of the loop, a new point is plotted for each series. Is there a way to set the value of the legend as the value of count in my example code? The count represents hours since the start of an experiment, so being able to display this is necessary. Thanks!
events: {
load: function() {
var thischart = this;
for (i = 0; i < allpoints.length; i++) {
thischart.addSeries({
enableMouseTracking: false,
lineWidth: 1,
marker: {
enabled: false
},
data: [0, 0, 0]
}, false)
thischart.redraw(false);
}
setInterval(function() {
if (count >= max_data_length) {
if (!pause_at_end) {
for (i = 0; i < allpoints.length; i++) {
thischart.series[i + marker_series_length].setData([0, 0, 0], false);
}
thischart.redraw(false);
count = 1;
} else {
is_paused = true;
document.getElementById('pauseit').value = "Unpause";
}
}
if (!is_paused) {
for (i = 0; i < allpoints.length; i++) {
if (allpoints[i].length > count) {
thischart.series[i + marker_series_length].addPoint([
allpoints[i][count][0], allpoints[i][count][2], allpoints[i][count][1]
], false);
}
}
thischart.redraw(false);
count = count + 4;
}
}, 10)
}
}
You can use series.update method to set new data and change the series name in legend:
chart: {
...,
events: {
load: function() {
var counter = 0,
series = this.series[0];
setInterval(function() {
counter++;
series.update({
data: getRandomData(),
name: 'Name ' + counter
});
}, 1000);
}
}
}
Live demo: https://jsfiddle.net/BlackLabel/7bq21tak/
API Reference: https://api.highcharts.com/class-reference/Highcharts.Series#update
Thanks ppotaczek! This pointed me in the right direction. I used chart.update instead to update the subtitle. Here is the code I used:
chart.update({
chart: {
inverted: false,
polar: false
},
subtitle: {
style: {
fontSize: '20px'
},
text:'Day:'+ countdays
}
});
We are going to buy a high chart.
We are going to implement the medical chart eeg chart on the web.
Can I implement the shape of an eeg chart with a high chart?
The EEG chart shows that the X axis is time and the Y axis
It has 19 channels with individual ranges.
https://www.researchgate.net/figure/Case-6-EEG-in-a-38-year-old-woman-with-refractory-complex-partial-seizures-and-left_fig3_233806823
By using Highcharts, you can create as many axes as you need. I have prepared a simple example with multiple yAxes and different ranges:
var series = [],
data,
seriesCount = 20,
pointsCount = 100,
axisTop = 50,
range,
axisHeight = 1100 / seriesCount,
yAxis = [];
for (var i = 0; i < seriesCount; i++) {
range = Math.round(Math.random() * 100);
data = [];
for (var j = 0; j < pointsCount; j++) {
data.push(Math.floor(Math.random() * range));
}
series.push({
data: data,
yAxis: i
});
yAxis.push({
title: {
text: ''
},
height: axisHeight,
top: axisTop,
offset: 0
});
axisTop += axisHeight + 12.5
}
Highcharts.chart('container', {
chart: {
height: 1500
},
series: series,
yAxis: yAxis
});
Live demo: http://jsfiddle.net/BlackLabel/425xctvw/
You can try for synchronized charts where x axis can be common across all the graphs.
https://www.highcharts.com/demo/synchronized-charts
Reference Code: https://jsfiddle.net/gh/get/library/pure/highcharts/highcharts/tree/master/samples/highcharts/demo/synchronized-charts/
/*
The purpose of this demo is to demonstrate how multiple charts on the same page
can be linked through DOM and Highcharts events and API methods. It takes a
standard Highcharts config with a small variation for each data set, and a
mouse/touch event handler to bind the charts together.
*/
/**
* In order to synchronize tooltips and crosshairs, override the
* built-in events with handlers defined on the parent element.
*/
$('#container').bind('mousemove touchmove touchstart', function (e) {
var chart,
point,
i,
event;
for (i = 0; i < Highcharts.charts.length; i = i + 1) {
chart = Highcharts.charts[i];
// Find coordinates within the chart
event = chart.pointer.normalize(e.originalEvent);
// Get the hovered point
point = chart.series[0].searchPoint(event, true);
if (point) {
point.highlight(e);
}
}
});
/**
* Override the reset function, we don't need to hide the tooltips and
* crosshairs.
*/
Highcharts.Pointer.prototype.reset = function () {
return undefined;
};
/**
* Highlight a point by showing tooltip, setting hover state and draw crosshair
*/
Highcharts.Point.prototype.highlight = function (event) {
event = this.series.chart.pointer.normalize(event);
this.onMouseOver(); // Show the hover marker
this.series.chart.tooltip.refresh(this); // Show the tooltip
this.series.chart.xAxis[0].drawCrosshair(event, this); // Show the crosshair
};
/**
* Synchronize zooming through the setExtremes event handler.
*/
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' }
);
}
}
});
}
}
// Get the data. The contents of the data file can be viewed at
$.getJSON(
'https://cdn.rawgit.com/highcharts/highcharts/057b672172ccc6c08fe7dbb27fc17ebca3f5b770/samples/data/activity.json',
function (activity) {
$.each(activity.datasets, function (i, dataset) {
// Add X values
dataset.data = Highcharts.map(dataset.data, function (val, j) {
return [activity.xData[j], val];
});
$('<div class="chart">')
.appendTo('#container')
.highcharts({
chart: {
marginLeft: 40, // Keep all charts left aligned
spacingTop: 20,
spacingBottom: 20
},
title: {
text: dataset.name,
align: 'left',
margin: 0,
x: 30
},
credits: {
enabled: false
},
legend: {
enabled: false
},
xAxis: {
crosshair: true,
events: {
setExtremes: syncExtremes
},
labels: {
format: '{value} min'
}
},
yAxis: {
title: {
text: null
}
},
tooltip: {
positioner: function () {
return {
// right aligned
x: this.chart.chartWidth - this.label.width,
y: 10 // align to title
};
},
borderWidth: 0,
backgroundColor: 'none',
pointFormat: '{point.y}',
headerFormat: '',
shadow: false,
style: {
fontSize: '18px'
},
valueDecimals: dataset.valueDecimals
},
series: [{
data: dataset.data,
name: dataset.name,
type: dataset.type,
color: Highcharts.getOptions().colors[i],
fillOpacity: 0.3,
tooltip: {
valueSuffix: ' ' + dataset.unit
}
}]
});
});
}
);
.chart {
min-width: 320px;
max-width: 800px;
height: 220px;
margin: 0 auto;
}
</style>
<!-- http://doc.jsfiddle.net/use/hacks.html#css-panel-hack -->
<meta name="viewport" content="width=device-width, initial-scale=1" />
<style>
<script src="https://code.jquery.com/jquery-3.1.1.min.js"></script>
<script src="https://code.highcharts.com/highcharts.js"></script>
<div id="container"></div>
<script type="text/javascript">
// Load the Visualization API and the piechart package.
google.load('visualization', '1.0', { 'packages': ['corechart'] });
// Set a callback to run when the Google Visualization API is loaded.
// Callback that creates and populates a data table,
// instantiates the pie chart, passes in the data and
// draws it.
$(document).ready(function () {
google.setOnLoadCallback(drawChartCountry);
$("a[href='#tab11']").on('shown.bs.tab', function (e) {
google.load('visualization', '1', {
packages: ['corechart'],
callback: drawChartCountry
});
});
$("a[href='#tab21']").on('shown.bs.tab', function (e) {
google.load('visualization', '1', {
packages: ['corechart'],
callback: drawChartDevice
});
});
$("a[href='#tab31']").on('shown.bs.tab', function (e) {
google.load('visualization', '1', {
packages: ['corechart'],
callback: drawChartVersion
});
});
function drawChartCountry() {
$.post('/AppDashboard/GetCountryChart', {},
function (data) {
var tdata = new google.visualization.DataTable();
tdata.addColumn('string', 'Country');
tdata.addColumn('number', 'No.of Users');
for (var i = 0; i < data.length; i++) {
tdata.addRow([data[i].Name, data[i].Value]);
}
var options = {
title: "",
is3D: true,
//pieSliceText: 'label',
pieStartAngle: 100,
'width': 450,
'height': 350
};
var chart = new google.visualization.PieChart(document.getElementById('chart_country'));
chart.draw(tdata, options);
});
}
function drawChartDevice() {
$.post('/AppDashboard/GetDeviceChart', {},
function (data) {
var devicedata = new google.visualization.DataTable();
devicedata.addColumn('string', 'Device');
devicedata.addColumn('number', 'No.of Users');
for (var i = 0; i < data.length; i++) {
devicedata.addRow([data[i].Name, data[i].Value]);
}
var options = {
title: "",
is3D: true,
pieStartAngle: 100,
'width': 450,
'height': 350
};
var chart = new google.visualization.PieChart(document.getElementById('chart-device'));
chart.draw(devicedata, options);
});
}
function drawChartVersion() {
$.post('/AppDashboard/GetVersionChart', {},
function (data) {
var versiondata = new google.visualization.DataTable();
versiondata.addColumn('string', 'Version');
versiondata.addColumn('number', 'No.of Users');
for (var i = 0; i < data.length; i++) {
versiondata.addRow([data[i].Name, data[i].Value]);
}
var options = {
title: "",
is3D: true,
//pieSliceText: 'label',
pieStartAngle: 100,
'width': 450,
'height': 350
};
var chart = new google.visualization.PieChart(document.getElementById('chart-version'));
chart.draw(versiondata, options);
});
}
});
I have set google chart inside a widget but the sad part is responsive is not working.When i resize it to mobile size the chart data exceeds my widget.Kindly help me with this and if you need more info lemme know,thanks in advance :)
Im using multiple highchart chart inside my page and i use addpoint function to update the chart.
the problem is after some time the chart will be compressed into less than a half of original chart size.
i captured my screen which could be found here for make the problem clear:
http://www.screenr.com/f3E7
sample chart generation code:
$(function () {
$(document).ready(function() {
Highcharts.setOptions({
global: {
useUTC: false
}
});
//var chart;
chart = new Highcharts.Chart({
chart: {
renderTo: 'ch_trafficio',
type: 'spline',
marginRight: 10,
events: {
load: function() {
// set up the updating of the chart each second
var series = this.series[0];
var series1= this.series[1];
}
}
},
title: {
text: ''
},
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);
}
},
plotOptions : {
area : {
lineWidth : 1,
marker : {
enabled : false,
states : {
hover : {
enabled : true,
radius : 5
}
}
},
shadow : false,
states : {
hover : {
lineWidth : 1
}
}
}
},
legend: {
enabled: true
},
exporting: {
enabled: true
},
series: [{
name: 'InBound',
type : "area",
color: '#89A54E',
data: (function() {
// generate an array of random data
var data = [],
time = (new Date()).getTime(),
i;
for (i = -119; i <= 0; i++) {
data.push({
x: time + i * 1000,
y: Math.random()
});
}
return data;
})()
},{
name: 'OutBound',
type : "area",
color: '#AA4643',
data: (function() {
// generate an array of random data
var data = [],
time = (new Date()).getTime(),
i;
for (i = -119; i <= 0; i++) {
data.push({
x: time + i * 1000,
y: Math.random()
});
}
return data;
})()
}
]
});
chart update functions:
chart.series[0].addPoint([x,data.oid1], false, true);
chart.series[1].addPoint([x,data.oid2], true, true);
chart1.series[0].addPoint([x,data.oid5], true, true);
chart2.series[0].addPoint([x,data.oid3], false, true);
chart2.series[1].addPoint([x,data.oid4], true, true);
chart3.series[0].addPoint([x,data.oid7], true, true);
thanks in advance
you need to add a shifting parameter for your points to shift over the chart
var series = chart.series[0],
shift = series.data.length > 100; // shift if the series is longer than 100
and to change adding point like below
chart.series[0].addPoint([x,data.oid1], true, shift);
example here