用榆树自动甘特图行编号

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