@syncfusion/ej2-gantt 19.4.55 → 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 (212) hide show
  1. package/CHANGELOG.md +1072 -1047
  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 +341 -240
  6. package/dist/es6/ej2-gantt.es2015.js.map +1 -1
  7. package/dist/es6/ej2-gantt.es5.js +713 -598
  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 +36 -9
  91. package/src/gantt/actions/rowdragdrop.js +37 -15
  92. package/src/gantt/actions/selection.js +3 -2
  93. package/src/gantt/actions/taskbar-edit.js +24 -24
  94. package/src/gantt/base/date-processor.js +0 -1
  95. package/src/gantt/base/gantt-chart.js +36 -5
  96. package/src/gantt/base/gantt-model.d.ts +779 -779
  97. package/src/gantt/base/gantt.d.ts +27 -27
  98. package/src/gantt/base/gantt.js +35 -76
  99. package/src/gantt/base/splitter.js +1 -0
  100. package/src/gantt/base/task-processor.js +13 -13
  101. package/src/gantt/base/tree-grid.js +3 -1
  102. package/src/gantt/export/pdf-base/treegrid-layouter.js +13 -13
  103. package/src/gantt/export/pdf-connector-line.js +11 -11
  104. package/src/gantt/export/pdf-gantt.js +24 -24
  105. package/src/gantt/export/pdf-taskbar.js +11 -11
  106. package/src/gantt/export/pdf-treegrid.js +13 -13
  107. package/src/gantt/models/add-dialog-field-settings-model.d.ts +21 -21
  108. package/src/gantt/models/add-dialog-field-settings.js +19 -19
  109. package/src/gantt/models/day-working-time-model.d.ts +11 -11
  110. package/src/gantt/models/day-working-time.js +19 -19
  111. package/src/gantt/models/edit-dialog-field-settings-model.d.ts +21 -21
  112. package/src/gantt/models/edit-dialog-field-settings.js +19 -19
  113. package/src/gantt/models/edit-settings-model.d.ts +50 -50
  114. package/src/gantt/models/edit-settings.js +19 -19
  115. package/src/gantt/models/event-marker-model.d.ts +16 -16
  116. package/src/gantt/models/event-marker.js +19 -19
  117. package/src/gantt/models/filter-settings-model.d.ts +34 -34
  118. package/src/gantt/models/filter-settings.js +19 -19
  119. package/src/gantt/models/holiday-model.d.ts +21 -21
  120. package/src/gantt/models/holiday.js +19 -19
  121. package/src/gantt/models/label-settings-model.d.ts +16 -16
  122. package/src/gantt/models/label-settings.js +19 -19
  123. package/src/gantt/models/resource-fields-model.d.ts +21 -21
  124. package/src/gantt/models/resource-fields.js +19 -19
  125. package/src/gantt/models/search-settings-model.d.ts +56 -56
  126. package/src/gantt/models/search-settings.js +19 -19
  127. package/src/gantt/models/selection-settings-model.d.ts +35 -35
  128. package/src/gantt/models/selection-settings.js +19 -19
  129. package/src/gantt/models/sort-settings-model.d.ts +24 -24
  130. package/src/gantt/models/sort-settings.js +19 -19
  131. package/src/gantt/models/splitter-settings-model.d.ts +30 -30
  132. package/src/gantt/models/splitter-settings.js +19 -19
  133. package/src/gantt/models/task-fields-model.d.ts +110 -110
  134. package/src/gantt/models/task-fields.js +19 -19
  135. package/src/gantt/models/timeline-settings-model.d.ts +71 -71
  136. package/src/gantt/models/timeline-settings.js +19 -19
  137. package/src/gantt/models/tooltip-settings-model.d.ts +26 -26
  138. package/src/gantt/models/tooltip-settings.js +19 -19
  139. package/src/gantt/renderer/chart-rows.js +49 -37
  140. package/src/gantt/renderer/connector-line.js +22 -18
  141. package/src/gantt/renderer/event-marker.js +1 -0
  142. package/src/gantt/renderer/nonworking-day.js +13 -6
  143. package/src/gantt/renderer/timeline.d.ts +1 -0
  144. package/src/gantt/renderer/timeline.js +51 -12
  145. package/src/gantt/renderer/tooltip.js +11 -3
  146. package/styles/bootstrap-dark.css +442 -427
  147. package/styles/bootstrap.css +442 -433
  148. package/styles/bootstrap4.css +454 -479
  149. package/styles/bootstrap5-dark.css +457 -433
  150. package/styles/bootstrap5.css +457 -433
  151. package/styles/fabric-dark.css +438 -421
  152. package/styles/fabric.css +445 -428
  153. package/styles/fluent-dark.css +1938 -0
  154. package/styles/fluent-dark.scss +1 -0
  155. package/styles/fluent.css +1938 -0
  156. package/styles/fluent.scss +1 -0
  157. package/styles/gantt/_all.scss +2 -2
  158. package/styles/gantt/_bootstrap-dark-definition.scss +210 -156
  159. package/styles/gantt/_bootstrap-definition.scss +211 -157
  160. package/styles/gantt/_bootstrap4-definition.scss +213 -158
  161. package/styles/gantt/_bootstrap5-definition.scss +215 -162
  162. package/styles/gantt/_fabric-dark-definition.scss +211 -157
  163. package/styles/gantt/_fabric-definition.scss +211 -157
  164. package/styles/gantt/_fluent-dark-definition.scss +1 -0
  165. package/styles/gantt/_fluent-definition.scss +215 -162
  166. package/styles/gantt/_fusionnew-definition.scss +214 -0
  167. package/styles/gantt/_highcontrast-definition.scss +211 -157
  168. package/styles/gantt/_highcontrast-light-definition.scss +211 -157
  169. package/styles/gantt/_layout.scss +1446 -1027
  170. package/styles/gantt/_material-dark-definition.scss +212 -157
  171. package/styles/gantt/_material-definition.scss +212 -157
  172. package/styles/gantt/_material3-definition.scss +215 -0
  173. package/styles/gantt/_tailwind-definition.scss +215 -161
  174. package/styles/gantt/_theme.scss +702 -668
  175. package/styles/gantt/bootstrap-dark.css +442 -427
  176. package/styles/gantt/bootstrap.css +442 -433
  177. package/styles/gantt/bootstrap4.css +454 -479
  178. package/styles/gantt/bootstrap5-dark.css +457 -433
  179. package/styles/gantt/bootstrap5.css +457 -433
  180. package/styles/gantt/fabric-dark.css +438 -421
  181. package/styles/gantt/fabric.css +445 -428
  182. package/styles/gantt/fluent-dark.css +1938 -0
  183. package/styles/gantt/fluent-dark.scss +22 -0
  184. package/styles/gantt/fluent.css +1938 -0
  185. package/styles/gantt/fluent.scss +22 -0
  186. package/styles/gantt/highcontrast-light.css +405 -405
  187. package/styles/gantt/highcontrast.css +444 -456
  188. package/styles/gantt/icons/_bootstrap-dark.scss +124 -113
  189. package/styles/gantt/icons/_bootstrap.scss +124 -113
  190. package/styles/gantt/icons/_bootstrap4.scss +124 -113
  191. package/styles/gantt/icons/_bootstrap5.scss +124 -112
  192. package/styles/gantt/icons/_fabric-dark.scss +124 -112
  193. package/styles/gantt/icons/_fabric.scss +124 -112
  194. package/styles/gantt/icons/_fluent-dark.scss +1 -0
  195. package/styles/gantt/icons/_fluent.scss +124 -112
  196. package/styles/gantt/icons/_fusionnew.scss +120 -0
  197. package/styles/gantt/icons/_highcontrast.scss +124 -112
  198. package/styles/gantt/icons/_material-dark.scss +124 -112
  199. package/styles/gantt/icons/_material.scss +124 -112
  200. package/styles/gantt/icons/_material3.scss +124 -0
  201. package/styles/gantt/icons/_tailwind-dark.scss +124 -113
  202. package/styles/gantt/icons/_tailwind.scss +124 -113
  203. package/styles/gantt/material-dark.css +446 -417
  204. package/styles/gantt/material.css +445 -419
  205. package/styles/gantt/tailwind-dark.css +452 -482
  206. package/styles/gantt/tailwind.css +449 -479
  207. package/styles/highcontrast-light.css +405 -405
  208. package/styles/highcontrast.css +444 -456
  209. package/styles/material-dark.css +446 -417
  210. package/styles/material.css +445 -419
  211. package/styles/tailwind-dark.css +452 -482
  212. 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
+ }