Skip to content

Instantly share code, notes, and snippets.

@stathissideris
Created December 4, 2015 17:38
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save stathissideris/5b55c7e805fe3a44f7b1 to your computer and use it in GitHub Desktop.
Save stathissideris/5b55c7e805fe3a44f7b1 to your computer and use it in GitHub Desktop.
(ns bsq.arch
(:require [dali.io :as dio]
[dali.layout :as l]
[dali.layout.utils :refer [place-by-anchor bounds->anchor-point]]
dali.layout.stack
dali.layout.distribute
dali.layout.align
dali.layout.connect
dali
[dali.syntax :as d]
[dali.geom :as geom]
[dali.prefab :as prefab]
[dali.utils :as utils]
[garden.core :refer [css]]
[clojure.string :as string]
[net.cgrand.enlive-html :as en]))
(def circle-radius 50)
(defmethod l/layout-nodes :surround
[_ {{:keys [attrs padding]} :attrs} elements bounds-fn]
(let [padding (or padding 20)
bounds (map bounds-fn elements)
min-x (apply min (map (fn [[_ [x y] [w h]]] x) bounds))
min-y (apply min (map (fn [[_ [x y] [w h]]] y) bounds))
max-x (apply max (map (fn [[_ [x y] [w h]]] (+ x w)) bounds))
max-y (apply max (map (fn [[_ [x y] [w h]]] (+ y h)) bounds))
x min-x
y min-y
w (- max-x min-x)
h (- max-y min-y)]
[(d/dali->ixml
[:rect (merge attrs {:dali/path :append})
[(- x padding) (- y padding)]
[(+ w (* 2 padding)) (+ h (* 2 padding))]
10])]))
(dali/register-layout-tag :surround)
(defmethod l/layout-nodes :place
[doc {{:keys [offset relative-to location]} :attrs} elements bounds-fn]
(let [relative-to-el (first (en/select doc [(keyword (str "#" (name relative-to)))]))
_ (when-not relative-to-el
(throw (ex-info "Cannot find element" {:element relative-to
:document doc})))
element (first elements)
offset (or offset [0 0])]
[(place-by-anchor element
:top
(geom/v+ offset (bounds->anchor-point :bottom (bounds-fn relative-to-el)))
(bounds-fn element))]))
(dali/register-layout-tag :place)
(defn text-stack [texts]
(vec (concat [:stack {:direction :down :gap 6}]
(map #(vector :text {:font-family "Verdana" :font-size 14} %) texts))))
(defn circle-text
([id text cl]
(circle-text id text cl nil))
([id text cl radius]
(let [radius (or radius circle-radius)]
[:align {:axis :center}
[:circle {:id id :class cl :filter "url(#ds)"} :_ radius]
(text-stack (string/split-lines text))])))
(defn text-box
([id text cl]
(text-box id text cl [20 20]))
([id text cl pos]
[:g {}
[:align {:axis :center}
[:rect {:id id :class [cl :box-text] :filter "url(#ds)"} pos [80 80] 10]
(text-stack (string/split-lines text))]]))
(defn tool-box
([id text cl pos]
(assoc-in (text-box id text cl pos) [1 :class] :dep)))
(defn circle-stack [id & circle-texts]
[:stack {:id id :direction :down :gap 25}
(for [[id text cl radius] circle-texts]
(circle-text id text cl radius))])
(defn label-box [id selector label]
(let [box-id (utils/keyword-concat id :-box)
text-id (utils/keyword-concat id :-text)]
(list
[:surround {:select selector
:padding 25
:attrs {:class :file :id box-id :dali/z-index -2}}]
[:text {:id text-id :font-family "Verdana" :font-size 18} label]
[:place {:select text-id :relative-to box-id :offset [0 15]}])))
(defn connect
([from to]
(connect from to {}))
([from to attrs]
[:connect (merge {:from from :to to :dali/marker-end :arrow-head} attrs)]))
(def nov-arch
(let [faint-grey "#777777"
dep {:stroke-dasharray [7 7]
:dali/z-index -1
:dali/marker-end {:id :arrow-head :fill faint-grey}
:dali/marker-group-attrs {:class :dep}}
dep-corner (assoc dep :type :|-)]
[:page
[:defs
(prefab/drop-shadow-effect :ds {:opacity 0.3 :offset [5 5] :radius 6})
(prefab/curvy-arrow-marker :arrow-head {:scale 1.5})
(d/css (css [[:.dep {:display :block}]
[:circle {:fill :none :stroke faint-grey}]
[:g.dep [:polyline {:stroke faint-grey}]]
[:.box-text {:stroke :black}]
[:polyline {:stroke :black}]
[:.main-fun {:fill "#bf9af2"}]
[:.corp-fun {:fill "#e1cca1"}]
[:.tool {:fill "#bffdc7"}]
[:.file {:fill "#00c3cf" :stroke "#00acb6"}]
[:.button {:fill "#ffffff"}]
[:.connector {:fill :none}]]))]
[:text {:font-family "Georgia" :font-size 30 :x 50 :y 60}
"Architecture Overview (1/12/2015)"]
(text-box :deps-toggle "show\ntools" :button [1200 20])
[:stack {:direction :right :gap 60 :position [30 500]}
(circle-text :maintenance "corp\nmaintenance" :corp-fun)
(circle-text :extraction "extraction" [:main-fun :extractor])
(circle-text :importing "importing" [:main-fun :extractor])
(circle-text :enrichment "enrichment" [:main-fun :extractor])
(circle-stack :limits-clj
[:limits "limits" :main-fun]
[:corp-targets "corp targets" :corp-fun])
(circle-stack :incidents-clj
[:limits-grouping "limits\ngrouping" :main-fun]
[:corp-targets-grouping "corp\ntargets\ngrouping" :corp-fun])
(circle-stack :reporter-clj
[:limits-reporting "limits\nreporting" :main-fun]
[:corp-targets-reporting "corp\ntargets\nreporting" :corp-fun])
(circle-text :corp-actions "corp\nactions" :corp-fun)]
[:distribute {:direction :right :gap 120}
(tool-box :sc "Site\nCatalyst\ntools" :tool [200 210])
(tool-box :postgres "Postgres\nstorage\ntools" :tool [0 210])
(tool-box :r "R\ntools" :tool [0 210])
(tool-box :jira "Jira\ntools" :tool [0 150])]
(label-box :extractor [:.extractor] "extractor")
(label-box :limits-clj [:#limits-clj] "limits.clj")
(label-box :incidents-clj [:#incidents-clj] "incidents.clj")
(label-box :reporter-clj [:#reporter-clj] "reporter.clj")
;;data flow
(connect :maintenance :extraction)
(connect :extraction :importing)
(connect :importing :enrichment)
(connect :enrichment :limits)
(connect :enrichment :corp-targets)
(connect :limits :limits-grouping)
(connect :corp-targets :corp-targets-grouping)
(connect :limits-grouping :limits-reporting)
(connect :corp-targets-grouping :corp-targets-reporting)
(connect :corp-targets-reporting :corp-actions)
;;deps
(connect :importing :postgres dep)
(connect :enrichment :postgres dep)
(connect :limits-clj-box :postgres dep-corner)
(connect :limits :r dep)
(connect :maintenance :jira dep-corner)
(connect :extraction :sc dep-corner)
(connect :corp-actions :jira dep-corner)
(d/javascript
(string/join
"\n"
["function toggleDeps() {"
" s = document.styleSheets[0].cssRules[0].style;"
" if(s.display == 'block') { s.display = 'none' } else {s.display = 'block'}"
"}"
"document.getElementById('deps-toggle').addEventListener('click', toggleDeps);"]))]))
(defn render []
(-> nov-arch
d/dali->ixml
l/resolve-layout
d/ixml->xml
(dio/spit-svg "resources/nov-arch-demo.svg")))
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment