GanttResourceItem.js 17 KB

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