Loop through a list of employees and their projects and display their months spent in a bar chart
This is a continuation from this and user2057925 was super awesome helping me out and also gives a good explanation. However, since my javascript is still very basic compared to what user2057925 had done before I've found an issue and have no idea how to fix.
So the bar chart works great but if an employee has 2 different chunks of time for a project in a given year, only the first (i'm assuming) gets rendered in the stacked bar, but not the second. I've got screen shots showing the issue.
Controller
@GetMapping("/chart")
public String viewChartPage(Model model) {
// List<Employee> employees = employeeService.getAllEmployees();
ChartYear year = new ChartYear("2023");
List<Employee> employees = employeeService.getAllEmployeesByEmployeeProjectStartDate(year);
List<String> yearList = employeeProjectService.findAllStartAndEndDatesByYear();
List<Project> projects = projectService.getAListOfProjectsAndTheirPersonMonthsByYear(year);
model.addAttribute("employees", employees);
model.addAttribute("projects", projects);
model.addAttribute("yearList", yearList);
model.addAttribute("currentYear", Year.now());
return "chart.html";
}
The chart
const labels = listEmployees.reduce(function(result, item) {
result.push(item.name);
return result;
}, []);
const randomColorGenerator = function () {
return '#' + (Math.random().toString(16) + '0000000').slice(2, 8);
};
const projects = listEmployees.reduce(function(result, item) {
item.employeeProjects.forEach(function(prj){
const prjId = prj.project.id;
if (!result[prjId]) {
result[prjId] = {
label: prj.project.name,
data: [],
backgroundColor: randomColorGenerator()
};
}
});
return result;
}, {});
listEmployees.forEach(function(item) {
for (const prjId of Object.keys(projects)) {
const prj = projects[prjId];
const empPrj = item.employeeProjects.filter(el => el.project.id === parseFloat(prjId));
if (empPrj.length) {
prj.data.push(empPrj[0].employeeBookedMonths);
} else {
prj.data.push(0);
}
}
});
const horizontalArbitraryLine = {
id: 'horizontalArbitraryLine',
beforeDraw(chart, args, options) {
const {ctx, chartArea: {top, right, bottom, left, width, height}, scales:
{x, y} } = chart;
ctx.save();
ctx.strokeStyle = 'red';
ctx.strokeRect(left, y.getPixelForValue(12), width, 1);
console.log(y.getPixelForValue(3))
}
};
const ctx = document.getElementById("myChart");
const myChart = new Chart(ctx, {
type: 'bar',
data: {
labels: labels,
datasets: Object.values(projects)
},
options: {
scales: {
x: {
stacked: true
},
y: {
stacked: true
}
}
},
plugins: [horizontalArbitraryLine]
});
HTML
<div class="container">
<div class="d-flex">
<h2>Chart for [[${currentYear}]]</h2>
</div>
<div class="d-flex">
<div id="selectYear" class="p-2">
<p>Select Sheet Year:</p>
</div>
<div class="p-2">
<form th:action="@{/ines/chart}" th:object="${chartYear}" method="post">
<select class="form-control" id="year" name="year" onchange="this.form.submit()">
<option></option>
<option th:each="year : ${yearList}" th:value="${year}"
th:text="${year}" th:selected="${year == currentYear}">
</option>
</select>
</form>
</div>
</div>
<div class="myChartDiv">
<canvas id="myChart" width="900" height="600"></canvas>
</div>
<div>
<canvas id="myBarChart"></canvas>
</div>
</div>
CSS
.myChartDiv {
max-width: 800px;
max-height: 600px;
}
#year {
width: 85px;
height: 35px;
}
So you can see Luke Sky has only 3 staked bars on the far right, but there is 4 in the console. The 6.5 is missing. The light pink is 0.5, dark pink is 1.5 and green is 1. All 4 are for "Test Project".
Am I right in assuming it has something to do with the prj.data.push(empPrj[0].employeeBookedMonths); part, as it only gets the first employeeProjectBookedMonths for that project? So how do we include both parts? Thanks in advance.


Comments
Post a Comment