Animations with OpenHAB

animation_v2

For my Sun2000 widget, I worked on the topic of animation in OpenHAB. I have learnt a lot again.

I would like to pass on the basics here using a widget that has been significantly reduced in complexity:

uid: ud_animation_widget
tags: []
props:
  parameters:
    - description: Direction of animatin
      label: Richtung Vorwärts?
      name: direction
      required: false
      type: BOOLEAN
    - description: Speed of animation
      label: Geschwindigkeit
      name: speed
      required: false
      type: TEXT
      options:
        - label: 1 second
          value: 1s
        - label: 4 seconds
          value: 4s
        - label: 8 seconds
          value: 8s
        - label: 16 seconds
          value: 16s
  parameterGroups: []
timestamp: Mar 19, 2024, 9:48:26 PM
component: f7-card
config:
  style:
    border: 3px solid green
    border-radius: 20px
    height: auto
    text-align: center
    width: 200px
  title: Watch animation!
  footer: "=props.speed + ((props.richtung) ? ' forward' : ' backwards')"
slots:
  content:
    - component: f7-col
      config:
        style:
          width: 200px
          height: 110px
        tag: svg
        xmlns: http://www.w3.org/2000/svg
      slots:
        default:
          - component: f7-row
            config:
              d: M0,15 h20 q60,0 60,45 t60,45 h20
              fill: none
              id: examplepath
              stroke: orange
              stroke-width: 1
              tag: path
          - component: f7-row
            config:
              fill: orange
              r: 6
              tag: circle
              visible: true
            slots:
              default:
                - component: f7-row
                  config:
                    dur: "=(props.speed) ? props.speed : 8"
                    keyPoints: "=(props.direction) ? '0;1' : '1;0'"
                    keyTimes: 0;1
                    repeatCount: indefinite
                    tag: animateMotion
                  slots:
                    default:
                      - component: f7-row
                        config:
                          tag: mpath
                          xlink:href: "#examplepath"

The animation consists of four lines within a parent element.

  • The first line describes the path (tag: path)
  • the second line describes the object that is moved (tag: circle)
  • the third line describes the movement (tag: animateMotion)
  • the fourth line binds the animation to the path (tag: mpath) via the id: examplepath

The tags and most of the keywords in the listings are SVG elements. Documentation on SVG elements can be found on the Mozilla website: SVG Attribute reference - SVG: Scalable Vector Graphics | MDN

A short description of the path, here the line drawing is described:

   d: M0,15 h20 q60,0 60,45 t60,45 h20

Specifically, the following is defined here (the comma is always between the components of a point)

  • MoveTo (0,15)
  • Line horizontel 20 points
  • Square Bézier curve to the point (60,45) with the control point (60,0)
  • Square Bézier curve as above, but mirrored at point (60,45)
  • Horizontal line 20 points

You can adjust the direction of movement and the speed via the props settings, but the animation should also work without further input.

I was mainly interested in the possibility of working with BOOLEAN parameters and the options for TEXT parameters.

5 Likes

Thanks for posting this, it does seem that lots of users are looking for things like this recently.

Here’s one small comment for you. You don’t need to use the tag property any more. The examples where you found that form are from the early versions of OH3. For any version more recent than 3.1 or so, you can just put xml tags (html or svg, etc.) directly in the component line which makes svgs like this a little easier to read. For example:

    - component: f7-col
      config:
        style:
          width: 200px
          height: 110px
        tag: svg
        xmlns: http://www.w3.org/2000/svg

becomes

    - component: svg
      config:
        style:
          width: 200px
          height: 110px
        xmlns: http://www.w3.org/2000/svg
1 Like

Great, your hint really makes this more readable, I never liked the nested f7-row.
I changed the script straight away:

uid: ud_animation_widget
tags: []
props:
  parameters:
    - description: Direction of animatin
      label: Richtung Vorwärts?
      name: direction
      required: false
      type: BOOLEAN
    - description: Speed of animation
      label: Geschwindigkeit
      name: speed
      required: false
      type: TEXT
      options:
        - label: 1 second
          value: 1s
        - label: 4 seconds
          value: 4s
        - label: 8 seconds
          value: 8s
        - label: 16 seconds
          value: 16s
  parameterGroups: []
timestamp: Mar 20, 2024, 6:33:20 PM
component: f7-card
config:
  style:
    border: 3px solid green
    border-radius: 20px
    height: auto
    text-align: center
    width: 200px
  title: Watch animation!
  footer: "=props.speed + ((props.direction) ? ' forward' : ' backwards')"
slots:
  content:
    - component: svg
      config:
        style:
          width: 200px
          height: 110px
        xmlns: http://www.w3.org/2000/svg
      slots:
        default:
          - component: path
            config:
              d: M0,15 h20 q60,0 60,45 t60,45 h20
              fill: none
              id: examplepath
              stroke: orange
              stroke-width: 1
          - component: circle
            config:
              fill: orange
              r: 6
              visible: true
            slots:
              default:
                - component: animateMotion
                  config:
                    dur: "=(props.speed) ? props.speed : 8"
                    keyPoints: "=(props.direction) ? '0;1' : '1;0'"
                    keyTimes: 0;1
                    repeatCount: indefinite
                  slots:
                    default:
                      - component: mpath
                        config:
                          xlink:href: "#examplepath"

I will also revise my Sun2000 widget again with this information.

1 Like

For this to work in Safari, the config for the animateMotion component needs

calcMode: linear

This is a good explanation. I will use it.

The id (examplepath) must be unique. You can use it different times in a page as long as the properties stay the same. If you want to use it more than once with different properties, you have to add something to the id to make it unique.

You could define a item property (with name: itemName) and add the itemName property to the id:

...
id: ='examplepath'+props.itemName
...
xlink:href: ='#examplepath'+props.itemName

It would be even better if you could add a random number, but I did not find how to do it.

Small detail: you can avoid double quotes if you use the ternary operator by eliminating the spaces. Brackets does not seem necessary too.

This:

footer: "=props.speed + ((props.direction) ? ' forward' : ' backwards')"
dur: "=(props.speed) ? props.speed : 8"
keyPoints: "=(props.direction) ? '0;1' : '1;0'"

is the same as this:

footer: =props.speed + props.direction?' forward':' backwards'
dur: =props.speed?props.speed:8
keyPoints: =props.direction?'0;1':'1;0'

I have updated this listing again, based on the suggestions here and my research on the subject of parameters:

uid: ud_animation_widget
tags:
  - Animation Widget V 2.0
props:
  parameters:
    - default: 1;0
      description: Direction of animation
      name: direction
      required: false
      type: TEXT
      limitToOptions: true
      options:
        - label: forward
          value: 0;1
        - label: backwards
          value: 1;0
    - default: 8s
      description: duration of animation
      label: Animationsdauer
      name: duration
      required: false
      type: TEXT
      options:
        - label: 1 second
          value: 1s
        - label: 4 seconds
          value: 4s
        - label: 8 seconds
          value: 8s
        - label: 16 seconds
          value: 16s
  parameterGroups: []
timestamp: Mar 28, 2024, 12:27:25 PM
component: f7-card
config:
  style:
    border: 3px solid green
    border-radius: 20px
    height: auto
    text-align: center
    width: 200px
  title: Watch animation!
  footer: =props.duration+((props.direction=='0;1')?' forward':' backwards')
slots:
  content:
    - component: svg
      config:
        style:
          width: 200px
          height: 110px
        xmlns: http://www.w3.org/2000/svg
      slots:
        default:
          - component: path
            config:
              d: M0,15 h20 q60,0 60,45 t60,45 h20
              fill: none
              id: examplepath
              stroke: orange
              stroke-width: 1
          - component: circle
            config:
              fill: orange
              r: 6
              visible: true
            slots:
              default:
                - component: animateMotion
                  config:
                    dur: =props.duration
                    keyPoints: =props.direction
                    keyTimes: 0;1
                    repeatCount: indefinite
                    calcMode: linear
                  slots:
                    default:
                      - component: mpath
                        config:
                          xlink:href: "#examplepath"