简介
笔者在开发一个基于Web的应用程序提供对人物和项目事件的管理。项目需要一个甘特图
控件可视化表示任务列表,笔者尝试寻找自由可用的解决方案(因为不想增加开销)。笔者找到了一些例子,不过并不满意。于是,决定创建一个自己的甘特图控件。此次是笔者工作的最初成果。这个SIcon的最初版本只做了几个小时,所以仍会有些问题。尽管如此,笔者还是希望与各位分享,希望能帮助大家。
SICon现在支持FireFox浏览器!
背景
掌握和使用这个示例需要Jscript和
CSS知识。
使用代码
代码并不是很复杂,所以我在这里将展示全部:
脚本代码
1. 1 /* --------- SICON GANTT CHART -----------------------------------------------------------
2. 2 * AUTHOR : Dathq - ICT Service Engineering Jsc, - [email]dathq@ise.com.vn[/email]
3. 3 * LICENSE : Free
4. 4 * DESCRIPTION : Create a new task item with these info
5. 5 * - from: start date (format: mm/dd/dddd)
6. 6 * - to: deadline of task (format: mm/dd/dddd)
7. 7 * - task: name of the task, what has to be solved (not includes ')
8. 8 * - resource: who have to solve this task (not includes ')
9. 9 * - progress: how is it going? (format: integer value from 0 to 100, not includes %)
10. 10 *----------------------------------------------------------------------------------------*/
11. 11 function Task(from, to, task, resource, progress)
12. 12 {
13. 13 var _from = new Date();
14. 14 var _to = new Date();
15. 15 var _task = task;
16. 16 var _resource = resource;
17. 17 var _progress = progress;
18. 18 var dvArr = from.split('/');
19. 19 _from.setFullYear(parseInt(dvArr[2], 10), parseInt(dvArr[0], 10) - 1, parseInt(dvArr[1], 10));
20. 20 dvArr = to.split('/');
21. 21 _to.setFullYear(parseInt(dvArr[2], 10), parseInt(dvArr[0], 10) - 1, parseInt(dvArr[1], 10));
22. 22
23. 23 this.getFrom = function(){ return _from};
24. 24 this.getTo = function(){ return _to};
25. 25 this.getTask = function(){ return _task};
26. 26 this.getResource = function(){ return _resource};
27. 27 this.getProgress = function(){ return _progress};
28. 28 }
29. 29
30. 30 function Gantt(gDiv)
31. 31 {
32. 32 var _GanttDiv = gDiv;
33. 33 var _taskList = new Array();
34. 34 this.AddTaskDetail = function(value)
35. 35 {
36. 36 _taskList.push(value);
37. 37
38. 38 }
39. 39 this.Draw = function()
40. 40 {
41. 41 var _offSet = 0;
42. 42 var _dateDiff = 0;
43. 43 var _currentDate = new Date();
44. 44 var _maxDate = new Date();
45. 45 var _minDate = new Date();
46. 46 var _dTemp = new Date();
47. 47 var _firstRowStr = "<table border=1 style='border-collapse:collapse'><tr><td rowspan='2' width='200px' style='width:200px;'><div class='GTaskTitle' style='width:200px;'>Task</div></td>";
48. 48 var _thirdRow = "";
49. 49 var _gStr = "";
50. 50 var _colSpan = 0;
51. 51 var counter = 0;
52. 52
53. 53 _currentDate.setFullYear(_currentDate.getFullYear(), _currentDate.getMonth(), _currentDate.getDate());
54. 54 if(_taskList.length > 0)
55. 55 {
56. 56 _maxDate.setFullYear(_taskList[0].getTo().getFullYear(), _taskList[0].getTo().getMonth(), _taskList[0].getTo().getDate());
57. 57 _minDate.setFullYear(_taskList[0].getFrom().getFullYear(), _taskList[0].getFrom().getMonth(), _taskList[0].getFrom().getDate());
58. 58 for(i = 0; i < _taskList.length; i++)
59. 59 {
60. 60 if(Date.parse(_taskList.getFrom()) < Date.parse(_minDate))
61. 61 _minDate.setFullYear(_taskList.getFrom().getFullYear(), _taskList.getFrom().getMonth(), _taskList.getFrom().getDate());
62. 62 if(Date.parse(_taskList.getTo()) > Date.parse(_maxDate))
63. 63 _maxDate.setFullYear(_taskList.getTo().getFullYear(), _taskList.getTo().getMonth(), _taskList.getTo().getDate());
64. 64 }
65. 65
66. 66 //---- Fix _maxDate value for better displaying-----
67. 67 // Add at least 5 days
68. 68
69. 69 if(_maxDate.getMonth() == 11) //December
70. 70 {
71. 71 if(_maxDate.getDay() + 5 > getDaysInMonth(_maxDate.getMonth() + 1, _maxDate.getFullYear()))
72. 72 _maxDate.setFullYear(_maxDate.getFullYear() + 1, 1, 5); //The fifth day of next month will be used
73. 73 else
74. 74 _maxDate.setFullYear(_maxDate.getFullYear(), _maxDate.getMonth(), _maxDate.getDate() + 5); //The fifth day of next month will be used
75. 75 }
76. 76 else
77. 77 {
78. 78 if(_maxDate.getDay() + 5 > getDaysInMonth(_maxDate.getMonth() + 1, _maxDate.getFullYear()))
79. 79 _maxDate.setFullYear(_maxDate.getFullYear(), _maxDate.getMonth() + 1, 5); //The fifth day of next month will be used
80. 80 else
81. 81 _maxDate.setFullYear(_maxDate.getFullYear(), _maxDate.getMonth(), _maxDate.getDate() + 5); //The fifth day of next month will be used
82. 82 }
83. 83
84. 84 //--------------------------------------------------
85. 85
86. 86 _gStr = "";
87. 87 _gStr += "</tr><tr>";
88. 88 _thirdRow = "<tr><td> </td>";
89. 89 _dTemp.setFullYear(_minDate.getFullYear(), _minDate.getMonth(), _minDate.getDate());
90. 90 while(Date.parse(_dTemp) <= Date.parse(_maxDate))
91. 91 {
92. 92 if(_dTemp.getDay() % 6 == 0) //Weekend
93. 93 {
94. 94 _gStr += "<td class='GWeekend'><div style='width:24px;'>" + _dTemp.getDate() + "</div></td>";
95. 95 if(Date.parse(_dTemp) == Date.parse(_currentDate))
96. 96 _thirdRow += "<td id='GC_" + (counter++) + "' class='GToDay' style='height:" + (_taskList.length * 21) + "'> </td>";
97. 97 else
98. 98 _thirdRow += "<td id='GC_" + (counter++) + "' class='GWeekend' style='height:" + (_taskList.length * 21) + "'> </td>";
99. 99 }
100. 100 else
101. 101 {
102. 102 _gStr += "<td class='GDay'><div style='width:24px;'>" + _dTemp.getDate() + "</div></td>";
103. 103 if(Date.parse(_dTemp) == Date.parse(_currentDate))
104. 104 _thirdRow += "<td id='GC_" + (counter++) + "' class='GToDay' style='height:" + (_taskList.length * 21) + "'> </td>";
105. 105 else
106. 106 _thirdRow += "<td id='GC_" + (counter++) + "' class='GDay'> </td>";
107. 107 }
108. 108 if(_dTemp.getDate() < getDaysInMonth(_dTemp.getMonth() + 1, _dTemp.getFullYear()))
109. 109 {
110. 110 if(Date.parse(_dTemp) == Date.parse(_maxDate))
111. 111 {
112. 112 _firstRowStr += "<td class='GMonth' colspan='" + (_colSpan + 1) + "'>T" + (_dTemp.getMonth() + 1) + "/" + _dTemp.getFullYear() + "</td>";
113. 113 }
114. 114 _dTemp.setDate(_dTemp.getDate() + 1);
115. 115 _colSpan++;
116. 116 }
117. 117 else
118. 118 {
119. 119 _firstRowStr += "<td class='GMonth' colspan='" + (_colSpan + 1) + "'>T" + (_dTemp.getMonth() + 1) + "/" + _dTemp.getFullYear() + "</td>";
120. 120 _colSpan = 0;
121. 121 if(_dTemp.getMonth() == 11) //December
122. 122 {
123. 123 _dTemp.setFullYear(_dTemp.getFullYear() + 1, 0, 1);
124. 124 }
125. 125 else
126. 126 {
127. 127 _dTemp.setFullYear(_dTemp.getFullYear(), _dTemp.getMonth() + 1, 1);
128. 128 }
129. 129 }
130. 130 }
131. 131 _thirdRow += "</tr>";
132. 132 _gStr += "</tr>" + _thirdRow;
133. 133 _gStr += "</table>";
134. 134 _gStr = _firstRowStr + _gStr;
135. 135 for(i = 0; i < _taskList.length; i++)
136. 136 {
137. 137 _offSet = (Date.parse(_taskList.getFrom()) - Date.parse(_minDate)) / (24 * 60 * 60 * 1000);
138. 138 _dateDiff = (Date.parse(_taskList.getTo()) - Date.parse(_taskList.getFrom())) / (24 * 60 * 60 * 1000) + 1;
139. 139 _gStr += "<div style='position:absolute; top:" + (20 * (i + 2)) + "; left:" + (_offSet * 27 + 204) + "; width:" + (27 * _dateDiff - 1 + 100) + "'><div title='" + _taskList.getTask() + "' class='GTask' style='float:left; width:" + (27 * _dateDiff - 1) + "px;'>" + getProgressDiv(_taskList.getProgress()) + "</div><div style='float:left; padding-left:3'>" + _taskList.getResource() + "</div></div>";
140. 140 _gStr += "<div style='position:absolute; top:" + (20 * (i + 2) + 1) + "; left:5px'>" + _taskList.getTask() + "</div>";
141. 141 }
142. 142 _GanttDiv.innerHTML = _gStr;
143. 143 }
144. 144 }
145. 145 }
146. 146
147. 147 function getProgressDiv(progress)
148. 148 {
149. 149 return "<div class='GProgress' style='width:" + progress + "%; overflow:hidden'></div>"
150. 150 }
151. 151 // GET NUMBER OF DAYS IN MONTH
152. 152 function getDaysInMonth(month, year)
153. 153 {
154. 154
155. 155 var days;
156. 156 switch(month)
157. 157 {
158. 158 case 1:
159. 159 case 3:
160. 160 case 5:
161. 161 case 7:
162. 162 case 8:
163. 163 case 10:
164. 164 case 12:
165. 165 days = 31;
166. 166 break;
167. 167 case 4:
168. 168 case 6:
169. 169 case 9:
170. 170 case 11:
171. 171 days = 30;
172. 172 break;
173. 173 case 2:
174. 174 if (((year% 4)==0) && ((year% 100)!=0) || ((year% 400)==0))
175. 175 days = 29;
176. 176 else
177. 177 days = 28;
178. 178 break;
179. 179 }
180. 180 return (days);
181. 181 }
182. 182 /*----- END OF MY CODE FOR Gantt CHART GENERATOR -----*/
复制代码
如何使用这段脚本
在你的HTML, ASCX, ASPX或PHP文档的Body部分,把下面几行代码拷贝到你想表示甘特图的地方。
1. 1 <body>
2. 2 <h3>Diagram</h3>
3. 3 <div style="position:relative" class="Gantt" id="GanttChart"></div>
4. 4 </body>
5. 5 <script>
6. 6 var g = new Gantt(document.all.GanttChart);
7. 7 g.AddTaskDetail(new Task('2/11/2008', '2/12/2008',
8. 8 '<b>Sample task 1 1</b>', 'Dathq', 50));
9. 9 g.AddTaskDetail(new Task('2/16/2008', '2/19/2008',
10. 10 ' Sample task 1.1', 'Dathq, Thanhdd', 30));
11. 11 g.AddTaskDetail(new Task('2/12/2008', '3/4/2008', 'Sample task 2', 'Hanhnd', 60));
12. 12 g.AddTaskDetail(new Task('2/11/2008', '2/16/2008', 'Sample task 3', 'Dathq', 50));
13. 13
14. 14 g.Draw();
15. 15 </script>
复制代码
使用var g = new Gantt(document.all.GanttChart);语句指定你要显示的甘特图到命名为"GanttChart"的DIV元素(你可以在body中看到它)。
g.AddTaskDetail()方法添加任务到任务列表。你可以使用AJAX或任何你喜欢的方式来生成这些命令以添加任务的集合。
使用g.Draw()来渲染基于追加到甘特图对象的任务列表的甘特图。
如何改变组件外观
这里笔者定义了一些类用来自定义甘特图的样式,为此提供了全部代码。你可以定义更多的类并且更轻易地改变甘特图控件的外观。
通过改变样式表,并且在代码中添加属性到任务对象,你可以为你自己创建更加智能的甘特图。例如:为任务条设置不同的颜色,漂亮的背景图片,更好的图标提示等等。
样式表
1. 1 /*----- SICON GANTT CHART STYLE CLASSES --------------------------
2. 2 * DESCRIPTION : Theses class is required for SIcon Gantt Chart
3. 3 * NOTE : Should change the color, the text style only
4. 4 *----------------------------------------------------------------*/
5. 5 .Gantt
6. 6 {
7. 7 font-family:tahoma, arial, verdana;
8. 8 font-size:11px;
9. 9 }
10. 10
11. 11 .GTaskTitle
12. 12 {
13. 13 font-family:tahoma, arial, verdana;
14. 14 font-size:11px;
15. 15 font-weight:bold;
16. 16 }
17. 17
18. 18 .GMonth
19. 19 {
20. 20 padding-left:5px;
21. 21 font-family:tahoma, arial, verdana;
22. 22 font-size:11px;
23. 23 font-weight:bold;
24. 24 }
25. 25
26. 26 .GToday
27. 27 {
28. 28 background-color: #FDFDE0;
29. 29 }
30. 30
31. 31 .GWeekend
32. 32 {
33. 33 font-family:tahoma, arial, verdana;
34. 34 font-size:11px;
35. 35 background-color:#F5F5F5;
36. 36 text-align:center;
37. 37 }
38. 38
39. 39 .GDay
40. 40 {
41. 41 font-family:tahoma, arial, verdana;
42. 42 font-size:11px;
43. 43 text-align:center;
44. 44 }
45. 45
46. 46 .GTask
47. 47 {
48. 48 border-top:1px solid #CACACA;
49. 49 border-bottom:1px solid #CACACA;
50. 50 height:14px;
51. 51 background-color:yellow;
52. 52 }
53. 53
54. 54 .GProgress
55. 55 {
56. 56 background-color:black;
57. 57 height:2px;
58. 58 overflow: hidden;
59. 59 margin-top:5px;
60. 60 }
复制代码
图表
Code
1. 1 var g = new Gantt(document.all.GanttChart);
2. 2 g.AddTaskDetail(new Task('2/11/2008', '2/19/2008', '<b>Sample task 1 1</b>', 'Dathq', 50));
3. 3 g.AddTaskDetail(new Task('2/16/2008', '2/19/2008', ' Sample task 1.1', 'Dathq, Thanhdo', 30));
4. 4 g.AddTaskDetail(new Task('2/12/2008', '3/2/2008', 'Sample task 2', 'Hanhnd', 60));
5. 5 g.AddTaskDetail(new Task('2/11/2008', '2/16/2008', '<i>Sample task 3<i>', 'Dathq', 50));
6. 6 g.AddTaskDetail(new Task('2/11/2008', '2/19/2008', '<b>Sample task 1 1</b>', 'Dathq', 50));
7. 7 g.AddTaskDetail(new Task('2/16/2008', '2/19/2008', ' Sample task 1.1', 'Dathq, Thanhdo', 30));
8. 8 g.AddTaskDetail(new Task('2/12/2008', '3/2/2008', 'Sample task 2', 'Hanhnd', 60));
9. 9 g.AddTaskDetail(new Task('2/11/2008', '2/16/2008', '<i>Sample task 3<i>', 'Dathq', 50));
10. 10 g.AddTaskDetail(new Task('2/11/2008', '2/19/2008', '<b>Sample task 1 1</b>', 'Dathq', 50));
11. 11 g.AddTaskDetail(new Task('2/16/2008', '2/19/2008', ' Sample task 1.1', 'Dathq, Thanhdo', 30));
12. 12 g.AddTaskDetail(new Task('2/12/2008', '3/2/2008', 'Sample task 2', 'Hanhnd', 60));
13. 13 g.AddTaskDetail(new Task('2/11/2008', '2/16/2008', '<i>Sample task 3<i>', 'Dathq', 50));
14. 14
15. 15 g.AddTaskDetail(new Task('2/11/2008', '2/19/2008', '<b>Sample task 1 1</b>', 'Dathq', 50));
16. 16 g.AddTaskDetail(new Task('2/16/2008', '2/19/2008', ' Sample task 1.1', 'Dathq, Thanhdo', 30));
17. 17 g.AddTaskDetail(new Task('2/12/2008', '3/2/2008', 'Sample task 2', 'Hanhnd', 60));
18. 18 g.AddTaskDetail(new Task('5/11/2008', '5/16/2008', '<i>Sample task 3<i>', 'Dathq', 50));
19. 19
20. 20 g.Draw();
复制代码
兴趣点
你会先注意到图标运行起来速度很快。
SIcon甘特图是通过Javascript创建的,这意味着你可以在众多的Web开发环境中使用它。我比较喜欢ASP.NET,所以我会把此控件和ASP.NET一起使用。另外,你可以使用AJAX创建更酷的应用。你可以自定义CSS类得到更好看的甘特图。我将试图添加链接到任务用来描述他们的关系,并将显示一个父任务,就像我们在MS Project中看到的一样。
甘特图通过HTML显示,因为它使用的是轻量级结构,所以你可以添加更多的功能到图表。例如,提示、链接、图片等,在JScript中使用一些基本的变化就可以获得。