Gauge node in compass mode - different values for pointer and displayed digits

I am using a Gauge node in Compass mode to display the output of a compass in integers ranging from 0-359.

Whilst I wish to show the incoming heading numerically, I would like to set the pointer to reflect ‘North’.
An example would be, say when heading due East, the numerical display would read 90°, yet the pointer would point to the left [270°], indicating where North is. This would effectively be a very simple equivalent of a compass card.

Is there a method the address the pointer and numerical display separately or is that beyond the scope of the Gauge node?

Any pointers will be very welcome.

This example may help

[{"id":"39166a0f54cb6880","type":"inject","z":"d1395164b4eec73e","name":"","props":[{"p":"payload"},{"p":"ui_control","v":"{\"options\":{\"donutStartAngle\":270}}","vt":"json"}],"repeat":"","crontab":"","once":false,"onceDelay":0.1,"topic":"","payload":"90","payloadType":"num","x":150,"y":4720,"wires":[["726bdfba8abfc844"]]},{"id":"726bdfba8abfc844","type":"ui_gauge","z":"d1395164b4eec73e","name":"","group":"8b5cde76.edd58","order":9,"width":0,"height":0,"gtype":"compass","title":"gauge","label":"units","format":"{{value}}","min":0,"max":"359","colors":["#00b500","#e6e600","#ca3838"],"seg1":"","seg2":"","diff":false,"className":"","x":290,"y":4760,"wires":[]},{"id":"8b5cde76.edd58","type":"ui_group","name":"default","tab":"8f03e639.85956","order":1,"disp":false,"width":"12","collapse":false},{"id":"8f03e639.85956","type":"ui_tab","name":"Home","icon":"dashboard","order":3,"disabled":false,"hidden":false}]

Check out note3 node-red-dashboard/config-fields.md at master · node-red/node-red-dashboard · GitHub

More options here D3 Liquid Fill Gauge · GitHub
most work but not all.

I am presuming you mean node-red-dashboard

I did show you this before but it looks like you never bothered to read it or check other options Gauge Node - hiding min & max value display - #2 by E1cid

Thanks for that.

"I did show you this before but it looks like you never bothered to read it or check other options" I did see your previous reply and did respond, for it was most helpful. Thank you for your generosity in offering guidance. However, you must remember that there some of us who don't [and probably never will] have your breadth of knowledge and understanding - and therefore we forget where to look and are often confused!

An example of my lack of understanding is that when looking at donutStartAngle the notes say " Angle to start from when in donut mode", yet I am using compass node so upon seeing that, I would normally have disregarded it as not applicable to me, had you not alerted me to it.

Thanks to your kind suggestion, I did set up a simple system to send the incoming compass data to the gauge [for display] plus a second stream to control the donuStartPosition. Unfortunately a fight ensued for they seem to be inseparable, with a constant flickering between the two values as the poor confused node tried to cope. Change one and it affects the other.

To confirm the issue, I set up a simple trial with a pair of slider controls to allow me to manually and independently control compass value and donutStartPosition but one just overrode the other. I really need to disconnect the pointer from the displayed value so they can be managed independently.

I did have a visually inelegant idea of setting the Label to the compass bearing and arranging the gauge node to display point to North, but again there appears to be an inseparable relationship. Sett the Label dynamically and the pointer moves too.

So in conclusion, I have a feeling that I am not able to achieve what I had hoped with this node and will have to think of options or abandon the idea.

Thanks again.

BTW For any other person stumbling across this, the helpful list is actually node-red-dashboard/config-fields.md at master · node-red/node-red-dashboard · GitHub

You would need to to some adding or possibly subtraction from the 360 degrees then send the doughnut start angle that would be correct for the heading.

If you provided example of heading and where you want the arrow to face, we could get a better understanding of the calc needed.

To find help always start with the node sidebar help, then the github page for the node. They will often give you more link to info that often helps.

If you experiment you often find that things you think might not work work fine.

p.s You could of informed me my post had a incorrect link, I have fixed it now.

The calc for the pointer is very simple, "360 - compass heading" . [There is a little tweak to manage the crossover point of 359 to 0 degrees but that is already accommodated in a function that handles the incoming compass MQTT data, which I have slowed for this experiment to update every 1 second

Some examples:

Imagine heading on a course of 030° - my compass module produces a tilt-compensated output of 30. North will be showing slightly to the left at 330°.

I would like the Gauge-ui node to show 30 in the centre and the pointer to point toward 330.

Similarly, turning further right on to a heading of 090° degrees, I would like to see 90 in the centre of the display and the 'needle' pointing at 270° to indicate the direction of North.

So in essence, whilst the digital value increases as one turns to the right, the pointer value needs to decrease to the left - imagine rotating a compass to the right, the card continues pointing to North and appears to turn to the left. Turning to the

left will have a similar effect, tracking North whilst displaying the heading.

donutStartAngle did sound like it was the answer to my problem until I discovered that it can only ever reflect the value displayed - and vice versa. There seem to be no option to get Gauge-ui to accept two separate inputs and display them independently.

That said, it is most certainly not intended as a criticism of this excellent node, only that my proposed usage is a little unconventional [ weird, perhaps ] !

I have attached a couple of examples created from screenshots showing what I would really like to see - I must emphasise these are contrived to show the intended values and not actual!

example2
example1

Does this do what you want ?

[{"id":"a78c5e6c732f1547","type":"ui_gauge","z":"8a4471faf1092e03","name":"","group":"1f653102b0526136","order":0,"width":0,"height":0,"gtype":"compass","title":"gauge","label":"degrees","format":"{{360-value}}","min":0,"max":"360","colors":["#00b500","#e6e600","#ca3838"],"seg1":"","seg2":"","diff":false,"className":"","x":510,"y":1000,"wires":[]},{"id":"155db7cf5b8c18e9","type":"ui_slider","z":"8a4471faf1092e03","name":"","label":"slider","tooltip":"","group":"1f653102b0526136","order":1,"width":0,"height":0,"passthru":true,"outs":"all","topic":"topic","topicType":"msg","min":0,"max":"360","step":"10","className":"","x":150,"y":1000,"wires":[["48626330883b078b"]]},{"id":"48626330883b078b","type":"function","z":"8a4471faf1092e03","name":"function 3","func":"msg.payload = 360 - msg.payload\nreturn msg;","outputs":1,"timeout":0,"noerr":0,"initialize":"","finalize":"","libs":[],"x":320,"y":1000,"wires":[["a78c5e6c732f1547"]]},{"id":"1f653102b0526136","type":"ui_group","name":"Default","tab":"168042a0a61f9cdb","order":1,"disp":true,"width":"6","collapse":false,"className":""},{"id":"168042a0a61f9cdb","type":"ui_tab","name":"Home","icon":"dashboard","disabled":false,"hidden":false}]

That is brilliant, what an elegant solution! Every day is a school day, eh? It certainly solves the problem and shows where North is at all times.

I was totally unaware that there is an opportunity to modify 'Value format' in such a manner. So much to learn and such little time.

Thank you so much for that, it is greatly appreciated!

Thank you too, to E1cid for taking the time to remind me of options.

1 Like

I tried that earlier with {{359 - msg.payload}} but it not work. but works with {{359 - value}}.
Can you explain why the difference.

... and shows where North is at all times ...

[{"id":"2c81cb5325f47588","type":"ui_template","z":"f7524a639caff2a3","group":"114a2e1f69fe362d","name":"compass","order":0,"width":"4","height":"4","format":"<div class=\"windrose\">\n    <svg xmlns=\"http://www.w3.org/2000/svg\" version=\"1.1\" x=\"0\" y=\"0\" width=\"100%\" height=\"100%\" viewBox=\"0 0 500 500\">\n        <g class=\"graphics\" id=\"{{'wr_'+$id}}\">\n            <g>\n                <circle cx=\"250\" cy=\"250\" r=\"205\" class=\"ring\" />\n                <circle cx=\"250\" cy=\"250\" r=\"205\" class=\"tick major\" pathLength=\"720\" />\n                <circle cx=\"250\" cy=\"250\" r=\"200\" class=\"tick mid\" pathLength=\"720\" />\n                <circle cx=\"250\" cy=\"250\" r=\"195\" class=\"tick minor\" pathLength=\"720\" />\n            </g>\n            <g>\n                <text transform=\"matrix(1 0 0 1 385 268)\" class=\"letters\">E</text>\n                <text transform=\"matrix(1 0 0 1 233 420)\" class=\"letters\">S</text>\n                <text transform=\"matrix(1 0 0 1 233 112)\" class=\"letters\">N</text>\n                <text transform=\"matrix(1 0 0 1 82 268)\" class=\"letters\">W</text>\n            </g>\n        </g>\n\n    </svg>\n    <div class=\"txt\">\n        <div id=\"{{'wrp_'+$id}}\"></div>\n        <div class=\"small\">PRIMARY</div>\n        <div class=\"small\">SECONDARY</div>\n        <div id=\"{{'wrs_'+$id}}\"></div>\n    </div>\n    <div class=\"needle\"></div>\n</div>\n\n<script>\n    (function(scope) {\n  scope.$watch('msg', function(msg) {\n    if (msg) {\n      $(\"#wr_\"+scope.$id).css('transform','rotate('+(360 - msg.payload)+'deg)')\n      $(\"#wrp_\"+scope.$id).text(msg.payload+\"°\")\n      $(\"#wrs_\"+scope.$id).text(360-msg.payload+\"°\")\n    }\n  });\n})(scope);\n</script>","storeOutMessages":true,"fwdInMessages":true,"resendOnRefresh":true,"templateScope":"local","className":"","x":500,"y":200,"wires":[[]]},{"id":"16475922080466d5","type":"ui_template","z":"f7524a639caff2a3","group":"114a2e1f69fe362d","name":"CSS","order":1,"width":0,"height":0,"format":"<style>\n    div:has(>.windrose) {\n        align-items: center;\n    }\n\n    .windrose {\n        position: relative;\n        width: 100%;\n        aspect-ratio: 1;\n        container-type: inline-size;\n    }\n    .windrose .graphics{\n        transform-box: fill-box;\n        transform-origin:center;\n    }\n\n    .tick {\n        fill: none;\n        stroke: currentColor;\n    }\n\n    .major {\n        stroke-dasharray: 1 89;\n        stroke-dashoffset: 0.5;\n        stroke-width: 40px;\n    }\n\n    .mid {\n        stroke-dasharray: 0 45 1 44 0 45 1 44;\n        stroke-dashoffset: 0.5;\n        stroke-width: 30px;\n    }\n\n    .minor {\n        stroke-dasharray: 0 5 1 4 1 4 1 4 1 4 1 4 1 4 1 4 1 4;\n        stroke-dashoffset: 0.5;\n        stroke-width: 20px;\n    }\n\n    .letters {\n        font-size: 48px;\n        fill: currentColor;\n    }\n\n    .ring {\n        fill: none;\n        stroke: currentColor;\n        stroke-width: 40;\n        opacity: 0.1;\n    }\n\n    .needle {\n        position: absolute;\n        inset: 0;\n        left: calc(50% - 1px);\n        width: 2px;\n        height: 100%;\n        transform-origin: center;\n        transition: rotate .5s;\n    }\n\n    .needle:before {\n        content: \"|\";\n        color: red;\n        position: absolute;\n        top: 1%;\n        text-align: center;\n        font-size: clamp(0.5rem, 10cqi, 2rem);\n        transform: translateX(calc(-50% + 1px));\n    }\n\n\n    .txt {\n        position: absolute;\n        inset: 0;\n        display: grid;\n        place-content: center;\n        width: 100%;\n        text-align: center;\n        font-size: clamp(0.5rem, 12cqi, 3rem);\n        font-weight: 700;\n        line-height: 1.2em;\n    }\n\n    .txt .small {\n        font-size: clamp(0.2rem, 6cqi, 1.5rem);\n        line-height: 1em;\n        font-weight: 500;\n    }\n</style>","storeOutMessages":true,"fwdInMessages":true,"resendOnRefresh":true,"templateScope":"global","className":"","x":490,"y":120,"wires":[[]]},{"id":"bd1e9e6dc546e00d","type":"ui_slider","z":"f7524a639caff2a3","name":"","label":"slider","tooltip":"","group":"114a2e1f69fe362d","order":2,"width":0,"height":0,"passthru":true,"outs":"all","topic":"topic","topicType":"msg","min":0,"max":"360","step":1,"className":"","x":350,"y":200,"wires":[["2c81cb5325f47588"]]},{"id":"114a2e1f69fe362d","type":"ui_group","name":"Default","tab":"47600b49e8d3c165","order":1,"disp":true,"width":"6","collapse":false,"className":""},{"id":"47600b49e8d3c165","type":"ui_tab","name":"Home","icon":"dashboard","disabled":false,"hidden":false}]
1 Like

@hotNipi Safari has a bit of a problem with your code, the compass rolls when you move the slider:

It's ok in FireFox, Brave and Chrome.

@dceejay example works fine, the gauge doesn't roll around.

No surprises.

3 Likes

I think that tells you something Paul :wink:

PS, happy cake day Sir.

1 Like

Well this is far better than I expected - or deserve even!

I took the liberty of adding the following to the CSS template to remove the redundant scroll bar on the RHS of the display. My application has a black background for maximum contrast in daylight on a tablet, hence the need to hide it.

.nr-dashboard-template {
overflow: hidden; /* Hide both vertical and horizontal scrollbars */
}

.nr-dashboard-template .md-card {
overflow: hidden; /* Ensure that the md-card element also hides overflow */
}

Not sure if the second entry is particularly essential, otherwise, totally brill!

It hadn't dawned upon me that a template node can be used in such a manner. I obviously need to immerse myself in these techniques to learn more, because I feel awkward when so much is handed on a plate a lot of people seem to want an instant solution as opposed to some pointers to start their research. Is there a source of sample templates or code which one can play around with to create custom gauges?

I would like to explore the option of feeding a second input to create an arc either side of the red lubber-line. A much simpler option would be to to set the secondary value to display from a second input, perhaps? As you can guess I am relatively new to Node-Red.

My system receives the Course Over Ground from a GPS NMEA sentence and when feeding it together with the Compass data through a simple differential comparator, I can create a Drift value and at present I am using an Artless-Gauge node in linear mode which is centred to display degrees +/- and spans left in red for drift to the left and green to the right.

If anyone is interested, here is a simplified flow,

[{"id":"698d3f71240ceac6","type":"function","z":"f8cabeaf5583af25","name":"Differential calculator","func":"\n// Extract HEADING and COURSE values from input\nvar heading = msg.payload.heading;\nvar course = msg.payload.track;\n\n// Convert to -180 to 180 range\nif (heading > 180) {\n    heading -= 360;\n}\nif (course > 180) {\n    course -= 360;\n}\n\n// Compute difference\nvar diff = course - heading;\n\n// Handle wraparound case\nif (diff > 180) {\n    diff -= 360;\n}\nelse if (diff < -180) {\n    diff += 360;\n}\n\n// Output difference  invert\nmsg.payload = diff *-1;\nmsg.payload = Number(msg.payload.toFixed(0));\nreturn msg;\n\n\n\n\n\n\n\n\n\n\nreturn msg;","outputs":1,"timeout":"","noerr":0,"initialize":"","finalize":"","libs":[],"x":920,"y":160,"wires":[["f1338bfc4ea2dac9"]]},{"id":"2419889beb674d9c","type":"mqtt in","z":"f8cabeaf5583af25","name":"","topic":"/nav/compass1","qos":"0","datatype":"auto-detect","broker":"a9d314e3.32bb38","nl":false,"rap":true,"rh":0,"inputs":0,"x":200,"y":260,"wires":[["f3043f6d21ebfaf9","9afd8086c41578dd"]]},{"id":"632488c623efb4bb","type":"join","z":"f8cabeaf5583af25","name":"","mode":"custom","build":"object","property":"payload","propertyType":"msg","key":"topic","joiner":"\\n","joinerType":"str","accumulate":true,"timeout":"","count":"2","reduceRight":false,"reduceExp":"","reduceInit":"","reduceInitType":"","reduceFixup":"","x":710,"y":160,"wires":[["698d3f71240ceac6"]]},{"id":"f3043f6d21ebfaf9","type":"function","z":"f8cabeaf5583af25","name":"set topic","func":"msg.topic = \"heading\";\nreturn msg;","outputs":1,"timeout":"","noerr":0,"initialize":"","finalize":"","libs":[],"x":460,"y":200,"wires":[["632488c623efb4bb"]]},{"id":"93b3ddc801a1b7ee","type":"function","z":"f8cabeaf5583af25","name":"set topic & convert","func":"//sets topic and converts GPS track ° string to number\n\nmsg.topic = \"track\";\n\nmsg.payload = Number(msg.payload);\n\nreturn msg;","outputs":1,"timeout":"","noerr":0,"initialize":"","finalize":"","libs":[],"x":490,"y":160,"wires":[["632488c623efb4bb"]]},{"id":"9afd8086c41578dd","type":"function","z":"f8cabeaf5583af25","name":"359° / 0° Transition","func":"\nif (msg.payload == null){\n    msg.payload = \"OFFLINE\";\n}\n\n//Correcton for North between and 360 / 0 \nif \n    (msg.payload <0) {\n        msg.payload = msg.payload + 359;\n    }\n\nreturn msg;","outputs":1,"timeout":0,"noerr":0,"initialize":"","finalize":"","libs":[],"x":490,"y":260,"wires":[["2c81cb5325f47588"]]},{"id":"f1338bfc4ea2dac9","type":"ui_artlessgauge","z":"f8cabeaf5583af25","group":"6bee4bad7f6e6f30","order":7,"width":4,"height":2,"name":"DRIFT","icon":"","label":"DRIFT","unit":"","layout":"linear","decimals":"0","differential":true,"minmax":false,"colorTrack":"#555555","style":"2, 2","colorFromTheme":true,"property":"payload","secondary":"secondary","inline":false,"animate":true,"sectors":[{"val":-25,"col":"#ff0000","t":"min","dot":0},{"val":-1,"col":"#ffffff","t":"sec","dot":0},{"val":2,"col":"#00ff40","t":"sec","dot":0},{"val":25,"col":"#00ff40","t":"max","dot":0}],"lineWidth":"21","bgcolorFromTheme":true,"diffCenter":"0","x":1110,"y":160,"wires":[]},{"id":"d93d907177019905","type":"link in","z":"f8cabeaf5583af25","name":"GPS COMPASS IN","links":["71af3fc27771da1d"],"x":265,"y":160,"wires":[["93b3ddc801a1b7ee"]]},{"id":"2c81cb5325f47588","type":"ui_template","z":"f8cabeaf5583af25","group":"6bee4bad7f6e6f30","name":"compass","order":2,"width":6,"height":6,"format":"<div class=\"windrose\">\n    <svg xmlns=\"http://www.w3.org/2000/svg\" version=\"1.1\" x=\"0\" y=\"0\" width=\"100%\" height=\"100%\" viewBox=\"0 0 500 500\">\n        <g class=\"graphics\" id=\"{{'wr_'+$id}}\">\n            <g>\n                <circle cx=\"250\" cy=\"250\" r=\"205\" class=\"ring\" />\n                <circle cx=\"250\" cy=\"250\" r=\"205\" class=\"tick major\" pathLength=\"720\" />\n                <circle cx=\"250\" cy=\"250\" r=\"200\" class=\"tick mid\" pathLength=\"720\" />\n                <circle cx=\"250\" cy=\"250\" r=\"195\" class=\"tick minor\" pathLength=\"720\" />\n            </g>\n            <g>\n                <text transform=\"matrix(1 0 0 1 385 268)\" class=\"letters\">E</text>\n                <text transform=\"matrix(1 0 0 1 233 420)\" class=\"letters\">S</text>\n                <text transform=\"matrix(1 0 0 1 233 112)\" class=\"letters\">N</text>\n                <text transform=\"matrix(1 0 0 1 82 268)\" class=\"letters\">W</text>\n            </g>\n        </g>\n\n    </svg>\n    <div class=\"txt\">\n        <div id=\"{{'wrp_'+$id}}\"></div>\n        <div class=\"small\"></div>\n        <div class=\"small\">DRIFT</div>\n        <div id=\"{{'wrs_'+$id}}\"></div>\n    </div>\n    <div class=\"needle\"></div>\n</div>\n\n<script>\n    (function(scope) {\n  scope.$watch('msg', function(msg) {\n    if (msg) {\n      $(\"#wr_\"+scope.$id).css('transform','rotate('+(360 - msg.payload)+'deg)')\n      $(\"#wrp_\"+scope.$id).text(msg.payload+\"°\")\n      $(\"#wrs_\"+scope.$id).text(360-msg.payload+\"°\")\n     // $(\"#wrs_\"+scope.$id).text(360-msg.payload+\"°\")\n    }\n  });\n})(scope);\n</script>","storeOutMessages":true,"fwdInMessages":true,"resendOnRefresh":true,"templateScope":"local","className":"","x":720,"y":260,"wires":[[]]},{"id":"16475922080466d5","type":"ui_template","z":"f8cabeaf5583af25","group":"114a2e1f69fe362d","name":"CSS","order":1,"width":0,"height":0,"format":"<style>\n    div:has(>.windrose) {\n        align-items: center;\n    }\n\n    .windrose {\n        position: relative;\n        width: 100%;\n        aspect-ratio: 1;\n        container-type: inline-size;\n    }\n    .windrose .graphics{\n        transform-box: fill-box;\n        transform-origin:center;\n    }\n\n    .tick {\n        fill: none;\n        stroke: currentColor;\n    }\n\n    .major {\n        stroke-dasharray: 1 89;\n        stroke-dashoffset: 0.5;\n        stroke-width: 40px;\n    }\n\n    .mid {\n        stroke-dasharray: 0 45 1 44 0 45 1 44;\n        stroke-dashoffset: 0.5;\n        stroke-width: 30px;\n    }\n\n    .minor {\n        stroke-dasharray: 0 5 1 4 1 4 1 4 1 4 1 4 1 4 1 4 1 4;\n        stroke-dashoffset: 0.5;\n        stroke-width: 20px;\n    }\n\n    .letters {\n        font-size: 48px;\n        fill: currentColor;\n    }\n\n    .ring {\n        fill: none;\n        stroke: currentColor;\n        stroke-width: 40;\n        opacity: 0.1;\n    }\n\n    .needle {\n        position: absolute;\n        inset: 0;\n        left: calc(50% - 1px);\n        width: 2px;\n        height: 100%;\n        transform-origin: center;\n        transition: rotate .5s;\n    }\n\n    .needle:before {\n        content: \"|\";\n        color: red;\n        position: absolute;\n        top: 1%;\n        text-align: center;\n        font-size: clamp(0.5rem, 10cqi, 2rem);\n        transform: translateX(calc(-50% + 1px));\n    }\n\n\n    .txt {\n        position: absolute;\n        inset: 0;\n        display: grid;\n        place-content: center;\n        width: 100%;\n        text-align: center;\n        font-size: clamp(0.5rem, 12cqi, 3rem);\n        font-weight: 700;\n        line-height: 1.2em;\n    }\n\n    .txt .small {\n        font-size: clamp(0.2rem, 6cqi, 1.5rem);\n        line-height: 1em;\n        font-weight: 500;\n    }\n\n\n.nr-dashboard-template {\noverflow: hidden; /* Hide both vertical and horizontal scrollbars */\n}\n\n\n\n\n</style>","storeOutMessages":true,"fwdInMessages":true,"resendOnRefresh":true,"templateScope":"global","className":"","x":710,"y":320,"wires":[[]]},{"id":"a9d314e3.32bb38","type":"mqtt-broker","name":"FLUIDS","broker":"192.168.4.1","port":"1883","clientid":"","autoConnect":true,"usetls":false,"protocolVersion":"4","keepalive":"60","cleansession":true,"autoUnsubscribe":true,"birthTopic":"","birthQos":"0","birthPayload":"","birthMsg":{},"closeTopic":"","closeQos":"0","closePayload":"","closeMsg":{},"willTopic":"","willQos":"0","willPayload":"","willMsg":{},"userProps":"","sessionExpiry":""},{"id":"6bee4bad7f6e6f30","type":"ui_group","name":"OPS","tab":"556fcff9.b3236","order":1,"disp":false,"width":"18","collapse":false,"className":""},{"id":"114a2e1f69fe362d","type":"ui_group","name":"Default","tab":"47600b49e8d3c165","order":1,"disp":true,"width":"6","collapse":false,"className":""},{"id":"556fcff9.b3236","type":"ui_tab","name":"OPS","icon":"dashboard","order":4,"disabled":false,"hidden":false},{"id":"47600b49e8d3c165","type":"ui_tab","name":"Home","icon":"dashboard","disabled":false,"hidden":false}]

I think this is not shortest path to solutions. It does give you maybe knowledge how some things can be done but same time stripe out most of the creativity.
Better will be to start from some create visualization and then to figure out is it possible in the world of HTML/CSS. If the idea is promising, the community will wake up for sure to support with that technical stuff. Some of such creatures will find their way to be widely used, some of such will be forgotten for ever.
For example this one - not much talkings about it. For sure it's not very practical thing but it has character. Sometimes that makes the thing.

But that one sort of exploded

Not giving much but there is something to explore and to think about.

1 Like

Food for thought!

Brilliant, thank you very much.

An update for anyone wanting further inspiration for their project.

The compass has now been modified;

  • to cover 360°, with cardinal points and scale values [set every30°] arranged radially, so the bottom of the text faces the compass rose centre.

  • to accept 2 independent inputs, the principle being Bearing which drives the rotating compass and is repeated in the upper numerical display. The lower window is just displaying a value created externally which in this case is Drift, generated from a comparator which looks at Magnetic Heading and Course Over Ground from a GPS.

These inputs and their associated text can always be manipulated programmatically if desired.

  • other tweaks are purely cosmetic and may not appeal to all.

[{"id":"16475922080466d5","type":"ui_template","z":"f8cabeaf5583af25","group":"114a2e1f69fe362d","name":"COMPASS CSS","order":1,"width":0,"height":0,"format":"<style>\n    div:has(>.windrose) {\n        align-items: center;\n    }\n\n    .windrose {\n        position: relative;\n        width: 100%;\n        aspect-ratio: 1;\n        container-type: inline-size;\n    }\n\n    .windrose .graphics {\n        transform-box: fill-box;\n        transform-origin: center;\n    }\n\n \n    .tick {\n        fill: none;\n        stroke: currentColor;\n    }\n\n    .major {\n        stroke-dasharray: 1 179;   \n        /* One tick, 179 units space */\n        stroke-dashoffset: 0;\n        stroke-width: 50px;\n        stroke:  #f9f902;\n    }\n\n    .mid {\n        stroke-dasharray: 1 19;\n        /* One tick, 19 units space */\n        stroke-dashoffset: 0;\n        stroke-width: 30px;\n        stroke: #77fe00;\n    }\n\n    .minor {\n        stroke-dasharray: 1 1;\n        /* One tick, 1 unit space */\n        stroke-dashoffset: 0;\n        stroke-width: 5px;\n        stroke: #8b8e89;\n    }\n\n    .letters {\n        font-size: 48px;\n        fill: currentColor;\n    }\n\n    .ring {\n        fill: none;\n        stroke: currentColor;\n        stroke-width: 40;\n        opacity: 0.1;\n    }\n\n    .needle {\n        position: absolute;\n        inset: 0;\n        left: calc(50% - 1px);\n        width: 2px;\n        height: 100%;\n        transform-origin: center;\n        transition: rotate .5s;\n    }\n\n    .needle:before {\n        content: \"||\";\n        color: #FF0000;\n        position: absolute;\n        top: 1%;\n        text-align: center;\n        font-size: clamp(0.5rem, 10cqi, 2rem);\n        transform: translateX(calc(-50% + 1px));\n    }\n\n    .txt {\n        position: absolute;\n        inset: 0;\n        display: grid;\n        place-content: center;\n        width: 100%;\n        text-align: center;\n        font-size: clamp(0.5rem, 12cqi, 3rem);\n        font-weight: 700;\n        line-height: 2.5em;\n    }\n\n    .txt .small {\n        font-size: clamp(0.2rem, 6cqi, 1.5rem);\n        line-height: 1em;\n        font-weight: 500;\n    }\n\n    .nr-dashboard-template {\n        overflow: hidden;\n        /* Hide both vertical and horizontal scrollbars */\n    }\n\n    .number {\n        font-size: 24px;\n        fill: currentColor;\n    }\n\n\n.txt {\n    position: absolute;\n    top: 50%;\n    left: 50%;\n    transform: translate(-50%, -50%);\n    text-align: center;\n    font-size: clamp(0.5rem, 12cqi, 3rem);\n    font-weight: 700;\n    line-height: 2.5em;\n}\n\n.digital-display {\n    border: 2px solid rgba(91, 93, 91, 0.8); /* Fine grey border */\n    border-radius: 10px; /* Rounded corners */\n    padding: 10px 10px; /* Reduced height padding */\n    display: inline-block; /* Ensure it wraps around the content */\n    font-size: 40px; /* Increase font size */\n    font-weight: bold;\n    text-align: center;\n    color: #ffffff; /* White text color */\n    background: none; /* Remove background color */\n    line-height: 1; /* Reduce line height to 1 */\n    margin-top: 8px; /* Adjust this value to fine-tune vertical centering */\n}\n\n.small {\n    font-size: clamp(0.2rem, 6cqi, 1.5rem);\n    line-height: 1em;\n    font-weight: 500;\n}\n\n\n\n\n\n</style>","storeOutMessages":true,"fwdInMessages":true,"resendOnRefresh":true,"templateScope":"global","className":"","x":860,"y":300,"wires":[[]],"info":".major {\r\n      \r\n       stroke-dasharray: 1 179;  //90° intervals \r\n\r\n\r\n\r\n\r\n       Original\r\n\r\n           .major {\r\n        stroke-dasharray: 1 89;\r\n        stroke-dashoffset: 0.5;\r\n        stroke-width: 40px;\r\n    }\r\n\r\n    .mid {\r\n        stroke-dasharray: 0 45 1 44 0 45 1 44;\r\n        stroke-dashoffset: 0.5;\r\n        stroke-width: 30px;\r\n    }\r\n\r\n    .minor {\r\n        stroke-dasharray: 0 5 1 4 1 4 1 4 1 4 1 4 1 4 1 4 1 4;\r\n        stroke-dashoffset: 0.5;\r\n        stroke-width: 20px;\r\n    }"},{"id":"0e23fe911177a82e","type":"ui_template","z":"f8cabeaf5583af25","group":"0e2c8f8e80d3d1f7","name":"COMPASS - FULL","order":3,"width":10,"height":10,"format":"<div class=\"windrose\">\n    <svg xmlns=\"http://www.w3.org/2000/svg\" version=\"1.1\" x=\"0\" y=\"0\" width=\"100%\" height=\"100%\" viewBox=\"0 0 500 500\">\n        <g class=\"graphics\" id=\"{{'wr_'+$id}}\">\n            <g>\n                <circle cx=\"250\" cy=\"250\" r=\"205\" class=\"ring\" />\n                <circle cx=\"250\" cy=\"250\" r=\"200\" class=\"tick mid\" pathLength=\"720\" />\n                <circle cx=\"250\" cy=\"250\" r=\"195\" class=\"tick minor\" pathLength=\"720\" />\n                <circle cx=\"250\" cy=\"250\" r=\"205\" class=\"tick major\" pathLength=\"720\" />\n            </g>\n            <g>\n                <text x=\"250\" y=\"113\" class=\"letters\" text-anchor=\"middle\">N</text>\n                <text x=\"250\" y=\"515\" class=\"letters\" text-anchor=\"middle\" transform=\"rotate(180, 250, 450)\">S</text>\n                <text x=\"430\" y=\"295\" class=\"letters\" text-anchor=\"middle\" transform=\"rotate(90, 430, 250)\">E</text>\n                <text x=\"70\" y=\"295\" class=\"letters\" text-anchor=\"middle\" transform=\"rotate(-90, 70, 250)\">W</text>\n            </g>\n            <g class=\"numbers\">\n                <text x=\"306\" y=\"140\" class=\"number\" text-anchor=\"middle\" transform=\"rotate(30, 380, 170)\">30</text>\n                <text x=\"343\" y=\"250\" class=\"number\" text-anchor=\"middle\" transform=\"rotate(60, 440, 250)\">60</text>\n                <text x=\"200\" y=\"414\" class=\"number\" text-anchor=\"middle\" transform=\"rotate(120, 320, 430)\">120</text>\n                <text x=\"120\" y=\"490\" class=\"number\" text-anchor=\"middle\" transform=\"rotate(150, 240, 470)\">150</text>\n                <text x=\"194\" y=\"460\" class=\"number\" text-anchor=\"middle\" transform=\"rotate(210, 170, 430)\">210</text>\n                <text x=\"20\" y=\"340\" class=\"number\" text-anchor=\"middle\" transform=\"rotate(240, 60, 310)\">240</text>\n                <text x=\"130\" y=\"130\" class=\"number\" text-anchor=\"middle\" transform=\"rotate(300, 150, 170)\">300</text>\n                <text x=\"150\" y=\"58\" class=\"number\" text-anchor=\"middle\" transform=\"rotate(330, 250, 50)\">330</text>\n            </g>\n        </g>\n    </svg>\n\n    <div class=\"txt\">\n       <div class=\"small\">HEADING</div>\n        <div id=\"{{'wrp_'+$id}}\" class=\"digital-display\">{{msg.payload.heading}}°</div>\n        \n        <div id=\"{{'wrd_'+$id}}\" class=\"digital-display\">{{msg.payload.drift}}°</div>\n        <div class=\"small\">DRIFT</div>\n    </div>\n\n    <div class=\"needle\"></div>\n</div>\n\n<script>\n    (function(scope) {\n        scope.$watch('msg', function(msg) {\n            if (msg) {\n                // Update heading\n                $(\"#wr_\" + scope.$id).css('transform', 'rotate(' + (360 - msg.payload.heading) + 'deg)');\n                $(\"#wrp_\" + scope.$id).text(msg.payload.heading + \"°\");\n                // Update drift\n                if (msg.payload.drift !== undefined) {\n                    $(\"#wrd_\" + scope.$id).text(msg.payload.drift + \"°\");\n                }\n            }\n        });\n    })(scope);\n</script>","storeOutMessages":true,"fwdInMessages":true,"resendOnRefresh":true,"templateScope":"local","className":"compass-border","x":1230,"y":340,"wires":[[]],"info":"WORKING SINGLE DISPLAY\r\n\r\n<div class=\"windrose\">\r\n    <svg xmlns=\"http://www.w3.org/2000/svg\" version=\"1.1\" x=\"0\" y=\"0\" width=\"100%\" height=\"100%\" viewBox=\"0 0 500 500\">\r\n        <g class=\"graphics\" id=\"{{'wr_'+$id}}\">\r\n            <g>\r\n                <circle cx=\"250\" cy=\"250\" r=\"205\" class=\"ring\" />\r\n                <circle cx=\"250\" cy=\"250\" r=\"205\" class=\"tick major\" pathLength=\"720\" />\r\n                <circle cx=\"250\" cy=\"250\" r=\"200\" class=\"tick mid\" pathLength=\"720\" />\r\n                <circle cx=\"250\" cy=\"250\" r=\"195\" class=\"tick minor\" pathLength=\"720\" />\r\n            </g>\r\n            <g>\r\n                <text x=\"250\" y=\"113\" class=\"letters\" text-anchor=\"middle\">N</text>\r\n                <text x=\"250\" y=\"515\" class=\"letters\" text-anchor=\"middle\" transform=\"rotate(180, 250, 450)\">S</text>\r\n                <text x=\"430\" y=\"295\" class=\"letters\" text-anchor=\"middle\" transform=\"rotate(90, 430, 250)\">E</text>\r\n                <text x=\"70\" y=\"295\" class=\"letters\" text-anchor=\"middle\" transform=\"rotate(-90, 70, 250)\">W</text>\r\n            </g>\r\n            <g class=\"numbers\">\r\n                <text x=\"306\" y=\"140\" class=\"number\" text-anchor=\"middle\" transform=\"rotate(30, 380, 170)\">30</text>\r\n                <text x=\"343\" y=\"250\" class=\"number\" text-anchor=\"middle\" transform=\"rotate(60, 440, 250)\">60</text>\r\n                <text x=\"200\" y=\"414\" class=\"number\" text-anchor=\"middle\" transform=\"rotate(120, 320, 430)\">120</text>\r\n                <text x=\"120\" y=\"490\" class=\"number\" text-anchor=\"middle\" transform=\"rotate(150, 240, 470)\">150</text>\r\n                <text x=\"194\" y=\"460\" class=\"number\" text-anchor=\"middle\" transform=\"rotate(210, 170, 430)\">210</text>\r\n                <text x=\"20\" y=\"340\" class=\"number\" text-anchor=\"middle\" transform=\"rotate(240, 60, 310)\">240</text>\r\n                <text x=\"130\" y=\"130\" class=\"number\" text-anchor=\"middle\" transform=\"rotate(300, 150, 170)\">300</text>\r\n                <text x=\"150\" y=\"58\" class=\"number\" text-anchor=\"middle\" transform=\"rotate(330, 250, 50)\">330</text>\r\n            </g>\r\n        </g>\r\n    </svg>\r\n\r\n  <!--  <div class=\"txt\">\r\n        <div id=\"{{'wrp_'+$id}}\"></div>\r\n        <div class=\"small\"></div>\r\n    </div>\r\n-->\r\n\r\n<div class=\"txt\">\r\n    <div id=\"{{'wrp_'+$id}}\" class=\"digital-display\">{{msg.payload}}°</div>\r\n    <div class=\"small\"></div>\r\n</div>\r\n\r\n\r\n\r\n\r\n\r\n    \r\n    <div class=\"needle\"></div>\r\n</div>\r\n\r\n\r\n\r\n<script>\r\n    (function(scope) {\r\n        scope.$watch('msg', function(msg) {\r\n            if (msg) {\r\n                $(\"#wr_\" + scope.$id).css('transform', 'rotate(' + (360 - msg.payload) + 'deg)');\r\n                $(\"#wrp_\" + scope.$id).text(msg.payload + \"°\");\r\n            }\r\n        });\r\n    })(scope);\r\n</script>"},{"id":"114a2e1f69fe362d","type":"ui_group","name":"Default","tab":"47600b49e8d3c165","order":1,"disp":true,"width":"6","collapse":false,"className":""},{"id":"0e2c8f8e80d3d1f7","type":"ui_group","name":"COMPASS","tab":"5","order":2,"disp":true,"width":22,"collapse":false,"className":""},{"id":"47600b49e8d3c165","type":"ui_tab","name":"Home","icon":"dashboard","disabled":false,"hidden":false},{"id":"5","type":"ui_tab","name":"COMPASS","icon":"dashboard","disabled":false,"hidden":false}]
5 Likes

Looks great

1 Like

Just missing a little bit of air between numbers and tickmarks.

1 Like

Yes indeed - good point!

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