Skip to content

Instantly share code, notes, and snippets.

@PaulWieland
Last active August 1, 2023 16:21
Show Gist options
  • Star 2 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • 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"
}
]
@PaulWieland
Copy link
Author

Update to fix the font sizes (they were not all supposed to be the same size) and also replace the JS for converting degrees to direction with a more efficent method courtesy of @shrickus

@PaulWieland
Copy link
Author

Update to add compass face background color depending on wind speed. The colors somewhat follow the ikitesurf meteogram color scheme for strength.

@chuckf201
Copy link

chuckf201 commented Mar 11, 2019

Tried your flow using node-red with raspberry-pi. Viewing with Firefox.
Seems the container is blank. Any thoughts? Input is via OpenWeather using winddirection, windspeed.

@N00BMmika
Copy link

Thanks for widget. Changed

to
to get arrow pointing where to wind blows. Originally it was pointing where from wind blows.

@PaulWieland
Copy link
Author

@N00BMmika - wind readings are always shown by telling you which direction the wind is coming from. Have a look at the windroses on wunderground.

@scalci
Copy link

scalci commented Apr 24, 2020

Thank you

@PswGithub
Copy link

Thanks, this looks awesome! I'll try to adapt my output to this.
Thanks again.

@PswGithub
Copy link

Hello,
I tried your flow without changing anything and i get the readings in the debug-window and a container on the dashboard but the container is empty. I am using Chromium on raspberry.
I have tried it on my Mac with Safari and there i get the Wind Gauge on the dashboard but the colors are not righ for me here. For example, the wind speed displays as very light grey on white background when very low speed. Is there a workaround for this for me as a newbie?

@PswGithub
Copy link

Hi again.
I got it to work properly. The problem was i needed to upgrade the chromium browser - then it worked perfectly.
I even adapted my sensor output to fit the wind gauge input and now the wind gauge works fine with my sensors.
Thanks for your good work!

@rboeije1
Copy link

After latest node-red update (I did the update in april 2021), it did not show the gauge anymore. It look lik it is out of display and the scaling seems to be broken. I noticed on a refresh that part of it was floating out of the area, so I changed the translateX an dY to a fixed value of -100 and now I can see part of it. I fiddled with the scaleWidth- and Height, but so far that did not help.
Nu clue what update destroyed it, but at least I got some warnings when I updated node-red, unlikely that they are the cause. (request, har-validator, node-pre-gyp, bcrypt)

@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.

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