How to hide/show bars differentiate by a colors and by click on labels, using chartjs bar charts? - laravel

I am using chartjs to show one month attendance data, what I want to acheive is to show each day data with different colors like Present, absent and leave. I want labels on top and by click on that label user should be able to hide/show that particular label data, below is my code.
<script src="https://cdnjs.cloudflare.com/ajax/libs/Chart.js/3.7.1/chart.min.js" integrity="sha512-QSkVNOCYLtj73J4hbmVoOV6KVZuMluZlioC+trLpewV8qMjsWqlIQvkn1KGX2StWvPMdWGBqim1xlC8krl1EKQ==" crossorigin="anonymous" referrerpolicy="no-referrer"></script>
<!-- HTML -->
<canvas id="chartJsDiv"></canvas>
<script>
function attendanceSummaryChart3(attendence)
{
var datasets = [];
var labels_data = [];
var num_of_hour = [];
var bar_colours = [];
var border_colr = [];
var real_data_count = attendence.length;
for (var i = 0; i < real_data_count; i++) {
var mydate = new Date(attendence[i].date);
var month = ["Jan", "Feb", "Mar", "Apr", "May", "June", "July", "Aug", "Sep", "Oct", "Nov", "Dec"][mydate.getMonth()];
var str = mydate.getDate() + ' ' +month;
labels_data.push(str);
if(parseFloat(attendence[i].hours.replace(':','.')) < 6.00)
{
if(attendence[i].is_leave != null)
{
var applied_leave_type = attendence[i].is_leave_applied.leave_type.slug;
if(applied_leave_type == "work-from-home")
{
// Full hours in case work from home
num_of_hour.push('9');
bar_colours.push('RGB(25, 135, 84)');
border_colr.push('rgba(3, 126, 25, 0.85)');
// creating datasets
datasets.push({label: 'Work From Home', data: '9', backgroundColor: 'RGB(25, 135, 84)' });
}
else
{
// Leave applied
if(parseFloat(attendence[i].hours.replace(':','.')) == 0)
{
num_of_hour.push('-9');
bar_colours.push('RGB(25, 135, 84)');
border_colr.push('rgba(14, 8, 191, 0.8)');
// creating datasets
datasets.push({label: 'On Leave', data: '-9', backgroundColor: 'RGB(25, 135, 84)'});
}
else
{
num_of_hour.push(parseFloat(attendence[i].hours.replace(':','.')));
bar_colours.push('RGB(25, 135, 84)');
border_colr.push('rgba(14, 8, 191, 0.8)');
// creating datasets
datasets.push({label: 'Half Leave', data: parseFloat(attendence[i].hours.replace(':','.')), backgroundColor: 'RGB(25, 135, 84)'});
}
}
}
else
{
if(parseFloat(attendence[i].hours.replace(':','.')) == 0)
{
// If absent and no leave is applied
num_of_hour.push('-9');
bar_colours.push('RGB(255, 0, 0)');
border_colr.push('rgba(6, 108, 166, 0.8)');
// creating datasets
datasets.push({label: 'Absent (No Leave Applied)', data: '-9', backgroundColor: 'RGB(255, 0, 0)' });
}
else
{
// If present and didn't complete 06 hours in office
num_of_hour.push(parseFloat(attendence[i].hours.replace(':','.')));
bar_colours.push('RGB(255, 0, 0)');
border_colr.push('rgba(255, 99, 132, 1)');
// creating datasets
datasets.push({label: 'Present (Half Time)', data: parseFloat(attendence[i].hours.replace(':','.')), backgroundColor: 'RGB(255, 0, 0)' });
}
}
}
else
{
// Full hours
num_of_hour.push(parseFloat(attendence[i].hours.replace(':','.')));
bar_colours.push('RGB(0, 255, 0)');
border_colr.push('rgba(75, 192, 192, 1)');
// creating datasets
datasets.push({label: 'Present', data: parseFloat(attendence[i].hours.replace(':','.')), backgroundColor: 'RGB(25, 135, 84)' });
}
}
console.log(datasets);
const ctx = document.getElementById('chartJsDiv').getContext('2d');
const myChart = new Chart(ctx, {
type: 'bar',
data: {
labels: labels_data,
datasets: [
{
label: ['Attendence'],
data: num_of_hour,
backgroundColor: bar_colours,
borderColor: border_colr,
}
]
},
options: {
scales: {
y: {
beginAtZero: true
}
}
},
});
}
</script>
I am attaching a screenshot below currently I only have one label but I want multiple labels based on multiple colors bar

You need to use a second dataset to achieve this:
Then you can fill null values in both datasets where you dont use the values of that dataset, so null values on the places where value is negative in positive dataset and vice versa in other one.
Then you can use the property skipNull to make it so the bars dont take up space:
const options = {
type: 'bar',
data: {
labels: ["Red", "Blue", "Yellow", "Green", "Purple", "Orange"],
datasets: [{
label: '# of Votes',
data: [12, null, 3, 5, null, 3],
backgroundColor: 'green'
},
{
label: '# of Points',
data: [null, -11, null, null, -3, null],
backgroundColor: 'red'
}
]
},
options: {
skipNull: true
}
}
const ctx = document.getElementById('chartJSContainer').getContext('2d');
new Chart(ctx, options);
<body>
<canvas id="chartJSContainer" width="600" height="400"></canvas>
<script src="https://cdnjs.cloudflare.com/ajax/libs/Chart.js/3.7.1/chart.js"></script>
</body>

should be this part
label: ['Attendence', 'newLabel', 'xxx'],
under
const ctx = document.getElementById('chartJsDiv').getContext('2d');

Related

cann't make Chart when convertting View MVC to PDF

I am trying to convert the output of MVC view to PDF. I could do that by Rotativa pretty good by using this video
https://www.youtube.com/watch?v=VkHcG24nM8U
but there is still a problem. in the view I am creating a radar chart dynamically. which when the pdf is created it is missing. is it possible to make chart when converting view to PDF file?
This is the code for making Rotativa viewTo PDF
public async Task<IActionResult> PrintPDF(long wId, long cId, long pId, long aId, short no)
{
var result = await _accessmentFacad.GetAssessmentResultForUserByIdService.Execute(wId, cId, pId, aId, no);
return new ViewAsPdf("PrintPDF", result)
{
FileName ="sample.pdf",
PageOrientation = Rotativa.AspNetCore.Options.Orientation.Portrait,
PageSize = Rotativa.AspNetCore.Options.Size.A4,
};
}
and using this jquery radarchart code for creating the chart
<script>
var BeforeWorkshop = []; //these are javascript array variables
var AfterWorkshop = [];
#if(Model.ResultCategoriesDtos.Count>0)
{
foreach(var item in Model.ResultCategoriesDtos)
{
#:BeforeWorkshop.push(#item.Answer3_1);
#:AfterWorkshop.push(#item.Answer3_2);
}
}
var RadarChart = document.getElementById('radarchart').getContext('2d');
var chart = new Chart(RadarChart, {
type: 'radar',
data: {
labels: ["1Lesson", "2Lesson","3Lesson", "4Lesson", "5Lesson"],//x axis labels
datasets: [{
label: "First",
data: BeforeWorkshop,
fill: true,
backgroundColor: 'rgba(255, 99, 132, 0.2)',
borderColor: 'rgb(255, 99, 255)',
pointBackgroundColor: 'rgb(255, 99, 132)',
pointBorderColor: '#fff',
pointHoverBackgroundColor: '#fff',
pointHoverBorderColor: 'rgb(255, 99, 132)',
}
, {
label: "Second",
data: AfterWorkshop,
fill: true,
backgroundColor: 'rgba(54, 162, 235, 0.2)',
borderColor: 'rgb(54, 162, 235)',
pointBackgroundColor: 'rgb(54, 162, 235)',
pointBorderColor: '#fff',
pointHoverBackgroundColor: '#fff',
pointHoverBorderColor: 'rgb(54, 162, 235)'
}
]
},
// Configuration options
options: {
tooltips: {
callbacks: {
label: function (tooltipItem, data) {
return data.datasets[tooltipItem.datasetIndex].label + ": " + tooltipItem.yLabel;
}
}
}
}
});
</script>

how to display multiple sum with chart js and laravel?

I have three table
Table drics
Table country_dric
Table Countries
I just display country name with sum legal from table drics.
I want to display sum column legal, illegal, applicant and mandatory from table drics with country name.
How to display the sum of each column from table drics?
my controller
$drics =DB::table('countries')
->join('country_dric','countries.id','country_dric.country_id')
->join('drics','drics.id','country_dric.dric_id')
->select('name',\DB::raw('sum(legal) as sum'))->groupby('name')
->whereYear('drics.created_at', $year)->get();
$dric_title=[];
$dric=[];
foreach ($drics as $key => $value) {
$dric_title[$key]=$value->name;
$dric[$key]=$value->sum;
}
return view('home.home', compact(' 'dric', 'dric_title'));
js Code
<script>
var ctx = document.getElementById('dric').getContext('2d');
var myChart = new Chart(ctx, {
type: 'bar',
data: {
labels: #json($dric_title),
datasets: [{
label: '# ',
data: #json($dric),
backgroundColor: "rgba(0,31,68,0.8)",
borderColor: "rgb(167, 105, 0)",
borderWidth: 1,
}]
},
options: {
scales: {
yAxes: [{
ticks: {
beginAtZero: true
}
}]
}
}
});
</script>
Try this
Your controller:
$drics =DB::table('countries')
->join('country_dric','countries.id','country_dric.country_id')
->join('drics','drics.id','country_dric.dric_id')
->select('name',\DB::raw('sum(legal) as legal_sum')
,\DB::raw('sum(ilegal) as ilegal_sum')
,\DB::raw('sum(applicant) as applicant_sum')
,\DB::raw('sum(mandatory) as mandatory_sum'))->groupby('name')
->whereYear('drics.created_at', $year)->get();
$dric_title=[];
$dric=[];
foreach ($drics as $key => $value) {
$dric_title[$key]=$value->name;
$dric['legal'][$key]=$value->legal_sum;
$dric['ilegal'][$key]=$value->ilegal_sum;
$dric['applicant'][$key]=$value->applicant_sum;
$dric['mandatory'][$key]=$value->mandatory_sum;
}
return view('home.home', compact(' 'dric', 'dric_title'));
js code:
<script>
var ctx = document.getElementById('dric').getContext('2d');
var myChart = new Chart(ctx, {
type: 'bar',
data: {
labels: #json($dric_title),
datasets: [{
label: 'Legal',
data: #json($dric['legal']),
backgroundColor: "rgba(0,31,68,0.8)",
borderColor: "rgb(167, 105, 0)",
borderWidth: 1,
}, {
label: 'Ilegal',
data: #json($dric['ilegal']),
backgroundColor: "rgba(0,31,68,0.8)", // Change the color to make it different
borderColor: "rgb(167, 105, 0)",
borderWidth: 1,
}, {
label: 'Applicant',
data: #json($dric['applicant']),
backgroundColor: "rgba(0,31,68,0.8)", // Change the color to make it different
borderColor: "rgb(167, 105, 0)",
borderWidth: 1,
}, {
label: 'Mandatory',
data: #json($dric['mandatory']),
backgroundColor: "rgba(0,31,68,0.8)", // Change the color to make it different
borderColor: "rgb(167, 105, 0)",
borderWidth: 1,
}]
},
options: {
scales: {
yAxes: [{
ticks: {
beginAtZero: true
}
}]
}
}
});
</script>
You can use #foreach loop if you want too

Adding icons to bar charts made using c3js

I have made a stacked bar chart using c3 libraries and would like to add icons to each column (using c3 or d3). I went through their documentation but there doesnt seem to be any relevant functionality!
var chart = c3.generate({
data: {
columns: [
['data1', 30, 200, 100],
['data2', 130, 100, 140]
],
type: 'bar',
groups: [['data1', 'data2']]
},
});
You can import font-awesome and then (mis)use c3's label format configuration to set an icon for each series
var chart = c3.generate({
data: {
columns: [
['data1', 30, -200, -100, 400, 150, 250],
['data2', -50, 150, -150, 150, -50, -150],
['data3', -100, 100, -40, 100, -150, -50]
],
groups: [
['data1', 'data2']
],
type: 'bar',
labels: {
// format: function (v, id, i, j) { return "Default Format"; },
format: {
data1: function (v, id, i, j) { return "\uf1ec"; }, // a calculator
data2: function (v, id, i, j) { return "\uf212"; }, // a book
data3: function (v, id, i, j) { return "\uf1ae"; }, // a human
}
}
},
grid: {
y: {
lines: [{value: 0}]
}
}
});
You'll need this css rule -->
.c3-chart-text .c3-text {
font-family: 'FontAwesome';
}
And to import the FontAwesome css to get access to the glyphs (this may be an old version) -->
https://cdnjs.cloudflare.com/ajax/libs/font-awesome/4.7.0/css/font-awesome.min.css
The glyph codes can be found here -->
https://fontawesome.com/cheatsheet
Example:
https://jsfiddle.net/h0g1fwpa/19/

Aligning C3 line shapes with Bar charts

We have the following mixed line chart / bar chart in C3:
a bar chart with two groups (light/dark blue is one group, gray is the
other group)
two other data sets represented as line with stroke-width = 0 that represent the limit for group1 and group2.
How can we place the circle shape for line1 aligned with the bar for group1 and the circle shape for line2 aligned with the two bars of group2?
In the following example, we basically would want one of the two circles to be moved slightly to the right so to align with the center of a group and the other one slightly to the left.
var chartSettings = {
padding: {
left: 120,
right: 120
},
bindto: '#chart',
data: {
x: 'Dates',
type: 'bar',
types: {
line1: 'line',
line2: 'line'
},
groups: [
['data2', 'data3'],
],
colors: {
data1: '#f3e274',
data2: '#85bdde',
data3: '#ccebfb'
},
},
bar: {
width: {
ratio: 0.50
}
},
point: {
r: 8
},
axis: {
x: {
type: 'timeseries',
tick: {
format: '%d-%m-%Y'
}
},
y: {
label: { // ADD
text: '',
position: 'outer-middle'
},
},
}
};
var date1 = new Date(2015, 1, 1, 0,0, 0,0);
var date2 = new Date(2015, 3, 1, 0,0, 0,0);
var date3 = new Date(2015, 6, 1, 0,0, 0,0);
var xAxis = ['Dates', date1, date2,date3];
var line1 = ['line1', 50, 60,55];
var line2 = ['line2', 70, 75,60];
var data1 = ['data1', 40, 35,30];
var data2 = ['data2', 5, 10,10];
var data3 = ['data3', 20, 15,30];
chartSettings.data.columns = [xAxis,
line1,
line2,
data1,
data2,
data3];
c3.generate(chartSettings);
#cr-chart .c3-line-accordatoTotale {
stroke-width: 0px;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/3.4.11/d3.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/c3/0.4.11/c3.min.js"></script>
<div id="chart"/>
var chartSettings = {
bindto: '#chart',
data: {
x: 'Dates',
type: 'bar',
types: {
line1: 'line',
line2: 'line'
},
groups: [
['data2', 'data3'],
],
names: {
line1: 'Limit for data1',
line2: 'Limit for data2 + data3',
data1: 'Data1',
data2: 'Data2',
data3: 'Data3'
},
},
bar: {
width: {
ratio: 0.50 // this makes bar width 50% of length between ticks
}
},
point: {
r: 8
},
axis: {
x: {
type: 'timeseries',
tick: {
format: '%d-%m-%Y'
}
},
y: {
label: { // ADD
text: '',
position: 'outer-middle'
}
},
}
};
var date1 = new Date(2016, 1, 1, 0, 0, 0, 0);
var date2 = new Date(2016, 3, 1, 0, 0, 0, 0);
var date3 = new Date(2016, 6, 1, 0, 0, 0, 0);
var xAxis = ['Dates',date1,date2,date3];
var line1 = ['line1', 50, 70,80];
var data1 = ['data1', 30, 40, 60];
var line2 = ['line2', 70, 60,40];
var data2 = ['data2',10,15,20];
var data3 = ['data3',15,30,5];
chartSettings.data.columns = [xAxis,
line1,
line2,
data1,
data2,
data3];
c3.generate(chartSettings);
#chart .c3-line-line1 {
stroke-width: 0px;
}
#chart .c3-line-line2 {
stroke-width: 0px;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/3.4.11/d3.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/c3/0.4.11/c3.min.js"></script>
<div id="chart"/>
It would be nice if you attached some jsfiddle.
But at this point I can say that you probably need to look inside .c3-chart-lines container and find desired line eighter by order:
.c3-chart-line:first-child // or last-child?
or by data name:
.c3-chart-line.c3-target-YOUR-ORANGE-DATA-NAME
Hope this helps.

How to make a multiple table header

I am trying to make a table with 2 headers merged. At the moment i made 2 seperate tables with 2 seperate headers and it looks okay, but when the table width expands the first table header does not expand. How can i merge the 2 headers or can i make 1 table with 2 tableheaders. Please see picture (how the table is at the moment with 2 tableheaders)
Here is my code :
function createPDF(){
/** START PDF INSTANCE */
//var doc = new jsPDF('p', 'pt');
var doc = new jsPDF('l', 'pt');
var row = 80;
addPdfHeader(doc, row, vm.translate("REPORT.LEGALFORMS ")+" "+vm.activeCompanyYear);
doc.setFillColor(33, 150, 243);
var columns = [ " ",vm.activeCompanyYear,vm.activeCompanyYear-1,vm.activeCompanyYear-2];
var rows = [];
var description = "";
for(var j=0; j<vm.reportData.length; j++){
var obj = vm.reportData[j];
description = obj.descriptionEng;
if(description == "total"){
description = vm.translate("REPORT.REGISTRY.TOTAL");
}
var singleRow = [description,
obj.year3Total,
obj.year3Local,
obj.year3International,
obj.year2Total,
obj.year2Local,
obj.year2International,
obj.year1Total,
obj.year1Local,
obj.year1International
]
rows.push(singleRow);
}
doc.autoTable(columns, [], {
theme : 'grid',
styles: {
halign: 'right'
},
headerStyles: {
fillColor: [33, 150, 243],
halign:'center',
lineWidth: 1,
lineColor: [221, 221, 221]
},
columnStyles:{
0: {columnWidth: 266}
},
margin : {
top : 100
}
});
var columns2 = [ vm.translate("MENU.SETTINGS.LEGALFORM"),
vm.translate("REPORT.REGISTRY.TOTAL"),
vm.translate("REPORT.REGISTRY.LOCAL"),
vm.translate("REPORT.REGISTRY.INTERNATIONAL"),
vm.translate("REPORT.REGISTRY.TOTAL"),
vm.translate("REPORT.REGISTRY.LOCAL"),
vm.translate("REPORT.REGISTRY.INTERNATIONAL"),
vm.translate("REPORT.REGISTRY.TOTAL"),
vm.translate("REPORT.REGISTRY.LOCAL"),
vm.translate("REPORT.REGISTRY.INTERNATIONAL")
];
doc.autoTable(columns2, rows, {
theme : 'grid',
styles: {
halign: 'right'
},
headerStyles: {
halign:'center',
lineWidth: 1,
lineColor: [221, 221, 221]
},
margin : {
top : 120
},
columnStyles:{
0: {halign:'left'}
},
createdCell: function(cell, data) {
if(data.row.raw[0] === vm.translate("REPORT.REGISTRY.TOTAL")) {
cell.styles.fontStyle = 'bold';
cell.styles.fillColor = [255,251,204];
}
}
});
doc.save();
};
Something like this (v3 and up):
let head = [
[
{content: 'People', colSpan: 3, styles: {halign: 'center', fillColor: [22, 160, 133]}},
{content: 'Data', colSpan: 2, styles: {halign: 'center', fillColor: [22, 160, 133]}}
],
['ID', 'Name', 'Email', 'City', 'Sum'],
];
doc.autoTable({
startY: 60,
head: head,
body: body,
theme: 'grid'
});

Resources