I'm coding a dynamic chart (a monitor app) which xAxis is datetime type, every three seconds I pull data from DB and add new point for each serie (so far so good). The problem comes with tick, every time I add a new point all ticks take the current time instead of keeping their original value when they were created this is my code
var chart1Obj = {
chart: {
renderTo: 'welcome-chart',
type: 'line',
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;
setInterval(function () {
Meteor.call("getGraphData", function (error, json) {
if (error) {
console.error("Welcome.graphData() failed\n", error);
} else {
temp = JSON.parse(json);
series[0].addPoint([temp.running], true, true);
series[1].addPoint([temp.queued], true, true);
series[2].addPoint([temp.suspended], true, true);
}
});
}, 3000);
}
}
},
title: {
text: 'Job monitoring'
},
xAxis: {
type: 'datetime',
tickPixelInterval: 150,
labels: {
formatter: function () {
var myTime = new Date();
return Highcharts.dateFormat('%H:%M:%S', myTime.getTime());
}
}
},
yAxis: {
title: {
text: 'Number of Task'
},
floor: 0,
plotLines: [{
value: 0,
width: 1,
color: '#808080'
}]
},
exporting: {
enabled: false
},
series: [{
name: 'Running',
data: [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
width: 1,
color: '#00FF00'
}, {
name: 'Queued',
width: 2,
data: [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
color: '#FFFF00'
}, {
name: 'Suspended',
width: 3,
data: [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
color: '#FF0000'
}]
};
Highcharts.setOptions({
global: {
useUTC: false,
}
});
var chart1 = new Highcharts.Chart(chart1Obj);
so the question is, what am I doing wrong? or what am I missing?
It's caused by this lines:
labels: {
formatter: function () {
var myTime = new Date();
return Highcharts.dateFormat('%H:%M:%S', myTime.getTime());
}
}
new Date() will create date object with actual time. Then you use that date for each label in tick labels. simply use:
return Highcharts.dateFormat('%H:%M:%S', this.value);
Related
We are developing some charts using Highcharts.
And we are using the series.events.afterAnimate in combination with an xAxis.max value.
But when we have for example points from Januari until September, but with an xAxis.max value until December the afterAnimate function is called when it reached December we guess..
But we would like have a callback when all the valid points are drawn, and not we it reaches its max value...
is this possible?
That happens because the clipPath width is by default equal width of the plot area. To change it you can overwrite Highcharts.Series.animate method and set clipPath width equal width of the particular series.
EDIT:
Also, note that when the width of the clipPath is shorter and the duration of the animation is the same the animation will be much slower. To make it look better the time has to be shortened - it can be calculated depending on series width and updated in chart load event.
Check demo and code posted below:
Code:
(function(H) {
H.Series.prototype.animate = function(init) {
var series = this,
chart = series.chart,
clipRect,
animation = H.animObject(series.options.animation),
sharedClipKey;
// Initialize the animation. Set up the clipping rectangle.
if (init) {
series.setClip(animation);
// Run the animation
} else {
sharedClipKey = this.sharedClipKey;
clipRect = chart[sharedClipKey];
if (clipRect) {
clipRect.animate({
width: series.group.getBBox().width,
x: 0
}, animation);
}
if (chart[sharedClipKey + 'm']) {
chart[sharedClipKey + 'm'].animate({
width: chart.plotSizeX + 99,
x: 0
}, animation);
}
// Delete this function to allow it only once
series.animate = null;
}
}
})(Highcharts);
Highcharts.setOptions({
chart: {
events: {
load: function() {
var chart = this,
series = chart.series[0],
seriesWidth = series.graph.getBBox().width,
duration = (seriesWidth / chart.plotWidth) * series.options.animation.duration;
chart.series[0].update({
animation: {
duration: duration
}
});
}
}
},
plotOptions: {
series: {
animation: {
duration: 2000
}
}
}
});
Highcharts.chart('container', {
title: {
text: 'Chart with half data but with max data'
},
subtitle: {
text: 'A label should appear when all points are drawn'
},
xAxis: {
type: 'datetime',
min: Date.UTC(2019, 0, 1),
max: Date.UTC(2019, 11, 31),
tickInterval: 2592000000, // month
},
plotOptions: {
series: {
events: {
afterAnimate: function() {
this.chart.renderer.label(this.name + ' has appeared', 100, 70)
.attr({
padding: 10,
fill: Highcharts.getOptions().colors[0]
})
.css({
color: 'white'
})
.add();
}
}
}
},
series: [{
data: [{
x: Date.UTC(2019, 0, 1),
y: 29.9
},
{
x: Date.UTC(2019, 1, 1),
y: 139.9
},
{
x: Date.UTC(2019, 2, 1),
y: 59.9
},
{
x: Date.UTC(2019, 3, 1),
y: 19.9
},
]
}]
});
Highcharts.chart('container2', {
title: {
text: 'Chart with full data'
},
subtitle: {
text: 'A label should appear on the plot area after animate'
},
xAxis: {
type: 'datetime',
min: Date.UTC(2019, 0, 1),
max: Date.UTC(2019, 11, 31),
tickInterval: 2592000000, // month
},
plotOptions: {
series: {
events: {
afterAnimate: function() {
this.chart.renderer.label(this.name + ' has appeared', 100, 70)
.attr({
padding: 10,
fill: Highcharts.getOptions().colors[0]
})
.css({
color: 'white'
})
.add();
}
}
}
},
series: [{
data: [{
x: Date.UTC(2019, 0, 1),
y: 29.9
},
{
x: Date.UTC(2019, 1, 1),
y: 139.9
},
{
x: Date.UTC(2019, 2, 1),
y: 59.9
},
{
x: Date.UTC(2019, 3, 1),
y: 19.9
},
{
x: Date.UTC(2019, 4, 1),
y: 29.9
},
{
x: Date.UTC(2019, 5, 1),
y: 139.9
},
{
x: Date.UTC(2019, 6, 1),
y: 59.9
},
{
x: Date.UTC(2019, 7, 1),
y: 19.9
},
{
x: Date.UTC(2019, 8, 1),
y: 29.9
},
{
x: Date.UTC(2019, 9, 1),
y: 139.9
},
{
x: Date.UTC(2019, 10, 1),
y: 59.9
},
{
x: Date.UTC(2019, 11, 1),
y: 19.9
},
]
}]
});
<script src="https://code.highcharts.com/highcharts.js"></script>
<div id="container" style="height: 400px"></div>
<div id="container2" style="height: 400px"></div>
Demo:
https://jsfiddle.net/BlackLabel/gj7eqkv8/
API reference:
https://api.highcharts.com/highcharts/chart.events.load
I want to show the value between the green and yellow and red plotBands.
in the example attached i want to show the values 135,172 (where the color are changing)
yAxis: {
min: 0,
max: 200,
minorTickInterval: 'auto',
minorTickWidth: 1,
minorTickLength: 10,
minorTickPosition: 'inside',
minorTickColor: '#666',
tickPixelInterval: 30,
tickWidth: 2,
tickPosition: 'inside',
tickLength: 10,
tickColor: '#666',
labels: {
step: 2,
rotation: 'auto'
},
title: {
text: 'km/h'
},
plotBands: [{
from: 0,
to: 135,
color: '#55BF3B' // green
}, {
from: 135,
to: 172,
color: '#DDDF0D' // yellow
}, {
from: 172,
to: 200,
color: '#DF5353' // red
}]
},
Working Example In JSFiddle
You can use tickPositioner function to define which ticks will be shown on the chart:
tickPositioner: function() {
var plotBands = this.options.plotBands,
ticks = [],
i = 0;
for (i; i <= 200; i += 20) {
ticks.push(i);
}
for (i = 0; i < plotBands.length - 1; i++) {
ticks.push(plotBands[i].to)
}
return ticks;
}
Live demo: https://jsfiddle.net/BlackLabel/1kpt7dws/
API: https://api.highcharts.com/highcharts/yAxis.tickPositioner
i have a gauge charts with defined tick positions and want to show some text labels there. e. g.:
-300 => Text 1
-200 => Text 2
-100 => Text 3
...
Is there a way to do that? Here's a fiddle of the chart.
jsfiddle.net/r8d3jnx6/
$('#container').highcharts({
chart: {
type: 'gauge',
alignTicks: false,
plotBackgroundColor: null,
plotBackgroundImage: null,
plotBorderWidth: 0,
plotShadow: false
},
title: {
text: null
},
tooltip: {
enabled: false
},
pane: {
startAngle: -70,
endAngle: 70,
background: null
},
plotOptions: {
gauge: {
dial: {
baseWidth: 2,
baseLength: '100%',
radius: '100%',
rearLength: 0
},
pivot: {
radius: 5
},
dataLabels: {
enabled: false
}
}
},
yAxis: [ {
min: -300,
max: 500,
tickPositions: [-300, -200, -100, 0, 100, 200, 300, 400, 500],
lineColor: '#933',
lineWidth: 0,
minorTickPosition: 'outside',
tickLength: 0,
minorTickLength: 0,
labels: {
distance: 12,
//rotation: 'auto'
},
//categories: ['Grunder'],
offset: 0,
plotBands: [{
from: -300,
to: 2,
thickness: 15,
color: '#55BF3B'
}, {
from: 0,
to: 202,
thickness: 15,
color: {
linearGradient: {x1: 0, x2: 1, y1: 0, y2: 0},
stops: [
[0, '#55BF3B'], //green
[1, '#DDDF0D'] //yellow
]
}
}, {
from: 200,
to: 500,
thickness: 15,
color: {
linearGradient: {x1: 0, x2: 1, y1: 0, y2: 0},
stops: [
[0, '#DDDF0D'], //yellow
[1, '#ff0000'] //red
]
}
}]
}, {
min: -200,
max: 200,
lineColor: '#339',
tickColor: '#339',
minorTickColor: '#339',
offset: -100,
lineWidth: 2,
labels: {
enabled: false
},
tickLength: 5,
minorTickLength: 5,
endOnTick: false
}],
series: [{
data: [250]
}]
});
You can use a yAxis.labels.formatter function to check what the label value is, and return a text of your choice depending on that value.
To take your example, it could look like this:
yAxis: {
labels: {
formatter: function() {
if(this.value == -300) return '-300 => Text 1';
if(this.value == -200) return '-200 => Text 2';
if(this.value == -100) return '-100 => Text 3';
return this.value;
}
}
See this updated JSFiddle of how it works. As you can see you'll have to face the potential issue of labels overlapping the gauge, but you can fix that with distance, rotation and some other attributes (see API), depending on how your labels end up looking.
I have a problem when I update the gauge chart.
I add some life from my chart using this code:
$(function () {
$.getJSON('my.php', function(data) {
$('.container').highcharts({
chart: {
type: 'gauge',
borderWidth: 0,
width: 170,
height: 200,
marginTop: 0,
},
title: {
text: 'title',align: 'center',x: 0,y: 8,floating: true
},
pane: [{
startAngle: -120,
endAngle: 120,
background: [
{
backgroundColor: {linearGradient: { x1: 0, y1: 0, x2: 0, y2: 1 },stops: [[0, '#FFF'],[1, '#333']]},borderWidth: 0,outerRadius: '109%'
},
{
backgroundColor: {linearGradient: { x1: 0, y1: 0, x2: 0, y2: 1 },stops: [[0, '#333'],[1, '#FFF']]},borderWidth: 1,outerRadius: '107%'
},
{
backgroundColor: mybackgroundColor(data,100,120),
},
{
backgroundColor: '#DDD',borderWidth: 0,outerRadius: '105%',innerRadius: '103%'
}
]
}],
yAxis: {
min: 0,
max: 250,
minorTickWidth: 1,
minorTickLength: 10,
minorTickPosition: 'inside',
minorTickColor: '#666',
tickPixelInterval: 30,
tickWidth: 2,tickLength: 10,
tickColor: '#666',
labels: {
step: 2,
rotation: 'auto'
},
title: {
text:'km/h',
y : 85
},
plotBands: [
{
from: 0,
to: 100,
color: '#DDDF0D' /*yellow*/
},
{
from: 100,
to: 120,
color: '#55BF3B' /*green*/
},
{
from: 120,
to: 250,
color: '#DDDF0D' /*yellow*/
},
{
from: 30,
to: 35,
color: '#DF5353' /*red*/
}
]
},
series: [
{
name: 'speed',
data: data,
dataLabels: {
enabled: true,
style: {
fontWeight:'bold',
fontSize: '12px'
}
}
}
]
},
// Add some life
function (chart) {
if (!chart.renderer.forExport) {
setInterval(function () {
chart.series[0].color = "#000";
var point = chart.series[0].points[0];
$.getJSON('mydata.php', function(data) {
point.update(data);
});
}, 3000);
};
});
});
});
my function mybackgroundColor(data,100,120) define the pane backgroundColor, it depends the value of data.
When I update point ussing this part of code:
// Add some life
function (chart) {
if (!chart.renderer.forExport) {
setInterval(function () {
chart.series[0].color = "#000";
var point = chart.series[0].points[0];
$.getJSON('mydata.php', function(data) {
point.update(data);
});
}, 3000);
};
});
The wild was updated, but the background didn't.
I try to do this, but it doesn't work:
this.chart.plotBackground.attr({
fill: '#fff'
})
;
Does anybody has an idea?
It's pane background, not a plotBackground. Anyway, in the fact pane background is stored as one of plotBands. So simple you can update it's color:
chart.yAxis[0].plotLinesAndBands[2].svgElem.attr({
fill: 'green'
});
It's [2], because I want to update red plotBand which is third element from background options in a pane.
And some demo: http://jsfiddle.net/Yrygy/190/
I have used highcharts library in my project and i have to update Gauge every 1 second with data creating by PHP file .
The highcharts Gauge Example have some code to make it trigger every 1 second , but i cant found some thing like This Link to get data from PHP file with Ajax Technic .
Anyone have any idea to implement this scenario and apply Ajax to this chart ?
You not found example because it is generic, see how it can be done with $.post():
http://jsfiddle.net/oceog/zpwdp/
$(function () {
var chart = new Highcharts.Chart({
chart: {
renderTo: 'container',
type: 'gauge',
plotBackgroundColor: null,
plotBackgroundImage: null,
plotBorderWidth: 0,
plotShadow: false
},
title: {
text: 'Speedometer'
},
pane: {
startAngle: -150,
endAngle: 150,
background: [{
backgroundColor: {
linearGradient: { x1: 0, y1: 0, x2: 0, y2: 1 },
stops: [
[0, '#FFF'],
[1, '#333']
]
},
borderWidth: 0,
outerRadius: '109%'
}, {
backgroundColor: {
linearGradient: { x1: 0, y1: 0, x2: 0, y2: 1 },
stops: [
[0, '#333'],
[1, '#FFF']
]
},
borderWidth: 1,
outerRadius: '107%'
}, {
// default background
}, {
backgroundColor: '#DDD',
borderWidth: 0,
outerRadius: '105%',
innerRadius: '103%'
}]
},
// the value axis
yAxis: {
min: 0,
max: 200,
minorTickInterval: 'auto',
minorTickWidth: 1,
minorTickLength: 10,
minorTickPosition: 'inside',
minorTickColor: '#666',
tickPixelInterval: 30,
tickWidth: 2,
tickPosition: 'inside',
tickLength: 10,
tickColor: '#666',
labels: {
step: 2,
rotation: 'auto'
},
title: {
text: 'km/h'
},
plotBands: [{
from: 0,
to: 120,
color: '#55BF3B' // green
}, {
from: 120,
to: 160,
color: '#DDDF0D' // yellow
}, {
from: 160,
to: 200,
color: '#DF5353' // red
}]
},
series: [{
name: 'Speed',
data: [80],
tooltip: {
valueSuffix: ' km/h'
}
}]
},
// Add some life
function (chart) {
setInterval(function () {
$.post('/echo/json/',{
json: JSON.stringify({
//This is just a sample data, see comments after code to real world usage
inc: Math.round((Math.random() - 0.5) * 20)
})},
function(data) {
var point = chart.series[0].points[0],
newVal,
inc = data.inc;
newVal = point.y + inc;
if (newVal < 0 || newVal > 200) {
newVal = point.y - inc;
}
point.update(newVal);
},"json");
}, 3000);
});
});
In real world you use something like
$.post('new_data.php',{last_time: last_time},function(data) {
//set point here
},"json")
in new_data.php you do something like
$data=get_data($last_time);
echo json_encode($data);
exit;