Es gibt mehrere Möglichkeiten, Aufgaben gemeinsam mit ihren abhängigen Aufgaben zu verschieben.
Eine Möglichkeit ist die Verwendung der Extension Auto Scheduling. Sie plant Aufgaben automatisch basierend auf deren Beziehungen.
Um die automatische Planung zu aktivieren, verwenden Sie die Methode gantt.plugins:
gantt.plugins({
auto_scheduling: true
});
Setzen Sie außerdem die Eigenschaft auto_scheduling auf true:
gantt.config.auto_scheduling = true;
Ein gängiger Weg, abhängige Aufgaben zu verschieben, ist:
Sie können eine der beiden folgenden Ansätze wählen:
In beiden Fällen besteht der erste Schritt darin, alle verknüpften Aufgaben zu ermitteln.
Um die mit einer Aufgabe verbundenen Links zu finden, verwenden Sie die Eigenschaften $source und $target des Aufgabenobjekts. Diese werden automatisch generiert und enthalten die IDs der zugehörigen Links:
var taskObj = gantt.getTask("t1");
var sourceLinks = taskObj.$source; //-> ["l1","l4"] - IDs der ausgehenden Links
var targetLinks = taskObj.$target; //-> ["l5","l8"] - IDs der eingehenden Links
Aus diesen Links können Sie die abhängigen Aufgaben ermitteln.
Um alle verknüpften Aufgaben zu sammeln, definieren Sie einen Iterator wie folgt:
gantt.eachSuccessor = function(callback, root){
if(!this.isTaskExists(root))
return;
// besuchte Aufgaben nachverfolgen, um Endlosschleifen zu vermeiden
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));
// den gesamten Abhängigkeitszweig durchlaufen, nicht nur die erste Ebene
this.eachSuccessor(callback, link.target, traversedTasks);
}
}
}
};
Nachfolgende Aufgaben können beim Ziehen zusammen mit der Hauptaufgabe verschoben werden. Das bedeutet, dass beim Verschieben der Hauptaufgabe alle abhängigen Aufgaben gleichzeitig mitverschoben werden. Dies wirkt flüssig, kann aber die Leistung beeinträchtigen, wenn viele Aufgaben betroffen sind.
Deklarieren Sie zunächst den Iterator wie oben unter Alle verknüpften Aufgaben ermitteln gezeigt.
Fügen Sie anschließend einen Handler für das Ereignis onTaskDrag hinzu. Dieses Ereignis wird bei jedem Zieh-Vorgang ausgelöst. Hier können Sie alle verknüpften Aufgaben verschieben.
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;
});
Wenn das Ziehen beendet ist und der Nutzer die Maus loslässt, runden Sie die Positionen der Nachfolger auf die Zeitskala. Dies kann mit dem Ereignis onAfterTaskDrag erfolgen:
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 );
}
});
Diese Methode funktioniert gut, solange keine große Anzahl verknüpfter Aufgaben betroffen ist.
Alternativ können die nachfolgenden Aufgaben erst aktualisiert werden, nachdem die Hauptaufgabe verschoben wurde. Dieser Ansatz ist visuell einfacher und bietet eine bessere Performance.
Die Idee ist, das Ziehen abzuwarten, dann die Verschiebungsdifferenz der Hauptaufgabe zu berechnen und alle abhängigen Aufgaben um diesen Wert zu verschieben.
Deklarieren Sie zunächst den Iterator wie zuvor unter Alle verknüpften Aufgaben ermitteln gezeigt.
Wenn der Nutzer das Ziehen beendet, fangen Sie das Ereignis onBeforeTaskChanged ab. Dieses Ereignis stellt sowohl die ursprüngliche als auch die geänderte Version der verschobenen Aufgabe zur Verfügung, wodurch Sie die Datumsdifferenz berechnen können.
Beachten Sie, dass Drag-and-Drop an dieser Stelle noch abgebrochen werden kann (da onBeforeTaskChanged eine Abbrechung unterstützt und Ihre App möglicherweise Handler dafür hat), daher werden abhängige Aufgaben hier noch nicht aktualisiert.
Speichern Sie stattdessen die berechnete Differenz in einer später zugänglichen Variablen.
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;
});
Verwenden Sie abschließend das Ereignis onAfterTaskDrag, um alle abhängigen Aufgaben mit der zuvor berechneten diff zu aktualisieren:
//Rundet die Positionen der Nachfolger auf die Zeitskala
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 );
}
});
Hier ist der vollständige Code:
(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;
});
//Rundet die Positionen der Nachfolger auf die Zeitskala
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 );
}
});
})();
Zurück nach oben