├── README.md
├── deps.edn
├── doc
└── images
│ ├── reagent-tree-example-custom.png
│ ├── reagent-tree-example-simple.png
│ └── reagent-tree.png
├── figwheel.edn
├── pom.xml
├── resources
└── public
│ ├── css
│ └── style.css
│ └── index.html
└── src
└── reagent_flowgraph
└── core.cljs
/README.md:
--------------------------------------------------------------------------------
1 | # reagent-flowgraph
2 |
3 | A reagent component for laying out tree nodes in 2D space.
4 | If you are not using reagent but want to draw trees your own way check [clj-tree-layout](https://github.com/jpmonettas/clj-tree-layout).
5 |
6 | ## Features
7 |
8 | - Tidy tree representations as per [Tilford and Reingold](http://hci.stanford.edu/cs448b/f09/lectures/CS448B-20091021-GraphsAndTrees.pdf)
9 | aesthetics rules.
10 | - Customizable node render function with any reagent component.
11 |
12 | ## Installation
13 |
14 | [](https://clojars.org/reagent-flowgraph)
15 |
16 | ## Usage
17 |
18 | ```clojure
19 | (ns tester.core
20 | (:require [reagent.core :as r]
21 | [reagent-flowgraph.core :refer [flowgraph]]))
22 |
23 | (defonce app-state (r/atom '(+ 1 2 (- 4 2) (/ 123 3) (inc 25))))
24 |
25 | (defn app []
26 | [:div
27 | [flowgraph @app-state
28 | :layout-width 1500
29 | :layout-height 500
30 | :branch-fn #(when (seq? %) %)
31 | :childs-fn #(when (seq? %) %)
32 | :render-fn (fn [n] [:div {:style {:border "1px solid black"
33 | :padding "10px"
34 | :border-radius "10px"}}
35 | (str n)] )]])
36 |
37 | (defn init []
38 | (r/render [app] (.getElementById js/document "app")))
39 | ```
40 |
41 | and that will render
42 |
43 |
44 |
45 | A more colorful example. Supouse we want to draw some aspects of the clojurescript analyzer output tree.
46 |
47 | ```clojure
48 | (ns tester.core
49 | (:require [reagent.core :as r]
50 | [reagent-flowgraph.core :refer [flowgraph]]
51 | [cljs.js :as j]))
52 |
53 | (defonce app-state (r/atom {}))
54 |
55 | (defmulti render-node :op)
56 |
57 | (def styles {:border "1px solid #586e75" :padding "10px" :border-radius "10px"
58 | :background-color "#002b36" :color "#B58900"})
59 |
60 | (defmethod render-node :fn [n]
61 | [:div {:style (merge styles {:color "#DC322F"})}
62 | [:b (str "(" (:name (:name n)) " ...)")]])
63 |
64 | (defmethod render-node :if [{:keys [then test else]}]
65 | [:div {:style (merge styles {:color "#CB4B16"})}
66 | [:div {:style {:text-align :center}} [:b "IF"]]
67 | [:div {:style {:display :flex}}
68 | [:div.if-test [:b "test"] [:div (str "'" (:form test) "'")]]
69 | [:div.if-then [:b "then"] [:div (str "'" (:form then) "'")]]
70 | [:div.if-else [:b "else"] [:div (str "'" (:form else) "'")]]]])
71 |
72 | (defmethod render-node :default [n]
73 | [:div {:style styles} (str ":op " (:op n))])
74 |
75 | (defn app []
76 | [:div {:style {:background-color "#002b36"}}
77 | [flowgraph @app-state
78 | :layout-width 500
79 | :layout-height 1500
80 | :branch-fn :children
81 | :childs-fn :children
82 | :render-fn render-node
83 | :line-styles {:stroke-width 2
84 | :stroke "#CB4B16"}]])
85 |
86 | (defn init []
87 | (r/render [app] (.getElementById js/document "app"))
88 |
89 | (j/analyze-str (j/empty-state)
90 | "(defn factorial [n]
91 | (if (zero? n)
92 | 1
93 | (* n (factorial (dec n)))))"
94 | #(reset! app-state (:value %))))
95 | ```
96 |
97 | which will render
98 |
99 |
100 |
101 | ## Options
102 |
103 | #### :layout-width
104 |
105 | An integer representing the width of the layout panel.
106 |
107 | #### :layout-height
108 |
109 | An integer representing the height of the layout panel.
110 |
111 | #### :branch-fn
112 |
113 | Is a fn that, given a node, returns true if can have
114 | children, even if it currently doesn't.
115 |
116 | #### :childs-fn
117 |
118 | Is a fn that, given a branch node, returns a seq of its
119 | children.
120 |
121 | #### :render-fn
122 |
123 | A one parameter fn that can be used as a reagent component. Will receive the full node
124 | as a parameter.
125 |
126 | #### :line-styles
127 |
128 | A map with styles for the svg lines that join nodes.
129 |
130 | ## How does it works?
131 |
132 | The trick is in rendering all nodes twice. The action goes like this :
133 |
134 | - Traverse the tree rendering every node using :render-fn.
135 | - Collect the width and height of every node.
136 | - Now we have node sizes we use a library like [clj-tree-layout](https://github.com/jpmonettas/clj-tree-layout) to calculate nodes positions.
137 | - With positions we can calculate edges.
138 | - Render everything again.
139 |
--------------------------------------------------------------------------------
/deps.edn:
--------------------------------------------------------------------------------
1 | {:deps {reagent {:mvn/version "0.8.0-alpha2"}
2 | clj-tree-layout {:mvn/version "0.1.0"}}
3 | :paths ["src" "resources" "test"]
4 | :aliases {:dev {:extra-deps {org.clojure/clojurescript {:mvn/version "1.10.238"}
5 | org.clojure/clojure {:mvn/version "1.9.0"}
6 | com.cemerick/piggieback {:mvn/version "0.2.2"}
7 | figwheel-sidecar {:mvn/version "0.5.15"}
8 | binaryage/devtools {:mvn/version "0.9.9"}
9 | philoskim/debux {:mvn/version "0.4.5"}}}}}
10 |
--------------------------------------------------------------------------------
/doc/images/reagent-tree-example-custom.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jpmonettas/reagent-flowgraph/9a26e2a123d45fcaf430fffc9fd141d00a791ea0/doc/images/reagent-tree-example-custom.png
--------------------------------------------------------------------------------
/doc/images/reagent-tree-example-simple.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jpmonettas/reagent-flowgraph/9a26e2a123d45fcaf430fffc9fd141d00a791ea0/doc/images/reagent-tree-example-simple.png
--------------------------------------------------------------------------------
/doc/images/reagent-tree.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jpmonettas/reagent-flowgraph/9a26e2a123d45fcaf430fffc9fd141d00a791ea0/doc/images/reagent-tree.png
--------------------------------------------------------------------------------
/figwheel.edn:
--------------------------------------------------------------------------------
1 | {:css-dirs ["resources/public/css"]
2 | :http-server-root "public" ;; default
3 | :server-port 3449 ;; default
4 | :builds [{:id "dev",
5 | :source-paths ["src"],
6 | :figwheel {:on-jsload "reagent-flowgraph.core/init"}
7 | :compiler
8 | {:main "reagent-flowgraph.core"
9 | :asset-path "js/out",
10 | :optimizations :none
11 | :preloads [devtools.preload]
12 | :output-to "resources/public/js/reagent-flowgraph.js",
13 | :output-dir "resources/public/js/out",
14 | :source-map-timestamp true}}]}
15 |
--------------------------------------------------------------------------------
/pom.xml:
--------------------------------------------------------------------------------
1 |
2 |