|
1 |
| -import React from "react"; |
2 |
| -import ReactECharts from "echarts-for-react"; |
3 |
| -import EmployeeData from "../json/stackedBarChart.json"; |
4 |
| -import { Card } from "react-bootstrap"; |
| 1 | +import React from 'react'; |
| 2 | +import ReactECharts from 'echarts-for-react'; |
| 3 | +import EmployeeData from '../json/stackedBarChart.json'; |
5 | 4 |
|
6 | 5 | // Function to parse the date in dd/mm/yyyy format
|
7 | 6 | const parseDate = (dateStr: string) => {
|
8 |
| - const [day, month, year] = dateStr.split("/").map(Number); |
9 |
| - return new Date(year, month - 1, day); // JavaScript months are 0-indexed |
| 7 | + const [day, month, year] = dateStr.split('/').map(Number); |
| 8 | + return new Date(year, month - 1, day); // JavaScript months are 0-indexed |
10 | 9 | };
|
11 | 10 |
|
12 | 11 | // Function to format the date in dd/mm/yyyy format
|
13 | 12 | const formatDate = (date: Date) => {
|
14 |
| - const day = String(date.getDate()).padStart(2, "0"); |
15 |
| - const month = String(date.getMonth() + 1).padStart(2, "0"); |
16 |
| - const year = date.getFullYear(); |
17 |
| - return `${day}/${month}/${year}`; |
| 13 | + const day = String(date.getDate()).padStart(2, '0'); |
| 14 | + const month = String(date.getMonth() + 1).padStart(2, '0'); |
| 15 | + const year = date.getFullYear(); |
| 16 | + return `${day}/${month}/${year}`; |
18 | 17 | };
|
19 | 18 |
|
20 | 19 | const StackedBarChart = () => {
|
21 |
| - const data = EmployeeData; |
| 20 | + const data = EmployeeData; |
22 | 21 |
|
23 |
| - // Transform the data and sort by date |
24 |
| - const transformData = (data: any) => { |
25 |
| - // Step 1: Extract unique dates and sort them in ascending order |
26 |
| - const dates = data |
27 |
| - .map((item: { date: string }) => item.date) |
28 |
| - .filter( |
29 |
| - (value: string, index: number, self: string[]) => |
30 |
| - self.indexOf(value) === index |
31 |
| - ) // Get unique dates |
32 |
| - .sort( |
33 |
| - (a: any, b: any) => parseDate(a).getTime() - parseDate(b).getTime() |
34 |
| - ); // Sort by date (getTime returns milliseconds) |
| 22 | + // Transform the data and sort by date |
| 23 | + const transformData = (data: any) => { |
| 24 | + // Step 1: Extract unique dates and sort them in ascending order |
| 25 | + const dates = data |
| 26 | + .map((item: { date: string }) => item.date) |
| 27 | + .filter( |
| 28 | + (value: string, index: number, self: string[]) => |
| 29 | + self.indexOf(value) === index |
| 30 | + ) // Get unique dates |
| 31 | + .sort( |
| 32 | + (a: any, b: any) => parseDate(a).getTime() - parseDate(b).getTime() |
| 33 | + ); // Sort by date (getTime returns milliseconds) |
35 | 34 |
|
36 |
| - // Step 2: Prepare the series data for the stacked bar chart |
37 |
| - const series = [ |
38 |
| - { |
39 |
| - name: "Worklog Hours", |
40 |
| - type: "bar", |
41 |
| - stack: "total", |
42 |
| - barWidth: 30, |
43 |
| - data: dates.map((date: string) => { |
44 |
| - const totalWorklog = data |
45 |
| - .filter((d: any) => d.date === date) |
46 |
| - .reduce((sum: any, item: any) => sum + item.worklog_hours, 0); |
47 |
| - return totalWorklog; |
48 |
| - }), |
49 |
| - }, |
50 |
| - { |
51 |
| - name: "Overtime Hours", |
52 |
| - type: "bar", |
53 |
| - stack: "total", |
54 |
| - barWidth: 30, |
55 |
| - data: dates.map((date: string) => { |
56 |
| - const totalOvertime = data |
57 |
| - .filter((d: any) => d.date === date) |
58 |
| - .reduce((sum: any, item: any) => sum + item.overtime_hours, 0); |
59 |
| - return totalOvertime; |
60 |
| - }), |
61 |
| - }, |
62 |
| - { |
63 |
| - name: "Meetings Attended", |
64 |
| - type: "bar", |
65 |
| - stack: "total", |
66 |
| - barWidth: 30, |
67 |
| - data: dates.map((date: string) => { |
68 |
| - const meetings = data.filter( |
69 |
| - (d: any) => d.date === date && d.meeting_attended |
70 |
| - ).length; |
71 |
| - return meetings; |
72 |
| - }), |
73 |
| - }, |
74 |
| - ]; |
| 35 | + // Step 2: Prepare the series data for the stacked bar chart |
| 36 | + const series = [ |
| 37 | + { |
| 38 | + name: 'Worklog Hours', |
| 39 | + type: 'bar', |
| 40 | + stack: 'total', |
| 41 | + barWidth: 30, |
| 42 | + data: dates.map((date: string) => { |
| 43 | + const totalWorklog = data |
| 44 | + .filter((d: any) => d.date === date) |
| 45 | + .reduce((sum: any, item: any) => sum + item.worklog_hours, 0); |
| 46 | + return totalWorklog; |
| 47 | + }), |
| 48 | + }, |
| 49 | + { |
| 50 | + name: 'Overtime Hours', |
| 51 | + type: 'bar', |
| 52 | + stack: 'total', |
| 53 | + barWidth: 30, |
| 54 | + data: dates.map((date: string) => { |
| 55 | + const totalOvertime = data |
| 56 | + .filter((d: any) => d.date === date) |
| 57 | + .reduce((sum: any, item: any) => sum + item.overtime_hours, 0); |
| 58 | + return totalOvertime; |
| 59 | + }), |
| 60 | + }, |
| 61 | + { |
| 62 | + name: 'Meetings Attended', |
| 63 | + type: 'bar', |
| 64 | + stack: 'total', |
| 65 | + barWidth: 30, |
| 66 | + data: dates.map((date: string) => { |
| 67 | + const meetings = data.filter( |
| 68 | + (d: any) => d.date === date && d.meeting_attended |
| 69 | + ).length; |
| 70 | + return meetings; |
| 71 | + }), |
| 72 | + }, |
| 73 | + ]; |
75 | 74 |
|
76 |
| - return { dates, series }; |
77 |
| - }; |
| 75 | + return { dates, series }; |
| 76 | + }; |
78 | 77 |
|
79 |
| - const { dates, series } = transformData(data); |
| 78 | + const { dates, series } = transformData(data); |
80 | 79 |
|
81 |
| - const options = { |
82 |
| - title: { |
83 |
| - text: "Employee Worklog Breakdown", |
84 |
| - left: "center", |
85 |
| - }, |
86 |
| - tooltip: { |
87 |
| - trigger: "axis", |
88 |
| - }, |
89 |
| - legend: { |
90 |
| - data: ["Worklog Hours", "Overtime Hours", "Meetings Attended"], |
91 |
| - top: 35, |
92 |
| - }, |
93 |
| - grid: { |
94 |
| - left: "3%", |
95 |
| - right: "4%", |
96 |
| - bottom: "10%", |
97 |
| - top: "35%", |
98 |
| - containLabel: true, |
99 |
| - }, |
100 |
| - xAxis: { |
101 |
| - type: "category", |
102 |
| - data: dates.map((date: string) => formatDate(parseDate(date))), // Display formatted dates on the x-axis |
103 |
| - name: "Date", // Label for x-axis |
104 |
| - nameLocation: "middle", |
105 |
| - nameGap: 30, |
106 |
| - nameTextStyle: { |
107 |
| - align: "center", // Can be "center", "right", or "left" |
108 |
| - verticalAlign: "top", // Can be "top", "middle", or "bottom" |
109 |
| - fontFamily: "Montserrat, serif", |
110 |
| - fontSize: 14, |
111 |
| - fontWeight: "bold", |
112 |
| - }, |
113 |
| - }, |
114 |
| - yAxis: { |
115 |
| - type: "value", |
116 |
| - name: "Hours", // Label for y-axis |
117 |
| - nameLocation: "middle", // Can also be "middle" or "end" |
118 |
| - nameTextStyle: { |
119 |
| - align: "center", // Can be "center", "right", or "left" |
120 |
| - verticalAlign: "top", // Can be "top", "middle", or "bottom" |
121 |
| - fontFamily: "Montserrat, serif", |
122 |
| - fontSize: 14, |
123 |
| - fontWeight: "bold", |
124 |
| - }, |
125 |
| - // Use padding to shift the title |
126 |
| - nameGap: 50, // You can adjust the gap between the axis and title |
127 |
| - padding: [10, 0, 0, 20], // Example padding |
128 |
| - axisLabel: { |
129 |
| - formatter: (value: number) => { |
130 |
| - if (value >= 1000) { |
131 |
| - return (value / 1000).toFixed(1) + "k"; // Format numbers > 999 as "1k", "2.3k", etc. |
132 |
| - } |
133 |
| - return value; // Return the value as it is if it's less than 1000 |
134 |
| - }, |
135 |
| - }, |
136 |
| - }, |
137 |
| - series: series, |
138 |
| - }; |
| 80 | + const options = { |
| 81 | + title: { |
| 82 | + text: 'Employee Worklog Breakdown', |
| 83 | + left: 'center', |
| 84 | + }, |
| 85 | + tooltip: { |
| 86 | + trigger: 'axis', |
| 87 | + }, |
| 88 | + legend: { |
| 89 | + data: ['Worklog Hours', 'Overtime Hours', 'Meetings Attended'], |
| 90 | + top: 35, |
| 91 | + }, |
| 92 | + grid: { |
| 93 | + left: '3%', |
| 94 | + right: '4%', |
| 95 | + bottom: '10%', |
| 96 | + top: '35%', |
| 97 | + containLabel: true, |
| 98 | + }, |
| 99 | + xAxis: { |
| 100 | + type: 'category', |
| 101 | + data: dates.map((date: string) => formatDate(parseDate(date))), // Display formatted dates on the x-axis |
| 102 | + name: 'Date', // Label for x-axis |
| 103 | + nameLocation: 'middle', |
| 104 | + nameGap: 30, |
| 105 | + nameTextStyle: { |
| 106 | + align: 'center', // Can be "center", "right", or "left" |
| 107 | + verticalAlign: 'top', // Can be "top", "middle", or "bottom" |
| 108 | + fontFamily: 'Montserrat, serif', |
| 109 | + fontSize: 14, |
| 110 | + fontWeight: 'bold', |
| 111 | + }, |
| 112 | + }, |
| 113 | + yAxis: { |
| 114 | + type: 'value', |
| 115 | + name: 'Hours', // Label for y-axis |
| 116 | + nameLocation: 'middle', // Can also be "middle" or "end" |
| 117 | + nameTextStyle: { |
| 118 | + align: 'center', // Can be "center", "right", or "left" |
| 119 | + verticalAlign: 'top', // Can be "top", "middle", or "bottom" |
| 120 | + fontFamily: 'Montserrat, serif', |
| 121 | + fontSize: 14, |
| 122 | + fontWeight: 'bold', |
| 123 | + }, |
| 124 | + // Use padding to shift the title |
| 125 | + nameGap: 50, // You can adjust the gap between the axis and title |
| 126 | + padding: [10, 0, 0, 20], // Example padding |
| 127 | + axisLabel: { |
| 128 | + formatter: (value: number) => { |
| 129 | + if (value >= 1000) { |
| 130 | + return (value / 1000).toFixed(1) + 'k'; // Format numbers > 999 as "1k", "2.3k", etc. |
| 131 | + } |
| 132 | + return value; // Return the value as it is if it's less than 1000 |
| 133 | + }, |
| 134 | + }, |
| 135 | + }, |
| 136 | + series: series, |
| 137 | + }; |
139 | 138 |
|
140 |
| - return ( |
141 |
| - <div style={{ width: "600px" }}> |
142 |
| - <ReactECharts option={options} /> |
143 |
| - </div> |
144 |
| - ); |
| 139 | + return ( |
| 140 | + <div style={{ width: '600px' }}> |
| 141 | + <ReactECharts option={options} /> |
| 142 | + </div> |
| 143 | + ); |
145 | 144 | };
|
146 | 145 |
|
147 | 146 | export default StackedBarChart;
|
0 commit comments