Mechanical counter display

Just for fun.

image

[{"id":"656888cd7308428e","type":"inject","z":"bf0d83d32eec75c2","name":"","props":[{"p":"payload"},{"p":"topic","vt":"str"}],"repeat":"1","crontab":"","once":false,"onceDelay":0.1,"topic":"","payload":"","payloadType":"date","x":230,"y":860,"wires":[["b7f0df3f43a8dc6e"]]},{"id":"b7f0df3f43a8dc6e","type":"function","z":"bf0d83d32eec75c2","name":"random data","func":"let current = context.get('current') || 1\n\ncurrent += Math.floor(Math.random()*2);\nif(current > 999999){\n    current = 1\n}\n\ncontext.set('current',current)\nmsg.payload = current \nreturn msg;","outputs":1,"noerr":0,"initialize":"","finalize":"","libs":[],"x":390,"y":860,"wires":[["aac264ba0df29e45"]]},{"id":"bf8580a24000c55c","type":"ui_template","z":"bf0d83d32eec75c2","group":"55888982bdd0637f","name":"display","order":5,"width":0,"height":0,"format":"<div id=\"{{'slot_'+$id+'_0'}}\" class=\"slot\" ng-init=\"init()\">\n    <div class=\"num current\"></div>\n    <div class=\"num next\"></div>\n</div>\n<div id=\"{{'slot_'+$id+'_1'}}\" class=\"slot\">\n    <div class=\"num current\"></div>\n    <div class=\"num next\"></div>\n</div>\n<div id=\"{{'slot_'+$id+'_2'}}\" class=\"slot\">\n    <div class=\"num current\"></div>\n    <div class=\"num next\"></div>\n</div>\n<div id=\"{{'slot_'+$id+'_3'}}\" class=\"slot\">\n    <div class=\"num current\"></div>\n    <div class=\"num next\"></div>\n</div>\n<div id=\"{{'slot_'+$id+'_4'}}\" class=\"slot\">\n    <div class=\"num current\"></div>\n    <div class=\"num next\"></div>\n</div>\n<div id=\"{{'slot_'+$id+'_5'}}\" class=\"slot\">\n    <div class=\"num current\"></div>\n    <div class=\"num next\"></div>\n</div>\n<div class=\"gap\"></div>\n<div id=\"{{'slot_'+$id+'_6'}}\" class=\"slot last\">\n    <div class=\"num current\"></div>\n    <div class=\"num next\"></div>\n</div>\n<div id=\"{{'slot_'+$id+'_7'}}\" class=\"slot last\">\n    <div class=\"num current\"></div>\n    <div class=\"num next\"></div>\n</div>\n<div class=\"unit\">kWh</div>\n\n<script>\n    (function(scope) {\n        let lock = 0\n        const count = 8\n        scope.previous = Array(count).fill(-1);\n        scope.drawlist = Array(count).fill(true);\n        scope.inited = false\n        scope.waitingData = null       \n        scope.init = function(){\n            if($(\"#slot_\"+scope.$id+\"_0\".length)){\n                actuallyInit()\n            }\n            else{\n                setTimeout(function(){\n                    actuallyInit()\n                },40)\n            }\n        }\n        function actuallyInit(){            \n            lock = 0\n            if(scope.waitingData){                \n                setTimeout(function(){\n                    callDraw()\n                },40)\n            }\n            scope.inited = true\n        }\n\n        scope.$watch('msg', function(msg) {\n            if (msg) { \n                let data = msg.payload.toString().split('')\n                if(!scope.inited){\n                    scope.waitingData = data\n                    return\n                }\n                if(checkCollapsed()){\n                    scope.waitingData = data\n                    return\n                }\n                if(locked()){\n                    scope.waitingData = data\n                    validateLocks()\n                }\n                else{\n                    if(!draw(data)){\n                        scope.waitingData = data\n                        setTimeout(function(){\n                            validateLocks()\n                        },40)\n                    }\n                    \n                }\n            }\n        });\n\n        function checkCollapsed(){\n           let d =  $(\"#slot_\"+scope.$id+\"_0\").closest('.nr-dashboard-cardcontainer').css('display')\n           if(d == 'none'){\n              lock = 0\n              return true\n           }\n           return false\n        }\n\n        function locked(){\n            return lock > 0 \n        }\n\n        function pickLock(){\n            if(locked()){\n                lock --;\n            }\n            if(lock < 0){\n                lock = 0;\n                return\n            }\n            if(!locked()){\n                if(scope.waitingData){\n                    setTimeout(function(){\n                        callDraw()\n                    },10)                    \n                }\n            }\n        }\n\n        function validateLocks(){\n            let e = 0\n            for(let i = 0;i<count;++i){\n                e += $(\"#slot_\"+scope.$id+\"_\"+i).find(\".current\").text().length\n            }          \n            if(e == 0){                \n                lock = 0\n                callDraw()\n            }\n        }\n\n        function callDraw(){           \n            if(!scope.waitingData){\n                return\n            }\n            draw(Array.from(scope.waitingData))            \n            scope.waitingData = null;\n        }\n\n        function draw(data){\n            if(locked()){                \n                return\n            }\n            let failures = 0            \n            while(data.length < count){\n                data.unshift(\"0\")\n            }\n            data.forEach((d,i)=>{\n                //d = parseInt(d)\n                if(scope.previous[i] == d && $(\"#slot_\"+scope.$id+\"_\"+i).find(\".current\").text().length > 0){\n                    scope.drawlist[i] = false\n                }\n                else{\n                    scope.previous[i] = d\n                    scope.drawlist[i] = true\n                    lock ++;\n                }            \n            })\n            data.forEach((d,i) => {\n                if(scope.drawlist[i] == false){\n                    return\n                }\n                let current = $(\"#slot_\"+scope.$id+\"_\"+i).find(\".current\")\n                let next = $(\"#slot_\"+scope.$id+\"_\"+i).find(\".next\")\n                let old = $(\"#slot_\"+scope.$id+\"_\"+i).find(\".old\")            \n           \n                if(next.length == 0 && old.length > 0){\n                    old.removeClass(\"old\").addClass(\"next\")\n                    next = $(\"#slot_\"+scope.$id+\"_\"+i).find(\".next\")\n                }\n                \n                next.text(data[i])\n                if(next.length == 0){                   \n                    failures ++\n                }               \n                current.removeClass(\"current\").addClass(\"old\").on('transitionend webkitTransitionEnd oTransitionEnd', function () {\n                    old = $(\"#slot_\"+scope.$id+\"_\"+i).find(\".old\")\n                    old.off('transitionend webkitTransitionEnd oTransitionEnd')\n                    old.removeClass(\"old\").addClass(\"next\")\n                    pickLock()\n                });\n                next.removeClass(\"next\").addClass(\"current\")\n               \n            })\n            return failures == 0\n        }\n})(scope);\n</script>","storeOutMessages":true,"fwdInMessages":true,"resendOnRefresh":true,"templateScope":"local","className":"roll-display","x":560,"y":900,"wires":[[]]},{"id":"f94b5cb02555e740","type":"ui_template","z":"bf0d83d32eec75c2","group":"674712f8d915bcc0","name":"display css","order":8,"width":0,"height":0,"format":"<style id='roll-display-styles'>\n    .roll-display {\n        --size: 2;\n        --speed: .95;\n        display: flex;\n        align-content: center;\n        justify-content: center;\n        align-items: center;\n        flex-direction: row;\n        overflow: hidden;\n    }\n\n    .roll-display .slot {\n        height: calc(var(--size) * 1em);\n        width: calc(var(--size) * .8em);\n        text-align: center;\n        line-height: calc(var(--size) * 1em);\n        outline: 1px solid #4d4d4d;\n        outline-offset: -3px;\n        border: 3px solid #000000a3;\n        border-radius: 6px;\n        position: relative;\n        overflow: hidden;\n        background: linear-gradient(0deg, #161616, #7e7e7e, #161616);\n    }\n\n    .roll-display .last {\n        background: linear-gradient(0deg, #5a5a5a, #e5e5e5, #5d5d5d);\n    }\n\n    .roll-display .num {\n        position: absolute;\n        left: 0;\n        right: 0;\n        user-select: none;\n        font-size: calc(var(--size) *.7em);\n    }\n\n    .roll-display .last>.num {\n        color: #2f2f2f;\n    }\n\n    .roll-display .num:after {\n        content: \"\";\n        position: absolute;\n        left: -2%;\n        width: 20%;\n        top: 0;\n        height: 100%;\n        background: linear-gradient(to bottom,\n                #00000050,\n                #00000050 50%,\n                transparent 50%,\n                transparent);\n        background-size: 100% 7%;\n    }\n    \n    .roll-display .num:before {\n        content: \"\";\n        position: absolute;\n        right: -2%;\n        width: 20%;\n        top: 0;\n        height: 100%;\n        background: linear-gradient(to bottom,\n                #00000050,\n                #00000050 50%,\n                transparent 50%,\n                transparent);\n        background-size: 100% 7%;\n    }\n\n    .roll-display .last>.num:before{\n        background: linear-gradient(to bottom,\n        #00000030,\n        #00000030 50%,\n        transparent 50%,\n        transparent);\n        background-size: 100% 7%;\n    }\n    \n    .roll-display .last>.num:after{\n        background: linear-gradient(to bottom,\n        #00000030,\n        #00000030 50%,\n        transparent 50%,\n        transparent);\n        background-size: 100% 7%;\n    }\n\n    .roll-display .current {\n        top: 0%;\n        transition: top calc(var(--speed) *1s) ease-in;\n    }\n\n    .roll-display .old {\n        top: 100%;\n        transition: top calc(var(--speed) *1s) ease-in;\n    }\n\n    .roll-display .next {\n        top: -100%;\n        transition: none;\n    }\n\n    .roll-display .gap {\n        position: relative;\n        width: 8px;\n    }\n\n    .roll-display .gap:after {\n        content: '•';\n        position: absolute;\n        text-align: center;\n        inset: 0;\n        color: #b9b9b9;\n    }\n\n    .roll-display .label {\n        display: flex;\n        flex-direction: column;\n        justify-content: center;\n        padding-right: 1em;\n    }\n\n    .roll-display .unit {\n        display: flex;\n        flex-direction: column;\n        justify-content: center;\n        padding-left: 0.5em;\n    }\n</style>","storeOutMessages":true,"fwdInMessages":true,"resendOnRefresh":true,"templateScope":"global","className":"","x":570,"y":820,"wires":[[]]},{"id":"aac264ba0df29e45","type":"ui_template","z":"bf0d83d32eec75c2","group":"55888982bdd0637f","name":"display last 2 red","order":5,"width":0,"height":0,"format":"<style>\n    .roll-display.red .last>.num {\n        color: #bd1818;\n       /* text-shadow: 0px 0px 1px black;*/\n    }\n</style>\n\n<div id=\"{{'slot_'+$id+'_0'}}\" class=\"slot\" ng-init=\"init()\">\n    <div class=\"num current\"></div>\n    <div class=\"num next\"></div>\n</div>\n<div id=\"{{'slot_'+$id+'_1'}}\" class=\"slot\">\n    <div class=\"num current\"></div>\n    <div class=\"num next\"></div>\n</div>\n<div id=\"{{'slot_'+$id+'_2'}}\" class=\"slot\">\n    <div class=\"num current\"></div>\n    <div class=\"num next\"></div>\n</div>\n<div id=\"{{'slot_'+$id+'_3'}}\" class=\"slot\">\n    <div class=\"num current\"></div>\n    <div class=\"num next\"></div>\n</div>\n<div id=\"{{'slot_'+$id+'_4'}}\" class=\"slot\">\n    <div class=\"num current\"></div>\n    <div class=\"num next\"></div>\n</div>\n<div id=\"{{'slot_'+$id+'_5'}}\" class=\"slot\">\n    <div class=\"num current\"></div>\n    <div class=\"num next\"></div>\n</div>\n<div class=\"gap\"></div>\n<div id=\"{{'slot_'+$id+'_6'}}\" class=\"slot last\">\n    <div class=\"num current\"></div>\n    <div class=\"num next\"></div>\n</div>\n<div id=\"{{'slot_'+$id+'_7'}}\" class=\"slot last\">\n    <div class=\"num current\"></div>\n    <div class=\"num next\"></div>\n</div>\n<div class=\"unit\">MWh</div>\n\n<script>\n    (function(scope) {\n        let lock = 0\n        const count = 8\n        scope.previous = Array(count).fill(-1);\n        scope.drawlist = Array(count).fill(true);\n        scope.inited = false\n        scope.waitingData = null       \n        scope.init = function(){\n            if($(\"#slot_\"+scope.$id+\"_0\".length)){\n                actuallyInit()\n            }\n            else{\n                setTimeout(function(){\n                    actuallyInit()\n                },40)\n            }\n        }\n        function actuallyInit(){            \n            lock = 0\n            if(scope.waitingData){                \n                setTimeout(function(){\n                    callDraw()\n                },40)\n            }\n            scope.inited = true\n        }\n\n        scope.$watch('msg', function(msg) {\n            if (msg) { \n                let data = msg.payload.toString().split('')\n                if(!scope.inited){\n                    scope.waitingData = data\n                    return\n                }\n                if(checkCollapsed()){\n                    scope.waitingData = data\n                    return\n                }\n                if(locked()){\n                    scope.waitingData = data\n                    validateLocks()\n                }\n                else{\n                    if(!draw(data)){\n                        scope.waitingData = data\n                        setTimeout(function(){\n                            validateLocks()\n                        },40)\n                    }\n                    \n                }\n            }\n        });\n\n        function checkCollapsed(){\n           let d =  $(\"#slot_\"+scope.$id+\"_0\").closest('.nr-dashboard-cardcontainer').css('display')\n           if(d == 'none'){\n              lock = 0\n              return true\n           }\n           return false\n        }\n\n        function locked(){\n            return lock > 0 \n        }\n\n        function pickLock(){\n            if(locked()){\n                lock --;\n            }\n            if(lock < 0){\n                lock = 0;\n                return\n            }\n            if(!locked()){\n                if(scope.waitingData){\n                    setTimeout(function(){\n                        callDraw()\n                    },10)                    \n                }\n            }\n        }\n\n        function validateLocks(){\n            let e = 0\n            for(let i = 0;i<count;++i){\n                e += $(\"#slot_\"+scope.$id+\"_\"+i).find(\".current\").text().length\n            }          \n            if(e == 0){                \n                lock = 0\n                callDraw()\n            }\n        }\n\n        function callDraw(){           \n            if(!scope.waitingData){\n                return\n            }\n            draw(Array.from(scope.waitingData))            \n            scope.waitingData = null;\n        }\n\n        function draw(data){\n            if(locked()){                \n                return\n            }\n            let failures = 0            \n            while(data.length < count){\n                data.unshift(\"0\")\n            }\n            data.forEach((d,i)=>{\n                //d = parseInt(d)\n                if(scope.previous[i] == d && $(\"#slot_\"+scope.$id+\"_\"+i).find(\".current\").text().length > 0){\n                    scope.drawlist[i] = false\n                }\n                else{\n                    scope.previous[i] = d\n                    scope.drawlist[i] = true\n                    lock ++;\n                }            \n            })\n            data.forEach((d,i) => {\n                if(scope.drawlist[i] == false){\n                    return\n                }\n                let current = $(\"#slot_\"+scope.$id+\"_\"+i).find(\".current\")\n                let next = $(\"#slot_\"+scope.$id+\"_\"+i).find(\".next\")\n                let old = $(\"#slot_\"+scope.$id+\"_\"+i).find(\".old\")            \n           \n                if(next.length == 0 && old.length > 0){\n                    old.removeClass(\"old\").addClass(\"next\")\n                    next = $(\"#slot_\"+scope.$id+\"_\"+i).find(\".next\")\n                }\n                \n                next.text(data[i])\n                if(next.length == 0){                   \n                    failures ++\n                }               \n                current.removeClass(\"current\").addClass(\"old\").on('transitionend webkitTransitionEnd oTransitionEnd', function () {\n                    old = $(\"#slot_\"+scope.$id+\"_\"+i).find(\".old\")\n                    old.off('transitionend webkitTransitionEnd oTransitionEnd')\n                    old.removeClass(\"old\").addClass(\"next\")\n                    pickLock()\n                });\n                next.removeClass(\"next\").addClass(\"current\")\n               \n            })\n            return failures == 0\n        }\n})(scope);\n</script>","storeOutMessages":true,"fwdInMessages":true,"resendOnRefresh":true,"templateScope":"local","className":"roll-display red","x":590,"y":860,"wires":[[]]},{"id":"608b4f75f0cdc9b1","type":"function","z":"bf0d83d32eec75c2","name":"random data","func":"let current = context.get('current') || 1\n\ncurrent += Math.floor(Math.random()*100);\nif(current > 999999){\n    current = 1\n}\n\ncontext.set('current',current)\nmsg.payload = current \nreturn msg;","outputs":1,"noerr":0,"initialize":"","finalize":"","libs":[],"x":390,"y":900,"wires":[["bf8580a24000c55c"]]},{"id":"93a93c8c71124851","type":"inject","z":"bf0d83d32eec75c2","name":"","props":[{"p":"payload"},{"p":"topic","vt":"str"}],"repeat":"2","crontab":"","once":false,"onceDelay":0.1,"topic":"","payload":"","payloadType":"date","x":230,"y":900,"wires":[["608b4f75f0cdc9b1"]]},{"id":"55888982bdd0637f","type":"ui_group","name":"1. group","tab":"62083694d0eab7ca","order":1,"disp":true,"width":"6","collapse":false,"className":""},{"id":"674712f8d915bcc0","type":"ui_group","name":"1. group","tab":"8482b305c416b850","order":1,"disp":true,"width":"6","collapse":true,"className":"ordered-1"},{"id":"62083694d0eab7ca","type":"ui_tab","name":"Home","icon":"dashboard","order":1,"disabled":false,"hidden":false},{"id":"8482b305c416b850","type":"ui_tab","name":"Away","icon":"dashboard","disabled":false,"hidden":false}]

Now I will have to find a way to use this in my dashboard :wink:

Speaking of which I'm already trying to modify this https://discourse.nodered.org/t/dashboard-tips-let-the-ui-text-act-as-level-gauge-diy-gauge-examples/40878

My curtains have 2 motors which are separate so it needs to accept 2 values 1 for left and 1 for right.

Any tips :thinking:

PS you should post these in the flows section !!

It really is a widget for the node-red dashboard only and there isn't much a flow shared.

For curtains:
$("#level_"+scope.$id).find(".levelbody.side") selects left and right
$("#level_"+scope.$id).find(".levelbody.side.left") selects left only
$("#level_"+scope.$id).find(".levelbody.side.right") selects right only

Please make this to display current time. This is excellent

I tried modifying your code, but this is not looking elegant, how do i control the spaces to get a compact clock ?

image

[{"id":"656888cd7308428e","type":"inject","z":"d12f70e7abaacb43","name":"","props":[{"p":"payload"},{"p":"topic","vt":"str"}],"repeat":"1","crontab":"","once":false,"onceDelay":0.1,"topic":"","payload":"","payloadType":"date","x":350,"y":2340,"wires":[["b7f0df3f43a8dc6e","7298fbb97901e0de"]]},{"id":"7298fbb97901e0de","type":"simpletime","z":"d12f70e7abaacb43","name":"","mydate":true,"myymd":true,"myyear":true,"mymonth":true,"mymonthn":true,"mydom":true,"mydoy":true,"myday":true,"myhourpm":true,"myhour":true,"mytime":true,"mytimes":true,"myminute":true,"myminutes":true,"mysecond":true,"mymillis":true,"myepoch":true,"myrawdate":true,"mypm":true,"x":520,"y":2340,"wires":[["ba666f4f58d33ae3"]]},{"id":"ba666f4f58d33ae3","type":"change","z":"d12f70e7abaacb43","name":"","rules":[{"t":"set","p":"payload","pt":"msg","to":"mytimes","tot":"msg"}],"action":"","property":"","from":"","to":"","reg":false,"x":700,"y":2340,"wires":[["a664b3b1662e2510"]]},{"id":"a664b3b1662e2510","type":"ui_template","z":"d12f70e7abaacb43","group":"513419908d693a02","name":"display","order":5,"width":0,"height":0,"format":"<style>\n    .roll-display {\n        display: flex;\n        align-content: center;\n        justify-content: flex-start;\n        flex-direction: row;\n    }\n    .slot {\n        height: 1.6em;\n        width: 1.2em;\n        text-align: center;\n        line-height: 1.6em;\n        border: 4px solid #000000a3;\n        border-radius: 6px;\n        border-top-width: 8px;\n        border-bottom-width: 8px;\n        position: relative;\n        overflow: hidden;\n        background: linear-gradient(0deg, #5a5a5a, #b7b7b7,#5d5d5d);\n    }\n    .num{\n        position:absolute;\n        left: 0;\n        right: 0;\n        user-select:none;\n        background: linear-gradient(0deg, #0000005e, #4c4c4c42, #0000005e);\n    } \n    .current{       \n        top:0em;\n        transition: top 0.25s;\n    }\n    .old{\n        top:1.6em;\n        transition: top 0.25s;\n    }\n    .next{\n        top:-1.6em;\n        transition: none;\n    }\n    .last > .num{\n       \n        background: linear-gradient(0deg, #53535300, #d5d5d52e, #53535300);\n        color: #464646;\n        font-weight: 700;\n        \n    }\n    .gap {\n        position:relative;\n        width: 8px;\n    }\n    .gap:after {\n        content:'•';\n        position:absolute;\n        bottom:0;\n        color:#a4a4a4;\n    }\n    .label{\n        display: flex;\n        flex-direction: column;\n        justify-content: center;\n        padding-right:1em;\n    }\n</style>\n\n<div class=\"label\">COUNTER</div>\n\n<div id=\"{{'slot_'+$id+'_0'}}\" class=\"slot\">\n    <div class=\"num current\"></div>\n    <div class=\"num next\"></div>\n</div>\n\n<div id=\"{{'slot_'+$id+'_1'}}\" class=\"slot\">\n    <div class=\"num current\"></div>\n    <div class=\"num next\"></div>\n</div>\n\n<div id=\"{{'slot_'+$id+'_2'}}\" class=\"slot\">\n    <div class=\"num current\"></div>\n    <div class=\"num next\"></div>\n</div>\n\n<div class=\"gap\"></div>\n\n<div id=\"{{'slot_'+$id+'_3'}}\" class=\"slot last\">\n    <div class=\"num current\"></div>\n    <div class=\"num next\"></div>\n</div>\n\n<div class=\"gap\"></div>\n\n<div id=\"{{'slot_'+$id+'_4'}}\" class=\"slot last\">\n    <div class=\"num current\"></div>\n    <div class=\"num next\"></div>\n</div>\n\n<div id=\"{{'slot_'+$id+'_5'}}\" class=\"slot last\">\n    <div class=\"num current\"></div>\n    <div class=\"num next\"></div>\n</div>\n\n<div class=\"gap\"></div>\n\n<div id=\"{{'slot_'+$id+'_6'}}\" class=\"slot last\">\n    <div class=\"num current\"></div>\n    <div class=\"num next\"></div>\n</div>\n\n<div id=\"{{'slot_'+$id+'_7'}}\" class=\"slot last\">\n    <div class=\"num current\"></div>\n    <div class=\"num next\"></div>\n</div>\n\n<script>\n    (function(scope) {\n        let lock = false\n        scope.previous = [-1,-1,-1,-1,-1,-1,-1,-1]\n        scope.drawlist = [true,true,true,true,true,true,true,true]\n        scope.$watch('msg', function(msg) {\n            if (msg) { \n                if(lock){\n                   // console.log(\"locked\")\n                    lock = false\n                    return\n                }  \n               // console.log(msg.payload)\n                lock = true \n\n                let data = msg.payload.toString().split('')\n                while(data.length < 8){\n                    data.unshift(0)\n                }\n\n                data.forEach((d,i) => \n                {\n                    d = parseInt(d)\n                    if(scope.previous[i] == d){\n                        scope.drawlist[i] = false\n                    }\n                    else{\n                        scope.previous[i] = d\n                        scope.drawlist[i] = true\n                    }\n\n                })\n                \n                data.forEach((d,i) => {\n                    if(scope.drawlist[i] == false){\n                        return\n                    }\n                    let current = $(\"#slot_\"+scope.$id+\"_\"+i).find(\".current\")\n                    let next = $(\"#slot_\"+scope.$id+\"_\"+i).find(\".next\")\n                    let old = $(\"#slot_\"+scope.$id+\"_\"+i).find(\".old\")\n\n                    if(next.length == 0 && old.length > 0){\n                        next = old\n                        next.removeClass(\"old\").addClass(\"next\")\n                    }                    \n\n                    next.text(data[i])\n                    current.removeClass(\"current\").addClass(\"old\").on('transitionend webkitTransitionEnd oTransitionEnd', function () {\n                        old = $(\"#slot_\"+scope.$id+\"_\"+i).find(\".old\")\n                        old.removeClass(\"old\").addClass(\"next\")\n                        lock = false\n                    });\n                    next.removeClass(\"next\").addClass(\"current\")\n                })\n            }\n    });\n})(scope);\n</script>","storeOutMessages":true,"fwdInMessages":true,"resendOnRefresh":true,"templateScope":"local","className":"roll-display","x":860,"y":2340,"wires":[[]]},{"id":"513419908d693a02","type":"ui_group","name":"HEADER","tab":"d90e028674af84a9","order":1,"disp":false,"width":"42","collapse":false,"className":""},{"id":"d90e028674af84a9","type":"ui_tab","name":"LIVE","icon":"dashboard","order":1,"disabled":false,"hidden":false}]

Modified to display time.
image

There is too many time formats so I give up immediately to provide any smart solution ...

[{"id":"534bdb8d43678c2a","type":"ui_template","z":"bf0d83d32eec75c2","group":"674712f8d915bcc0","name":"display","order":5,"width":0,"height":0,"format":"<style>\n    .roll-display {\n        display: flex;\n        align-content: center;\n        justify-content: flex-start;\n        flex-direction: row;\n    }\n    .slot {\n        height: 1.6em;\n        width: 1.2em;\n        text-align: center;\n        line-height: 1.6em;\n        border: 4px solid #000000a3;\n        border-radius: 6px;\n        border-top-width: 8px;\n        border-bottom-width: 8px;\n        position: relative;\n        overflow: hidden;\n        background: linear-gradient(0deg, #5a5a5a, #b7b7b7,#5d5d5d);\n    }\n    .num{\n        position:absolute;\n        left: 0;\n        right: 0;\n        user-select:none;\n        background: linear-gradient(0deg, #0000005e, #4c4c4c42, #0000005e);\n    } \n    .current{       \n        top:0em;\n        transition: top 0.25s;\n    }\n    .old{\n        top:1.6em;\n        transition: top 0.25s;\n    }\n    .next{\n        top:-1.6em;\n        transition: none;\n    }\n    .last > .num{\n       \n        background: linear-gradient(0deg, #53535300, #d5d5d52e, #53535300);\n        color: #464646;\n        font-weight: 700;\n        \n    }\n    .gap {\n        position:relative;\n        width: 8px;\n    }\n    .gap:after {\n        content:'•';\n        position:absolute;\n        bottom:0;\n        color:#a4a4a4;\n    }\n    .label{\n        display: flex;\n        flex-direction: column;\n        justify-content: center;\n        padding-right:1em;\n    }\n</style>\n\n\n<div id=\"{{'slot_'+$id+'_0'}}\" class=\"slot\">\n    <div class=\"num current\"></div>\n    <div class=\"num next\"></div>\n</div>\n<div id=\"{{'slot_'+$id+'_1'}}\" class=\"slot\">\n    <div class=\"num current\"></div>\n    <div class=\"num next\"></div>\n</div>\n<div id=\"{{'slot_'+$id+'_2'}}\" class=\"slot\">\n    <div class=\"num current\"></div>\n    <div class=\"num next\"></div>\n</div>\n<div id=\"{{'slot_'+$id+'_3'}}\" class=\"slot\">\n    <div class=\"num current\"></div>\n    <div class=\"num next\"></div>\n</div>\n<div id=\"{{'slot_'+$id+'_4'}}\" class=\"slot\">\n    <div class=\"num current\"></div>\n    <div class=\"num next\"></div>\n</div>\n<div id=\"{{'slot_'+$id+'_5'}}\" class=\"slot\">\n    <div class=\"num current\"></div>\n    <div class=\"num next\"></div>\n</div>\n\n<div id=\"{{'slot_'+$id+'_6'}}\" class=\"slot last\">\n    <div class=\"num current\"></div>\n    <div class=\"num next\"></div>\n</div>\n<div id=\"{{'slot_'+$id+'_7'}}\" class=\"slot last\">\n    <div class=\"num current\"></div>\n    <div class=\"num next\"></div>\n</div>\n\n<script>\n    (function(scope) {\n        let lock = false\n        scope.previous = [-1,-1,-1,-1,-1,-1,-1,-1]\n        scope.drawlist = [true,true,true,true,true,true,true,true]\n        scope.$watch('msg', function(msg) {\n            if (msg) { \n\n                let time = new Date(msg.payload).toTimeString().split(\" \")[0]\n                console.log(time)\n\n                if(lock){\n                   // console.log(\"locked\")\n                    lock = false\n                    return\n                }  \n               // console.log(msg.payload)\n                lock = true \n\n                let data = time.split('')\n                while(data.length < 8){\n                    data.unshift(0)\n                }\n\n                data.forEach((d,i) => \n                {\n                    //d = parseInt(d)\n                    if(scope.previous[i] == d){\n                        scope.drawlist[i] = false\n                    }\n                    else{\n                        scope.previous[i] = d\n                        scope.drawlist[i] = true\n                    }\n\n                })\n                \n                data.forEach((d,i) => {\n                    if(scope.drawlist[i] == false){\n                        return\n                    }\n                    let current = $(\"#slot_\"+scope.$id+\"_\"+i).find(\".current\")\n                    let next = $(\"#slot_\"+scope.$id+\"_\"+i).find(\".next\")\n                    let old = $(\"#slot_\"+scope.$id+\"_\"+i).find(\".old\")\n\n                    if(next.length == 0 && old.length > 0){\n                        next = old\n                        next.removeClass(\"old\").addClass(\"next\")\n                    }                    \n\n                    next.text(data[i])\n                    current.removeClass(\"current\").addClass(\"old\").on('transitionend webkitTransitionEnd oTransitionEnd', function () {\n                        old = $(\"#slot_\"+scope.$id+\"_\"+i).find(\".old\")\n                        old.removeClass(\"old\").addClass(\"next\")\n                        lock = false\n                    });\n                    next.removeClass(\"next\").addClass(\"current\")\n                })\n            }\n    });\n})(scope);\n</script>","storeOutMessages":true,"fwdInMessages":true,"resendOnRefresh":true,"templateScope":"local","className":"roll-display","x":580,"y":740,"wires":[[]]},{"id":"f2fbe600d2ab5417","type":"inject","z":"bf0d83d32eec75c2","name":"","props":[{"p":"payload"},{"p":"topic","vt":"str"}],"repeat":"1","crontab":"","once":false,"onceDelay":0.1,"topic":"","payload":"","payloadType":"date","x":430,"y":740,"wires":[["534bdb8d43678c2a"]]},{"id":"674712f8d915bcc0","type":"ui_group","name":"1. group","tab":"62083694d0eab7ca","order":1,"disp":true,"width":"6","collapse":true,"className":"ordered-1"},{"id":"62083694d0eab7ca","type":"ui_tab","name":"Home","icon":"dashboard","order":1,"disabled":false,"hidden":false}]

Hi,
I enlarged the slot but I can't enlarge the font ...
Can you help me?

0003

I would like to create this ... approximately .....

Modified the time version to have size a bit dynamically changeable

image

[{"id":"bf8580a24000c55c","type":"ui_template","z":"bf0d83d32eec75c2","group":"674712f8d915bcc0","name":"display","order":5,"width":0,"height":0,"format":"<style>\n    .roll-display {\n        --size:4;\n        display: flex;\n        align-content: center;\n        justify-content: flex-start;\n        flex-direction: row;\n    }\n    .slot {\n        height: calc(var(--size) * 1em);\n        width: calc(var(--size) * .8em);\n        text-align: center;\n        line-height: calc(var(--size) * 1em);\n        border: 4px solid #000000a3;\n        border-radius: 6px;\n        border-top-width: 8px;\n        border-bottom-width: 8px;\n        position: relative;\n        overflow: hidden;\n        background: linear-gradient(0deg, #5a5a5a, #b7b7b7,#5d5d5d);\n    }\n    .num{\n        position:absolute;\n        left: 0;\n        right: 0;\n        user-select:none;\n        font-size:calc(var(--size) *.7em);\n        background: linear-gradient(0deg, #0000005e, #4c4c4c42, #0000005e);\n    } \n    .current{       \n        top:0em;\n        transition: top 0.25s;\n    }\n    .old{\n        top:calc(var(--size) * 1em);\n        transition: top 0.25s;\n    }\n    .next{\n        top:calc(var(--size) * -1em);\n        transition: none;\n    }\n    .last > .num{\n       \n        background: linear-gradient(0deg, #53535300, #d5d5d52e, #53535300);\n        color: #464646;\n        font-weight: 700;\n        \n    }\n    .gap {\n        position:relative;\n        width: 8px;\n    }\n    .gap:after {\n        content:'•';\n        position:absolute;\n        bottom:0;\n        color:#a4a4a4;\n    }\n    .label{\n        display: flex;\n        flex-direction: column;\n        justify-content: center;\n        padding-right:1em;\n    }\n</style>\n\n\n<div id=\"{{'slot_'+$id+'_0'}}\" class=\"slot\">\n    <div class=\"num current\"></div>\n    <div class=\"num next\"></div>\n</div>\n<div id=\"{{'slot_'+$id+'_1'}}\" class=\"slot\">\n    <div class=\"num current\"></div>\n    <div class=\"num next\"></div>\n</div>\n<div id=\"{{'slot_'+$id+'_2'}}\" class=\"slot\">\n    <div class=\"num current\"></div>\n    <div class=\"num next\"></div>\n</div>\n<div id=\"{{'slot_'+$id+'_3'}}\" class=\"slot\">\n    <div class=\"num current\"></div>\n    <div class=\"num next\"></div>\n</div>\n<div id=\"{{'slot_'+$id+'_4'}}\" class=\"slot\">\n    <div class=\"num current\"></div>\n    <div class=\"num next\"></div>\n</div>\n<div id=\"{{'slot_'+$id+'_5'}}\" class=\"slot\">\n    <div class=\"num current\"></div>\n    <div class=\"num next\"></div>\n</div>\n\n<div id=\"{{'slot_'+$id+'_6'}}\" class=\"slot last\">\n    <div class=\"num current\"></div>\n    <div class=\"num next\"></div>\n</div>\n<div id=\"{{'slot_'+$id+'_7'}}\" class=\"slot last\">\n    <div class=\"num current\"></div>\n    <div class=\"num next\"></div>\n</div>\n\n<script>\n    (function(scope) {\n        let lock = false\n        scope.previous = [-1,-1,-1,-1,-1,-1,-1,-1]\n        scope.drawlist = [true,true,true,true,true,true,true,true]\n        scope.$watch('msg', function(msg) {\n            if (msg) { \n\n                let time = new Date(msg.payload).toTimeString().split(\" \")[0]\n                console.log(time)\n\n                if(lock){\n                   // console.log(\"locked\")\n                    lock = false\n                    return\n                }  \n               // console.log(msg.payload)\n                lock = true \n\n                let data = time.split('')\n                while(data.length < 8){\n                    data.unshift(0)\n                }\n\n                data.forEach((d,i) => \n                {\n                    //d = parseInt(d)\n                    if(scope.previous[i] == d){\n                        scope.drawlist[i] = false\n                    }\n                    else{\n                        scope.previous[i] = d\n                        scope.drawlist[i] = true\n                    }\n\n                })\n                \n                data.forEach((d,i) => {\n                    if(scope.drawlist[i] == false){\n                        return\n                    }\n                    let current = $(\"#slot_\"+scope.$id+\"_\"+i).find(\".current\")\n                    let next = $(\"#slot_\"+scope.$id+\"_\"+i).find(\".next\")\n                    let old = $(\"#slot_\"+scope.$id+\"_\"+i).find(\".old\")\n\n                    if(next.length == 0 && old.length > 0){\n                        next = old\n                        next.removeClass(\"old\").addClass(\"next\")\n                    }                    \n\n                    next.text(data[i])\n                    current.removeClass(\"current\").addClass(\"old\").on('transitionend webkitTransitionEnd oTransitionEnd', function () {\n                        old = $(\"#slot_\"+scope.$id+\"_\"+i).find(\".old\")\n                        old.removeClass(\"old\").addClass(\"next\")\n                        lock = false\n                    });\n                    next.removeClass(\"next\").addClass(\"current\")\n                })\n            }\n    });\n})(scope);\n</script>","storeOutMessages":true,"fwdInMessages":true,"resendOnRefresh":true,"templateScope":"local","className":"roll-display","x":580,"y":780,"wires":[[]]},{"id":"ee10705e762837ef","type":"inject","z":"bf0d83d32eec75c2","name":"","props":[{"p":"payload"},{"p":"topic","vt":"str"}],"repeat":"1","crontab":"","once":false,"onceDelay":0.1,"topic":"","payload":"","payloadType":"date","x":430,"y":780,"wires":[["bf8580a24000c55c"]]},{"id":"674712f8d915bcc0","type":"ui_group","name":"1. group","tab":"62083694d0eab7ca","order":1,"disp":true,"width":"6","collapse":true,"className":"ordered-1"},{"id":"62083694d0eab7ca","type":"ui_tab","name":"Home","icon":"dashboard","order":1,"disabled":false,"hidden":false}]

Thank you ....

Found a use for it :wink:

image

Thanks !!

Oh no - I now find myself watching the numbers going up in a pretty but worryingly fast rate :rofl:

Did a bit cleanup in overall look and in the code to improve readability in both areas.

image

[{"id":"656888cd7308428e","type":"inject","z":"bf0d83d32eec75c2","name":"","props":[{"p":"payload"},{"p":"topic","vt":"str"}],"repeat":"1","crontab":"","once":false,"onceDelay":0.1,"topic":"","payload":"","payloadType":"date","x":210,"y":820,"wires":[["b7f0df3f43a8dc6e"]]},{"id":"b7f0df3f43a8dc6e","type":"function","z":"bf0d83d32eec75c2","name":"random data","func":"let current = context.get('current') || 1\n\ncurrent += Math.floor(Math.random()*100);\nif(current > 999999){\n    current = 1\n}\n\ncontext.set('current',current)\nmsg.payload = current \nreturn msg;","outputs":1,"noerr":0,"initialize":"","finalize":"","libs":[],"x":370,"y":820,"wires":[["aac264ba0df29e45"]]},{"id":"bf8580a24000c55c","type":"ui_template","z":"bf0d83d32eec75c2","group":"674712f8d915bcc0","name":"display","order":5,"width":0,"height":0,"format":"<div id=\"{{'slot_'+$id+'_0'}}\" class=\"slot\">\n    <div class=\"num current\"></div>\n    <div class=\"num next\"></div>\n</div>\n<div id=\"{{'slot_'+$id+'_1'}}\" class=\"slot\">\n    <div class=\"num current\"></div>\n    <div class=\"num next\"></div>\n</div>\n<div id=\"{{'slot_'+$id+'_2'}}\" class=\"slot\">\n    <div class=\"num current\"></div>\n    <div class=\"num next\"></div>\n</div>\n<div id=\"{{'slot_'+$id+'_3'}}\" class=\"slot\">\n    <div class=\"num current\"></div>\n    <div class=\"num next\"></div>\n</div>\n<div id=\"{{'slot_'+$id+'_4'}}\" class=\"slot\">\n    <div class=\"num current\"></div>\n    <div class=\"num next\"></div>\n</div>\n<div id=\"{{'slot_'+$id+'_5'}}\" class=\"slot\">\n    <div class=\"num current\"></div>\n    <div class=\"num next\"></div>\n</div>\n<div class=\"gap\"></div>\n<div id=\"{{'slot_'+$id+'_6'}}\" class=\"slot last\">\n    <div class=\"num current\"></div>\n    <div class=\"num next\"></div>\n</div>\n<div id=\"{{'slot_'+$id+'_7'}}\" class=\"slot last\">\n    <div class=\"num current\"></div>\n    <div class=\"num next\"></div>\n</div>\n<div class=\"unit\">kWh</div>\n\n<script>\n    (function(scope) {\n        let lock = false\n        let count = 8\n        scope.previous = Array(count).fill(-1);\n        scope.drawlist = Array(count).fill(true);       \n        scope.$watch('msg', function(msg) {\n            if (msg) { \n                if(lock){\n                    lock = false\n                    return\n                }\n                lock = true \n                let data = msg.payload.toString().split('')\n               \n                while(data.length < count){\n                    data.unshift(\"0\")\n                }\n\n                data.forEach((d,i) => \n                {\n                    //d = parseInt(d)\n                    if(scope.previous[i] == d && $(\"#slot_\"+scope.$id+\"_\"+i).find(\".current\").text().length > 0){\n                        scope.drawlist[i] = false\n                    }\n                    else{\n                        scope.previous[i] = d\n                        scope.drawlist[i] = true\n                    }\n\n                })\n                \n                data.forEach((d,i) => {\n                    if(scope.drawlist[i] == false){\n                        return\n                    }\n                    let current = $(\"#slot_\"+scope.$id+\"_\"+i).find(\".current\")\n                    let next = $(\"#slot_\"+scope.$id+\"_\"+i).find(\".next\")\n                    let old = $(\"#slot_\"+scope.$id+\"_\"+i).find(\".old\")\n\n                    if(next.length == 0 && old.length > 0){\n                        next = old\n                        next.removeClass(\"old\").addClass(\"next\")\n                    }                    \n\n                    next.text(data[i])\n                    current.removeClass(\"current\").addClass(\"old\").on('transitionend webkitTransitionEnd oTransitionEnd', function () {\n                        old = $(\"#slot_\"+scope.$id+\"_\"+i).find(\".old\")\n                        old.removeClass(\"old\").addClass(\"next\")\n                        lock = false\n                    });\n                    next.removeClass(\"next\").addClass(\"current\")\n                })\n            }\n    });\n})(scope);\n</script>","storeOutMessages":true,"fwdInMessages":true,"resendOnRefresh":true,"templateScope":"local","className":"roll-display","x":560,"y":840,"wires":[[]]},{"id":"f94b5cb02555e740","type":"ui_template","z":"bf0d83d32eec75c2","group":"674712f8d915bcc0","name":"dixplay css","order":8,"width":0,"height":0,"format":"<style id='roll-display-styles'>\n    .roll-display {\n        --size: 2;\n        --speed: .95;\n        display: flex;\n        align-content: center;\n        justify-content: center;\n        align-items: center;\n        flex-direction: row;\n        overflow: hidden;\n    }\n\n    .roll-display .slot {\n        height: calc(var(--size) * 1em);\n        width: calc(var(--size) * .8em);\n        text-align: center;\n        line-height: calc(var(--size) * 1em);\n        outline: 1px solid #4d4d4d;\n        outline-offset: -3px;\n        border: 3px solid #000000a3;\n        border-radius: 6px;\n        position: relative;\n        overflow: hidden;\n        background: linear-gradient(0deg, #161616, #7e7e7e, #161616);\n    }\n\n    .roll-display .last {\n        background: linear-gradient(0deg, #5a5a5a, #e5e5e5, #5d5d5d);\n    }\n\n    .roll-display .num {\n        position: absolute;\n        left: 0;\n        right: 0;\n        user-select: none;\n        font-size: calc(var(--size) *.7em);\n    }\n\n    .roll-display .last>.num {\n        color: #2f2f2f;\n    }\n\n    .roll-display .num:after {\n        content: \"\";\n        position: absolute;\n        left: -2%;\n        width: 20%;\n        top: 0;\n        height: 100%;\n        background: linear-gradient(to bottom,\n                #00000050,\n                #00000050 50%,\n                transparent 50%,\n                transparent);\n        background-size: 100% 7%;\n    }\n    \n    .roll-display .num:before {\n        content: \"\";\n        position: absolute;\n        right: -2%;\n        width: 20%;\n        top: 0;\n        height: 100%;\n        background: linear-gradient(to bottom,\n                #00000050,\n                #00000050 50%,\n                transparent 50%,\n                transparent);\n        background-size: 100% 7%;\n    }\n\n    .roll-display .last>.num:before{\n        background: linear-gradient(to bottom,\n        #00000030,\n        #00000030 50%,\n        transparent 50%,\n        transparent);\n        background-size: 100% 7%;\n    }\n    \n    .roll-display .last>.num:after{\n        background: linear-gradient(to bottom,\n        #00000030,\n        #00000030 50%,\n        transparent 50%,\n        transparent);\n        background-size: 100% 7%;\n    }\n\n    .roll-display .current {\n        top: 0%;\n        transition: top calc(var(--speed) *1s) ease-in;\n    }\n\n    .roll-display .old {\n        top: 100%;\n        transition: top calc(var(--speed) *1s) ease-in;\n    }\n\n    .roll-display .next {\n        top: -100%;\n        transition: none;\n    }\n\n    .roll-display .gap {\n        position: relative;\n        width: 8px;\n    }\n\n    .roll-display .gap:after {\n        content: '•';\n        position: absolute;\n        text-align: center;\n        inset: 0;\n        color: #b9b9b9;\n    }\n\n    .roll-display .label {\n        display: flex;\n        flex-direction: column;\n        justify-content: center;\n        padding-right: 1em;\n    }\n\n    .roll-display .unit {\n        display: flex;\n        flex-direction: column;\n        justify-content: center;\n        padding-left: 0.5em;\n    }\n</style>","storeOutMessages":true,"fwdInMessages":true,"resendOnRefresh":true,"templateScope":"local","className":"","x":570,"y":880,"wires":[[]]},{"id":"aac264ba0df29e45","type":"ui_template","z":"bf0d83d32eec75c2","group":"674712f8d915bcc0","name":"display last 2 red","order":5,"width":0,"height":0,"format":"<style>\n    .roll-display.red .last>.num {\n        color: #bd1818;\n       /* text-shadow: 0px 0px 1px black;*/\n    }\n</style>\n\n<div id=\"{{'slot_'+$id+'_0'}}\" class=\"slot\">\n    <div class=\"num current\"></div>\n    <div class=\"num next\"></div>\n</div>\n<div id=\"{{'slot_'+$id+'_1'}}\" class=\"slot\">\n    <div class=\"num current\"></div>\n    <div class=\"num next\"></div>\n</div>\n<div id=\"{{'slot_'+$id+'_2'}}\" class=\"slot\">\n    <div class=\"num current\"></div>\n    <div class=\"num next\"></div>\n</div>\n<div id=\"{{'slot_'+$id+'_3'}}\" class=\"slot\">\n    <div class=\"num current\"></div>\n    <div class=\"num next\"></div>\n</div>\n<div id=\"{{'slot_'+$id+'_4'}}\" class=\"slot\">\n    <div class=\"num current\"></div>\n    <div class=\"num next\"></div>\n</div>\n<div id=\"{{'slot_'+$id+'_5'}}\" class=\"slot\">\n    <div class=\"num current\"></div>\n    <div class=\"num next\"></div>\n</div>\n<div class=\"gap\"></div>\n<div id=\"{{'slot_'+$id+'_6'}}\" class=\"slot last\">\n    <div class=\"num current\"></div>\n    <div class=\"num next\"></div>\n</div>\n<div id=\"{{'slot_'+$id+'_7'}}\" class=\"slot last\">\n    <div class=\"num current\"></div>\n    <div class=\"num next\"></div>\n</div>\n<div class=\"unit\">MWh</div>\n\n<script>\n    (function(scope) {\n        let lock = false\n        let count = 8\n        scope.previous = Array(count).fill(-1);\n        scope.drawlist = Array(count).fill(true);       \n        scope.$watch('msg', function(msg) {\n            if (msg) { \n                if(lock){\n                    lock = false\n                    return\n                }\n                lock = true \n                let data = msg.payload.toString().split('')\n               \n                while(data.length < count){\n                    data.unshift(\"0\")\n                }\n\n                data.forEach((d,i) => \n                {                    \n                    if(scope.previous[i] == d && $(\"#slot_\"+scope.$id+\"_\"+i).find(\".current\").text().length > 0){\n                        scope.drawlist[i] = false\n                    }\n                    else{\n                        scope.previous[i] = d\n                        scope.drawlist[i] = true\n                    }\n\n                })\n                \n                data.forEach((d,i) => {\n                    if(scope.drawlist[i] == false){\n                        return\n                    }\n                    let current = $(\"#slot_\"+scope.$id+\"_\"+i).find(\".current\")\n                    let next = $(\"#slot_\"+scope.$id+\"_\"+i).find(\".next\")\n                    let old = $(\"#slot_\"+scope.$id+\"_\"+i).find(\".old\")\n\n                    if(next.length == 0 && old.length > 0){\n                        next = old\n                        next.removeClass(\"old\").addClass(\"next\")\n                    }                    \n\n                    next.text(data[i])\n                    current.removeClass(\"current\").addClass(\"old\").on('transitionend webkitTransitionEnd oTransitionEnd', function () {\n                        old = $(\"#slot_\"+scope.$id+\"_\"+i).find(\".old\")\n                        old.removeClass(\"old\").addClass(\"next\")\n                        lock = false\n                    });\n                    next.removeClass(\"next\").addClass(\"current\")\n                })\n            }\n    });\n})(scope);\n</script>","storeOutMessages":true,"fwdInMessages":true,"resendOnRefresh":true,"templateScope":"local","className":"roll-display red","x":590,"y":800,"wires":[[]]},{"id":"608b4f75f0cdc9b1","type":"function","z":"bf0d83d32eec75c2","name":"random data","func":"let current = context.get('current') || 1\n\ncurrent += Math.floor(Math.random()*50);\nif(current > 999999){\n    current = 1\n}\n\ncontext.set('current',current)\nmsg.payload = current \nreturn msg;","outputs":1,"noerr":0,"initialize":"","finalize":"","libs":[],"x":370,"y":860,"wires":[["bf8580a24000c55c"]]},{"id":"93a93c8c71124851","type":"inject","z":"bf0d83d32eec75c2","name":"","props":[{"p":"payload"},{"p":"topic","vt":"str"}],"repeat":"1.1","crontab":"","once":false,"onceDelay":0.1,"topic":"","payload":"","payloadType":"date","x":210,"y":860,"wires":[["608b4f75f0cdc9b1"]]},{"id":"674712f8d915bcc0","type":"ui_group","name":"1. group","tab":"62083694d0eab7ca","order":1,"disp":true,"width":"6","collapse":true,"className":"ordered-1"},{"id":"62083694d0eab7ca","type":"ui_tab","name":"Home","icon":"dashboard","order":1,"disabled":false,"hidden":false}]

You really should put these in the flows section - they are a great resource.

Easier to find there than searching through old posts.

Is there an easy way to get it to refresh all digits when changing tabs, (without having to refresh the whole page) ?

I am loving it !

How can i make the Unit Display (°C) slightly larger to match the display font ?

time_temp

Not easy but it's done now.

[{"id":"bf8580a24000c55c","type":"ui_template","z":"bf0d83d32eec75c2","group":"674712f8d915bcc0","name":"display","order":5,"width":0,"height":0,"format":"<div id=\"{{'slot_'+$id+'_0'}}\" class=\"slot\" ng-init=\"init()\">\n    <div class=\"num current\"></div>\n    <div class=\"num next\"></div>\n</div>\n<div id=\"{{'slot_'+$id+'_1'}}\" class=\"slot\">\n    <div class=\"num current\"></div>\n    <div class=\"num next\"></div>\n</div>\n<div id=\"{{'slot_'+$id+'_2'}}\" class=\"slot\">\n    <div class=\"num current\"></div>\n    <div class=\"num next\"></div>\n</div>\n<div id=\"{{'slot_'+$id+'_3'}}\" class=\"slot\">\n    <div class=\"num current\"></div>\n    <div class=\"num next\"></div>\n</div>\n<div id=\"{{'slot_'+$id+'_4'}}\" class=\"slot\">\n    <div class=\"num current\"></div>\n    <div class=\"num next\"></div>\n</div>\n<div id=\"{{'slot_'+$id+'_5'}}\" class=\"slot\">\n    <div class=\"num current\"></div>\n    <div class=\"num next\"></div>\n</div>\n<div class=\"gap\"></div>\n<div id=\"{{'slot_'+$id+'_6'}}\" class=\"slot last\">\n    <div class=\"num current\"></div>\n    <div class=\"num next\"></div>\n</div>\n<div id=\"{{'slot_'+$id+'_7'}}\" class=\"slot last\">\n    <div class=\"num current\"></div>\n    <div class=\"num next\"></div>\n</div>\n<div class=\"unit\">kWh</div>\n\n<script>\n    (function(scope) {\n        let lock = 0\n        const count = 8\n        scope.previous = Array(count).fill(-1);\n        scope.drawlist = Array(count).fill(true);\n        scope.inited = false\n        scope.waitingData = null       \n        scope.init = function(){\n            if($(\"#slot_\"+scope.$id+\"_0\".length)){\n                actuallyInit()\n            }\n            else{\n                setTimeout(function(){\n                    actuallyInit()\n                },40)\n            }\n        }\n        function actuallyInit(){\n            console.log('actuallyInit')  \n            lock = 0\n            if(scope.waitingData){\n                console.log('draw from waitingData:',scope.waitingData)\n                setTimeout(function(){\n                    callDraw()\n                },40)\n            }\n            scope.inited = true\n        }\n        scope.$watch('msg', function(msg) {\n            if (msg) { \n                let data = msg.payload.toString().split('')\n                if(!scope.inited){\n                    scope.waitingData = data\n                    return\n                }\n                if(locked()){\n                    scope.waitingData = data\n                    validateLocks()\n                }\n                else{\n                    if(!draw(data)){\n                        scope.waitingData = data\n                        setTimeout(function(){\n                            validateLocks()\n                        },40)\n                    }\n                    \n                }\n            }\n        });\n\n        function locked(){\n            return lock > 0 \n        }\n\n        function pickLock(){\n            if(locked()){\n                lock --;\n            }\n            if(lock < 0){\n                lock = 0;\n                return\n            }\n            if(!locked()){\n                if(scope.waitingData){\n                    setTimeout(function(){\n                        callDraw()\n                    },10)                    \n                }\n            }\n        }\n\n        function validateLocks(){\n            let e = 0\n            for(let i = 0;i<count;++i){\n                e += $(\"#slot_\"+scope.$id+\"_\"+i).find(\".current\").text().length\n            }          \n            if(e == 0){                \n                lock = 0\n                callDraw()\n            }\n        }\n\n        function callDraw(){           \n            if(!scope.waitingData){\n                return\n            }\n            draw(Array.from(scope.waitingData))            \n            scope.waitingData = null;\n        }\n\n        function draw(data){\n            if(locked()){                \n                return\n            }\n            let failures = 0            \n            while(data.length < count){\n                data.unshift(\"0\")\n            }\n            data.forEach((d,i)=>{\n                //d = parseInt(d)\n                if(scope.previous[i] == d && $(\"#slot_\"+scope.$id+\"_\"+i).find(\".current\").text().length > 0){\n                    scope.drawlist[i] = false\n                }\n                else{\n                    scope.previous[i] = d\n                    scope.drawlist[i] = true\n                    lock ++;\n                }            \n            })\n            data.forEach((d,i) => {\n                if(scope.drawlist[i] == false){\n                    return\n                }\n                let current = $(\"#slot_\"+scope.$id+\"_\"+i).find(\".current\")\n                let next = $(\"#slot_\"+scope.$id+\"_\"+i).find(\".next\")\n                let old = $(\"#slot_\"+scope.$id+\"_\"+i).find(\".old\")            \n           \n                if(next.length == 0 && old.length > 0){\n                    old.removeClass(\"old\").addClass(\"next\")\n                    next = $(\"#slot_\"+scope.$id+\"_\"+i).find(\".next\")\n                }\n                \n                next.text(data[i])\n                if(next.length == 0){                   \n                    failures ++\n                }               \n                current.removeClass(\"current\").addClass(\"old\").on('transitionend webkitTransitionEnd oTransitionEnd', function () {\n                    old = $(\"#slot_\"+scope.$id+\"_\"+i).find(\".old\")\n                    old.off('transitionend webkitTransitionEnd oTransitionEnd')\n                    old.removeClass(\"old\").addClass(\"next\")\n                    pickLock()\n                });\n                next.removeClass(\"next\").addClass(\"current\")\n               \n            })\n            return failures == 0\n        }\n})(scope);\n</script>","storeOutMessages":true,"fwdInMessages":true,"resendOnRefresh":true,"templateScope":"local","className":"roll-display","x":540,"y":860,"wires":[[]]},{"id":"f94b5cb02555e740","type":"ui_template","z":"bf0d83d32eec75c2","group":"674712f8d915bcc0","name":"dixplay css","order":8,"width":0,"height":0,"format":"<style id='roll-display-styles'>\n    .roll-display {\n        --size: 2;\n        --speed: .95;\n        display: flex;\n        align-content: center;\n        justify-content: center;\n        align-items: center;\n        flex-direction: row;\n        overflow: hidden;\n    }\n\n    .roll-display .slot {\n        height: calc(var(--size) * 1em);\n        width: calc(var(--size) * .8em);\n        text-align: center;\n        line-height: calc(var(--size) * 1em);\n        outline: 1px solid #4d4d4d;\n        outline-offset: -3px;\n        border: 3px solid #000000a3;\n        border-radius: 6px;\n        position: relative;\n        overflow: hidden;\n        background: linear-gradient(0deg, #161616, #7e7e7e, #161616);\n    }\n\n    .roll-display .last {\n        background: linear-gradient(0deg, #5a5a5a, #e5e5e5, #5d5d5d);\n    }\n\n    .roll-display .num {\n        position: absolute;\n        left: 0;\n        right: 0;\n        user-select: none;\n        font-size: calc(var(--size) *.7em);\n    }\n\n    .roll-display .last>.num {\n        color: #2f2f2f;\n    }\n\n    .roll-display .num:after {\n        content: \"\";\n        position: absolute;\n        left: -2%;\n        width: 20%;\n        top: 0;\n        height: 100%;\n        background: linear-gradient(to bottom,\n                #00000050,\n                #00000050 50%,\n                transparent 50%,\n                transparent);\n        background-size: 100% 7%;\n    }\n    \n    .roll-display .num:before {\n        content: \"\";\n        position: absolute;\n        right: -2%;\n        width: 20%;\n        top: 0;\n        height: 100%;\n        background: linear-gradient(to bottom,\n                #00000050,\n                #00000050 50%,\n                transparent 50%,\n                transparent);\n        background-size: 100% 7%;\n    }\n\n    .roll-display .last>.num:before{\n        background: linear-gradient(to bottom,\n        #00000030,\n        #00000030 50%,\n        transparent 50%,\n        transparent);\n        background-size: 100% 7%;\n    }\n    \n    .roll-display .last>.num:after{\n        background: linear-gradient(to bottom,\n        #00000030,\n        #00000030 50%,\n        transparent 50%,\n        transparent);\n        background-size: 100% 7%;\n    }\n\n    .roll-display .current {\n        top: 0%;\n        transition: top calc(var(--speed) *1s) ease-in;\n    }\n\n    .roll-display .old {\n        top: 100%;\n        transition: top calc(var(--speed) *1s) ease-in;\n    }\n\n    .roll-display .next {\n        top: -100%;\n        transition: none;\n    }\n\n    .roll-display .gap {\n        position: relative;\n        width: 8px;\n    }\n\n    .roll-display .gap:after {\n        content: '•';\n        position: absolute;\n        text-align: center;\n        inset: 0;\n        color: #b9b9b9;\n    }\n\n    .roll-display .label {\n        display: flex;\n        flex-direction: column;\n        justify-content: center;\n        padding-right: 1em;\n    }\n\n    .roll-display .unit {\n        display: flex;\n        flex-direction: column;\n        justify-content: center;\n        padding-left: 0.5em;\n    }\n</style>","storeOutMessages":true,"fwdInMessages":true,"resendOnRefresh":true,"templateScope":"local","className":"","x":550,"y":900,"wires":[[]]},{"id":"608b4f75f0cdc9b1","type":"function","z":"bf0d83d32eec75c2","name":"random data","func":"let current = context.get('current') || 1\n\ncurrent += Math.floor(Math.random()*100);\nif(current > 999999){\n    current = 1\n}\n\ncontext.set('current',current)\nmsg.payload = current \nreturn msg;","outputs":1,"noerr":0,"initialize":"","finalize":"","libs":[],"x":370,"y":860,"wires":[["bf8580a24000c55c"]]},{"id":"93a93c8c71124851","type":"inject","z":"bf0d83d32eec75c2","name":"","props":[{"p":"payload"},{"p":"topic","vt":"str"}],"repeat":"2","crontab":"","once":false,"onceDelay":0.1,"topic":"","payload":"","payloadType":"date","x":210,"y":860,"wires":[["608b4f75f0cdc9b1"]]},{"id":"674712f8d915bcc0","type":"ui_group","name":"1. group","tab":"8482b305c416b850","order":1,"disp":true,"width":"6","collapse":true,"className":"ordered-1"},{"id":"8482b305c416b850","type":"ui_tab","name":"Away","icon":"dashboard","disabled":false,"hidden":false}]

The unit has class
.roll-display .unit {

Add font-size to it

:+1:

image

image

I keep code updated at first post.
Latest fixes also the issue with collapsed group.

You demo works OK, but when I put new version in my flow it only updates once ?

If I leave old and new version then old version still works ( updates all digits after 1st msg)
New one updates with last value sent, but ignores next msgs, unless I switch tabs and go back. But then doesn't update again.
Cannot figure out what the issue is, I just send same msg.payload with a number to both.

Will do some more testing.

Using old and new together has no guarantees what so ever ...