用榆树自动甘特图行编号
automatic gantt line numbering with elm
我在 python 很久以前就已经完成了一个功能。
我以无法用 elm 重现的特定方式绘制甘特图。
这是我的代码:
https://ellie-app.com/8sYLsxTZHk5a1
问题出在我尝试设置任务行的 "calcTaskPosition" 函数中。
calcTaskPosition : Int -> Task -> List(Task)
calcTaskPosition row task =
let
precs = List.concatMap (calcTaskPosition (row+1)) (taskPrecs task)
in
{ task | col = (Maybe.withDefault -1 <|
List.maximum <|
List.map (\t -> t.col) precs) + 1
--, row = row
}
:: precs
在我的示例中,任务行由 initTask 函数设置。
我希望获得相同的任务顺序,而不必在 initTask 函数中设置明确的行位置。
第一个线索是,当您查看 svg 时,您会注意到 "task1" 实际上被渲染了两次。如果您取消注释您发布的代码段中的行 --, row = row
,这将更容易看到。
在 elm(和其他函数式语言)中,您的任务不会就地操作,而是在您改变它们时复制您的任务。因此,在模型中保留 col 和 row 值(目前)并不是很有用。
此外,使用任务 ID 比直接链接对象更有意义。
考虑到这一点,我将创建两种不同的任务记录:一种用于将其保存在模型中(在我的示例中为 Task
),另一种用于渲染它(我称之为 DrawableTask
) .
然后你需要一个像
这样的转换函数
toDrawableListOfTasks : List Task -> List DrawableTask
将在视图中调用。
转换函数本质上使用你的tasksNotInTaskPrecs
,你select所有可以立即绘制的任务(因为它们的precs列表是空的)。我将它概括化并称之为 allDependenciesMet
,并在每次迭代中使用它来 select 可以绘制的任务。
所有可以绘制的任务都将添加到一个临时列表(在我的例子中是一个用于快速查找已输入任务的字典),然后下一次迭代从所有尚未绘制的任务开始。
当没有剩余任务时,您可以 return 列表,渲染过程将再次遍历列表。
order : Temp -> List Task -> List DrawableTask
order temp todo =
case List.partition (allDependenciesMet temp) todo of
( [], [] ) ->
-- We are done and can return the list
Dict.values temp
|> List.sortBy .row
( [], _ ) ->
Debug.todo "An invalid list of tasks was passed"
( drawableTasks, nextTodo ) ->
let
nextTemp =
List.indexedMap (toDrawable temp) drawableTasks
|> List.map (\t -> ( t.id, t ))
|> Dict.fromList
|> Dict.union temp
in
order nextTemp nextTodo
我不确定这是否可以理解,但你应该可以理解https://ellie-app.com/8tdzrgLfBfya1
我在 python 很久以前就已经完成了一个功能。
我以无法用 elm 重现的特定方式绘制甘特图。
这是我的代码: https://ellie-app.com/8sYLsxTZHk5a1
问题出在我尝试设置任务行的 "calcTaskPosition" 函数中。
calcTaskPosition : Int -> Task -> List(Task)
calcTaskPosition row task =
let
precs = List.concatMap (calcTaskPosition (row+1)) (taskPrecs task)
in
{ task | col = (Maybe.withDefault -1 <|
List.maximum <|
List.map (\t -> t.col) precs) + 1
--, row = row
}
:: precs
在我的示例中,任务行由 initTask 函数设置。 我希望获得相同的任务顺序,而不必在 initTask 函数中设置明确的行位置。
第一个线索是,当您查看 svg 时,您会注意到 "task1" 实际上被渲染了两次。如果您取消注释您发布的代码段中的行 --, row = row
,这将更容易看到。
在 elm(和其他函数式语言)中,您的任务不会就地操作,而是在您改变它们时复制您的任务。因此,在模型中保留 col 和 row 值(目前)并不是很有用。
此外,使用任务 ID 比直接链接对象更有意义。
考虑到这一点,我将创建两种不同的任务记录:一种用于将其保存在模型中(在我的示例中为 Task
),另一种用于渲染它(我称之为 DrawableTask
) .
然后你需要一个像
toDrawableListOfTasks : List Task -> List DrawableTask
将在视图中调用。
转换函数本质上使用你的tasksNotInTaskPrecs
,你select所有可以立即绘制的任务(因为它们的precs列表是空的)。我将它概括化并称之为 allDependenciesMet
,并在每次迭代中使用它来 select 可以绘制的任务。
所有可以绘制的任务都将添加到一个临时列表(在我的例子中是一个用于快速查找已输入任务的字典),然后下一次迭代从所有尚未绘制的任务开始。 当没有剩余任务时,您可以 return 列表,渲染过程将再次遍历列表。
order : Temp -> List Task -> List DrawableTask
order temp todo =
case List.partition (allDependenciesMet temp) todo of
( [], [] ) ->
-- We are done and can return the list
Dict.values temp
|> List.sortBy .row
( [], _ ) ->
Debug.todo "An invalid list of tasks was passed"
( drawableTasks, nextTodo ) ->
let
nextTemp =
List.indexedMap (toDrawable temp) drawableTasks
|> List.map (\t -> ( t.id, t ))
|> Dict.fromList
|> Dict.union temp
in
order nextTemp nextTodo
我不确定这是否可以理解,但你应该可以理解https://ellie-app.com/8tdzrgLfBfya1