I'm having next problem -> when i use the encode json string printed by a php echo tag in my front-end everything works, but when i want to use it with the angular get function I don't get it to work.
Codeigniter Controller (back-end)
public function getLogs(){
$this->load->model('Home_model');
$logs = $this->Home_model->getLogs();
echo json_encode($logs);
}
AngularJs Controller (front-end)
$http.get('index.php/Welcome/getLogs')
.then(function (response) {
json = response.data;
});
var chartjsData = [];
for (var i = 0; i < json.length; i++) {
chartjsData.push(json[i].aantal);
}
var chartjsLabels = [];
for (var i = 0; i < json.length; i++) {
chartjsLabels.push(json[i].datum);
}
var ctx = document.getElementById('myChart').getContext('2d');
var myChart = new Chart(ctx, {
type: 'line',
data: {
labels: chartjsLabels,
datasets: [{
label: "Aantal meldingen",
borderColor: 'rgb(255, 131, 48)',
data: chartjsData,
fill: false
}]
},
options: {
responsive: false
}
});
Thanks in advance!
Since, the $http.get() method is asynchronous, you need to initialize your chart inside the callback function of $http.get() , like so ...
$http.get('index.php/Welcome/getLogs')
.then(function(response) {
json = response.data;
json = JSON.parse(json); //parse JSON string (if needed)
var chartjsData = [];
for (var i = 0; i < json.length; i++) {
chartjsData.push(json[i].aantal);
}
var chartjsLabels = [];
for (var i = 0; i < json.length; i++) {
chartjsLabels.push(json[i].datum);
}
var ctx = document.getElementById('myChart').getContext('2d');
var myChart = new Chart(ctx, {
type: 'line',
data: {
labels: chartjsLabels,
datasets: [{
label: "Aantal meldingen",
borderColor: 'rgb(255, 131, 48)',
data: chartjsData,
fill: false
}]
},
options: {
responsive: false
}
});
});
Related
I am new to generating a chart using the ajax mechanism and chartjs. It seems that I managed to generate the graph but they are plotted incorrectly. Please enlighten me on how I could improve. Would really appreciate Thank you
Following is my code in javascript to plot chart
var ctx = document.getElementById('myChart').getContext('2d');
$.ajax({
url:"/dashboard",
type:"POST",
data: {},
error: function() {
alert("Error");
},
success: function(data, status, xhr) {
debugger
// declare all variables to draw chart
var chartDim = {};
var chartDim = data.chartDim;
var xLabels = data.labels;
var vLabels = [];
var vData = [];
let newValues =[]
// get from database to push to draw the chart
for (const [key, values] of Object.entries(chartDim)) {
vLabels.push(key);
let newValues = values.map(myFunction);
debugger;
vData.push(newValues);
}
debugger
var myChart = new Chart(ctx, {
data: {
labels: xLabels,
datasets: []
},
options: {
responsive: false
}
});
// draw to chart
debugger
for (i= 0; i < vLabels.length; i++ ) {
myChart.data.datasets.push({
label: vLabels[i],
type: "bar",
// borderColor: '#'+(0x1ff0000+Math.random()*0xffffff).toString(16).substr(1,6),
borderColor: '#'+(0x1100000+Math.random()*0xffffff).toString(16).substr(1,6),
backgroundColor: "rgba(249, 238, 236, 0.74)",
data: vData[i],
spanGaps: true
});
myChart.update();
}
}})
This happens because while making your chart you push each data point as a new dataset. Instead you just need to use a single dataset and pass the data array to it like so:
var myChart = new Chart(ctx, {
type: 'bar',
data: {
labels: xLabels,
datasets: [{
borderColor: '#' + (0x1100000 + Math.random() * 0xffffff).toString(16).substr(1, 6),
backgroundColor: "rgba(249, 238, 236, 0.74)",
data: vData,
spanGaps: true
}]
},
options: {
responsive: false
}
});
I'm creating a chart using chart.js, when I open the web page the chart is there but the data only loads when I resize the window after a few seconds. I assume its something to do with the asynchronous functions but i'm not sure?
Here is my code
let xlabels = [];
let ydata = [];
chartIt();
async function chartIt(){
await getData();
const ctx = document.getElementById('chart').getContext('2d');
const myChart = new Chart(ctx, {
type: 'line',
data: {
labels: xlabels,
datasets:[{
data: ydata
}],
},
options: {
scales: {
yAxes: [{
ticks: {
beginAtZero: true
}
}]
}
}
});
}
async function getData(){
fetch('/test')
.then(function (response) {
return response.json();
})
.then(function (text){
for(var i= 0; i < text.length; ++i){
const date = text[i].date;
xlabels.push(date);
const mass=text[i].mass;
ydata.push(mass);
}
});
}
I want to display separate charts. When the user selects more than 1 SensorData on the page it should display the data of the sensors separately. What I'm now getting is basically a so called "multi chart", which I do not want.
This is the code for drawing the chart based upon the data that gets returned from the Ajax POST call:
var visualisesensor = [];
$(document).ready(function () {
//When the button is clicked it should add the ID's from the Sensors I want to visualise in to an array.
$("#visualisebtn").click(function () {
$.each($("input[name='removecheckbox']:checked"), function () {
visualisesensor.push($(this).val());
});
//This is where I create multiple DIVs based upon howmany Sensors the user selected to display
for (var i = 0; i < visualisesensor.length; i++) {
$("#chart-container").append("<canvas id=" + visualisesensor[i] + "></canvas>");
}
//This is where I basically draw the charts based upon the amount of sensors the user selected
$.ajax({
url: "visualise.php",
method: "POST",
data: {visualisesensor: visualisesensor},
success: function (data) {
var Sensornaam = [];
var Temperatuur = [];
for (var i in data) {
Sensornaam.push("Sensor: " + data[i].Sensornaam);
Temperatuur.push(data[i].Temperatuur);
}
var chartdata = []
for (var k = 0; k < data.length; k++) {
chartdata = {
labels: Temperatuur,
datasets: [
{
label: 'Sensor Temperatuur',
backgroundColor: 'rgba(200, 200, 200, 0.75)',
borderColor: 'rgba(200, 200, 200, 0.75)',
hoverBackgroundColor: 'rgba(200, 200, 200, 1)',
hoverBorderColor: 'rgba(200, 200, 200, 1)',
data: Temperatuur[k]
}
]
};
}
for (var j = 0; j < data.length; j++) {
var ctx = $("#" + data[j].SensorID);
var barGraph = new Chart(ctx, {
type: 'bar',
data: chartdata,
});
console.log(chartdata[j]);
alert('Chart has been added!');
}
},
error: function (data) {
console.log(data);
}
});
});
});
This is the visualise.php code:
<?php
//setting header to json
header('Content-Type: application/json');
include ('../DATABASE/connection.php');
if(isset($_POST["visualisesensor"]))
{
$j = implode(',',$_POST["visualisesensor"]);
$query = sprintf("SELECT SensorID, Sensornaam, Temperatuur FROM sensoren WHERE SensorID in ($j)");
$result = $con->query($query);
//loop through the returned data
$data = array();
foreach ($result as $row) {
$data[] = $row;
}
//free memory associated with result
$result->close();
//close connection
$con->close();
//now print the data
print json_encode($data);
}
?>
What I'm now getting is a multichart. It display the data that's in the array successfully, but just in the same chart. I want the data of the sensors to be separately displayed. How would I go about this?
What's inside data:
Picture of database:
Picture of the output I get (and don't want):
The success function of the $.ajax call is very odd; I can't understand why the data variable is iterated 3 separate times. Since no test data was provided in the question I've reverse-engineered some, based on the code, and created a simplified answer that draws three separate charts:
// spoofed user input for testing.
var visualisesensor = ['1', '2'];
// spoofed ajax result data for test purposes.
var data = [{
SensorID: '1',
Sensornaam: 'tempsensor',
Temperatuur: '45'
}, {
SensorID: '2',
Sensornaam: 'meter',
Temperatuur: '83'
}];
for (var i = 0; i < visualisesensor.length; i++) {
$("#chart-container").append("<canvas id=" + visualisesensor[i] + "></canvas>");
}
for (var i = 0; i < data.length; i++) {
var ctx = $("#" + data[i].SensorID);
var chartdata = {
labels: [data[i].Sensornaam],
datasets: [{
label: 'Sensor Temperatuur',
backgroundColor: 'rgba(200, 200, 200, 0.75)',
borderColor: 'rgba(200, 200, 200, 0.75)',
hoverBackgroundColor: 'rgba(200, 200, 200, 1)',
hoverBorderColor: 'rgba(200, 200, 200, 1)',
data: [data[i].Temperatuur]
}]
};
new Chart(ctx, {
type: 'bar',
data: chartdata,
options: {
scales: {
yAxes: [{
ticks: {
beginAtZero: true
}
}]
}
}
});
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/Chart.js/2.9.3/Chart.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<div id="chart-container"></div>
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
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
}
}
});