有几种方式可以处理将任务与其依赖任务一起移动的情况。
一种选择是使用 自动调度 扩展。它会根据任务之间的关系自动调度任务。
要启用自动调度,请使用 gantt.plugins 方法:
gantt.plugins({
auto_scheduling: true
});
同时,将 auto_scheduling 属性设置为 true:
gantt.config.auto_scheduling = true;
一种常见的拖动依赖任务的方式是:
你可以选择以下两种方法之一:
无论哪种方式,第一步都是获取所有关联任务。
要查找与任务相关的链接,可以使用任务对象上的 $source 和 $target 属性。 这些属性是自动生成的,包含相关链接的 ID:
var taskObj = gantt.getTask("t1");
var sourceLinks = taskObj.$source; //-> ["l1","l4"] - 外发链接的ID
var targetLinks = taskObj.$target; //-> ["l5","l8"] - 入链的ID
通过这些链接,可以找到依赖的任务。
要收集所有关联任务,可以定义如下迭代器:
gantt.eachSuccessor = function(callback, root){
if(!this.isTaskExists(root))
return;
// 跟踪已访问的任务,避免死循环
var traversedTasks = arguments[2] || {};
if(traversedTasks[root])
return;
traversedTasks[root] = true;
var rootTask = this.getTask(root);
var links = rootTask.$source;
if(links){
for(var i=0; i < links.length; i++){
var link = this.getLink(links[i]);
if(this.isTaskExists(link.target) && !traversedTasks[link.target]){
callback.call(this, this.getTask(link.target));
// 遍历整个依赖分支,不仅仅是第一层
this.eachSuccessor(callback, link.target, traversedTasks);
}
}
}
};
在拖动主任务时,可以将其后代任务一起移动。也就是说,用户移动主任务时,所有依赖任务会同步移动。这种方式视觉上流畅,但如果涉及任务较多,可能会影响性能。
首先,按照获取所有关联任务中的方法声明迭代器。
接下来,绑定 onTaskDrag 事件的处理器。该事件会在每一帧拖动时触发,在此可以移动所有关联任务。
gantt.attachEvent("onTaskDrag", function(id, mode, task, original){
var modes = gantt.config.drag_mode;
if(mode == modes.move){
var diff = task.start_date - original.start_date;
gantt.eachSuccessor(function(child){
child.start_date = new Date(+child.start_date + diff);
child.end_date = new Date(+child.end_date + diff);
gantt.refreshTask(child.id, true);
},id );
}
return true;
});
最后,当拖动结束,用户释放鼠标时,将子任务的位置对齐到时间刻度。这可以通过 onAfterTaskDrag 事件完成:
gantt.attachEvent("onAfterTaskDrag", function(id, mode, e){
var modes = gantt.config.drag_mode;
if(mode == modes.move ){
gantt.eachSuccessor(function(child){
child.start_date = gantt.roundDate(child.start_date);
child.end_date = gantt.calculateEndDate(child.start_date, child.duration);
gantt.updateTask(child.id);
},id );
}
});
除非关联任务数量非常多,否则这种方法效果良好。
另一种方式是,仅在主任务移动完成后才更新其后代任务。这种方式视觉上更简单,性能也更好。
思路是等待拖拽操作完成后,再计算主任务移动了多少天,然后将所有关联任务按此幅度移动。
首先,按照前文获取所有关联任务的方法声明迭代器。
当用户完成拖动时,捕获 onBeforeTaskChanged 事件。该事件会同时提供被移动任务的原始版本和修改后的版本,可以用来计算日期差。
注意,此时拖拽操作仍有可能被取消(因为 onBeforeTaskChanged 支持取消,并且你的应用可能有相关处理器),因此此处不会更新依赖任务。
相反,可以将计算出的差值保存在稍后可访问的变量中。
var diff = 0;
gantt.attachEvent("onBeforeTaskChanged", function(id, mode, originalTask){
var modes = gantt.config.drag_mode;
if(mode == modes.move ){
var modifiedTask = gantt.getTask(id);
diff = modifiedTask.start_date - originalTask.start_date;
}
return true;
});
最后,使用 onAfterTaskDrag 事件,利用之前计算的 diff 更新所有依赖任务:
//将子任务位置对齐到时间刻度
gantt.attachEvent("onAfterTaskDrag", function(id, mode, e){
var modes = gantt.config.drag_mode;
if(mode == modes.move ){
gantt.eachSuccessor(function(child){
child.start_date = gantt.roundDate(new Date(child.start_date.valueOf() + diff));
child.end_date = gantt.calculateEndDate(child.start_date, child.duration);
gantt.updateTask(child.id);
},id );
}
});
完整代码如下:
(function(){
var diff = 0;
gantt.attachEvent("onBeforeTaskChanged", function(id, mode, originalTask){
var modes = gantt.config.drag_mode;
if(mode == modes.move ){
var modifiedTask = gantt.getTask(id);
diff = modifiedTask.start_date - originalTask.start_date;
}
return true;
});
//将子任务位置对齐到时间刻度
gantt.attachEvent("onAfterTaskDrag", function(id, mode, e){
var modes = gantt.config.drag_mode;
if(mode == modes.move ){
gantt.eachSuccessor(function(child){
child.start_date = gantt.roundDate(new Date(child.start_date.valueOf() + diff));
child.end_date = gantt.calculateEndDate(child.start_date, child.duration);
gantt.updateTask(child.id);
},id );
}
});
})();
Back to top