OH3 CSS Animation of variable oh-repeater result

Hi All

I am trying to animate the result from an oh-repeater component. The oh-repeater is based on an example by JustinG, modified for what I wanted.

The final result will make uses of a nested oh-repeater to generate a list of between 1 and 4 lines, depending on the state of the relevant items based on a group.

I have a working example using the groups, however the animation is inconsistent depending on the number of lines returned.

4 Lines:

4 Visible

1 Line:

1 Visible

I am interested in the “visible display” which will be inside the block.

As you can see, the scrolling looks OK with the full 4 lines, however with 1 line it has a lot of blank space being displayed.

I am looking for a way to make the animation for consistent.

My test code looks like:

uid: filter_demo2
tags: []
props:
  parameters:
    - context: item
      description: Partition ExitDelay Group
      label: Partition ExitDelay Group
      name: partitionExitDelayGroup
      required: false
      type: TEXT
  parameterGroups: []
timestamp: Feb 25, 2023, 8:18:44 PM
component: f7-block
config:
  style:
    --f7-block-margin-horizontal: 0px
    --f7-block-margin-vertical: 0px
    --f7-block-padding-horizontal: 0px
    --f7-block-padding-verticall: 0px
    border-radius: 5px
    height: 90px
    justify-content: center
    left: 30px
    /*overflow: hidden*/
    position: absolute
    top: 20px
    width: 300px
    border: 2px solid black
  stylesheet: >
    .roll_block {
      display: block; /* Important to give the content a width */
      height: 100%;
      overflow: hidden;
      position: relative;
      /* Add the animation */
      animation: move 3s linear infinite /* infinite make reapeat the animation indefinitely */;   
    } /* Create the animation */ @keyframes move {
      from {
          translateY(100%);
            transform: translateY(100%);}
      to { 
          translateY(-350%);
            transform: translateY(-350%); }
    }        
slots:
  default:
    - component: oh-repeater
      config:
        for: exitDelay
        sourceType: array
        in:
          - title: Partition 1 Exit Delay
            filter: OFF
          - title: Partition 2 Exit Delay
            filter: OFF
          - title: Partition 3 Exit Delay
            filter: OFF
          - title: Partition 4 Exit Delay
            filter: ON
        filter: ({'ON':1,'-':1})[loop.exitDelay.filter]
        fragment: true
      slots:
        default:
          - component: Label
            config:
              class: roll_block
              large: true
              raised: true
              style:
                background: var(--paradox-background-color)
                color: var(--paradox-font-color)
                flex: 0 0 420px
                font-size: 25px
                font-weight: 700
                white-space: nowrap
                width: 420px
              text: =loop.exitDelay.title

I would appreciate any ideas on how to make this look better?

It appears that to get the animation more consistent the scrolling would need to be applied to an already rendered component with the results from the oh-repeater so that the percentages used to calculate the animation are more accurate? Not sure if this is possible?

Any advise would be appreciated.
Mark

I’d say probably only two things that you want to adjust.

  1. You don’t want to be applying the animation to each label separately. You really want one block to keep the visible area cropped and one animated block that has all the content in it. A structure like this:
component: f7-block
  - component: f7-block <-- this is roll_block class
    - component: oh-repeater
      - component: Label
  1. Then you just have to adjust the size of the labels and the animation distance of the single block to get it spaced the way you want. You know that the display area is 90px so you want each of your labels to be that height (assuming that you want only one label to be visible at a time). You just want the animated block to start right at the bottom of the display area so instead of trying to calculate some % you just set the animation transform start at 90px. Similarly you can calculate a better end of the animation transform because you want it to start over as soon as the last text has passed through, not all the space below the last text. That’s 100% less 25px (your defined text height). Css has a calc function that lets you easily combine values with different units so thsi would be calc(-100% + 25px).

Thanks Justin. As usual you are 100% correct. I had tried to do this, but put my block inside the oh-repeater - which clearly was not correct and I ended up with multiple blocks.

I have done some adjustments as per your suggestions (showing block border etc to try get an idea of what is happening):

3 Visible inside block

It looks WAY better, but I still have the issue with the size of the scrolling block when there are less than 4 Labels to display. The block is fixed in size, so the “missing” Labels are replaced by empty space as you can see above.

My current code:

uid: filter_demo2
tags: []
props:
  parameters:
    - context: item
      description: Partition ExitDelay Group
      label: Partition ExitDelay Group
      name: partitionExitDelayGroup
      required: false
      type: TEXT
  parameterGroups: []
timestamp: Feb 25, 2023, 8:18:44 PM
component: f7-block
config:
  style:
    --f7-block-margin-horizontal: 0px
    --f7-block-margin-vertical: 0px
    --f7-block-padding-horizontal: 0px
    --f7-block-padding-verticall: 0px
    border-radius: 5px
    height: 45px
    justify-content: center
    left: 30px
    /*overflow: hidden*/
    position: absolute
    top: 20px
    width: 300px
    border: 2px solid black
  stylesheet: >
    .roll_block {
      display: block; /* Important to give the content a width */
      height: 100%;
      overflow: hidden;
      position: relative;
      /* Add the animation */
      animation: move 5s linear infinite /* infinite make reapeat the animation indefinitely */;   
    } /* Create the animation */ @keyframes move {
      from {
          translateY(25px);
            transform: translateY(25px);}
      to { 
          translateY(calc(-100% - 25px));
            transform: translateY(calc(-100% - 25px)); }
    }      
slots:
  default:
    - component: f7-block
      config:
        class: roll_block
        style:
          --f7-block-margin-horizontal: 0px
          --f7-block-margin-vertical: 0px
          --f7-block-padding-horizontal: 0px
          --f7-block-padding-verticall: 0px
          border-radius: 5px
          height: 150px
          justify-content: center
          left: 0px
          /*overflow: hidden*/
          position: absolute
          top: 20px
          width: 300px
          border: 2px solid black   
      slots:
        default:  
          - component: oh-repeater
            config:
              for: exitDelay
              sourceType: array
              in:
                - title: Partition 1 Exit Delay
                  filter: OFF
                - title: Partition 2 Exit Delay
                  filter: OFF
                - title: Partition 3 Exit Delay
                  filter: ON
                - title: Partition 4 Exit Delay
                  filter: ON
              filter: ({'ON':1,'-':1})[loop.exitDelay.filter]
              fragment: true
            slots:
              default:
                - component: Label
                  config:
                    class: roll_block1
                    large: true
                    raised: true
                    style:
                      background: var(--paradox-background-color)
                      color: var(--paradox-font-color)
                      flex: 0 0 420px
                      font-size: 25px
                      font-weight: 700
                      white-space: nowrap
                      width: 420px
                    text: =loop.exitDelay.title

4 Visible inside block

Any suggestions for making the size of the

Dynamic to match the number of Labels? Or some other “magic”

Thank you so much.

Why is the box fixed in size? You don’t need or want that. Get rid of the box’s height style and let it set its own height based on how many labels there are.

Thanks Justin.

If I remove the height:

    - component: f7-block
      config:
        class: roll_block
        style:
          --f7-block-margin-horizontal: 0px
          --f7-block-margin-vertical: 0px
          --f7-block-padding-horizontal: 0px
          --f7-block-padding-verticall: 0px
          /*overflow: hidden*/
          border: 2px solid black
          border-radius: 5px
          width: 300px
          justify-content: center
          left: 0px
          position: absolute
          top: 20px

Only 1 line of the Labels is displayed, even though all 4 should be. When I change back to height: 150px all 4 are shown.
3 Visible inside block

Cheers

You still have a ton of extra stuff from your various attempts (happens to me all the time). You should take a few moments to go back and clean up back down to only the bare bones.

This is because you are also setting the height and overflow styles in the roll_block class def and you don’t want either of those.

You don’t need any styles in the roll-block class def (that aren’t directly related to the animations) if you are going to use the style property of the component or vice versa. Here’s another example, you set the position style in under the block component:

but also in the roll_block class def:

Sorry for wasting your time. You were obviously correct. I guess this is a side effect of using examples that may not be 100% relevant but give you the basics that work until you are trying to do something more complex.

Works almost 100% as I wanted now with one small issue that only shows because the block is now a variable size - the speed of the animation becomes unbearably slow with only 1 item (works nicely with 5 seconds for 4 items, but 5 seconds for 1 item is not great…

1 Visible inside block

Do you know if a way to make the following dynamics?

animation: move 5s linear infinite /* infinite make repeat the animation indefinitely */;

I don’t think I can use the oh-repeater loop.variableName_source.length since the block is not a child of the oh-repeater. Any chance you have another solution?

My current code:

tags: []
props:
  parameters:
    - context: item
      description: Partition ExitDelay Group
      label: Partition ExitDelay Group
      name: partitionExitDelayGroup
      required: false
      type: TEXT
  parameterGroups: []
timestamp: Feb 26, 2023, 9:24:20 AM
component: f7-block
config:
  style:
    --f7-block-margin-horizontal: 0px
    --f7-block-margin-vertical: 0px
    --f7-block-padding-horizontal: 0px
    --f7-block-padding-verticall: 0px
    border: 2px solid black
    border-radius: 5px
    height: 45px
    justify-content: center
    left: 30px
    overflow: hidden
    position: absolute
    top: 20px
    width: 300px
  stylesheet: >
    .roll_block {
      display: block; /* Important to give the content a width */
      overflow: hidden;
      /* Add the animation */
      animation: move 5s linear infinite /* infinite make repeat  the animation indefinitely */;   
    } /* Create the animation */ @keyframes move {
      from {
          translateY(0px);
            transform: translateY(0px);}
      to { 
          translateY(calc(-100% - 25px));
            transform: translateY(calc(-100% - 25px)); }
    }      
slots:
  default:
    - component: f7-block
      config:
        class: roll_block
        style:
          --f7-block-margin-horizontal: 0px
          --f7-block-margin-vertical: 0px
          --f7-block-padding-horizontal: 0px
          --f7-block-padding-verticall: 0px
          /*overflow: hidden*/
          border: 2px solid black
          border-radius: 5px
          width: 300px
          justify-content: center
          left: 0px
          position: absolute
      slots:
        default:
          - component: oh-repeater
            config:
              filter: ({'ON':1,'-':1})[loop.exitDelay.filter]
              for: exitDelay
              fragment: true
              in:
                - filter: ON
                  title: Partition 1 Exit Delay
                - filter: OFF
                  title: Partition 2 Exit Delay
                - filter: OFF
                  title: Partition 3 Exit Delay
                - filter: OFF
                  title: Partition 4 Exit Delay
              sourceType: array
            slots:
              default:
                - component: Label
                  config:
                    large: true
                    raised: true
                    style:
                      background: var(--paradox-background-color)
                      color: var(--paradox-font-color)
                      flex: 0 0 420px
                      font-size: 25px
                      font-weight: 700
                      white-space: nowrap
                      width: 420px
                    text: =loop.exitDelay.title

I really appreciate the time you take to help and explain.

Not easily. This is one of those situations where because the stylesheet is not parsed, the only way to get dynamic values is to use a css variable for the value and set that value dynamically in the style object.

100% correct.

I actually just posted an explanation similar to what you are looking for in another thread:, but it adds a couple levels of component complexity to your widget:

Thanks Justin. Seems quite complex - but will give it a go…