Fork me on GitHub
#reagent
<
2021-07-06
>
tlonist15:07:31

has anybody tried threeagent(https://github.com/DougHamil/threeagent) for rendering graphics? I keep getting black canvas no matter what.

tlonist15:07:47

I’ve read https://github.com/DougHamil/threeagent/issues/23, and by setting light attribute I can see the shapes I wanted, but still the canvas itself is black.

tlonist15:07:18

It seems like I need to somehow set .setClearColor to be white, but can’t find a way to get there.

ChillPillzKillzBillz20:07:29

Hi Everyone, Can anyone help me with a coding logic required for having reagent components nested? To elaborate.... Say you want to create an svg which is responsive. The SVG needs to have smiley faces. Each of the smiley faces can be happy or sad... So lets partition this into 3 components - SVG_Component for the top level, Smiley faces for the face component & the curve component for happy or sad element. Note each of the components have their own individual states, but will also require some information from their parent component e.g. positions. So the overall component call stack becomes SVG_Comp -> calls -> Smiley_Comp -> calls -> Smile/Sad_Comp. What is the best way to pass information down & up this stream? I've created states for each of the components and they all have with-let definition for the atom. I can only nest the components this way 1 level. I am doing something silly for sure.... maybe there is a better way to pass information... I don't want anyone to implement this... I just wanted to understand how to pass information down & up a chain of components? or even how to form components to be able to do that... any information will be helpful...

p-himik20:07:12

The way you describe it, you don't need any atoms at all.

(defn smile-or-frown [smile?]
  (if smile? (create-smile-hiccup) (create-frown-hiccup)))

(defn face [smile?]
  [:svg
    [smile-or-frown smile?]])

ChillPillzKillzBillz21:07:31

yes... I am aware I took a very simple example... couldn't think of anything better... but imagine that I do need states for all 3 components. So e.g. I want to render the smiley faces when I click on the svg... and then when I click on the smiley faces themselves, I can change the sad to happy and back... This is why I need to inherit the x, y locations of the click position.. too... OK this is all hypothetical... I just want to understand the mechanism to pass information in the chain of reagent components.... sorry if I am not making sense!

p-himik21:07:07

Two ways: • Just pass the arguments, as with that smile? above. It can be a map that stores a lot of keys and values where some of them used by some components and others by others • Pass whole Hiccup vectors with pre-filled arguments:

(defn face [smile-child]
  [:svg smile-child])

;; when using
[face [smile-or-frown true]]

p-himik21:07:30

There are a lot of examples in the Reagent repo - just go through them, you should see the most useful patterns.

ChillPillzKillzBillz21:07:12

Thanks for that. I'll have a look. I understand that without some code from myside, it is a bit hard to grasp what I am after... SVG component is as follows: (defn svgrender    []    `(with-let [svgstate (atom {:content-width 500`                                `:content-height 500`                                `})]`       `[:svg {:viewBox "0 0 500 500";;(gstring/format "0 0 %s %s" (:content-width @svgstate) (:content-height @svgstate))`              `:width 500`              `:height 500` :onMouseDown #(let [clickpos_x (.-clientX %) clickpos_y (.-clientY %)] [render_smiley clickpos_x clickpos_y])        `[:g {:id "ContentLayer"}]])` There is a mouseclick handler on this component which will render the smiley component defined as follows: (defn render_smiley   `[origx origy]`   `(try`     `(with-let [smileystate (atom {:origx origx`                                   `:origy origy})]`       `[:g {:id "smiley"}`        `[:circle {:cx (:origx @smileystate)`                  `:cy (:origy @smileystate)`                  `:r 50`                  `:style {:stroke "#000000"`                          `:stroke-width 2`                          `:stroke-linecap "round"`                          `:stroke-linejoin "round"`                          `:fill-opacity 100`                          `:fill "yellow"}}]`        `[:circle {:cx (+ (:origx @smileystate) (/ 30 1.414))`                  `:cy (- (:origy @smileystate) (/ 30 1.414))`                  `:r 5`                  `:style {:stroke "#000000"`                          `:stroke-width 2`                          `:stroke-linecap "round"`                          `:stroke-linejoin "round"`                          `:fill-opacity 100`                          `:fill "black"}}]`        `[:circle {:cx (+ (:origx @smileystate) (/ 30 -1.414))`                  `:cy (- (:origy @smileystate) (/ 30 1.414))`                  `:r 5`                  `:style {:stroke "#000000"`                          `:stroke-width 2`                          `:stroke-linecap "round"`                          `:stroke-linejoin "round"`                          `:fill-opacity 100`                          `:fill "black"}}]]`        `[render_sadhappy origx origy]`       `)`     `(catch :default e`       `(println "Smiley.cljs : " e))))` This component renders the sadhappy component defined as below: (defn render_sadhappy   `[origx origy]`   `(try`     `(with-let [sadhappystate (atom {:origx origx`                                     `:origy origy`                                     `:r 30`                                     `:happy true})]`       `[:path {:style {:stroke "#000000"`                       `:stroke-width 2`                       `:stroke-linecap "round"`                       `:stroke-linejoin "round"`                       `:fill-opacity 100`                       `:fill "yellow"}`               `:d (gstring/format "M %s %s a%s,%s 0 0, 0 %s%s,0"`                                  `(- (:origx @sadhappystate) (* 0.5 (:r @sadhappystate)))`                                  `(:origy @sadhappystate)`                                  `(:r @sadhappystate)`                                  `(:r @sadhappystate)`                                  `(if (:happy @sadhappystate)`                                    `""`                                    `"-")`                                  `(:r @sadhappystate))}])`     `(catch :default e`       `(println "Smiley.cljs : " e))))` There is one chain of command which is the rendering point where all gets rendered. The second interaction is on the smiley or sadhappy component whereby if the user clicks on any of these components, the sadhappy component changes the smile to scowl... How do you go about it? This code is just me writing up the concept and hasn't been tested at all... the code is not the point... it is again how the state of one component effects the chain... I am sorry if I can't express the query properly...

p-himik00:07:53

I don't understand what you don't understand. • Make sure that those atoms come from Reagent and not Clojure. Better yet, don't use :refer or :use - instead, use :as, e.g. [reagent.core :as r], and then use r/atom and r/with-let • Attach :on-click handlers to whatever needs to be clicked and just swap! or reset! the ratoms to the new values

p-himik00:07:56

Before trying anything and writing more code - go through Reagent examples. Go through its documentation. State passing and alteration are everywhere, you can't miss it.

ChillPillzKillzBillz07:07:27

@U2FRKM4TW Thanks for all your help. I guess I am all muddled up... in my head. 😄 So the top level component must hold the state where the positions of the Smiley components are defined. These locations are to be passed to each of the smiley components so that they can render themselves... The smiley components themselves should have a state of the location of the sadhappy component and should pass this down to them. Event handling wise... the click in top level component must instantiate a new smiley component, and a click on the smiley component or the sadhappy component must change the sadhappy component. Also the top level component must be able to query the smiley components for their happy/sad status. There is information flow downwards and upwards. I know this is a silly example. I intend to implement something much more complex, but without the patterns it is hard to start architecting something. I've used the standard ratom with-let constructs for all components, but I find it hard to figure out how the bidirectional information flow is achieved. Thanks for your help anyways... I'll have a look in the examples...

wombawomba23:07:54

Is there an equivalent of with-let that will re-initialize its bindings when their inputs change?

p-himik00:07:15

If something depends on an input that's not a ratom, don't put it in with-let - put it inside the render function instead. Don't forget that that function itself has to provide the parameters.

p-himik00:07:13

And if something depends on a ratom, use a reaction.

wombawomba07:07:38

alright, thanks

wombawomba07:07:25

bummer... with-let is just so much more convenient to use than type-3 components

Michaël Salihi08:07:54

Maybe a form-2 component is what you want?

wombawomba09:07:50

I don't think just a form-2 component is sufficient... I'm setting up an event listener that depends on the component inputs, so I need the (finally ...) part of with-let to unregister the event listener when the component is unmounted.

p-himik10:07:49

You need to remove the listener not only when the component is unmounted, but also when the inputs are changed. Two ways to do that • With a form-3 component with a :component-did-update function • With a form-1 component within the render function The former is more correct but more complex. The latter is simpler but will likely lead to more re-renders of the component. And is definitely wrong if you require the exact correspondence between the number of re-renders and the number of state changes.