I'm trying to have my Highstock chart update every minute, by replacing its existing data set with one that is extracted from a url request (which would have different data at different times).
So far I'm not even able to get the data to refresh based on manual changes.
Work so far: https://jsfiddle.net/Lz8gLw8j/
I'm trying to test changing data and then updating it with:
varData = [[0,0],[1,2]]
$('#chart2').highcharts().redraw();
Which does nothing.
You can set the new data to highchart in following way:
var newData = [
[1251763200000, 23.61],
[1251849600000, 23.60],
[1251936000000, 23.79]
]
var chart = $('#chart2').highcharts();
chart.series[0].setData(newData);
$('#chart2').highcharts().redraw();
Updated fiddler:
https://jsfiddle.net/Lz8gLw8j/5/
It looks like there is a load event that you can use
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
y = Math.round(Math.random() * 100);
series.addPoint([x, y], true, true);
}, 1000);
}
}
}
Here's a fiddle: https://jsfiddle.net/jjwilly16/Lz8gLw8j/6/
FYI: I pulled this from an example off of the Highcharts website: http://jsfiddle.net/gh/get/jquery/1.9.1/highslide-software/highcharts.com/tree/master/samples/stock/demo/dynamic-update/
You can add data to the existing series using the addPoint method and replace the dataset using the setData method. The second option argument for both of the methods allows you to redraw the chart. The data should be an array of arrays. The nested array contains the actual data that is plotted. The first elements of the inner, nested array is the epoch (x) while the second is the actual value (y). The epoch is the number of seconds since January 1, 1970 Midnight GMT/UTC. I have updated the fiddle to allow you to add data points as well as reset the data.
The main change are these lines:
$('#updateButton').click(function() {
var date = $('#newDate').val();
var epoch = Math.round(new Date(date).getTime());
var value = parseInt($('#newValue').val());
var chart = $('#chart2').highcharts();
chart.series[0].addPoint([epoch, value], true);
});
$('#resetChart').click(function() {
var chart = $('#chart2').highcharts();
chart.series[0].setData(null, true);
});
https://jsfiddle.net/Lz8gLw8j/7/
Related
I tried to add flags for loading dynamical data that worked at first when I used the continuous update charts as follows https://www.highcharts.com/stock/demo/dynamic-update and then the flags as follows https://www.highcharts.com/stock/demo/flags-shapes.
Can you please give me some solution for adding flags for continuous data? Also, I would want that if the continuous data exceeds some limit, the flags should appear on that series. And i want flags on continuous data also
Similar to adding points for the basic series, you should also add flag series points:
events: {
load: function () {
var series = this.series[0],
flagSeries = this.series[1];
setInterval(function () {
var x = (new Date()).getTime(), // current time
y = Math.round(Math.random() * 100);
series.addPoint([x, y], true, true);
flagSeries.addPoint({
x: x,
title: y
});
}, 1000);
}
}
Live demo: https://jsfiddle.net/BlackLabel/rh8jug5d/
API: https://api.highcharts.com/class-reference/Highcharts.Series#addPoint
I have angular scope variable which is being used in ng-repeat as well. I want to create a chart starting from a date and ending at a certain date with the current day marker. I am using javascript loader.js for drawing the charts but since I need to draw multiple charts inside ng-repeat.
My code looks like this:
$scope.items = [{"title1":"start_day: 01-01-2017", "end_day:15-02-2018"},
{"title2":"start_day: 05-10-2017", "end_day:10-01-2019"}];
and javascript code from google charts:
anychart.onDocumentReady(function () {
// create data tree on our data
var treeData = anychart.data.tree(getData());
// create resource gantt chart
var chart = anychart.ganttResource();
// set container id for the chart
chart.container('container');
// set data for the chart
chart.data(treeData);
// set start splitter position settings
chart.splitterPosition(150);
var now = (new Date()).getTime();
var sec = 1000;
var min = 60*sec;
var hour = 60*min;
var day = 24*hour;
// create linemarkers
var tl = chart.getTimeline();
tl.lineMarker(0).value("current");
// get chart data grid link to set column settings
var dataGrid = chart.dataGrid();
// initiate chart drawing
chart.draw();
// zoom chart to specified date
chart.fitAll();
});
function getData() {
var now = (new Date()).getTime();
var sec = 1000;
var min = 60*sec;
var hour = 60*min;
var day = 24*hour;
return [
{
"periods": [
{"id": "1_1", "start": now - 365*day, "end": now + 100*day }]
},
];
}
I want to pass the dates from angularjs scope variable to javascript code here which will replace the existing data of start and end, also I need to convert the dates difference.
Thanks in advance! :)
I would recommend to use another JS object that stores common data for both angular and js.
var DATES = [{"title1":"start_day: 01-01-2017", "end_day:15-02-2018"},
{"title2":"start_day: 05-10-2017", "end_day:10-01-2019"}];
...
//in agular
$scope.items = DATES;
...
//in loader
function getData() {
...
return DATES;
}
You can also store an angular $scope into a variable and then use it as a usual variable into JS code, var ctrl = $scope but I would recommend to go with the first option.
--
Regarding to dates difference. Try to use standard Date class.
For example:
var deltaMS = new Date("02-15-2018") - new Date("01-01-2017");
var deltaDays = delta / 1000 / 60/ 60 / 24;
//410 days
The data series in my HighCharts chart only includes dates from the past few days, but the chart's x-axis and zoom bar show a date range all the way back to 1970.
How can I limit the presented date range so it only goes back as far as the first date present in the series data?
Example
HTML
<div id="chart_container" style="height: 500px></div>
JavaScript
$(function () {
var timestamps = [1481000484000,1481108510000,1481215541000,1481316568000,1481417583000];
var series_raw_data = [100,300,750,400,200];
// prepare data
var points = [[],[]];
for (var i = 0; i < timestamps.length; i++) {
points.push([timestamps[i], series_raw_data[i]]);
}
// create chart
$('#chart_container').highcharts('StockChart', {
series: [{
data: points
}]
});
});
Here's Fiddle1 which shows the behavior.
I also tried setting the xAxis 'min' option to the first timestamp, and setting the axis type to 'datetime', but those didn't help - Fiddle2.
The reason why it happens is your points array.
If fact, after filling, it looks like this:
points = [ [], [], [x, y], [x, y]]
Those two empty arrays create unwanted behaviour.
Fix the initial array and it works
var points = [];
example: https://jsfiddle.net/hbwosk3o/3/
I'm using highcharts.js to visualize data series from a database. There's lots of data series and they can potantially change from the database they are collected from with ajax. I can't guarantee that they are flawless and sometimes they will have blank gaps in the dates, which is a problem. Highcharts simply draws a line through the entire gap to the next available date, and that's bad in my case.
The series exists in different resolutions. Hours, Days and Weeks. Meaning that a couple of hours, days or weeks can be missing. A chart will only show 1 resolution at a time on draw, and redraw if the resolution is changed.
The 'acutal' question is how to get highcharts to not draw those gaps in an efficient way that works for hous, days and weeks
I know highcharts (line type) can have that behaviour where it doesn't draw a single line over a gap if the gap begins with a null.
What I tried to do is use the resolution (noted as 0, 1, 2 for hour day or week), to loop through the array that contains the values for and detect is "this date + 1 != (what this date + 1 should be)
The code where I need to work this out is here. Filled with psudo
for (var k in data.values) {
//help start, psudo code.
if(object-after-k != k + resolution){ //The date after "this date" is not as expected
data.values.push(null after k)
}
//help end
HC_datamap.push({ //this is what I use to fill the highchart later, so not important
x: Date.parse(k),
y: data.values[k]
});
}
the k objects in data.values look like this
2015-05-19T00:00:00
2015-05-20T00:00:00
2015-05-21T00:00:00
...and more dates
as strings. They can number in thousands, and I don't want the user to have to wait forever. So performance is an issue and I'm not an expert here either
Please ask away for clarifications.
I wrote this loop.
In my case my data is always keyed to a date (12am) and it moves either in intervals of 1 day, 1 week or 1 month. Its designed to work on an already prepared array of points ({x,y}). Thats what dataPoints is, these are mapped to finalDataPoints which also gets the nulls. finalDataPoints is what is ultimately used as the series data. This is using momentjs, forwardUnit is the interval (d, w, or M).
It assumes that the data points are already ordered from earliest x to foremost x.
dataPoints.forEach(function (point, index) {
var plotDate = moment(point.x);
finalDataPoints.push(point);
var nextPoint = dataPoints[index+1];
if (!nextPoint) {
return;
}
var nextDate = moment(nextPoint.x);
while (plotDate.add(1, forwardUnit).isBefore(nextDate)) {
finalDataPoints.push({x: plotDate.toDate(), y: null});
}
});
Personally, object with property names as dates may be a bit problematic, I think. Instead I would create an array of data. Then simple loop to fill gaps shouldn't be very slow. Example: http://jsfiddle.net/4mxtvotv/ (note: I'm changing format to array, as suggested).
var origData = {
"2015-05-19T00:00:00": 20,
"2015-05-20T00:00:00": 30,
"2015-05-21T00:00:00": 50,
"2015-06-21T00:00:00": 50,
"2015-06-22T00:00:00": 50
};
// let's change to array format
var data = (function () {
var d = [];
for (var k in origData) {
d.push([k, origData[k]]);
}
return d;
})();
var interval = 'Date'; //or Hour or Month or Year etc.
function fillData(data, interval) {
var d = [],
now = new Date(data[0][0]), // first x-point
len = data.length,
last = new Date(data[len - 1][0]), // last x-point
iterator = 0,
y;
while (now <= last) { // loop over all items
y = null;
if (now.getTime() == new Date(data[iterator][0]).getTime()) { //compare times
y = data[iterator][1]; // get y-value
iterator++; // jump to next date in the data
}
d.push([now.getTime(), y]); // set point
now["set" + interval](now.getDate() + 1); // jump to the next period
}
return d;
}
var chart = new Highcharts.StockChart({
chart: {
renderTo: 'container'
},
series: [{
data: fillData(data, interval)
}]
});
Second note: I'm using Date.setDay() or Date.setMonth(), of course if your data is UTC-based, then should be: now["setUTC" + interval].
I'm working with chart.js and to render a doughnut chart. I want to set the initial chart total value to zero so it can render a full " empty" chart. When I instatiate the chart with zeros it does not render. I cannot find how it handle zeros in the developer documentation.
var kPoints = 000;
var mPoints = 000;
var tPoints = 000;
var cPoints = 000;
var doughnutData = [ {
value : kPoints,
color : "#FF8000"
}, {
value : mPoints,
color : "#99CC00"
}, {
value : tPoints,
color : "#0099CC"
}, {
value : cPoints,
color : "#333333"
}, ];
var ctx = $("#profileChart").get(0).getContext("2d");
var myDoughnut = new Chart(ctx).Doughnut(doughnutData);
From reading the source code for Chart.js I've found that the it tries to sum each of the value fields in its datasource before rendering the chart (see the use of segmentTotal here).
To workaround this, use null for all the values and set one (or more) of the data points to a very small, near zero value. I've used a float notation here for one of the values:
var kPoints = null;
var mPoints = null;
var tPoints = null;
var cPoints = 1e-10;
After that, the example below re-renders the chart (after a 3 second delay) with different data values to show a case of the values updating from the default "dark" chart to a filled out version:
setTimeout(function () {
// Generate a new, random value for each of the data points
doughnutData.forEach(function (item) {
item.value = Math.floor((Math.random() * 10) + 1);
});
var ctx = $("#profileChart").get(0).getContext("2d");
var myDoughnut = new Chart(ctx).Doughnut(doughnutData);
}, 3000);
JSFiddle Example: http://jsfiddle.net/MasterXen/6S9DB/3/
Keep a running total of the values when building the doughnut data.
If there are zero data points, or the total value of all data points is zero, then simply inject an extra dummy point with a label like "No Data" along with an either imperceptible (near-zero) value or a dummy value like 1. In either case, you'll end up with a valid chart with a single category like "No Data".