UNPKG

netzplan

Version:

Vorgangsknoten-Netzplan https://de.wikipedia.org/wiki/Netzplantechnik

205 lines (180 loc) 6.57 kB
const exampleGraph = { "A": { "children": ["B","C"], "duration": 6, "earliestStart": 0, "earliestEnd": 0, "latestStart": 0, "latestEnd": 0, }, "B": { "children": ["D","E"], "duration": 3 }, "C": { "children": ["F"], "duration": 1 }, "D": { "children": ["G"], "duration": 1 }, "E": { "children": ["F"], "duration": 2 }, "F": { "children": ["G"], "duration": 1 }, "G": { "children": [], "duration": 1 } }; function resetCalcedTimesGraph(graphJSON){ let copy = JSON.parse(JSON.stringify(graphJSON)); let allNodeLabels = Object.keys(copy); for(let i=0; i<allNodeLabels.length; i++){ let nodeLabel = allNodeLabels[i]; let node = copy[nodeLabel]; delete node.earliestStart; delete node.earliestEnd; delete node.latestStart; delete node.latestEnd; copy[nodeLabel] = node; } return copy; } function calcForwardGraph(graphJSON, startNodeLabel){ let startNode = graphJSON[startNodeLabel]; startNode.earliestStart = 0; startNode.earliestEnd = startNode.duration; startNode.latestStart = 0; startNode.latestEnd = startNode.duration; graphJSON[startNodeLabel] = startNode; let listOfImpoveableNodes = [startNodeLabel]; while(listOfImpoveableNodes.length > 0){ let liftOfNextImproveableNodes = []; for(let i=0; i<listOfImpoveableNodes.length; i++){ let parentLabel = listOfImpoveableNodes[i]; let parent = graphJSON[parentLabel]; let children = parent.children || []; parent.children = children; graphJSON[parentLabel] = parent; for(let j=0; j<children.length; j++){ let childLabel = children[j]; let child = graphJSON[childLabel]; let parents = child.parents || []; parents.push(parentLabel); child.parents = parents; let childsEarliestStart = child.earliestStart; if(!childsEarliestStart || childsEarliestStart < parent.earliestEnd){ childsEarliestStart = parent.earliestEnd; liftOfNextImproveableNodes.push(childLabel); } child.earliestStart = childsEarliestStart; child.earliestEnd = childsEarliestStart + child.duration; graphJSON[childLabel] = child; } } listOfImpoveableNodes = liftOfNextImproveableNodes; } return graphJSON; } function calcBackwardGraph(graphJSON){ let listOfLeafes = getAllLeafes(graphJSON); for(let i=0; i<listOfLeafes.length; i++){ let endNodeLabel = listOfLeafes[i]; graphJSON = calcBackwardGraphForEndlabel(graphJSON, endNodeLabel); } return graphJSON; } function calcBackwardGraphForEndlabel(graphJSON, endNodeLabel){ let endNode = graphJSON[endNodeLabel]; endNode.latestEnd = endNode.earliestEnd; endNode.latestStart = endNode.earliestStart; endNode.buffer = 0; graphJSON[endNodeLabel] = endNode; let listOfImpoveableNodes = [endNodeLabel]; while(listOfImpoveableNodes.length > 0){ let liftOfNextImproveableNodes = []; for(let i=0; i<listOfImpoveableNodes.length; i++){ let childLabel = listOfImpoveableNodes[i]; let child = graphJSON[childLabel]; let parents = child.parents; for(let j=0; j<parents.length; j++){ let parentLabel = parents[j]; let parent = graphJSON[parentLabel]; let parentsLatestEnd = parent.latestEnd; if(!parentsLatestEnd || parentsLatestEnd > child.latestStart){ parentsLatestEnd = child.latestStart; liftOfNextImproveableNodes.push(parentLabel); } parent.latestEnd = parentsLatestEnd; parent.latestStart = parentsLatestEnd - parent.duration; parent.buffer = parent.latestEnd - parent.earliestEnd; graphJSON[parentLabel] = parent; } } listOfImpoveableNodes = liftOfNextImproveableNodes; } return graphJSON; } function isCriticalPath(parent, child){ // buffer 0 is not enough //A --> B && B --> C && A --> C //crititcal path would be A-->B-->C but we dont want A-->C as critical path if(child.latestStart === parent.latestEnd && child.buffer===0 && parent.buffer === 0) { return true; } return false; } function getCriticalPaths(graphJSON, startNodeLabel){ let criticalPaths = []; let parent = graphJSON[startNodeLabel]; if(parent.buffer===0){ let children = parent.children; if(children.length > 0){ for(let i=0; i<children.length; i++){ let childLabel = children[i]; let child = graphJSON[childLabel]; if(isCriticalPath(parent, child)){ //A --> B && B --> C && A --> C //crititcal path would be A-->B-->C but we dont want A-->C as critical path let childsCriticalPaths = getCriticalPaths(graphJSON, childLabel); for(let j=0; j<childsCriticalPaths.length; j++){ let childsCriticalPath = childsCriticalPaths[j]; let completedChildsCriticalPath = [startNodeLabel].concat(childsCriticalPath); criticalPaths.push(completedChildsCriticalPath); } } } return criticalPaths; } else { return [startNodeLabel]; } } return criticalPaths; } function getAllLeafes(graphJSON){ let listOfLeafes = []; let allNodeLabels = Object.keys(graphJSON); for(let i=0; i<allNodeLabels.length; i++){ let nodeLabel = allNodeLabels[i]; let node = graphJSON[nodeLabel]; if(node.children.length === 0){ listOfLeafes.push(nodeLabel); } } return listOfLeafes; } function init(graphJSON, startNodeLabel) { graphJSON = resetCalcedTimesGraph(graphJSON); graphJSON = calcForwardGraph(graphJSON, startNodeLabel); graphJSON = calcBackwardGraph(graphJSON); return graphJSON; } module.exports.init = init; module.exports.getCriticalPaths = getCriticalPaths; module.exports.isCriticalPath = isCriticalPath;