@syncfusion/ej2-gantt 19.4.56 → 20.1.47-1460716

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (211) hide show
  1. package/CHANGELOG.md +1072 -1060
  2. package/README.md +75 -75
  3. package/dist/ej2-gantt.umd.min.js +1 -10
  4. package/dist/ej2-gantt.umd.min.js.map +1 -1
  5. package/dist/es6/ej2-gantt.es2015.js +274 -176
  6. package/dist/es6/ej2-gantt.es2015.js.map +1 -1
  7. package/dist/es6/ej2-gantt.es5.js +642 -534
  8. package/dist/es6/ej2-gantt.es5.js.map +1 -1
  9. package/dist/global/ej2-gantt.min.js +1 -10
  10. package/dist/global/ej2-gantt.min.js.map +1 -1
  11. package/dist/global/index.d.ts +0 -9
  12. package/dist/ts/components.ts +4 -0
  13. package/dist/ts/gantt/actions/actions.ts +18 -0
  14. package/dist/ts/gantt/actions/cell-edit.ts +606 -0
  15. package/dist/ts/gantt/actions/chart-scroll.ts +167 -0
  16. package/dist/ts/gantt/actions/column-menu.ts +35 -0
  17. package/dist/ts/gantt/actions/column-reorder.ts +52 -0
  18. package/dist/ts/gantt/actions/column-resize.ts +52 -0
  19. package/dist/ts/gantt/actions/connector-line-edit.ts +829 -0
  20. package/dist/ts/gantt/actions/context-menu.ts +754 -0
  21. package/dist/ts/gantt/actions/day-markers.ts +80 -0
  22. package/dist/ts/gantt/actions/dependency.ts +692 -0
  23. package/dist/ts/gantt/actions/dialog-edit.ts +2208 -0
  24. package/dist/ts/gantt/actions/edit.ts +3499 -0
  25. package/dist/ts/gantt/actions/excel-export.ts +61 -0
  26. package/dist/ts/gantt/actions/filter.ts +302 -0
  27. package/dist/ts/gantt/actions/keyboard.ts +306 -0
  28. package/dist/ts/gantt/actions/pdf-export.ts +214 -0
  29. package/dist/ts/gantt/actions/rowdragdrop.ts +839 -0
  30. package/dist/ts/gantt/actions/selection.ts +536 -0
  31. package/dist/ts/gantt/actions/sort.ts +98 -0
  32. package/dist/ts/gantt/actions/taskbar-edit.ts +1940 -0
  33. package/dist/ts/gantt/actions/toolbar.ts +489 -0
  34. package/dist/ts/gantt/actions/virtual-scroll.ts +60 -0
  35. package/dist/ts/gantt/base/common.ts +9 -0
  36. package/dist/ts/gantt/base/constant.ts +13 -0
  37. package/dist/ts/gantt/base/css-constants.ts +148 -0
  38. package/dist/ts/gantt/base/date-processor.ts +1257 -0
  39. package/dist/ts/gantt/base/enum.ts +372 -0
  40. package/dist/ts/gantt/base/gantt-chart.ts +1248 -0
  41. package/dist/ts/gantt/base/gantt.ts +4069 -0
  42. package/dist/ts/gantt/base/interface.ts +955 -0
  43. package/dist/ts/gantt/base/splitter.ts +174 -0
  44. package/dist/ts/gantt/base/task-processor.ts +2217 -0
  45. package/dist/ts/gantt/base/tree-grid.ts +694 -0
  46. package/dist/ts/gantt/base/utils.ts +208 -0
  47. package/dist/ts/gantt/export/export-helper.ts +552 -0
  48. package/dist/ts/gantt/export/pdf-base/dictionary.ts +152 -0
  49. package/dist/ts/gantt/export/pdf-base/pdf-borders.ts +277 -0
  50. package/dist/ts/gantt/export/pdf-base/pdf-grid-table.ts +901 -0
  51. package/dist/ts/gantt/export/pdf-base/pdf-style/gantt-theme.ts +131 -0
  52. package/dist/ts/gantt/export/pdf-base/pdf-style/style.ts +91 -0
  53. package/dist/ts/gantt/export/pdf-base/treegrid-layouter.ts +414 -0
  54. package/dist/ts/gantt/export/pdf-connector-line.ts +422 -0
  55. package/dist/ts/gantt/export/pdf-gantt.ts +282 -0
  56. package/dist/ts/gantt/export/pdf-taskbar.ts +395 -0
  57. package/dist/ts/gantt/export/pdf-timeline.ts +202 -0
  58. package/dist/ts/gantt/export/pdf-treegrid.ts +406 -0
  59. package/dist/ts/gantt/models/add-dialog-field-settings.ts +33 -0
  60. package/dist/ts/gantt/models/column.ts +464 -0
  61. package/dist/ts/gantt/models/day-working-time.ts +22 -0
  62. package/dist/ts/gantt/models/edit-dialog-field-settings.ts +33 -0
  63. package/dist/ts/gantt/models/edit-settings.ts +79 -0
  64. package/dist/ts/gantt/models/event-marker.ts +27 -0
  65. package/dist/ts/gantt/models/filter-settings.ts +53 -0
  66. package/dist/ts/gantt/models/holiday.ts +34 -0
  67. package/dist/ts/gantt/models/label-settings.ts +30 -0
  68. package/dist/ts/gantt/models/models.ts +36 -0
  69. package/dist/ts/gantt/models/resource-fields.ts +38 -0
  70. package/dist/ts/gantt/models/search-settings.ts +77 -0
  71. package/dist/ts/gantt/models/selection-settings.ts +56 -0
  72. package/dist/ts/gantt/models/sort-settings.ts +50 -0
  73. package/dist/ts/gantt/models/splitter-settings.ts +47 -0
  74. package/dist/ts/gantt/models/task-fields.ts +171 -0
  75. package/dist/ts/gantt/models/timeline-settings.ts +112 -0
  76. package/dist/ts/gantt/models/tooltip-settings.ts +46 -0
  77. package/dist/ts/gantt/renderer/chart-rows.ts +1838 -0
  78. package/dist/ts/gantt/renderer/connector-line.ts +1025 -0
  79. package/dist/ts/gantt/renderer/edit-tooltip.ts +228 -0
  80. package/dist/ts/gantt/renderer/event-marker.ts +96 -0
  81. package/dist/ts/gantt/renderer/nonworking-day.ts +205 -0
  82. package/dist/ts/gantt/renderer/render.ts +5 -0
  83. package/dist/ts/gantt/renderer/timeline.ts +1397 -0
  84. package/dist/ts/gantt/renderer/tooltip.ts +450 -0
  85. package/dist/ts/gantt/renderer/virtual-content-render.ts +50 -0
  86. package/license +9 -9
  87. package/package.json +80 -80
  88. package/src/gantt/actions/cell-edit.js +2 -1
  89. package/src/gantt/actions/dialog-edit.js +2 -1
  90. package/src/gantt/actions/edit.js +11 -2
  91. package/src/gantt/actions/rowdragdrop.js +37 -15
  92. package/src/gantt/actions/taskbar-edit.js +24 -24
  93. package/src/gantt/base/date-processor.js +0 -1
  94. package/src/gantt/base/gantt-chart.js +9 -4
  95. package/src/gantt/base/gantt-model.d.ts +779 -779
  96. package/src/gantt/base/gantt.d.ts +27 -27
  97. package/src/gantt/base/gantt.js +22 -22
  98. package/src/gantt/base/splitter.js +1 -0
  99. package/src/gantt/base/task-processor.js +13 -13
  100. package/src/gantt/base/tree-grid.js +3 -1
  101. package/src/gantt/export/pdf-base/treegrid-layouter.js +13 -13
  102. package/src/gantt/export/pdf-connector-line.js +11 -11
  103. package/src/gantt/export/pdf-gantt.js +24 -24
  104. package/src/gantt/export/pdf-taskbar.js +11 -11
  105. package/src/gantt/export/pdf-treegrid.js +13 -13
  106. package/src/gantt/models/add-dialog-field-settings-model.d.ts +21 -21
  107. package/src/gantt/models/add-dialog-field-settings.js +19 -19
  108. package/src/gantt/models/day-working-time-model.d.ts +11 -11
  109. package/src/gantt/models/day-working-time.js +19 -19
  110. package/src/gantt/models/edit-dialog-field-settings-model.d.ts +21 -21
  111. package/src/gantt/models/edit-dialog-field-settings.js +19 -19
  112. package/src/gantt/models/edit-settings-model.d.ts +50 -50
  113. package/src/gantt/models/edit-settings.js +19 -19
  114. package/src/gantt/models/event-marker-model.d.ts +16 -16
  115. package/src/gantt/models/event-marker.js +19 -19
  116. package/src/gantt/models/filter-settings-model.d.ts +34 -34
  117. package/src/gantt/models/filter-settings.js +19 -19
  118. package/src/gantt/models/holiday-model.d.ts +21 -21
  119. package/src/gantt/models/holiday.js +19 -19
  120. package/src/gantt/models/label-settings-model.d.ts +16 -16
  121. package/src/gantt/models/label-settings.js +19 -19
  122. package/src/gantt/models/resource-fields-model.d.ts +21 -21
  123. package/src/gantt/models/resource-fields.js +19 -19
  124. package/src/gantt/models/search-settings-model.d.ts +56 -56
  125. package/src/gantt/models/search-settings.js +19 -19
  126. package/src/gantt/models/selection-settings-model.d.ts +35 -35
  127. package/src/gantt/models/selection-settings.js +19 -19
  128. package/src/gantt/models/sort-settings-model.d.ts +24 -24
  129. package/src/gantt/models/sort-settings.js +19 -19
  130. package/src/gantt/models/splitter-settings-model.d.ts +30 -30
  131. package/src/gantt/models/splitter-settings.js +19 -19
  132. package/src/gantt/models/task-fields-model.d.ts +110 -110
  133. package/src/gantt/models/task-fields.js +19 -19
  134. package/src/gantt/models/timeline-settings-model.d.ts +71 -71
  135. package/src/gantt/models/timeline-settings.js +19 -19
  136. package/src/gantt/models/tooltip-settings-model.d.ts +26 -26
  137. package/src/gantt/models/tooltip-settings.js +19 -19
  138. package/src/gantt/renderer/chart-rows.js +49 -37
  139. package/src/gantt/renderer/connector-line.js +22 -18
  140. package/src/gantt/renderer/event-marker.js +1 -0
  141. package/src/gantt/renderer/nonworking-day.js +13 -6
  142. package/src/gantt/renderer/timeline.d.ts +1 -0
  143. package/src/gantt/renderer/timeline.js +48 -12
  144. package/src/gantt/renderer/tooltip.js +11 -3
  145. package/styles/bootstrap-dark.css +442 -427
  146. package/styles/bootstrap.css +442 -433
  147. package/styles/bootstrap4.css +454 -479
  148. package/styles/bootstrap5-dark.css +457 -433
  149. package/styles/bootstrap5.css +457 -433
  150. package/styles/fabric-dark.css +438 -421
  151. package/styles/fabric.css +445 -428
  152. package/styles/fluent-dark.css +1938 -0
  153. package/styles/fluent-dark.scss +1 -0
  154. package/styles/fluent.css +1938 -0
  155. package/styles/fluent.scss +1 -0
  156. package/styles/gantt/_all.scss +2 -2
  157. package/styles/gantt/_bootstrap-dark-definition.scss +210 -156
  158. package/styles/gantt/_bootstrap-definition.scss +211 -157
  159. package/styles/gantt/_bootstrap4-definition.scss +213 -158
  160. package/styles/gantt/_bootstrap5-definition.scss +215 -162
  161. package/styles/gantt/_fabric-dark-definition.scss +211 -157
  162. package/styles/gantt/_fabric-definition.scss +211 -157
  163. package/styles/gantt/_fluent-dark-definition.scss +1 -0
  164. package/styles/gantt/_fluent-definition.scss +215 -162
  165. package/styles/gantt/_fusionnew-definition.scss +214 -0
  166. package/styles/gantt/_highcontrast-definition.scss +211 -157
  167. package/styles/gantt/_highcontrast-light-definition.scss +211 -157
  168. package/styles/gantt/_layout.scss +1446 -1027
  169. package/styles/gantt/_material-dark-definition.scss +212 -157
  170. package/styles/gantt/_material-definition.scss +212 -157
  171. package/styles/gantt/_material3-definition.scss +215 -0
  172. package/styles/gantt/_tailwind-definition.scss +215 -161
  173. package/styles/gantt/_theme.scss +702 -668
  174. package/styles/gantt/bootstrap-dark.css +442 -427
  175. package/styles/gantt/bootstrap.css +442 -433
  176. package/styles/gantt/bootstrap4.css +454 -479
  177. package/styles/gantt/bootstrap5-dark.css +457 -433
  178. package/styles/gantt/bootstrap5.css +457 -433
  179. package/styles/gantt/fabric-dark.css +438 -421
  180. package/styles/gantt/fabric.css +445 -428
  181. package/styles/gantt/fluent-dark.css +1938 -0
  182. package/styles/gantt/fluent-dark.scss +22 -0
  183. package/styles/gantt/fluent.css +1938 -0
  184. package/styles/gantt/fluent.scss +22 -0
  185. package/styles/gantt/highcontrast-light.css +405 -405
  186. package/styles/gantt/highcontrast.css +444 -456
  187. package/styles/gantt/icons/_bootstrap-dark.scss +124 -113
  188. package/styles/gantt/icons/_bootstrap.scss +124 -113
  189. package/styles/gantt/icons/_bootstrap4.scss +124 -113
  190. package/styles/gantt/icons/_bootstrap5.scss +124 -112
  191. package/styles/gantt/icons/_fabric-dark.scss +124 -112
  192. package/styles/gantt/icons/_fabric.scss +124 -112
  193. package/styles/gantt/icons/_fluent-dark.scss +1 -0
  194. package/styles/gantt/icons/_fluent.scss +124 -112
  195. package/styles/gantt/icons/_fusionnew.scss +120 -0
  196. package/styles/gantt/icons/_highcontrast.scss +124 -112
  197. package/styles/gantt/icons/_material-dark.scss +124 -112
  198. package/styles/gantt/icons/_material.scss +124 -112
  199. package/styles/gantt/icons/_material3.scss +124 -0
  200. package/styles/gantt/icons/_tailwind-dark.scss +124 -113
  201. package/styles/gantt/icons/_tailwind.scss +124 -113
  202. package/styles/gantt/material-dark.css +446 -417
  203. package/styles/gantt/material.css +445 -419
  204. package/styles/gantt/tailwind-dark.css +452 -482
  205. package/styles/gantt/tailwind.css +449 -479
  206. package/styles/highcontrast-light.css +405 -405
  207. package/styles/highcontrast.css +444 -456
  208. package/styles/material-dark.css +446 -417
  209. package/styles/material.css +445 -419
  210. package/styles/tailwind-dark.css +452 -482
  211. package/styles/tailwind.css +449 -479
@@ -0,0 +1,1397 @@
1
+ import { TimelineFormat } from './../base/interface';
2
+ import { createElement, isNullOrUndefined, getValue, addClass, removeClass, extend } from '@syncfusion/ej2-base';
3
+ import { Gantt } from '../base/gantt';
4
+ import { TimelineSettingsModel } from '../models/timeline-settings-model';
5
+ import * as cls from '../base/css-constants';
6
+ import { TimelineViewMode } from '../base/enum';
7
+ import { ITimeSpanEventArgs, ITimelineFormatter, IGanttData, ZoomEventArgs, ZoomTimelineSettings } from '../base/interface';
8
+ import { DataUtil } from '@syncfusion/ej2-data';
9
+ /**
10
+ * Configures the `Timeline` of the gantt.
11
+ */
12
+ export class Timeline {
13
+ private parent: Gantt;
14
+ public timelineStartDate: Date;
15
+ public timelineEndDate: Date;
16
+ public topTierCellWidth: number;
17
+ public bottomTierCellWidth: number;
18
+ public customTimelineSettings: TimelineSettingsModel;
19
+ public chartTimelineContainer: HTMLElement;
20
+ public topTier: string;
21
+ public bottomTier: string;
22
+ public isSingleTier: boolean;
23
+ private previousIsSingleTier: boolean;
24
+ public timelineRoundOffEndDate: Date;
25
+ public totalTimelineWidth: number;
26
+ public isZoomIn: boolean = false;
27
+ public isZooming: boolean = false;
28
+ public isZoomToFit: boolean = false;
29
+ public topTierCollection: TimelineFormat[] = [];
30
+ public bottomTierCollection: TimelineFormat[] = [];
31
+ constructor(ganttObj?: Gantt) {
32
+ this.parent = ganttObj;
33
+ this.initProperties();
34
+ }
35
+
36
+ /**
37
+ * To initialize the public property.
38
+ *
39
+ * @returns {void}
40
+ * @private
41
+ */
42
+ private initProperties(): void {
43
+ this.timelineStartDate = null;
44
+ this.timelineEndDate = null;
45
+ this.totalTimelineWidth = 0;
46
+ this.customTimelineSettings = null;
47
+ this.parent.isTimelineRoundOff = this.isZoomToFit ? false : isNullOrUndefined(this.parent.projectStartDate) ? true : false;
48
+ }
49
+
50
+ /**
51
+ * To render timeline header series.
52
+ *
53
+ * @returns {void}
54
+ * @private
55
+ */
56
+ public validateTimelineProp(): void {
57
+ this.roundOffDays();
58
+ this.processTimelineProperty();
59
+ this.timelineWidthCalculation();
60
+ }
61
+
62
+ /**
63
+ * Function used to refresh Gantt rows.
64
+ *
65
+ * @returns {void}
66
+ * @private
67
+ */
68
+ public refreshTimeline(): void {
69
+ this.initProperties();
70
+ this.processTimelineUnit();
71
+ this.parent.dataOperation.calculateProjectDates();
72
+ if (!this.parent.isFromOnPropertyChange) {
73
+ this.parent.updateProjectDates(
74
+ this.parent.cloneProjectStartDate, this.parent.cloneProjectEndDate, this.parent.isTimelineRoundOff);
75
+ }
76
+ }
77
+
78
+ /**
79
+ * Function used to refresh Gantt rows.
80
+ *
81
+ * @returns {void}
82
+ * @private
83
+ */
84
+ public refreshTimelineByTimeSpan(): void {
85
+ this.validateTimelineProp();
86
+ this.parent.ganttChartModule.chartTimelineContainer.innerHTML = '';
87
+ this.createTimelineSeries();
88
+ }
89
+
90
+ /**
91
+ * Function used to refresh Gantt rows.
92
+ *
93
+ * @returns {void}
94
+ * @private
95
+ */
96
+ public updateChartByNewTimeline(): void {
97
+ this.parent.chartRowsModule.refreshChartByTimeline();
98
+ this.parent.notify('refreshDayMarkers', {});
99
+
100
+ }
101
+ /**
102
+ * Function used to perform Zoomin and Zoomout actions in Gantt control.
103
+ *
104
+ * @param {boolean} isZoomIn .
105
+ * @private
106
+ * @returns {void}
107
+ */
108
+ public processZooming(isZoomIn: boolean): void {
109
+ this.isZoomToFit = false;
110
+ if (!isNullOrUndefined(this.parent.zoomingProjectStartDate)) {
111
+ this.parent.cloneProjectStartDate = this.parent.cloneProjectStartDate.getTime() < this.parent.zoomingProjectStartDate.getTime()
112
+ ? this.parent.cloneProjectStartDate : this.parent.zoomingProjectStartDate;
113
+ this.parent.cloneProjectEndDate = this.parent.cloneProjectEndDate.getTime() > this.parent.zoomingProjectEndDate.getTime()
114
+ ? this.parent.cloneProjectEndDate : this.parent.zoomingProjectEndDate;
115
+ }
116
+ this.parent.zoomingProjectStartDate = null;
117
+ this.parent.zoomingProjectEndDate = null;
118
+ const currentZoomingLevel: number = this.checkCurrentZoomingLevel();
119
+ this.isZoomIn = isZoomIn;
120
+ this.isZooming = true;
121
+ let currentLevel: number = isZoomIn ? currentZoomingLevel + 1 : currentZoomingLevel - 1;
122
+ if (this.parent.toolbarModule) {
123
+ if (isZoomIn) {
124
+ if (currentLevel === this.parent.zoomingLevels[this.parent.zoomingLevels.length - 1].level) {
125
+ this.parent.toolbarModule.enableItems([this.parent.controlId + '_zoomin'], false); // disable toolbar items.
126
+ } else {
127
+ this.parent.toolbarModule.enableItems([this.parent.controlId + '_zoomout'], true); // disable toolbar items.
128
+ }
129
+ } else {
130
+ if (currentLevel === this.parent.zoomingLevels[0].level) {
131
+ this.parent.toolbarModule.enableItems([this.parent.controlId + '_zoomout'], false); // disable toolbar items.
132
+ } else {
133
+ this.parent.toolbarModule.enableItems([this.parent.controlId + '_zoomin'], true); // enable toolbar items.
134
+ }
135
+ }
136
+ }
137
+ currentLevel = this.parent.zoomingLevels.findIndex((tempLevel: ZoomTimelineSettings) => {
138
+ return tempLevel.level === currentLevel;
139
+ });
140
+ let newTimeline: ZoomTimelineSettings = this.parent.zoomingLevels[currentLevel];
141
+ const args: ZoomEventArgs = {
142
+ requestType: isZoomIn ? 'beforeZoomIn' : 'beforeZoomOut',
143
+ timeline: newTimeline,
144
+ cancel: false
145
+ };
146
+ this.parent.trigger('actionBegin', args);
147
+ if (!args.cancel) {
148
+ newTimeline = args.timeline;
149
+ this.changeTimelineSettings(newTimeline);
150
+ }
151
+ }
152
+
153
+ /**
154
+ * To change the timeline settings property values based upon the Zooming levels.
155
+ *
156
+ * @param {ZoomTimelineSettings} newTimeline .
157
+ * @returns {void}
158
+ * @private
159
+ */
160
+ private changeTimelineSettings(newTimeline: ZoomTimelineSettings): void {
161
+ const skipProperty: string = this.isSingleTier ?
162
+ this.customTimelineSettings.topTier.unit === 'None' ?
163
+ 'topTier' : 'bottomTier' : null;
164
+ Object.keys(this.customTimelineSettings).forEach((property: string) => {
165
+ if (property !== skipProperty) {
166
+ this.customTimelineSettings[property] = (typeof newTimeline[property] === 'object'
167
+ && !isNullOrUndefined(newTimeline[property])) ? { ...newTimeline[property] } : newTimeline[property];
168
+ } else {
169
+ const value: string = property === 'topTier' ? 'bottomTier' : 'topTier';
170
+ const assignValue: string = 'bottomTier';
171
+ this.customTimelineSettings[value] = { ...newTimeline[assignValue] };
172
+ }
173
+ });
174
+ this.parent.isTimelineRoundOff = this.isZoomToFit ? false : isNullOrUndefined(this.parent.projectStartDate) ? true : false;
175
+ this.processTimelineUnit();
176
+ this.parent.updateProjectDates(
177
+ this.parent.cloneProjectStartDate, this.parent.cloneProjectEndDate, this.parent.isTimelineRoundOff);
178
+ if (this.isZooming || this.isZoomToFit) {
179
+ const args: ZoomEventArgs = {
180
+ requestType: this.isZoomIn ? 'AfterZoomIn' : this.isZoomToFit ? 'AfterZoomToProject' : 'AfterZoomOut',
181
+ timeline: this.parent.currentZoomingLevel
182
+ };
183
+ this.parent.trigger('actionComplete', args);
184
+ }
185
+
186
+ }
187
+ /**
188
+ * To perform the zoom to fit operation in Gantt.
189
+ *
190
+ * @returns {void}
191
+ * @private
192
+ */
193
+ public processZoomToFit(): void {
194
+ this.isZoomToFit = true;
195
+ this.isZooming = false;
196
+ if (!this.parent.zoomingProjectStartDate) {
197
+ this.parent.zoomingProjectStartDate = this.parent.cloneProjectStartDate;
198
+ this.parent.zoomingProjectEndDate = this.parent.cloneProjectEndDate;
199
+ }
200
+ this.parent.dataOperation.calculateProjectDates();
201
+ const timeDifference: number = (this.parent.cloneProjectEndDate.getTime() - this.parent.cloneProjectStartDate.getTime());
202
+ const totalDays: number = (timeDifference / (1000 * 3600 * 24));
203
+ const chartWidth: number = this.parent.ganttChartModule.chartElement.offsetWidth;
204
+ const perDayWidth: number = chartWidth / totalDays;
205
+ let zoomingLevel: ZoomTimelineSettings;
206
+ let firstValue: ZoomTimelineSettings;
207
+ let secondValue: ZoomTimelineSettings;
208
+ const zoomingCollections: ZoomTimelineSettings[] = [...this.parent.zoomingLevels];
209
+ const sortedCollectons: ZoomTimelineSettings[] = zoomingCollections.sort((a: ZoomTimelineSettings, b: ZoomTimelineSettings) =>
210
+ (a.perDayWidth < b.perDayWidth) ? 1 : -1);
211
+ if (perDayWidth === 0) { // return when the Gantt chart is not in viewable state.
212
+ return;
213
+ }
214
+ for (let i: number = 0; i < sortedCollectons.length; i++) {
215
+ firstValue = sortedCollectons[i];
216
+ if (i === sortedCollectons.length - 1) {
217
+ zoomingLevel = sortedCollectons[i];
218
+ break;
219
+ } else {
220
+ secondValue = sortedCollectons[i + 1];
221
+ }
222
+ if (perDayWidth >= firstValue.perDayWidth) {
223
+ zoomingLevel = sortedCollectons[i];
224
+ break;
225
+ }
226
+ if (perDayWidth < firstValue.perDayWidth && perDayWidth > secondValue.perDayWidth) {
227
+ zoomingLevel = sortedCollectons[i + 1];
228
+ break;
229
+ }
230
+ }
231
+ const newTimeline: ZoomTimelineSettings = extend({}, {}, zoomingLevel, true);
232
+ this.roundOffDateToZoom(this.parent.cloneProjectStartDate, true, perDayWidth, newTimeline.bottomTier.unit);
233
+ this.roundOffDateToZoom(this.parent.cloneProjectEndDate, false, perDayWidth, newTimeline.bottomTier.unit);
234
+ const numberOfCells: number = this.calculateNumberOfTimelineCells(newTimeline);
235
+ const scrollHeight: number = this.parent.ganttChartModule.scrollElement.offsetHeight - 17; //17 is horizontal scrollbar width
236
+ const contentHeight: number = this.parent.ganttChartModule.chartBodyContent.offsetHeight;
237
+ const emptySpace: number = contentHeight <= scrollHeight ? 0 : 17;
238
+ newTimeline.timelineUnitSize = Math.abs((chartWidth - emptySpace)) / numberOfCells;
239
+ const args: ZoomEventArgs = {
240
+ requestType: 'beforeZoomToProject',
241
+ timeline: newTimeline
242
+ };
243
+ if (this.parent.toolbarModule) {
244
+ this.parent.toolbarModule.enableItems([this.parent.controlId + '_zoomin', this.parent.controlId + '_zoomout'], true);
245
+ }
246
+ this.parent.trigger('actionBegin', args);
247
+ this.changeTimelineSettings(newTimeline);
248
+ }
249
+
250
+ private roundOffDateToZoom(date: Date, isStartDate: boolean, perDayWidth: number, tierMode: string): void {
251
+ const width: number = tierMode === 'Month' || tierMode === 'Year' ? 60 : 20;
252
+ const roundOffTime: number = (width / perDayWidth) * (24 * 60 * 60 * 1000);
253
+ if (isStartDate) {
254
+ date.setTime(date.getTime() - roundOffTime);
255
+ } else {
256
+ date.setTime(date.getTime() + roundOffTime);
257
+ }
258
+ if (tierMode === 'Hour') {
259
+ date.setMinutes(isStartDate ? -120 : 120);
260
+ } else if (tierMode === 'Minutes') {
261
+ date.setSeconds(isStartDate ? -120 : 120);
262
+ } else {
263
+ date.setHours(isStartDate ? -48 : 48, 0, 0, 0);
264
+ }
265
+ }
266
+
267
+ private calculateNumberOfTimelineCells(newTimeline: ZoomTimelineSettings): number {
268
+ const numberOfDays: number = Math.abs((this.parent.cloneProjectEndDate.getTime() -
269
+ this.parent.cloneProjectStartDate.getTime()) / (24 * 60 * 60 * 1000));
270
+ const count: number = newTimeline.bottomTier.count;
271
+ const unit: string = newTimeline.bottomTier.unit;
272
+ if (unit === 'Day') {
273
+ return numberOfDays / count;
274
+ } else if (unit === 'Week') {
275
+ return (numberOfDays / count) / 7;
276
+ } else if (unit === 'Month') {
277
+ return (numberOfDays / count) / 28;
278
+ } else if (unit === 'Year') {
279
+ return (numberOfDays / count) / (12 * 28);
280
+ } else if (unit === 'Hour') {
281
+ return numberOfDays * (24 / count);
282
+ } else {
283
+ return numberOfDays * ((60 * 24) / count);
284
+ }
285
+ }
286
+ /**
287
+ * To validate time line unit.
288
+ *
289
+ * @returns {void}
290
+ * @private
291
+ */
292
+ public processTimelineUnit(): void {
293
+ const directProperty: string[] = ['timelineViewMode', 'timelineUnitSize', 'weekStartDay', 'weekendBackground'];
294
+ const innerProperty: Object = {
295
+ 'topTier': ['unit', 'format', 'count', 'formatter'],
296
+ 'bottomTier': ['unit', 'format', 'count', 'formatter']
297
+ };
298
+ const tierUnits: string[] = ['Year', 'Month', 'Week', 'Day', 'Hour', 'Minutes'];
299
+ this.customTimelineSettings = this.customTimelineSettings ? this.customTimelineSettings :
300
+ this.extendFunction(this.parent.timelineSettings, directProperty, innerProperty);
301
+ if ((tierUnits.indexOf(this.customTimelineSettings.topTier.unit) === -1) &&
302
+ (tierUnits.indexOf(this.customTimelineSettings.bottomTier.unit) === -1)) {
303
+ this.customTimelineSettings.topTier.unit = tierUnits.indexOf(this.customTimelineSettings.timelineViewMode) !== -1 ?
304
+ this.customTimelineSettings.timelineViewMode : 'Week';
305
+ this.customTimelineSettings.bottomTier.unit = tierUnits.indexOf(this.customTimelineSettings.topTier.unit) !== 5 ?
306
+ tierUnits[tierUnits.indexOf(this.customTimelineSettings.topTier.unit) + 1] as TimelineViewMode : 'None';
307
+ } else if ((tierUnits.indexOf(this.customTimelineSettings.topTier.unit) !== -1 &&
308
+ tierUnits.indexOf(this.customTimelineSettings.bottomTier.unit) !== -1)
309
+ && (tierUnits.indexOf(this.customTimelineSettings.topTier.unit) >
310
+ tierUnits.indexOf(this.customTimelineSettings.bottomTier.unit))) {
311
+ this.customTimelineSettings.bottomTier.unit = this.customTimelineSettings.topTier.unit;
312
+ } else {
313
+ this.customTimelineSettings.topTier.unit = tierUnits.indexOf(this.customTimelineSettings.topTier.unit) === -1 ?
314
+ 'None' : this.customTimelineSettings.topTier.unit;
315
+ this.customTimelineSettings.bottomTier.unit = tierUnits.indexOf(this.customTimelineSettings.bottomTier.unit) === -1 ?
316
+ 'None' : this.customTimelineSettings.bottomTier.unit;
317
+ }
318
+ this.topTier = this.customTimelineSettings.topTier.unit;
319
+ this.bottomTier = this.customTimelineSettings.bottomTier.unit;
320
+ this.previousIsSingleTier = this.isSingleTier;
321
+ this.isSingleTier = this.topTier === 'None' || this.bottomTier === 'None' ? true : false;
322
+ }
323
+
324
+ /**
325
+ * To validate timeline properties.
326
+ *
327
+ * @returns {void}
328
+ * @private
329
+ */
330
+ private processTimelineProperty(): void {
331
+
332
+ this.customTimelineSettings.topTier.count = (this.topTier === 'None') ?
333
+ 1 : this.validateCount(this.customTimelineSettings.topTier.unit, this.customTimelineSettings.topTier.count, 'topTier');
334
+ this.customTimelineSettings.bottomTier.count = this.customTimelineSettings.bottomTier.unit === 'None' ?
335
+ 1 : this.validateCount(this.customTimelineSettings.bottomTier.unit, this.customTimelineSettings.bottomTier.count, 'bottomTier');
336
+ this.customTimelineSettings.bottomTier.format = this.validateFormat(
337
+ this.customTimelineSettings.bottomTier.unit, this.customTimelineSettings.bottomTier.format);
338
+ this.customTimelineSettings.topTier.format = this.validateFormat(this.topTier, this.customTimelineSettings.topTier.format);
339
+ this.customTimelineSettings.weekStartDay = this.customTimelineSettings.weekStartDay >= 0 &&
340
+ this.customTimelineSettings.weekStartDay <= 6 ? this.customTimelineSettings.weekStartDay : 0;
341
+ this.checkCurrentZoomingLevel();
342
+ }
343
+ /**
344
+ * To find the current zooming level of the Gantt control.
345
+ *
346
+ * @returns {void}
347
+ * @private
348
+ */
349
+ public calculateZoomingLevelsPerDayWidth(): void {
350
+ const collections: ZoomTimelineSettings[] = this.parent.zoomingLevels;
351
+ for (let i: number = 0; i < collections.length; i++) {
352
+ const perDayWidth: number =
353
+ this.getPerDayWidth(
354
+ collections[i].timelineUnitSize,
355
+ collections[i].bottomTier.count,
356
+ collections[i].bottomTier.unit);
357
+ collections[i].perDayWidth = perDayWidth;
358
+ }
359
+ }
360
+ /**
361
+ * To find the current zooming level of the Gantt control.
362
+ *
363
+ * @returns {void}
364
+ * @private
365
+ */
366
+ private checkCurrentZoomingLevel(): number {
367
+ const count: number = this.customTimelineSettings.bottomTier.unit !== 'None' ?
368
+ this.customTimelineSettings.bottomTier.count : this.customTimelineSettings.topTier.count;
369
+ const unit: string = this.customTimelineSettings.bottomTier.unit !== 'None' ?
370
+ this.customTimelineSettings.bottomTier.unit : this.customTimelineSettings.topTier.unit;
371
+ const zoomLevel: number = this.getCurrentZoomingLevel(unit, count);
372
+ if (this.parent.toolbarModule) {
373
+ if (zoomLevel === this.parent.zoomingLevels[this.parent.zoomingLevels.length - 1].level) {
374
+ this.parent.toolbarModule.enableItems([this.parent.controlId + '_zoomin'], false);
375
+ } else if (zoomLevel === this.parent.zoomingLevels[0].level) {
376
+ this.parent.toolbarModule.enableItems([this.parent.controlId + '_zoomout'], false);
377
+ }
378
+
379
+ }
380
+ this.parent.currentZoomingLevel = this.parent.zoomingLevels[zoomLevel];
381
+ return zoomLevel;
382
+ }
383
+ /**
384
+ * @param {string} unit .
385
+ * @param {number} count .
386
+ * @returns {number} .
387
+ * @private
388
+ */
389
+ private getCurrentZoomingLevel(unit: string, count: number): number {
390
+ let level: number;
391
+ let currentZoomCollection: ZoomTimelineSettings;
392
+ let checkSameCountLevels: ZoomTimelineSettings[];
393
+ let secondValue: ZoomTimelineSettings;
394
+ let firstValue: ZoomTimelineSettings;
395
+ if (!this.parent.zoomingLevels.length) {
396
+ this.parent.zoomingLevels = this.parent.getZoomingLevels();
397
+ }
398
+ let sameUnitLevels: ZoomTimelineSettings[] = this.parent.zoomingLevels.filter((tempLevel: ZoomTimelineSettings) => {
399
+ return tempLevel.bottomTier.unit === unit;
400
+ });
401
+ if (sameUnitLevels.length === 0) {
402
+ const closestUnit: string = this.getClosestUnit(unit, '', false);
403
+ sameUnitLevels = this.parent.zoomingLevels.filter((tempLevel: ZoomTimelineSettings) => {
404
+ return tempLevel.bottomTier.unit === closestUnit;
405
+ });
406
+ }
407
+ const sortedUnitLevels: ZoomTimelineSettings[] = sameUnitLevels.sort((a: ZoomTimelineSettings, b: ZoomTimelineSettings) =>
408
+ (a.bottomTier.count < b.bottomTier.count) ? 1 : -1);
409
+ for (let i: number = 0; i < sortedUnitLevels.length; i++) {
410
+ firstValue = sortedUnitLevels[i];
411
+ if (i === sortedUnitLevels.length - 1) {
412
+ level = sortedUnitLevels[i].level;
413
+ break;
414
+ } else {
415
+ secondValue = sortedUnitLevels[i + 1];
416
+ }
417
+
418
+ if (count >= firstValue.bottomTier.count) {
419
+ currentZoomCollection = sortedUnitLevels[i];
420
+ checkSameCountLevels = sortedUnitLevels.filter((tempLevel: ZoomTimelineSettings) => {
421
+ return tempLevel.bottomTier.count === currentZoomCollection.bottomTier.count;
422
+ });
423
+ if (checkSameCountLevels.length > 1) {
424
+ level = this.checkCollectionsWidth(checkSameCountLevels);
425
+ } else {
426
+ level = checkSameCountLevels[0].level;
427
+ }
428
+ break;
429
+ } else if (count < firstValue.bottomTier.count && count > secondValue.bottomTier.count) {
430
+ currentZoomCollection = sortedUnitLevels[i + 1];
431
+ checkSameCountLevels = sortedUnitLevels.filter((tempLevel: ZoomTimelineSettings) => {
432
+ return tempLevel.bottomTier.count === currentZoomCollection.bottomTier.count;
433
+ });
434
+ if (checkSameCountLevels.length > 1) {
435
+ level = this.checkCollectionsWidth(checkSameCountLevels);
436
+ } else {
437
+ level = checkSameCountLevels[0].level;
438
+ }
439
+ break;
440
+ }
441
+ }
442
+ return level;
443
+ }
444
+ /**
445
+ * Getting closest zooimg level.
446
+ *
447
+ * @param {string} unit .
448
+ * @param {string} closetUnit .
449
+ * @param {boolean} isCont .
450
+ * @returns {string} .
451
+ * @private
452
+ */
453
+ private getClosestUnit(unit: string, closetUnit: string, isCont: boolean): string {
454
+ const bottomTierUnits: string[] = ['Year', 'Month', 'Week', 'Day', 'Hour', 'Minutes'];
455
+ const index: number = bottomTierUnits.indexOf(unit);
456
+ if (index === 0) {
457
+ isCont = true;
458
+ }
459
+ if (this.isZoomIn || isCont) {
460
+ unit = bottomTierUnits[index + 1];
461
+ } else {
462
+ unit = bottomTierUnits[index - 1];
463
+
464
+ }
465
+ const sameUnitLevels: ZoomTimelineSettings[] = this.parent.zoomingLevels.filter((tempLevel: ZoomTimelineSettings) => {
466
+ return tempLevel.bottomTier.unit === unit;
467
+ });
468
+ if (sameUnitLevels.length === 0) {
469
+ if (unit === 'Year') {
470
+ isCont = true;
471
+ }
472
+ closetUnit = unit;
473
+ return this.getClosestUnit(unit, closetUnit, isCont);
474
+ } else {
475
+ return unit;
476
+ }
477
+
478
+
479
+ }
480
+ private checkCollectionsWidth(checkSameLevels: ZoomTimelineSettings[]): number {
481
+ const zoomLevels: ZoomTimelineSettings[] = checkSameLevels;
482
+ const width: number = this.customTimelineSettings.timelineUnitSize;
483
+ let level: number;
484
+ let secondValue: ZoomTimelineSettings;
485
+ let firstValue: ZoomTimelineSettings;
486
+ const sortedZoomLevels: ZoomTimelineSettings[] = zoomLevels.sort((a: ZoomTimelineSettings, b: ZoomTimelineSettings) =>
487
+ (a.timelineUnitSize < b.timelineUnitSize) ? 1 : -1);
488
+ for (let i: number = 0; i < sortedZoomLevels.length; i++) {
489
+ firstValue = sortedZoomLevels[i];
490
+ if (i === sortedZoomLevels.length - 1) {
491
+ level = sortedZoomLevels[i].level;
492
+ break;
493
+ } else {
494
+ secondValue = sortedZoomLevels[i + 1];
495
+ }
496
+ if (width >= firstValue.timelineUnitSize) {
497
+ level = sortedZoomLevels[i].level;
498
+ break;
499
+ } else if (width < firstValue.timelineUnitSize && width > secondValue.timelineUnitSize) {
500
+ level = sortedZoomLevels[i + 1].level;
501
+ break;
502
+ }
503
+ }
504
+ return level;
505
+ }
506
+ /**
507
+ * To create timeline header template.
508
+ *
509
+ * @returns {void}
510
+ * @private
511
+ */
512
+ public updateTimelineHeaderHeight(): void {
513
+ if (this.parent.timelineModule.isSingleTier) {
514
+ addClass([this.parent.ganttChartModule.chartTimelineContainer as Element], cls.timelineSingleHeaderOuterDiv);
515
+ if (this.parent.treeGrid.element) {
516
+ addClass(this.parent.treeGrid.element.querySelectorAll('.e-headercell'), cls.timelineSingleHeaderOuterDiv);
517
+ addClass(this.parent.treeGrid.element.querySelectorAll('.e-columnheader'), cls.timelineSingleHeaderOuterDiv);
518
+ }
519
+ } else {
520
+ removeClass([this.parent.ganttChartModule.chartTimelineContainer as Element], cls.timelineSingleHeaderOuterDiv);
521
+ if (this.parent.treeGrid.element) {
522
+ removeClass(this.parent.treeGrid.element.querySelectorAll('.e-headercell'), cls.timelineSingleHeaderOuterDiv);
523
+ removeClass(this.parent.treeGrid.element.querySelectorAll('.e-columnheader'), cls.timelineSingleHeaderOuterDiv);
524
+ }
525
+ }
526
+ if (this.previousIsSingleTier !== this.isSingleTier) {
527
+ let toolbarHeight: number = 0;
528
+ if (!isNullOrUndefined(this.parent.toolbarModule) && !isNullOrUndefined(this.parent.toolbarModule.element)) {
529
+ toolbarHeight = this.parent.toolbarModule.element.offsetHeight;
530
+ }
531
+ this.parent.ganttChartModule.scrollObject.
532
+ setHeight(this.parent.ganttHeight - this.parent.ganttChartModule.chartTimelineContainer.offsetHeight - toolbarHeight);
533
+ this.parent.treeGrid.height = this.parent.ganttHeight - toolbarHeight -
534
+ this.parent.ganttChartModule.chartTimelineContainer.offsetHeight;
535
+ }
536
+ }
537
+
538
+ /**
539
+ * To create timeline header template.
540
+ *
541
+ * @returns {void}
542
+ * @private
543
+ */
544
+ public createTimelineSeries(): void {
545
+ let tr: Element;
546
+ let td: Element;
547
+ let div: Element;
548
+ let table: HTMLElement;
549
+ let thead: Element;
550
+ const loopCount: number = this.isSingleTier ? 1 : 2;
551
+ let tier: string = this.topTier === 'None' ? 'bottomTier' : 'topTier';
552
+ this.updateTimelineHeaderHeight();
553
+ this.topTierCollection = [];
554
+ this.bottomTierCollection = [];
555
+ for (let count: number = 0; count < loopCount; count++) {
556
+ table = createElement(
557
+ 'table', { className: cls.timelineHeaderTableContainer, styles: 'display: block;' });
558
+ thead = createElement('thead', { className: cls.timelineHeaderTableBody, styles: 'display:block; border-collapse:collapse' });
559
+ tr = createElement('tr', { innerHTML: this.createTimelineTemplate(tier) });
560
+ td = createElement('th');
561
+ div = createElement('div', { styles: 'width: 20px' });
562
+ td.appendChild(div);
563
+ tr.appendChild(td);
564
+ thead.appendChild(tr);
565
+ table.appendChild(thead);
566
+ this.parent.ganttChartModule.chartTimelineContainer.appendChild(table);
567
+ tier = 'bottomTier';
568
+ tr = null;
569
+
570
+
571
+ }
572
+ }
573
+
574
+ /**
575
+ * To validate timeline tier count.
576
+ *
577
+ * @param {string} mode .
578
+ * @param {number} count .
579
+ * @param {string} tier .
580
+ * @returns {number} .
581
+ * @private
582
+ */
583
+ private validateCount(mode: string, count: number, tier: string): number {
584
+ let tierCount: number = !isNullOrUndefined(count) && parseInt(count.toString(), 10) > 0 ? parseInt(count.toString(), 10) : 1;
585
+ const timeDifference: number = Math.abs(this.timelineRoundOffEndDate.getTime() - this.timelineStartDate.getTime());
586
+ let difference: number;
587
+ switch (mode) {
588
+ case 'Year':
589
+ difference = Math.round((timeDifference / (1000 * 3600 * 24)) / (12 * 28));
590
+ tierCount = tierCount <= difference ? tierCount : difference > 0 ? difference : 1;
591
+ if (this.topTier !== 'None' && tier === 'bottomTier') {
592
+ tierCount = this.validateBottomTierCount(mode, tierCount);
593
+ }
594
+ break;
595
+ case 'Month':
596
+ difference = Math.round((timeDifference / (1000 * 3600 * 24)) / 28);
597
+ tierCount = tierCount <= difference ? tierCount : difference > 0 ? difference : 1;
598
+ if (this.topTier !== 'None' && tier === 'bottomTier') {
599
+ tierCount = this.validateBottomTierCount(mode, tierCount);
600
+ }
601
+ break;
602
+ case 'Week':
603
+ difference = Math.round((timeDifference / (1000 * 3600 * 24)) / 7);
604
+ tierCount = tierCount <= difference ? tierCount : difference > 0 ? difference : 1;
605
+ if (this.topTier !== 'None' && tier === 'bottomTier') {
606
+ tierCount = this.validateBottomTierCount(mode, tierCount);
607
+ }
608
+ break;
609
+ case 'Day':
610
+ difference = Math.round(timeDifference / (1000 * 3600 * 24));
611
+ tierCount = tierCount <= difference ? tierCount : difference > 0 ? difference : 1;
612
+ if (this.topTier !== 'None' && tier === 'bottomTier') {
613
+ tierCount = this.validateBottomTierCount(mode, tierCount);
614
+ }
615
+ break;
616
+ case 'Hour':
617
+ difference = Math.round(timeDifference / (1000 * 3600));
618
+ tierCount = tierCount <= difference ? tierCount : difference > 0 ? difference : 1;
619
+ if (this.topTier !== 'None' && tier === 'bottomTier') {
620
+ tierCount = this.validateBottomTierCount(mode, tierCount);
621
+ }
622
+ break;
623
+ case 'Minutes':
624
+ difference = Math.round(timeDifference / (1000 * 60));
625
+ tierCount = tierCount <= difference ? tierCount : difference > 0 ? difference : 1;
626
+ if (this.topTier !== 'None' && tier === 'bottomTier') {
627
+ tierCount = this.validateBottomTierCount(mode, tierCount);
628
+ }
629
+ break;
630
+ }
631
+ if (count !== tierCount && this.isZooming && this.parent.toolbarModule && (tier === 'bottomTier' || this.isSingleTier)) {
632
+ if (this.isZoomIn) {
633
+ this.parent.toolbarModule.enableItems([this.parent.controlId + '_zoomin'], false);
634
+ } else {
635
+ this.parent.toolbarModule.enableItems([this.parent.controlId + '_zoomout'], false);
636
+ }
637
+ }
638
+ return tierCount;
639
+ }
640
+
641
+ /**
642
+ * To validate bottom tier count.
643
+ *
644
+ * @param {string} mode .
645
+ * @param {number} tierCount .
646
+ * @returns {number} .
647
+ * @private
648
+ */
649
+ private validateBottomTierCount(mode: string, tierCount: number): number {
650
+ let count: number;
651
+ switch (mode) {
652
+ case 'Year':
653
+ count = tierCount <= this.customTimelineSettings.topTier.count ?
654
+ tierCount : this.customTimelineSettings.topTier.count;
655
+ break;
656
+ case 'Month':
657
+ count = this.topTier === 'Year' ? tierCount <= (this.customTimelineSettings.topTier.count * 12) ?
658
+ tierCount : (this.customTimelineSettings.topTier.count * 12) :
659
+ tierCount <= this.customTimelineSettings.topTier.count ?
660
+ tierCount : this.customTimelineSettings.topTier.count;
661
+ break;
662
+ case 'Week':
663
+ count = this.topTier === 'Year' ? tierCount <= (this.customTimelineSettings.topTier.count * (12 * 4)) ?
664
+ tierCount : (this.customTimelineSettings.topTier.count * (12 * 4)) :
665
+ this.topTier === 'Month' ? tierCount <= (this.customTimelineSettings.topTier.count * 4) ?
666
+ tierCount : (this.customTimelineSettings.topTier.count * 4) :
667
+ tierCount <= this.customTimelineSettings.topTier.count ?
668
+ tierCount : this.customTimelineSettings.topTier.count;
669
+ break;
670
+ case 'Day':
671
+ count = this.topTier === 'Year' ? tierCount <= (this.customTimelineSettings.topTier.count * (12 * 28)) ?
672
+ tierCount : (this.customTimelineSettings.topTier.count * (12 * 28)) :
673
+ this.topTier === 'Month' ? tierCount <= (this.customTimelineSettings.topTier.count * 28) ?
674
+ tierCount : (this.customTimelineSettings.topTier.count * 28) :
675
+ this.topTier === 'Week' ? tierCount <= (this.customTimelineSettings.topTier.count * 7) ?
676
+ tierCount : (this.customTimelineSettings.topTier.count * 7) :
677
+ tierCount <= this.customTimelineSettings.topTier.count ? tierCount : this.customTimelineSettings.topTier.count;
678
+ break;
679
+ case 'Hour':
680
+ count = this.topTier === 'Year' ? tierCount <= (this.customTimelineSettings.topTier.count * (12 * 28 * 24)) ?
681
+ tierCount : (this.customTimelineSettings.topTier.count * (12 * 28 * 24)) :
682
+ this.topTier === 'Month' ? tierCount <= (this.customTimelineSettings.topTier.count * (28 * 24)) ?
683
+ tierCount : (this.customTimelineSettings.topTier.count * (28 * 24)) :
684
+ this.topTier === 'Week' ? tierCount <= (this.customTimelineSettings.topTier.count * 7 * 24) ?
685
+ tierCount : (this.customTimelineSettings.topTier.count * 7 * 24) :
686
+ this.topTier === 'Day' ? tierCount <= (this.customTimelineSettings.topTier.count * 24) ?
687
+ tierCount : (this.customTimelineSettings.topTier.count * 24) :
688
+ tierCount <= this.customTimelineSettings.topTier.count ?
689
+ tierCount : this.customTimelineSettings.topTier.count;
690
+ break;
691
+ case 'Minutes':
692
+ count = this.topTier === 'Year' ? tierCount <= (this.customTimelineSettings.topTier.count * (12 * 28 * 24 * 60)) ?
693
+ tierCount : (this.customTimelineSettings.topTier.count * (12 * 28 * 24 * 60)) :
694
+ this.topTier === 'Month' ? tierCount <= (this.customTimelineSettings.topTier.count * (28 * 24 * 60)) ?
695
+ tierCount : (this.customTimelineSettings.topTier.count * (28 * 24 * 60)) :
696
+ this.topTier === 'Week' ? tierCount <= (this.customTimelineSettings.topTier.count * 7 * 24 * 60) ?
697
+ tierCount : (this.customTimelineSettings.topTier.count * 7 * 24 * 60) :
698
+ this.topTier === 'Day' ? tierCount <= (this.customTimelineSettings.topTier.count * 24 * 60) ?
699
+ tierCount : (this.customTimelineSettings.topTier.count * 24 * 60) :
700
+ this.topTier === 'Hour' ? tierCount <= (this.customTimelineSettings.topTier.count * 60) ?
701
+ tierCount : (this.customTimelineSettings.topTier.count * 60) :
702
+ tierCount <= this.customTimelineSettings.topTier.count ?
703
+ tierCount : this.customTimelineSettings.topTier.count;
704
+ break;
705
+ }
706
+ return count;
707
+ }
708
+
709
+ /**
710
+ * To validate timeline tier format.
711
+ *
712
+ * @param {string} mode .
713
+ * @param {string} format .
714
+ * @returns {string} .
715
+ * @private
716
+ */
717
+ private validateFormat(mode: string, format: string): string {
718
+ let tierFormat: string;
719
+ switch (mode) {
720
+ case 'Week':
721
+ tierFormat = !format ? 'MMM dd, yyyy' : format;
722
+ break;
723
+ case 'Day':
724
+ case 'None':
725
+ tierFormat = !format ? '' : format;
726
+ break;
727
+ case 'Hour':
728
+ tierFormat = !format ? 'H' : format;
729
+ break;
730
+ case 'Month':
731
+ tierFormat = !format ? 'MMM yyyy' : format;
732
+ break;
733
+ case 'Year':
734
+ tierFormat = !format ? 'yyyy' : format;
735
+ break;
736
+ case 'Minutes':
737
+ tierFormat = !format ? 'm' : format;
738
+ break;
739
+ }
740
+ return tierFormat;
741
+ }
742
+
743
+ /**
744
+ * To perform extend operation.
745
+ *
746
+ * @param {object} cloneObj .
747
+ * @param {string[]} propertyCollection .
748
+ * @param {object} innerProperty .
749
+ * @returns {object} .
750
+ * @private
751
+ */
752
+ public extendFunction(cloneObj: Object, propertyCollection: string[], innerProperty?: Object): Object {
753
+ const tempObj: Object = {};
754
+ for (let index: number = 0; index < propertyCollection.length; index++) {
755
+ tempObj[propertyCollection[index]] = cloneObj[propertyCollection[index]];
756
+ }
757
+ if (innerProperty) {
758
+ Object.keys(innerProperty).forEach((key: string) => {
759
+ tempObj[key] = this.extendFunction(cloneObj[key], innerProperty[key], null);
760
+ });
761
+ }
762
+ return tempObj;
763
+ }
764
+
765
+ /**
766
+ * To format date.
767
+ *
768
+ * @param {string} dayFormat .
769
+ * @param {Date} data .
770
+ * @returns {string} .
771
+ * @private
772
+ */
773
+ private formatDateHeader(dayFormat: string, data: Date): string {
774
+ const date: Date = new Date(data.getTime());
775
+ let dateString: string;
776
+ if (dayFormat === '') {
777
+ dateString = this.parent.globalize.formatDate(date, { format: 'E' });
778
+ if (this.parent.locale === 'zh') {
779
+ dateString = dateString.slice(1);
780
+ } else {
781
+ dateString = dateString.slice(0, 1);
782
+ }
783
+ } else {
784
+ dateString = this.parent.globalize.formatDate(date, { format: dayFormat });
785
+ }
786
+ return dateString;
787
+ }
788
+
789
+ /**
790
+ * Custom Formatting.
791
+ *
792
+ * @param {Date} date .
793
+ * @param {string} format .
794
+ * @param {string} tier .
795
+ * @param {string} mode .
796
+ * @param {string | ITimelineFormatter} formatter .
797
+ * @returns {string} .
798
+ * @private
799
+ */
800
+ private customFormat(date: Date, format: string, tier: string, mode: string, formatter: string | ITimelineFormatter): string {
801
+ formatter = (typeof formatter === 'string' ? getValue(formatter, window) as ITimelineFormatter : formatter);
802
+ return formatter(date, format, tier, mode);
803
+ }
804
+
805
+ /**
806
+ * To create timeline template .
807
+ *
808
+ * @param {string} tier .
809
+ * @returns {string} .
810
+ * @private
811
+ */
812
+ private createTimelineTemplate(tier: string): string {
813
+ var isFirstCell = false;
814
+ const parent: Gantt = this.parent;
815
+ let parentTh: string = '';
816
+ let parentTr: string = '';
817
+ const mode: string = tier === 'topTier' ?
818
+ parent.timelineModule.customTimelineSettings.topTier.unit : parent.timelineModule.customTimelineSettings.bottomTier.unit;
819
+ const count: number = tier === 'topTier' ? parent.timelineModule.customTimelineSettings.topTier.count :
820
+ parent.timelineModule.customTimelineSettings.bottomTier.count;
821
+ let increment: number;
822
+ let newTime: number;
823
+ const startDate: Date = new Date(this.parent.timelineModule.timelineStartDate.toString());
824
+ const endDate: Date = new Date(this.timelineRoundOffEndDate.toString());
825
+ const scheduleDateCollection: Date[] = [];
826
+ do {
827
+ // PDf export collection
828
+ const timelineCell: TimelineFormat = {};
829
+ timelineCell.startDate = new Date(startDate.getTime());
830
+ if (mode === 'Month' && tier === 'bottomTier' && ((this.parent.currentZoomingLevel.level === 5) || (this.parent.currentZoomingLevel.level === 6)) && scheduleDateCollection.length === 0) {
831
+ isFirstCell = true;
832
+ }
833
+ parentTr = this.getHeaterTemplateString(new Date(startDate.toString()), mode, tier, false, count, timelineCell, isFirstCell);
834
+ scheduleDateCollection.push(new Date(startDate.toString()));
835
+ if (isFirstCell) {
836
+ newTime = this.calculateQuarterEndDate(startDate).getTime();
837
+ } else {
838
+ increment = this.getIncrement(startDate, count, mode);
839
+ newTime = startDate.getTime() + increment;
840
+ }
841
+ isFirstCell = false;
842
+ startDate.setTime(newTime);
843
+ if (startDate >= endDate) {
844
+ /* eslint-disable-next-line */
845
+ parentTr = this.getHeaterTemplateString(scheduleDateCollection[scheduleDateCollection.length - 1], mode, tier, true, count, timelineCell);
846
+ }
847
+ parentTh = parentTh + parentTr;
848
+ const tierCollection: TimelineFormat[] = tier === 'topTier' ? this.topTierCollection : this.bottomTierCollection;
849
+ timelineCell.endDate = new Date(startDate.getTime());
850
+ tierCollection.push(timelineCell);
851
+ } while ((startDate < endDate));
852
+ return parentTh;
853
+ }
854
+ public updateTimelineAfterZooming(endDate: Date, resized: boolean) {
855
+ let timeDiff: number;
856
+ let perDayWidth: number;
857
+ let totWidth: number;
858
+ let contentElement: HTMLElement = document.getElementsByClassName('e-chart-scroll-container e-content')[0] as HTMLElement;
859
+ if (!isNullOrUndefined(contentElement)) {
860
+ let contentWidth: number = contentElement['offsetWidth'];
861
+ let contentHeight: number = contentElement['offsetHeight'];
862
+ let scrollHeight: number = document.getElementsByClassName('e-chart-rows-container')[0]['offsetHeight'];
863
+ timeDiff = Math.abs(this.timelineStartDate.getTime() - endDate.getTime());
864
+ timeDiff = timeDiff / (1000 * 3600 * 24);
865
+ if (this.bottomTier === 'None') {
866
+ perDayWidth = this.getPerDayWidth(this.customTimelineSettings.timelineUnitSize, this.customTimelineSettings.topTier.count, this.topTier);
867
+ } else {
868
+ perDayWidth = this.getPerDayWidth(this.customTimelineSettings.timelineUnitSize, this.customTimelineSettings.bottomTier.count, this.bottomTier);
869
+ }
870
+ if (contentHeight < scrollHeight) {
871
+ totWidth = (perDayWidth * timeDiff) + 17;
872
+ } else {
873
+ totWidth = (perDayWidth * timeDiff);
874
+ }
875
+ if (contentWidth >= totWidth) {
876
+ let widthDiff: number = contentWidth - totWidth;
877
+ widthDiff = Math.round(widthDiff / perDayWidth);
878
+ endDate.setDate(endDate.getDate() + widthDiff);
879
+ this.parent.timelineModule.timelineEndDate = endDate;
880
+ if (resized) {
881
+ this.parent.updateProjectDates(this.timelineStartDate, this.timelineEndDate, this.parent.isTimelineRoundOff)
882
+ }
883
+ }
884
+ }
885
+ }
886
+ private getTimelineRoundOffEndDate(date: Date): Date {
887
+ const tierMode: string = this.topTier === 'None' ? this.bottomTier : this.topTier;
888
+ const endDate: Date = new Date(date.toString());
889
+ if (this.parent.isTimelineRoundOff) {
890
+ if (tierMode === 'Hour') {
891
+ endDate.setMinutes(60);
892
+ } else if (tierMode === 'Minutes') {
893
+ endDate.setSeconds(60);
894
+ } else {
895
+ endDate.setHours(24, 0, 0, 0);
896
+ }
897
+ }
898
+ if (this.isZooming || this.parent.isLoad) {
899
+ this.updateTimelineAfterZooming(endDate, false);
900
+ }
901
+ return endDate;
902
+ }
903
+ /**
904
+ *
905
+ * @param {Date} startDate .
906
+ * @param {number} count .
907
+ * @param {string} mode .
908
+ * @returns {number} .
909
+ * @private
910
+ */
911
+ public getIncrement(startDate: Date, count: number, mode: string): number {
912
+ let firstDay: Date = new Date(startDate.getTime());
913
+ let lastDay: Date = new Date(startDate.getTime());
914
+ let increment: number;
915
+ switch (mode) {
916
+ case 'Year':
917
+ firstDay = startDate;
918
+ lastDay = new Date(startDate.getFullYear() + (count - 1), 11, 31);
919
+ increment = (lastDay.getTime() - firstDay.getTime()) + (1000 * 60 * 60 * 24);
920
+ break;
921
+ case 'Month':
922
+ firstDay = startDate;
923
+ lastDay = new Date(startDate.getFullYear(), startDate.getMonth() + count, 1);
924
+ increment = lastDay.getTime() - firstDay.getTime();
925
+ break;
926
+ case 'Week':
927
+ {
928
+ const dayIndex: number = this.parent.timelineModule.customTimelineSettings.weekStartDay;
929
+ let dayIntervel: number = startDate.getDay() < dayIndex ? (dayIndex - startDate.getDay()) :
930
+ (6 - startDate.getDay()) + dayIndex;
931
+ count = dayIntervel > 0 ? count - 1 : 0;
932
+ lastDay.setHours(24, 0, 0, 0);
933
+ dayIntervel = startDate.getDay() < dayIndex ? dayIntervel > 0 ?
934
+ dayIntervel - 1 : dayIntervel : dayIntervel;
935
+ lastDay.setDate(lastDay.getDate() + (dayIntervel + (7 * count)));
936
+ increment = lastDay.getTime() - firstDay.getTime();
937
+ break;
938
+ }
939
+ case 'Day':
940
+ lastDay.setHours(24, 0, 0, 0);
941
+ increment = (lastDay.getTime() - firstDay.getTime()) + (1000 * 60 * 60 * 24 * (count - 1));
942
+ break;
943
+ case 'Hour':
944
+ lastDay.setMinutes(60);
945
+ lastDay.setSeconds(0);
946
+ increment = (lastDay.getTime() - firstDay.getTime()) + (1000 * 60 * 60 * (count - 1));
947
+ increment = this.checkDate(firstDay, lastDay, increment, count);
948
+ break;
949
+ case 'Minutes':
950
+ lastDay.setSeconds(60);
951
+ increment = (lastDay.getTime() - firstDay.getTime()) + (1000 * 60 * (count - 1));
952
+ break;
953
+ }
954
+ return increment;
955
+ }
956
+
957
+ private checkDate(firstDay: Date, lastDay: Date, increment: number, count: number): number {
958
+ var date = new Date(firstDay.getTime());
959
+ date.setTime(date.getTime() + increment);
960
+ if (((date.getTime() - lastDay.getTime()) / (1000 * 60 * 60)) != count && (firstDay.getTimezoneOffset() !== date.getTimezoneOffset())) {
961
+ var diffCount = count - (date.getTime() - lastDay.getTime()) / (1000 * 60 * 60);
962
+ if (!this.parent.isInDst(date)) {
963
+ increment += (1000 * 60 * 60 * diffCount);
964
+ }
965
+ else if (this.parent.isInDst(date)) {
966
+ increment -= (1000 * 60 * 60 * diffCount);
967
+ }
968
+ }
969
+ return increment;
970
+ }
971
+
972
+ /**
973
+ * Method to find header cell was weekend or not
974
+ *
975
+ * @param {string} mode .
976
+ * @param {string} tier .
977
+ * @param {Date} day .
978
+ * @returns {boolean} .
979
+ */
980
+ private isWeekendHeaderCell(mode: string, tier: string, day: Date): boolean {
981
+ return (mode === 'Day' || mode === 'Hour' || mode === 'Minutes') && (this.customTimelineSettings[tier].count === 1 ||
982
+ mode === 'Hour' || mode === 'Minutes') &&
983
+ this.parent.nonWorkingDayIndex.indexOf(day.getDay()) !== -1;
984
+ }
985
+
986
+ private calculateQuarterEndDate(date: Date) {
987
+ const month: number = date.getMonth();
988
+ if (month >= 0 && month <= 2) {
989
+ return new Date(date.getFullYear(), 3, 1);
990
+ } else if (month >= 3 && month <= 5) {
991
+ return new Date(date.getFullYear(), 6, 1);
992
+ } else if (month >= 6 && month <= 8) {
993
+ return new Date(date.getFullYear(), 9, 1);
994
+ } else {
995
+ return new Date(date.getFullYear() + 1, 0, 1);
996
+ }
997
+ }
998
+
999
+ /**
1000
+ * To construct template string.
1001
+ *
1002
+ * @param {Date} scheduleWeeks .
1003
+ * @param {string} mode .
1004
+ * @param {string} tier .
1005
+ * @param {boolean} isLast .
1006
+ * @param {number} count .
1007
+ * @param {TimelineFormat} timelineCell .
1008
+ * @returns {string} .
1009
+ * @private
1010
+ */
1011
+ /* eslint-disable-next-line */
1012
+ private getHeaterTemplateString(scheduleWeeks: Date, mode: string, tier: string, isLast: boolean, count?: number, timelineCell?: TimelineFormat, isFirstCell?: boolean): string {
1013
+ let parentTr: string = '';
1014
+ let td: string = '';
1015
+ const format: string = tier === 'topTier' ?
1016
+ this.parent.timelineModule.customTimelineSettings.topTier.format :
1017
+ this.parent.timelineModule.customTimelineSettings.bottomTier.format;
1018
+ const formatter: string | ITimelineFormatter = tier === 'topTier' ?
1019
+ this.parent.timelineModule.customTimelineSettings.topTier.formatter :
1020
+ this.parent.timelineModule.customTimelineSettings.bottomTier.formatter;
1021
+ let thWidth: number;
1022
+ const date: string = isNullOrUndefined(formatter) ?
1023
+ this.parent.globalize.formatDate(scheduleWeeks, { format: this.parent.getDateFormat() }) :
1024
+ this.customFormat(scheduleWeeks, format, tier, mode, formatter);
1025
+ thWidth = (this.getIncrement(scheduleWeeks, count, mode) / (1000 * 60 * 60 * 24)) * this.parent.perDayWidth;
1026
+ const cellWidth: number = thWidth;
1027
+ thWidth = isLast || isFirstCell ? isLast ? this.calculateWidthBetweenTwoDate(
1028
+ mode, scheduleWeeks, this.timelineRoundOffEndDate) : this.calculateWidthBetweenTwoDate(mode, scheduleWeeks, this.calculateQuarterEndDate(scheduleWeeks))
1029
+ : thWidth;
1030
+ const isWeekendCell: boolean = this.isWeekendHeaderCell(mode, tier, scheduleWeeks);
1031
+ const textClassName: string = tier === 'topTier' ? ' e-gantt-top-cell-text' : '';
1032
+ const value: string = (isNullOrUndefined(formatter) ? this.formatDateHeader(format, scheduleWeeks) :
1033
+ this.customFormat(scheduleWeeks, format, tier, mode, formatter));
1034
+ td += this.parent.timelineModule.isSingleTier ?
1035
+ '<th class="' + cls.timelineSingleHeaderCell + ' ' : '<th class="' + cls.timelineTopHeaderCell;
1036
+ td += isWeekendCell ? ' ' + cls.weekendHeaderCell : '';
1037
+ td += '" tabindex="-1" aria-label= "' + this.parent.localeObj.getConstant('timelineCell') + ' ' + date;
1038
+ td += '" style="width:' + thWidth + 'px;';
1039
+ td += isWeekendCell && this.customTimelineSettings.weekendBackground ?
1040
+ 'background-color:' + this.customTimelineSettings.weekendBackground + ';' : '';
1041
+ td += '"><div class="' + cls.timelineHeaderCellLabel + textClassName + '" style="width:' +
1042
+ (thWidth - 1) + 'px;' + (this.parent.timelineSettings.showTooltip ? '"title="' + date : '');
1043
+ td += '">' + value + '</div>';
1044
+ parentTr += td;
1045
+ parentTr += '</th>';
1046
+ if ((this.isSingleTier || tier === 'topTier') && !isLast) {
1047
+ this.totalTimelineWidth = this.totalTimelineWidth + thWidth;
1048
+ } else if ((this.isSingleTier || tier === 'topTier') && isLast) {
1049
+ this.totalTimelineWidth = (this.totalTimelineWidth - cellWidth) + thWidth;
1050
+ }
1051
+ // PDf export collection
1052
+ timelineCell.value = value;
1053
+ timelineCell.isWeekend = isWeekendCell;
1054
+ timelineCell.width = cellWidth;
1055
+ return parentTr;
1056
+ }
1057
+
1058
+ /**
1059
+ * To calculate last 'th' width.
1060
+ *
1061
+ * @param {string} mode .
1062
+ * @param {Date} scheduleWeeks .
1063
+ * @param {Date} endDate .
1064
+ * @returns {number} .
1065
+ * @private
1066
+ */
1067
+ private calculateWidthBetweenTwoDate(mode: string, scheduleWeeks: Date, endDate: Date): number {
1068
+ let timeDifference: number = (endDate.getTime() - scheduleWeeks.getTime());
1069
+ const balanceDay: number = (timeDifference / (1000 * 60 * 60 * 24));
1070
+ return balanceDay * this.parent.perDayWidth;
1071
+ }
1072
+
1073
+ /**
1074
+ * To calculate timeline width.
1075
+ *
1076
+ * @returns {void} .
1077
+ * @private
1078
+ */
1079
+ private timelineWidthCalculation(): void {
1080
+ const timelineUnitSize: number = this.customTimelineSettings.timelineUnitSize;
1081
+ const bottomTierCount: number = this.customTimelineSettings.bottomTier.count;
1082
+ const topTierCount: number = this.customTimelineSettings.topTier.count;
1083
+ this.bottomTierCellWidth = timelineUnitSize;
1084
+ if (this.bottomTier === 'None') {
1085
+ this.parent.perDayWidth = this.getPerDayWidth(timelineUnitSize, topTierCount, this.topTier);
1086
+ } else {
1087
+ this.parent.perDayWidth = this.getPerDayWidth(timelineUnitSize, bottomTierCount, this.bottomTier);
1088
+ }
1089
+ this.topTierCellWidth = this.bottomTier !== 'None' ? this.topTier === 'Week' ?
1090
+ this.parent.perDayWidth * 7 : this.topTier === 'Hour' ?
1091
+ this.parent.perDayWidth / 24 : this.topTier === 'Minutes' ?
1092
+ this.parent.perDayWidth / (24 * 60) : this.parent.perDayWidth : timelineUnitSize;
1093
+ this.topTierCellWidth = this.isSingleTier ? this.topTierCellWidth : this.topTierCellWidth * topTierCount;
1094
+ }
1095
+
1096
+ /**
1097
+ * To validate per day width.
1098
+ *
1099
+ * @param {number} timelineUnitSize .
1100
+ * @param {number} bottomTierCount .
1101
+ * @param {string} mode .
1102
+ * @returns {number} .
1103
+ * @private
1104
+ */
1105
+ private getPerDayWidth(timelineUnitSize: number, bottomTierCount: number, mode: string): number {
1106
+ let perDayWidth: number;
1107
+ switch (mode) {
1108
+ case 'Year':
1109
+ perDayWidth = (timelineUnitSize / bottomTierCount) / (12 * 28);
1110
+ break;
1111
+ case 'Month':
1112
+ perDayWidth = (timelineUnitSize / bottomTierCount) / 28;
1113
+ break;
1114
+ case 'Week':
1115
+ perDayWidth = (timelineUnitSize / bottomTierCount) / 7;
1116
+ break;
1117
+ case 'Day':
1118
+ perDayWidth = timelineUnitSize / bottomTierCount;
1119
+ break;
1120
+ case 'Hour':
1121
+ perDayWidth = (24 / bottomTierCount) * timelineUnitSize;
1122
+ break;
1123
+ case 'Minutes':
1124
+ perDayWidth = ((60 * 24) / bottomTierCount) * timelineUnitSize;
1125
+ break;
1126
+ }
1127
+ return perDayWidth;
1128
+ }
1129
+
1130
+ /**
1131
+ * To validate project start date and end date.
1132
+ *
1133
+ * @returns {void} .
1134
+ * @private
1135
+ */
1136
+ private roundOffDays(): void {
1137
+ let startDate: Date = this.parent.cloneProjectStartDate;
1138
+ let endDate: Date = this.parent.cloneProjectEndDate;
1139
+ const tierMode: string = this.topTier === 'None' ? this.bottomTier : this.topTier;
1140
+ if (this.parent.isTimelineRoundOff) {
1141
+ if (tierMode === 'Year') {
1142
+ startDate = new Date(startDate.getFullYear(), 0, 1);
1143
+ endDate = new Date(endDate.getFullYear(), 11, 31);
1144
+ } else if (tierMode === 'Month') {
1145
+ startDate = new Date(startDate.getFullYear(), startDate.getMonth(), 1);
1146
+ endDate = new Date(endDate.getFullYear(), endDate.getMonth() + 1, 0);
1147
+ } else if (tierMode === 'Week') {
1148
+ const dayIndex: number = this.parent.timelineModule.customTimelineSettings.weekStartDay;
1149
+ const roundOffStartDate: number = startDate.getDay() < dayIndex ?
1150
+ (startDate.getDate()) - (7 - dayIndex + startDate.getDay()) :
1151
+ (startDate.getDate()) - startDate.getDay() + dayIndex;
1152
+ startDate.setDate(roundOffStartDate);
1153
+ const first: number = endDate.getDate() - endDate.getDay();
1154
+ const last: number = first + 6 + dayIndex;
1155
+ endDate.setDate(last);
1156
+ }
1157
+ if (tierMode === 'Hour') {
1158
+ startDate.setMinutes(0);
1159
+ } else if (tierMode === 'Minutes') {
1160
+ startDate.setSeconds(0);
1161
+ } else {
1162
+ startDate.setHours(0, 0, 0, 0);
1163
+ }
1164
+ }
1165
+ this.timelineStartDate = startDate;
1166
+ this.timelineEndDate = endDate;
1167
+ this.timelineRoundOffEndDate = this.getTimelineRoundOffEndDate(this.timelineEndDate);
1168
+
1169
+ }
1170
+
1171
+ /**
1172
+ * To validate project start date and end date.
1173
+ *
1174
+ * @param {string} mode .
1175
+ * @param {string} span .
1176
+ * @param {Date} startDate .
1177
+ * @param {Date} endDate .
1178
+ * @returns {void} .
1179
+ * @private
1180
+ */
1181
+ public updateScheduleDatesByToolBar(mode: string, span: string, startDate: Date, endDate: Date): void {
1182
+ if (mode === 'Year') {
1183
+ if (span === 'prevTimeSpan') {
1184
+ if (startDate.getMonth() === 0) {
1185
+ startDate = new Date(startDate.getFullYear() - 1, 0, 1);
1186
+ } else {
1187
+ startDate = new Date(startDate.getFullYear(), 0, 1);
1188
+ }
1189
+ } else {
1190
+ if (endDate.getMonth() === 11) {
1191
+ endDate = new Date(endDate.getFullYear() + 1, 0, 1);
1192
+ } else {
1193
+ endDate = new Date(endDate.getFullYear(), 12, 1);
1194
+ }
1195
+ }
1196
+ }
1197
+ if (mode === 'Month') {
1198
+ if (span === 'prevTimeSpan') {
1199
+ if (startDate.getDate() === 1) {
1200
+ startDate = new Date(startDate.getFullYear(), startDate.getMonth() - 1, 1);
1201
+ } else {
1202
+ startDate = new Date(startDate.getFullYear(), startDate.getMonth(), 1);
1203
+ }
1204
+ } else {
1205
+ endDate = new Date(endDate.getFullYear(), endDate.getMonth() + 1, 1);
1206
+ }
1207
+ }
1208
+ if (mode === 'Week') {
1209
+ const dayIndex: number = this.parent.timelineModule.customTimelineSettings.weekStartDay;
1210
+ let dayIntervel: number;
1211
+ if (span === 'prevTimeSpan') {
1212
+ dayIntervel = startDate.getDay() < dayIndex ? 7 - (dayIndex - startDate.getDay()) :
1213
+ startDate.getDay() - dayIndex;
1214
+ startDate.setHours(0, 0, 0, 0);
1215
+ if (dayIntervel === 0) {
1216
+ startDate.setDate(startDate.getDate() - 7);
1217
+ } else {
1218
+ startDate.setDate(startDate.getDate() - dayIntervel);
1219
+ }
1220
+ } else {
1221
+ dayIntervel = endDate.getDay() < dayIndex ? (dayIndex - endDate.getDay()) :
1222
+ (7 - endDate.getDay()) + dayIndex;
1223
+ endDate.setHours(0, 0, 0, 0);
1224
+ if (dayIntervel === 0) {
1225
+ endDate.setDate(endDate.getDate() + 6);
1226
+ } else {
1227
+ endDate.setDate(endDate.getDate() + dayIntervel);
1228
+ }
1229
+ }
1230
+ }
1231
+ if (mode === 'Day') {
1232
+ if (span === 'prevTimeSpan') {
1233
+ if (startDate.getHours() === 0) {
1234
+ startDate.setTime(startDate.getTime() - (1000 * 60 * 60 * 24));
1235
+ } else {
1236
+ startDate.setHours(0);
1237
+ }
1238
+ } else {
1239
+ if (endDate.getHours() === 0) {
1240
+ endDate.setTime(endDate.getTime() + (1000 * 60 * 60 * 24));
1241
+ } else {
1242
+ endDate.setHours(24);
1243
+ }
1244
+ }
1245
+ }
1246
+ if (mode === 'Hour') {
1247
+ if (span === 'prevTimeSpan') {
1248
+ if (startDate.getMinutes() === 0) {
1249
+ startDate.setTime(startDate.getTime() - (1000 * 60 * 60));
1250
+ } else {
1251
+ startDate.setMinutes(0);
1252
+ }
1253
+ } else {
1254
+ if (endDate.getMinutes() === 0) {
1255
+ endDate.setTime(endDate.getTime() + (1000 * 60 * 60));
1256
+ } else {
1257
+ endDate.setMinutes(60);
1258
+ }
1259
+ }
1260
+ }
1261
+ if (mode === 'Minutes') {
1262
+ if (span === 'prevTimeSpan') {
1263
+ if (startDate.getSeconds() === 0) {
1264
+ startDate.setTime(startDate.getTime() - (1000 * 60));
1265
+ } else {
1266
+ startDate.setSeconds(0);
1267
+ }
1268
+ } else {
1269
+ if (endDate.getSeconds() === 0) {
1270
+ endDate.setTime(endDate.getTime() + (1000 * 60));
1271
+ } else {
1272
+ endDate.setSeconds(60);
1273
+ }
1274
+ }
1275
+ }
1276
+ this.parent.cloneProjectStartDate = startDate;
1277
+ this.parent.cloneProjectEndDate = endDate;
1278
+ }
1279
+ /**
1280
+ * To validate project start date and end date.
1281
+ *
1282
+ * @param {IGanttData[]} tempArray .
1283
+ * @param {string} action .
1284
+ * @returns {void} .
1285
+ * @private
1286
+ */
1287
+ public updateTimeLineOnEditing(tempArray: IGanttData[][], action: string): void {
1288
+ if (tempArray[0].length >= 1)
1289
+ {
1290
+ for (let i: number = 0; i < tempArray.length; i++)
1291
+ {
1292
+ /* eslint-disable-next-line */
1293
+ const temp: any = tempArray[i];
1294
+ const filteredStartDateRecord: IGanttData[] = temp.filter(
1295
+ (pdc: IGanttData) => { return !isNullOrUndefined(pdc.ganttProperties.startDate); });
1296
+ const filteredEndDateRecord: IGanttData[] = temp.filter(
1297
+ (pdc: IGanttData) => { return !isNullOrUndefined(pdc.ganttProperties.endDate); });
1298
+ let minStartDate: Date = filteredStartDateRecord.length > 0 ?
1299
+ new Date(DataUtil.aggregates.min(filteredStartDateRecord, 'ganttProperties.startDate')) : null;
1300
+ let maxEndDate: Date = filteredEndDateRecord.length > 0 ?
1301
+ new Date(DataUtil.aggregates.max(filteredEndDateRecord, 'ganttProperties.endDate')) : null;
1302
+ const validStartDate: Date = new Date(this.parent.dataOperation.checkStartDate(this.timelineStartDate).getTime());
1303
+ const validEndDate: Date = new Date(this.parent.dataOperation.checkEndDate(this.timelineEndDate).getTime());
1304
+ const maxStartLeft: number = isNullOrUndefined(minStartDate) ?
1305
+ null : this.parent.dataOperation.getTaskLeft(minStartDate, false);
1306
+ const maxEndLeft: number = isNullOrUndefined(maxEndDate) ?
1307
+ null : this.parent.dataOperation.getTaskLeft(maxEndDate, false);
1308
+ const validStartLeft: number = this.parent.dataOperation.getTaskLeft(validStartDate, false);
1309
+ const validEndLeft: number = this.parent.dataOperation.getTaskLeft(validEndDate, false);
1310
+ let isChanged: string;
1311
+ if (!isNullOrUndefined(maxStartLeft) && (maxStartLeft < this.bottomTierCellWidth || maxStartLeft <= validStartLeft)) {
1312
+ isChanged = 'prevTimeSpan';
1313
+ minStartDate = minStartDate > this.timelineStartDate ? this.timelineStartDate : minStartDate;
1314
+ } else {
1315
+ minStartDate = this.timelineStartDate;
1316
+ }
1317
+ if (!isNullOrUndefined(maxEndLeft) && (maxEndLeft >= (this.totalTimelineWidth - this.bottomTierCellWidth) ||
1318
+ maxEndLeft >= validEndLeft)) {
1319
+ isChanged = isChanged === 'prevTimeSpan' ? 'both' : 'nextTimeSpan';
1320
+ maxEndDate = maxEndDate < this.timelineEndDate ? this.timelineEndDate : maxEndDate;
1321
+ } else {
1322
+ maxEndDate = this.timelineEndDate;
1323
+ }
1324
+ if (isChanged) {
1325
+ this.performTimeSpanAction(isChanged, action, minStartDate, maxEndDate);
1326
+ } else if (!isNullOrUndefined(temp[0].ganttProperties.segments)) {
1327
+ this.parent.dataOperation.updateWidthLeft(temp[0]);
1328
+ }
1329
+ break;
1330
+ }
1331
+ }
1332
+ }
1333
+ /**
1334
+ * To validate project start date and end date on editing action
1335
+ *
1336
+ * @param {string} type .
1337
+ * @param {string} isFrom .
1338
+ * @param {Date} startDate .
1339
+ * @param {Date} endDate .
1340
+ * @param {string} mode .
1341
+ * @returns {void} .
1342
+ * @private
1343
+ */
1344
+ public performTimeSpanAction(type: string, isFrom: string, startDate: Date, endDate: Date, mode?: string): void {
1345
+ mode = !isNullOrUndefined(mode) ? mode : this.parent.timelineModule.topTier === 'None' ?
1346
+ this.parent.timelineModule.bottomTier : this.parent.timelineModule.topTier;
1347
+ const projectStartDate: Date = new Date(this.parent.cloneProjectStartDate.getTime());
1348
+ const projectEndDate: Date = new Date(this.parent.cloneProjectEndDate.getTime());
1349
+ if (isFrom !== 'publicMethod' && type === 'both') {
1350
+ this.updateScheduleDatesByToolBar(
1351
+ mode, 'prevTimeSpan', startDate, endDate);
1352
+ this.updateScheduleDatesByToolBar(
1353
+ mode, 'nextTimeSpan', new Date(this.parent.cloneProjectStartDate.getTime()), endDate);
1354
+ } else {
1355
+ this.updateScheduleDatesByToolBar(
1356
+ mode, type, startDate, endDate);
1357
+ }
1358
+ const args: ITimeSpanEventArgs = this.timeSpanActionEvent('actionBegin', type, isFrom);
1359
+ if (!args.cancel) {
1360
+ this.parent.updateProjectDates(args.projectStartDate, args.ProjectEndDate, args.isTimelineRoundOff, isFrom);
1361
+ if (type === 'prevTimeSpan' && isFrom === 'publicMethod') {
1362
+ this.parent.ganttChartModule.updateScrollLeft(0);
1363
+ } else if (type === 'nextTimeSpan' && isFrom === 'publicMethod') {
1364
+ this.parent.ganttChartModule.updateScrollLeft(this.parent.timelineModule.totalTimelineWidth);
1365
+ }
1366
+
1367
+ this.parent.timelineModule.timeSpanActionEvent('actionComplete', type, isFrom);
1368
+ } else {
1369
+ this.parent.cloneProjectStartDate = projectStartDate;
1370
+ this.parent.cloneProjectEndDate = projectEndDate;
1371
+ }
1372
+ }
1373
+
1374
+ /**
1375
+ * To validate project start date and end date.
1376
+ *
1377
+ * @param {string} eventType .
1378
+ * @param {string} requestType .
1379
+ * @param {string} isFrom .
1380
+ * @returns {void}
1381
+ * @private
1382
+ */
1383
+ public timeSpanActionEvent(eventType: string, requestType?: string, isFrom?: string): ITimeSpanEventArgs {
1384
+ const args: ITimeSpanEventArgs = {} as ITimeSpanEventArgs;
1385
+ args.projectStartDate = new Date(this.parent.cloneProjectStartDate.getTime());
1386
+ args.ProjectEndDate = new Date(this.parent.cloneProjectEndDate.getTime());
1387
+ args.requestType = isFrom === 'publicMethod' ? requestType : isFrom === 'beforeAdd' ?
1388
+ 'TimelineRefreshOnAdd' : isFrom === 'TaskbarEditing' ? 'TimelineRefreshOnEdit' : requestType;
1389
+ if (eventType === 'actionBegin') {
1390
+ args.isTimelineRoundOff = this.parent.isTimelineRoundOff;
1391
+ args.cancel = false;
1392
+ }
1393
+ args.action = 'TimescaleUpdate';
1394
+ this.parent.trigger(eventType, args);
1395
+ return args;
1396
+ }
1397
+ }