Glad you got it working. I haven't really got the context to follow (deep in server side event sourcing ATM) but one tiny tiny point; (-> :a (identity)) is the same as (-> :a identity) (i.e. for single parameter functions you can just put their symbol which I think reads nicer). Tiny, as I said :).
On 19 March 2015 at 13:43, Wilker <[email protected]> wrote: > Thanks for the reply Colin, I did read the entire thread but I'm still don't > have a solution... > > My case is a bit different than yours, because yours will just render in the > end, in my case I need to do more manual stuff (for rending on the canvas > context) and I'm trying to rely on the React lifecycle methods to do some > caching on the rendering (the idea is to render off-canvas when data changes > for that component, and parent components will ask childs to render itself > on the canvas, and they can do that from the off-screen cached). > > My current major issue is that I can't find a way to get the children of a > component, on React that would be done by simply props.children, but I can't > find a way to do the same on Om (tried to look at state, props, owner and > this, but not found anything there. > > Here is some code that I'm trying to get to work: > > (defprotocol IDraw > (draw [this ctx])) > > (defn surface [data owner] > (let [redraw (fn [] > (let [ctx (-> (om/get-node owner) (.getContext "2d"))] > (doseq [child (GET_CHILDS_SOMEHOW)] > (if (satisfies? IDraw child) > (draw child ctx)))))] > (reify > om/IDisplayName > (display-name [_] "Surface") > om/IDidMount > (did-mount [_] (redraw)) > om/IDidUpdate > (did-update [_ _ _] (redraw)) > om/IRender > (render [_] > (apply dom/canvas #js {:width 300 :height 300} data))))) > > (defn surface-square [{:keys [width height x y]} owner] > (reify > om/IDisplayName (display-name [_] "Square") > ; caching rendering on mount > om/IDidMount > (did-mount [_] > (om/set-state! owner :rendered (render-off-screen #(.fillRect % x y > width height)))) > ; the update cache on update is missing for now, but I think you got > point > IDraw > ; draw the cached version > (draw [_ ctx] (.drawImage ctx (om/get-state owner :rendered))) > om/IRender > (render [_] nil))) > > (om/build surface > [(om/build surface-square {:x 10 :y 10 :width 20 :height 20})]) > > So, the code above doesn't work for a couple of reasons: > > 1. I didn't found yet a way to actually get the children components (but on > React inspector it shows they are there) > 2. Besides I like the idea of having a protocol for drawing, it will not > work since this reified object is not actually used, instead it's wrapped by > Om, so I guess this protocol idea will never really work (at least this is > what I understood after reading the sources, please tell me if I'm wrong > about it)... > > ----------------------- > > I paused writing this post and now I got a working solution, I'll leave the > previous text since it may be useful to follow the though process, but here > is a working solution using multimethods: > > (defmulti render :type) > > (defn render-off-screen [f w h] > (let [canvas (doto (.createElement js/document "canvas") > (aset "width" w) (aset "height" h)) > ctx (.getContext canvas "2d")] > (f ctx) > canvas)) > > (defn clear-canvas [canvas] > (doto (.getContext canvas "2d") > (.clearRect 0 0 (.-width canvas) (.-height canvas)))) > > (defn surface [data owner] > (reify > om/IDisplayName > (display-name [_] "Surface") > om/IDidMount > (did-mount [_]) > om/IWillUpdate > (will-update [_ _ _] (clear-canvas (om/get-node owner))) > om/IRender > (render [_] > (apply dom/canvas #js {:width 300 :height 300} (map #(render (assoc % > :surface owner)) data))))) > > (defn render-to-cache [owner render-fn w h] > (om/set-state! owner :rendered (render-off-screen render-fn w h))) > > (defn render-cached [owner] > (let [ctx (-> (om/get-props owner :surface) (om/get-node) (.getContext > "2d"))] > (.drawImage ctx (om/get-state owner :rendered) 0 0))) > > (defn surface-square [{:keys [width height x y] :as data} owner] > (let [render (fn [ctx] (.fillRect ctx x y width height))] > (reify > om/IDisplayName (display-name [_] "Square") > om/IDidMount > (did-mount [_] > (render-to-cache owner render width height) > (render-cached owner)) > om/IDidUpdate > (did-update [_ props _] > (if (not= props data) (render-to-cache owner render width height)) > (render-cached owner)) > om/IRender > (render [_] nil)))) > > (defmethod render :square [d] (om/build surface-square d)) > > (om/build surface > [{:type :square :x 10 :y 10 :width 20 :height 20}]) > > I think that will work, I would like to be able to reference the parent > component owner without having to explicitly send it on the props (which I'm > currently doing on the Surface render). > > Besides that I would like any suggestions on improvements for this, at least > now it's working :) > > Thanks. > > On Thu, Mar 19, 2015 at 8:57 AM Colin Yates <[email protected]> wrote: >> >> Hi, I asked this before and the short answer is *not* by passing in >> realised components in another another component's state as you have >> done (which was almost my first attempt). >> >> The consensus was to use multi-methods. If you can't then you pass the >> child state and the child fn through to the container which then >> invokes (om/build child-fn child-state). >> >> https://groups.google.com/d/msg/clojurescript/6HfwarWsFfI/lvRbRFAeiV0J >> has a lot more detail. >> >> On 19 March 2015 at 11:53, Wilker <[email protected]> wrote: >> > Hi, >> > >> > I'm creating a component here that will actually render on canvas, to be >> > more specific I wanna have a tree definition that end's up rendering on >> > Canvas (kind of the react-canvas project, but on Om, and for other >> > purposes). >> > >> > In React is more clear how to write things like this, you can do: >> > >> > <Surface> >> > <Layer> >> > <Rectangle width="100" height="100" /> >> > </Layer> >> > </Surface> >> > >> > And on react you have the children props and that stuff that can be use >> > to >> > "integrate" those components. >> > >> > But how do I accomplish a similar thing with Om? >> > >> > The farthest that I was able to got was an idea like this: >> > >> > (om/build surface >> > [(om/build layer [(om/build square {:width 100 :height 100}]]) >> > >> > This is just an "idea" on how to nest components that I came up, but >> > it's >> > not really working... >> > >> > Ideally I would like for the child node to be able to access the parent >> > in >> > order to call methods on the canvas (that's on the surface component) to >> > render things. >> > >> > How can I manage this kind of components with Om? >> > >> > Thanks. >> > >> > -- >> > Note that posts from new members are moderated - please be patient with >> > your >> > first post. >> > --- >> > You received this message because you are subscribed to the Google >> > Groups >> > "ClojureScript" group. >> > To unsubscribe from this group and stop receiving emails from it, send >> > an >> > email to [email protected]. >> > To post to this group, send email to [email protected]. >> > Visit this group at http://groups.google.com/group/clojurescript. >> >> -- >> Note that posts from new members are moderated - please be patient with >> your first post. >> --- >> You received this message because you are subscribed to the Google Groups >> "ClojureScript" group. >> To unsubscribe from this group and stop receiving emails from it, send an >> email to [email protected]. >> To post to this group, send email to [email protected]. >> Visit this group at http://groups.google.com/group/clojurescript. > > -- > Note that posts from new members are moderated - please be patient with your > first post. > --- > You received this message because you are subscribed to the Google Groups > "ClojureScript" group. > To unsubscribe from this group and stop receiving emails from it, send an > email to [email protected]. > To post to this group, send email to [email protected]. > Visit this group at http://groups.google.com/group/clojurescript. -- Note that posts from new members are moderated - please be patient with your first post. --- You received this message because you are subscribed to the Google Groups "ClojureScript" group. To unsubscribe from this group and stop receiving emails from it, send an email to [email protected]. To post to this group, send email to [email protected]. Visit this group at http://groups.google.com/group/clojurescript.
