Home

Awesome

reagent-flowgraph

A reagent component for laying out tree nodes in 2D space. If you are not using reagent but want to draw trees your own way check clj-tree-layout.

Features

Installation

Clojars Project

Usage

(ns tester.core
  (:require [reagent.core :as r]
            [reagent-flowgraph.core :refer [flowgraph]]))

(defonce app-state (r/atom '(+ 1 2 (- 4 2) (/ 123 3) (inc 25))))

(defn app []
  [:div
   [flowgraph @app-state
    :layout-width 1500
    :layout-height 500
    :branch-fn #(when (seq? %) %)
    :childs-fn #(when (seq? %) %)
    :render-fn (fn [n] [:div {:style {:border "1px solid black"
                                      :padding "10px"
                                      :border-radius "10px"}}
                        (str n)] )]])

(defn init []
  (r/render [app] (.getElementById js/document "app")))

and that will render

<img src="/doc/images/reagent-tree-example-simple.png?raw=true"/>

A more colorful example. Supouse we want to draw some aspects of the clojurescript analyzer output tree.

(ns tester.core
  (:require [reagent.core :as r]
            [reagent-flowgraph.core :refer [flowgraph]]
            [cljs.js :as j]))

(defonce app-state (r/atom {}))

(defmulti render-node :op)

(def styles {:border "1px solid #586e75" :padding "10px" :border-radius "10px"
             :background-color "#002b36" :color "#B58900"})

(defmethod render-node :fn [n]
  [:div {:style (merge styles {:color "#DC322F"})}
    [:b (str "(" (:name (:name n)) " ...)")]])

(defmethod render-node :if [{:keys [then test else]}]
  [:div {:style (merge styles {:color "#CB4B16"})}
   [:div {:style {:text-align :center}} [:b "IF"]]
   [:div {:style {:display :flex}}
    [:div.if-test [:b "test"] [:div (str "'" (:form test) "'")]]
    [:div.if-then [:b "then"] [:div (str "'" (:form then) "'")]]
    [:div.if-else [:b "else"] [:div (str "'" (:form else) "'")]]]])

(defmethod render-node :default [n]
  [:div {:style styles} (str ":op " (:op n))])

(defn app []
  [:div {:style {:background-color "#002b36"}}
   [flowgraph @app-state
    :layout-width 500
    :layout-height 1500
    :branch-fn :children
    :childs-fn :children
    :render-fn render-node
    :line-styles {:stroke-width 2
                  :stroke "#CB4B16"}]])

(defn init []
  (r/render [app] (.getElementById js/document "app"))

  (j/analyze-str (j/empty-state)
                 "(defn factorial [n]
                     (if (zero? n)
                        1
                        (* n (factorial (dec n)))))"
                 #(reset! app-state (:value %))))

which will render

<img src="/doc/images/reagent-tree-example-custom.png?raw=true"/>

Options

:layout-width

An integer representing the width of the layout panel.

:layout-height

An integer representing the height of the layout panel.

:branch-fn

Is a fn that, given a node, returns true if can have children, even if it currently doesn't.

:childs-fn

Is a fn that, given a branch node, returns a seq of its children.

:render-fn

A one parameter fn that can be used as a reagent component. Will receive the full node as a parameter.

:line-styles

A map with styles for the svg lines that join nodes.

How does it works?

The trick is in rendering all nodes twice. The action goes like this :