 
 (defn projectors-for-state [state]
   (if (= (:projection state) :fisheye) fisheye-projectors zoom-out-projectors))
+
+;; D3 magic
 
 (defn sync-graph! [state & {:keys [animation-signaller]}]
   (let [{:keys [svg nodes links camera-pos view-size]} state


(def vec-distance (comp vec-length subtract-vec))

(defn vec-clamp-to-bounds [v bounds]
  (let [ratios (merge-with (comp js/Math.abs /) bounds v)
        max-ratio (min 1 (:x ratios) (:y ratios))]
    (scalar-multiply v max-ratio)))

;; D3 magic

(defn scroll-scale-for-state [state]
  (if (= :zoom-out (:projection state)) zoom-out-scale 1))

(defn scaled-distance-from-camera
  "Returns the distance of the given point from the camera, scaled so that


;; Gestures - pinch

(defn pinch-observable [manager svg]
  (.map (gesture-observable manager svg "pinchmove")
        (fn [e] {:center (math-vec (-> e .-center .-x) (-> e .-center .-y))
                 :scale (.-scale e)})))

(defn zoom-on-pinch! [manager
                      current-state
                      animation-observable
                      animation-signaller]
  (let [pinches (pinch-observable manager (:svg @current-state))
        pinch-ins (-> pinches (.filter #(< (:scale %) 0.8))
                      (suppress-while-animating animation-observable))
        pinch-outs (-> pinches (.filter #(> (:scale %) 1.2))
                       (suppress-while-animating animation-observable))]
    (.subscribe
      pinch-ins
      #(if (= (:projection @current-state) :fisheye)
         (set-projection! current-state :zoom-out animation-signaller)))
    (.subscribe
      pinch-outs
      #(if (= (:projection @current-state) :zoom-out)
         (zoom-in-to-pos! current-state
                          (zoom-out->world-pos @current-state (:center %))
                          animation-signaller)))))

;; Exported function to do magic

