Fork me on GitHub
#membrane
<
2023-02-13
>
jjttjj19:02:01

Hey I'm coming back to membrane to draw some visuals after not using it for a bit. I'm a little rusty so mainly asking this to see if I'm missing something obvious. I'm using skija as the drawing platform. I have this code:

(ui/with-style :membrane.ui/style-stroke
      (apply ui/horizontal-layout
        (for [[colnum row->v]
              {4 {1 "id0", 2 "id1", 3 "id2"},
               5 {1 "id3", 2 "id4", 3 "id5", 4 "id6"},
               6 {1 "id7", 2 "id8", 3 "id9", 4 "id10"},
               7 {1 "id11", 2 "id12", 3 "id13"},
               8 {1 "id14"}}]
          (apply ui/vertical-layout
            (for [[peer v] row->v]
              (ui/padding 20
                (let [rect (ui/rectangle 50 50)
                      label (ui/center (ui/label v) (ui/bounds rect) )]
                  [rect label])))))))
Which in the attached image. Is there a way in membrane to draw a line from one of these rectangles to another one? That is, if I can keep a reference to all the rect records, is there a way to get the absolute location of any two of them given a common parent? Is the only obvious way to do this (without re-implementing the layout engine) by pre-calculating coordinates manually and not using the horizontal/vertical layout features?

phronmophobic19:02:26

There's more than one way to do it.

phronmophobic19:02:45

I think the way I would do it is traverse the created views to get a mapping of rect coordinates that you could use. horizontal and vertical layout are really just measuring and stacking items. It seems like you're working with a fairly regular grid, so it wouldn't be unreasonable to write a few helper functions to do the layout within the grid.

phronmophobic19:02:20

I'll write some example code. One sec.

jjttjj19:02:45

Awesome thanks!

phronmophobic20:02:57

ok, here's quick sketch. It's a little longer than I'd like, but hopefully most of the uninteresting parts can be hidden away in a util.clj or similar. This solution uses zippers. I can update the example with something else, but zippers do a really great job of fulfilling the OO equivalent parent/back references. The other thing to note is the introduction of IContentOffset . ui/bounds and ui/origin conflate hitboxes, view extents, and probably a few other things. This is a known problem and something I'd like to fix in membrane, but I'm also trying to avoid partial fixes until I get a chance to think things through a bit more (or reference someone else who has thought it through).

phronmophobic20:02:26

I think @U63D7UXJB has also been working on diagramming and maybe has some tips.

phronmophobic20:02:08

I've also done some basic diagramming. It would be nice to investigate building a standalone library similar to mermaid.

jjttjj20:02:45

Awesome thanks for all that! Really appreciate it

phronmophobic20:02:14

If the layout is grid based, I might also explicitly model that.

zimablue20:02:14

It's easy to create a protocol which you use to lay out elements eg top-left bottom-right, also easy to write your own eg horizontal-layout

👍 1
zimablue20:02:02

What would be more involved/interesting might be changing how events get dispatched based on capture but it's not super necessary as they just get passed along

jjttjj20:02:22

It's tricky because it seems like working at a higher level like this (without pixel coords, or possibly any coords, but as you say, explicit nominal coords might be worth it too) is desirable when possible, but it takes a bit of effort to get there too, it's sort of unclear before implementing a couple options which will be the nicest to actually use

👍 1
zimablue20:02:31

I think because html DOM is such a cluster fuck people might assume rolling your own here is harder than it is

phronmophobic20:02:48

I should keep a list of missing utilities somewhere so that they can either be added to membrane or packaged in helper libraries.

phronmophobic21:02:41

or even just a list of utilities people would like to see.

👍 1
jjttjj21:02:10

I always hit this pattern of problem where I want to draw say a graph, look up some libraries, find one that looks nice, say https://js.cytoscape.org/#notation/graph-model (i tried this first. Well, after graphviz which also wasn't really doing what I want without hacks). But then before the day is over I always hit something that is basically impossible to express cleanly in that framework. Like I wanted to add labels to the x and y axis here, you can't do that in cytoscape without awkwardly using separate graph items as labels, or shoving the graph in a dom and trying to line things up there. Like it seems like it would be ideal if a "graph" library could just plug into an existing ui/layout engine (like membrane 🙂 ) and it's job is just to draw the lines nicely between things with splines and whatever nice graph features. But instead every visualization/charting/etc library re-implements it's own layout/coordinate stuff in a non-compatible way, and they all have a learning curve, and you always hit limitations (at least I always do)

zimablue21:02:15

Yeah I've felt this, if they yielded effects/data it would help but people also want interactions

phronmophobic06:02:08

Added a https://github.com/phronmophobic/membrane/discussions/66#discussioncomment-5085064 in github discussions to start keeping track of "missing pieces".

👍 2