Reputation: 1
In ChartJs I want to custamize the bar chart.I'm placed the images in empty places if i click on the legend that images cannot be hide. I made a attendance bar chart if person is absent that place will show absent image & alslo if person is working hours place in that place(bar chart in stacked). Finally I want if absent label or Leave label legend click that image will hide.this ref for my bar chart.my issue if i click legend hide`.
if i click on legend remove that image
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Chart Js</title>
<link rel="stylesheet" href="chart.css">
<script src="https://cdn.jsdelivr.net/npm/chart.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/chartjs-plugin-datalabels/2.2.0/chartjs-plugin-datalabels.min.js" integrity="sha512-JPcRR8yFa8mmCsfrw4TNte1ZvF1e3+1SdGMslZvmrzDYxS69J7J49vkFL8u6u8PlPJK+H3voElBtUCzaXj+6ig==" crossorigin="anonymous" referrerpolicy="no-referrer"></script>
<script src="https://unpkg.com/chart.js-plugin-labels-dv/dist/chartjs-plugin-labels.min.js"></script>
</head>
<body>
<section class="container">
<div class="sub_container">
<div className="trans_header">
<div className="payment_onetxt">
<p className="box_txtone">Chart.js — Bar Chart</p>
</div>
<div className="payment_onetxt trans_selectbox">
<select id="selected_box" >
</select>
</div>
</div>
<div>
<canvas id="barChart"></canvas>
</div>
</div>
<div class="sub_container">
<h2>Chart.js — Doughnut Chart</h2>
<div>
<canvas id="donutChart"></canvas>
</div>
</div>
</section>
<script>
//select tag handle & options create
const today = new Date();
const monthNames = Array.from({ length: 12 }).map((_, i) => new Date(today.getFullYear(), i).toLocaleString('default', { month: 'long' }));
const selectElement = document.getElementById('selected_box');
let selectValue=new Date().getMonth();
const options = monthNames.map((month, index) => {
return `<option value="${index}" ${index === selectValue ? 'selected' : ''}>${month}</option>`;
});
let handleMonthChange=(event)=>{
const selectedMonthIndex = event.target.value;
barChart.data.labels=getCurrentMonthDates(Number(selectedMonthIndex));
barChart.update()
}
selectElement.innerHTML = options;
selectElement.addEventListener('change', handleMonthChange);
//get month Data
let getCurrentMonthDates=(currentMonth)=>{
const todays = new Date();
const currentYear = todays.getFullYear();
// const currentMonth = todays.getMonth();
// Get the number of days in the current month
const daysInMonth = new Date(currentYear, currentMonth + 1, 0).getDate();
// Create an acurrentMonthrray to store the dates
const dates = [];
// Loop through each day in the month
for (let day = 1; day <= daysInMonth; day++) {
// Format the date as 'M/D/YYYY'
const formattedDate ="Day"+day
dates.push(formattedDate);
}
return dates;
}
const currentMonth = new Date().getMonth();
let currentMonthDates = getCurrentMonthDates(currentMonth);
let barChartDatas={
Xlabel :currentMonthDates,
Ylabel :["Above 8 Hours","Below 8 Hours","Over Time","Leave","Early Entry","Late","Absent","Early Out"],
bgs :["blue","indianred","#2196f3","pink","purple","yellow","orange",'grey'],
attendanceDatas:{
"Working Hours":[0, 6, 9, 8, 7, 6, 7, 8, 9, 9, 9, 0, 9, 0, 6, 7, 9, 6, 9, 9, 0, 7, 9, 9, 6, 8, 9, 6, 5, 9, 6],
"Over Time":[0, 2, 1, 0, 0, 0, 0, 4, 2, 1, 2, 0, 1, 0, 1, 0, 0, 0, 0, 0, 0, 2, 0, 0, 0, 0, 0, 1, 0, 0,2],
"Leave":[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 'l', 0, 0, 0, 0, 0, 0, 'l', 0, 0, 0, 0, 0, 0, 0, 0, 0],
"Early Entry":[0, 1, 1, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
"Late": [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
"Absent":['a', 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 'a', 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,0],
"Early Out":[0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0,1],
}
}
let initialState={
absent:false,
leave:false,
}
let showImages = () => {
const numDates = barChartDatas?.Xlabel?.length || 0;
const leaveData = barChartDatas?.attendanceDatas?.["Leave"];
const absentData = barChartDatas?.attendanceDatas?.["Absent"];
const imageData = Array.from({ length: numDates }, (_, index) => {
const isAbsent = absentData?.[index] === 'a';
const isLeave = leaveData?.[index] === 'l';
// Check if the respective legend item is visible in legendItems array
return isAbsent
? { src: "ab1.png", width: 30, height: 100 }
: isLeave
? { src: "https://cdn-icons-png.flaticon.com/128/422/422930.png", width: 30, height: 30 }
: null;
});
return imageData;
};
console.log(showImages())
const userImg = new Image();
userImg.src = "user.png";
const barAvatar = {
id: "barAvatar",
afterDraw(chart, args, options) {
const { ctx, chartArea: { top, bottom }, scales: { x, y } } = chart;
ctx.save();
chart.data.datasets.forEach((dataset, datasetIndex) => {
// Check if data is an array
if (Array.isArray(dataset.data)) {
dataset.data.forEach((datapoint, index) => {
// Check if value is above 0, null, or a number
if (typeof datapoint === 'number' && !isNaN(datapoint) && datapoint > 0) {
ctx.drawImage(userImg,
x.getPixelForValue(index) - 10,
chart.getDatasetMeta(7).data[index].y - 20,
18, 18);
}
});
}
});
ctx.restore();
}
};
// Define an empty array to store datasets dynamically
let datasets = [];
// Filter data for "Above 8 Hours" and "Below 8 Hours" based on "Working Hours"
let workingHoursData = barChartDatas?.attendanceDatas["Working Hours"];
let above8HoursData = workingHoursData.map((hours, index) => (hours > 8 ? hours : 0));
let below8HoursData = workingHoursData.map((hours, index) => (hours <= 8 ? hours : 0));
// Create datasets for "Above 8 Hours" and "Below 8 Hours"
datasets.push({
label: "Above 8 Hours",
data: above8HoursData,
backgroundColor:barChartDatas?.bgs[0], // Use the first color for "Above 8 Hours"
});
datasets.push({
label: "Below 8 Hours",
data: below8HoursData,
backgroundColor: barChartDatas?.bgs[1], // Use the second color for "Below 8 Hours"
});
barChartDatas?.Ylabel.slice(2).forEach((label, index) => {
datasets.push({
label: label,
data: barChartDatas?.attendanceDatas[label],
backgroundColor: barChartDatas?.bgs[index + 2]})
})
var ctx = document.getElementById("barChart").getContext('2d');
var barChart = new Chart(ctx, {
type: 'bar',
data: {
labels: barChartDatas?.Xlabel,
datasets:datasets
} ,
options: {
plugins: {
datalabels: {
color: 'black',
rotation:-90,
align: 'end',
anchor: 'end',
display: function(context) {
return context.dataset.data[context.dataIndex] > 0;
},
font: {
weight: 'bold',
},
formatter: function(value, context) {
const datasetLabel = context.dataset?.label.toLowerCase().replace(/\s/g, '')
switch(datasetLabel) {
case 'absent':
return 'Absent';
case 'leave':
return 'Leave';
default:
return '';
}
},
},
legend: {
display: true,
onClick :async(e, legendItem, legend)=>{
const index = legendItem.datasetIndex;
const ci = legend.chart;
// const legendItemCh= legendItem?.text.toLowerCase().replace(/\s/g, '');
// const isVisible=ci.isDatasetVisible(index);
if (ci.isDatasetVisible(index)) {
ci.hide(index);
legendItem.hidden = true;
} else {
ci.show(index);
legendItem.hidden = false;
}
},
labels: {
usePointStyle: true,
pointStyle: 'circle'
}
},
labels: {
render: "image",
textMargin: 0,
images: showImages(),
usePointStyle: true,
useLineStyle: true,
},
},
// Core options
aspectRatio: 5 / 3,
layout: {
padding: {
top: 24,
right: 16,
bottom: 0,
left: 8
}
},
elements: {
line: {
fill: false
},
point: {
hoverRadius: 7,
radius: 5
}
},
scales: {
x: {
stacked: true
},
y: {
stacked: true,
beginAtZero: true,
min: 0,
max: 20,
ticks: {
stepSize: 2,
},
}
}
},
plugins: [ChartDataLabels,barAvatar],
});
</script>
```
Upvotes: 0
Views: 66