Gauge's for Dashboard 2.0 made with ui_template

Tomorrow can take a look.

Thanks Steve, that makes sense, but having crashed node-RED a further 3 times I'm not having much success :face_with_raised_eyebrow:
A further step would be also needed to ensure that the gauge line displays correctly like in my images above because the range is set 0 - 3000 (negative values would need to be multiplied by -1). But... the ag-value should of course always display the correct value.

Without these changes, I would need to set the range to -3000W to +3000W, which then spans 6000W, to accommodate both positive & negative values, which would not be easy to visualize on a phone screen.

So it is intentional that negative value still shows the bar. Cos naturally it shouldn't.

Correct, I would be aware if it was a negative or positive value because of it's colour, and also because the value would be preceded by a -

Interesting and valuable usage. Let's call it somehow. ZeroCrossing

1 Like

Collecting more info. The dead zero is in those conditions positive or negative?

If you mean to use it with dashboard 1 then yes, it is possible. It takes to adjust code of course. Do you expect me to do so or you will try first and if you struggle then asking sharply pointed questions to get things going and finally achieve the goal that way?

1 Like

I suppose zero should be green (negative), because it means I'm not using any power.

Yes, I mean to use it with dashboard 1.....
I will try first, thank you ....

Changed (simplified/optimized) code for compass. Take a new copy from original post...

ZeroCross done.

It doesn't currently change colour when the values are =<0, is that something I need to add myself, something like @Steve-Mcl's class example above.

It should work out of box.
All you need is to turn zeroCross (boolean) to true, define 2 colors and min should be 0

And I'd quess you'll need to change the code for all instances cos using old and new together may not work properly.

Ah OK, now I have defined just 2 colours it works great!

test

Thank you :smiley:

EDIT it looks much better when it's not as wide (8x1) as the screenshot, 4x1 on a phone looks great.

1 Like

Maybe the better solution would be that it takes colors from beginning and from end of colors array so you can have still long list of colors defined which is mostly same for other gauges and you don't need to change that list just for zeroCross. But that's only if that IF is really the case so..

And I'm thinking - the user who likes artless most probably don't use others thus it is maybe reasonable to separate that out from this bundle.

The layout falls apart (not completely but ..) in case of the label text is long. So you know...

Yes, good idea

I'm only using artless, but no strong opinions either way.

Here's the artless only. Just as to not pollute the dashboard with code you don't actually use.

Includes :

TEMPLATE
<template>
    <div ref="hng" :class="icon ? 'ag-wrapper-2' : 'ag-wrapper-1'" :style="`--line-color:${colors[0]};`">
        <div v-if="icon" class="ag-icon">
            <v-icon aria-hidden="false">{{icon}}</v-icon>
        </div>
        <div class="ag-content">
            <div class="ag-text">
                <span class="ag-label">{{label}}</span>
                <span class="ag-value">{{formattedValue}}<span class="ag-unit">{{unit}}</span></span>
            </div>
            <div class="ag-track" ref="agLine">
                <div class="ag-track-background"></div>
                <div class="ag-track-foreground" :style="{'width': linesize +'%'}"></div>
            </div>
            <div class="ag-limits">
                <span class="ag-min">{{min}}</span>
                <span class="ag-max">{{max}}</span>
            </div>
        </div>
    </div>
</template>

<script>
    export default {
    data(){
        return {
            //Define me here
                                             
            label:"Artless single", // The label
            icon:"mdi-account", // (type: artless) (optional) the icon
            zeroCross:false,// (type: artless) line changes color depending on value being positive or negative (at least 2 colors must be defined)
            min:0, // Smallest expected value
            max:100, // Highest expected value
            unit:"cmĀ³",// The unit of the measurement           
            animate:true, // Animating led's is not most performant thing in the world.                          
            
            // Define colors           
            colors:[
                    "#0fb60f",
                    "#0fb60f",
                    "#0fb60f",
                    "#0fb60f",
                    "#0fb60f",
                    "orange",
                    "orange",                    
                    "red"
                   ],            
            
            //no need to change those
            value:0,          
            inited:false
        }
    },


   
    methods: {        
        getElement: function(name,base){        
            if(base){
                return this.$refs[name]
            }
            return this.$refs[name][0]
        },
        validate(data){
            let ret
            if(typeof data !== "number"){
                ret = parseFloat(data)
                if(isNaN(ret)){
                    console.log("BAD DATA! gauge type:",this.type, "id:",this.id,"data:",data)
                    return null
                }   
            }
            else{
                ret = data
            }            
            return ret
        },
        changeLine:function(){
            const line = this.getElement("agLine",true);
            if(!line){
                console.log("no line found")
                return            
            }
           
            let c = Math.floor(this.colors.length * this.percentage / 100)
            if(c >= this.colors.length){
                c = this.colors.length - 1
            }
            if(c < 0){
                c = 0
            }
            if(this.zeroCross){
                c = this.value > 0 ? (this.colors.length - 1) : 0
            }
            line.style.setProperty('--line-color',this.colors[c])

        }
    },
       
    watch: {
        msg: function(){    
            if(this.msg.payload !== undefined){  
                const v = this.validate(this.msg.payload)                
                if(v === null){
                    return
                }         
                this.value = v
                this.changeLine()              
            }
        }
    },
    computed: {
        formattedValue: function () {
            return this.value.toFixed(2)
        },
        percentage: function(){
            return Math.floor(((this.value - this.min) / (this.max - this.min)) * 100);
        },
        linesize:function(){
            if(this.zeroCross){
                return Math.floor(((Math.abs(this.value) - this.min) / (this.max - this.min)) * 100);           
            }
            else{
                return Math.max(0,this.percentage)
            }
        }
    },
    mounted(){
        const line = this.getElement("agLine",true);
        line.style.setProperty('--line-color',this.colors[0])
        if(this.animate == true){
            if(!line){
                console.log("artless init() no line found")
                return
            }
            line.style.transition = "width 0.5s";
        }
       
        this.inited = true;
    }
}
</script>
CSS
.ag-wrapper-2 {
    display: grid;
    grid-template-columns: 3em 1fr;
    gap:1em;
}
.ag-wrapper-1 {
    display: grid;
    grid-template-columns: 1fr;   
}
.ag-icon{
    font-size: 2em;
    display: flex;
    flex-direction: column;
    justify-content: center;        
}
.ag-content{
    display: grid;
    grid-template-rows: 1fr 7px 0.75em;
    gap: 2px;
}
.ag-text{
    font-size: 1.25em;
    line-height: 1em;
    align-self: end;
    display: flex;
    flex-wrap: wrap;
    justify-content: space-between;
    user-select: none;
}
.ag-value{       
    font-weight:bold;
}
.ag-unit{
    font-size:.75em;
    font-weight:normal;
    padding-inline-start: 0.15em;
}
.ag-limits{
    display: flex;
    justify-content: space-between;
    font-size: .75em;
    line-height: .75em;
    align-content: center;
    flex-wrap: wrap;
    user-select: none;
}

.ag-track{
    position:relative;
    display:flex;
    align-items: center;
    width: 100%;
    border-radius: 6px;
}

.ag-track-background{
    position:absolute;
    background: var(--line-color,rgb(var(--v-theme-primary)));
    opacity: 0.45;
    width: 100%;
    height: 50%;
    border-radius:inherit;
}
.ag-track-foreground{
    position:absolute;
    background-color: var(--line-color,rgb(var(--v-theme-primary)));
    width: 50%;
    height: 100%;
    max-width: 100%;
    border-radius:inherit;
    transition:inherit;
}
2 Likes

Awesome work. I don't have much knowledge about HTML/CSS. How would I dynamically change the icon and its colour within a Node-RED flow?