i want to process generated Eloquent result data in server side before show it to Chart.js, all the data are dynamically generated from databases.
I've facing some issue while try to increment subtotal values for the same items_name and sales_date and then show labels, x & y axis from database.
Here's my Eloquent ->toArray() response :
array:5 [
0 => array:3 [
"sales_date" => "2021-02-25"
"subtotal" => 800000
"items_name" => "Kitchen Set"
],
1 => array:3 [
"sales_date" => "2021-02-25"
"subtotal" => 2000000
"items_name" => "Kitchen Set"
],
2 => array:3 [
"sales_date" => "2021-02-26"
"subtotal" => 1000000
"items_name" => "Chair"
],
3 => array:3 [
"sales_date" => "2021-02-26"
"subtotal" => 1000000
"items_name" => "Chair"
],
4 => array:3 [
"sales_date" => "2021-02-27"
"subtotal" => 1000000
"items_name" => "Stove"
],
]
I also tried to use ->map() function in server side :
$processed['labels'] = [];
$results->map( function( $val, $key ) use(&$processed) {
$processed['labels'][$key] = $val->sales_date;
if( $processed['labels'][$key] === $val->sales_date) {
$processed['datas'][$key] = ["data" => $val->subtotal, "label" => $val->varieties_name];
}
});
but i confused about the required data structure for Chart.js and show "0" sales like Google Analytics chart if there's no visitor like this image below :
Here's some expected result in Chart.js (the x axis should same from the datasets) :
This is my hardcoded Chart.js
$.ajax({
url : "{{ route('home.selling') }}",
type : "GET",
success : function( res ){
var selling_chart = new Chart(document.getElementById("selling_per_items"), {
type: 'line',
data: {
labels: ['2021-02-24', '2021-02-25', '2021-02-26', '2021-02-27'],
datasets: [{
data : [ '2800000' ],
label : 'Kitchen Set',
lineTension: 0,
fill : false,
borderColor : dynamicColors(),
},{
data : [ '2000000' ],
label : 'Chair',
lineTension: 0,
fill : false,
borderColor : dynamicColors(),
},{
data : [ '100000' ],
label : 'Stove',
lineTension: 0,
fill : false,
borderColor : dynamicColors(),
}]
},
options: {
title: {
display: false
},
responsive: true,
maintainAspectRatio : false,
},
scales: {
xAxes: [{
stacked: true,
}],
yAxes: [{
stacked: true,
ticks: {
beginAtZero: true
}
}]
}
});
}
});
My environment :
jQuery : v3.4.1
Chart.js : v2.8.0
Laravel : 8.x
Thank You
Related
I have an array of data as follows
getDates stores all the dates set by the backend team (01 => 1 April, 02 =>2 April and so on)
getAllApplicantsPerDay stores the number of registrations on each day
Array Name All Data
-------------------------------------------------------------------
getDates '01', '02','03'
getAllApplicantsPerDay 6,4,5,8,7,8
So, basically the data stored are as follows
getDates
Array ( [0] => '01' [1] => '02' [2] => '03')
getAllApplicantsPerDay
Array ( [0] => 6 [1] => 4 [2] => 5 [3] => 8 [4] => 7 [5] => 8 )
Now, as per the requirement of the backend team, they can change the date by adding or removing some dates
So, let's say they add 3 days, the new getDates array would be
getGender
Array ( [0] => '01' [1] => '02' [2] => '03' [3] => '04' [4] => '05' [5] => '06')
In accordance, getAllApplicantsPerDay would also change. I would also want different colours each time (randomly selected color)
However, I cannot show that in a graph. I dont know the syntax to do it.
here is what I tried so far
Script
var config111 = {
type: 'bar',
data: {
labels: [
<?php echo json_encode($getDates); ?>
],
datasets: [{
label: 'DAILY REGISTRATIONS',
backgroundColor:'rgba(178,150,200,0.9)', ------>I want this dynamic too
borderColor: 'rgba(70,158,210,0.9)',
data: [
<?php echo json_encode($getAllApplicantsPerDay ); ?>
],
fill: false,
},
]
},
options: {
responsive: true,
title: {
display: false,
text: 'Daily Registrations'
},
tooltips: {
mode: 'index',
intersect: false,
},
/*hover: {
mode: 'nearest',
intersect: true
},*/
hover: {
mode: 'nearest',
"animationDuration": 0,
intersect: true
},
"animation": {
"duration": 1,
"onComplete": function () {
var chartInstance = this.chart,
ctx = chartInstance.ctx;
ctx.font = Chart.helpers.fontString(Chart.defaults.global.defaultFontSize, Chart.defaults.global.defaultFontStyle, Chart.defaults.global.defaultFontFamily);
ctx.textAlign = 'left';
ctx.textBaseline = 'bottom';
this.data.datasets.forEach(function (dataset, i) {
var meta = chartInstance.controller.getDatasetMeta(i);
meta.data.forEach(function (bar, index) {
var data = dataset.data[index];
ctx.fillText(data, bar._model.x, bar._model.y - 5);
});
});
}
},
scales: {
xAxes: [{
display: true,
scaleLabel: {
display: true,
labelString: ' Monthly Panchayat Samiti'
}
}],
/*yAxes: [{
display: true,
scaleLabel: {
display: true,
labelString: 'Value'
}
}]*/
yAxes: [{
ticks: {
beginAtZero: true
}
}]
}
}
};
$(function () {
var ctx111 = document.getElementById('canvas').getContext('2d');
window.myLine = new Chart(ctx111, config111);
});
Using json_encode would mean that you are encoding the data in JSON format. This format,may not be acceptable by chartjs,as chartjs requires strings for labels, and numbers for data.
Here is what you can do (only the required section of the code)
(Please Note):- Copy and paste this in label tag in chartjs. You can do this exact same thing for data tag as well.
labels: [
<?php
for($i=0;$i<count($getDates);$i++){
echo $getDates[$i];
echo ',';
}
?>
],
Also, make sure to send the data as an array from the backend, if you want to use this method.
As for the random color thing, I suggest you check out this github repository. You can search for other options for random colors as well.
i am using angular and i required to draw a graph/chart i have a data that contains name and time.
in the above situtaion name represents the name of customer and the time represent tha time of call he make(a single customer can make several calls so a customer can have many times). i want to draw a chart in such a way that we can see a customer make a call on this time.
i tried to use chart.js and try line and scatter chart but unable to get desired result.
any suggestion which chart i can use and or how to achieve this
thankyou in advance
Using a scatter chart is a good choice. The solution however depends on the format of your data. Let's presume, it looks like this:
const data = [
{ name: 'Rachel', calls: ['2021-03-01 10:15', '2021-03-01 18:02', '2021-03-02 06:48'] },
{ name: 'William', calls: ['2021-03-01 13:24', '2021-03-02 08:41', '2021-03-02 11:13'] },
{ name: 'Barbara', calls: ['2021-03-01 07:58', '2021-03-01 15:47', '2021-03-02 10:16'] }
];
You need to create a dataset for each user and provide the data in point format where the values of distinct users are different but all values of a same user are identical. This can be done using the Array.map() method as follows:
data.map((user, i) => ({
label: user.name,
data: user.calls.map(call => ({ x: call, y: i + 1 }))
}))
Now you also need to define a ticks.callback function on the y-axis that transforms the numeric tick value back to the user name
yAxes: [{
ticks: {
...
callback: v => v % 1 == 0 ? data[v - 1].name : undefined
}
}],
Please take a look at below runnable code and see how it works.
const data = [
{ name: 'Rachel', calls: ['2021-03-01 10:15', '2021-03-01 18:02', '2021-03-02 06:48'] },
{ name: 'William', calls: ['2021-03-01 13:24', '2021-03-02 08:41', '2021-03-02 11:13'] },
{ name: 'Barbara', calls: ['2021-03-01 07:58', '2021-03-01 15:47', '2021-03-02 10:16'] }
];
const colors = ['red', 'blue', 'green'];
new Chart('myChart', {
type: 'scatter',
data: {
datasets: data.map((user, i) => ({
label: user.name,
data: user.calls.map(call => ({ x: call, y: i + 1 })),
backgroundColor: colors[i],
pointRadius: 4
}))
},
options: {
responsive: true,
tooltips: {
callbacks: {
title: tooltipItem => data[tooltipItem[0].datasetIndex].name,
label: tooltipItem => tooltipItem.xLabel
}
},
scales: {
yAxes: [{
ticks: {
min: 0.5,
max: data.length + 0.5,
stepSize: 0.5,
callback: v => v % 1 == 0 ? data[v - 1].name : undefined
}
}],
xAxes: [{
type: 'time',
time: {
unit: 'hour',
displayFormats: {
hour: 'MMM-DD HH'
},
tooltipFormat: 'MMM-DD HH:mm'
},
gridLines: {
lineWidth: 0
}
}]
}
}
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/Chart.js/2.9.4/Chart.bundle.min.js"></script>
<canvas id="myChart" height="80"></canvas>
Right now the callbacks (on hover) show the data from data set. I want to change each of that point with a different value. For that I have a same size array as the original data array.
I tried this
tooltips: {
callbacks: {
label: function(tooltipItem, data) {
return measures;
}
}
},
but it returned the whole array for every point.
The chart can have more then 1 datasets. They are created dynamically in a for loop. I tried creating the callbacks dynamically as well
call[r] = {
abel: function(tooltipItem, data) {
return measures;
}
};
tooltips: {
callbacks: call
},
But that just threw TypeErrors
TypeError: c.callbacks.labelColor is undefined
TypeError: e.title is undefined
How can i get each array element on a different point? And in case of multiple datasets show the values from the same position array as dataset?
Sorry if im not clear enough. Just cant quite wrap my head around this.
Thanks!
I have implemented graph in one of my project for Power On Time duration. I have refered you with my code. Please see if it can help.
Labels Array:
Array(9)
0
:
"2018-09-17"
1
:
"2018-09-17"
2
:
"2018-09-17"
3
:
"2018-09-17"
4
:
"2018-09-17"
5
:
"2018-09-17"
6
:
"2018-09-17"
7
:
"2018-09-17"
8
:
"2018-09-18"
Data Array:
Array(9)
0
:
"200"
1
:
"211"
2
:
"234"
3
:
"255"
4
:
"300"
5
:
"321"
6
:
"400"
7
:
"421"
8
:
"00421"
<script>
var powerontimedata_chart_labels=[];
var powerontimedata_chart_data=[];
function initiateChart(labels, data){
chart_labels=JSON.parse(labels);
chart_data=JSON.parse(data);
console.log(powerontimedata_chart_labels);
console.log(powerontimedata_chart_data);
plotDataLineChart();
}
function plotDataLineChart(){
var lineChartOptions = {
maintainAspectRatio: false,
steppedLine : 'after',
responsive : true,
showTooltips : false,
showInlineValues : true,
centeredInllineValues : true,
tooltipCaretSize : 0,
tooltipTemplate : "<%= value %>",
scales: {
xAxes: [{
position: "right",
scaleLabel: {
display: true,
stepSize : 1,
autoSkip: false,
labelString: "Date",
fontFamily: "Montserrat",
fontColor: "black",
},
ticks:{
stepSize : 2,
autoSkip: true
}
}],
yAxes: [{
position: "left",
scaleLabel: {
display: true,
stepSize : 1,
autoSkip: false,
labelString: "Time in Hour",
fontFamily: "Montserrat",
fontColor: "black",
},
ticks: {
beginAtZero:true,
autoSkip: true
}
}]
},
"animation": {
"duration": 1,
"onComplete": function() {
var chartInstance = this.chart,
ctx = chartInstance.ctx;
ctx.font = Chart.helpers.fontString(Chart.defaults.global.defaultFontSize, Chart.defaults.global.defaultFontStyle, Chart.defaults.global.defaultFontFamily);
console.log(ctx);
ctx.textAlign = 'center';
ctx.textBaseline = 'bottom';
ctx.fillStyle = '#ff0000';
this.data.datasets.forEach(function(dataset, i) {
var meta = chartInstance.controller.getDatasetMeta(i);
meta.data.forEach(function(bar, index) {
var data = dataset.data[index];
ctx.fillText(data, bar._model.x, bar._model.y - 5);
});
});
}
},
//multiTooltipTemplate: "<%= datasetLabel %> - <%= value %>"
};
var lineChartCanvas = $('#weekbarChart').get(0).getContext('2d')
var ontime = {
labels : chart_labels,
datasets : [
{
label : 'Power Ontime',
fill : true,
borderColor : "#FF0000",
backgroundColor : "#F5B7B1",
data : powerontimedata_chart_data,
steppedLine: false,
pointStyle: 'clearInterval',
pointBorderColor : "#FF0000",
}
]
}
realTimeChart = new Chart(lineChartCanvas, {
type: 'line',
data: ontime,
options: lineChartOptions
});
}
initiateChart('<?= json_encode($chart["labels"])?>','<?= json_encode($chart["data"])?>');
</script>
And my graph comes out to be :
I am using echarts and i am having problems when trying to make echarts display a time period of one day on the x-axis. Here is my code
this.area = {
color: ["#009C95","#21ba45"],
title : {
text: 'Fuel History',
textStyle: {
fontFamily: 'lato'
}
},
tooltip : {
trigger: 'axis'
},
calculable : true,
xAxis : [
{
type: 'time',
boundaryGap:false,
axisLabel: {
formatter: (function(value){
return moment(value).format('HH:mm');
})
},
data : dates
}
],
yAxis : [
{
type : 'value'
}
],
series : [
{
backgroundColor: '#4D86FF',
name:'Refuelling',
type:'line',
smooth:true,
itemStyle: {normal: {areaStyle: {type: 'default'}}},
data: historyRefuelling
},
{
name:'Fuel Theft',
type:'line',
smooth:true,
itemStyle: {normal: {areaStyle: {type: 'default'}}},
data: historyTheft
}
]
}
Here are the sample dates and historical data
`
let dates = [
"2018-08-15T10:04:01.339Z",
"2018-08-15T10:14:13.914Z",
"2018-08-15T10:40:03.147Z",
"2018-08-15T11:50:14.335Z",
"2018-08-15T12:04:05.655Z",
"2018-08-15T15:00:19.441Z"
]
let historyRefuelling = [1,1]
let historyTheft = [
1,1,1,1
]
`
The chart displays correctly but the x-axis spans from 31st December 2017 to 2nd January 2018, so that the results appear as a point instead of an area chart with two series data. Is there a way to tell echarts to begin and end the x-axis at a given time? or rather, How can i handle this?
xAxis.min, xAxis.max these two can be set to achieve that;
check here for more detail
xAxis.minInterval can set the gap between axis labels, like one hour or one day.
And if you use type=time, you don't have to set data of Axis, just set series datas, axis range will auto set by given time, like:
let historyRefuelling = [["2018-08-15T10:04:01.339Z",5],["2018-08-15T10:14:13.914Z",7]]
let historyTheft = [
["2018-08-15T10:04:01.339Z",1],[ "2018-08-15T10:14:13.914Z",2],[ "2018-08-15T10:40:03.147Z",3],[ "2018-08-15T11:50:14.335Z",4]
]
option = {
color: ["#009C95","#21ba45"],
title : {
text: 'Fuel History',
textStyle: {
fontFamily: 'lato'
}
},
tooltip : {
trigger: 'axis'
},
calculable : true,
xAxis : [
{
type: 'time',
boundaryGap:false,
axisLabel: {
formatter: (function(value){
return moment(value).format('HH:mm');
})
}
}
],
yAxis : [
{
type : 'value'
}
],
series : [
{
backgroundColor: '#4D86FF',
name:'Refuelling',
type:'line',
smooth:true,
itemStyle: {normal: {areaStyle: {type: 'default'}}},
data: historyRefuelling
},
{
name:'Fuel Theft',
type:'line',
smooth:true,
itemStyle: {normal: {areaStyle: {type: 'default'}}},
data: historyTheft
}
]
}
check this demo
Referring this example to create scatter graph using echarts library:
Basic Scattergraph
My code for this is as follows:
option ={
xAxis : [
{
type : 'value',
scale:true
}
],
yAxis : [
{
type : 'value',
scale:true
}
],
series : [
{
symbolSize: 40,
itemStyle: {
normal: {
color: 'lightblue',
borderWidth: 4,
label : {
show: true,
position: 'inside',
formatter: function(v)
{
if (v==[161.2, 51.6])
return 'a'
else
return v
}
}
}
},
type:'scatter',
data: [
[161.2, 51.6],[167.5, 59.0],[157.0, 63.0],[155.8, 53.6],
[170.0, 59.0], [166.0, 69.8], [176.2, 66.8]
],
}
]
};
In the formatter function inside series I am trying to match my variable 'v' with a coordinate point from data. But that condition is not satisfied. Where am I going wrong? I only see [object Object] in all the bubbles. Please help.
If you are using the Echarts2.x version, code is as follow:
option ={
xAxis : [
{
type : 'value',
scale:true
}
],
yAxis : [
{
type : 'value',
scale:true
}
],
series : [
{
symbolSize: 40,
itemStyle: {
normal: {
color: 'lightblue',
borderWidth: 4,
label : {
show: true,
position: 'inside',
formatter: function(data){
var v = data.value;
if (v[0]==161.2 && v[1]==51.6)
return 'a'
else
return v
}
}
}
},
type:'scatter',
data: [
[161.2, 51.6],[167.5, 59.0],[157.0, 63.0],[155.8, 53.6],
[170.0, 59.0], [166.0, 69.8], [176.2, 66.8]
],
}
]
};
the parameter of formatter function is an object which is a point object on the scatter, Its structure is as follow:
$vars:Array[3]
color:"lightblue"
componentSubType:"scatter"
componentType:"series"
data:Array[2]
dataIndex:0
dataType:undefined
name:""
seriesIndex:0
seriesName:"-"
seriesType:"scatter"
status:"normal"
value:Array[2]
So the parameter isn't the array you wanted.
The itemStyle attribute is used to set the graphic style, The label attribute is used to set the text label on the graph, which can be used to explain some data information of the graph. Such as value, name, etc. In Echarts3.x in order to make the structure of entire configuration more flat and reasonable, label was taken out with itemStyle at the same level. like itemStyle have two states of normal and emphasis. if you are using Echarts3.x version, code is like as follow:
option ={
xAxis : [
{
type : 'value',
scale:true
}
],
yAxis : [
{
type : 'value',
scale:true
}
],
series : [
{
symbolSize: 40,
itemStyle: {
normal: {
color: 'lightblue',
borderWidth: 4,
}
},
label : {
normal: {
show: true,
position: 'inside',
formatter: function(data){
var v = data.value;
if (v[0]==161.2 && v[1]==51.6)
return 'a'
else
return v
}
}
},
type:'scatter',
data: [
[161.2, 51.6],[167.5, 59.0],[157.0, 63.0],[155.8, 53.6],
[170.0, 59.0], [166.0, 69.8], [176.2, 66.8]
],
}
]
};