ChartJS looping string issue - javascript

I am trying to use chart.JS in order to render dynamicaly charts in my django app
I am trying to generate dynamic datasets based on the number of users.
I used the following code to loop on my users:
$.ajax({
method: "GET",
url: endpoint,
success: function(data){
console.log(data)
//Labels comming from wevsite.views//
team = data.team_list
info_data = data.info_process_data
var datasetValue = [];
var name = team
var count = name.length;
for (var j=0; j<count; j++) {
datasetValue[j] = {
backgroundColor: 'rgba(220,220,220,0.5)',
label : name[j],
data : info_data,
};
}
var looped_data = JSON.stringify(datasetValue);
var ctx = document.getElementById("mainGraph").getContext('2d');
var info_process = new Chart(ctx2,{
type: 'radar',
data: {
labels: labels_info,
datasets: looped_array
},
options: {
scale: {display: true,
ticks: {
beginAtZero: true,
}
},
responsive:true,
maintainAspectRatio: true,
}
});
})
I get the error Uncaught TypeError: Cannot create property '_meta' on string.
I guess because chartsJS does not accept string ..
How can I make it work ?
Thx you very much

Related

Why does my variables reset inside ajax request?

I'm currently trying to use CanvasJS to render multiple charts on my page, and using AJAX to get the data for the tables. I'm using a loop on the AJAX to get the data values, and that's working fine atm, but I'm having problems on getting the value of a variable outside the AJAX.
This is the part I'm having problems with:
for(var i = 0; i < nMeses; i++) {
var mes = dtIni.addMonths(i);
var ano = mes.getFullYear();
mes = mes.getMonth()+1;
mes = (mes<10 ? '0' : '') + mes;
var res = ano + mes;
console.log(res);
$.ajax({
url: "getMesGrafico.php",
type: "GET",
dataType: "json",
data: {"m": mes},
success: function(data) {
console.log(res);
var chart = new CanvasJS.Chart("body"+res, {
animationEnabled: true,
theme: "light1", // "light1", "light2", "dark1", "dark2"
title:{
text: "Gráfico de contas a pagar do mês"
},
data: [{
type: "column", //change type to bar, line, area, pie, etc
dataPoints: data
}]
});
chart.render();
},
error: function(data) {
console.log("Error");
}
});
}
Inside the ajax>success I'm successfully getting the data I want, but I can't get the right value for 'res'. My console output is currently: 201912 202001 202001 202001, but I'm trying to understand why the first and second values are different since they are in the same loop.
It's beeen a long time since I've used jquery, however:
$.ajax() is an async function, which means it just makes the request and keeps going, it doesn't wait for the response, which is why you need to specify your code inside the "success" callback.
If you want your "res" variable to update synchronously, you should make the async request using a polling function.
Make the request, wait for the response, increase your counter and call the function again.
Here's an example:
let i = 0;
(function poll(){
var mes = dtIni.addMonths(i);
var ano = mes.getFullYear();
mes = mes.getMonth()+1;
mes = (mes<10 ? '0' : '') + mes;
var res = ano + mes;
console.log(res);
$.ajax({
url: "getMesGrafico.php",
type: "GET",
dataType: "json",
data: {"m": mes},
success: function(data) {
console.log(res);
var chart = new CanvasJS.Chart("body"+res, {
animationEnabled: true,
theme: "light1", // "light1", "light2", "dark1", "dark2"
title:{
text: "Gráfico de contas a pagar do mês"
},
data: [{
type: "column", //change type to bar, line, area, pie, etc
dataPoints: data
}]
});
chart.render();
//once the request is done, increase "i" and call poll() again
i++;
if(i < nMeses)
poll();
},
error: function(data) {
console.log("Error");
}
});
})();

How to properly code Javascript / Ajax for use with Chart.js

I have a controller action in my MVC project that creates a json record with the components needed. This is working. The issue I am having is bringing it into a chart.js canvas. This will be a pie chart that shows all the related countries with a count of each. Json has this info. Originally this was setup to use google visualization but I want to use chart.js. I just started using it. Creating charts with static data is no issue but I am pulling the info from a SQL table and creating a json to read from.
I have tried using the same structure and calling the data: data[] but it doesn't work I have also tried data: getData, which is a var for the ajax function. I am getting the data per the council on refresh.
Here is my controller Action
public ActionResult CustomersByCountry()
{
CustomerEntities _context = new CustomerEntities();
var customerByCountry = (from c in _context.Addresses
group c by c.Country into g
orderby g.Count() descending
select new
{
Country = g.Key,
CountCustomer = g.Count()
}).ToList();
return Json(new { result = customerByCountry }, JsonRequestBehavior.AllowGet);
}
And here is the JavaScript/ajax - which is nested in a document.ready function with the rest of the charts.
EDIT - changed Ajax - Still not working
OrdersByCountry()
function OrdersByCountry() {
$.ajax({
url: '/admin/CustomersByCountry',
method: "GET",
dataType: "json",
error: function (_, err) {
console.log(_, err)
},
success: function (data) {
console.log (data);
var customer = $("#customerByCountryPieChart").get(0).getContext("2d");
console.log(customer)
var cpieChart = new Chart(customer, {
type: 'pie',
data: data,
options: {
responsive: true,
title: {
display: true,
text: "Customers By Country",
}
}
});
}
});
};
Edit - The now working code is below.
I changed it to get states instead of country, just to clear up possible confusion. It made more sense to me to get States rather than Country at this point. This is working - meaning displaying the graph, I still need to work on the labels etc.
OrdersByStates()
function OrdersByStates() {
$.ajax({
url: '#Url.Action("CustomersByStates", "Admin")',
data: JSON,
contentType: "application/json; charset=utf-8",
method: "get",
dataType: "json",
error: function (_, err) {
console.log(_, err)
},
success: function (response) {
console.log(response);
var jsonresult = response
var labels = jsonresult.result.map(function (e) {
return e.State;
});
var data = jsonresult.result.map(function (e) {
return e.CountCustomer;
});;
var ctx = document.getElementById("CustomerByStatePieChart").getContext("2d");
var cpieChart = new Chart(ctx, {
type: 'pie',
data:
{
datasets: [
{
backgroundColor: ["#46BFBD", "#F7464A"],
hoverBackgroundColor: ["#5AD3D1", "#FF5A5E"],
label: "Orders",
data: data,
}]
},
options: {
responsive: true,
title: {
display: true,
text: "Customers By Country",
}
}
});
}
});
};
});
try:
var cpieChart = new Chart(customer, {
type: 'pie',
data: data.result,
options: {
responsive: true,
title: {
display: true,
text: "Customers By Country",
}
}
});
the response from the server "data" var on your request is {result: LIST}

Morris Chart with dynamic data from C#

I am trying to build a Morris graph in an ASP.NET web app, where the data that the graph is being populated with is coming from an ajax post to a C# method.
The return data is:
[{"process":"W3WP","xKey":"2018-8-1 7:00","yKey":"60"},
{"process":"Proc","xKey":"2018-8-1 7:00","yKey":"35"},
{"process":"W3WP","xKey":"2018-8-1 7:30","yKey":"75"},
{"process":"Proc","xKey":"2018-8-1 7:30","yKey":"30"},
{"process":"W3WP","xKey":"2018-8-1 8:00","yKey":"70"},
{"process":"Proc","xKey":"2018-8-1 8:00","yKey":"39"},
{"process":"W3WP","xKey":"2018-8-1 8:30","yKey":"71"},
{"process":"Proc","xKey":"2018-8-1 8:30","yKey":"30"}]
Basically, I want a graph that shows CPU usage for a list (dynamic) of processes. Each process should be represented by a line.
When I build the graph with the following JavaScript, the graph is not displaying correctly:
var procChart = new Morris.Line({
element: 'chartProcesses',
data: $.parseJSON(ProcGraph()),
xkey: ['xKey'],
ykeys: ['yKey'],
labels: ['process'],
hideHover: 'auto',
resize: true
});
The JSON post is as follows:
function ProcGraph() {
var data = "";
$.ajax({
type: 'POST',
url: 'Servers.aspx/GetGraphData',
dataType: 'json',
async: false,
contentType: "application/json; charset=utf-8",
data: {},
success: function (result) {
data = result.d;
alert(data);
},
error: function (xhr, status, error) {
alert(error);
}
});
return data;
}
And finally, the C# class:
public class GraphChartData
{
public string process { get; set; }
public string xKey { get; set; }
public string yKey { get; set; }
public GraphChartData(string process, string _xKey, string _yKey)
{
this.process = process;
this.xKey = _xKey;
this.yKey = _yKey;
}
public GraphChartData()
{
}
}
Graph results as follows:
Morris Graph
I made a WebMethod that simulates dynamic data:
It generates a random number of lines and processes (between 2 and 5), then returns an object containing the labels, the yKeys and the data needed for the Morris Line graph.
[WebMethod]
public static object GetGraphData()
{
Random random = new Random();
List<Dictionary<string, object>> processes = new List<Dictionary<string, object>>();
List<string> labels = new List<string>();
List<string> yKeys = new List<string>();
bool labelsDone = false;
int nbLines = random.Next(2, 5);
int nbProcesses = random.Next(2, 5);
for (int i = 0; i < nbLines; i++)
{
Dictionary<string, object> processLine = new Dictionary<string, object>();
string time = DateTime.Now.AddMinutes(i).ToString();
processLine.Add("datetime", time);
for (int j = 0; j < nbProcesses; j++)
{
processLine.Add($"processName{j + 1}", random.Next(100));
if (!labelsDone)
{
labels.Add($"Process Name{j + 1}");
yKeys.Add($"processName{j + 1}");
}
}
labelsDone = true;
processes.Add(processLine);
}
return new
{
labels = labels,
ykeys = yKeys,
processes = processes
};
}
JavaScript code used to get data from the WebMethod GetGraphData:
$(document).ready(function () {
ProcGraph();
});
function ProcGraph() {
var data = "";
$.ajax({
type: 'POST',
url: 'Servers.aspx/GetGraphData',
dataType: 'json',
contentType: "application/json; charset=utf-8",
data: {},
success: function (result) {
data = result.d;
SetMorris(data)
},
error: function (xhr, status, error) {
alert(error);
}
});
return data;
}
function SetMorris(data) {
var procChart = new Morris.Line({
element: 'chartProcesses',
data: data.processes,
xkey: ['datetime'],
ykeys: data.ykeys,
labels: data.labels,
hideHover: 'auto',
resize: true,
parseTime: false
});
}
Please try the following snippet using data generated from the WebMethod:
var data =
[
{ "datetime": "14/08/2018 14:41:28", "processName1": 2, "processName2": 50 },
{ "datetime": "14/08/2018 14:42:28", "processName1": 20, "processName2": 34 },
{ "datetime": "14/08/2018 14:43:28", "processName1": 17, "processName2": 81 },
{ "datetime": "14/08/2018 14:44:28", "processName1": 86, "processName2": 67 }
]
var procChart = new Morris.Line({
element: 'chartProcesses',
data : data,
xkey: ['datetime'],
ykeys: ['processName1', 'processName2'],
labels: ['ProcessName1', "Process Name1"],
hideHover: 'auto',
resize: true,
parseTime: false
});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<script src="//cdnjs.cloudflare.com/ajax/libs/raphael/2.1.0/raphael-min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/morris.js/0.5.1/morris.min.js"></script>
<link href="https://cdnjs.cloudflare.com/ajax/libs/morris.js/0.5.1/morris.css" rel="stylesheet"/>
<div id="chartProcesses"></div>
Make sure to set the parseTime attribute to false:
parseTime: false

How to make this code more simple or shorten?

I have this code below for displaying a chart. My problem here is that the labels and datasets are static not dynamic. Can this be possible to make dyanmic?.
var globalNewData = "";
function ChartDataLabel() {
var barChartData = {
labels: [globalNewData[0]["CandidateName"], globalNewData[1]["CandidateName"],
globalNewData[2]["CandidateName"], globalNewData[3]["CandidateName"],
globalNewData[4]["CandidateName"]],
datasets: [{
fillColor: "rgba(0,100,0,1)",
strokeColor: "black",
data: [globalNewData[0]["Votes"], globalNewData[1]["Votes"], globalNewData[2]["Votes"],
globalNewData[3]["Votes"], globalNewData[4]["Votes"]] // Votes = Number of Votes
}]
}
//var index = 11;
var ctx = document.getElementById("canvas").getContext("2d");
var barChartDemo = new Chart(ctx).Bar(barChartData, {
responsive: true,
barValueSpacing: 2
});
}
NewData();
function NewData() {
var url = '../Controller/_NewData'
var res = "";
$.ajax({
type: "POST",
url: url,
dataType: 'json',
// async: false,
success: function (response) {
var Data = response.data;
globalNewData = Data;
ChartDataLabel();
},
error: function (response) {
alert("error");
alert(response);
}
});
}
Controller
public JsonResult _NewData()
{
var Data = new List<object>();
Data = (from a in db.Testings
select new
{
TestID = a.TestID,
CandidateName = a.Candidatename,
Position = a.Position,
Votes = a.NoOfVotes
}).ToList<object>();
return Json(new
{
data = Data
}, JsonRequestBehavior.AllowGet);
}
What I mean in Static is as you can see in the chart code [globalNewData[0]["CandidateName"] It is fix(5) in how many data will be display in the chart. In Dynamic even it add new data it will add the array inside [6]... for example.
Any suggestion will be accepted.
You could map new arrays for labels and dataset data
Something like:
function ChartDataLabel(chartData) {
var barChartData = {
labels: chartData.labels,// reference to labels array created below
datasets: [{
fillColor: "rgba(0,100,0,1)",
strokeColor: "black",
data: chartData.points // reference to points array created below
}]
}
//var index = 11;
var ctx = document.getElementById("canvas").getContext("2d");
var barChartDemo = new Chart(ctx).Bar(barChartData, {
responsive: true,
barValueSpacing: 2
});
}
$.ajax({
...
success: function (response) {
// object with new arrays need to pass to charting function
var chartData ={
labels:[],
points:[]
}
// loop through response data and add to each of labels and points arrays
response.data.forEach(function(item){
chartData.labels.push(item.CandidateName);
chartData.points.push(item.Votes);
})
// pass chartData into function
ChartDataLabel(chartData);
}
})
There are numerous other methods that could be used to map these new arrays also that would reduce code needed even more. I used a longer method for better understanding
Alternative would be to do this mapping on server and send data from server so response.data contains the labels and points arrays needed

Redraw Morris Donut after AJAX call

I'm using Morris Donut for a dashboard I'm working on and retrieving data via AJAX using two date ranges as parameters. The problem I'm facing is when I enter two new date ranges the Donut Chart renders a new one on top of Donut already created upon page load. I've searched about and can see information on using setData(), but I have no idea how to include this within my code.
My Code:
$(document).ready(function () {
var start = $('#SearchStart').val();
var end = $('#SearchEnd').val();
populateDonut(start, end);
});
The search button does the following when clicked:
$('#DateRange').click(function() {
var start = $('#SearchStart').val();
var end = $('#SearchEnd').val();
populateDonut(start, end);
});
Here is the function that is called.
function populateDonut(start, end) {
var param = { start: start, end: end };
$.ajax({
type: "POST",
url: "/WebService.asmx/getDonutData",
contentType: "application/json; charset=utf-8",
dataType: 'json',
async: true,
data: JSON.stringify(param),
success: function (result) {
var data = eval("(" + result.d + ")");
var pieChart = '';
if (data.status == 0) {
var donut = Morris.Donut({
element: 'pieChart',
data: [
{ label: "Inbound", value: data.inbound },
{ label: "Outbound", value: data.outbound },
{ label: "Unanswered", value: data.unanswered }
],
colors: ['#1ca8dd', '#33b86c', '#ebc142'],
resize: true,
formatter: function (x) { return x + "%" }
});
}
}
});
}
Screenshot of what is happening after entering new date ranges:
Try calling $("#pieChart").empty(); before rendering the second chart.
Preferably in here:
$('#DateRange').click(function() {
var start = $('#SearchStart').val();
var end = $('#SearchEnd').val();
// Clear the existing chart before populating new donut
$("#pieChart").empty();
populateDonut(start, end);
});
I tried the below code and it's working with me :
$("#chart-id").empty();
You can use it on each time you call chart data .

Categories