GanttResourceItem.js 17 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461
  1. // wrapped by build app
  2. define("dojox/gantt/GanttResourceItem", ["dijit","dojo","dojox","dojo/require!dojo/date/locale"], function(dijit,dojo,dojox){
  3. dojo.provide("dojox.gantt.GanttResourceItem");
  4. dojo.require("dojo.date.locale");
  5. dojo.declare("dojox.gantt.GanttResourceItem", null, {
  6. constructor: function(ganttchart){
  7. this.ganttChart = ganttchart;
  8. this.ownerItem = [];
  9. this.ownerNameItem = [];
  10. this.ownerTaskNodeMapping = {};
  11. this.ownerTaskNodeMapping_time = {};
  12. this.resourceInfo = {};
  13. this.ownerTimeConsume = {};
  14. },
  15. clearAll: function(){
  16. this.clearData();
  17. this.clearItems();
  18. },
  19. clearData: function(){
  20. this.ownerItem = [];
  21. this.ownerNameItem = [];
  22. this.ownerTaskNodeMapping = {};
  23. this.ownerTaskNodeMapping_time = {};
  24. this.resourceInfo = {};
  25. this.ownerTimeConsume = {};
  26. },
  27. clearItems: function(){
  28. if(this.content.firstChild){
  29. dojo.destroy(this.content.firstChild);
  30. }
  31. },
  32. buildResource: function(){
  33. var resourceInfo = {};
  34. dojo.forEach(this.ganttChart.arrProjects, function(project){
  35. dojo.forEach(project.arrTasks, function(task){
  36. task.buildResourceInfo(resourceInfo);
  37. }, this);
  38. }, this);
  39. return resourceInfo;
  40. },
  41. buildOwnerTimeConsume: function(){
  42. var ownerTimeConsume = {};
  43. for(var owner in this.resourceInfo){
  44. var tasks = this.resourceInfo[owner];
  45. //combine time zone (startTime - this.startDate) / (60 * 60 * 1000) * this.pixelsPerHour;
  46. var timeZoom = {};
  47. for(var i = 0; i < tasks.length; i++){
  48. var task = tasks[i];
  49. var startTime = task.taskItem.startTime.getTime(), dur = task.taskItem.duration * 24 * 60 * 60 * 1000 / this.ganttChart.hsPerDay;
  50. timeZoom.min = timeZoom.min ? Math.min(timeZoom.min, startTime) : startTime;
  51. timeZoom.max = timeZoom.max ? Math.max(timeZoom.max, (startTime + dur)) : (startTime + dur);
  52. }
  53. timeZoom.dur = (timeZoom.max - timeZoom.min) * this.ganttChart.hsPerDay / (24 * 60 * 60 * 1000);
  54. timeZoom.min = new Date(timeZoom.min);
  55. timeZoom.max = new Date(timeZoom.max);
  56. ownerTimeConsume[owner] = timeZoom;
  57. }
  58. return ownerTimeConsume;
  59. },
  60. refresh: function(){
  61. this.ownerTimeConsume = this.buildOwnerTimeConsume();
  62. //resize outer div
  63. this.contentData.firstChild.style.width = Math.max(1200, this.ganttChart.pixelsPerDay * this.ganttChart.totalDays) + "px";
  64. for(var owner in this.resourceInfo){
  65. this.refreshOwnerEntry(owner);
  66. }
  67. },
  68. reConstruct: function(){
  69. this.clearAll();
  70. this.resourceInfo = this.buildResource();
  71. this.ownerTimeConsume = this.buildOwnerTimeConsume();
  72. this.tableControl = dojo.create("table", {
  73. cellPadding: "0",
  74. cellSpacing: "0",
  75. className: "ganttResourceTableControl"
  76. });
  77. var newRowTblControl = this.tableControl.insertRow(this.tableControl.rows.length);
  78. //Add to content Table
  79. this.contentHeight = this.content.offsetHeight;
  80. this.contentWidth = this.content.offsetWidth;
  81. this.content.appendChild(this.tableControl);
  82. //Creation panel contentData
  83. this.contentData = dojo.create("div", {className: "ganttResourceContentDataContainer"});
  84. this.contentData.appendChild(this.createPanelOwners());
  85. dojo.style(this.contentData, "height", (this.contentHeight - this.ganttChart.panelTimeHeight) + "px");
  86. //Creation panel of names
  87. var newCellTblControl = dojo.create("td", {
  88. vAlign: "top"
  89. });
  90. this.panelNames = dojo.create("div", {className: "ganttResourcePanelNames"});
  91. this.panelNames.appendChild(this.createPanelNamesOwners());
  92. newCellTblControl.appendChild(this.panelNames);
  93. newRowTblControl.appendChild(newCellTblControl);
  94. //add to control contentData and contentDataTime
  95. newCellTblControl = dojo.create("td", {
  96. vAlign: "top"
  97. });
  98. var divCell = dojo.create("div", {className: "ganttResourceDivCell"});
  99. divCell.appendChild(this.contentData);
  100. newCellTblControl.appendChild(divCell);
  101. newRowTblControl.appendChild(newCellTblControl);
  102. //Show panel of names
  103. dojo.style(this.panelNames, {
  104. height: (this.contentHeight - this.ganttChart.panelTimeHeight - this.ganttChart.scrollBarWidth) + "px",
  105. width: this.ganttChart.maxWidthPanelNames + "px"
  106. });
  107. this.contentData.style.width = (this.contentWidth - this.ganttChart.maxWidthPanelNames) + "px";
  108. this.contentData.firstChild.style.width = this.ganttChart.pixelsPerDay * (this.ganttChart.panelTime.firstChild.firstChild.rows[3].cells.length) + "px";
  109. var _this = this;
  110. this.contentData.onscroll = function(){
  111. if(_this.panelNames){
  112. _this.panelNames.scrollTop = this.scrollTop;
  113. }
  114. }
  115. this.contentData.scrollLeft = this.ganttChart.contentData.scrollLeft;
  116. for(var owner in this.resourceInfo){
  117. this.createOwnerEntry(owner);
  118. }
  119. this.postAdjustment();
  120. },
  121. create: function(){
  122. var resourceHeader = dojo.create("div", {
  123. innerHTML: "Resource Chart:",
  124. className: "ganttResourceHeader"
  125. }, this.ganttChart.content, "after");
  126. dojo.style(resourceHeader, "width", this.ganttChart.contentWidth + "px");
  127. var content = dojo.create("div", {className: "ganttResourceContent"}, resourceHeader, "after");
  128. dojo.style(content, {
  129. width: this.ganttChart.contentWidth + "px",
  130. height: (this.ganttChart.resourceChartHeight || (this.ganttChart.contentHeight * 0.8)) + "px"
  131. });
  132. this.content = content || this.content;
  133. //create Table
  134. this.reConstruct();
  135. },
  136. postAdjustment: function(){
  137. //contentData height
  138. this.contentData.firstChild.style.height = (this.ownerItem.length * 23) + "px";
  139. this.panelNames.firstChild.style.height = (this.ownerItem.length * 23) + "px";
  140. },
  141. refreshOwnerEntry: function(owner){
  142. this.refreshOwnerItem(owner);
  143. dojo.forEach(this.resourceInfo[owner], function(task, i){
  144. var item = this.ownerTaskNodeMapping[owner].tasks[i][0];
  145. this.refreshDetailedTaskEntry(owner, item, task);
  146. }, this);
  147. },
  148. createOwnerEntry: function(owner){
  149. var containerOwner = this.contentData.firstChild;
  150. var previousOwner = this.ownerItem[this.ownerItem.length - 1];
  151. this.ownerTaskNodeMapping[owner] = {};
  152. this.ownerTaskNodeMapping[owner][owner] = [];
  153. //create nodes
  154. var pos = dojo.position(containerOwner);
  155. //creation arrTasks
  156. var posY = (previousOwner ? parseInt(previousOwner.style.top) : (6 - 23)) + this.ganttChart.heightTaskItem + 11;
  157. //creation task item
  158. var oItem = this.createOwnerItem(owner, posY);
  159. containerOwner.appendChild(oItem);
  160. this.ownerItem.push(oItem);
  161. this.ownerTaskNodeMapping[owner][owner].push(oItem);
  162. if(this.panelNames){
  163. var oNameItem = this.createOwnerNameItem(owner, posY);
  164. this.panelNames.firstChild.appendChild(oNameItem);
  165. this.ownerNameItem.push(oNameItem);
  166. this.ownerTaskNodeMapping[owner][owner].push(oNameItem);
  167. }
  168. var currentOwnerNode = this.ownerItem[this.ownerNameItem.length - 1],
  169. currentOwnerNameNode = this.ownerNameItem[this.ownerNameItem.length - 1];
  170. //adjust nodes
  171. if(this.panelNames){
  172. this.checkWidthTaskNameItem(currentOwnerNameNode);
  173. var treeImg = this.createTreeImg(currentOwnerNameNode);
  174. this.panelNames.firstChild.appendChild(treeImg);
  175. this.ownerTaskNodeMapping[owner][owner].push(treeImg);
  176. }
  177. this.ownerTaskNodeMapping[owner]["taskCount"] = this.resourceInfo[owner].length;
  178. this.ownerTaskNodeMapping[owner]["isOpen"] = false;
  179. this.ownerTaskNodeMapping[owner]["tasks"] = [];
  180. dojo.forEach(this.resourceInfo[owner], function(task){
  181. this.ownerTaskNodeMapping[owner]["tasks"].push(this.createDetailedTaskEntry(owner, currentOwnerNameNode, task));
  182. }, this);
  183. return this;
  184. },
  185. createOwnerNameItem: function(owner, posY){
  186. var ownerName = dojo.create("div", {
  187. id: owner,
  188. title: owner,
  189. innerHTML: owner,
  190. className: "ganttOwnerNameItem"
  191. });
  192. dojo.style(ownerName, "top", posY + "px");
  193. return ownerName;
  194. },
  195. refreshOwnerItem: function(owner){
  196. var item = this.ownerTaskNodeMapping[owner][owner][0],
  197. start = this.ownerTimeConsume[owner].min, end = this.ownerTimeConsume[owner].max, dur = this.ownerTimeConsume[owner].dur,
  198. posX = this.ganttChart.getPosOnDate(start); // should be task start date
  199. item.style.left = posX + "px";
  200. item.style.width = dur * this.ganttChart.pixelsPerWorkHour + "px";
  201. dojo.forEach(this.resourceInfo[owner], function(task, i){
  202. var tposX = this.ganttChart.getPosOnDate(task.taskItem.startTime); // should be task start date
  203. dojo.style(item.childNodes[i], {
  204. left: (tposX - posX) + "px",
  205. width: task.taskItem.duration * this.ganttChart.pixelsPerWorkHour + "px"
  206. });
  207. }, this);
  208. },
  209. createOwnerItem: function(owner, posY){
  210. var start = this.ownerTimeConsume[owner].min, end = this.ownerTimeConsume[owner].max, dur = this.ownerTimeConsume[owner].dur;
  211. var posX = this.ganttChart.getPosOnDate(start); // should be task start date
  212. var ownerControl = dojo.create("div", {
  213. id: owner,
  214. owner: true,
  215. className: "ganttOwnerBar"
  216. });
  217. dojo.style(ownerControl, {
  218. left: posX + "px",
  219. top: posY + "px",
  220. width: dur * this.ganttChart.pixelsPerWorkHour + "px",
  221. height: this.ganttChart.heightTaskItem + "px"
  222. });
  223. dojo.forEach(this.resourceInfo[owner], function(task){
  224. var ownerTaskItem = dojo.create("div", {
  225. id: owner,
  226. className: "ganttOwnerTaskBar"
  227. }, ownerControl);
  228. var tposX = this.ganttChart.getPosOnDate(task.taskItem.startTime); // should be task start date
  229. dojo.style(ownerTaskItem, {
  230. left: (tposX - posX) + "px",
  231. width: task.taskItem.duration * this.ganttChart.pixelsPerWorkHour + "px", // should be task duration
  232. height: this.ganttChart.heightTaskItem + "px"
  233. });
  234. }, this);
  235. return ownerControl;
  236. },
  237. refreshDetailedTaskEntry: function(owner, item, task){
  238. this.refreshTaskItem(item, task);
  239. },
  240. createDetailedTaskEntry: function(owner, parentNode, task){
  241. var taskItems = [];
  242. var containerTasks = this.contentData.firstChild;
  243. var posY = parseInt(parentNode.style.top);
  244. //creation task item
  245. var taskItem = this.createTaskItem(task, posY);
  246. taskItem.style.display = "none";
  247. containerTasks.appendChild(taskItem);
  248. this.ownerItem.push(taskItem);
  249. taskItems.push(taskItem);
  250. if(this.panelNames){
  251. var taskNameItem = this.createTaskNameItem(task.taskItem.name, posY);
  252. this.panelNames.firstChild.appendChild(taskNameItem);
  253. taskNameItem.style.display = "none";
  254. this.ownerNameItem.push(taskNameItem);
  255. taskItems.push(taskNameItem);
  256. }
  257. if(this.panelNames){
  258. this.ownerNameItem[this.ownerNameItem.length - 1].style.left = dojo.style(parentNode, "left") + 15 + "px";
  259. var arrConnectingLinesNames = this.createConnectingLinesPN(parentNode, this.ownerNameItem[this.ownerNameItem.length - 1]);
  260. dojo.forEach(arrConnectingLinesNames, function(lineName){
  261. lineName.style.display = "none";
  262. }, this);
  263. taskItems.push({
  264. "v": arrConnectingLinesNames[0],
  265. "h": arrConnectingLinesNames[1]
  266. });
  267. this.checkWidthTaskNameItem(this.ownerNameItem[this.ownerNameItem.length - 1]);
  268. }
  269. return taskItems;
  270. },
  271. createTaskNameItem: function(owner, posY){
  272. var taskNameItem = dojo.create("div", {
  273. id: owner,
  274. className: "ganttTaskNameItem",
  275. title: owner,
  276. innerHTML: owner
  277. });
  278. dojo.style(taskNameItem, "top", posY + "px");
  279. return taskNameItem;
  280. },
  281. refreshTaskItem: function(item, task){
  282. var posX = this.ganttChart.getPosOnDate(task.taskItem.startTime); // should be task start date
  283. dojo.style(item, {
  284. left: posX + "px",
  285. width: task.taskItem.duration * this.ganttChart.pixelsPerWorkHour + "px"
  286. });
  287. },
  288. createTaskItem: function(task, posY){
  289. var posX = this.ganttChart.getPosOnDate(task.taskItem.startTime); // should be task start date
  290. var itemControl = dojo.create("div", {
  291. id: task.taskItem.name,
  292. className: "ganttTaskBar"
  293. });
  294. dojo.style(itemControl, {
  295. left: posX + "px",
  296. top: posY + "px",
  297. width: task.taskItem.duration * this.ganttChart.pixelsPerWorkHour + "px",
  298. height: this.ganttChart.heightTaskItem + "px"
  299. });
  300. return itemControl;
  301. },
  302. createConnectingLinesPN: function(parentNode, currentNode){
  303. var arrConnectingLinesNames = [];
  304. var lineVerticalLeft = dojo.create("div", {
  305. innerHTML: "&nbsp;",
  306. className: "ganttResourceLineVerticalLeft"
  307. }, this.panelNames.firstChild);
  308. lineVerticalLeft.cNode = currentNode;
  309. lineVerticalLeft.pNode = parentNode;
  310. var LineHorizontalLeft = dojo.create("div", {
  311. noShade: true,
  312. color: "#000",
  313. className: "ganttResourceLineHorizontalLeft"
  314. }, this.panelNames.firstChild);
  315. LineHorizontalLeft.cNode = currentNode;
  316. LineHorizontalLeft.pNode = parentNode;
  317. this.panelNames.firstChild.appendChild(LineHorizontalLeft);
  318. arrConnectingLinesNames.push(lineVerticalLeft);
  319. arrConnectingLinesNames.push(LineHorizontalLeft);
  320. return arrConnectingLinesNames;
  321. },
  322. createTreeImg: function(ownerNameItem){
  323. var treeImg = dojo.create("div", {
  324. id: ownerNameItem.id,
  325. className: "ganttImageTreeExpand"
  326. });
  327. dojo.attr(treeImg, "tabIndex", 0);
  328. var currentItem = this.ownerTaskNodeMapping[ownerNameItem.id];
  329. dojo.forEach(["onclick", "onkeydown"], function(e){
  330. this.ganttChart._events.push(
  331. dojo.connect(treeImg, e, this, function(evt){
  332. var reachTarget = false, owner, ownerItem;
  333. if(e == "onkeydown" && evt.keyCode != dojo.keys.ENTER){ return; }
  334. //TODO: perhaps the following conditional can be collapsed? Duplicate code.
  335. if(currentItem.isOpen){
  336. dojo.removeClass(treeImg, "ganttImageTreeCollapse");
  337. dojo.addClass(treeImg, "ganttImageTreeExpand");
  338. currentItem.isOpen = false;
  339. //collapse
  340. for(owner in this.ownerTaskNodeMapping){
  341. ownerItem = this.ownerTaskNodeMapping[owner];
  342. if(reachTarget){
  343. dojo.forEach(ownerItem[owner], function(tItem){
  344. dojo.style(tItem, "top", dojo.style(tItem, "top") - currentItem.taskCount * 23 + "px");
  345. });
  346. dojo.forEach(ownerItem.tasks, function(tItems){
  347. dojo.forEach(tItems, function(tItem){
  348. var item = !tItem.v && !tItem.h ? [tItem] : [tItem.v, tItem.h];
  349. dojo.forEach(item, function(t){
  350. dojo.style(t, "top", dojo.style(t, "top") - currentItem.taskCount * 23 + "px");
  351. });
  352. });
  353. });
  354. }else{
  355. if(owner == ownerNameItem.id){
  356. reachTarget = true;
  357. dojo.forEach(ownerItem.tasks, function(tItems, i){
  358. dojo.forEach(tItems, function(tItem){
  359. this.styleOwnerItem(tItem, ownerItem[owner][0], "none", 0);
  360. }, this);
  361. }, this);
  362. }
  363. }
  364. }
  365. }else{
  366. dojo.removeClass(treeImg, "ganttImageTreeExpand");
  367. dojo.addClass(treeImg, "ganttImageTreeCollapse");
  368. currentItem.isOpen = true;
  369. //expand
  370. for(owner in this.ownerTaskNodeMapping){
  371. ownerItem = this.ownerTaskNodeMapping[owner];
  372. if(reachTarget){
  373. dojo.forEach(ownerItem[owner], function(tItem){
  374. dojo.style(tItem, "top", dojo.style(tItem, "top") + currentItem.taskCount * 23 + "px");
  375. });
  376. dojo.forEach(ownerItem.tasks, function(tItems){
  377. dojo.forEach(tItems, function(tItem){
  378. var item = !tItem.v && !tItem.h ? [tItem] : [tItem.v, tItem.h];
  379. dojo.forEach(item, function(t){
  380. dojo.style(t, "top", dojo.style(t, "top") + currentItem.taskCount * 23 + "px");
  381. });
  382. });
  383. });
  384. }else{
  385. if(owner == ownerNameItem.id){
  386. reachTarget = true;
  387. dojo.forEach(ownerItem.tasks, function(tItems, i){
  388. dojo.forEach(tItems, function(tItem){
  389. this.styleOwnerItem(tItem, ownerItem[owner][0], "inline", (i + 1) * 23);
  390. }, this);
  391. }, this);
  392. }
  393. }
  394. }
  395. }
  396. })
  397. );
  398. }, this);
  399. dojo.addClass(treeImg, "ganttResourceTreeImage");
  400. dojo.style(treeImg, {
  401. left: (dojo.style(ownerNameItem, "left") - 12) + "px",
  402. top: (dojo.style(ownerNameItem, "top") + 3) + "px"
  403. });
  404. return treeImg;
  405. },
  406. styleOwnerItem: function(tItem, owner, displayType, topOffset){
  407. if(tItem.v || tItem.h){
  408. dojo.style(tItem.v, {
  409. height: Math.max(1, (tItem.v.cNode.offsetTop - tItem.v.pNode.offsetTop)) + "px",
  410. top: (tItem.v.pNode.offsetTop + 5) + "px",
  411. left: (tItem.v.pNode.offsetLeft - 9) + "px",
  412. display: displayType
  413. });
  414. dojo.style(tItem.h, {
  415. width: Math.max(1, (tItem.h.cNode.offsetLeft - tItem.h.pNode.offsetLeft + 4)) + "px",
  416. top: (tItem.h.cNode.offsetTop + 5) + "px",
  417. left: (tItem.h.pNode.offsetLeft - 9) + "px",
  418. display: displayType
  419. });
  420. }else{
  421. dojo.style(tItem, {
  422. display: displayType,
  423. top: parseInt(owner.style.top) + topOffset + "px"
  424. });
  425. }
  426. },
  427. checkWidthTaskNameItem: function(taskNameItem){
  428. if(taskNameItem && taskNameItem.offsetWidth + taskNameItem.offsetLeft > this.ganttChart.maxWidthPanelNames){
  429. var width = taskNameItem.offsetWidth + taskNameItem.offsetLeft - this.ganttChart.maxWidthPanelNames,
  430. countChar = Math.round(width / (taskNameItem.offsetWidth / taskNameItem.firstChild.length)),
  431. tName = taskNameItem.id.substring(0, taskNameItem.firstChild.length - countChar - 3);
  432. taskNameItem.innerHTML = tName + "...";
  433. }
  434. },
  435. createPanelOwners: function(){
  436. var panelOwner = dojo.create("div", {
  437. className: "ganttOwnerPanel"
  438. });
  439. dojo.style(panelOwner, {
  440. height: (this.contentHeight - this.ganttChart.panelTimeHeight - this.ganttChart.scrollBarWidth) + "px"
  441. });
  442. return panelOwner;
  443. },
  444. createPanelNamesOwners: function(){
  445. var panelNameOwner = dojo.create("div", {
  446. innerHTML: "&nbsp;",
  447. className: "ganttResourcePanelNamesOwners"
  448. });
  449. dojo.style(panelNameOwner, {
  450. height: (this.contentHeight - this.ganttChart.panelTimeHeight - this.ganttChart.scrollBarWidth) + "px",
  451. width: this.ganttChart.maxWidthPanelNames + "px"
  452. });
  453. return panelNameOwner;
  454. }
  455. });
  456. });