Skip to content

Instantly share code, notes, and snippets.

@nvbn
Created May 28, 2015 01:31
Show Gist options
  • Star 2 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save nvbn/581ff6a88a805bd2a7ab to your computer and use it in GitHub Desktop.
Save nvbn/581ff6a88a805bd2a7ab to your computer and use it in GitHub Desktop.
svg animation
(ns ^:figwheel-always svg-image-example.core
(:require-macros [cljs.core.async.macros :refer [go-loop]])
(:require [cljs.core.async :refer [<! timeout]]
[om.core :as om :include-macros true]
[om-tools.core :refer-macros [defcomponent]]
[om-tools.dom :as dom]))
(enable-console-print!)
(defcomponent rotated-rect-rect
[{:keys [x y width height]} owner]
(init-state [_] {:angle 0})
(will-mount [_]
(go-loop []
(om/update-state! owner :angle #(-> % inc (mod 360)))
(<! (timeout 10))
(recur)))
(render-state [_ {:keys [angle]}]
(let [center-x (+ x (/ width 2))
center-y (+ y (/ height 2))]
(dom/rect {:width width
:height height
:fill "red"
:transform (str "rotate(" angle ", " center-x ", " center-y ")")
:x x
:y y}))))
(defcomponent scene-1
[_ _]
(render [_]
(dom/svg {:width "100%" :height "100%"}
(om/build rotated-rect-rect {:x 50
:y 50
:width 100
:height 100}))))
(defcomponent scene-2
[_ owner]
(init-state [_] {:x 0})
(will-mount [_]
(go-loop []
(om/update-state! owner :x #(-> % inc (mod 600)))
(<! (timeout 10))
(recur)))
(render-state [_ {:keys [x]}]
(dom/svg {:width "100%" :height "100%"}
(om/build rotated-rect-rect {:x x
:y 50
:width 100
:height 100}))))
(defcomponent sprite
[{:keys [x y img-width img-height scale sprite-x sprite-y sprite-w sprite-h href]} _]
(render-state [_ _]
(let [id (gensym)]
(dom/g (dom/defs {:dangerouslySetInnerHTML {:__html (str "
<pattern id='" id "'
patternUnits='userSpaceOnUse'
x='" x "'
y='" y "'
width='" sprite-w "'
height='" sprite-h "'>
<image x='" (- 0 sprite-x) "'
y='" (- 0 sprite-y) "'
xlink:href='" href "'
width='" img-width "'
height='" img-height "'
transform='scale(" scale ")' />
</pattern>")}})
(dom/rect {:x x :y y :width sprite-w :height sprite-h
:fill (str "url(#" id ")")})))))
(defcomponent scene-3
[_ _]
(render [_]
(dom/svg {:width "100%" :height "100%"}
(om/build sprite {:img-width 406
:img-height 1507
:scale 2
:sprite-w 40
:sprite-h 80
:href "mario.png"
:sprite-x 214
:sprite-y 240}))))
(defn mario-sprite
[& opts]
(om/build sprite (assoc (apply hash-map opts)
:img-width 406
:img-height 1507
:scale 2
:sprite-w 40
:sprite-h 80
:href "mario.png")))
(def sprites
{:right {:run [328 320]
:run-1 [354 320]
:run-2 [378 320]
:jump [335 240]
:stand [214 240]}
:left {:run [60 320]
:run-1 [34 320]
:run-2 [8 320]
:jump [54 240]
:stand [174 240]}})
(defcomponent mario
[{:keys [x y]} owner]
(init-state [_] {:state :stand
:direction :left})
(will-mount [_]
(go-loop []
(let [state (om/get-props owner :state)
direction (om/get-props owner :direction)
drawing-state (om/get-state owner :state)
drawing-direction (om/get-state owner :direction)
next-state (if (and (= direction drawing-direction) (= state :run))
(condp = drawing-state
:run :run-1
:run-1 :run-2
:run)
state)]
(om/set-state! owner :state next-state)
(om/set-state! owner :direction direction))
(<! (timeout 100))
(recur)))
(render-state [_ {:keys [state direction]}]
(let [[sx sy] (get-in sprites [direction state])]
(mario-sprite :x x
:y y
:sprite-x sx
:sprite-y sy))))
(defcomponent scene-4
[_ _]
(render [_]
(dom/svg {:width "100%" :height "100%"}
(om/build mario {:x 10 :y 10 :state :stand :direction :right})
(om/build mario {:x 60 :y 10 :state :run :direction :right})
(om/build mario {:x 110 :y 10 :state :jump :direction :right})
(om/build mario {:x 10 :y 100 :state :stand :direction :left})
(om/build mario {:x 60 :y 100 :state :run :direction :left})
(om/build mario {:x 110 :y 100 :state :jump :direction :left}))))
(defcomponent scene-5
[_ owner]
(init-state [_] {:mario-state :stand
:mario-x 20
:mario-y 10
:mario-direction :right})
(will-mount [_]
(go-loop []
; Stand a half
(om/set-state! owner :mario-state :stand)
(<! (timeout 500))
; Jump
(om/set-state! owner :mario-state :jump)
(dotimes [_ 20]
(<! (timeout 5))
(om/update-state! owner :mario-y dec))
(dotimes [_ 20]
(<! (timeout 5))
(om/update-state! owner :mario-y inc))
; Stand a half
(om/set-state! owner :mario-state :stand)
(<! (timeout 500))
; Go right
(om/set-state! owner :mario-state :run)
(dotimes [_ 300]
(<! (timeout 5))
(om/update-state! owner :mario-x inc))
; Stand a second
(om/set-state! owner :mario-state :stand)
(<! (timeout 500))
(om/set-state! owner :mario-direction :left)
(<! (timeout 500))
; Jump
(om/set-state! owner :mario-state :jump)
(dotimes [_ 20]
(<! (timeout 5))
(om/update-state! owner :mario-y dec))
(dotimes [_ 20]
(<! (timeout 5))
(om/update-state! owner :mario-y inc))
;Stand a half
(om/set-state! owner :mario-state :stand)
(<! (timeout 500))
; Go back
(om/set-state! owner :mario-state :run)
(dotimes [_ 300]
(<! (timeout 5))
(om/update-state! owner :mario-x dec))
; Stand a half
(om/set-state! owner :mario-direction :right)
(<! (timeout 500))
(recur)))
(render-state [_ {:keys [mario-state mario-direction mario-x mario-y]}]
(dom/svg {:width "100%" :height "100%"}
(om/build mario {:x mario-x
:y mario-y
:state mario-state
:direction mario-direction})
(dom/rect {:fill "green"
:x 0
:y 70
:width 400
:height 20}))))
(defn ^:export main
[n]
(let [scene (nth [scene-1 scene-2 scene-3 scene-4 scene-5] (dec n))]
(om/root scene {} {:target (.getElementById js/document "main")})))
<html>
<body>
<div id="main"></div>
<script src="result.js"></script>
<script>
var scene = parseInt(location.hash[1], 10);
if (scene) svg_image_example.core.main(scene);
</script>
</body>
</html>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment