mirror of
https://github.com/fazo96/pbs.git
synced 2025-01-27 14:34:19 +01:00
WIP async transformation of the library
This commit is contained in:
parent
265f3bc7f8
commit
6c6843df49
@ -22,6 +22,7 @@
|
|||||||
"bootstrap": "~3.3.4",
|
"bootstrap": "~3.3.4",
|
||||||
"sweetalert": "~0.5.0",
|
"sweetalert": "~0.5.0",
|
||||||
"angular": "~1.3.15",
|
"angular": "~1.3.15",
|
||||||
"angular-ui-router": "~0.2.13"
|
"angular-ui-router": "~0.2.13",
|
||||||
|
"async": "~0.9.2"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -35,6 +35,7 @@ gulp.task('js',function(){
|
|||||||
jsFiles = ["src/*.js",
|
jsFiles = ["src/*.js",
|
||||||
"bower_components/jquery/dist/jquery.js",
|
"bower_components/jquery/dist/jquery.js",
|
||||||
"bower_components/moment/moment.js",
|
"bower_components/moment/moment.js",
|
||||||
|
"bower_components/async/lib/async.js",
|
||||||
"bower_components/bootstrap/dist/js/bootstrap.js",
|
"bower_components/bootstrap/dist/js/bootstrap.js",
|
||||||
"bower_components/bootstrap/js/collapse.js",
|
"bower_components/bootstrap/js/collapse.js",
|
||||||
"bower_components/angular/angular.js",
|
"bower_components/angular/angular.js",
|
||||||
|
@ -1,6 +1,7 @@
|
|||||||
class PBS
|
class PBS
|
||||||
constructor: (@list, @verbose) ->
|
constructor: (@list, @verbose) ->
|
||||||
@days = []
|
@days = []
|
||||||
|
@verbose = yes
|
||||||
@criticalPaths = []
|
@criticalPaths = []
|
||||||
|
|
||||||
log: (x...) ->
|
log: (x...) ->
|
||||||
@ -25,68 +26,89 @@ class PBS
|
|||||||
return item
|
return item
|
||||||
|
|
||||||
# Compute the item's end day
|
# Compute the item's end day
|
||||||
calculateEndDay: (item) =>
|
calculateEndDay: (item,cb) =>
|
||||||
if !item.startDay?
|
if item.endDay? then cb null, item.endDay
|
||||||
|
else if !item.startDay?
|
||||||
@log "calculating start day of",item.id
|
@log "calculating start day of",item.id
|
||||||
item.startDay = @calculateStartDay item
|
@calculateStartDay item, => @calculateEndDay item, cb
|
||||||
@log "start day of",item.id,"is",item.startDay
|
else
|
||||||
item.endDay = item.startDay + item.duration
|
@log "start day of",item.id,"is",item.startDay
|
||||||
@log "end day of",item.id,"is",item.endDay
|
item.endDay = item.startDay + item.duration
|
||||||
@insertDay item.endDay
|
@log "end day of",item.id,"is",item.endDay
|
||||||
return item.endDay
|
@insertDay item.endDay
|
||||||
|
cb null, item.endDay
|
||||||
|
|
||||||
# Find out which day the activity starts
|
# Find out which day the activity starts
|
||||||
calculateStartDay: (item) =>
|
calculateStartDay: (item,cb) =>
|
||||||
if !item.depends? or item.depends.length is 0
|
if item.startDay? then cb null, item.startDay
|
||||||
|
else if !item.depends? or item.depends.length is 0
|
||||||
@insertDay 0
|
@insertDay 0
|
||||||
return item.startDay = 0
|
cb null, item.startDay = 0
|
||||||
item.startDay = @maxa item.depends.map(@toActivity).map @calculateEndDay
|
else
|
||||||
@log "start day of",item.id,"is",item.startDay
|
async.map item.depends.map(@toActivity), @calculateEndDay.bind(@), (er, r) =>
|
||||||
# write max delay time to each depend
|
item.startDay = @maxa r
|
||||||
for j,x of item.depends
|
@log "start day of",item.id,"is",item.startDay
|
||||||
@log "checking permittedDelay to dependency", x, "of", item
|
# write max delay time to each depend
|
||||||
i = @toActivity x
|
checkPermittedDelay = (x,c) =>
|
||||||
if !i.dependant? then i.dependant = [item.id]
|
@log "checking permittedDelay to dependency", x, "of", item
|
||||||
else i.dependant.push item.id
|
i = @toActivity x
|
||||||
if !i.permittedDelay?
|
if !i.dependant? then i.dependant = [item.id]
|
||||||
i.permittedDelay = item.startDay - @calculateEndDay i
|
else i.dependant.push item.id
|
||||||
@log "written permittedDelay to dependency", x, "of", item, "as", i.permittedDelay
|
if !i.permittedDelay?
|
||||||
else @log "aborting permittedDelay: already calculated"
|
@calculateEndDay i, (e,d) =>
|
||||||
@log "permitted delay of",x,"is",i.permittedDelay
|
i.permittedDelay = item.startDay - d
|
||||||
@insertDay item.startDay
|
@log "written permittedDelay to dependency", x, "of", item, "as", i.permittedDelay
|
||||||
return item.startDay
|
@log "permitted delay of",x,"is",i.permittedDelay
|
||||||
|
c()
|
||||||
|
else
|
||||||
|
@log "aborting permittedDelay: already calculated"
|
||||||
|
@log "permitted delay of",x,"is",i.permittedDelay
|
||||||
|
c()
|
||||||
|
async.each item.depends, checkPermittedDelay.bind(@), =>
|
||||||
|
@insertDay item.startDay
|
||||||
|
cb null, item.startDay
|
||||||
|
|
||||||
calculateDelays: (item) =>
|
calculateDelays: (item,cb) =>
|
||||||
if !item.dependant? or item.dependant.length is 0 then return no
|
if !item.dependant? or item.dependant.length is 0 then cb null, no
|
||||||
lowestFDelay = 0; fDelay = no; cDelay = 0
|
else
|
||||||
for j,i of item.dependant
|
lowestFDelay = 0; fDelay = no; cDelay = 0
|
||||||
x = @toActivity i
|
checkDependant = (i,c) =>
|
||||||
if !isNaN(x.permittedDelay) or x.permittedDelay < lowestFDelay or fDelay is no
|
x = @toActivity i
|
||||||
@log "activity", i, "dependant on", item.id, "has the lowest delay for now ("+(x.permittedDelay or 0)+")"
|
if !isNaN(x.permittedDelay) or x.permittedDelay < lowestFDelay or fDelay is no
|
||||||
lowestFDelay = x.permittedDelay or 0
|
@log "activity", i, "dependant on", item.id, "has the lowest delay for now ("+(x.permittedDelay or 0)+")"
|
||||||
cDelay = x.chainedDelay or 0
|
lowestFDelay = x.permittedDelay or 0
|
||||||
fDelay = yes
|
cDelay = x.chainedDelay or 0
|
||||||
olDelay = item.chainedDelay
|
fDelay = yes
|
||||||
item.chainedDelay = lowestFDelay + cDelay
|
c()
|
||||||
@log "chained delay of", item.id, "is", item.chainedDelay
|
async.each item.dependant, checkDependant.bind(@), =>
|
||||||
return item.chainedDelay isnt olDelay
|
olDelay = item.chainedDelay
|
||||||
|
item.chainedDelay = lowestFDelay + cDelay
|
||||||
|
@log "chained delay of", item.id, "is", item.chainedDelay
|
||||||
|
cb null, item.chainedDelay isnt olDelay
|
||||||
|
|
||||||
calculateCriticalPaths: (path) ->
|
calculateCriticalPaths: (path,cb) ->
|
||||||
@log "calculating path from",path
|
@log "calculating path from",path
|
||||||
lastID = path[path.length - 1]
|
lastID = path[path.length - 1]
|
||||||
last = @toActivity lastID
|
last = @toActivity lastID
|
||||||
if last.dependant? and last.dependant.length > 0
|
if last.dependant? and last.dependant.length > 0
|
||||||
last.dependant.forEach (x) =>
|
checkDependant = (x,cb2) =>
|
||||||
ii = @toActivity x
|
ii = @toActivity x
|
||||||
delay = ii.permittedDelay or 0
|
delay = ii.permittedDelay or 0
|
||||||
if delay is 0
|
if delay is 0
|
||||||
@calculateCriticalPaths path.concat x
|
cb2 null, yes
|
||||||
|
@calculateCriticalPaths path.concat(x), cb
|
||||||
else
|
else
|
||||||
@log "dead end at", lastID, "-->", x, "because delay is", delay
|
@log "dead end at", lastID, "-->", x, "because delay is", delay
|
||||||
|
cb2 null, no
|
||||||
|
async.each last.dependant, checkDependant.bind(@), (a,b) -> return
|
||||||
else
|
else
|
||||||
path.forEach (x) => @toActivity(x).critical = yes
|
setCritical = (x,c) =>
|
||||||
@log "calculated path", path
|
@toActivity(x).critical = yes
|
||||||
@criticalPaths.push path
|
c null, yes
|
||||||
|
async.each path, setCritical.bind(@), =>
|
||||||
|
@log "calculated path", path
|
||||||
|
@criticalPaths.push path
|
||||||
|
cb null, path
|
||||||
|
|
||||||
# Find out which activity has the highest id
|
# Find out which activity has the highest id
|
||||||
highestID: => return @maxa(@list.map (x) -> x.id)
|
highestID: => return @maxa(@list.map (x) -> x.id)
|
||||||
@ -100,26 +122,41 @@ class PBS
|
|||||||
setData: (data) ->
|
setData: (data) ->
|
||||||
@list = data
|
@list = data
|
||||||
return @
|
return @
|
||||||
|
|
||||||
calculate: (options,cb) ->
|
calculate: (options,cb) ->
|
||||||
h = @highestID()
|
@log "(Step 1) calculating startDay, endDay, freeDelay"
|
||||||
for x,i in @list
|
async.each @list, @calculateEndDay.bind(@), =>
|
||||||
@log '('+x.id+'/'+h+')'
|
@log "(Step 2) Starting chained delay calculations."
|
||||||
@calculateEndDay x
|
cont = yes; i = 0
|
||||||
finished = no; i = 0
|
notDone = ->
|
||||||
while !finished
|
console.log cont
|
||||||
i++; finished = yes
|
cont
|
||||||
for x,i in @list
|
chainedDelayChanged = (x,res) =>
|
||||||
if @calculateDelays x
|
i++
|
||||||
finished = no
|
cont = no
|
||||||
@log "Done calculating delays. Took", i, "iterations"
|
@calculateDelays x, (e,r) =>
|
||||||
for x,i in @list
|
@log "cDelay calc result:",r
|
||||||
if !x.depends? or x.depends.length is 0
|
res null, r
|
||||||
@calculateCriticalPaths [x.id]
|
calculateAllDelays = (cb2) =>
|
||||||
results = activities: @list, days: @days, criticalPaths: @criticalPaths
|
async.map @list, chainedDelayChanged, (err,r) ->
|
||||||
if options?.json
|
iterator = (acc,x,cb3) ->
|
||||||
if cb? then cb(JSON.stringify results)
|
if x
|
||||||
JSON.stringify results
|
cb3 null, yes
|
||||||
else
|
else cb3 null, acc
|
||||||
if cb? then cb(results)
|
async.reduce r, no, iterator, (err,res) ->
|
||||||
results
|
cont = res
|
||||||
|
cb2 null
|
||||||
|
#TODO: check WHILST
|
||||||
|
async.whilst notDone, calculateAllDelays, =>
|
||||||
|
@log "Done calculating delays. Took", i, "iterations"
|
||||||
|
#TODO: check THIS vvvvv
|
||||||
|
calculateCriticalPathIfApplicable = (x, c) =>
|
||||||
|
if !x.depends? or x.depends.length is 0
|
||||||
|
@calculateCriticalPaths [x.id], c
|
||||||
|
async.each @list, calculateCriticalPathIfApplicable.bind(@), =>
|
||||||
|
results = activities: @list, days: @days, criticalPaths: @criticalPaths
|
||||||
|
@log "DONE:", results
|
||||||
|
if options?.json
|
||||||
|
cb JSON.stringify results
|
||||||
|
else
|
||||||
|
cb results
|
||||||
|
@ -46,13 +46,15 @@ pertController = ($scope) ->
|
|||||||
localStorage.setItem 'ganttpert', sdata
|
localStorage.setItem 'ganttpert', sdata
|
||||||
unless options.silent
|
unless options.silent
|
||||||
swal 'Ok', 'Data updated', 'success'
|
swal 'Ok', 'Data updated', 'success'
|
||||||
$scope.pbs = new PBS(data).calculate()
|
$scope.pbs = new PBS(data).calculate {}, ->
|
||||||
$scope.$broadcast 'dataChanged'
|
$scope.$broadcast 'dataChanged'
|
||||||
catch e
|
catch e
|
||||||
swal 'Error', e, 'error'
|
swal 'Error', e, 'error'
|
||||||
|
|
||||||
$scope.fromLocalStorage = (options) ->
|
$scope.fromLocalStorage = (options,cb) ->
|
||||||
options = options || {}
|
options = options || {}
|
||||||
|
if options.call? then cb = options
|
||||||
|
else unless cb?.call? then return console.log "fromLocalStorage called without callback"
|
||||||
data = localStorage.getItem options.name || 'ganttpert'
|
data = localStorage.getItem options.name || 'ganttpert'
|
||||||
if data is null then data = "[]"
|
if data is null then data = "[]"
|
||||||
try
|
try
|
||||||
@ -63,13 +65,15 @@ pertController = ($scope) ->
|
|||||||
swal 'JSON Error', e, 'error'
|
swal 'JSON Error', e, 'error'
|
||||||
if options.raw
|
if options.raw
|
||||||
#console.log 'Loading: []'
|
#console.log 'Loading: []'
|
||||||
return []
|
cb []
|
||||||
else
|
else
|
||||||
#console.log 'Loading: {list: [], days: []}'
|
#console.log 'Loading: {list: [], days: []}'
|
||||||
return list: [], days: []
|
cb list: [], days: []
|
||||||
if options.raw
|
if options.raw
|
||||||
#console.log 'Loading: '+jdata
|
#console.log 'Loading: '+jdata
|
||||||
return jdata
|
cb jdata
|
||||||
else
|
else
|
||||||
#console.log 'Loading: '+$scope.pbs
|
#console.log 'Loading: '+$scope.pbs
|
||||||
return $scope.pbs ?= new PBS(jdata).calculate()
|
new PBS(jdata).calculate (x) ->
|
||||||
|
$scope.pbs = x
|
||||||
|
cb x
|
||||||
|
@ -1,9 +1,8 @@
|
|||||||
pertApp.controller 'tableController', ($scope) ->
|
pertApp.controller 'tableController', ($scope) ->
|
||||||
$scope.list = []
|
$scope.list = []
|
||||||
$scope.refreshTable = ->
|
$scope.refreshTable = ->
|
||||||
ls = $scope.fromLocalStorage()
|
$scope.fromLocalStorage (ls) ->
|
||||||
if ls?
|
if ls? then $scope.list = ls.activities
|
||||||
$scope.list = ls.activities
|
|
||||||
$scope.$on 'dataChanged', $scope.refreshTable
|
$scope.$on 'dataChanged', $scope.refreshTable
|
||||||
$scope.refreshTable()
|
$scope.refreshTable()
|
||||||
|
|
||||||
@ -32,7 +31,7 @@ pertApp.controller 'pertDiagController', ($scope) ->
|
|||||||
network = new vis.Network (document.getElementById 'pertDiagram'), { nodes: nodes, edges: connections }, options
|
network = new vis.Network (document.getElementById 'pertDiagram'), { nodes: nodes, edges: connections }, options
|
||||||
$scope.rebuild = ->
|
$scope.rebuild = ->
|
||||||
console.log 'rebuild'
|
console.log 'rebuild'
|
||||||
$scope.buildGraph $scope.fromLocalStorage()
|
$scope.fromLocalStorage (r) -> $scope.buildGraph r
|
||||||
$scope.$on 'dataChanged', $scope.rebuild
|
$scope.$on 'dataChanged', $scope.rebuild
|
||||||
$scope.rebuild()
|
$scope.rebuild()
|
||||||
|
|
||||||
@ -47,8 +46,8 @@ pertApp.controller 'ganttDiagController', ($scope) ->
|
|||||||
if !data? then return
|
if !data? then return
|
||||||
timeline = new vis.Timeline (document.getElementById 'timeline'), ($scope.toDates data.activities), {}
|
timeline = new vis.Timeline (document.getElementById 'timeline'), ($scope.toDates data.activities), {}
|
||||||
$scope.$on 'dataChanged', ->
|
$scope.$on 'dataChanged', ->
|
||||||
$scope.buildTimeline $scope.fromLocalStorage()
|
$scope.fromLocalStorage (r) -> $scope.buildTimeline r
|
||||||
$scope.buildTimeline $scope.fromLocalStorage()
|
$scope.fromLocalStorage (r) -> $scope.buildTimeline r
|
||||||
|
|
||||||
pertApp.controller 'rawEditorController', ($scope) ->
|
pertApp.controller 'rawEditorController', ($scope) ->
|
||||||
$scope.reset = ->
|
$scope.reset = ->
|
||||||
@ -60,10 +59,9 @@ pertApp.controller 'rawEditorController', ($scope) ->
|
|||||||
swal 'Invalid Data', e, 'error'
|
swal 'Invalid Data', e, 'error'
|
||||||
$scope.toLocalStorage data
|
$scope.toLocalStorage data
|
||||||
$scope.reloadData = ->
|
$scope.reloadData = ->
|
||||||
$scope.taData = JSON.stringify $scope.fromLocalStorage silent: yes, raw: yes
|
$scope.fromLocalStorage { silent: yes, raw: yes }, (x) ->
|
||||||
$scope.$on 'dataChanged', ->
|
$scope.taData = JSON.stringify x
|
||||||
$scope.reloadData()
|
$scope.$on 'dataChanged', -> $scope.reloadData()
|
||||||
#$('#ta').val JSON.stringify $scope.fromLocalStorage silent: yes, raw: yes
|
|
||||||
$scope.reloadData()
|
$scope.reloadData()
|
||||||
|
|
||||||
pertApp.controller 'editorController', ($scope) ->
|
pertApp.controller 'editorController', ($scope) ->
|
||||||
@ -77,18 +75,18 @@ pertApp.controller 'editorController', ($scope) ->
|
|||||||
swal 'Ops', 'could not find '+id, 'warning'
|
swal 'Ops', 'could not find '+id, 'warning'
|
||||||
|
|
||||||
$scope.delete = (index,id) ->
|
$scope.delete = (index,id) ->
|
||||||
newdata = $scope.fromLocalStorage raw: yes
|
$scope.fromLocalStorage { raw: yes }, (newdata) ->
|
||||||
l = []
|
l = []
|
||||||
if id? then for i,j of newdata
|
if id? then for i,j of newdata
|
||||||
if id isnt j.id
|
if id isnt j.id
|
||||||
l.push j
|
l.push j
|
||||||
else for i,j of newdata
|
else for i,j of newdata
|
||||||
if parseInt(i) isnt index
|
if parseInt(i) isnt index
|
||||||
l.push j
|
l.push j
|
||||||
diff = newdata.length - l.length
|
diff = newdata.length - l.length
|
||||||
$scope.toLocalStorage l, silent: yes
|
$scope.toLocalStorage l, silent: yes
|
||||||
if diff isnt 1
|
if diff isnt 1
|
||||||
swal 'Done', diff+' item(s) deleted', 'warning'
|
swal 'Done', diff+' item(s) deleted', 'warning'
|
||||||
|
|
||||||
$scope.addNew = (id, dur, deps) ->
|
$scope.addNew = (id, dur, deps) ->
|
||||||
dur ?= $('#new-duration').val().trim()
|
dur ?= $('#new-duration').val().trim()
|
||||||
@ -109,14 +107,14 @@ pertApp.controller 'editorController', ($scope) ->
|
|||||||
unless isNaN dep
|
unless isNaN dep
|
||||||
deps[i] = parseInt dep
|
deps[i] = parseInt dep
|
||||||
catch e
|
catch e
|
||||||
newdata = $scope.fromLocalStorage silent: yes, raw: yes
|
$scope.fromLocalStorage { silent: yes, raw: yes }, (newdata) ->
|
||||||
if !newdata? or newdata is null or !newdata.push?
|
if !newdata? or newdata is null or !newdata.push?
|
||||||
newdata = []
|
newdata = []
|
||||||
newdata.push { id: id, duration: dur, depends: deps }
|
newdata.push { id: id, duration: dur, depends: deps }
|
||||||
$scope.toLocalStorage newdata, silent: yes
|
$scope.toLocalStorage newdata, silent: yes
|
||||||
|
|
||||||
$scope.refreshEditor = ->
|
$scope.refreshEditor = ->
|
||||||
data = $scope.fromLocalStorage { silent: yes, raw: yes }
|
$scope.fromLocalStorage { silent: yes, raw: yes }, (data) ->
|
||||||
$scope.list = data || []
|
$scope.list = data || []
|
||||||
$scope.$on 'dataChanged', $scope.refreshEditor
|
$scope.$on 'dataChanged', $scope.refreshEditor
|
||||||
$scope.refreshEditor()
|
$scope.refreshEditor()
|
||||||
|
@ -9,6 +9,7 @@
|
|||||||
<link rel="stylesheet" href="style.css">
|
<link rel="stylesheet" href="style.css">
|
||||||
<link rel="stylesheet" href="sweet-alert.css">
|
<link rel="stylesheet" href="sweet-alert.css">
|
||||||
<script src="jquery.js"></script>
|
<script src="jquery.js"></script>
|
||||||
|
<script src="async.js"></script>
|
||||||
<script src="sweet-alert.js"></script>
|
<script src="sweet-alert.js"></script>
|
||||||
<script src="angular.js"></script>
|
<script src="angular.js"></script>
|
||||||
<script src="bootstrap.js"></script>
|
<script src="bootstrap.js"></script>
|
||||||
|
Loading…
Reference in New Issue
Block a user