Fixed project-planner maths
This commit is contained in:
parent
d36b98a20c
commit
01ea1b6d01
|
@ -122,31 +122,9 @@ gantt1.AddTask({
|
|||
CollatedTaskID: 8
|
||||
});
|
||||
|
||||
gantt1.InvalidateTasks();
|
||||
|
||||
console.log(gantt1.ExportTasks);
|
||||
|
||||
// console.log(gantt1.Tasks);
|
||||
|
||||
|
||||
|
||||
|
||||
// var dataSet = [
|
||||
// { key: "b", value: "B2", num: 2, f: 2.2, date: new Date(2001, 2, 2) },
|
||||
// { key: "d", value: "D4", num: 4, f: 4.4, date: new Date(2001, 4, 4) },
|
||||
// { key: "a", value: "A1", num: 1, f: 1.1, date: new Date(2001, 10, 1) },
|
||||
// { key: "e", value: "E5", num: 5, f: 5.5, date: new Date(2001, 5, 5) },
|
||||
// { key: "c", value: "C3", num: 3, f: 3.3, date: new Date(2001, 3, 3) }
|
||||
// ];
|
||||
|
||||
// // let result = dataSet.index("key", "d");
|
||||
// //dataSet = dataSet.orderBy("date");
|
||||
// dataSet = dataSet.orderByDesc("date");
|
||||
|
||||
// console.log(result);
|
||||
// console.log(dataSet);
|
||||
|
||||
gantt1.Invalidate();
|
||||
|
||||
console.log(gantt1.ExportTasks());
|
||||
|
||||
</script>
|
||||
|
||||
|
|
299
ryz-gantts.js
299
ryz-gantts.js
|
@ -62,22 +62,6 @@ class RyzGantt {
|
|||
};
|
||||
}
|
||||
|
||||
get ExportTasks() {
|
||||
const a = this;
|
||||
|
||||
let result = [];
|
||||
|
||||
a.#exportTasks(result, a.Tasks.copy());
|
||||
|
||||
for (var i=0; i<result.length; i++) {
|
||||
result[i].Order = (i + 1);
|
||||
|
||||
delete result[i].Tasks;
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
AddTask(task) {
|
||||
const a = this;
|
||||
|
@ -113,6 +97,22 @@ class RyzGantt {
|
|||
a.Tasks = [];
|
||||
}
|
||||
|
||||
ExportTasks() {
|
||||
const a = this;
|
||||
|
||||
let result = [];
|
||||
|
||||
a.#exportTasks(result, a.Tasks.copy());
|
||||
|
||||
for (var i=0; i<result.length; i++) {
|
||||
result[i].Order = (i + 1);
|
||||
|
||||
delete result[i].Tasks;
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
FindTask(id) {
|
||||
const a = this;
|
||||
|
||||
|
@ -171,97 +171,20 @@ class RyzGantt {
|
|||
return 0;
|
||||
}
|
||||
|
||||
InvalidateTasks() {
|
||||
Invalidate() {
|
||||
const a = this;
|
||||
let isSuccess = false;
|
||||
|
||||
// a.#log(a.Tasks.copy());
|
||||
if (!a.Recalc()) {
|
||||
isSuccess = false;
|
||||
}
|
||||
|
||||
a.Recalc();
|
||||
|
||||
// a.#log(a.Tasks.copy());
|
||||
|
||||
// return;
|
||||
|
||||
|
||||
// a.#resetTasks();
|
||||
|
||||
// console.log("Original");
|
||||
// console.log(a.Tasks.copy());
|
||||
|
||||
// // Get root nodes
|
||||
// let nodes = a.Tasks.selectMany(
|
||||
// { propName: "DependsOnTaskID", value: null },
|
||||
// { propName: "CollatedTaskID", value: null }
|
||||
// );
|
||||
// nodes.orderBy("StartDelay");
|
||||
|
||||
// a.Tasks.removeRange(nodes);
|
||||
|
||||
// console.log("Root");
|
||||
// console.log(a.Tasks.copy());
|
||||
// console.log(nodes.copy());
|
||||
|
||||
// //
|
||||
// for (let i=(nodes.length - 1); i>=0; i--) {
|
||||
// // Find dependent tasks
|
||||
// let foundNodes = a.Tasks.select("DependsOnTaskID", nodes[i].ID);
|
||||
// foundNodes.forEach(e => {
|
||||
// nodes.insert((i + 1), e);
|
||||
// });
|
||||
|
||||
// a.Tasks.removeRange(foundNodes);
|
||||
|
||||
// // Add child tasks
|
||||
// if (nodes[i].IsCollated == true) {
|
||||
// foundNodes = a.Tasks.select("CollatedTaskID", nodes[i].ID);
|
||||
// foundNodes.forEach(e => {
|
||||
// nodes.insert((i + 1), e);
|
||||
// });
|
||||
|
||||
// a.Tasks.removeRange(foundNodes);
|
||||
|
||||
// }
|
||||
// }
|
||||
|
||||
// // console.log(a.Tasks.copy());
|
||||
|
||||
|
||||
// // a.Tasks = a.#findTasksL0(a.Tasks);
|
||||
|
||||
// console.log("Final");
|
||||
// console.log(a.Tasks.copy());
|
||||
// console.log(nodes.copy());
|
||||
return isSuccess;
|
||||
}
|
||||
|
||||
|
||||
// #popL0Tasks(array) {
|
||||
// const a = this;
|
||||
|
||||
// let nodes = array.selectMany(
|
||||
// { propName: "DependsOnTaskID", value: null },
|
||||
// { propName: "CollatedTaskID", value: null }
|
||||
// );
|
||||
// nodes = nodes.orderBy("StartDelay");
|
||||
|
||||
// array.removeRange(nodes);
|
||||
|
||||
// return nodes;
|
||||
// }
|
||||
|
||||
// #addTasks(sourceTasksArray, targetTasksArray, index) {
|
||||
// const a = this;
|
||||
|
||||
// const nodes = sourceTasksArray.select("DependsOnTaskID", targetTasksArray[index].ID);
|
||||
|
||||
// for (let i=0; i<nodes.length; i++) {
|
||||
// targetTasksArray.insert((index + 1), nodes[i]);
|
||||
// }
|
||||
|
||||
// sourceTasksArray.removeRange(nodes);
|
||||
// }
|
||||
|
||||
Recalc() {
|
||||
const a = this;
|
||||
let isSuccess = false;
|
||||
|
||||
a.Sort();
|
||||
|
||||
|
@ -277,42 +200,87 @@ class RyzGantt {
|
|||
result[i].CalcWorkHours = null;
|
||||
}
|
||||
|
||||
for (var i=0; i<result.length; i++) {
|
||||
const nodeType = a.GetNodeType(result[i]);
|
||||
// Maximum 128 rounds
|
||||
for (var x=0; x<128; x++) {
|
||||
let pendingCount = result.copy().countMany(
|
||||
{ propName: "StartDate", value: null },
|
||||
{ propName: "FinishDate", value: null }
|
||||
);
|
||||
|
||||
switch (nodeType) {
|
||||
case 1: // task no-parent/root
|
||||
result[i].StartDate = Date.addDays(a.Project.StartDate, result[i].StartDelay);
|
||||
result[i].FinishDate = Date.addDays(result[i].StartDate, result[i].Duration);
|
||||
break;
|
||||
case 2: // task no-parent/root, collated/group
|
||||
break;
|
||||
case 3: // task with parent
|
||||
const node = result.first("ID", result[i].DependsOnTaskID);
|
||||
if (node != null) {
|
||||
if (node.FinishDate != null) {
|
||||
result[i].StartDate = Date.addDays(node.FinishDate, result[i].StartDelay);
|
||||
result[i].FinishDate = Date.addDays(result[i].StartDate, result[i].Duration);
|
||||
}
|
||||
}
|
||||
|
||||
break;
|
||||
case 4: // task with parent, collated/group
|
||||
break;
|
||||
case 5: // sub-task
|
||||
break;
|
||||
case 6: // sub-task, collated/group
|
||||
break;
|
||||
default: // orphan
|
||||
break;
|
||||
// Done
|
||||
if (pendingCount <= 0) {
|
||||
isSuccess = true;
|
||||
break;
|
||||
}
|
||||
|
||||
a.#log("Round " + (x + 1));
|
||||
|
||||
for (var i=0; i<result.length; i++) {
|
||||
const nodeType = a.GetNodeType(result[i]);
|
||||
|
||||
switch (nodeType) {
|
||||
case 1: // task no-parent/root
|
||||
result[i].StartDate = Date.addDays(a.Project.StartDate, result[i].StartDelay);
|
||||
result[i].FinishDate = Date.addDays(result[i].StartDate, result[i].Duration);
|
||||
break;
|
||||
case 2: // task no-parent/root, collated/group
|
||||
result[i].StartDate = Date.addDays(a.Project.StartDate, result[i].StartDelay);
|
||||
|
||||
// update finish date, if possible
|
||||
result[i].FinishDate = a.#calcCollatedFinishDate(result, i);
|
||||
|
||||
break;
|
||||
case 3: // task with parent
|
||||
const node3 = result.first("ID", result[i].DependsOnTaskID);
|
||||
if (node3 != null) {
|
||||
if (node3.FinishDate != null) {
|
||||
result[i].StartDate = Date.addDays(node3.FinishDate, result[i].StartDelay);
|
||||
result[i].FinishDate = Date.addDays(result[i].StartDate, result[i].Duration);
|
||||
}
|
||||
}
|
||||
|
||||
break;
|
||||
case 4: // task with parent, collated/group
|
||||
const node4 = result.first("ID", result[i].DependsOnTaskID);
|
||||
if (node4 != null) {
|
||||
if (node4.FinishDate != null) {
|
||||
result[i].StartDate = Date.addDays(node4.FinishDate, result[i].StartDelay);
|
||||
|
||||
// update finish date, if possible
|
||||
result[i].FinishDate = a.#calcCollatedFinishDate(result, i);
|
||||
}
|
||||
}
|
||||
|
||||
break;
|
||||
case 5: // sub-task
|
||||
const node5 = result.first("ID", result[i].CollatedTaskID);
|
||||
if (node5 != null) {
|
||||
if (node5.StartDate != null) {
|
||||
result[i].StartDate = Date.addDays(node5.StartDate, result[i].StartDelay);
|
||||
result[i].FinishDate = Date.addDays(result[i].StartDate, result[i].Duration);
|
||||
}
|
||||
}
|
||||
|
||||
break;
|
||||
case 6: // sub-task, collated/group
|
||||
const node6 = result.first("ID", result[i].CollatedTaskID);
|
||||
if (node6 != null) {
|
||||
if (node6.StartDate != null) {
|
||||
result[i].StartDate = Date.addDays(node6.StartDate, result[i].StartDelay);
|
||||
|
||||
// update finish date, if possible
|
||||
result[i].FinishDate = a.#calcCollatedFinishDate(result, i);
|
||||
}
|
||||
}
|
||||
|
||||
break;
|
||||
default: // orphan
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
// a.#resetTasks(a.Tasks);
|
||||
// a.#recalcTasks(a.Project.StartDate, a.Tasks);
|
||||
return isSuccess;
|
||||
}
|
||||
|
||||
Sort() {
|
||||
|
@ -322,6 +290,28 @@ class RyzGantt {
|
|||
}
|
||||
|
||||
|
||||
#calcCollatedFinishDate(array, index) {
|
||||
let node2 = array.select("CollatedTaskID", array[index].ID);
|
||||
if (node2.length <= 0) {
|
||||
// No children
|
||||
return new Date(array[index].StartDate);
|
||||
}
|
||||
|
||||
// Not ready, calculation pending
|
||||
if (node2.any("FinishDate", null)) {
|
||||
return null;
|
||||
}
|
||||
|
||||
let node2FinishDate = new Date(array[index].StartDate);
|
||||
node2.forEach(e => {
|
||||
if (e.FinishDate > node2FinishDate) {
|
||||
node2FinishDate = e.FinishDate;
|
||||
}
|
||||
});
|
||||
|
||||
return new Date(node2FinishDate);
|
||||
}
|
||||
|
||||
#exportTasks(outputArray, array) {
|
||||
const a = this;
|
||||
|
||||
|
@ -338,50 +328,6 @@ class RyzGantt {
|
|||
console.log(message);
|
||||
}
|
||||
|
||||
// #recalcTasks(startDate, array) {
|
||||
// const a = this;
|
||||
|
||||
// for (let i=0; i<array.length; i++) {
|
||||
// array[i].Order = null;
|
||||
// array[i].StartDate = Date.addDays(startDate, array[i].StartDelay);
|
||||
// array[i].FinishDate = null;
|
||||
// // array[i].CalcWorkHours = null;
|
||||
|
||||
// if (array[i].IsCollated == true) {
|
||||
// if (array[i].Tasks.length > 0) {
|
||||
// a.#recalcTasks(array[i].StartDate, array[i].Tasks);
|
||||
// }
|
||||
|
||||
// } else {
|
||||
// array[i].FinishDate = Date.addDays(array[i].StartDate, array[i].Duration);
|
||||
|
||||
// if (array[i].Tasks.length > 0) {
|
||||
// a.#recalcTasks(array[i].FinishDate, array[i].Tasks);
|
||||
// }
|
||||
|
||||
// }
|
||||
|
||||
// // if (array[i].Tasks.length > 0) {
|
||||
// // a.#recalcTasks(array[i].StartDate, array[i].Tasks);
|
||||
// // }
|
||||
// }
|
||||
// }
|
||||
|
||||
// #resetTasks(array) {
|
||||
// const a = this;
|
||||
|
||||
// for (let i=0; i<array.length; i++) {
|
||||
// array[i].Order = null;
|
||||
// array[i].StartDate = null;
|
||||
// array[i].FinishDate = null;
|
||||
// array[i].CalcWorkHours = null;
|
||||
|
||||
// if (array[i].Tasks.length > 0) {
|
||||
// a.#resetTasks(array[i].Tasks);
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
|
||||
#searchForTaskID(array, id) {
|
||||
const a = this;
|
||||
|
||||
|
@ -415,7 +361,4 @@ class RyzGantt {
|
|||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
}
|
|
@ -10,10 +10,40 @@ Array.prototype.addRange = function (array) {
|
|||
return this;
|
||||
};
|
||||
|
||||
Array.prototype.any = function (propName, value) {
|
||||
return (this.count(propName, value) > 0);
|
||||
};
|
||||
|
||||
Array.prototype.copy = function () {
|
||||
return JSON.parse(JSON.stringify(this));
|
||||
};
|
||||
|
||||
Array.prototype.count = function (propName, value) {
|
||||
let result = 0;
|
||||
|
||||
for (let i = 0; i < this.length; i++) {
|
||||
if (typeof(this[i][propName]) == "undefined") {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (this[i][propName] == value){
|
||||
result++;
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
};
|
||||
|
||||
Array.prototype.countMany = function (...filters) {
|
||||
let result = 0;
|
||||
|
||||
filters.forEach(e => {
|
||||
result += this.count(e.propName, e.value);
|
||||
});
|
||||
|
||||
return result;
|
||||
};
|
||||
|
||||
Array.prototype.index = function (propName, value) {
|
||||
for (let i = 0; i < this.length; i++) {
|
||||
if (typeof(this[i][propName]) == "undefined") {
|
||||
|
|
Loading…
Reference in New Issue