peterszerzo/elm-arborist

Tree-editing interface for Elm


Keywords
elm, tree-structure, visualization
License
MIT
Install
elm-package install peterszerzo/elm-arborist 2.3.0

Documentation

  🌲           🌲                             🌲          
 🌲🌲   🌲🌲 🌲      🌲   🌲  🌲   🌲     🌲  🌲      🌲🌲             🌲    
🌲🌲🌲  🌲🌲🌲 🌲  🌲🌲🌲 🌲🌲  🌲  🌲🌲🌲 🌲🌲🌲   🌲 🌲🌲        🌲🌲      🌲   

elm-arborist

Drag-and-drop interface to edit, dissect and-rearrange tree structures, with nodes holding any data type you wish. Here is a demo, and here some docs.

Getting started: a family tree

First things first, we need to specify what kind of data structure our tree's nodes will hold. For this demo, it'll be a tuple of names and ages.

type alias Node = ( String, Int )

exampleNode = ( "Frank", 54 )

We can then use the Arborist.Tree module to construct a tree structure:

import Arborist.Tree as Tree

tree =
  Arborist.node ( "Frank", 54 )
    [ Arborist.node ( "Mark", 36 ) []
    , Arborist.node ( "Sally", 31 )
        [ Arborist.node ( "Robert", 14 )
        ]
    ]

The tree is defined recursively, with each node holding an arbitrary number of children. This is similar to the binary tree example on the Elm website.

Anyway, we can now define a model Arborist can work with:

import Arborist

type alias Model = Arborist.Model Node

init : Model
init = Arborist.init tree

Notice how the model needs to know what data structure it holds, hence the type variable reference to the Node structure defined above.

The rest is pretty much standard Elm architecture:

type Msg = ArboristMsg Arborist.Msg

update msg model =
  case msg of
    ArboristMsg arboristMsg ->
      Arborist.update arboristMsg model

view model =
  Arborist.view nodeView [] model

The final missing piece is nodeView. It specifies how a node should be displayed, and has the following form:

-- Ignore `Context` for now
view : Context -> Maybe Node -> Html msg
view _ maybeNode =
  -- The node is not always available, because we also need to
  -- specify how placeholders are rendered. 
  case maybeNode of
    Just ( name, age ) ->
      div [] [ span [] [ text name ], span [] [ text (toString age) ] ]    
    Nothing ->
      div [] [ text "Insert node" ] 

That's it - your very own tree editor is ready.

Next steps: a glimpse

Context

The context object provides, as its name suggests, contextual information to the node when it is rendered, including their parent node and list of siblings (see Arborist.Context docs for details). You may for instance want to signal to the user that a child can't be older than their parent in the family tree as they edit it, but traversing the tree to find that information is tedious and inefficient - so Arborist gives you access to it directly.

This should work for a large number of tree editing cases. If you need a broader context, you will need to traverse the tree for it yourself.

Settings

Replace init with initWith [ Arborist.Settings.canvasWidth 800, Arborist.Settings.nodeHeight 40, Arborist.Settings.gutter 20 ] to add all kinds of customizations to the editor. See Arborist.Settings.

Animations

Using the Arborist.subscriptions, you can smoothly animate to center a node when it is activated. See example for details.

Styling

You can use styledView instead of view, taking StyledNodeView instead of NodeView if you wish to use elm-css to style your view. Arborist uses elm-css under the hood, as it was necessary for most realistic use-cases that came up with the library.

Please open an issue if first-class style-elements support is essential to your project.

🌲🌲🌲  🌲🌲🌲 🌲  🌲🌲🌲 🌲🌲  🌲  🌲🌲🌲 🌲🌲🌲   🌲 🌲🌲        🌲🌲      🌲   
 🌲🌲   🌲🌲 🌲      🌲   🌲  🌲   🌲     🌲  🌲      🌲🌲             🌲    
  🌲           🌲                             🌲