Best practice for size of a UI node

Hi folks,

A few minutes ago, I announced a new node: node-red-contrib-ui-joystick. This node is based on nipplejs, which expects me to specify the size of the joystick widget in pixels:

var options = {
   ...
   size: size, // Default size is 100 (px)
   ...
};  
nipplejs.create(options);

When I started today with that node, I thought it would be best to set the node automatically as a percentage of the parent div element:

var size = Math.min($scope.containerDiv.clientWidth, $scope.containerDiv.clientHeight) * 0.49;

Because I thought: when the user increases the widget size in Node-RED, then the joystick circle will increase:

image

But at the end - as you can see above - I had to calculate the size of the widget as 49% of the parent div, otherwise nipplejs starts behaving very weird. But this means that I always have a lot of empty space around the joystick :frowning_face:.

So I'm now wondering whether it is better to set a fixed size (e.g. 100px) on such a widget. If so, I don't know whether it is user-friendly to make this size adjustable as a property on the node's config screen? Or is a fixed size not good, because scrollbars will occur when the widget size is set too small?? But due to the empty space, I think a fixed size is much better ...

Any advise is welcome, because I'm stuck with this decision...
Thanks !
Bart

I would look at transform scale to size it to fully fit the users choice.

"scale() - CSS: Cascading Style Sheets | MDN" scale() - CSS: Cascading Style Sheets | MDN

Do you mean:

  1. I pass a fixed size (e.g. 100 px) via the options, to make sure nipplejs always works correctly.
  2. Add some options to the config screen: e.g. a checkbox "scale to fit".
  3. Then apply the scaling (to the generated child content of my parent div) if that option is set.

Did I understand it correctly?

For something like your joystick then I would say something like a default of 3x3 would make sense as it's naturally a square - But yes everything inside needs to scale probably based on the smaller of width or height, and indeed if you need to fit a label in as well. (Currently I would probably try to avoid that for now)

1 Like

^ what Dave said :slight_smile:

Essentially, take the smaller of width & height then using transform scale, linearly size up to best possible fit in the centre of the UI div.

The beauty of transform scale is it takes care of mouse events and border widths etc etc and literally zooms in/out.

1 Like

Ok guys, thanks!!
Seems to work much better, compared to my approach.

I use now a fixed size (e.g. the default 100px) for the widget:

var options = {
   ...
   size: 100,
   ...
};  
nipplejs.create(options);

This means the total width of this widget can become 150px (due to the rotating circle, whose diameter is half the diameter of the large circle):

image

So I simply had to define my parent container div like this:

<div style="width:100%; height:100%; position:relative;"></div>

And scale its child div (which belongs to the nipplejs widget):

var scaleFactor = Math.min($scope.containerDiv[0].clientWidth, $scope.containerDiv[0].clientHeight) / 150;
$scope.containerDiv.children(":first").css({ transform: 'scale(' + scaleFactor + ')' });

Now the nipplejs widget is nicely scaled into the available area of my parent div, and I get no scrollbars when I start dragging the small circle around:

joystick_scale

Hopefully other UI node developers can learn from our discussion ...

2 Likes