🕶 Design patterns for filtering

Hi fellow Vuo-ers

Here’s one I’m struggling with. I’m hoping for some advice on general patterns for designs flows where there is a large selection of things, and I want to filter to one thing, or output the first result that matches some criteria.

For example, here is my (nonworking) attempt to take a row of images, and detect a mouse click on one and highlight it.

So, I have a list of layers that I want to just find one (the first would do) and output that. However, the Process List node is optimised for doing the same flow to a complete list. In code, I’d just user Event Listeners, or a similar approach.

  1. How best to achieve my immediate goal of making a row of n images that are clickable (etc)?
  2. In general, is there an approach I should be using to find one-of-many? That is, to process a set of objects, with expectations of one (or maybe a short list) of results?

(Yes, yes, I know that Vuo is not a tool optimised for building UI. My problem still seems inside what one might hope to do with Vuo though, IMO.)

Here’s another unsuccessful attempt, this time using Spin Off Events.
What am I missing?

You could try something like this:

Looks a bit excessive, but should scale up pretty easily to 2d and 3d grids as well. The general idea is to select forwards, not backwards. That way you check the points and create and modify any layers/images/objects on those points based on an arbitrary input (mouse position in this case).

selectLayers.vuo (7.39 KB)

1 Like

Once again, thank you @martinusMagneson for all your work in wiring this up. :pray::pray::pray:

I gotta admit though, this makes me tenor.gif
The knottiness of this solution makes me feel like Vuo is lacking something architectural. I know all nodal stuff can end up a bit like this, but this just feels like there is some fundamental piece missing to avoid this knitting. :slightly_smiling_face:

Thanks again for your help!
So I think I found a nice solution, for me. Spin Off Events is rather handy (feature request: Spin Off ValueS) for this task.

Although, looking over it, it feels like we have very similar solutions in some ways. :man_bowing:t2:

This comp takes an a group of layers, and overlays a rectangle that matches the layer pos+size, if mouse is over it. only works for non-overlapping rectangles, which is my use-case.

For some reason I couldn’t get Is Point Within Layer to work. Could be user error, but could be buggy?  

mouseOverRects.vuo (6.78 KB)

Haha, it was way to late in the evening when writing that, and I didn’t exactly do a good job of explaining! Good to see you got it working! One cool (or annoying) thing with your approach is that it should be fairly easy to animate the overlay using the Smooth with *** nodes so that it glides to the next one instead of popping over. A thing to keep in mind when using Build/Process List is that the whole function of the loop has to be contained within that node hierarchy, or you’ll get errors. This means that you can’t pass a value from inside the loop to an outside node without it being part of the “Finished Building” port. I suspect the issue might lie there in your first iteration.

To explain my approach a bit better (hopefully), system nodes are lime, math nodes are yellow, input is blue, constructors are magenta and the build loop is orange. In addition the hold nodes are there to sync outside values to the loop and are colored violet.

It works by first getting the window dimensions and setting the start/end of a “Points along Line (2D)” to the left/right points of the window. The width is then divided by the amount of elements you want, that gives you the per-layer dimensions, and also a “bounding box” for checking the mouse position. Height is hard-coded to 1 in this instance, but the height calculation is the same as for width if you want a 2D grid (or 3D, but then you’ll need depth and a different input than the mouse to get a 3D point to check).

This data is then fed into a “Build List” node that checks the mouse position and then create the layers based on that input (changes color if the point is within the rectangle bounds of the point). This way you set up, create and check all parameters before making the layers, what I clumsily referred to as “selecting forwards”. This as opposed to creating the layers and doing the selection and manipulation after the fact (or selecting backwards).

For me the flexibility that points provide usually is a lot easier to relate to, but as it is more of an abstract way of thinking about compositing it can be a bit of a task to wrap your head around it. In that vein, the composition I posted isn’t restricted to layers, but can be images or objects, or even points to generate other points from (which can again be used to tile layers/objects/images/points. To swap it around, the only node you need to change is the “Make Rectangle Layer”. To organize things in a circle, swap out the “Make Points Along Line”, insert a MM.Spirograph node (for simplicity) and add the calculations for height.

I do think that the learning curve might be a bit steep, and see the need for simple UI nodes. I also understand that it’s hard to make a one-size-fits-all node for these things without it being an unwieldy and huge node to account for all permutations of how to select things. Most of it should by now be possible to do with subcomps, which I think is the preferred way of solving it as they can easily be changed by the end user.

For me, I much prefer the more structured way of working, where there can be a list of images, and each image can have its properties. I can easily move this group of images through a flow, and if I need to get the property of an image, then I can. If anything, I wish I could work more like this.

There are some other issues I see making this harder than I’d hope for. One is the requirement to supply Window detail to a patch.

  1. Wiring across large distances (often requiring scrolling) is actually quite physically difficult. And cognitively difficult to keep track off, even when the wire is hidden.
  2. The need to wire stuff from the end of the composition back to the beginning is annoying and messy. This applies to anything mouse-y. I wonder if we might guess that 90%+ of compositions only ever have one window. If you want mouse coordinates relative to the window (which I would guess is vastly most common scenario), then you need to wire from the far ends of your composition.

There’s no user hack I can think of that could make this easier.

Actually, my solution posted earlier was horrible, and shouldn’t be used. Something was gnawing at the back of my head, and was confirmed when I took another look at it with a lot more items. It is very, very inefficient choking at around 20 items for me. I still think that creating the grid beforehand is the most flexible solution though, but not for the reasons as posted above (or sort of at least).

The node you want to use for this sort of thing is the “Change Item in List”. Then it’s only a matter of calculating the index from a position in the window, get the item you want to change, do the processing, and change the item in the list. Optionally just have a different item that is the selected one. That way the rest of the list remains unchanged meaning there is no processing required for the most part. In turn this means that you can have huge selectable grids without using much processing power. This way should also be more compatible with your way of thinking about the flow if I understood you right. In the attached example I use a build list, but it is more for convenience in both testing and showing the concept. The “Build List” node can be swapped out for a list of images or objects or whatever you want to display.

So, this is the basic gist of the procedure:

Screenshot 2020-09-21 at 19.41.16.jpg

I’m attaching the composition itself, and the “Grid With Index” subcomposition - because nobody wants to deal with what’s inside it on a regular basis. You will need to put this in your user modules folder along with MM.Points to make the example composition work. Not sure if it’s a user hack but I usually place my render node to the left if I need window info. There is usually only one wire going to the render node, so I’ll just hide that one and color/comment the node going to it to neaten things up.

It seems like there is some lag when starting a composition, so you’ll need to press the mouse button once after starting or resizing the window to make it display properly. I don’t know why. If @jstrecker or someone from team Vuo can take a look at it, they might have a few pointers as to why this happens though.

Using this approach a 100 x 100 grid of layers, and with mouse position as the selector still works on my old MBP. Laggy, but works, which is a feat considering it’s 10,000 layers. 200 x 200 lags to the point of breaking the composition, but if your UI depends on 40,000 separately selectable items by hovering the mouse I think you have other issues than a laggy interface. Interestingly, using mouse buttons it works with around a second of lag at 200 x 200, and technically still works at 500 x 500, but I wouldn’t call it usable. However at 250,000 layers I’m surprised it runs at all. Especially considering this is with old intel integrated gfx and Haswell series CPU. So depending on your hardware, your experience may be quite a bit different.

SelectGrid.vuo (9.92 KB)
mm.gridWithIndex.vuo (9.36 KB)

2 Likes

It seems like there is some lag when starting a composition, so you’ll need to press the mouse button once after starting or resizing the window to make it display properly.

@MartinusMagneson, sorry for the belated reply. The problem is in the “Create base items” section of the composition, specifically the Build List node.

With a couple of extra nodes, I saw that Build List was getting 2 events in rapid succession when the composition starts…

However, the Build List node was only outputting 1 time. This is because (quoting the node documentation): “If the Start Building port receives an event while the node is still building the list for the previous Start Building event, then the later Start Building event is ignored (dropped). To avoid having events ignored, you can modify your composition to limit the rate at which events hit this node.”

Instead of trying to track down where the 2 events were coming from, I figured it would be easier (and more performant) to replace the Build List with Copy Layer. That seems to work. Composition attached.

SelectGrid-CopyLayer.vuo (9.39 KB)