1+ function createGraph ( combiData , plainData , singleDayData , canvas ) {
2+ /**
3+ * The DOM has jQuery as $ and the ChartJS library.
4+ * The data can be found in the three first data parameters and canvas is the canvas for the chart.
5+ * The function should return the ChartJS object.
6+ */
7+ function getLabelFromTimestamp ( t ) {
8+ let date = new Date ( t * 1000 ) ;
9+
10+ // month and year
11+ let month = date . getMonth ( ) + 1
12+ let year = date . getFullYear ( )
13+
14+ // monday of week (day - weekday)
15+ var dayMap = {
16+ 0 :6 ,
17+ 1 :0 ,
18+ 2 :1 ,
19+ 3 :2 ,
20+ 4 :3 ,
21+ 5 :4 ,
22+ 6 :5 ,
23+ }
24+ let monday = date . getDate ( ) - dayMap [ date . getDay ( ) ]
25+ if ( monday < 1 ) { // begin of month, monday was last month
26+ month -- ;
27+
28+ let daysPerMonth = [ 31 , 31 , ( ( year % 400 ) == 0 || ( ( year % 4 ) == 0 && ( year % 100 ) != 0 ) ? 29 : 28 ) , 31 , 30 , 31 , 30 , 31 , 31 , 30 , 31 , 30 , 31 ] ;
29+ monday += daysPerMonth [ month ] ;
30+ }
31+ if ( month < 1 ) { // now january and monday in december?
32+ year -- ;
33+ month = 12
34+ }
35+
36+ return `${ monday } .${ month } .${ year } ` ;
37+ }
38+
39+ // get time span and all categories
40+ var minDate = Number . MAX_SAFE_INTEGER ;
41+ var maxDate = Number . MIN_SAFE_INTEGER ;
42+ var allCategories = { }
43+ var allNames = { }
44+ plainData . forEach ( data => {
45+ if ( data . begin < minDate ) {
46+ minDate = data . begin ;
47+ }
48+ if ( data . end > maxDate ) {
49+ maxDate = data . end ;
50+ }
51+ if ( ! allCategories . hasOwnProperty ( data . category ) ) {
52+ allCategories [ data . category ] = 0 ;
53+ }
54+ if ( ! allNames . hasOwnProperty ( data . name ) ) {
55+ allNames [ data . name ] = 0 ;
56+ }
57+ } ) ;
58+ if ( Object . keys ( allCategories ) . length === 1 ) {
59+ var catsColumn = 'name' ;
60+ var allCats = allNames ;
61+ }
62+ else {
63+ var catsColumn = 'category' ;
64+ var allCats = allCategories ;
65+ }
66+
67+ // fill (empty) categories in each day
68+ let plotdata = { } ;
69+ let plotdataLabels = [ ] ;
70+ for ( let timestamp = minDate ; timestamp <= maxDate ; timestamp += 604800 ) {
71+ let label = getLabelFromTimestamp ( timestamp ) ;
72+ plotdata [ label ] = Object . assign ( { } , allCats ) ;
73+ plotdataLabels . push ( label )
74+ }
75+ let lastLabel = getLabelFromTimestamp ( maxDate ) ;
76+ if ( ! plotdata . hasOwnProperty ( lastLabel ) ) {
77+ plotdata [ lastLabel ] = Object . assign ( { } , allCats ) ;
78+ plotdataLabels . push ( lastLabel )
79+ }
80+
81+ // fill with data
82+ plainData . forEach ( data => {
83+ plotdata [ getLabelFromTimestamp ( data . begin ) ] [ data [ catsColumn ] ] += data . duration ;
84+ } ) ;
85+
86+ // convert to hours
87+ Object . keys ( plotdata ) . forEach ( function ( label ) {
88+ Object . keys ( plotdata [ label ] ) . forEach ( function ( category ) {
89+ plotdata [ label ] [ category ] = Math . round ( ( plotdata [ label ] [ category ] / 3600 ) * 100 ) / 100 ;
90+ } ) ;
91+ } ) ;
92+
93+ /**
94+ * Colors from
95+ * chartjs-plugin-colorschemes MIT License
96+ * Copyright (c) 2019 Akihiko Kusanagi
97+ * https://github.com/nagix/chartjs-plugin-colorschemes/blob/master/src/colorschemes/colorschemes.tableau.js
98+ */
99+ const baseColors = [ '#4E79A7' , '#A0CBE8' , '#F28E2B' , '#FFBE7D' , '#59A14F' , '#8CD17D' , '#B6992D' , '#F1CE63' , '#499894' , '#86BCB6' , '#E15759' , '#FF9D9A' , '#79706E' , '#BAB0AC' , '#D37295' , '#FABFD2' , '#B07AA1' , '#D4A6C8' , '#9D7660' , '#D7B5A6' ] ;
100+
101+ var categoryDatasetIdMap = { } ;
102+ var chartData = {
103+ labels : plotdataLabels ,
104+ datasets : [ ]
105+ } ;
106+
107+ var datasetIndex = 0 ;
108+ plotdataLabels . forEach ( function ( label ) {
109+ Object . keys ( plotdata [ label ] ) . forEach ( function ( category ) {
110+ if ( ! categoryDatasetIdMap . hasOwnProperty ( category ) ) {
111+ categoryDatasetIdMap [ category ] = datasetIndex ;
112+ chartData . datasets . push ( {
113+ label : category ,
114+ backgroundColor : baseColors [ datasetIndex % baseColors . length ] ,
115+ data : [ ]
116+ } ) ;
117+ datasetIndex ++ ;
118+ }
119+ chartData . datasets [ categoryDatasetIdMap [ category ] ] . data . push (
120+ plotdata [ label ] [ category ]
121+ ) ;
122+ } ) ;
123+ } ) ;
124+
125+ let config = {
126+ type : 'bar' ,
127+ data : chartData ,
128+ options : {
129+ responsive : true ,
130+ tooltips : {
131+ callbacks : {
132+ label : function ( tooltipItem , chartData ) {
133+ return `${ chartData . datasets [ tooltipItem . datasetIndex ] . label } ${ chartData . datasets [ tooltipItem . datasetIndex ] . data [ tooltipItem . index ] } hours` ;
134+ } ,
135+ title : function ( tooltipItem , chartData ) {
136+ return tooltipItem [ 0 ] . label + ': ' + Math . round ( chartData . datasets . reduce ( ( p , c ) => p + c . data [ tooltipItem [ 0 ] . index ] , 0 ) * 100 ) / 100 + ' hours' ;
137+ }
138+ }
139+ } ,
140+ scales : {
141+ xAxes : [ {
142+ stacked : true ,
143+ beginAtZero : true
144+ } ] ,
145+ yAxes : [ {
146+ stacked : true
147+ } ]
148+ }
149+ }
150+ } ;
151+
152+ return new Chart ( canvas , config ) ;
153+ }
0 commit comments