Live Update Callback -> afterTitle with Array via JSON file - javascript

I'm working on a chart, I'm live updating the Chart every 5 seconds that the data comes in. I could manage to get the info from the database and update it really easy, but I just came across a problem with involves setting a path to a part of the chart, in the case: options->tootltips->callbacks->afterTitle and inside of it create an array and pass the array from the JSON to an array inside the callback.
What I would need to do, In a really brief way is, since I already made a function to update the info from my Data and Labels, somehow I will need to make inside this function, a path to the afterTitle, than I will be able send the fifth array, in with stores the data. As you can see in my function, I could manage to do it for the data and label.
I can't have another function that updates, so basically I can't have 2 loadData(), because it makes the Chart blink every time it updates, and that's not what I'm aiming for (The chart can't blink).
Inside this patch, I made an example that didn't work, with is the //:
$.getJSON('loadchart.php', function(response) {
myLineChart.data.datasets[0].data = response[0];
myLineChart.data.datasets[1].data = response[1];
myLineChart.data.datasets[2].data = response[2];
myLineChart.data.datasets[3].data = response[3];
myLineChart.data.labels = response[4];
//The response array that I need is response[5];
//myLineChart.options.tooltips.callbacks[1] = return response[tooltipItem[0]['index']];
myLineChart.update();
});
All my Chart so you can see the path:
<script>
function loadData() {
$.getJSON('loadchart.php', function(response) {
myLineChart.data.datasets[0].data = response[0];
myLineChart.data.datasets[1].data = response[1];
myLineChart.data.datasets[2].data = response[2];
myLineChart.data.datasets[3].data = response[3];
myLineChart.data.labels = response[4];
myLineChart.update();
});
}
loadData();
setInterval(loadData, 5000);
var lbl = [];
var ctx1 = document.getElementById('mychart1').getContext('2d');
var myLineChart = new Chart(ctx1, {
type: 'line',
data: {
labels: lbl,
datasets: [
{
label: "Corrente 1",
data: [],
borderWidht: 6,
borderColor: 'red',
backgroundColor: 'transparent'
},
{
label: "Corrente 2",
data: [],
borderWidht: 6,
borderColor: 'blue',
backgroundColor: 'transparent'
},
{
label: "Corrente 3",
data: [],
borderWidht: 6,
borderColor: 'green',
backgroundColor: 'transparent'
},
{
label: "Corrente Total",
data: [],
borderWidht: 6,
borderColor: 'black',
backgroundColor: 'transparent'
},
]
},
options: {
animation:{
update: 0
},
scales: {
yAxes: [{
ticks: {
beginAtZero: true
}
}],
xAxes: [{
gridLines: {
display: false
}
}]
},
title: {
display: true,
fontSize: 20,
text: "Gráfico das Correntes"
},
labels: {
fontStyle: "bold",
},
layout: {
padding: {
left: 0,
right: 0,
top: 0,
bottom: 0
}
},
tooltips: {
enabled: true,
mode: 'single',
responsive: true,
backgroundColor: 'black',
titleFontFamily: "'Arial'",
titleFontSize: 14,
titleFontStyle: 'bold',
titleAlign: 'center',
titleSpacing: 4,
titleMarginBottom: 10,
bodyFontFamily: "'Mukta'",
bodyFontSize: 14,
borderWidth: 2,
borderColor: 'grey',
callbacks:{
title: function(tooltipItem, data) {
return data.labels[tooltipItem[0].index];
},
afterTitle: function(tooltipItem, data) {
var tempo = [];
return tempo[tooltipItem[0]['index']];
},
label: function(tooltipItem, data) {
var label = data.datasets[tooltipItem.datasetIndex].label || '';
if (label) {
label += ': ';
}
label += (tooltipItem.yLabel)+"A";
return label;
}
}
},
aspectRatio: 1,
maintainAspectRatio: false
}
});
</script>
The part I need is this one:
afterTitle: function(tooltipItem, data) {
var tempo = [];
return tempo[tooltipItem[0]['index']];

This will display a clock but you can also set it to 5000 seconds and call your chart update. Which i would suggest to put in some kind of AJAX to let it work asynchonous.
<!DOCTYPE html>
<html>
<head>
<script>
function startTime() {
var today = new Date();
var h = today.getHours();
var m = today.getMinutes();
var s = today.getSeconds();
m = checkTime(m);
s = checkTime(s);
document.getElementById('txt').innerHTML =
h + ":" + m + ":" + s;
var t = setTimeout(startTime, 500); //<---- !!!
}
function checkTime(i) {
if (i < 10) {i = "0" + i}; // add zero in front of numbers < 10
return i;
}
</script>
</head>
<body onload="startTime()">
<div id="txt"></div>
</body>
</html>

As you mention in afterTitle function you want to create an array and pass the array from the JSON to an array inside the callback, and the missing part is you are creating an array tempo and treating it like an object tempo[tooltipItem[0]['index']];, but what you need to do is push this object tooltipItem[0]['index'] to tempo array.
Please replace afterTitle function with the below code
afterTitle: function(tooltipItem, data) {
var tempo = [];
return tempo.push(tooltipItem[0]['index']);

Related

How can my Chart.js just update when data in SQL change?

I build a web app in MVC using SignalR to update real-time data. I can display my chart with real-time data from SQL but it just updates by the time set in setInterval. But now I want my chart to just update when my data in SQL SERVER changes. I have tried many ways but it's not correct. Can you help me with the algorithm? Thank you.
Here is my code :
<!--Chart-->
<script>
var ctx = document.getElementById("percent-chart2");
var colorarray = ['#00b5e9', '#fa4251', '#006400'];
var pre_vals = 0;
//
var myVar = setInterval(GetValue, 1000);
function GetValue() {
var val1 = parseFloat(document.getElementById("tblValue").innerHTML);
var val2 = parseFloat(document.getElementById("tblValue1").innerHTML);
var vals = [val1, val2, 2000];
return vals;
}
if (ctx) {
ctx.height = 209;
var myChart = new Chart(ctx, {
type: 'doughnut',
data: {
datasets: [
{
label: "My First dataset",
//data: [GetValue, GetValue, GetValue],
data: GetValue(),
backgroundColor: [
'#00b5e9',
'#fa4251',
'#006400'
],
hoverBackgroundColor: [
'#00b5e9',
'#fa4251',
'#006400'
],
borderWidth: [
0, 0, 0
],
hoverBorderColor: [
'transparent',
'transparent',
'transparent'
]
}
],
labels: [
'STATION 1',
'STATION 2',
'STATION 3'
]
},
options: {
maintainAspectRatio: false,
responsive: true,
cutoutPercentage: 57,
animation: {
animateScale: true,
animateRotate: true
},
legend: {
display: false,
position: 'bottom',
labels: {
fontSize: 14,
fontFamily: "Poppins,sans-serif"
}
},
tooltips: {
titleFontFamily: "Poppins",
xPadding: 15,
yPadding: 10,
caretPadding: 0,
bodyFontSize: 16,
}
}
});
}
function UpdateChart(datachart, data, color) {
datachart.data.datasets.pop();
datachart.data.datasets.push({
data: data,
backgroundColor: color,
hoverBackgroundColor: color
});
datachart.update();
}
setInterval(function () {
const my_val = GetValue();
//var updatedata = [my_val, my_val, 2000];
var updatedata = my_val;
UpdateChart(myChart, updatedata, colorarray);
}, 10000);
</script>
The way I handle this is by adding a client call with the dataset after the database update has completed. This way you only update when that update is called.
Here is a rough example off the top of my head:
public void UpdateDB(int updatedData)
{
//DB work to commit the updatedData
....
//Query your dataset into an serialized updatedDataset
....
//Call a method to create an array (updatedColors) of colors based on the the Count of updatedDataset
....
//Send data to client(s)
Clients.All.yourclientfunction(updatedDataset, updatedColors);
}

How to use a Data Array within a Chart JS dataset?

I have the following JSON, that I want to insert a chart using Chart JS:
{"Results":[{"Data":"25/02/2021","Valor":18},{"Data":"24/02/2021","Valor":2993},{"Data":"23/02/2021","Valor":1936},{"Data":"22/02/2021","Valor":1844},{"Data":"21/02/2021","Valor":1114},{"Data":"20/02/2021","Valor":1060},{"Data":"19/02/2021","Valor":1134}]}
And I created a function to load this JSON into an Array:
function ShowData(jsonObj) {
var bases = jsonObj['Results'];
var Date = [];
var Val = [];
for (var i = bases.length-1; i >= 0; i--) {
Date.push([bases[i].Data]);
Val.push([bases[i].Valor]);
}
}
When I load this Array into the Chart, As below:
var chartGraph = new Chart(ctx,{
type:'line',
data:{
labels: Date,
datasets: [
{
label: "Lbl Name",
data: Val,
borderWidth: 6,
borderColor: 'rgba(77,166,253, 0.85)',
backgroundColor: 'transparent'
}
]
},
options: {
title: {
display: true,
fontSize: 20,
text: 'Chart Name'
},
legend: {
display: true,
position: 'right',
labels: {
fontColor: '#666'
}
}
}
})
No information on "datasets" appears to me, only the "label", what is the mistake I am making?
Graphic Image
Try to split series and data, something like:
function splitData(type) {
return json.Results.map(v => v[type]);
}
// your Chart.js config
data: {
labels: splitData('Date'),
datasets: [
{
// ...otherProps,
data: splitData('Valor')
}
]
}
You cant use Date as variable name since its a build in class. Also from my testing couldnt reference the vars inside the function. But the real problem with your code is that you push an array to the val array. This made it an array containing arrays. This is not supported. If you change your code to the sample below it will work
let date = [];
let val = [];
function ShowData(jsonObj) {
var bases = jsonObj['Results'];
date = [];
val = [];
for (var i = bases.length-1; i >= 0; i--) {
date.push(bases[i].Data);
val.push(bases[i].Valor);
}
}
var chartGraph = new Chart(ctx,{
type:'line',
data:{
labels: Date,
datasets: [
{
label: "Lbl Name",
data: Val,
borderWidth: 6,
borderColor: 'rgba(77,166,253, 0.85)',
backgroundColor: 'transparent'
}
]
},
options: {
title: {
display: true,
fontSize: 20,
text: 'Chart Name'
},
legend: {
display: true,
position: 'right',
labels: {
fontColor: '#666'
}
}
}
})

Chart JS - Line chart with days in x-axis

I need to draw chart with the x-axis to be in day with 12.00 AM. It is using quite alot of point
This is my desire output
But this is the output I am getting:
I am getting this weird "Object object" in the x-axis
//I have truncated the stats as it exceeded the max length in SO
let response = '{"stats":[ { "time":"2018-10-24 13:30:02", "occupation":"54", "liveness":"78", "efficiency":"48", "pms":"up" }, { "time":"2018-10-24 13:45:02", "occupation":"55", "liveness":"78", "efficiency":"50", "pms":"up" }, { "time":"2018-10-24 14:00:01", "occupation":"56", "liveness":"76", "efficiency":"51", "pms":"up" }, { "time":"2018-10-24 14:15:02", "occupation":"56", "liveness":"77", "efficiency":"52", "pms":"up" }, { "time":"2018-10-24 14:30:01", "occupation":"56", "liveness":"78", "efficiency":"53", "pms":"up" }, { "time":"2018-10-24 14:45:01", "occupation":"57", "liveness":"79", "efficiency":"56", "pms":"up" }, { "time":"2018-10-24 15:00:02", "occupation":"57", "liveness":"79", "efficiency":"56", "pms":"up" }]}';
let parsedResponse = ($.parseJSON(response));
let stats = parsedResponse.stats;
let arrayDays = [];
$.each(parsedResponse.days, function(key, value) {
arrayDays.push(moment(value).toDate());
});
let statLength = stats.length;
let occupation = [];
let liveness = [];
let efficiency = [];
let labels = [];
parsedResponse = undefined;
let dataDateTime = '';
let dataDateTimeFormat = 'MMM DD HH:mm A';
for(let index = 0; index < statLength; index++) {
dataDateTime = moment(stats[index]['time']).format(dataDateTimeFormat);
// occupation.push({'x': dataDateTime, 'y': stats[index]['occupation']});
// liveness.push({'x': dataDateTime, 'y': stats[index]['liveness']});
// efficiency.push({'x': dataDateTime, 'y': stats[index]['efficiency']});
occupation.push(stats[index]['occupation']);
liveness.push(stats[index]['liveness']);
efficiency.push(stats[index]['efficiency']);
labels.push({dataDateTime});
}
let fill = false;
let color = Chart.helpers.color;
let data = {
labels: labels,
datasets: [{
label: 'Screens',
pointRadius: 0,
tension: 0,
backgroundColor: color(window.chartColors.green).alpha(0.5).rgbString(),
borderColor: window.chartColors.green,
fill: fill,
data: liveness
},{
label: 'Occupation',
pointRadius: 0,
tension: 0,
backgroundColor: color(window.chartColors.blue).alpha(0.5).rgbString(),
borderColor: window.chartColors.blue,
fill: fill,
data: occupation
},{
label: 'Efficiency',
pointRadius: 0,
tension: 0,
backgroundColor: color(window.chartColors.orange).alpha(0.5).rgbString(),
borderColor: window.chartColors.orange,
fill: fill,
data: efficiency
}]
};
let chartOptions = {
scales: {
yAxes: [{
ticks: {
beginAtZero:true,
stepSize: 10,
max: 100
},
scaleLabel: {
display: true,
labelString: 'Percentage'
}
}],
xAxes: [{
//editing this will mess it up pretty bad
}]
},
tooltips: {
callbacks: {
label: function(value, index) {
return index.datasets[value.datasetIndex].label + ": " + value.yLabel;
},
}
}
};
The thing is, I tried several times to edit the x-axis option but it keeps messing the output
Your variable dataDateTime, for some reason, you are pushing it as an object in the label value, right here:
labels.push({dataDateTime});
That's why you are getting an X-axis label with [Object object]... You have two possible solutions:
1.Change the push:
labels.push(dataDateTime);
2.Add a callback to the xAxes[0].ticks property:
xAxes: [{
ticks: {
callback: function(value, index, values) {
return value.dataDateTime
}
}
}]
Both will work well (I tested), you also can check this fiddle that I made, to check it working (using the first solution)

Horizontal stacked angular bar charts

I am trying to implement an Angular horizontal stacked bar chart- Something like this example.
However, I want just one bar that is stacked.
I am working with AngularJS and Chart.js. I have the example showing on the page.
In the PieController, ChartData contains:
{"data":["63","38"],"labels":["Ford","GM"]}
In the example, instead of the label on the outside, I would like the label and then the number to be inside the chart. Like [=====Ford 63====|===GM 38===] the equals represent bar colors. There will be more data points than the current two.
Here is my page
<div ng-controller="PieController">
data {{ChartData}} //testing purposes
<div ng-init="getBarChart()">
<canvas id="Chart1"></canvas>
</div>
Here is my JavaScript controller
app.controller('PieController', function($scope, ChartService) {
$scope.getBarChart = function(){
ChartService.get({name: 'main'}, function(data) {
$scope.ChartData = data;
var barOptions_stacked = {
tooltips: {
enabled: false
},
hover: {
animationDuration: 0
},
scales: {
xAxes: [{
ticks: {
beginAtZero: true,
fontFamily: "'Open Sans Bold', sans-serif",
fontSize: 11
},
scaleLabel: {
display: false
},
gridLines: {},
stacked: true
}],
yAxes: [{
gridLines: {
display: false,
color: "#fff",
zeroLineColor: "#fff",
zeroLineWidth: 0
},
ticks: {
fontFamily: "'Open Sans Bold', sans-serif",
fontSize: 11
},
stacked: true
}]
},
legend: {
display: false
},
animation: {
onComplete: function () {
var chartInstance = this.chart;
var ctx = chartInstance.ctx;
ctx.textAlign = "left";
ctx.font = "9px Open Sans";
ctx.fillStyle = "#fff";
Chart.helpers.each(this.data.datasets.forEach(function (dataset, i) {
var meta = chartInstance.controller.getDatasetMeta(i);
Chart.helpers.each(meta.data.forEach(function (bar, index) {
data = dataset.data[index];
if (i == 0) {
ctx.fillText(data, 50, bar._model.y + 4);
} else {
ctx.fillText(data, bar._model.x - 25, bar._model.y + 4);
}
}), this)
}), this);
}
},
pointLabelFontFamily: "Quadon Extra Bold",
scaleFontFamily: "Quadon Extra Bold",
};
var ctx = document.getElementById("Chart1");
var myChart = new Chart(ctx, {
type: 'horizontalBar',
data: {
labels: ["2014", "2013", "2012", "2011"],
datasets: [{
data: [727, 589, 537, 543, 574],
backgroundColor: "rgba(63,103,126,1)",
hoverBackgroundColor: "rgba(50,90,100,1)"
}, {
data: [238, 553, 746, 884, 903],
backgroundColor: "rgba(163,103,126,1)",
hoverBackgroundColor: "rgba(140,85,100,1)"
}, {
data: [1238, 553, 746, 884, 903],
backgroundColor: "rgba(63,203,226,1)",
hoverBackgroundColor: "rgba(46,185,235,1)"
}]
},
options: barOptions_stacked,
})
});//end chat service.get
}
});
Instead of hard coding in the dataset which is what its doing now, is there a way I can use the data "ChartData" that I outlined in the beginning of the post?
I'm not sure how to do it or if its even possible.
In order to get the label to show in the bar, reference the labels property of $scope.ChartData:
ctx.fillText($scope.ChartData.labels[index] +" "+ data, 50, bar._model.y + 4);
Instead of hard coding in the dataset which is what its doing now, is there a way I can use the data "ChartData" that I outlined in the beginning of the post?
Use properties from the data variable (supplied by the ChartService get function) i.e. data.labels and data.data instead of the hard-coded values.
So update the labels line from:
labels: ["2014", "2013", "2012", "2011"],
To this:
labels: data.labels,
And similarly for the datasets:
datasets: [{
data: data.data,
So when creating the Chart it should look like this:
var myChart = new Chart(ctx, {
type: 'horizontalBar',
data: {
labels: data.labels,
datasets: [{
data: data.data,
backgroundColor: "rgba(63,103,126,1)",
hoverBackgroundColor: "rgba(50,90,100,1)"
}]
},
options: barOptions_stacked,
});
Expand the code snippet below for a demonstration.
Note: there is currently an issue with the resize-listener, blocked by a CORS issue - I am trying to find a way to disable that.
Update:
Per your comment about stacking the bars (horizontally) - yes that is possible. Just have one element in the datasets array for each item. One simple way to have this is to use Array.map() to create an array similar to the example:
var bgColors = [
"rgba(63,103,126,1)",
"rgba(50,90,100,1)"
];
var hoverBgColors = [
"rgba(50,90,100,1)",
"rgba(140,85,100,1)"
];
var datasets = data.data.map(function(value, index) {
return {
data: [value],
backgroundColor: bgColors[index],
hoverBackgroundColor: hoverBgColors[index]
}
});
Then use variable datasets when creating the Chart object:
var myChart = new Chart(ctx, {
type: 'horizontalBar',
data: {
labels: data.labels,
datasets: datasets
},
options: barOptions_stacked,
});
Also, there is some weird math going on for the location of the second label but the helper function can be updated like below (I tried dividing the x value by 75 but that may need to be adjusted - I am not sure what "appropriate" values are for that ...):
if (i == 0) {
ctx.fillText($scope.ChartData.labels[i] + " " + data, 50, bar._model.y + 4);
} else {
ctx.fillText($scope.ChartData.labels[i] + " " + data, (bar._model.x - 25) / 75, bar._model.y + 4);
}
var app = angular.module('myApp', []);
app.factory('ChartService', function() {
return { //dummy chart service
get: function(obj, callback) {
var data = {
"data": ["63", "38"],
"labels": ["Ford", "GM"]
};
callback(data);
}
};
});
app.controller('PieController', function($scope, ChartService) {
$scope.getBarChart = function() {
ChartService.get({
name: 'main'
}, function(data) {
$scope.ChartData = data;
var barOptions_stacked = {
tooltips: {
enabled: false
},
hover: {
animationDuration: 0
},
scales: {
xAxes: [{
ticks: {
beginAtZero: true,
fontFamily: "'Open Sans Bold', sans-serif",
fontSize: 11
},
scaleLabel: {
display: false
},
gridLines: {},
stacked: true
}],
yAxes: [{
gridLines: {
display: false,
color: "#fff",
zeroLineColor: "#fff",
zeroLineWidth: 0
},
ticks: {
fontFamily: "'Open Sans Bold', sans-serif",
fontSize: 11
},
stacked: true
}]
},
legend: {
display: false
},
animation: {
onComplete: function() {
var chartInstance = this.chart;
var ctx = chartInstance.ctx;
ctx.textAlign = "left";
ctx.font = "9px Open Sans";
ctx.fillStyle = "#fff";
Chart.helpers.each(this.data.datasets.forEach(function(dataset, i) {
var meta = chartInstance.controller.getDatasetMeta(i);
Chart.helpers.each(meta.data.forEach(function(bar, index) {
data = dataset.data[index];
if (i == 0) {
ctx.fillText($scope.ChartData.labels[i] + " " + data, 50, bar._model.y + 4);
} else {
ctx.fillText($scope.ChartData.labels[i] + " " + data, (bar._model.x - 25) / 75, bar._model.y + 4);
}
}), this)
}), this);
}
},
pointLabelFontFamily: "Quadon Extra Bold",
scaleFontFamily: "Quadon Extra Bold",
};
var ctx = document.getElementById("Chart1");
var bgColors = [
"rgba(63,103,126,1)",
"rgba(50,90,100,1)"
];
var hoverBgColors = [
"rgba(50,90,100,1)",
"rgba(140,85,100,1)"
];
var datasets = data.data.map(function(value, index) {
return {
data: [value],
backgroundColor: bgColors[index],
hoverBackgroundColor: hoverBgColors[index]
}
});
var myChart = new Chart(ctx, {
type: 'horizontalBar',
data: {
//use empty labels because the labels are on the bars
labels: data.labels.map(function() {
return '';
}),
datasets: datasets
},
options: barOptions_stacked,
})
}); //end chat service.get
}
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/Chart.js/2.1.3/Chart.js"></script>
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.23/angular.min.js"></script>
<div ng-app="myApp" ng-controller="PieController">
data {{ChartData}} //testing purposes
<div ng-init="getBarChart()">
<canvas id="Chart1"></canvas>

Jquery - Counting JSON objects

Im building a chart system that will show me all data entries. I retrieve my data using ajax and I loop trough the data and group the results by colors (red, blue and yellow) and then divide them by months.
I setup base objects (dateCounts_Red, dateCounts_Blue and dateCounts_Yellow) so that by default it starts all months at 0. A counter would then add when it finds a match tot he apropriate color and month.
When I output my dateCounts I get:
{"2015":{"2015-12":1,"2015-10":null,"2015-08":null,"2015-11":null}}
{"2015":{"2015-12":0,"2015-10":null}}
{"2015":{"2015-12":0,"2015-10":null}}
Here is the code I have so far:
var dateCounts_Red = {"2015":{"2015-01":0,"2015-02":0,"2015-03":0,"2015-04":0},"2015":{"2015-05":0},"2015":{"2015-06":0},"2015":{"2015-07":0},"2015":{"2015-08":0},"2015":{"2015-09":0},"2015":{"2015-10":0},"2015":{"2015-11":0},"2015":{"2015-12":0}};
var dateCounts_Blue = {"2015":{"2015-01":0,"2015-02":0,"2015-03":0,"2015-04":0},"2015":{"2015-05":0},"2015":{"2015-06":0},"2015":{"2015-07":0},"2015":{"2015-08":0},"2015":{"2015-09":0},"2015":{"2015-10":0},"2015":{"2015-11":0},"2015":{"2015-12":0}};
var dateCounts_Yellow = {"2015":{"2015-01":0,"2015-02":0,"2015-03":0,"2015-04":0},"2015":{"2015-05":0},"2015":{"2015-06":0},"2015":{"2015-07":0},"2015":{"2015-08":0},"2015":{"2015-09":0},"2015":{"2015-10":0},"2015":{"2015-11":0},"2015":{"2015-12":0}};
data.d.results.forEach(function(element) {
var date = element.created_date.slice(0, 7);
var yr = date.slice(0, 4);
var Color = element.colorvalue;
if(Color == "red") {
dateCounts_Red[yr][date]++;
}
if(Color == "blue"){
dateCounts_Blue[yr][date]++;
}
if(Color == "yellow"){
dateCounts_Yellow[yr][date]++;
}
});
Red_yr_2015_data = [dateCounts_Red['2015']['2015-01'], dateCounts_Red['2015']['2015-02'], dateCounts_Red['2015']['2015-03'], dateCounts_Red['2015']['2015-04'], dateCounts_Red['2015']['2015-05'], dateCounts_Red['2015']['2015-06'], dateCounts_Red['2015']['2015-07'], dateCounts_Red['2015']['2015-08'], dateCounts_Red['2015']['2015-09'], dateCounts_Red['2015']['2015-10'], dateCounts_Red['2015']['2015-11'], dateCounts_Red['2015']['2015-12']];
Blue_yr_2015_data = [dateCounts_Blue['2015']['2015-01'], dateCounts_Blue['2015']['2015-02'], dateCounts_Blue['2015']['2015-03'], dateCounts_Blue['2015']['2015-04'], dateCounts_Blue['2015']['2015-05'], dateCounts_Blue['2015']['2015-06'], dateCounts_Blue['2015']['2015-07'], dateCounts_Blue['2015']['2015-08'], dateCounts_Blue['2015']['2015-09'], dateCounts_Blue['2015']['2015-10'], dateCounts_Blue['2015']['2015-11'], dateCounts_Blue['2015']['2015-12']];
Yellow_yr_2015_data = [dateCounts_Yellow['2015']['2015-01'], dateCounts_Yellow['2015']['2015-02'], dateCounts_Yellow['2015']['2015-03'], dateCounts_Yellow['2015']['2015-04'], dateCounts_Yellow['2015']['2015-05'], dateCounts_Yellow['2015']['2015-06'], dateCounts_Yellow['2015']['2015-07'], dateCounts_Yellow['2015']['2015-08'], dateCounts_Yellow['2015']['2015-09'], dateCounts_Yellow['2015']['2015-10'], dateCounts_Yellow['2015']['2015-11'], dateCounts_Yellow['2015']['2015-12']];
Im currently getting the following error from my Highcharts js:
Uncaught TypeError: Cannot set property 'index' of undefined
THis is preventing the chart system to work correctly the data returned is not being returned with it's expected data.
Here a full example to the issue https://jsfiddle.net/awo5aaqb/21/
Would anyone know what im missing?
Your date count objects have major structural flaw.
When you prettify them they look like:
var dateCounts_Blue = {
"2015": {
"2015-01": 0,
"2015-02": 0,
"2015-03": 0,
"2015-04": 0
},
"2015": {
"2015-05": 0
},
"2015": {
"2015-06": 0
},
"2015": {
"2015-07": 0
},
......
Object keys must be unique so these are clearly being repeated and the compiler will over write duplicates.
Fix the pattern that breaks away from the intended pattern grouping at the beginning
var dateCounts_Red = {
"2015":
{
"2015-01":0,
"2015-02":0,
"2015-03":0,
"2015-04":0,
"2015-05":0,
"2015-06":0,
"2015-07":0,
"2015-08":0,
"2015-09":0,
"2015-10":0,
"2015-11":0,
"2015-12":0
},
};
var dateCounts_Blue = {
"2015":{
"2015-01":0,
"2015-02":0,
"2015-03":0,
"2015-04":0,
"2015-05":0,
"2015-06":0,
"2015-07":0,
"2015-08":0,
"2015-09":0,
"2015-10":0,
"2015-11":0,
"2015-12":0
}
};
var dateCounts_Yellow = {
"2015":{
"2015-01":0,
"2015-02":0,
"2015-03":0,
"2015-04":0,
"2015-05":0,
"2015-06":0,
"2015-07":0,
"2015-08":0,
"2015-09":0,
"2015-10":0,
"2015-11":0,
"2015-12":0}
};
Your data structure is flawed and such comparing values when doing the foreach loop becomes inconsistent because it compares it to multiple values, the above JSON is the fix for your problem.
Not quite codereview.stackexchange.com, but I heavily modified your javascript to make it work a bit better
$.ajax({
url: basePath,
dataType: 'json',
cache: false,
success: function(data) {
var counts = {};
data.d.results.forEach(function(element) {
// If you know it's all the same year, you could totally ignore this
var yr = element.created_date.slice(0, 4);
var month = parseInt(element.created_date.slice(5,7));
var color = element.colorvalue;
if (counts[color] === undefined) {
counts[color] = {};
}
if (counts[color][yr] === undefined) {
counts[color][yr] = {};
}
current_value = counts[color][yr][month];
if (current_value === undefined) {
// Doesnt exist yet, so add it
counts[color][yr][month] = 1;
} else {
// Exists, so increment by 1
counts[color][yr][month] = current_value + 1;
}
});
console.log(JSON.stringify(counts));
console.log(transform_series(counts['red']['2015']));
console.log(transform_series(counts['blue']['2015']));
console.log(transform_series(counts['yellow']['2015']));
var Options = {
chart: {
renderTo: 'myfirstchart',
type: 'column',
margin: 75,
options3d: {
enabled: true,
alpha: 25,
beta: 0,
depth: 70
}
},
title: {
text: "Test Highcharts"
},
subtitle: {
text: 'Test charts'
},
plotOptions: {
column: {
depth: 25
}
},
xAxis: {
categories: ["Janvier", "Février", "Mars", "Avril", "Mai", "Juin", "Juillet", "Août", "Septembre", "Octobre", "Novembre", "Décembre"]
},
yAxis: {
title: {
text: "Number of entries"
}
},
tooltip: {
headerFormat: '<b>{point.key}</b><br>',
pointFormat: '<span style="color:{series.color}">\u25CF</span> {series.name}: {point.y} / {point.stackTotal}'
},
plotOptions: {
column: {
stacking: 'normal',
depth: 40
}
},
series: [{
name: 'Red',
color: 'red',
data: transform_series(counts['red']['2015']),
stack: '2015'
}, {
name: 'Blue',
color: 'blue',
data: transform_series(counts['blue']['2015']),
stack: '2015'
}, {
name: 'Yellow',
color: 'yellow',
data: transform_series(counts['yellow']['2015']),
stack: '2015'
}]
};
return new Highcharts.Chart(Options);
}
});
// this transforms the hash {10: 5, 11:1, 12:1} to get you all 12 months
// and returns an array of values [ 0, 0, 0, 0, 0 ... 5, 1, 1] that
// can be used in high charts
function transform_series(series) {
return Array.apply(null, Array(13)).map(function (_, i) {return (series[i] === undefined) ? 0 : series[i];}).slice(1,13);
}

Categories

Resources