How to make scroll-time/speed and TranslateX string length dependent in css animation

and yet there is an evolution…

css Marquee

(nevermind the choppiness here, thats because of reduce screen resolution of Giphy, it’s completely fluent in the real life View/Dashboard)

Ive dropped the complete ‘Marquee’ button inside a decluttering template, and make the core Frontend decide which orientation and as a consequence which available space there is for the Marquee:

type: vertical-stack
visibility:
  - condition: state
    entity: binary_sensor.alerts
    state: 'on'
cards:

  - type: conditional
    conditions:
      - condition: screen
        media_query: '(min-width:400px)'
    card:
      type: custom:decluttering-card
      template: marquee
      variables:
        - available: 36

  - type: conditional
    conditions:
      - condition: screen
        media_query: '(max-width:390px)'
      - condition: screen
        media_query: '(orientation:portrait)'
    card:
      type: custom:decluttering-card
      template: marquee
      variables:
        - available: 25

  - type: grid
    columns: 4
    cards: !include /config/dashboard/buttons/buttons_alerts.yaml

the decluttering template holds the complete Marquee:

Complete code inside the decluttering to be easily injected in the vertical-stack
card:
  type: custom:button-card
  entity: sensor.marquee_alerts
  template: styles_tooltip
  show_icon: false
#   triggers_update: all #no longer required, because of the visibility check on the containing vertical-stack
  variables:
    count: >
      [[[ return entity.state; ]]]
    phrase: >
      [[[ return entity.state == 1 ? 'Alert:' : 'Alerts:'; ]]]
    marquee: >
      [[[ return entity.attributes.marquee; ]]]
    length: >
      [[[ return Math.round(entity.attributes.marquee.length); ]]]
    snelheid: >
       [[[ return states['input_number.marquee_snelheid'].state; ]]]
    available: '[[available]]'
  styles:
    grid:
      - grid-template-areas: '"n marquee" '
      - grid-template-columns: max-content 1fr
    card:
      - background: var(--background-color-off)
      - color: var(--text-color-off)
      - font-size: 20px
      - font-weight: 400
      - padding: 12px
      - height: 48px
    name:
      - justify-self: left
      - text-align: center
      - padding-right: 4px
      - font-family: led_counter-7
    custom_fields:
      marquee:
        - font-family: led_counter-7
        - text-align: center

  # create local vars to inject in extra_styles
        - --scroll-time: >
            [[[ return variables.snelheid*variables.length/100 + 's'; ]]]
  #       - animation: scroll 5s linear infinite # not here because overflows name/full button
        - --trans-x: >
            [[[ return '-' + 100*(variables.length/variables.available) + '%' ; ]]]
  name: >
    [[[ return variables.count + ' ' + variables.phrase; ]]]
  custom_fields:
    marquee: >
      [[[ return `<p>${variables.marquee}</p>`; ]]]
  extra_styles: |
    p {
      animation: scroll var(--scroll-time) linear infinite;
      animation-delay: 1s;
      /*animation-direction: reverse;*/
    }
    @keyframes scroll {
      0% { transform: translateX(90%); }
      100% { transform: translateX( var(--trans-x) ); }
    }

and the sensor.marquee_alerts is just a huge template sensor building on individual alerts

Actual Marquee with all texts that need to be scrolling by
template:

  - sensor:

      - unique_id: marquee_alerts
        state: >
          {{states('sensor.alerts_notifying')|int(0)}}
        icon: >
          mdi:{{'check' if is_state('sensor.alerts_notifying','0') else 'alert'}}-circle
        attributes:
          marquee: >
            {%- if is_state('binary_sensor.alerts','on') -%}
              {%- if is_state('binary_sensor.config_notifications','on') %} - Updates of repairs actief{{'\n'}}{%- endif -%}
              {%- if is_state('binary_sensor.rookmelder','on') %} - Rook gesignaleerd, controleer keuken, zolder en/of stookhok!!{{'\n'}}{%- endif -%}
              {%- if is_state('binary_sensor.co_alert','on') %} - CO gemeten, controleer zolder en/of stookhok!!{{'\n'}}{%- endif -%}
              {%- if is_state('binary_sensor.watermeter_leak_detected','on') %} - Water lekkage, controleer of er een kraan open staat!!{{'\n'}}{%- endif -%}
              {%- if is_state('binary_sensor.alarm_triggered','on') -%} - Alarm getriggered, controleer!!{{'\n'}}{%- endif -%}
              {%- if is_state('binary_sensor.flood_alert','on') -%} - Overstroming gesignaleerd: {{state_attr('sensor.flood_sensors','status')}}{{'\n'}}{%- endif -%}
              {%- if is_state('binary_sensor.garage_deur','on') -%} - Garage deur is open, controleer camera{{'\n'}}{%- endif -%}
              {%- if is_state('binary_sensor.schuifpuien','on') -%} - {{state_attr('sensor.schuifpuien_samenvatting','tekst')}}{{'\n'}}{%- endif -%}
              {%- if is_state('binary_sensor.deuren','on') -%} - {{state_attr('sensor.deuren_samenvatting','tekst')}}{{'\n'}}{%- endif -%}
              {%- if is_state('binary_sensor.ramen','on') -%} - {{state_attr('sensor.ramen_samenvatting','tekst')}}{{'\n'}}{%- endif -%}
              {%- if is_state('binary_sensor.klimaat_woonkamer_alert','on') -%} - Klimaat woonkamer: Ventileer!{{'\n'}}{%- endif -%}
              {%- if is_state('binary_sensor.schimmel_alert','on') -%} - Schimmel alert: {{states('sensor.schimmel_sensor')|float(0)}}% / CO2: {{states('sensor.co2_woonkamer')}} ppm{{'\n'}}{%- endif -%}
              {%- if is_state('binary_sensor.luchtvochtigheid_woonkamer_laag','on') -%} - Luchtvochtigheid in de woonkamer is te laag: {{states('sensor.luchtvochtigheid_woonkamer')}} %{{'\n'}}{%- endif -%}
              {%- if is_state('binary_sensor.uv_alert','on') -%} - Uv index: {{state_attr('binary_sensor.uv_alert','uv_index')}}, maximaal {{state_attr('binary_sensor.uv_alert','maximaal_in_zon')}} minuten in de zon!{{'\n'}}{%- endif -%}
              {%- if is_state('binary_sensor.meteoalarm_brabant','on') -%} - MeteoAlarm: {{state_attr('binary_sensor.meteoalarm_brabant','headline').split(' -')[0]}}{{'\n'}}{%- endif -%}
              {%- if is_state('binary_sensor.earthquakes_near_active','on') -%} - Opgepast, aardbeving in de buurt: {{state_attr('sensor.earthquakes_near','list')}}{{'\n'}}{%- endif -%}
              {%- if is_state('binary_sensor.lightning_nearest_below_range','on') -%} - Opgepast, bliksem: {{states('sensor.lightning_strikes_near')}} inslag{{'en' if states('sensor.lightning_strikes_near')|int(0) != 1}} in de buurt, ga naar binnen!{{'\n'}}{%- endif -%}
              {%- if is_state('binary_sensor.espresso_needs_refill','on') -%} - Espresso {{states('sensor.espresso')}}{{'\n'}}{%- endif -%}
              {%- if is_state('binary_sensor.hubs_offline','on') -%} - {{state_attr('sensor.hubs_samenvatting','message')}}{{'\n'}}{%- endif -%}
              {%- if is_state('binary_sensor.kritieke_schakelaars_offline','on') -%} - {{state_attr('sensor.kritieke_schakelaars_samenvatting','message')}}{{'\n'}}{%- endif -%}
              {%- if is_state('binary_sensor.afvalwijzer_notificatie','on') -%} - {{states('sensor.afval_alert')}}{{'\n'}}{%- endif -%}


            {%- else -%} Geen actieve waarschuwingen
            {%- endif -%}
1 Like