highcharts-ng ajax data load - javascript

I have the following HTTP request that i use to fill out my chart:
$scope.series = ['Moduler tager', 'Gns.score'];
$scope.activity_data = [];
$scope.activity_ticks = [];
var tmp_data = [];
$scope.bar = [];
$scope.line = [];
$http.get(api.getUrl('findSelfActivityByDivisions', null))
.success(function (response) {
response.forEach(function(y){
var i = 0;
var log_date = y.date.substr(0, y.date.indexOf('T'));
var date = new Date(log_date);
var logg_date = moment(date).fromNow();
var indexOf = tmp_data.indexOf(logg_date);
var found = false;
var index = 0;
if(tmp_data.length > 0){
tmp_data.forEach(function(current_data){
if(current_data[0] == logg_date){
found = true;
}
if(!found){
index++;
}
})
}
if(found){
var tmp = tmp_data[index];
tmp[1] = tmp[1] + y.num_modules;
tmp[2] = tmp[2] + y.num_score_modules;
tmp[3] = tmp[3] + y.sum_score;
tmp_data[index] = tmp;
}
else
{
var tmp = [logg_date, y.num_modules, y.num_score_modules, y.sum_score];
tmp_data.push(tmp);
}
})
var line = [];
var bar = [];
tmp_data.forEach(function(data){
$scope.activity_ticks.push(data[0])
line.push(data[1]);
var avg_score = data[3] / data[2];
if(isNaN(avg_score)){
avg_score = 0;
}
bar.push(avg_score);
});
$scope.line = line;
$scope.bar = bar;
});
Now then i have the following chart config:
$scope.chartConfig = {
options: {
chart: {
type: 'areaspline'
}
},
series: [{
data: $scope.bar,
type: 'column'
},{
data: $scope.line,
type: 'line'
}],
xAxis: {
categories: $scope.activity_ticks
},
title: {
text: 'Hello'
},
loading: false
}
Sadly none of the graphs are showing (im guessing it has something to do with the date comming after the load)
Can anyone help me out?

Your $scope.chartConfig is likely firing before the success callback of your $http.get(api.getUrl('findSelfActivityByDivisions', null)) completes. I am assuming $scope.chartConfig is located in a controller. Try placing a $watchGroup on the values then apply your chart rendering logic once those values resolve. An example may include
Note that $watchGroup is found within Angular as of 1.3
$scope.$watchGroup(['line', 'bar'], function(newValues, oldValues) {
// newValues[0] --> $scope.line
// newValues[1] --> $scope.bar
if(newValues !== oldValues) {
$scope.chartConfig = {
options: {
chart: {
type: 'areaspline'
}
},
series: [{
data: $scope.bar,
type: 'column'
},{
data: $scope.line,
type: 'line'
}],
xAxis: {
categories: $scope.activity_ticks
},
title: {
text: 'Hello'
},
loading: false
}
}
});

Related

Change Highcharts Graph based on two Select inputs

I have an array of data of the following format:
[["sno","day","status","data1","data2","data3","data4"],
["1","01-12-2020","success","23","66","53","34"],
["2","02-12-2020","success","12","9","8","6"],
["3","03-12-2020","success","10","11","16","13"],
["4","04-12-2020","success","34","43","54","34"],
["5","01-12-2020","fail","45","26","36","44"],
["6","02-12-2020","fail","12","15","11","13"],
["7","03-12-2020","fail","34","43","33","29"],
["8","04-12-2020","fail","23","34","31","23"]
]
to display the particular text in Highcharts I used the Following code:
var weekData = [["sno","day","status","data1","data2","data3","data4"],["1","01-12-2020","success","23","66","53","34"],["2","02-12-2020","success","12","9","8","6"],["3","03-12-2020","success","10","11","16","13"],["4","04-12-2020","success","34","43","54","34"],["5","01-12-2020","fail","45","26","36","44"],["6","02-12-2020","fail","12","15","11","13"],["7","03-12-2020","fail","34","43","33","29"],["8","04-12-2020","fail","23","34","31","23"]] ;
//console.log(weekData);
function change()
{
var valStatus = document.getElementById("statusSelect");
status = valStatus.value;
//console.log(status);
if(status == 'success')
{
const successValues = weekData.filter((x)=>x[2] === "success"); //New Cases
console.log(successValues);
return successValues;
}
else if(status == 'fail')
{
const failValues = weekData.filter((x)=>x[2] === "fail"); //New Cases
console.log(failValues)
return failValues;
}
}
function getCol(matrix, col){
var column = [];
for(var i=0; i<matrix.length; i++){
column.push(matrix[i][col]);
}
return column;
}
function chartCreate()
{
change();
const toNumbers = arr => arr.map(Number);
var getstat= change();
var day = getCol(getstat,1);
console.log(day);
var sdata1 = toNumbers(getCol(getstat,3));
console.log("data 1" ,sdata1);
var sdata2 = toNumbers(getCol(getstat,4));
console.log(sdata2);
var sdata3 = toNumbers(getCol(getstat,5));
console.log(sdata3);
var sdata4 = toNumbers(getCol(getstat,6));
console.log(sdata4);
For the full program You can check my fiddle : https://jsfiddle.net/abnitchauhan/L27n0wfs/
the problem is that when I am status select box, The Chart is not updating.
Also I feel that this code is quite lengthy when the datasets will increase overtime. is there any efficient approach to display this data on Highchart's based on the same select options.
I made an update to JS code. See if this is what you want:
var weekData = [["sno","day","status","data1","data2","data3","data4"],["1","01-12-2020","success","23","66","53","34"],["2","02-12-2020","success","12","9","8","6"],["3","03-12-2020","success","10","11","16","13"],["4","04-12-2020","success","34","43","54","34"],["5","01-12-2020","fail","45","26","36","44"],["6","02-12-2020","fail","12","15","11","13"],["7","03-12-2020","fail","34","43","33","29"],["8","04-12-2020","fail","23","34","31","23"]] ;
//console.log(weekData);
function change()
{
var valStatus = document.getElementById("statusSelect");
status = valStatus.value;
//console.log(status);
if(status == 'success')
{
const successValues = weekData.filter((x)=>x[2] === "success"); //New Cases
console.log(successValues);
return chartCreate(successValues);
}
else if(status == 'fail')
{
const failValues = weekData.filter((x)=>x[2] === "fail"); //New Cases
console.log(failValues)
return chartCreate(failValues);
}
}
function getCol(matrix, col){
var column = [];
for(var i=0; i<matrix.length; i++){
column.push(matrix[i][col]);
}
return column;
}
function chartCreate(stat)
{
const toNumbers = arr => arr.map(Number);
var getstat= stat;
var day = getCol(getstat,1);
console.log(day);
var sdata1 = toNumbers(getCol(getstat,3));
console.log("data 1" ,sdata1);
var sdata2 = toNumbers(getCol(getstat,4));
console.log(sdata2);
var sdata3 = toNumbers(getCol(getstat,5));
console.log(sdata3);
var sdata4 = toNumbers(getCol(getstat,6));
console.log(sdata4);
var options = {
chart:{
renderTo: 'chart',
defaultSeriesType: 'line'
},
title: {
text: 'dummy'
},
subtitle: {
text: ' '
},
yAxis: {
title: {
text: ' ',
//tickPointInterval: 250
},
minorTickInterval: 'auto',
// tickInterval: 4,
},
xAxis: {
labels :{
minorTickInterval: 'auto',
formatter: function(){
return day[this.value];
}
},
tickInterval: 10
},
credits: {
enabled: false
},
legend: {
layout: 'vertical',
align: 'right',
verticalAlign: 'middle'
},
plotOptions: {
series: {
label: {
connectorAllowed: false
},
// pointStart: 0
}
},
tooltip: {
// split: true,
formatter: function() {
var points = this.points,
tooltipArray = ['day: <b>' + day[this.x] + '</b><br/> Value : <b>'+ this.y +'</b>']
return tooltipArray;
}
},
series: [
{
name: 'Check',
data: sdata1
}],
responsive: {
rules: [{
condition: {
maxWidth: 500
},
chartOptions: {
legend: {
layout: 'horizontal',
align: 'center',
verticalAlign: 'bottom'
}
}
}]
}
};
var chart = new Highcharts.Chart(options);
$("#dataSelect").on('change', function(){
//alert('f')
var selVal = $("#dataSelect").val();
if(selVal == 'data1' || selVal == '')
{
options.series = [{name: 'Data', data: sdata1}];
options.yAxis = [{tickInterval:undefined, minorTickInterval: 'auto'}];
}
else if(selVal == 'data2')
{
options.series = [{name: 'Data', data: sdata2}]
}
else if(selVal == 'data3')
{
options.series = [{name: 'Data', data: sdata3}];
options.yAxis = [{tickInterval:undefined, minorTickInterval: 'auto'}];
}
else if(selVal == 'data4')
{
options.series = [{name: 'Data', data: sdata4}];
options.yAxis = [{tickInterval:undefined, minorTickInterval: 'auto'}];
}
var chart = new Highcharts.Chart(options);
});
}
change();
Your code looks very complex and does not fully work. In this case, I will suggest using the series setData method mixed with the change event listener. My example is a bit simplified, but I think it might be the right way.
document.getElementById('dataSelect').addEventListener('change', () => {
const selectorValue = document.getElementById('dataSelect').value
chart.series[0].setData(data[selectorValue])
});
API: https://api.highcharts.com/class-reference/Highcharts.Series#setData
Demo: https://jsfiddle.net/BlackLabel/nfz0a9bm/

Highcharts Remote Data - JSON Object Undefined

I'm trying to render a Highcharts column chart from MySQL data -> json_encode() -> getJSON(). 95% of the time there are 6 rows of data to process, so this can be easily looped through manually and the chart renders fine. The problem is when there are occasionally fewer rows in the results array - I am of course seeing TypeError: Cannot read property 'name' of undefined in these cases.
My working code:
$.getJSON(url, function(json)) {
if(typeof json === 'object' && json.length > 0) {
var nameData = [json[0]['name'],json[1]['name'],json[2]['name'],json[3]['name'],json[4]['name'],json[5]['name']];
var matchedData = [json[0]['data']['Matched'],json[1]['data']['Matched'],json[2]['data']['Matched'],json[3]['data']['Matched'],json[4]['data']['Matched'],json[5]['data']['Matched']];
var bookedData = [json[0]['data']['Booked'],json[1]['data']['Booked'],json[2]['data']['Booked'],json[3]['data']['Booked'],json[4]['data']['Booked'],json[5]['data']['Booked']];
}
var options = {
chart: {
renderTo: 'div',
type: 'column'
},
title: {
text: 'Chart Title',
x: -20
},
xAxis: {
type: 'category',
categories: nameData,
crosshair: true
},
series: [{
name: 'Matched',
data: matchedData
}, {
name: 'Booked',
data: bookedData
}]
}
chart = new Highcharts.Chart(options);
}
This renders the chart correctly. However when there are fewer than the usual 6 items in the array, the TypeError stops things.
I attempted this to count the array items prior to sending to Highcharts:
var nameData = [];
var matchedData = [];
var bookedData = [];
if (typeof json === 'object' && json.length > 0) {
for (var a = 0; a < json.length; a++) {
nameData += [json[a]['name']+","];
matchedData += [json[a]['data']['Matched']+","];
bookedData += [json[a]['data']['Booked']+","];
}
}
This alerts() out the same results as the manually-created array, but nothing renders on the chart. What needs to change?
Try mapping over your data. You can set everything really easily using the map function. It's a lot cleaner and simpler as well. You can find a reference for map here.
$.getJSON(url, function(json)) {
if(typeof json === 'object' && json.length > 0) {
var nameData = json.map(obj => obj['name']);
var matchedData = json.map(obj => obj['data']['Matched']);
var bookedData = json.map(obj => obj['data']['Booked']);
}
var options = {
chart: {
renderTo: 'div',
type: 'column'
},
title: {
text: 'Chart Title',
x: -20
},
xAxis: {
type: 'category',
categories: nameData,
crosshair: true
},
series: [{
name: 'Matched',
data: matchedData
}, {
name: 'Booked',
data: bookedData
}]
}
chart = new Highcharts.Chart(options);
}

Set a full background color to the canvas in chartjs 2.0

Basically my question is similar to the one asked here How to set a full length background color for each bar in chartjs bar
It has a desired jsfiddle link http://jsfiddle.net/x73rhq2y/
But it does not work for chartjs 2.* (I am using chart.min.bundle.js v2.1.6)
I am trying to extend my bar chart to display multiple stacked bar chart. Along with it I need to separate out the bar chart background.
Chart.defaults.groupableBar = Chart.helpers.clone(Chart.defaults.bar);
var helpers = Chart.helpers;
Chart.controllers.groupableBar = Chart.controllers.bar.extend({
calculateBarX: function (index, datasetIndex) {
// position the bars based on the stack index
var stackIndex = this.getMeta().stackIndex;
return Chart.controllers.bar.prototype.calculateBarX.apply(this, [index, stackIndex]);
},
hideOtherStacks: function (datasetIndex) {
var meta = this.getMeta();
var stackIndex = meta.stackIndex;
this.hiddens = [];
for (var i = 0; i < datasetIndex; i++) {
var dsMeta = this.chart.getDatasetMeta(i);
if (dsMeta.stackIndex !== stackIndex) {
this.hiddens.push(dsMeta.hidden);
dsMeta.hidden = true;
}
}
},
unhideOtherStacks: function (datasetIndex) {
var meta = this.getMeta();
var stackIndex = meta.stackIndex;
for (var i = 0; i < datasetIndex; i++) {
var dsMeta = this.chart.getDatasetMeta(i);
if (dsMeta.stackIndex !== stackIndex) {
dsMeta.hidden = this.hiddens.unshift();
}
}
},
calculateBarY: function (index, datasetIndex) {
this.hideOtherStacks(datasetIndex);
var barY = Chart.controllers.bar.prototype.calculateBarY.apply(this, [index, datasetIndex]);
this.unhideOtherStacks(datasetIndex);
return barY;
},
calculateBarBase: function (datasetIndex, index) {
this.hideOtherStacks(datasetIndex);
var barBase = Chart.controllers.bar.prototype.calculateBarBase.apply(this, [datasetIndex, index]);
this.unhideOtherStacks(datasetIndex);
return barBase;
},
getBarCount: function () {
var stacks = [];
// put the stack index in the dataset meta
Chart.helpers.each(this.chart.data.datasets, function (dataset, datasetIndex) {
var meta = this.chart.getDatasetMeta(datasetIndex);
if (meta.bar && this.chart.isDatasetVisible(datasetIndex)) {
var stackIndex = stacks.indexOf(dataset.stack);
if (stackIndex === -1) {
stackIndex = stacks.length;
stacks.push(dataset.stack);
}
meta.stackIndex = stackIndex;
}
}, this);
this.getMeta().stacks = stacks;
return stacks.length;
},
initialize: function (data) {
debugger;
var self = data;
var originalBuildScale = self.buildScale;
self.buildScale = function () {
originalBuildScale.apply(this, arguments);
debugger;
var ctx = self.chart.ctx;
var scale = self.scale;
var originalScaleDraw = self.scale.draw;
var barAreaWidth = scale.calculateX(1) - scale.calculateX(0);
var barAreaHeight = scale.endPoint - scale.startPoint;
self.scale.draw = function () {
originalScaleDraw.call(this, arguments);
scale.xLabels.forEach(function (xLabel, i) {
ctx.fillStyle = data.labelBackgrounds[i];
ctx.fillRect(
scale.calculateX(i - (scale.offsetGridLines ? 0.5 : 0)),
scale.startPoint,
barAreaWidth,
barAreaHeight);
ctx.fill();
});
};
};
Chart.controllers.bar.prototype.initialize.apply(this, arguments);
}
});
But since the documentation has been updated , i am not able to find the solution.
My data Array is as follows:
var data = {
labels: ["Label1","Label2","Label2","Label2",],
labelBackgrounds: ["rgba(120,220,220,0.2)", "rgba(220,120,220,0.2)", "rgba(220,220,120,0.2)", "rgba(120,120,220,0.2)"],
datasets: [
{
label: "Pass",
backgroundColor: "rgba(3,166,120,0.7)",
data: [40,50,30,45],
stack: 1
},
{
label: "Fail",
backgroundColor: "rgba(212,82,84,0.7)",
data: [40,50,30,45],
stack: 1
},
{
label: "Not run",
backgroundColor: "rgba(89,171,227,0.7)",
data: [40,50,30,45],
stack: 1
},
{
label: "Pass",
backgroundColor: "rgba(3,166,120,0.7)",
data: [40,50,30,45],
stack: 2
},
{
label: "Fail",
backgroundColor: "rgba(212,82,84,0.7)",
data: [40,50,30,45],
stack: 2
},
{
label: "Not run",
backgroundColor: "rgba(89,171,227,0.7)",
data: [40,50,30,45],
stack: 2
}
]
};
P.S: I had to create a new question as my reputation does not allows me to comment on https://stackoverflow.com/a/31833017/4787971

JavaScript - Highcharts box plot not displaying

I am having trouble creating a highcharts box-plot graph, I have all the data in the correct format i.e. min, lower quartile, median, upper quartile and max.
I can display the categories but I cannot get it to display the data.
This is my code:
function BoxPlot() {
//ViewBag Variables
var Till = #Html.Raw(Json.Encode(#ViewBag.Tills));
var Per20 = #Html.Raw(Json.Encode(#ViewBag.P20));
var Per30 = #Html.Raw(Json.Encode(#ViewBag.P30));
var Per40 = #Html.Raw(Json.Encode(#ViewBag.P40));
var Per50 = #Html.Raw(Json.Encode(#ViewBag.P50));
var Per60 = #Html.Raw(Json.Encode(#ViewBag.P60));
var Per70 = #Html.Raw(Json.Encode(#ViewBag.P70));
var Per80 = #Html.Raw(Json.Encode(#ViewBag.P80));
var Per90 = #Html.Raw(Json.Encode(#ViewBag.P90));
//Combine the till no with its data
var final = [];
for(var i=0; i < Till.length; i++) {
final.push({
name: Till[i],
p20: Per20[i],
p30: Per30[i],
p40: Per40[i],
p50: Per50[i],
p60: Per60[i],
p70: Per70[i],
p80: Per80[i],
p90: Per90[i],
});
}
console.log(final)
//get the data into the correct format for box plot
var formated = [];
for(var i=0; i < final.length; i++) {
formated.push({
a: final[i].p20,
b: ((final[i].p30 + final[i].p40) / 2),
c: ((final[i].p50 + final[i].p60) / 2),
d: ((final[i].p70 + final[i].p80) / 2),
e: final[i].p90,
});
}
console.log(formated)
//graph the data
$('#container').highcharts({
chart: {
type: 'boxplot'
},
title: {
text: 'Highcharts Box Plot'
},
legend: {
enabled: true
},
xAxis: {
categories: Till,
title: {
text: 'Till No.'
}
},
yAxis: {
title: {
text: 'Value'
}
},
series: [{
name: 'Values',
data: formated,
tooltip: {
headerFormat: '<em>Till No. {point.key}</em><br/>'
}
}]
});
}
This is an example of the formatted array and the data it contains:
This is how the graph currently looks, you can see the categories array is working but it is not showing the data:
I was able to solve this by changing how I gathered the data, Im not sure if the box plot is case sensitive but by changing the variable names the data displayed
This is the whole code I am using:
function BoxPlot() {
//ViewBag Variables
var Till = #Html.Raw(Json.Encode(#ViewBag.Tills));
var Per20 = #Html.Raw(Json.Encode(#ViewBag.P20));
var Per30 = #Html.Raw(Json.Encode(#ViewBag.P30));
var Per40 = #Html.Raw(Json.Encode(#ViewBag.P40));
var Per50 = #Html.Raw(Json.Encode(#ViewBag.P50));
var Per60 = #Html.Raw(Json.Encode(#ViewBag.P60));
var Per70 = #Html.Raw(Json.Encode(#ViewBag.P70));
var Per80 = #Html.Raw(Json.Encode(#ViewBag.P80));
var Per90 = #Html.Raw(Json.Encode(#ViewBag.P90));
var heading = #Html.Raw(Json.Encode(#ViewBag.QueryTitle));
//Combine the till no with its data
var final = [];
for(var i=0; i < Till.length; i++) {
final.push({
name: Till[i],
p20: Per20[i],
p30: Per30[i],
p40: Per40[i],
p50: Per50[i],
p60: Per60[i],
p70: Per70[i],
p80: Per80[i],
p90: Per90[i],
});
}
console.log(final)
//get the data into the correct format for box plot
var formated = [];
for(var i=0; i < final.length; i++) {
formated.push({
low: final[i].p20,
q1: ((final[i].p30 + final[i].p40) / 2),
median: ((final[i].p50 + final[i].p60) / 2),
q3: ((final[i].p70 + final[i].p80) / 2),
high: final[i].p90,
});
}
console.log(formated)
var boxData = [];
//boxData.push(formated);
//console.log(boxData);
//graph the data
$('#container').highcharts({
chart: {
type: 'boxplot'
},
title: {
text: heading
},
legend: {
enabled: true
},
xAxis: {
categories: Till,
title: {
text: 'Till No.'
}
},
yAxis: {
title: {
text: 'Distribution'
}
},
series: [{
name: 'Tills',
data:
formated
}]
});
}

Update Highchart data form exported button

I'm trying to use the exporting option to add a button which is then used to switch between a line chart with the real point and another with the cumulative sum of them.
I'm using the following code:
$(function () {
$('#container').highcharts({
chart: {
type: 'line'
},
xAxis: {
tickPixelInterval: 200,
categories: jsonResponse["Date"]
},
series: {
data: jsonResponse["values"]
},
exporting: {
buttons: {
'myButton': {
_id: 'myButton',
symbol: 'diamond',
text: 'Cumulative',
x: -62,
symbolFill: '#B5C9DF',
hoverSymbolFill: '#779ABF',
onclick: function() {
if(!cumulative){
this.series[0].setData = cumcum(jsonResponse["values"]);
alert(this.series[1].setData);
cumulative = true;
} else {
this.series[0].setData = jsonResponse["values"];
cumulative = false;
alert(this.series[1].setData);
}
},
_titleKey: "myButtonTitle"
}
}
}
});
});
function cumcum(data){
var res = new Array();
res[0] = data[0];
for(var i=1; i<data.length; i++) {
res[i] = res[i-1] + data[i];
}
return res;
}
From the alert I can see that the data are correctly calculated but the plot stays the same.
I also tried series[0].yData and series[0].processedYData
setData is a function, you have to call it like:
this.series[0].setData(cumcum(jsonResponse["values"])
See API http://api.highcharts.com/highstock#Series for more information.

Categories

Resources