Chart.js堆叠柱状图:员工同一项目多段工时仅显示第一段的修复问询
问题描述
这是之前Stack Overflow问题的延续,感谢user2057925的帮助。目前实现的堆叠柱状图可正常展示员工项目工时,但当员工在某一年同一项目存在两段不同工时记录时,仅渲染第一段,第二段未显示。
比如数据示例里的Luke Sky,实际有4段工时数据,但柱状图只显示3段堆叠,其中6.5的工时未被统计。推测问题出在prj.data.push(empPrj[0].employeeBookedMonths)仅获取同一项目的第一段工时,需要修改代码以累加同一项目的所有工时数据。
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"; }
图表JavaScript代码
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) { // 原代码只取第一个记录,现在改为累加所有匹配项目的工时 const totalMonths = empPrj.reduce((sum, record) => sum + record.employeeBookedMonths, 0); prj.data.push(totalMonths); } 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; }
数据示例
[Employee{id=7, name='Luke Sky', contractedFrom='2022-01-15', contractedTo='2025-04-30', employeeProjects=[EmployeeProject{id=24, project=Project{id=1, projectNumber=12345, name='Test Project', startDate='2022-02-01', endDate='2024-08-28', projectLengthInMonths=31.0, currentBookedMonths=32.5, remainingBookedMonths=-30.5, numberOfEmployees=0, comment='31 months'}, employeeBookedMonths=1.0, employeeProjectStartDate=2023-01-01, employeeProjectEndDate=2023-01-31, projectName='Test Project'}, EmployeeProject{id=25, project=Project{id=2, projectNumber=54321, name='Test Project 2', startDate='2021-12-01', endDate='2023-02-28', projectLengthInMonths=15.0, currentBookedMonths=19.5, remainingBookedMonths=-16.5, numberOfEmployees=0, comment='Comment 15 months'}, employeeBookedMonths=0.5, employeeProjectStartDate=2023-04-01, employeeProjectEndDate=2023-04-14, projectName='Test Project 2'}, EmployeeProject{id=27, project=Project{id=1, projectNumber=12345, name='Test Project', startDate='2022-02-01', endDate='2024-08-28', projectLengthInMonths=31.0, currentBookedMonths=32.5, remainingBookedMonths=-30.5, numberOfEmployees=0, comment='31 months'}, employeeBookedMonths=6.5, employeeProjectStartDate=2023-04-15, employeeProjectEndDate=2023-10-31, projectName='Test Project'}, EmployeeProject{id=26, project=Project{id=3, projectNumber=2468, name='Test Project 3', startDate='2022-02-01', endDate='2025-04-30', projectLengthInMonths=39.0, currentBookedMonths=45.0, remainingBookedMonths=-42.0, numberOfEmployees=0, comment='Comment 39 months'}, employeeBookedMonths=1.5, employeeProjectStartDate=2023-11-15, employeeProjectEndDate=2023-12-31, projectName='Test Project 3'}], projectIds=null, startDates=null, endDates=null}]
修改说明
原代码中prj.data.push(empPrj[0].employeeBookedMonths)仅提取了该员工当前项目的第一条工时记录,现在改用reduce方法累加所有匹配项目的employeeBookedMonths值,得到该员工在该项目下的总工时,再推入数据数组中。这样同一项目的多段工时就会被合并统计,堆叠柱状图就能正确显示总工时了。
内容的提问来源于stack exchange,提问作者Kayd Anderson
相关产品推荐
相关产品推荐

