# Mechanical counter display

**URL:** <https://discourse.nodered.org/t/mechanical-counter-display/72078>\
**Category:** Dashboard\
**Tags:** node-red-dashboard, ui-widgets\
**Created:** [12 December 2022 13:37 UTC](https://discourse.nodered.org/t/mechanical-counter-display/72078 "2022-12-12T13:37:06Z")\
**Posts on this page:** 20\
**Page:** 1

<div class="post-metadata">

**Author:** ![hotNipi](https://sea2.discourse-cdn.com/flex026/user_avatar/discourse.nodered.org/hotnipi/32/383_2.png) [@hotNipi](https://discourse.nodered.org/u/hotNipi)\
**Post date:** [12 December 2022 13:37 UTC](https://discourse.nodered.org/t/mechanical-counter-display/72078/1 "2022-12-12T13:37:06Z")

</div>

Just for fun.

![image](https://us1.discourse-cdn.com/flex026/uploads/nodered/original/3X/2/a/2a183c2fb82a446f33618d4d1571443da5334bef.png)

```auto
[{"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}]

```

---

<div class="post-metadata">

**Author:** ![Sean-McG](https://sea2.discourse-cdn.com/flex026/user_avatar/discourse.nodered.org/sean-mcg/32/54677_2.png) [@Sean-McG](https://discourse.nodered.org/u/Sean-McG)\
**Post date:** [12 December 2022 13:59 UTC](https://discourse.nodered.org/t/mechanical-counter-display/72078/2 "2022-12-12T13:59:31Z")

</div>

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

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](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 🤔

PS you should post these in the flows section !!

---

<div class="post-metadata">

**Author:** ![hotNipi](https://sea2.discourse-cdn.com/flex026/user_avatar/discourse.nodered.org/hotnipi/32/383_2.png) [@hotNipi](https://discourse.nodered.org/u/hotNipi)\
**Post date:** [12 December 2022 14:27 UTC](https://discourse.nodered.org/t/mechanical-counter-display/72078/3 "2022-12-12T14:27:15Z")

</div>

> [@Sean-McG](#):
>
> 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

---

<div class="post-metadata">

**Author:** ![smanjunath211](https://sea2.discourse-cdn.com/flex026/user_avatar/discourse.nodered.org/smanjunath211/32/95742_2.png) [@smanjunath211](https://discourse.nodered.org/u/smanjunath211)\
**Post date:** [12 December 2022 16:31 UTC](https://discourse.nodered.org/t/mechanical-counter-display/72078/4 "2022-12-12T16:31:13Z")

</div>

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](https://us1.discourse-cdn.com/flex026/uploads/nodered/original/3X/d/3/d3f75c4f68ce9bf80eb576abde5ff47dad1486f7.png)

```auto
[{"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}]

```

---

<div class="post-metadata">

**Author:** ![hotNipi](https://sea2.discourse-cdn.com/flex026/user_avatar/discourse.nodered.org/hotnipi/32/383_2.png) [@hotNipi](https://discourse.nodered.org/u/hotNipi)\
**Post date:** [12 December 2022 17:32 UTC](https://discourse.nodered.org/t/mechanical-counter-display/72078/5 "2022-12-12T17:32:27Z")

</div>

Modified to display time.  
 ![image](https://us1.discourse-cdn.com/flex026/uploads/nodered/original/3X/4/7/4768ad493041696a34ff36350486b62f220ed814.png)

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

```auto
[{"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}]

```

---

<div class="post-metadata">

**Author:** ![Giamma](https://avatars.discourse-cdn.com/v4/letter/g/e47774/32.png) [@Giamma](https://discourse.nodered.org/u/Giamma)\
**Post date:** [12 December 2022 19:00 UTC](https://discourse.nodered.org/t/mechanical-counter-display/72078/6 "2022-12-12T19:00:26Z")

</div>

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

![0003](https://us1.discourse-cdn.com/flex026/uploads/nodered/original/3X/d/f/df27d7fe13bd4ed1e2d2f1ef6537db2c228f73a8.png)

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

 ![0002](https://us1.discourse-cdn.com/flex026/uploads/nodered/original/3X/8/f/8f3f6773204546f3dbe8712846fd6b9e4e42fba7.png)

---

<div class="post-metadata">

**Author:** ![hotNipi](https://sea2.discourse-cdn.com/flex026/user_avatar/discourse.nodered.org/hotnipi/32/383_2.png) [@hotNipi](https://discourse.nodered.org/u/hotNipi)\
**Post date:** [12 December 2022 19:40 UTC](https://discourse.nodered.org/t/mechanical-counter-display/72078/7 "2022-12-12T19:40:02Z")

</div>

Modified the time version to have size a bit dynamically changeable

![image](https://us1.discourse-cdn.com/flex026/uploads/nodered/original/3X/4/e/4ed224055b45c34a11eef6a9339df8e35b783703.png)

```auto
[{"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}]

```

---

<div class="post-metadata">

**Author:** ![Giamma](https://avatars.discourse-cdn.com/v4/letter/g/e47774/32.png) [@Giamma](https://discourse.nodered.org/u/Giamma)\
**Post date:** [12 December 2022 20:03 UTC](https://discourse.nodered.org/t/mechanical-counter-display/72078/8 "2022-12-12T20:03:52Z")

</div>

Thank you ....

---

<div class="post-metadata">

**Author:** ![Sean-McG](https://sea2.discourse-cdn.com/flex026/user_avatar/discourse.nodered.org/sean-mcg/32/54677_2.png) [@Sean-McG](https://discourse.nodered.org/u/Sean-McG)\
**Post date:** [13 December 2022 01:48 UTC](https://discourse.nodered.org/t/mechanical-counter-display/72078/9 "2022-12-13T01:48:16Z")

</div>

Found a use for it 😉

![image](https://us1.discourse-cdn.com/flex026/uploads/nodered/original/3X/c/9/c9f5b3acd4074e9adc6c9c1ea319f9bb38784ad4.png)

Thanks !!

---

<div class="post-metadata">

**Author:** ![Sean-McG](https://sea2.discourse-cdn.com/flex026/user_avatar/discourse.nodered.org/sean-mcg/32/54677_2.png) [@Sean-McG](https://discourse.nodered.org/u/Sean-McG)\
**Post date:** [13 December 2022 18:46 UTC](https://discourse.nodered.org/t/mechanical-counter-display/72078/10 "2022-12-13T18:46:53Z")

</div>

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

---

<div class="post-metadata">

**Author:** ![hotNipi](https://sea2.discourse-cdn.com/flex026/user_avatar/discourse.nodered.org/hotnipi/32/383_2.png) [@hotNipi](https://discourse.nodered.org/u/hotNipi)\
**Post date:** [14 December 2022 10:36 UTC](https://discourse.nodered.org/t/mechanical-counter-display/72078/11 "2022-12-14T10:36:22Z")

</div>

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

![image](https://us1.discourse-cdn.com/flex026/uploads/nodered/original/3X/2/a/2a183c2fb82a446f33618d4d1571443da5334bef.png)

```auto
[{"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}]

```

---

<div class="post-metadata">

**Author:** ![Sean-McG](https://sea2.discourse-cdn.com/flex026/user_avatar/discourse.nodered.org/sean-mcg/32/54677_2.png) [@Sean-McG](https://discourse.nodered.org/u/Sean-McG)\
**Post date:** [15 December 2022 00:36 UTC](https://discourse.nodered.org/t/mechanical-counter-display/72078/12 "2022-12-15T00:36:25Z")

</div>

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

Easier to find there than searching through old posts.

---

<div class="post-metadata">

**Author:** ![Sean-McG](https://sea2.discourse-cdn.com/flex026/user_avatar/discourse.nodered.org/sean-mcg/32/54677_2.png) [@Sean-McG](https://discourse.nodered.org/u/Sean-McG)\
**Post date:** [15 December 2022 00:42 UTC](https://discourse.nodered.org/t/mechanical-counter-display/72078/13 "2022-12-15T00:42:22Z")

</div>

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

---

<div class="post-metadata">

**Author:** ![smanjunath211](https://sea2.discourse-cdn.com/flex026/user_avatar/discourse.nodered.org/smanjunath211/32/95742_2.png) [@smanjunath211](https://discourse.nodered.org/u/smanjunath211)\
**Post date:** [15 December 2022 06:46 UTC](https://discourse.nodered.org/t/mechanical-counter-display/72078/14 "2022-12-15T06:46:51Z")

</div>

I am loving it !

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

![time_temp](https://us1.discourse-cdn.com/flex026/uploads/nodered/original/3X/2/2/2241e681bd1bae4501fc46dca2c1d3fdf758f6b5.gif)

---

<div class="post-metadata">

**Author:** ![hotNipi](https://sea2.discourse-cdn.com/flex026/user_avatar/discourse.nodered.org/hotnipi/32/383_2.png) [@hotNipi](https://discourse.nodered.org/u/hotNipi)\
**Post date:** [15 December 2022 09:16 UTC](https://discourse.nodered.org/t/mechanical-counter-display/72078/15 "2022-12-15T09:16:21Z")

</div>

> [@Sean-McG](#):
>
> Is there an easy way to get it to refresh all digits when changing tabs, (without having to refresh the whole page) ?

Not easy but it's done now.

```auto
[{"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}]

```

---

<div class="post-metadata">

**Author:** ![hotNipi](https://sea2.discourse-cdn.com/flex026/user_avatar/discourse.nodered.org/hotnipi/32/383_2.png) [@hotNipi](https://discourse.nodered.org/u/hotNipi)\
**Post date:** [15 December 2022 09:18 UTC](https://discourse.nodered.org/t/mechanical-counter-display/72078/16 "2022-12-15T09:18:41Z")

</div>

> [@smanjunath211](#):
>
> How can i make the Unit Display (°C) slightly larger

The unit has class  
`.roll-display .unit {`

Add `font-size` to it

---

<div class="post-metadata">

**Author:** ![smanjunath211](https://sea2.discourse-cdn.com/flex026/user_avatar/discourse.nodered.org/smanjunath211/32/95742_2.png) [@smanjunath211](https://discourse.nodered.org/u/smanjunath211)\
**Post date:** [15 December 2022 09:37 UTC](https://discourse.nodered.org/t/mechanical-counter-display/72078/17 "2022-12-15T09:37:42Z")

</div>

👍

![image](https://us1.discourse-cdn.com/flex026/uploads/nodered/original/3X/2/0/208422a5031f7ffac0e27a249913f79fb8efb82b.png)

![image](https://us1.discourse-cdn.com/flex026/uploads/nodered/original/3X/7/d/7d4cffca8302427c3a29781843ba1affffcf17f0.png)

---

<div class="post-metadata">

**Author:** ![hotNipi](https://sea2.discourse-cdn.com/flex026/user_avatar/discourse.nodered.org/hotnipi/32/383_2.png) [@hotNipi](https://discourse.nodered.org/u/hotNipi)\
**Post date:** [15 December 2022 13:58 UTC](https://discourse.nodered.org/t/mechanical-counter-display/72078/18 "2022-12-15T13:58:45Z")

</div>

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

---

<div class="post-metadata">

**Author:** ![Sean-McG](https://sea2.discourse-cdn.com/flex026/user_avatar/discourse.nodered.org/sean-mcg/32/54677_2.png) [@Sean-McG](https://discourse.nodered.org/u/Sean-McG)\
**Post date:** [15 December 2022 14:25 UTC](https://discourse.nodered.org/t/mechanical-counter-display/72078/19 "2022-12-15T14:25:56Z")

</div>

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.

---

<div class="post-metadata">

**Author:** ![hotNipi](https://sea2.discourse-cdn.com/flex026/user_avatar/discourse.nodered.org/hotnipi/32/383_2.png) [@hotNipi](https://discourse.nodered.org/u/hotNipi)\
**Post date:** [15 December 2022 14:29 UTC](https://discourse.nodered.org/t/mechanical-counter-display/72078/20 "2022-12-15T14:29:56Z")

</div>

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

[Next page](https://discourse.nodered.org/t/mechanical-counter-display/72078.md?page=2)
