Skip to content

Instantly share code, notes, and snippets.

@PaulWieland
Last active October 10, 2024 19:13
Show Gist options
  • Save PaulWieland/b9a57175ac5a5e240c9916bcce136dca to your computer and use it in GitHub Desktop.
Save PaulWieland/b9a57175ac5a5e240c9916bcce136dca to your computer and use it in GitHub Desktop.
Wind Gauge with Compass

This is a dashboard widget for displaying wind speed and direction in one gauge.

The gauge takes three inputs from msg.payload:

  1. speed (number)
  2. speed_unit (string) - Any string you want displayed after the speed, e.g. MPH, KMH, KTS, etc
  3. degrees (0-360 to for compass direction)

An example input node is included. You can replace it with your own data source (e.g. wunderground PWS)

Tested on Safari & Chrome (sorry, I have no access to IE or Edge).

[
{
"id": "409af0a5.b6e3e8",
"type": "inject",
"z": "ed02aad4.a669c8",
"name": "",
"repeat": "2",
"crontab": "",
"once": true,
"topic": "",
"payload": "",
"payloadType": "date",
"x": 150,
"y": 1120,
"wires": [
[
"d12411f0.075428"
]
]
},
{
"id": "a3654026.abf898",
"type": "ui_template",
"z": "ed02aad4.a669c8",
"group": "64704468.613964",
"name": "Wind",
"order": 1,
"width": "4",
"height": "4",
"format": "<!--\npass msg.payload.degrees, msg.payload.speed, msg.payload.speed_unit\n-->\n<script>\n // Watch the incoming message and convert the degrees to a human readable compass direction\n (function(scope){\n scope.$watch('msg', function(msg) {\n if(typeof(msg) === \"object\"){\n // Convert the degrees to cardinal directions\n var deg = msg.payload.degrees;\n var dirs = [\"N\",\"NNE\",\"NE\",\"ENE\",\"E\",\"ESE\",\"SE\",\"SSE\",\"S\",\"SSW\",\"SW\",\"WSW\",\"W\",\"WNW\",\"NW\",\"NNW\",\"N\"];\n var idx = Math.round(deg*(dirs.length-1)/360);\n scope.direction = dirs[idx];\n \n \n // Keep track of the highest speed value, giving it 40 as a rough starting point.\n // Works okay for MPH and KTS, but KMH will show purple at a lower speed than the rest\n scope.max_val = (msg.payload.speed > scope.max_val ? msg.payload.speed : 40);\n \n scope.p_speed = msg.payload.speed;\n scope.p_max_val = scope.max_val;\n var low_colors = [\n '#FFFFFF', // white\n '#d6f7ff', // light blue\n '#85ffd2', // blue green\n '#61ff6e' // green 10mph\n ];\n var high_colors = [\n '#61ff6e', // green 10mph\n '#d5ff61', // green yellow\n '#fffc61', // yellow\n '#ffe561', // yellow orange 20mph\n '#ffcd61', // orange\n '#ffad61', // orange red\n '#ff7661', // red\n '#ff61dd', // red purple\n '#e261ff' // purple\n ];\n \n if(msg.payload.speed <= 10){\n scope.color = low_colors[Math.round(msg.payload.speed*(low_colors.length-1)/10)];\n }else{\n scope.color = high_colors[Math.round(msg.payload.speed*(high_colors.length-1) / scope.max_val)];\n }\n \n //$(\".compass_container\").css(\"background-color\",scope.color);\n }\n \t});\n })(scope);\n \n // Hacks to improve the layout and make it scale\n $(document).ready(function(){\n setTimeout(function () {\n // Remove the auto scrolling from the parent node\n $(\".compass_container\").parent().css(\"overflow\",\"hidden\");\n \n // Adjust the color to match the theme base color by looking up the toolbar header background color;\n $(\".compass_container .triangle\").css(\"border-bottom-color\",$(\"md-toolbar\").css(\"background-color\"));\n \n // Scale the compass into the box that it's being rendered in\n // This CSS hack helps make sure the line & font size scales appropriately\n // Based on the node's grid size\n $(\".compass_container\").each(function(k,v){\n var scaleWidth = $(v).parent().width() / $(v).width();\n var scaleHeight = $(v).parent().height() / $(v).height();\n \n var translateX = ($(v).width() - $(v).parent().width()) / 2;\n var translateY = ($(v).height() - $(v).parent().height()) / 2;\n \n $(v).css(\"transform\",\"translate(-\"+translateX+\"px,-\"+translateY+\"px) scale(\"+scaleWidth+\",\"+scaleHeight+\") \");\n });\n \n $(\".compass_container\").css(\"display\",\"block\"); // Unhide it now that it's resized\n }, 1000);\n });\n</script>\n<style>\n @import url(https://fonts.googleapis.com/css?family=Dosis:200,400,500,600);\n \n .compass_container{\n transition: 1s ease-in-out;\n position: relative;\n display: none;\n width: 500px;\n height: 500px;\n flex-shrink:0;\n border-radius: 100%;\n font-family: 'Dosis';\n font-size: 80px;\n box-shadow: inset 0px 0px 0px 30px #777; \n background-color: {{color}};\n }\n \n .compass_container .compass_header{\n font-weight: bold;\n position: absolute;\n text-align: center;\n width: 100%;\n font-size: 75%;\n top: -15px\n }\n .compass_container .text_container{\n height: 100%;\n width: 100%;\n padding: 0px;\n display: block;\n border-radius: 100%;\n display: flex;\n flex-direction: column;\n justify-content: center;\n align-items: center;\n }\n \n .compass_container .arrow{\n transition: 1s ease-in-out;\n width: 100%;\n height: 100%;\n display: block;\n position: absolute;\n top: 0;\n }\n \n .compass_container .arrow .triangle{\n width: 0;\n\t\theight: 0;\n\t\tborder-left: 45px solid transparent;\n\t\tborder-right: 45px solid transparent;\n\t\tborder-bottom: 90px solid black;\n\t\tposition: absolute;\n\t\ttop: -15px;\n\t\tleft: 50%;\n\t\tmargin-left: -45px;\n\t\tz-index: 99;\n }\n</style>\n\n<div class=\"compass_container\" style=\"\">\n <div class=\"compass_header\">N</div>\n \n <div class=\"nr-dashboard-text text_container\">\n \n <div class=\"direction\" style=\"font-size: 120%\">{{direction}}</div>\n <div style=\"flex-direction: row; font-weight: bold;\">\n <span style=\"font-size: 100%\">{{msg.payload.speed}}</span>\n <span style=\"font-size: 75%\">{{msg.payload.speed_unit}}</span>\n </div>\n </div>\n <div class=\"arrow\" style=\"transform: rotate({{msg.payload.degrees}}deg);\">\n <div class=\"triangle\"></div>\n </div>\n</div>",
"storeOutMessages": true,
"fwdInMessages": true,
"resendOnRefresh": false,
"templateScope": "local",
"x": 450,
"y": 1120,
"wires": [
[]
]
},
{
"id": "d12411f0.075428",
"type": "function",
"z": "ed02aad4.a669c8",
"name": "",
"func": "var msg = {\n \"payload\": {\n \"speed\":Math.round(Math.random() * 60),\n \"speed_unit\":\"MPH\",\n \"degrees\":Math.round(Math.random() * 360)\n \n }\n}\nreturn msg;",
"outputs": 1,
"noerr": 0,
"x": 310,
"y": 1120,
"wires": [
[
"a3654026.abf898"
]
]
},
{
"id": "64704468.613964",
"type": "ui_group",
"name": "Default Group",
"tab": "ef22f042.de6a1",
"order": 1,
"disp": true,
"width": "9"
},
{
"id": "ef22f042.de6a1",
"type": "ui_tab",
"name": "Home Tab",
"icon": "dashboard"
}
]
@austindetzel
Copy link

I have the same problem with the latest update, it seems to not be formatted correctly. Any suggestions?

@rboeije1
Copy link

rboeije1 commented May 2, 2021

I have the same problem with the latest update, it seems to not be formatted correctly. Any suggestions?

On one hand it looks like $(document).ready(function() is nnot fired, however, if I change var translateX = -1 to any negative number (Becomming '--1' a few lines down) it shows part of the dial. So I tried to fiddle with the scale, no effect at all, even if I add the '%' in the line where the variables are used. With some values it apears and floats to the right. (Like when you kame it zero)
If you make the box bigger (like 5x5 and not 3x3 as I used to have) you see a bigger part of the dial.
Let me know if you figured it out. The other elements on my layout are not affected by the update.

@PaulWieland
Copy link
Author

I started looking into this, and its definitely some issue with Chrome. The widget still renders fine under Safari.

The Wind Gauge is drawn as a 500px x 500px box, and then after the UI loads, I use a CSS transform to scale it to the size of the box that the user defined. It does this by getting the parent element's width and height, and then calculates the scaling factor. This logic is running correctly under Chrome (same values as Safari), however the css transformation that chrome performs is completely different than it used to be.

@rboeije1
Copy link

rboeije1 commented May 3, 2021

Hi Paul, thanks for taking time to look into this. As you may have noticed from my comment, I did find the scaling part of the code. Even if you put in a fixed number, it does not change. The same for the transformation. I tried a couple of fixed values, strange enough, whatever negative value you put in, it does shift in to the box. But I assume you tried that as well.
I tried Firefox, as you mentioned it does work on safari, but firefox has the same behavior as chrome. For now, I lack css experience to resolve it. Hope you do.

@rboeije1
Copy link

rboeije1 commented May 3, 2021

Well, making slight progress. Changed the translate to 3d and moved Y -100px. It now displays an oval on chrome, a better shape on the samsung browser on android.

var translateX = ($(v).width() - $(v).parent().width()) / 2;
var translateY = -100+($(v).height() - $(v).parent().height()) / 2;
        
$(v).css("transform","translate3d(-"+translateX+"px,-"+translateY+"px, 0) scale("+scaleWidth+","+scaleHeight+") ");

image

@PaulWieland
Copy link
Author

I just updated the gist. Add flex-shrink:0; to .compass-container css declaration.

@rboeije1
Copy link

rboeije1 commented May 3, 2021

Thanks. It's working again. Although it looks like the thickness of the circle is slightly smaller, but as I do not know you initial design, maybe that was wrong on chrome already and is now corrected.

@austindetzel
Copy link

I just updated the gist. Add flex-shrink:0; to .compass-container css declaration.

Thanks a lot man!

@RicharddeCrep
Copy link

This is great, but being a pilot, the arrow ALWAYS points from where the wind originates. So a northerly wind has an arrow pointing down on a compass.

So I'd suggest adding " transform: rotate(180deg);" to the Arrow section near the botom of the template.
It now looks normal to pilots.

Thank you for a great contribution.

@PaulWieland
Copy link
Author

@RicharddeCrep You're right. The arrow is in the right place on the circle (north wind has the arrow at the top) but the point on the triangle is backward (it should point down, and it points up instead). It wasn't originally like this, somewhere along the line I screwed it up.

Will issue an update to the gist as soon as I have time.

@Nicehavetoo
Copy link

Thank you for sharing this awesome gauge. I modified it a bit to show the direction of my next waypoint.
image
Only I like to change the letter N that indicates north. How can I modify this "N"?
The way I am using the gauge is; I got my heading is up and the arrow points at my waypoint.
I'd like to change the "N" to the value of my heading.

@chuckf201
Copy link

Has this great node been updated to dashboard 2.0?
and
can it be resized to minimize area? I tried this several years ago and the compass became deformed.

@rboeije1
Copy link

rboeije1 commented Oct 8, 2024

I have dashboard version 3.4.0 running on node-red v3.02 if that is what you mean. And I am using this for wind direction.

@rboeije1
Copy link

rboeije1 commented Oct 8, 2024

image
I edited the source a tiny bit, so the N is as high as the band.

@chuckf201
Copy link

Excellent. Will try as soon as I get past this huricane stuff.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment