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.

Reply via email to