Custom UI node - layout problems

Hi folks,

It has become very clear that I will never receive a Nobel Prize in styling, layouting, CSS, ... :woozy_face:

For my new contribution node-red-contrib-ui-camera, I want a 'canvas' tag that displays my camera images (so I can draw all kind of custom graphics stuff on top of those images). In my current version the HTML part is very short:

<canvas id="cameraCanvas" width="100%" height="100%" ng-init='init(` + configAsJson + `)'></canvas>

The video stream is decoded nicely, and those decoded images are drawn onto this canvas.
But for some obscure reason the canvas had a wrong height:


So I tried the nice tips from @steuck13, but must have done something wrong because it became worse. So I changed my code back to my original version, but I must have forgotten something because now the canvas has become awfull small with annoying scrollbars:


Here you can see the size of the canvas:

And it's parent element is also very small, although I 'think' I cannot influence that (except with my 100% perhaps?):

Below is my 'size' setting, but to be honest I have no clue at all how I should take this setting into account in my styling:

Any help to get this integrated nicely into the dashboard is HIGHLY appreciated !!!


@BartButenaers you have a naming issue.

If I run npm install bartbutenaers/node-red-contrib-ui-camera I end up with node-red-contrib-ui-video

Pauls-mini-3:.node-red Paul$ npm install bartbutenaers/node-red-contrib-ui-camera
npm WARN node-red-project@0.0.1 No repository field.
npm WARN node-red-project@0.0.1 No license field.

+ node-red-contrib-ui-video@0.0.1
added 1 package from 1 contributor and audited 1313 packages in 6.427s
found 13 vulnerabilities (1 low, 10 moderate, 2 high)
  run `npm audit fix` to fix them, or `npm audit` for details

I'm still stumbling around with the dashboard but I had to change the Size property to 13x7 to display a 640x360 image

13x48 = 624
7x48 = 336

Which would seem too small, but I appear to get the full image. I definitely don't have much of an understanding of the dashboard layout parameters.

Hey Paul (@zenofmud), good catch. My node is faaaaaaar from completed... The first name was node-red-contrib-ui-video since it could also play video files, but the same evening someone else announced his node-red-contrib-ui-media. So I removed the video playing functionality from my node, and I renamed it to node-red-contrib-ui-camera. But seems I forgot to update the package.json file. I have now updated it on Github...

Hi @Wb666greene,
I assume that most users will display multiple camera's simultaneously, and with a mix of different sizes. Like in this professional video surveillance software:


But I don't know how I should set my canvas style, to make this kind of stuff possible :woozy_face: Hoping that somebody can help me with this, to make sure it is correct from the start...

have you tried both setting the CSS width, height values and the width, height values of the canvas? Further, the canvas width, heigh values cannot be percentages, they have to be pixels

Hi @cinhcet, I have tried first to set a width and height as attributes on the canvas element. Afterwards I removed those and I applied a canvas style (containing width and height), but that became worse. So now I have again just a width and height attribute, as you can see in the code snippet above.

Ah thanks, I wasn't aware of that. But then I understand it even less. A user wants to set the size of the widget using the 'size' option in the config screen, and I need to resize my image to fit into the canvas. Or not? But when I need to set pixels as canvas width and height, my theorie isn't correct anymore...

one way would be to set the width/height of the canvas directly with javascript/angularjs based on the size of the widget, multiplied by the factor dashboard size unit -- pixels (I think it was 48 or something?!?).

@wb666greene - from the Dashboard sidebar site tab
So if you set it 13 wide the widget will be
13x48 units + 12x6 spaces = 624 + 72 = 696 px


It's the other way round... your styling needs to work within the space allocated to the widget - so 100%x100% is probably a good starting point. Then you need to allocate the height either as per what the user specifies manually - or automatically if they set to auto - usually I do that based on width - eg for the chart I use this is the control: { section of the ui_chart.js

width: parseInt(config.width || group.config.width || 6),
height: parseInt(config.height || group.config.width/2+1 || 4),
1 Like

So it would appear that my image is displaying in the spaces or is being silently cropped (which I probably wouldn't have noticed as my goal was to get rid of the scroll bars that automatically seemed to appear).

That would be the "standard" model and if that is what you want, IMHO why re-invent the wheel? Blue Iris, etc. work fine for this model, but unless you can afford to hire someone to watch the display its really not all that useful once the cameras have been positioned. In the real world people who are hired to watch these displays often miss things as the boredom factor of such jobs is mind numbing.

My initial goal was to add AI to my "professional" security system so I could get effective notifications with as near zero false positive rate as possible, its "motion detection" notifications either flooded me with false alerts or missed me much of the time I walked by when testing. I have succeeded with the "add-on" I can count the false positives on my fingers and its been running since July 2018. Most of these were fixed with camera re-positioning (dog walkers not on my property) or a per camera "filter" to stop the notifications for a few fixed location/size detections (my wife's hanging plants).

I've discovered that some cheap netcams and a small computer can make a much more effective system without the "traditional" 24/7 recording.

??? - 696 pixels across the widget is bigger than the 640px of your image so it should fit without cropping...

Well major reason is that I'm a developer, and my hobby is developing Node-RED stuff in the evenings. Yes I could install a series of other softwares (which are probably very good), or perhaps buy a magnificent system. But that won't be any fun anymore for me... So I will continue building things like this in Node-RED, even if half of the planet thinks I'm getting nuts.

And thanks to you all. I have now a number of things learned, so I can start experimenting. And then I will come back here, asking new stupid questions :wink:


I guess I'm naively assuming a field labeled spacing in the layout would be blank and unused by the elements.

I'm totally unfamiliar with the underlying system (angular?) that the dashboard is built on. I'm using/abusing the dashboard to avoid diving into this rabbit hole. It works fine for my purposes and its pretty impressive how I get something usable in a browser on a cellphone or a desktop with minimal effort. There are issues with connection drops and "hangs" when used for "continuous" monitoring that is being discussed/worked on in another thread.

If you have a grid to put thing in... we have a widget slot - then a space to the next widget - then the next widget slot - and so on. Each widget slot has a size (default 48) - then each space has a size (default 6)... An actual widget can be any number of "units" - and if it is say 3x1 it fits across 3 slots and 2 spaces in between them.

Then all these widgets fit into a group - so there is some padding around the set of widgets (default 0) and then a gap between one group and the next (default 6). Groups can rearrange themselves on the page to fit the available space - ie from vertically on mobile to across the page on wider screens - but widgets within a group will stay in place (as the overall group width is fixed).

Just to possibly confuse - a couple of versions ago we did add the possibility to add a "spacer" widget within a group (see pic) - that can then be sized like any other widget and placed in order - and by being there can help force the layout within a group to leave holes if you want to. e.g. gaps between buttons and so on.

I certainly don't think you are nuts, I'm just trying to steer your considerable talents into something I see as "missing" instead of solving a problem that would seem to have adequate solutions already.

For instance there appears to be a node for Dropbox but not Google Drive. If you want images view-able "from anywhere" these would seem to be nice solutions.

My friend running Windows 10 got this for free simply changing the detection_save_path in my code from my default (a folder created in the directory of the python executable) to his "G drive". Linux appears to be missing a good solution for having google drive or dropbox mounted as if it were a samba share or nfs mount. So instead of Emailing images, it can just "Tweet" (something he already uses heavily) him the name of the AI detection image uploaded to Google Drive. A node to upload/download from Google Drive would seem to be useful in a lot of situations.

It'd certainly be useful to have a dashboard "widget" that displays a live rtsp or mjpeg stream when setting up cameras, but the real issue is getting WiFi coverage out where the cameras are. I've gone as far as dragging a 100' Ethernet cable with POE injector and splitter to put a WiFi access point near enough to my ladder for my phone to view the images for camera adjustment. My Onvif cameras I can just refresh a webpage view of the "snapshot". My Lorex DVR has an app for that, but its too low resolution to use for adjusting focus (most netcams are fixed focus, but ones with zoom adjusts usually are not parafocal). VLC would be OK if you maybe had a Bluetooth keyboard to type in the ridiculous rtsp URLs, but when I tried VLC, it was not robust enough to use with marginal WiFi connections.

I did stumble onto the spacer widget and do use it. Its not going away is it?

I think all my dashboard stuff started with v19.x . I do have some older versions running on Raspberry Pi ZeroWs and Android but these dashboards were just to help me with testing/debugging and I never look at them now. I never tried the dashboard on Android.

@dceejay: indeed, if I apply CSS style width and height 100% (instead of dom element attributes width and height) - as @cinhcet also suggested - then I already looks much better:


For the above animation, I used NO width and height element attributes (only CSS width and height):

<canvas id="cameraCanvas" style="width:100%; height:100%" ng-init='init(` + configAsJson + `)'></canvas>

Is it not correct what I am doing? Do I really need to calculate the width and height, like in your code snippet?

Well what happens when the user sets the size ? To say 2x2 or 20x12 (in dashboard units). If you scale to fit then all good.

Dave (@dceejay),
I now have another custom UI node, where I have a similar problem.
However it doesn't work, which is evidence nr A that I still don't get how it works :sob:

The html string contains only a single div (of 100% width and height):

var html = String.raw`
    <script src="heatmap/js/heatmap.min.js"></script>
    <div id="heatMapContainer` + + `" width="100%" height="100%" ng-init='init(` + configAsJson + `)'>

P.S. I have added the node's id to the name, to make it unique (in case multiple of those UI nodes are being added to the dashboard) ...

Then I need to call a third party library, which expects that parent div element as input:

var parentDiv = document.getElementById('heatMapContainer' +
$scope.heatMapInstance = h337.create({
       container: parentDiv

As you can see from their documentation, their heatmap canvas would automatically adapt to the parent element:

But now I need to draw heat points on that heat map (with X and Y coordinates), so I need to have the available area to draw on (width and height). Thought that the dashboard would have set the size (in pixels) of my div tag, but that is not the case:


Any ideas or suggestions?