Chartjs-Chartjs Stacked bar graph with forEach for labels

0๐Ÿ‘

โœ…

If I understood well, I think you could create the labels for the chart getting all employees name.
Then you can extract all datasets getting all projects for employee, setting the label as project name, the data as an array with all person months of employee (in my example I have got only 4 employees therefore data.length = 4).

See snippet or codepen: https://codepen.io/stockinail/pen/BaxjwWM

// ------------------
// data to show on te chart
// ------------------
const employees = [
{
  name: 'John Smith', 
  contractFrom: '01.3.2021',
  contractTo: '01.3.2023',
  projects: [{
    projectId: '0001', 
    projectName: 'project1', 
    startDate: '9/22', 
    endDate: '8/24', 
    monthFrom: '9', 
    monthTo: '12', 
    personMonths: 1.0
  }]
}, {
  name: 'Bob Kennedy', 
  contractFrom: '01.3.2021',
  contractTo: '01.3.2023',
  projects: [{
    projectId: '0001', 
    projectName: 'project1', 
    startDate: '9/22', 
    endDate: '8/24', 
    monthFrom: '9', 
    monthTo: '12', 
    personMonths: 2.0
  }, {
    projectId: '0002', 
    projectName: 'Project 2', 
    startDate: '10/22', 
    endDate: '10/22', 
    monthFrom: '3', 
    monthTo: '8', 
    personMonths: 3.0
  }]
}, {
  name: 'Kevin Red', 
  contractFrom: '01.3.2021',
  contractTo: '01.3.2023',
  projects: [{
    projectId: '0001', 
    projectName: 'project1', 
    startDate: '9/22', 
    endDate: '8/24', 
    monthFrom: '9', 
    monthTo: '12', 
    personMonths: 4.0
  }, {
    projectId: '0002', 
    projectName: 'Project 2', 
    startDate: '10/22', 
    endDate: '10/22', 
    monthFrom: '3', 
    monthTo: '8', 
    personMonths: 5.0
  }, {
    projectId: '0003', 
    projectName: 'Project 3', 
    startDate: '12/22', 
    endDate: '12/22', 
    monthFrom: '10', 
    monthTo: '12', 
    personMonths: 6.0
  }, {
    projectId: '0004', 
    projectName: 'Project 4', 
    startDate: '12/22', 
    endDate: '12/22', 
    monthFrom: '10', 
    monthTo: '12', 
    personMonths: 7.0
  }]
},
  {
  name: 'James Brown', 
  contractFrom: '01.3.2021',
  contractTo: '01.3.2023',
  projects: [{
    projectId: '0001', 
    projectName: 'project1', 
    startDate: '9/22', 
    endDate: '8/24', 
    monthFrom: '9', 
    monthTo: '12', 
    personMonths: 8.0
  }, {
    projectId: '0002', 
    projectName: 'Project 2', 
    startDate: '10/22', 
    endDate: '10/22', 
    monthFrom: '3', 
    monthTo: '8', 
    personMonths: 9.0
  }, {
    projectId: '0003', 
    projectName: 'Project 3', 
    startDate: '12/22', 
    endDate: '12/22', 
    monthFrom: '10', 
    monthTo: '12', 
    personMonths: 10.0
  }, {
    projectId: '0004', 
    projectName: 'Project 4', 
    startDate: '12/22', 
    endDate: '12/22', 
    monthFrom: '10', 
    monthTo: '12', 
    personMonths: 11.0
  }]
}];
// ---------------------
// scans all data, creating an array as result with all employees names
// this array represents the "labels" of the scale X
// ---------------------
const labels = employees.reduce(function(result, item) {
  // adds the employee name to the array to return
  result.push(item.name);
  return result;
}, []); // <-- in the reduce, the [] is the initial value of variable "result"
// ---------------------
// random colors generator
// this can be removed and use specific color 
// or other plugins to use series of color
// ---------------------
const randomColorGenerator = function () { 
  return '#' + (Math.random().toString(16) + '0000000').slice(2, 8); 
};
// ---------------------
// scans all data, creating an object as result with all prjects
// the object has got as property name the ID of the project and as value the dataset object.
// in the chart, 1 dataset is equals to 1 project
// the scan is done for each employee and then for each project of each employee
// the cycle checks if the project is already created for another employee
// ---------------------
const projects = employees.reduce(function(result, item) {
  // scans project
  item.projects.forEach(function(prj){
    // gets project ID 
    const prjId = prj.projectId;
    // checks if already the related dataset is already created
    if (!result[prjId]) {
      // if not, adds to the object the dataset with project ID as property of the object
      result[prjId] = {
        label: prj.projectName, // name of dataset is project name
        data: [], // the data, in this phase, is empty, it will fill afterwards
        backgroundColor: randomColorGenerator()
      };
    }
  });
  return result;
}, {}); // <-- in the reduce, the {} is the initial value of variable "result"
// ---------------------
// scans all data, to fill the datasets (related to the projects) withe data, taken from the data.
// Some employees couldn't have any engagement on some projects therefore 0 is added to the data
// the chart will have the folloing matrix:
// 
// employee | prj1              | prj2              | ... | prjn             |
// emp1     | personMonths or 0 | personMonths or 0 | ... |personMonths or 0 |
// ---------------------
employees.forEach(function(item) {
  // scans all projects previously extracted, againts the employee projects
  for (const prjId of Object.keys(projects)) {
    const prj = projects[prjId];
    // checks if the employee was engaged for this project
    const empPrj = item.projects.filter(el => el.projectId === prjId);
    // if the array is not empty, the the employee was engaged in teh project
    // then adds personMonths the teh data array.
    if (empPrj.length) {
      prj.data.push(empPrj[0].personMonths); 
    } else {
    // if here, the employee wasn't engaged in teh project then add 0.
      prj.data.push(0); 
    }
  }
});

const ctx = document.getElementById("myChart");
const myChart = new Chart(ctx, {
  type: 'bar',
  data: {
    labels: labels, // employees names
    datasets: Object.values(projects)  // projects 
  },
  options: {
    scales: {
      x: {
        stacked: true
      },
      y: {
        stacked: true
      }
    }
  }
});
.myChartDiv {
  max-width: 600px;
  max-height: 400px;
}
<script src="https://cdn.jsdelivr.net/npm/chart.js@3.9.1/dist/chart.min.js"></script>
<html>
  <body>
    <div class="myChartDiv">
      <canvas id="myChart" width="600" height="400"/>
    </div>
  </body>
</html>

Leave a comment