Not sure why because I have done it in the past, but I have a Highcharts bar chart and it won't animate. This is the declaration of the chart,
function initializeData() {
$http.get(url).success(function(ret) {
$scope.jsondata = ret;
var newdata = [];
for (x = 0; x < 5; x++) {
newdata.push({
name: setName($scope.jsondata[x].name),
y: $scope.jsondata[x].data[0],
color: getColor($scope.jsondata[x].data[0])
});
}
$scope.chart.series[0].setData(newdata);
});
mainInterval = $interval(updateData, 5000);
}
function updateData() {
$http.get(url).success(function(ret) {
$scope.jsondata = ret;
console.debug("here");
for (x = 0; x < 5; x++) {
$scope.chart.series[0].data[x].update({
y: $scope.jsondata[x].data[0],
color: getColor($scope.jsondata[x].data[0])
});
}
});
}
$scope.chart = new Highcharts.Chart({
chart: {
renderTo: 'container',
type: 'bar',
animation: true,
events: {
load: initializeData
}
},
title: {
text: ''
},
xAxis: {
type: 'category',
labels: {
style: {
fontSize: '11px'
}
}
},
yAxis: {
min: 0,
max: 100,
title: {
text: 'Total Score',
align: 'high'
}
},
legend: {
enabled: false
},
tooltip: {
pointFormat: 'Total Score <b>{point.y:.3f}</b>'
},
series: [{
name: 'Active Users',
data: [],
dataLabels: {
enabled: true,
rotation: 30,
style: {
fontSize: '10px',
fontFamily: 'Verdana, sans-serif'
},
format: '{point.y:.3f}', // one decimal
}
}]
});
And as you can see I have animate : true, so I am not sure what is the problem here. I have this older plunker where all of the data is in separate series, but it animates fine. But this is the plunker I am working on and having trouble with. They are like identical basically. In the newer one I broke out the initialization of data into its own method, but that is the only real main difference.
Some edits:
So as I was saying, I have done things this way with an areaspline chart (I know it was said they work a bit different but they are set up identically).
function initializeData() {
$interval.cancel(mainInterval);
$scope.previousPackets = '';
$http.get("https://api.myjson.com/bins/nodx").success(function(returnedData) {
var newdata = [];
var x = (new Date()).getTime();
for (var step = 9; step >= 0; step--) {
newdata.push([x - 1000 * step, 0]);
}
$scope.chart.series[0].setData(newdata);
});
mainInterval = $interval(updateData, 2000);
}
function updateData() {
$http.get(url + acronym + '/latest').success(function(returnedData) {
var x = (new Date()).getTime();
if ($scope.previousPackets != returnedData[0].numPackets) {
$scope.chart.series[0].addPoint([x, returnedData[0].numPackets], true, true);
$scope.previousPackets = returnedData[0].numPackets;
} else {
$scope.chart.series[0].addPoint([x, 0], true, true);
}
});
}
$scope.chart = new Highcharts.Chart({
chart: {
renderTo: 'container',
type: 'areaspline',
animation: Highcharts.svg, // don't animate in old IE
marginRight: 10,
events: {
load: initializeData
}
},
title: {
text: ''
},
xAxis: {
type: 'datetime',
tickPixelInterval: 150
},
yAxis: {
title: {
text: 'Packets'
},
plotLines: [{
value: 0,
width: 1,
color: '#d9534f'
}]
},
tooltip: {
formatter: function() {
return Highcharts.numberFormat(this.y) + ' packets<b> | </b>' + Highcharts.dateFormat('%H:%M:%S', this.x);
}
},
legend: {
enabled: false
},
exporting: {
enabled: false
},
series: [{
name: 'Packets',
data: []
}]
});
I also updated the first chunk of code with the initializeData() method and updateData() method which are seemingly identical in both different charts.
It looks like it plays an important role if you provide your data at chart initialization or after. For simplicity I refactored your code a little
function initializeChart(initialData, onload) {
$scope.chart = new Highcharts.Chart({
chart: {
renderTo: 'container',
type: 'bar',
animation: true,
events: {
load: onload
}
....
series: [{
name: 'Active Users',
data: initialData,
dataLabels: {
enabled: true,
format: '{point.y:.3f}', // one decimal
}
}]
});
}
function getData(callback) {
$http.get(url).success(function(ret) {
$scope.jsondata = ret;
var newdata = [];
for (x = 0; x < 5; x++) {
newdata.push([setName(ret[x].name), ret[x].data]);
}
callback(newdata);
});
}
As a result your two planks are in essense reduced to two methods below. The first initializes chart with preloaded data and the second updates data in existing chart.
function readDataFirst() {
getData(function(newdata) {
initializeChart(newdata);
});
}
function initializeChartFirst() {
initializeChart([], function() {
getData(function(newdata) {
$scope.chart.series[0].setData(newdata);
})
});
}
The first one animates fine while the second does not. It looks like highcharts skips animation if dataset is not initial and is treated incompatible.
However if you really want to have animation in your current plant (chart first workflow) you can achieve that by initializing first serie with zeros and then with the real data. This case it will be treated as update
function forceAnimationByDoubleInitialization() {
getData(function(newdata) {
initializeChart([]);
var zerodata = newdata.map(function(item) {
return [item[0], 0]
});
$scope.chart.series[0].setData(zerodata);
$scope.chart.series[0].setData(newdata);
});
All these options are available at http://plnkr.co/edit/pZhBJoV7PmjDNRNOj2Uc
Is it possible to have Highcharts drilldown on multiple graphs that are sharing the same data when one graph is clicked?
As an example, I included a JSFiddle that uses the demo code (browser percentages).
http://jsfiddle.net/Pq6gb/
var gridster;
$(function(){
gridster = $(".gridster ul").gridster({
widget_base_dimensions: [150, 150],
widget_margins: [5, 5],
helper: 'clone',
resize: {
enabled: true,
stop: function(e, ui, $widget) {
for (var i = 0; i < Highcharts.charts.length; i++) {
Highcharts.charts[i].reflow();
}
}
}
}).data('gridster');
});
$(function () {
Highcharts.data({
csv: document.getElementById('tsv').innerHTML,
itemDelimiter: '\t',
parsed: function (columns) {
var brands = {},
brandsData = [],
versions = {},
drilldownSeries = [];
// Parse percentage strings
columns[1] = $.map(columns[1], function (value) {
if (value.indexOf('%') === value.length - 1) {
value = parseFloat(value);
}
return value;
});
$.each(columns[0], function (i, name) {
var brand,
version;
if (i > 0) {
// Remove special edition notes
name = name.split(' -')[0];
// Split into brand and version
version = name.match(/([0-9]+[\.0-9x]*)/);
if (version) {
version = version[0];
}
brand = name.replace(version, '');
// Create the main data
if (!brands[brand]) {
brands[brand] = columns[1][i];
} else {
brands[brand] += columns[1][i];
}
// Create the version data
if (version !== null) {
if (!versions[brand]) {
versions[brand] = [];
}
versions[brand].push(['v' + version, columns[1][i]]);
}
}
});
$.each(brands, function (name, y) {
brandsData.push({
name: name,
y: y,
drilldown: versions[name] ? name : null
});
});
$.each(versions, function (key, value) {
drilldownSeries.push({
name: key,
id: key,
data: value
});
});
// Create the chart
$('#container').highcharts({
chart: {
type: 'pie'
},
title: {
text: 'Browser market shares. November, 2013.'
},
subtitle: {
text: 'Click the slices to view versions. Source: netmarketshare.com.'
},
plotOptions: {
series: {
dataLabels: {
enabled: true,
format: '{point.name}: {point.y:.1f}%'
}
}
},
tooltip: {
headerFormat: '<span style="font-size:11px">{series.name}</span><br>',
pointFormat: '<span style="color:{point.color}">{point.name}</span>: <b>{point.y:.2f}%</b> of total<br/>'
},
series: [{
name: 'Brands',
colorByPoint: true,
data: brandsData
}],
drilldown: {
series: drilldownSeries
}
})
}
});
});
$(function () {
Highcharts.data({
csv: document.getElementById('tsv').innerHTML,
itemDelimiter: '\t',
parsed: function (columns) {
var brands = {},
brandsData = [],
versions = {},
drilldownSeries = [];
// Parse percentage strings
columns[1] = $.map(columns[1], function (value) {
if (value.indexOf('%') === value.length - 1) {
value = parseFloat(value);
}
return value;
});
$.each(columns[0], function (i, name) {
var brand,
version;
if (i > 0) {
// Remove special edition notes
name = name.split(' -')[0];
// Split into brand and version
version = name.match(/([0-9]+[\.0-9x]*)/);
if (version) {
version = version[0];
}
brand = name.replace(version, '');
// Create the main data
if (!brands[brand]) {
brands[brand] = columns[1][i];
} else {
brands[brand] += columns[1][i];
}
// Create the version data
if (version !== null) {
if (!versions[brand]) {
versions[brand] = [];
}
versions[brand].push(['v' + version, columns[1][i]]);
}
}
});
$.each(brands, function (name, y) {
brandsData.push({
name: name,
y: y,
drilldown: versions[name] ? name : null
});
});
$.each(versions, function (key, value) {
drilldownSeries.push({
name: key,
id: key,
data: value
});
});
// Create the chart
$('#container2').highcharts({
chart: {
type: 'column'
},
title: {
text: 'Browser market shares. November, 2013'
},
subtitle: {
text: 'Click the columns to view versions. Source: netmarketshare.com.'
},
xAxis: {
type: 'category'
},
yAxis: {
title: {
text: 'Total percent market share'
}
},
legend: {
enabled: false
},
plotOptions: {
series: {
borderWidth: 0,
dataLabels: {
enabled: true,
format: '{point.y:.1f}%'
}
}
},
tooltip: {
headerFormat: '<span style="font-size:11px">{series.name}</span><br>',
pointFormat: '<span style="color:{point.color}">{point.name}</span>: <b>{point.y:.2f}%</b> of total<br/>'
},
series: [{
name: 'Brands',
colorByPoint: true,
data: brandsData
}],
drilldown: {
series: drilldownSeries
}
})
}
});
});
There is a pie chart and a bar chart displaying the same data and can drilldown individually. I would like to click on any browser in the pie/bar chart and have both charts filter down to versions of that browser.
How would I go about doing this? Thanks.
Yes, it's possible. This is what you need to implement:
on drilldown event you can find respective point on a second chart and simple call 1point.doDrilldown()1
on drillup even in one chart, call on a second chart.drillUp()
Note: You need to be aware of infinite loop (for example drillUp() in one chart will call drillup event, which will drillUp() first chart again.. ) - just add some flag to call drillUp/doDrilldown only once per user click.
I have following generated JavaScript-Code to display a chart with HighCharts:
<script type="text/javascript">
var highchartsOptions = Highcharts.setOptions(Highcharts.theme);
var TaskChart; // Chart-Objekt
var TaskDuration = new Array();
// Save starting points to javascript variables for HighCharts
var startingUTC = 1288102643364;
TaskDuration = [0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,206,216,216,206,206];
for(var i = 0; i < TaskDuration.length; i++) {
if(TaskDuration[i] == 0) {
TaskDuration[i] = null;
}
}
</script>
<script type="text/javascript">
$j(document).ready(function() {
TaskChart = new Highcharts.Chart({
credits: {
enabled: false
},
chart: {
renderTo: "chart01",
defaultSeriesType: 'area',
zoomType: 'x',
spacingBottom: 250
},
title: {
text: "Task Duration"
},
xAxis: {
type: 'datetime',
dateTimeLabelFormats: {
week: '%e. %b %Y'
},
offset: 10,
startOnTick: true,
maxZoom: 7 * 24 * 3600000 // seven days
},
yAxis: {
title: {
text: "Duration"
}
},
tooltip: {
formatter: function() {
return '<b>'+ this.series.name +'</b><br/>';
}
},
plotOptions: {
area: {
stacking: 'normal',
lineColor: '#666666',
lineWidth: 1,
marker: {
lineWidth: 1,
lineColor: '#666666'
}
}
},
series: [
{
name: 'Duration',
pointStart: startingUTC,
pointInterval: 24*60*60*1000,
data: TaskDuration
}]
});
});
</script>
The problem is now that I want to remove all the "0" values from the beginning of the TaskDuration series array.
I try to set the values in the array to 'null':
for(var i = 0; i < TaskDuration.length; i++) {
if(TaskDuration[i] == 0) {
TaskDuration[i] = null;
}
}
But Highcharts still display the values in the chart.
How to prevent this behavior?
I also try to remove all values from the array until a value which is not "0". But with this approach the "startingUTC" is wrong. Maybe I have also to recalculate this value...
Regards,
Sandro
You need to remove elements not to set null, use this to remove zero element from array:
var myArray=[];
for(var i = 0; i < TaskDuration.length; i++) {
if(TaskDuration[i] != 0) {
myArray.push(TaskDuration[i]);
}
}
working JSfiddle
The problem is that you're using pointStart and pointInterval.
PointInterval will ignore your null points and will add points to the yAxis.
So, remove it.
series: [{
name: 'Duration',
data: TaskDuration
}]