Chroma-Spirals

svgcolour

Rewrote python code [from Peter Derlien], in ClojureScript - see "The Pi-Cubed Programming Challenge : Golden Angle, Sunflowers and Chromospirals http://pi3.sites.sheffield.ac.uk/tutorials/week-2"

30 Mar 2013 by rm-hull
rm-hull/5278162
chroma-spirals.cljs
; chroma-spirals.cljs 
; loosely based on some python code written by Peter Derlien, University of Sheffield, March 2013
; Draws spiralling patterns of circles using the Golden Angle.
 
(ns chroma-spirals.demo
  (:use [monet.canvas :only [fill-style fill-rect circle rotate translate composition-operation]]
        [monet.core :only [animation-frame]]
        [enchilada :only [ctx canvas]]
        [chroma-spirals.color-chart :only [color-seq]]
        [jayq.core :only [show]]
        [dommy.core :only [insert-after! value]]
        [dommy.template :only [->node-like]])
  (:use-macros [dommy.macros :only [sel1 node]]))
        
(->> 
  (sel1 :#canvas-area)
  (insert-after! 
    (node 
      [:div#control-panel
       [:label {:for "colors"} "# Colors:"]
       [:select#colors (for [n (range 1 217)] [:option (if (= n 10) {:selected 1} {}) n])]
       [:label {:for "start"} "Start:"]
       [:select#start (for [n (range 1 217)] [:option n])]
       [:label {:for "step"} "# Step:"]
       [:select#step (for [n (range 1 217)] [:option n])]
       [:label {:for "direction"} "Direction:"]
       [:select#direction 
         [:option {:value -0.005} "Anti-clockwise"] 
         [:option {:value 0.005}  "Clockwise"]]])))

(def color (sel1 :select#colors))
(def start (sel1 :select#start))
(def step  (sel1 :select#step))
(def direction (sel1 :select#direction))

(defn colors []
  (color-seq
    (js/parseInt (value color))
    (js/parseInt (value start))
    (js/parseInt (value step))))

(defn patches [n offset scale]
  (let [tau       (/ (inc (Math/pow 5 0.5)) 2.0) ; golden ratio approx = 1.618033989
        angle     (+ (* (- 2 tau) 2 Math/PI) offset)
        drad      (* scale tau 0.5)
        generator (fn [{:keys [i theta]}]
                    (let [i     (inc i)
                          r     (* scale (Math/pow i 0.5))
                          theta (+ theta angle)
                          x     (* r (Math/cos theta))
                          y     (* r (Math/sin theta))]
                      { :x x :y y :r drad :theta theta :i i }))]
    (->>
      { :x 0 :y 0 :r drad :theta 0 :i 0 }
      (iterate generator)
      (take n))))

(defn draw-points! [ctx points colors]
  (if (nil? points)
    ctx ; return for threading
    (->
      ctx
      (fill-style (first colors))
      (circle (first points))
      (recur
        (next points) 
        (next colors)))))

(defn draw-frame! [ctx w h points colors]
  (->
    ctx
    (fill-style "rgba(255,255,255,0.75)") ; dial-in a smidgen of motion blur
    (fill-rect { :x (quot w -2) :y (quot h -2) :w w :h h })
    ;(composition-operation :lighter)
    (draw-points! points colors)
    (rotate (js/parseFloat (value direction)))))

(defn animate [ctx w h]
  (translate ctx (quot w 2) (quot h 2))
  (let [circles (patches 1500 0 7)]
    (letfn [(loop [] 
              (animation-frame loop)
              (draw-frame! ctx w h circles (colors)))] 
      (loop))))

(show canvas)

(animate ctx 800 600)
color-chart.cljs
(ns chroma-spirals.color-chart)

(def web-safe-colors [
  "#990033" "#FF3366" "#CC0033" "#FF0033" "#FF9999" "#CC3366" "#FFCCFF" "#CC6698" 
  "#993366" "#660033" "#CC3399" "#FF99CC" "#FF66CC" "#FF99FF" "#FF6699" "#CC0066"
  "#FF0066" "#FF3399" "#FF0099" "#FF33CC" "#FF00CC" "#FF66FF" "#FF33FF" "#FF00FF"
  "#CC0099" "#990066" "#CC66CC" "#CC33CC" "#CC99FF" "#CC66FF" "#CC33FF" "#993399"
  "#CC00CC" "#CC00FF" "#9900CC" "#990099" "#CC99CC" "#996699" "#663366" "#660099"
  "#9933CC" "#660066" "#9900FF" "#9933FF" "#9966CC" "#330033" "#663399" "#6633CC"
  "#6600CC" "#9966FF" "#330066" "#6600FF" "#6633FF" "#CCCCFF" "#9999FF" "#9999CC"
  "#6666CC" "#6666FF" "#666699" "#333366" "#333399" "#330099" "#3300CC" "#3300FF"
  "#3333FF" "#3333CC" "#0066FF" "#0033FF" "#3366FF" "#3366CC" "#000066" "#000033"
  "#0000FF" "#000099" "#0033CC" "#0000CC" "#336699" "#0066CC" "#99CCFF" "#6699FF"
  "#003366" "#6699CC" "#006699" "#3399CC" "#0099CC" "#66CCFF" "#3399FF" "#003399"
  "#0099FF" "#33CCFF" "#00CCFF" "#99FFFF" "#66FFFF" "#33FFFF" "#00FFFF" "#00CCCC"
  "#009999" "#669999" "#99CCCC" "#CCFFFF" "#33CCCC" "#66CCCC" "#339999" "#336666"
  "#006666" "#003333" "#00FFCC" "#33FFCC" "#33CC99" "#00CC99" "#66FFCC" "#99FFCC"
  "#00FF99" "#339966" "#006633" "#336633" "#669966" "#66CC66" "#99FF99" "#66FF66"
  "#339933" "#99CC99" "#66FF99" "#33FF99" "#33CC66" "#00CC66" "#66CC99" "#009966"
  "#009933" "#33FF66" "#00FF66" "#CCFFCC" "#CCFF99" "#99FF66" "#99FF33" "#00FF33"
  "#33FF33" "#00CC33" "#33CC33" "#66FF33" "#00FF00" "#66CC33" "#006600" "#003300"
  "#009900" "#33FF00" "#66FF00" "#99FF00" "#66CC00" "#00CC00" "#33CC00" "#339900"
  "#99CC66" "#669933" "#99CC33" "#336600" "#669900" "#99CC00" "#CCFF66" "#CCFF33"
  "#CCFF00" "#999900" "#CCCC00" "#CCCC33" "#333300" "#666600" "#999933" "#CCCC66"
  "#666633" "#999966" "#CCCC99" "#FFFFCC" "#FFFF99" "#FFFF66" "#FFFF33" "#FFFF00"
  "#FFCC00" "#FFCC66" "#FFCC33" "#CC9933" "#996600" "#CC9900" "#FF9900" "#CC6600"
  "#993300" "#CC6633" "#663300" "#FF9966" "#FF6633" "#FF9933" "#FF6600" "#CC3300"
  "#996633" "#330000" "#663333" "#996666" "#CC9999" "#993333" "#CC6666" "#FFCCCC"
  "#FF3333" "#CC3333" "#FF6666" "#660000" "#990000" "#CC0000" "#FF0000" "#FF3300"
  "#CC9966" "#FFCC99" "#FFFFFF" "#CCCCCC" "#999999" "#666666" "#333333" "#000000" ])

(def color-seq 
  (memoize 
    (fn [n start step]
      (->>
        (cycle web-safe-colors)
        (drop start) 
        (take-nth step)
        (take n)
        (cycle)))))