Gauge's for Dashboard 2.0 made with ui_template

Compass

Code is HERE
<template>
    <div class="windrose" v-resize="onResize">
        <svg xmlns="http://www.w3.org/2000/svg" version="1.1" x="0" y="0" width="100%" height="100%" viewBox="0 0 500 500">
            <g>
                <circle cx="250" cy="250" r="205" class="ring" />
                <circle cx="250" cy="250" r="205" class="tick major" pathLength="720"/>
                <circle cx="250" cy="250" r="200" class="tick mid" pathLength="720"/>
                <circle cx="250" cy="250" r="195" class="tick minor" pathLength="720"/>                
            </g>
            <g>
                <text transform="matrix(1 0 0 1 385 268)" class="letters">E</text>
                <text transform="matrix(1 0 0 1 233 420)" class="letters">S</text>
                <text transform="matrix(1 0 0 1 233 112)" class="letters">N</text>
                <text transform="matrix(1 0 0 1 82 268)" class="letters">W</text>
            </g>
        </svg>
        <div class="txt">
            <div>{{formattedDirection}}</div>
            <div class="small">DIRECTION</div>
            <div class="small">SPEED</div>
            <div>{{formattedSpeed}}</div>
        </div>
        <div ref="needle" class="needle" :style="{'rotate': direction +'deg'}"></div>
    </div>
</template>

<script>
    export default {       
        data() {           
            return {              
               direction:0,
               speed:0,
               timeout:null
            }
        },
        watch: {
            msg: function(){           
                if(this.msg?.payload != undefined){
                    if(this.msg.payload.direction != undefined){
                        this.direction = this.shortWayRotation(this.direction, this.msg.payload.direction)
                        if(this.msg.speed == undefined){
                            this.msg.speed = this.speed
                        }                                            
                    }
                    if(this.msg.payload.speed != undefined){
                        this.speed = this.msg.payload.speed 
                        if(this.msg.payload.direction == undefined){
                            this.msg.payload.direction = this.direction;
                        }                                          
                    }
                    this.send({payload:this.msg.payload})
                }
            }
        }
        ,
        computed: {
            formattedSpeed:function(){
                return this.speed + "m/s" 
            },
            formattedDirection:function(){
                let r = (this.direction + 360) % 360;
                if(r<0){
                    r += 360;
                }
                return r + "°"
            }

        },
        methods: {

            onResize(){
                console.log('this',this)
            },
            
            shortWayRotation:function(frm, to){               
                let delta = ((((to - frm) % 360) + 540) % 360) - 180;
                return (frm + delta);
            },
            manageAnimations:function(event){
           
                if(document.hidden){                   
                    if(this.$refs.needle){                        
                        this.$refs.needle.style.transition = "rotate 0s"
                    }
                }
                else{                   
                    if(this.$refs.needle){
                        if(this.timeout){
                            clearTimeout(this.timeout)
                            this.timeout = null
                        }
                        this.timeout = setTimeout(()=>{
                            this.$refs.needle.style.transition = "rotate .5s"
                        },40)

                        
                    } 
                }
            }
            
            
        },        
        mounted() {
            document.addEventListener("visibilitychange", this.manageAnimations);
            window.addEventListener("blur", this.manageAnimations);
            window.addEventListener("focus", this.manageAnimations);      
            
        },
        
        unmounted() {
            if(this.timeout){
                clearTimeout(this.timeout)
                this.timeout = null
            }
            document.removeEventListener("visibilitychange", this.manageAnimations);
            window.removeEventListener("blur", this.manageAnimations);
            window.removeEventListener("focus", this.manageAnimations);
        }
    }
</script>
<style>    
    div:has(>.windrose){
        align-items: center;
    }
    .windrose{
        position:relative;
        width:100%;       
        aspect-ratio: 1;
        container-type: inline-size;
    }
    .tick {
        fill: none;
        stroke: currentColor;       
    }
    .major{
        stroke-dasharray:1 89;
        stroke-dashoffset:0.5;
        stroke-width:40px;
    }
    .mid{
        stroke-dasharray:0 45 1 44 0 45 1 44;
        stroke-dashoffset:0.5;
        stroke-width:30px;
    }
    .minor{
        stroke-dasharray:0 5 1 4 1 4 1 4 1 4 1 4 1 4 1 4 1 4;
        stroke-dashoffset:0.5;
        stroke-width:20px;
    }
    .letters {
        font-size: 48px;
        fill:currentColor;
    }
    .ring{
        fill:none;
        stroke:currentColor;
        stroke-width:40;
        opacity:0.1;
    }
    .needle{
        position: absolute;
        inset: 0;
        left: calc(50% - 1px);
        width: 2px;
        height: 100%;
        transform-origin: center;
        transition: rotate .5s;
    }
    
    .needle:before, .needle:after{
        content: "▼";
        color: red;
        position: absolute;
        top: 1%;
        text-align: center;
        font-size: clamp(0.5rem, 10cqi, 2rem);
        transform: translateX(calc(-50% + 1px));
    }
    .needle:before{
        color:currentColor;
        font-size: calc(clamp(0.5rem, 10cqi, 2rem) + 4px);
    }
    .txt{
        position:absolute;
        inset:0;
        display: grid;
        place-content: center;
        width: 100%;
        text-align: center;        
        font-size: clamp(0.5rem, 12cqi, 3rem);
        font-weight:700;
        line-height:1.2em;
    }
    .txt .small{
        font-size: clamp(0.2rem, 6cqi, 1.5rem);
        line-height: 1em;
        font-weight:500;
    }
</style>

image

The payload for compass must be combined to have speed and direction properties. (previously was topic = "direction") This is changed to have porper wakeup on replayMessage.

12 Likes