Gauge's for Dashboard 2.0 made with ui_template

No. Unexpected Token.

In fact, in retrospect, I would rather turn the logic round and code that section as

                    const v = this.validate(this.msg.payload)                   
                    if(v !== null){
                        this.value = v
                        this.getElement('o-needle',true).style.rotate = this.rotation(this.value)    
                    }
1 Like

Nice to have companions with interest to dig in deep. :smiley:
Who the hell in the world even tries to familiarize himself about the stroke-dasharray madness :stuck_out_tongue: ..

There are some things to work on yet - "magic numbers" like const arcLength = 203.356 or const maxAngle = 122.64 * 1.2 will bite hard if you'll need to change the ark shape even a bit. Not that I didn't use them. I did and mostly it is a bit of laziness and bit of ambition to showup no matter that the thing is not perfect.
But overall "magic numbers" should be avoided as much as possible.

No matter, I like it. I like it a lot.

1 Like

You are quite right about the hard coded numbers. I wanted to get it going first. I do plan to put some more maths in to calculate those too. Perhaps making the basic layout configurable too, rather than hard coding it.

2 Likes

One thing i added to these gauges (and also to the artless gauges) was to add a property to define how many decimal places the values should have when shown. This variable is then passed to ".toFixed(this.valueDecimalPlaces)" to format the value shown.

The dashboard I am attempting to make, the people using it require to see more "decimal places" for some values (no specific reason, just because yes... :upside_down_face:).

In the version posted by colin, also added a "majorDecimalPlaces" for situations where the full range is small, in my case for example something between 0 and 2Bar.

Thanks, and nice work.

Not that it doesn't make sense to have things easy to configure, just the default should follow good practices.
Just mentioning couple in that sense..
When designing a gauge (value reading area of the measuring device), the top of design requirements contains readability. The top list of "readability killers" contains overcroudness.

2 vs 2.0 makes quite of difference.

I agree the default should follow good practices.

Fortunately, in my case, the dashboard i made using Node-Red are only for "internal" consumption and not for "final/outside client" use, and since my main area of focus is embedded device programming (mainly C) and hardware design, have some trouble thinking in good GUI paradigm and specially working with html and css.

These dashboards are for the customer support people have access to an "advanced mode" when checking equipment status since the current software "cannot" have that mode and only show basic information.

Regarding the Gauge, one of the ones with "decimal places" look like this:

image

What happened with the last tick value?
image

Not sure.

Trying to check that.

The maximum should be 1.4, and it is not showing, i think is something related to "precision of floats / comparisons between floats" in the function "generateNumbers", at least in "page inspect" there is no label in SVG for that position.

Trying to find how i can make debug statements to check what is being calculated.

Show the code where you use the "majorDecimalPlaces" to format

Ok, found the issue...

The code looks like this (is not pretty, but it works for now)

generateNumbers:function(min,max,majorDivision){               
        const minDegrees = 237.36
        const maxDegrees = 482.64
        const degRange = maxDegrees-minDegrees
        const degPerDiv = degRange * majorDivision/(max-min)
        console.log(`degRange: ${degRange}`);
        console.log(`degPerDiv: ${degPerDiv}`);
        let nums = []
        for (let degrees=minDegrees; degrees<=maxDegrees; degrees+=degPerDiv) {
            const n = ((degrees-minDegrees)/degRange * (max-min) + min).toFixed(this.majorDecimalPlaces);
            nums.push({r: degrees, n: n});
            console.log(`n: ${n}, Degrees: ${degrees}`);
            degrees = Math.round(degrees);
        }
        return nums 
    },

The issue is the comparasion in the for "loop" regarding how floats number work.

Not pretty, probably going to scale by 100 the values to use only "int" values, and then re-scale before passing to the "nums" array.

Before adding the "Math.round" the console output was:

degRange: 245.27999999999997
VM6221:7 degPerDiv: 35.04
VM6221:15 n: 0.0, Degrees: 237.36
VM6221:15 n: 0.2, Degrees: 272.40000000000003
VM6221:15 n: 0.4, Degrees: 307.44000000000005
VM6221:15 n: 0.6, Degrees: 342.4800000000001
VM6221:15 n: 0.8, Degrees: 377.5200000000001
VM6221:15 n: 1.0, Degrees: 412.5600000000001
VM6221:15 n: 1.2, Degrees: 447.60000000000014

And "447.60000000000014 + 35.04" is greater than "482.64" and as such the last point could not appear.

As I haven't tested this approach of generating numbers I cant tell how bulletproof it can be made. Current version is a bit weak .

As it's not my idea, I cant see or think behind the design target fully. Having less ticks is only the outcome. (Having more is possible but not reasonable cos they most probably don't fit)

So if to go with this kind of approach, it takes to improve the math behind it.

I have changed the function, it looks better, at least for my use case is working

            generateNumbers:function(min,max,majorDivision){               
                const minDegrees = Math.floor(237.36 * 100);    //Scale to try and only using 'int' numbers...
                const maxDegrees = Math.floor(482.64 * 100);    //Scale to try and only using 'int' numbers...
                const degRange = maxDegrees-minDegrees
                const degPerDiv = Math.floor(degRange * majorDivision/(max-min));
                let nums = []
                for (let degrees=minDegrees; degrees<=maxDegrees; degrees+=degPerDiv) {
                    const n = ((degrees-minDegrees)/degRange * (max-min) + min).toFixed(this.majorDecimalPlaces);
                    nums.push({r: (degrees / 100), n: n});  //Re-scale to have value in correct format
                }
                return nums 
            },

I know that in javascript the 'int' type, does not really exist, internally is a floating-point value, but we can use some tricks to go around...

As long it is for numbers (tick labels) only, the rounding produces slight misalignment, which I don't think will be noticeable.
Still, for common usage - it doesn't contain any validation that max value is included.

I haven't had a chance to test it, but I think replacing that with

const topLimit = maxDegrees + degPerDiv/100
for (let degrees=minDegrees; degrees<=topLimit; degrees+=degPerDiv) {

would do the job.

Is possible convert this compass for dashboard?

Which compass?

I mean this ....

compass

It is already for the dashboard.

@hotNipi I'm using your artless gauge to display inflow/outflow of power on a phone, and wanted to dynamically change the colour of the gauge depending upon this.value.
So if the value is >0 the gauge should be red (signifying that I'm consuming power), else the gauge should be #0fb60f (green, signifying that solar energy is exceeding consumption).

1
2

I've tried modifying your code several times today (and several times crashed node-RED!!), do you have any suggestions please?
I don't need any other colours, just red if >0 or else green.
Note that the gauge range is set at 0 - 3000, so both 1000 & -1000 would extend to the same point on the axis, but differentiated due to both the colour and it's value being different.

classes, like any other property can be dynamically bound.

e.g.

<div :class="[{ red: (value > 0 ) },  'ag-track-foreground']">

What this does is apply class .red conditionally (e.g. value > 0) and unconditionally adds class ag-track-foreground