How to create dynamic update spline Highcharts chart? - arrays

I'm scratching my head for few days with no luck.
I would like to create Highcharts chart that shows data from my database.
I did some charts without problem, but I'm stuck on chart that shows some points (20 or more) and scrolls spline chart to the left showing new data.
I have created two arrays jfDatumi (containing times in format hh:mm from database) (12:10) and jfTempOuts containing temperature values (-2.3…).
Now I want to show those data on chart that moves every second adding new point (time, temperature) but showing only 20 points at the time.
When it comes to the end of an array I would like chart to start over from first point.
It's like this chart https://www.highcharts.com/demo/dynamic-update but I want X axis to show my times from my array (jfDatumi) not current time (without var x = (new Date()).getTime())
Can anyone please help me? I'm pulling my hair out because of this.
Below is my current code.
$(function ()
{
$(document).ready(function ()
{
Highcharts.setOptions(
{
global:
{
useUTC: false,
}
});
$('#test').highcharts(
{
credits:
{
text: 'By: http://amicus.ba',
href: 'http://amicus.ba'
},
chart:
{
type: 'spline',
animation: Highcharts.svg, // Ne animiraj u starom IE
marginRight: 1,
events:
{
load: function ()
{
// Postaviti update grafikona svake sekunde
var series = this.series[0];
setInterval(function ()
{
var x = jfDatumi, // Trenutno vrijeme
//var x = new Date(), // current time
//x=jfDatumi,
//var x = (new Date()).getTime(),
y = jfTempOuts;
series.addPoint([x, y], true, true);
}, 1500);
}
}
},
title:
{
text: 'Test Vanjska temperatura [°C]'
},
xAxis:
{
type: 'datetime',
categories: jfDatumi,
minRange: 1,
title:
{
text: 'Vrijeme'
},
tickPixelInterval: 1,
},
yAxis:
{
minRange: 0,
title:
{
text: '[°C]'
},
plotLines: [
{
value: 0,
width: 2,
color: '#808080'
}]
},
tooltip:
{
formatter: function ()
{
return '<b>' + this.series.name + '</b><br/>' +
Highcharts.numberFormat(this.y, 2) + ' [°C]';
}
},
legend:
{
enabled: false
},
exporting:
{
enabled: false
},
series: [
{
name: 'Vanjska temperatura',
//data: (jfTempOuts)
data: (function () {
// generate an array of random data
var data = [],
time = jfDatumi,
i;
for (i = 0; i <= 20; i += 1) {
data.push([
time,
jfTempOuts
]);
}
return data;
}())
}]
});
});
});
At this time, i have my times from jfDatumi, but NO temperature values from jfTempOuts.

I have found solution by myself.
Here is code that works for me:
// Animirani grafikon vanjske temperature
$(function ()
{
$(document).ready(function ()
{
Highcharts.setOptions(
{
global:
{
useUTC: false,
}
});
$('#vanjskaTemp').highcharts(
{
credits:
{
text: 'By: http://amicus.ba',
href: 'http://amicus.ba'
},
chart:
{
type: 'spline',
animation: Highcharts.svg, // Ne animiraj u starom IE
marginRight: 1,
events:
{
load: function ()
{
// Postaviti update grafikona po podešenom intervalu
var series = this.series[0];
var br=20; // Start brojača za indeksiranje niza temperatura (podešeno u: for (i = 0; i <= 20; i += 1))
setInterval(function ()
{
br=br+1; // Brojač za indeksiranje niza temperatura
// Zaustavljanje skrolovanja ako je dostignut kraj niza jfTempOuts
if (br<=jfTempOuts.length-1)
{
var x = jfSamoVrijeme; // Vrijeme za X osu (zaustavi se osa ako se ne očitava)
y = jfTempOuts[br]; // Vrijednosti za Y osu (Vanjske temperature)
series.addPoint([x, y], true, true);
}
else
{
//document.write("BR:<li>"+br+"</li>");
}
}, 1500);
}
}
},
title:
{
text: 'Vanjska temperatura [°C]'
},
xAxis:
{
type: 'datetime',
categories: jfSamoVrijeme,
minRange: 1,
title:
{
text: 'Vrijeme'
},
tickPixelInterval: 1,
},
yAxis:
{
minRange: 0,
title:
{
text: 'Vanjska temperatura [°C]'
},
plotLines: [
{
value: 0,
width: 0.5,
color: '#808080'
}]
},
tooltip:
{
formatter: function ()
{
return '<b>' + this.series.name + '</b><br/>' +
Highcharts.numberFormat(this.y, 2) + ' [°C]';
}
},
legend:
{
enabled: false
},
exporting:
{
enabled: false
},
series: [
{
name: 'Vanjska temperatura',
data: (function () {
var data = [],
time = jfSamoVrijeme,
i;
for (i = 0; i <= 20; i += 1) {
data.push([
time,
jfTempOuts
]);
}
return data;
}())
}]
});
});
});
// Kraj animiranog grafikona vanjske temperature
Only problem I have now is that I CAN'T show first 20 points, but not so important.
I will find solution for that problem too.
My chart

Related

How to aligment nodes with highcharts

I am trying to alignment nodes, But I cant see any options how to do it,
Currently my code is
Highcharts.chart('container', {
chart: {
type: 'networkgraph',
plotBorderWidth: 1
},
title: {
text: 'Trans-Siberian Railway'
},
subtitle: {
text: 'Barnes-Hut approximation'
},
plotOptions: {
networkgraph: {
layoutAlgorithm: {
enableSimulation: false,
linkLength: 100,
integration: 'verlet',
approximation: 'barnes-hut',
gravitationalConstant: 4,
// Elastic like forces:
attractiveForce: function (d, k) {
return (k - d) / d;
},
/* repulsiveForce: function (d, k) {
return Math.min((k * k) / (d), 100);
} */
}
}
},
series: [{
marker: {
radius: 3,
lineWidth: 1
},
dataLabels: {
enabled: true,
linkFormatter: function () {
return '';
}
},
nodes: [
{
id: 'test',
marker: {
radius: 10
}
},
{
id: 'Moscow',
marker: {
radius: 10
}
}, {
id: 'Beijing',
marker: {
radius: 10
}
},
{
id: 'Brussels',
marker: {
radius: 10
}
},
{
id: 'Bangkok',
marker: {
radius: 10
}
}],
data: [
{ from: 'Bangkok', to: 'Beijing', color: 'blue' },
{ from: 'Moscow', to: 'Beijing', color: 'blue' },
{ from: 'test', to: 'Moscow', color: 'blue' },
{ from: 'Beijing', to: 'Brussels', color: 'blue' },
]
}]
});
the result of code is:
and its still not alignment the wanted results is
You should be able to set fixed positions in the networkgraph chart by using the initialPositions callback. To work it well you need also to set maxIterations to some small value, like 1.
See demo
initialPositions: function() {
var chart = this.series[0].chart,
width = chart.plotWidth,
height = chart.plotHeight;
this.nodes.forEach(function(node, i) {
if(i === 0){
node.plotX = 600;
node.plotY = 100;
}
if(i === 1) {
node.plotX = 350;
node.plotY = 100;
}
if(i === 2){
node.plotX = 200;
node.plotY = 0;
}
if(i === 3) {
node.plotX = 0;
node.plotY = 0;
}
if(i === 4) {
node.plotX = 200;
node.plotY = 200;
}
});
}
API: https://api.highcharts.com/highcharts/series.networkgraph.layoutAlgorithm.maxIterations
API: https://api.highcharts.com/highcharts/series.networkgraph.layoutAlgorithm.initialPositions
If you want to have those points not draggable, maybe an easier solution will be to render regular line chart?
Demo: https://jsfiddle.net/BlackLabel/06Lkgwbz/

How to drilldown to third level when its data is determined by second's click event?

So, I have been trying to use drill down to multiple levels, problem I am facing is that I couldn't drill down to the third level because the data will be fetched by ajax upon second drilldown's selection.
for example, refer to this link:
https://codepen.io/ajaymalhotra15/pen/aZpxXq
drilldown example
Here, the third level is possible because he has the data already, but mine will be depended on seconds selection.
So, how to make this happen, where am I supposed to call the ajax request and set the drill down series data dynamically?
EDIT:
Highcharts.chart("energy_chart", {
chart: {
type: "column",
spacingBottom: 15,
spacingTop: 10,
spacingLeft: 10,
spacingRight: 10,
backgroundColor: "#f2f2f2",
events: {
load: function() {
var fin = new Date();
var finDate = fin.getDate();
var finMonth = fin.getMonth();
var finYear = fin.getFullYear();
var ini = new Date();
ini.setFullYear(ini.getFullYear() - 1);
var iniDate = ini.getDate();
var iniMonth = ini.getMonth();
var iniYear = ini.getFullYear();
if (this.yAxis[0].dataMax == 0) {
this.yAxis[0].setExtremes(null, 1);
}
//this.yAxis.set
this.xAxis[0].setExtremes(
Date.UTC(iniYear, iniMonth, iniDate),
Date.UTC(finYear, finMonth, finDate)
);
},
drilldown: function(e) {
var charts_this = this;
var inidrillDate = new Date(e.point.x);
setTimeout(function() {
inidrillDate.setDate(0);
inidrillDate.setMonth(inidrillDate.getMonth());
var DateinidrillDate = inidrillDate.getDate();
var MonthinidrillDate = inidrillDate.getMonth();
var YearinidrillDate = inidrillDate.getFullYear();
var findrillDate = inidrillDate;
findrillDate.setMonth(findrillDate.getMonth() + 1);
findrillDate.setDate(findrillDate.getDate() - 1);
var DatefindrillDate = findrillDate.getDate();
var MonthfindrillDate = findrillDate.getMonth();
var YearfindrillDate = findrillDate.getFullYear();
charts_this.xAxis[0].setExtremes(
Date.UTC(
YearinidrillDate,
MonthinidrillDate,
DateinidrillDate
),
Date.UTC(
YearfindrillDate,
MonthfindrillDate,
DatefindrillDate
)
);
if (charts_this.yAxis[0].dataMax === 0) {
charts_this.yAxis[0].setExtremes(null, 1);
}
}, 0);
}
}
},
title: {
text: '<p className="energy_gen">Energy Generated</p>'
},
exporting: { enabled: false },
xAxis: {
type: "datetime",
labels: {
step: 1
},
dateTimeLabelFormats: {
day: "%e"
}
},
yAxis: {
title: {
text: "kWh"
}
},
credits: {
enabled: false
},
plotOptions: {
series: {
cursor: "pointer",
dataLabels: {
enabled: true,
format: "{point.y}"
},
color: "#fcd562",
point:{
events:{
click:function(event){
if(this.options!=null){
var dayOfYear=new Date(this.x).getFullYear() +"-"+(new Date(this.x).getMonth()+1)+"-"+new Date(this.x).getDate();
var formatted_date = new Date(this.x).getDate() + " " + months[(new Date(this.x).getMonth())] +" "+ new Date(this.x).getFullYear();
// document.getElementById('chart_date_id').innerHTML = formatted_date; //setting modal title with current date
$('#container').bind('mousemove touchmove touchstart', function (e) {
var chart,
point,
i,
event;
var sync_charts = $('.chart');
for (i = 0; i < sync_charts.length; i = i + 1) {
var chart_1 = sync_charts[i];
var chart_2 = chart_1.getAttribute('data-highcharts-chart');
chart=Highcharts.charts[chart_2];
event = chart.pointer.normalize(e.originalEvent);
point = chart.series[0].searchPoint(event, true);
if (point) {
point.highlight(e);
}
}
});
Highcharts.Pointer.prototype.reset = function () {
return undefined;
};
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
};
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' }
);
}
}
});
}
}
axios({
url: config.fvcstat,
method: "POST",
data: {
"customerId":self.props.location.state.detail.customerId,"rmsVendorId":self.props.location.state.detail.rmsVendorId,
"date":dayOfYear,
"powerType":self.props.location.state.detail.powerType
},
headers: {
"Content-Type": "application/json"
}
}).then((res)=>{
let activity = fvc.data;
if($('.chart')){
$('.chart').remove();
}
$.each(activity.datasets, function (i, dataset) {
console.log(1)
var chartDiv = document.createElement('div');
chartDiv.className = 'chart';
document.getElementById('container').appendChild(chartDiv);
Highcharts.chart(chartDiv,{
chart: {
},
plotOptions: {
series: {
marker:{
enabled:false
}
}
},
exporting: { enabled: false },
title: {
text: dataset.name,
align: 'left',
margin: 0,
x: 30
},
credits: {
enabled: false
},
legend: {
enabled: false
},
xAxis: {
crosshair:{ width: 3},
events: {
setExtremes: syncExtremes
},
labels: {
format: '{value}'
},categories: activity.xData
},
yAxis: {
title: {
text: null
}
},
series: [{
data: dataset
}],
tooltip: {
positioner: function () {
return {
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
}
}]
});
});
})
}
}
}
}
}
},
tooltip: {
formatter: function() {
if (this.point.options.drilldown) {
return (
"Energy generated: <b> " +
this.y +
"</b> kWh " +
"<br>" +
Highcharts.dateFormat("%b %Y", new Date(this.x))
);
} else {
return (
"Energy generated: <b> " +
this.y +
"</b> kWh " +
"<br>" +
Highcharts.dateFormat("%e %b %Y", new Date(this.x))
);
}
}
},
series: [{'data':obj.data,'name':obj.name,"color":"#4848d3"}],
drilldown: {
series: obj.data
}
});
So, here if you notice in plotoptions i am trying to create a whole new chart which is a synced line charts showing frquency, voltage and current.
But, i am guessing my approach is not correct as i am plotting a new highchart.
So, how do i make this synced line chart part of my drilldown.
let me know if you require any help in understanding.
I will suggest first minimize the plotoption. Then expand for further fuck up :P
Thanks.
You can put all your logic to get the third level data and to create a drilldown series in drilldown event:
chart: {
type: 'column',
events: {
drilldown: function(e) {
if (!thirdLevel.length) {
// get data
}
if (!e.seriesOptions) {
var chart = this,
drilldowns = {
'Animals': {
name: 'Animals',
data: [
['Cows', 2],
['Sheep', 3]
]
},
'Fruits': {
name: 'Fruits',
data: [
['Apples', 5],
['Oranges', 7],
['Bananas', 2]
]
},
'Cars': {
name: 'Cars',
data: [
['Toyota', 1],
['Volkswagen', 2],
['Opel', 5]
]
}
},
series = drilldowns[e.point.name];
chart.addSingleSeriesAsDrilldown(e.point, series);
chart.applyDrilldown();
}
}
}
}
Live demo : http://jsfiddle.net/BlackLabel/86v3L4ft/
API Reference: https://api.highcharts.com/highcharts/chart.events.drilldown

Highcharts/Highstock with React and Boost not working (very high cpu usage)

I'm implementing this example http://jsfiddle.net/gh/get/library/pure/highcharts/highcharts/tree/samples/highcharts/boost/line-series-heavy-dynamic/ but with React.
import React from 'react'
import Highcharts from 'highcharts'
import HighchartsBoost from 'highcharts/modules/boost'
HighchartsBoost(Highcharts)
Highcharts.setOptions({
global: {
useUTC: false
}
});
class Plot extends React.Component {
constructor(props) {
super(props)
this.n = 20
this.s = 600
this.addPoint = this.addPoint.bind(this)
}
componentDidMount() {
var series = getSeries(this.n, this.s)
console.time('line');
this.chart = Highcharts.chart('hc-container', {
boost: {
enabled: true,
seriesThreshold: 1
},
chart: {
animation: false,
zoomType: 'x'
},
title: {
text: 'Highcharts drawing ' + (this.n * this.s) + ' points across ' + this.s + ' series'
},
navigator: {
xAxis: {
ordinal: false//,
},
yAxis: {
},
series: {
color: null
}
},
legend: {
enabled: false
},
xAxis: {
ordinal: false
},
yAxis: {
},
subtitle: {
text: 'Using the Boost module'
},
tooltip: {
valueDecimals: 2,
shared: false
},
series: series
});
console.timeEnd('line');
setInterval(this.addPoint, 1000);
}
addPoint() {
++this.n;
if (!this.chart.series) return
this.chart.series.forEach(se => {
var x = this.n
var y = 2 * Math.sin(x / 100) + Math.random()
//Yeah...
if (se.options.className === "highcharts-navigator-series") {
return;
}
se.addPoint([x, y], false, true, false);
// se.options.data.push([x, y]);
// se.options.data.shift();
// se.isDirty = true;
// se.isDirtyData = true;
});
this.chart.redraw();
}
render() {
return <div id='hc-container' />
}
}
export default Plot
function getData(n) {
var arr = [],
i;
for (i = 0; i < n; i = i + 1) {
arr.push([
i,
2 * Math.sin(i / 100) + Math.random()
]);
}
return arr;
}
function getSeries(n, s) {
var i = 0,
r = [];
for (; i < s; i++) {
r.push({
data: getData(n),
animation: false,
lineWidth: 2,
boostThreshold: 1,
turboThreshold: 1,
showInNavigator: true,
requireSorting: false
});
}
return r;
}
I don't think boost module is working this way because CPU goes very very high.
I their example (running in chrome) CPU is around 0.x
But in my implementation it goes to 120 most of the time.

Angular js - Highcharts how to set option setInterval to update chart while data is null?

I'm using HighChart library to draw live chart with data return from serve. I set time reload is 3s, but data from serve return null, my Chart drawn in the blank.
I want if data return is null, my chart will wait for new data to update..
Tks all.
my image app:
My file js:
$http({
method: 'GET',
url: 'https://api.coinbase.com/v2/prices/BTC-USD/buy'
}).then(function successCallback(response) {
$scope.dataChart = response.data.data.amount
//start config for chart
Highcharts.stockChart('container', {
chart: {
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 - value x
// y = Math.round(Math.random() * 20); // value y
y = $scope.dataChart
series.addPoint([x, y], true, true);
}, 3000);
alert($scope.dataChart)
}
}
},
rangeSelector: {
buttons: [{
count: 1,
type: 'minute',
text: '1M'
}, {
count: 5,
type: 'minute',
text: '5M'
}, {
type: 'all',
text: 'All'
}],
inputEnabled: false,
selected: 0
},
title: {
text: ''
},
exporting: {
enabled: false
},
series: [{
name: 'Fake Data: (Random)',
data: (function() {
// generate an array of random data
var data = [],
time = (new Date()).getTime(),
i;
for (i = -999; i <= 0; i += 1) {
data.push([
time + i * 1000,
//gioi han truc Y
Math.round(Math.random() * 1270)
]);
}
return data;
}())
}]
});
//end chart
}, function errorCallback(response) {
//alert('error')
$scope.myWelcome = "error"
});
Highcharts.setOptions({
global: {
useUTC: false
}
});

Integrating Sparkline High Chart in Angular Nested UI Grid

I am trying to integrate spark line high chart in Angularjs nested UI grid. I have implemented Highcharts.SparkLine function within row expand event in UI grid. Is there any function like rowExpandComplete in Angular UiGrid?
gridApi.expandable.on.rowExpandedStateChanged($scope, function (row) {
if (row.isExpanded) {
var str = "10,12,45,34";
$scope.template = "<table id='table-sparkline'><tbody id='tbody-sparkline'><tr><td data-sparkline=" + str + "> </td> </tr> </tbody></table>";
row.entity.subGridOptions = {
columnDefs: [
{ name: 'name' },
{ name: 'gender', cellTemplate: $scope.template },
{ name: 'company' }
]
};
$http.get('https://cdn.rawgit.com/angular-ui/ui-grid.info/gh-pages/data/100.json')
.success(function (data) {
row.entity.subGridOptions.data = data;
/**
* 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 (a, b, c) {
var hasRenderToArg = typeof a === 'string' || a.nodeName,
options = arguments[hasRenderToArg ? 1 : 0],
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'
},
// small optimalization, saves 1-2 ms each sparkline
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 hasRenderToArg ?
new Highcharts.Chart(a, options, c) :
new Highcharts.Chart(options, b);
};
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,
$td,
stringdata,
arr,
data,
chart;
for (i = 0; i < len; i += 1) {
$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 += 1;
// 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();
});
}
});
But it is triggering only for second time when we expand the row. Can any one tell me where I am going wrong. I have created the plunker for the same.

Resources