Skip to content

maxi-k/drawer

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

Drawer

What’s this?

A web-site for drawing polygons, polyhedra and polychora, written in ClojureScript. This is a complementary program for my essay “Rotation and Mirroring in the plane R2, the Space R3 and the Hyperspace R4”, which I created in the course of the seminar “Polygons, Polyhedra and Polychora”. The writing of a scientific essay as part of a seminar is part of the graduation from German high school, the Abitur.

Controls

  • ALT: Change the active camera (There are two cameras because there are 4 dimensions)
  • RIGHT ARROW: Decreases the active camera’s x-position (‘moving the screen content to the left’)
  • LEFT ARROW: Increases the active camera’s x-position (‘moving the screen content to the right’)
  • UP ARROW: Decreases the active camera’s y-position (‘moving the screen content down’)
  • DOWN ARROW: Increases the active camera’s y-position (‘moving the screen content up’)
  • PAGE UP: Decreases the active camera’s z-position (‘zooming in’) [mac: fn-up]
  • PAGE DOWN: Increases the active camera’s z-position (‘zooming out’) [mac: fn-down]
  • HOME: Decreases the active camera’s w-position (‘zooming into the 4th dimension’) [mac: fn-left]
  • END: Increases the active camera’s w-position (‘zooming out of the 4th dimension’) [mac: fn-right]

HOME and END only have a visible effect when manipulating camera 1, because it is the one projecting 4D to 3D

Technologies/Packages

Everything is written in ClojureScript. There’s no JavaScript.

Used for various things where asynchronous or timed actions are required. Most notably, it is used for the main ‘rendering loop’ updating the canvas:

;; From core.cljs, edited
(go (while true
      (<! (timeout fps))
      (update-canvas (canvas/get-canvas-update))))

Or for smoothly fading in a growl-style message div, showing it for given time, and then fading it out again:

;; From api.cljs, unedited
(defn ^:export showMessage
  "Shows the message div with given message for
  'time' milliseconds and then hides it again.
  Accesses the state through given action."
  ([action msg] (showMessage action msg 2500))
  ([action msg time]
     (let [step 0.05
           times (/ 1.0 step)
           fps 1]
       (go (action #(assoc-in % [:message :value] msg))
           (doseq [i (range times)]
             (<! (timeout fps))
             (action #(update-in % [:message :opacity] + step)))
           (action #(assoc-in % [:message :opacity] 1.0))
           (<! (timeout time))
           (doseq [i (range (inc times))]
             (<! (timeout fps))
             (action #(update-in % [:message :opacity] - step)))
           (action #(assoc-in % [:message :opacity] 0))
           (action #(assoc-in % [:message :value] ""))))))

Used for rendering everything. Nothing is done in html itself:

/* From index.html */
  <body>
    <script> drawer.core.init() </script>
  </body>

The html tree is defined in a hiccup-style syntax:

;; From gui.cljs, unedited
(defn body
  "Combining all components into the body component."
  [state action]
  [:div#body-wrapper
   (prompt action)
   (controls state action)
   (canvas (@state :canvas))
   [:div.clearfloat]
   (message (@gui-state :message))])

(defn init-gui
  "Initialize the gui rendering."
  [state user-action]
  (r/render-component [(fn [] (body state user-action))]
                      (.-body js/document)))

Converts clojure(script) data to json ad vice versa. Used for html5 local storage

;; From util.cljs, unedited
(defn store-locally
  "Stores given object in the
  html5 localStorage.
  Use fetch to get it again."
  [k obj]
  (.setItem js/localStorage k (clj->cljson obj)))

(defn fetch-local
  "Fetches a locally stored object
  with given key and converts it
  into a clojure data-structure."
  [k default]
  (if-let [item (.getItem js/localStorage k)]
    (cljson->clj item)
    default))