Wrapping pill-shaped items to the next row of a fixed width container


#1

Hello friends,

I’m trying to load objects (pill shaped items) in this case within a container of a fixed width. I need help with wrapping these pills to the next row as the container height can be variable. These pills are dynamically populated by selection from the drop-down and are appended to the already existing list of pills.

Thanks!


#2

Not sure how you’ve set this up… I’ll assume you’re dynamically setting the width of the pills, like with a javascript hack. In general, seems like you should be able to use a global variable or two to calculate the width of the new/current pill (maybe varPillWidth) and the width of all pills in the current row (plus padding)–or conversely, the remaining available width in the container (maybe varRowWidth). When a new pill is added, compare its needed width with the available width in the current row. If it fits, update varRowWidth. If it won’t fit, move it to the “next row” position and reset the varRowWidth.

Is your container a dynamic panel, or are you doing this in a repeater, maybe a dynamic panel in a repeater, or is it something else? Are the pill widgets hidden and resized and/or moved into position, or does the repeater load them–showing otherwise hidden widgets, or setting a dynamic panel state (e.g., states for 1-pill, 2-pills, etc.)?

Here’s how I’d start trying to handle this with a repeater (not totally sure this would work…) I guess your pill selection dropdown could have some logic to either add a new row (first pill or not enough room for new pill) or update an existing row (at least one pill in the current row and enough space for the new pill). Your repeater would need multiple columns, at least one per possible pill. For example, maybe the maximum number of pills is 3. Repeater columns could be Pill1, Pill2, Pill3. Your repeater cell could have a dynamic panel with 3 matching states. The Item Loaded event could have conditional cases like,

If [[Item.Pill3]] does not equal “”
Set Text 3Pill3 to [[Item.Pill3]]
Set Text 3Pill2 to [[Item.Pill2]]
Set Text 3Pill1 to [[Item.Pill1]]
Set Size 3Pill3 to (varPillWidth3, )
Set Size 3Pill2 to (varPillWidth2, )
Set Size 3Pill1 to (varPillWidth1, )
Set Panel State to 3Pills

Else If [[Item.Pill2]] does not equal “”
Set Text 2Pill2 to [[Item.Pill2]]
Set Text 2Pill1 to [[Item.Pill1]]
Set Size 2Pill2 to (varPillWidth2, )
Set Size 2Pill1 to (varPillWidth1, )
Set Panel State to 2Pills

Else If [[Item.Pill1]] does not equal “”
Set Text 1Pill1 to [[Item.Pill1]]
Set Size 1Pill1 to (varPillWidth1, )

Hope this makes sense. If not, and you have a .rp file you can post here, I can try to apply a solution. Or, if not, I could probably make a demo file --just let me know if you need a straight dynamic panel or a repeater version.


#3

I don’t have an .rp file yet. It’d be great if you could do a demo file using the dynamic panel approach. And I have to tell you that the contents of the pills themselves are loaded from a list driven by a repeater. Thanks!


#4

Here is a demo file
Auto-place items in container.rp (87.6 KB)

Because your pills are chosen by droplist, each pill can be created in the editor and the width of each pill is known. To help with this, I set the first pill to “Fit to Text Width” in the STYLE panel. Then, when duplicated and the text label changed, the width of the pill is automatically set.

To keep things relatively simple and to demonstrate how this works, I created a few global variables. Default values are shown in parentheses. :

  • varPillWidth
    //width of currently selected pill
  • varRowWidth
    //available width of current row
  • varRowX (20)
    //the x-position to place the next pill
  • varRowY (20)
    //the y-position to place the next pill
  • varRowMargin (20)
    //distance from edge of container to the pills
  • varRowPadding (10)
    //distance between pills (and between rows)

A droplist has 10 items (plus the default “Select an item”). Choosing an item selects the associated pill in the dynamic panel container. When a pill is selected, the pill calculates where it should be placed, based on its own width (and height; all the same in this demo, but it supports pills of varying heights.)

A dynamic panel serves as the pill container, and has two states: “State1” and “blank”. Its Loaded event sets the available row width by calculating its width minus the padding, and it sets itself to the “blank” state, essentially hiding itself from view. Its “State1” contains 10 hidden pills plus a hotspot. The hotspot is just an invisible widget set to the height of the row margin and placed at the bottom of the dynamic panel to ensure there is a consistent bottom margin. This dynamic panel is set to the default “Fit to Content” so when a new row is added (by moving and then showing a pill) its height can automatically grow.

Now, when a pill’s state changes to “selected” it does a few things, which you can see in each pill’s Interaction code:

  • There are two conditional cases, used to determine if this pill will fit on the current row, or if a new row is needed.
  • The appropriate global variables are updated, so the current pill width, available row width, and the (x, y) location for this pill are known. (It turns out the varPillWidth is not really used, because each pill moves itself, which can use [[This.width]], but I kept varPillWidth anyway for demonstration purposes.)
  • The pill moves itself to the appropriate location and then shows itself. It also updates the location to place the next pill (by setting varRowX, and if it is in a new row, also setting the varRowY value.)

If you need to “clear” or delete a pill, for example by clicking on it, you could set its selection state to “false”, hide it and move the pills after it accordingly. It may be a little tricky to handle moving pill(s) to a previous row, but the logic would involve checking the deleted pill’s y-location, whether the next pill could fit on that row, and if so, updating varRowY then move the next pill. For this, I would imagine another global variable could help, which would be essentially a list of the chosen pills in order. A kind of “pseudo array” of pill names or numbers, if you will, because Axure doesn’t support true arrays. The more interactions like this you need to support, the more a repeater approach will likely help save time and effort in the Interaction code.


#5

All the trick is to figure out the correct coordinates and move the components.

I tried to use repeater, but there are still some bugs.

https://1ou0qz.axshare.com/


#6

Thanks much @mbc66 for your quick response. You are amazing!


#7

Thanks much @Jorkin for your solution. Could you please post your .rp file so that I can try to understand your logic and learn from it?


#8

I have given up Axure 9,
I can’t do the “fit to content” function without a monospaced font, and even if I use it, I can’t achieve the “fit to content” function of a string which mixes single-byte characters and double-byte characters.

This is a RP10 file:
AutoPlacePills_RP10.rp (76.8 KB)

Preview: https://rwcl1c.axshare.com


#9

It’s possible to do with Axure 9 but you have to use javascript injection to find widget id’s and use those to detect the “real” width of the entered text. Dynamic_Tags.rp (7.3 MB)
And you’d still have to add the max width calculations to move chips to the next line…

If you can use Axure 10, go with that. It’s much easier.