Laravel 5.4 ChartJs - Use Collections/Arrays as Labels and Data - javascript

I wanted the chart's labels and data to be dynamic.
To get things started, I have a function called search in my Controller and it has a query like this:
$total_cost = DB::raw('SUM(qty * cost) as total_cost');
$total_grossrev = DB::raw('(SUM(price * qty)) as total_grossrev');
$total_profit = DB::raw('(SUM(price * qty)) - (SUM(qty * cost)) as total_profit');
$period = DB::raw('date(created_at) as period');
$format = 'j F Y h:i A';
$salesanalysis = DB::table('orders')
->whereDate('created_at','>=', $request->datefrom)
->whereDate('created_at', '<=', $request->dateto)
->where('status', 'served')
->select($total_cost, $total_grossrev, $total_profit, $period, 'created_at')
->groupBy('period')
->get();
And in my script to have the chart, this is my structure:
<script src="{{ asset('js/Chart.min.js') }}"></script>
<script>
let salesAnalysisChart = document.getElementById('salesAnalysisChart').getContext('2d');
let barChart = new Chart(salesAnalysisChart, {
responsive: true,
type:'bar',
data:{
labels:[ //period of salesanalysis ],
datasets:[{
label:'Sales',
data:[
// total_profit of salesanalysis
],
backgroundColor: 'rgba(73, 187, 235, 0.7)',
hoverBorderWidth: 1,
hoverBorderColor: '#000'
}]
},
options:{
maintainAspectRatio: false,
scales: {
yAxes: [{
ticks: {
beginAtZero: true,
}
}]
},
legend:{
position:'bottom',
display:false,
},
layout:{
padding: 0,
}
}
});
</script>
Also, the period of salesanalysis is gonna be parsed by Carbon with the use of $format. So I thought of using this syntax:
{{\Carbon\Carbon::parse($collection->period)->format($format)}}
The bottomline is, how am I gonna use the collection for the label and data of ChartJs.

At the bottom of the view create a buildChart function that takes the labels, data, and any other as paremeters. Pass them over using the PHP implode method and return the imploded variable in blade to a function that creates chart.
//View
buildChart({{ $variable }}, ect)

Somehow I managed to solve the problem.
In my controller, I did a query and converted it into array:
$salesanalysisarray = DB::table('orders')
->whereDate('created_at','>=', $request->datefrom)
->whereDate('created_at', '<=', $request->dateto)
->where('status', 'served')
->select($total_cost, $total_grossrev, $total_profit, $period, 'created_at')
->groupBy('period')
->get()
->toArray();
And in my script, I initialized another array and did a loop to push each data into the array itself:
var periodArray = new Array();
var profitArray = new Array();
var costArray = new Array();
#forelse($salesanalysis as $analysis)
periodArray.push("{{\Carbon\Carbon::parse($analysis->created_at)->format($format)}}");
profitArray.push("{{$analysis->total_profit}}");
costArray.push("{{$analysis->total_cost}}");
#empty
#endforelse

Related

Passing data to a chart javascript object and array

What is the best approach to display the data in a chart?
To begin, my application has an empty array that receives objects.
// location where the users are storage
let usersList = [];
// these are the information from an user
const newUser = {
name:`${user.name.first} ${user.name.last}`,
social: Math.floor(Math.random() * 1000 )
}
So, by the end of my code, I have the chart, everything is working but with dummy data.
const myChart = new Chart(ctx, {
type: 'line',
data: {
labels: ['Red', 'Blue', 'Yellow', 'Green', 'Purple', 'Orange'], // should get the usersList.name
datasets: [{
label: ' Views per channel ',
data: [12, 10, 3, 5, 2, 3], // // should get the usersList.social
borderWidth: 1
}]
},
options: {
scales: {
yAxes: [{
ticks: {
beginAtZero: true
}
}]
}
}
});
Ideally, I would need to change the labels to have the name of each user, and the data to have the social of each user. My initial thought was a for loop, but I remember that ES6 has array destructuring.
I am not sure how to approach the problem, do you have any insight?
Thank you very much.
You can use the Array.map() method on the usersList to create the arrays that contain the desired attributes of the users.
Your code would have to be changed as follows:
data: {
labels: usersList.map(u => u.name),
datasets: [{
label: ' Views per channel ',
data: usersList.map(u => u.social),
borderWidth: 1
}]
}

Filling Javascript Chart (line chart) with SQL data

I'm using .NET MVC. Currently I have a data set that fills in points for a JS chart. Currently, I have static data(numbers) in the data property of the data set. I'm looking for idea's, tutorials, how-to's, on how to fill the data property with data from my SQL DB. I've looked all over and see numerous tutorials with static data like I have.
var ctx2 = document.getElementById("totalSpendingChart");
var data2 = {
datasets: [{
label: "Spending",
data: [8,10,11,15], /* THIS.. how do I get SQL data here? */
borderColor: "#e8144d"
}],
labels: [ "2017", "2018", "2019"]
};
var LinChart1 = new Chart(ctx2, {
type: "line", data: data2, options: {
pointStyle: "circle",
legend: { display: false },
scales: { yAxes: [{ display: true, gridLines: { display: true } }], xAxes: [{ display: false, gridLines: { display: false } }] }
}
});
You somehow need to get the data from the backend (SQL) to the frontend (JavaScript).
Option 1
You could inject the data into your template (before you render the chart). For example by serializing your data to JSON and parse it using javascript:
<script>
var chartData = JSON.parse(<%= DataSet %>);
</script>
Option 2
You could create an endpoint (url to fetch the data from) which can be used in javascript with an ajax get request. Once the data is loaded you can render the chart:
$.ajax("https://your-endpoint-to-fetch-the-data")
.done(renderChart);
function renderChart(data) {
var ctx = document.getElementById("totalSpendingChart");
var chartData = {
datasets: [{
data: data,
// ...
}]
};
var lineChart = new Chart(ctx, {
// ...
});
};
(this example uses jQuery for the ajax part)

Get data from dynamic ID for Chart.js

I have created a simple chart.js line graph that can produce plots when there is a static "url" provided (Ex. localhost/test/data.php). On data.php there is a string of data that looks like this:
[{"bdi":"4","date":"2018-07-11"},{"bdi":"1","date":"2018-07-21"},{"bdi":"5","date":"2018-07-21"},{"bdi":"34","date":"2018-07-21"},{"bdi":"34","date":"2018-07-21"},{"bdi":"3","date":"2018-07-22"},{"bdi":"2","date":"2018-07-23"},{"bdi":"12","date":"2018-07-23"},{"bdi":"3","date":"2018-07-24"},{"bdi":"2","date":"2018-07-25"},{"bdi":"12","date":"2018-07-30"},{"bdi":"3","date":"2018-07-30"},{"bdi":"4","date":"2018-07-30"},{"bdi":"11","date":"2018-07-30"}]
The code for data.php looks like this:
<?php
//setting header to json
header('Content-Type: application/json');
//database
define('DB_HOST', 'localhost');
define('DB_USERNAME', 'root');
define('DB_PASSWORD', '');
define('DB_NAME', 'test');
//get connection
$mysqli = new mysqli(DB_HOST, DB_USERNAME, DB_PASSWORD, DB_NAME);
if(!$mysqli){
die("Connection failed: " . $mysqli->error);
}
//query to get data from the table
$query = sprintf("SELECT treatment_log.bdi, treatment_log.date FROM treatment_log WHERE treatment_fk = 21 ORDER BY created_at");
//execute query
$result = $mysqli->query($query);
//loop through the returned data
$data = array();
foreach ($result as $row) {
$data[] = $row;
}
//free memory associated with result
$result->close();
//close connection
$mysqli->close();
//now print the data
print json_encode($data); ?>
Notice that the treatment_fk is 21. This means that the graph will be generated for this specific customer.
I wanted to make it so that every time you visit a cutomer.php page there will be a graph generated for that specific customer (According to their data). So I redid my coding for data.php. Instead I put the code into customer.php as a prepared statment where treatment_fk would be a variable:
<?php
$cid = htmlentities ($_GET['customer_id']);
//query to get data from the table
$sql = sprintf("SELECT treatment_log.bdi, treatment_log.date FROM treatment_log WHERE treatment_fk = ? ORDER BY created_at");
$stmt = mysqli_stmt_init($conn);
mysqli_stmt_prepare($stmt, $sql);
mysqli_stmt_bind_param($stmt, "i", $cid);
mysqli_stmt_execute($stmt);
$data = array();
mysqli_stmt_bind_result($stmt, $bdi, $date);
while(mysqli_stmt_fetch($stmt)) {
$data[]['bdi'] = $bdi;
$data[]['date'] = $date;
}
//free memory associated with result
$result->close();
//now print the data
print json_encode($data); ?>
So now, every time you visit a unique customer with different ID's (in the url) a different string of data will be generated on the customer.php page.
Now the issue that I am facing is that I cannot successfully generate the line graph based on this string of data (bdi vs date).
Here is my code of the chart.js graphing field:
$(document).ready(function(){
$.ajax({
url: "http://localhost/test/data.php",
method: "GET",
success: function(data) {
console.log(data);
var bdi = [];
var date = [];
for(var i in data) {
date.push( data[i].date);
bdi.push(data[i].bdi);
}
var chartdata = {
labels: date,
datasets : [
{
label: 'BDI',
backgroundColor: 'rgba(239, 243, 255, 0.75)',
borderColor: 'rgba(84, 132, 255, 0.75)',
hoverBackgroundColor: 'rgba(200, 200, 200, 1)',
hoverBorderColor: 'rgba(200, 200, 200, 1)',
data: bdi
}
]
};
var ctx = $("#mycanvas");
var barGraph = new Chart(ctx, {
type: 'line',
data: chartdata,
options: {
responsive: true,
legend: {
position: 'bottom',
},
scales: {
yAxes: [{
ticks: {
fontColor: "rgba(0,0,0,0.5)",
fontStyle: "bold",
beginAtZero: true,
maxTicksLimit: 5,
padding: 20
},
gridLines: {
drawTicks: false,
drawBorder: false,
}
}],
xAxes: [{
gridLines: {
zeroLineColor: "transparent",
display: false
},
ticks: {
padding: 20,
fontColor: "rgba(0,0,0,0.5)",
fontStyle: "bold"
}
}]
},
tooltips: {
backgroundColor: 'rgba(255,255,255)',
titleFontColor: 'rgb(184,189,201)',
bodyFontColor: 'black',
displayColors: false,
borderColor: 'rgb(214,217,225)',
borderWidth: 1,
caretSize: 5,
cornerRadius: 2,
xPadding: 10,
yPadding: 10
}
}
});
},
error: function(data) {
console.log(data);
}
});
});
Notice that the URL is http://localhost/test/data.php.
Although this does generate graph, it is not a graph specific to the customer. I have tried to replace the url with http://localhost/test/view_customer?customer_id=12&operation=edit (to test if a change in URL would work). However, it still does not generate a graph. Keep in mind that when I visit http://localhost/test/view_customer?customer_id=12&operation=edit in the source code, there is a string of data bdi vs. date. Regardless a graph is still not generated.
Here is my question:
1. How do I make the URL dynamic so that I generates a graph based on the specific ID of the customer.php? (Is there a better way?)
P.s. remember that http://localhost/test/view_customer?customer_id=12&operation=edit did not generated a graph when it was placed as the url in chart.js code.
You are not creating the same type of array on customer.php as you are on data.php. Replace your while loop in customers with the below and you should have the same format of JSON.
while(mysqli_stmt_fetch($stmt)) {
$data[] = array('bdi' => $bdi, 'date' => $date);
}

How to add data to pie chart Javascript

I am trying to display the percentage of pets per owner in a pie chart, how do i push data to the piechart? the for loop keeps getting a SyntaxError: Unexpected token var. here's my code.
window.onload = function() {
var count = "<?php echo($i)?>";
var name = [];
var per = [];
var j = -1;
var chart = new CanvasJS.Chart("chartContainer", {
animationEnabled: true,
title: {
text: "TB_PET"
},
data: [{
type: "pie",
startAngle: 240,
yValueFormatString: "##0.00\"%\"",
indexLabel: "{label} {y}",
Error here-->for(var i = 0; i < count; i++){
name[i] = document.getElementById(i).value;
per[j] = document.getElementById(j).value;
dataPoints: [
{y: per[j], label: name[i]}
]
j--;
}
}]
});
chart.render();
}
You cannot iterate inside the object literal (configuration for the chart) that is passed as a parameter to a function call.
Iterate over you data prior to the new CanvasJS.Chart(...) call, and pass the variable as part of the config object.
Iterate here
var dataPoints = [];
for(...){
dataPoints.push(..);
]
then pass dataPoints in as below
var chart = new CanvasJS.Chart("chartContainer", {
animationEnabled: true,
title: {
text: "TB_PET"
},
data: [
{
type: "pie",
startAngle: 240,
yValueFormatString: '##0.00"%"',
indexLabel: "{label} {y}",
dataPoints: dataPoints
}
]
});
chart.render();
Note: This would be a comment if my rep was higher
I'm not familiar with php returns, but I would first start with manually changing the 'count' variable to be an actual number before moving forward. It appears that your for loop is evaluating the 'count' variable as a string and then throwing the error you're seeing.
https://airbrake.io/blog/javascript-error-handling/unexpected-token

Good practice to return DateTime from PHP to JS

I've created file api.php
<?php
// Prevent caching.
header('Cache-Control: no-cache, must-revalidate');
// The JSON standard MIME header.
header('Content-type: application/json');
//mssql_select_db("**", mssql_connect(**));
$conn=mssql_connect(***);
$query = "SELECT ROUND([AirTemp_C],1) as [T]
,[DT]
FROM [ASUTP].[dbo].[Temperature_ER]
WHERE [Place] = 'ER06' AND [DT] > '26.05.2015 11:00'";
$qwr_res = mssql_query($query);
while ($row=mssql_fetch_array($qwr_res))
{
$temps[] = array (
'x' => $row['DT'],
'y' => $row['T']
);
}
echo json_encode($temps);
?>
It returns JSON like [{"x":"2015-05-26 11:02:04","y":26.3}] with my measurments.
I want to use this data to draw graph using canvasjs-1.6.2. Here is my code:
window.onload = function () {
$.getJSON("api.php",function(data1)
{
var chart = new CanvasJS.Chart("chartContainer",
{
title:{
text: "Title",
fontSize: 30
},
animationEnabled: true,
zoomEnabled:true,
height: 500,
axisX:{
gridColor: "Silver",
tickColor: "silver",
labelAngle: -80,
valueFormatString: "DD.MM HH:mm"
},
toolTip:{
shared:true
},
theme: "theme2",
axisY: {
gridColor: "Silver",
tickColor: "silver"
},
legend:{
verticalAlign: "center",
horizontalAlign: "right"
},
data: [
{
type: "line",
showInLegend: true,
lineThickness: 2,
name: "T",
//markerType: "square",
color: "#F08080",
dataPoints: data1
}
],
legend:{
cursor:"pointer",
itemclick:function(e){
if (typeof(e.dataSeries.visible) === "undefined" || e.dataSeries.visible) {
e.dataSeries.visible = false;
}
else{
e.dataSeries.visible = true;
}
chart.render();
}
}
});
chart.render();
});
But it seems that this chart (or JS at all) cant use my Date value as a correct DateTime so chart can't render.
I've fixed this issue with such loop:
for(var i=0;i<data1.length;i++)
{
data1[i].x = new Date(data1[i].x);
}
I should notice that I'm using PHP 5.2 and I'm not allowed to upgrade it.
So my questions are:
Is my way to get data for chart via api.php correct?
Is there a way to pass correct DateTime values from php to JS without that loop convert?
As noted in comments, the most reliable cross-browser way to transfer dates is using a time value. UNIX time values are in seconds since 1970-01-01T00:00:00Z. Javascript time values are from the same epoch, but use milliseconds so you just multiply UNIX time values by 1000 and pass directly to the Date constructor.
So the JSON might be like:
'[{x:"1432788147300", y:26.3}]'
and if the x value is read into a variable called unixTimeValue, the code would be like:
var javascriptDate = new Date(unixTimeValue * 1000);
However, if you can't do that, you can parse strings like '2015-05-26 11:02:04' fairly easily. Assuming that the date is UTC, you can use Date.UTC to convert it to a date object:
function parseISOUTC(s) {
var b = s.split(/\D/);
return new Date(Date.UTC(b[0],b[1],b[2],b[3],b[4],b[5]));
}

Categories