Tank level indication inside of ui-template(v2)

I need to put a tank level indication or ui-gauge inside of a ui-template. Does anyone have a idea on how to achieve that?

Or a bit more "tank like" level widget

image

Code is HERE
<script>
    export default{
        data(){
            return {
                min:0,
                max:6.5,
                label:"Second Tank",
                unit:"mÂł",
                showMax:true,
                maxLabel:"Max",
                value:0
            }
        }
    }
</script>
    
<template>
    <div class="wrapper">
        <div class="tank">
            <div class="fluid" :style="{'height':percentage}"></div>
            <div class="frame"></div>
            <p class="txt">{{formattedValue}}<span>{{unit}}</span></p>
            <p class="label">{{label}}</p>
            <p v-if="showMax" class="limit"><span>{{maxLabel}}</span>{{max}}{{unit}}</p>
        </div>
        <div>
</template>

<script>
    export default{        
        methods:{
            getElement: function(name,base){
                if(base){
                    return this.$refs[name]
                }
                return this.$refs[name][0]
            },
            validate: function(data){
                let ret
                if(typeof data !== "number"){
                    ret = parseFloat(data)
                    if(isNaN(ret)){
                        console.log("BAD DATA! gauge id:",this.id,"data:",data)
                        ret = null
                    }
                }
                else{
                    ret = data
                }
                return ret
            }
        },
        computed: {
            formattedValue: function () {
                return this.value.toFixed(2)
            },
            percentage: function(){
                return Math.floor(((this.value - this.min) / (this.max - this.min)) * 100)+"%";
            }
        },
        watch: {
            msg: function(){            
                const v = this.validate(this.msg.payload)           
                this.value = v                         
            }
        }    
    }    
</script>
<style>
    .wrapper{
        position:relative;
        --border:3px;
        --corner:30px;
        --fluidColor:#00a8ff;
    }
    .tank {
        position: absolute;
        width: 100%;
        height: 100%;
        margin: auto;
        inset: 0;
        overflow: hidden;
        border-bottom-left-radius: var(--corner);
        border-bottom-right-radius: var(--corner);
    }
    .tank .txt {
        position: relative;
        width: 100%;
        top: 55%;
        text-align: center;
        font-size: x-large;
        font-weight: 700;
        user-select: none;
    }
    .tank .txt span {
        font-size: small;
        display: contents;
    }
    .tank .label {
        position: absolute;
        width: 100%;
        top: 20%;
        text-align: center;
        font-size: 1rem;        
        user-select: none;
    }
    .tank .limit {
        position: absolute;
        top: 1ch;
        right: 1ch;
        text-align: end;
        font-size: smaller;
        opacity:.7;
        user-select: none;
    }
    .tank .limit span {
        padding-right:0.5ch;
    }
    .tank .frame {
        position: absolute;
        width: calc(100% - var(--border));
        height:calc(100% - var(--border));
        margin: auto;
        inset: 0;
        outline: var(--border) solid;     
        border-bottom-left-radius: var(--corner);
        border-bottom-right-radius: var(--corner);
    }

    .tank .fluid {
        position: absolute;
        width: 100%;
        height:100%;
        bottom: 0;
        background: var(--fluidColor);
        border-bottom-left-radius: var(--corner);
        border-bottom-right-radius: var(--corner);
    }
</style>
3 Likes

Thank you @hotNipi, this is exactly what I wan't.

But, what is I need multiple tanks?

Kind regards

O

Multiple in one widget?

In the same widget.

Btw the number is 10 tanks....

O

Multitank

Code
<script>
    export default{
        data(){
            return {
                config:[
                    {
                        label:"First Tank",
                        topic:"first",
                        min:0,
                        max:20                                        
                    },
                    {
                        label:"Second Tank",
                        topic:"second",
                        min:0,
                        max:6.5                       
                    }
                ],
                unit:"mÂł",
                showMax:true,
                maxLabel:"Max",
                values:[]
            }
        }
    }
</script>
    
<template>
    <div class="multitank-wrapper">
        <div v-for="tank in config" class="multitank">
            <div class="fluid" :style="{'height':percentage(tank.topic)}"></div>
            <div class="frame"></div>
            <p class="txt">{{formattedValue(tank.topic)}}<span>{{unit}}</span></p>
            <p class="label">{{tank.label}}</p>
            <p v-if="showMax" class="limit"><span>{{maxLabel}}</span>{{tank.max}}{{unit}}</p>
        </div>
    </div>
</template>

<script>
    export default{        
        methods:{           
            validate: function(data){
                let ret
                if(typeof data !== "number"){
                    ret = parseFloat(data)
                    if(isNaN(ret)){
                        console.log("BAD DATA! gauge id:",this.id,"data:",data)
                        ret = null
                    }
                }
                else{
                    ret = data
                }
                return ret
            },
            formattedValue: function (t) {
                if(!this.values[t]){
                    return ""
                }
                return this.values[t].toFixed(2)
            },
            getLimit(t,max){
                const c = this.config.find(e => e.topic == t)
                if(max){
                    return c.max
                }
                else{
                    return c.min
                }
            },
            percentage: function(t){
                if(!this.values[t]){
                    return "0%"
                }
                return Math.floor(((this.values[t] - this.getLimit(t)) / (this.getLimit(t,true) - this.getLimit(t))) * 100)+"%";
            }
        },        
        watch: {
            msg: function(){                     
                const v = this.validate(this.msg.payload)
                const t = this.msg.topic
                if(v == null || t == undefined || t == ""){
                    return
                }                           
                this.values[t] = v          
            }
        }
    }    
</script>
<style>
    .multitank-wrapper{
        position:relative;
        --border:3px;
        --corner:30px;
        --fluidColor:#00a8ff;
        display:grid;
        grid-template-columns: repeat(5, minmax(12ch, auto));
        gap:1rem;
    }
    .multitank {
        position: relative;
        width: 100%;
        height: 100%;
        margin: auto;
        inset: 0;
        overflow: hidden;
        border-bottom-left-radius: var(--corner);
        border-bottom-right-radius: var(--corner);
    }
    .multitank .txt {
        position: relative;
        width: 100%;
        top: 55%;
        text-align: center;
        font-size: x-large;
        font-weight: 700;
        user-select: none;
    }
    .multitank .txt span {
        font-size: small;
        display: contents;
    }
    .multitank .label {
        position: absolute;
        width: 100%;
        top: 20%;
        text-align: center;
        font-size: 1rem;        
        user-select: none;
    }
    .multitank .limit {
        position: absolute;
        top: 1ch;
        right: 1ch;
        text-align: end;
        font-size: smaller;
        opacity:.7;
        user-select: none;
    }
    .multitank .limit span {
        padding-right:0.5ch;
    }
    .multitank .frame {
        position: absolute;
        width: calc(100% - var(--border));
        height:calc(100% - var(--border));
        margin: auto;
        inset: 0;
        outline: var(--border) solid;     
        border-bottom-left-radius: var(--corner);
        border-bottom-right-radius: var(--corner);
    }

    .multitank .fluid {
        position: absolute;
        width: 100%;
        height:100%;
        bottom: 0;
        background: var(--fluidColor);
        border-bottom-left-radius: var(--corner);
        border-bottom-right-radius: var(--corner);
    }
</style>

Why not put multiple (single) tank widgets in one group

1 Like

Same as we don't expect the bar chart to be widget per bar.

No one expected the Inquisition.

1 Like

Not too often, but still, from time to time, there are flashes of thoughts with deep meaning that my gray brain cells cannot reach.

Totally there are 7 pages with 10 tanks in each. Totally 70 instances of an tank. I wan't to make the code reuseable and thats the reason I don't want to use multiple widget in one group.

If it was possible to put 7 instances into a group and then use this group as a complete object it would have worked. So far I haven't found a way to do so....

O

If you are happy living on the bleeding edge, node-red v4 beta and latest dashboard 2.0 have early support for UI nodes in subflows.

Well the multitank code I have shared has no limits, You can put all in one, just you have to configure topic and label + min/max per item and manage how they arrange in rows / columns.

1 Like

Happy Birthday @Steve-Mcl .

the widget array feature in FlexDash by @tve was a good one. Is it similar ?

Thank you!
I also need to include some more info like product, filling-source and pressure. I'll try to investigate your code and see if I can do it myselve. :slight_smile:

O

Thank you kind sir

No, this is more like packing 1 or more functional parts (flows) into a single reusable node for easy re-use. You can now select a config (e.g. the ui-group) as a property and allow it to be selected to set where your UI elements will be displayed. Unfortunately, it's quite difficult to explain in words and the benefits are not immediately recognisable. But when you realise you need this, you will realise it potential.

This topic was automatically closed 14 days after the last reply. New replies are no longer allowed.