Background image in Dashboard 2.0


With Dashboard 1.0 I used this flow to set background image that seems to work no longer with Dashboard 2.0. Could someone point out where I have the error?

    {
        "id": "123a3abe13057c25",
        "type": "inject",
        "z": "a6df4c391c658bbc",
        "name": "Trigger Image Load",
        "props": [
            {
                "p": "payload"
            }
        ],
        "repeat": "",
        "crontab": "00 12 * * *",
        "once": true,
        "onceDelay": "1",
        "topic": "",
        "payload": "",
        "payloadType": "date",
        "x": 140,
        "y": 900,
        "wires": [
            [
                "3de0634d2a482679"
            ]
        ]
    },
    {
        "id": "8efe01f5a0056fa7",
        "type": "file in",
        "z": "a6df4c391c658bbc",
        "name": "",
        "filename": "/home/gesinne/Logo/gesinne.jpg",
        "filenameType": "str",
        "format": "",
        "chunk": false,
        "sendError": false,
        "encoding": "none",
        "allProps": false,
        "x": 610,
        "y": 900,
        "wires": [
            [
                "515f9079f70bb618"
            ]
        ]
    },
    {
        "id": "515f9079f70bb618",
        "type": "function",
        "z": "a6df4c391c658bbc",
        "name": "Convert to base64",
        "func": "msg.payload = Buffer.from(msg.payload).toString('base64');\nreturn msg;",
        "outputs": 1,
        "noerr": 0,
        "x": 850,
        "y": 900,
        "wires": [
            [
                "c5f4ddf9eb75d72a"
            ]
        ]
    },
    {
        "id": "76eac3cee3ed3655",
        "type": "file in",
        "z": "a6df4c391c658bbc",
        "name": "",
        "filename": "/home/gesinne/Logo/gesinne_inicio.jpg",
        "filenameType": "str",
        "format": "",
        "chunk": false,
        "sendError": false,
        "encoding": "none",
        "allProps": false,
        "x": 590,
        "y": 940,
        "wires": [
            [
                "843b0d1bf1d69263"
            ]
        ]
    },
    {
        "id": "843b0d1bf1d69263",
        "type": "function",
        "z": "a6df4c391c658bbc",
        "name": "Convert to base64",
        "func": "msg.payload = Buffer.from(msg.payload).toString('base64');\nreturn msg;",
        "outputs": 1,
        "noerr": 0,
        "x": 850,
        "y": 940,
        "wires": [
            [
                "f93b1cb17cbba913"
            ]
        ]
    },
    {
        "id": "3de0634d2a482679",
        "type": "delay",
        "z": "a6df4c391c658bbc",
        "name": "",
        "pauseType": "delay",
        "timeout": "30",
        "timeoutUnits": "seconds",
        "rate": "1",
        "nbRateUnits": "1",
        "rateUnits": "second",
        "randomFirst": "1",
        "randomLast": "5",
        "randomUnits": "seconds",
        "drop": false,
        "allowrate": false,
        "outputs": 1,
        "x": 340,
        "y": 900,
        "wires": [
            [
                "8efe01f5a0056fa7",
                "76eac3cee3ed3655"
            ]
        ]
    },
    {
        "id": "c5f4ddf9eb75d72a",
        "type": "ui-template",
        "z": "a6df4c391c658bbc",
        "group": "4fea4ef402f7f9de",
        "page": "",
        "ui": "",
        "name": "Set Background Image",
        "order": 4,
        "width": 2,
        "height": 0,
        "head": "",
        "format": "<style>\n    #dashboard-root {\n        background-image: url('data:image/jpeg;base64,{{msg.payload}}');\n        background-size: cover;\n        background-position: center;\n        background-repeat: no-repeat;\n        width: 100%;\n        height: 100%;\n    }\n    .nr-dashboard-app {\n        background-image: url('data:image/jpeg;base64,{{msg.payload}}');\n        background-size: cover;\n        background-position: center;\n        background-repeat: no-repeat;\n    }\n</style>",
        "storeOutMessages": true,
        "passthru": true,
        "resendOnRefresh": true,
        "templateScope": "local",
        "className": "",
        "x": 1120,
        "y": 900,
        "wires": [
            []
        ]
    },
    {
        "id": "f93b1cb17cbba913",
        "type": "ui-template",
        "z": "a6df4c391c658bbc",
        "group": "1eb81248916883dc",
        "page": "",
        "ui": "",
        "name": "Set Background Image",
        "order": 1,
        "width": 0,
        "height": 0,
        "head": "",
        "format": "<style>\n    #dashboard-root {\n        background-image: url('data:image/jpeg;base64,{{msg.payload}}');\n        background-size: cover;\n        background-position: center;\n        background-repeat: no-repeat;\n        width: 100%;\n        height: 100%;\n    }\n</style>\n",
        "storeOutMessages": true,
        "passthru": true,
        "resendOnRefresh": true,
        "templateScope": "local",
        "className": "",
        "x": 1120,
        "y": 940,
        "wires": [
            []
        ]
    },
    {
        "id": "4fea4ef402f7f9de",
        "type": "ui-group",
        "name": "Escrituras",
        "page": "a31827662386e738",
        "width": 6,
        "height": "1",
        "order": 2,
        "showTitle": true,
        "className": "",
        "visible": true,
        "disabled": false
    },
    {
        "id": "1eb81248916883dc",
        "type": "ui-group",
        "name": "Group 1",
        "page": "666d17ce4d703f44",
        "width": "6",
        "height": "1",
        "order": 1,
        "showTitle": false,
        "className": "",
        "visible": true,
        "disabled": false
    },
    {
        "id": "a31827662386e738",
        "type": "ui-page",
        "name": "Registros",
        "ui": "e8131e089dc51482",
        "path": "/registros",
        "icon": "error_outline",
        "layout": "grid",
        "theme": "f8ed03d03ad5243c",
        "breakpoints": [
            {
                "name": "Default",
                "px": "0",
                "cols": "3"
            },
            {
                "name": "Tablet",
                "px": "576",
                "cols": "6"
            },
            {
                "name": "Small Desktop",
                "px": "768",
                "cols": "9"
            },
            {
                "name": "Desktop",
                "px": "1024",
                "cols": "12"
            }
        ],
        "order": 12,
        "className": "registros",
        "visible": "true",
        "disabled": "false"
    },
    {
        "id": "666d17ce4d703f44",
        "type": "ui-page",
        "name": "Inicio",
        "ui": "e8131e089dc51482",
        "path": "/inicio",
        "icon": "dashboard",
        "layout": "grid",
        "theme": "f8ed03d03ad5243c",
        "breakpoints": [
            {
                "name": "Default",
                "px": "0",
                "cols": "3"
            },
            {
                "name": "Tablet",
                "px": "576",
                "cols": "6"
            },
            {
                "name": "Small Desktop",
                "px": "768",
                "cols": "9"
            },
            {
                "name": "Desktop",
                "px": "1024",
                "cols": "12"
            }
        ],
        "order": 1,
        "className": "inicio",
        "visible": "true",
        "disabled": "false"
    },
    {
        "id": "e8131e089dc51482",
        "type": "ui-base",
        "name": "My Dashboard",
        "path": "/dashboard",
        "appIcon": "",
        "includeClientData": true,
        "acceptsClientConfig": [
            "ui-notification",
            "ui-control"
        ],
        "showPathInSidebar": false,
        "headerContent": "page",
        "navigationStyle": "default",
        "titleBarStyle": "default",
        "showReconnectNotification": true,
        "notificationDisplayTime": 5,
        "showDisconnectNotification": true
    },
    {
        "id": "f8ed03d03ad5243c",
        "type": "ui-theme",
        "name": "Mi tema",
        "colors": {
            "surface": "#ffffff",
            "primary": "#0094ce",
            "bgPage": "#eeeeee",
            "groupBg": "#ffffff",
            "groupOutline": "#cccccc"
        },
        "sizes": {
            "density": "compact",
            "pagePadding": "0px",
            "groupGap": "0px",
            "groupBorderRadius": "0px",
            "widgetGap": "0px"
        }
    }
]```


My try, but it doesn't work either

    {
        "id": "inject-trigger",
        "type": "inject",
        "z": "a6df4c391c658bbc",
        "name": "Start Timer",
        "props": [],
        "repeat": "",
        "crontab": "",
        "once": true,
        "onceDelay": "30",
        "topic": "",
        "x": 130,
        "y": 1020,
        "wires": [
            [
                "file-inicio",
                "file-registros"
            ]
        ]
    },
    {
        "id": "file-inicio",
        "type": "file in",
        "z": "a6df4c391c658bbc",
        "name": "Read Inicio Image",
        "filename": "/home/gesinne/Logo/gesinne_inicio.jpg",
        "filenameType": "str",
        "format": "",
        "sendError": false,
        "encoding": "none",
        "x": 390,
        "y": 1020,
        "wires": [
            [
                "convert-base64-inicio"
            ]
        ]
    },
    {
        "id": "convert-base64-inicio",
        "type": "function",
        "z": "a6df4c391c658bbc",
        "name": "Convert to base64",
        "func": "msg.payload = Buffer.from(msg.payload).toString('base64');\nreturn msg;",
        "outputs": 1,
        "noerr": 0,
        "x": 710,
        "y": 1020,
        "wires": [
            [
                "set-background-inicio"
            ]
        ]
    },
    {
        "id": "file-registros",
        "type": "file in",
        "z": "a6df4c391c658bbc",
        "name": "Read Registros Image",
        "filename": "/home/gesinne/Logo/gesinne.jpg",
        "format": "",
        "sendError": false,
        "encoding": "none",
        "x": 400,
        "y": 1080,
        "wires": [
            [
                "convert-base64-registros"
            ]
        ]
    },
    {
        "id": "convert-base64-registros",
        "type": "function",
        "z": "a6df4c391c658bbc",
        "name": "Convert to base64",
        "func": "msg.payload = Buffer.from(msg.payload).toString('base64');\nreturn msg;",
        "outputs": 1,
        "noerr": 0,
        "x": 710,
        "y": 1080,
        "wires": [
            [
                "set-background-registros"
            ]
        ]
    },
    {
        "id": "set-background-inicio",
        "type": "ui-template",
        "z": "a6df4c391c658bbc",
        "group": "1eb81248916883dc",
        "page": "",
        "ui": "",
        "name": "Set Background Inicio",
        "order": 2,
        "width": 0,
        "height": 0,
        "format": "<style>\n.inicio #dashboard-root {\n    background-image: url('data:image/jpeg;base64,{{msg.payload}}');\n    background-size: cover;\n    background-position: center;\n    background-repeat: no-repeat;\n}\n</style>",
        "storeOutMessages": false,
        "passthru": true,
        "templateScope": "local",
        "className": "",
        "x": 980,
        "y": 1020,
        "wires": [
            []
        ]
    },
    {
        "id": "set-background-registros",
        "type": "ui-template",
        "z": "a6df4c391c658bbc",
        "group": "4fea4ef402f7f9de",
        "page": "",
        "ui": "",
        "name": "Set Background Registros",
        "order": 3,
        "width": 0,
        "height": 0,
        "format": "<style>\n.registros #dashboard-root {\n    background-image: url('data:image/jpeg;base64,{{msg.payload}}');\n    background-size: cover;\n    background-position: center;\n    background-repeat: no-repeat;\n}\n</style>",
        "storeOutMessages": false,
        "passthru": true,
        "templateScope": "local",
        "className": "",
        "x": 990,
        "y": 1080,
        "wires": [
            []
        ]
    },
    {
        "id": "1eb81248916883dc",
        "type": "ui-group",
        "name": "Group 1",
        "page": "666d17ce4d703f44",
        "width": "6",
        "height": "1",
        "order": 1,
        "showTitle": false,
        "className": "",
        "visible": true,
        "disabled": false
    },
    {
        "id": "4fea4ef402f7f9de",
        "type": "ui-group",
        "name": "Escrituras",
        "page": "a31827662386e738",
        "width": 6,
        "height": "1",
        "order": 2,
        "showTitle": true,
        "className": "",
        "visible": true,
        "disabled": false
    },
    {
        "id": "666d17ce4d703f44",
        "type": "ui-page",
        "name": "Inicio",
        "ui": "e8131e089dc51482",
        "path": "/inicio",
        "icon": "dashboard",
        "layout": "grid",
        "theme": "f8ed03d03ad5243c",
        "breakpoints": [
            {
                "name": "Default",
                "px": "0",
                "cols": "3"
            },
            {
                "name": "Tablet",
                "px": "576",
                "cols": "6"
            },
            {
                "name": "Small Desktop",
                "px": "768",
                "cols": "9"
            },
            {
                "name": "Desktop",
                "px": "1024",
                "cols": "12"
            }
        ],
        "order": 1,
        "className": "inicio",
        "visible": "true",
        "disabled": "false"
    },
    {
        "id": "a31827662386e738",
        "type": "ui-page",
        "name": "Registros",
        "ui": "e8131e089dc51482",
        "path": "/registros",
        "icon": "error_outline",
        "layout": "grid",
        "theme": "f8ed03d03ad5243c",
        "breakpoints": [
            {
                "name": "Default",
                "px": "0",
                "cols": "3"
            },
            {
                "name": "Tablet",
                "px": "576",
                "cols": "6"
            },
            {
                "name": "Small Desktop",
                "px": "768",
                "cols": "9"
            },
            {
                "name": "Desktop",
                "px": "1024",
                "cols": "12"
            }
        ],
        "order": 12,
        "className": "registros",
        "visible": "true",
        "disabled": "false"
    },
    {
        "id": "e8131e089dc51482",
        "type": "ui-base",
        "name": "My Dashboard",
        "path": "/dashboard",
        "appIcon": "",
        "includeClientData": true,
        "acceptsClientConfig": [
            "ui-notification",
            "ui-control"
        ],
        "showPathInSidebar": false,
        "headerContent": "page",
        "navigationStyle": "default",
        "titleBarStyle": "default",
        "showReconnectNotification": true,
        "notificationDisplayTime": 5,
        "showDisconnectNotification": true
    },
    {
        "id": "f8ed03d03ad5243c",
        "type": "ui-theme",
        "name": "Mi tema",
        "colors": {
            "surface": "#ffffff",
            "primary": "#0094ce",
            "bgPage": "#eeeeee",
            "groupBg": "#ffffff",
            "groupOutline": "#cccccc"
        },
        "sizes": {
            "density": "compact",
            "pagePadding": "0px",
            "groupGap": "0px",
            "groupBorderRadius": "0px",
            "widgetGap": "0px"
        }
    }
]```

I've haven't been able to get it to work either. The Dashboard 2.0 docs even have an example here.

Dashboard 2.0 Background Image

I would love to see someone get this working.

1 Like

It works for me. Import this template and deploy.

[{"id":"dea7518b69bf48a9","type":"ui-template","z":"7cfea54947ff318f","group":"","page":"","ui":"ID-BASE-1","name":"","order":0,"width":0,"height":0,"head":"","format":".v-main {\n    background-image: url(\"\thttps://www.transparenttextures.com/patterns/batthern.png\");\n    background-repeat: repeat;\n}","storeOutMessages":true,"passthru":true,"resendOnRefresh":true,"templateScope":"site:style","className":"","x":410,"y":760,"wires":[[]]},{"id":"ID-BASE-1","type":"ui-base","name":"Dashboard","path":"/dashboard","includeClientData":true,"acceptsClientConfig":["ui-control","ui-notification","ui-gauge-classic"],"titleBarStyle":"default"}]

Works for me for a while :wink:

and here full background from example

I should have clarified, like the OP, I'm trying to host it locally. I can also load an image hosted on the web, but I'd prefer the Dashboard not lose its background if the connection is lost.

And since I'm throwing out wish list items, I'd REALLY prefer that I be able to host the image inside of a project, not just in the Node-Red root. Ideally, I could load up a project on any NR instance and have everything needed for a functional dashboard.

You can simply serve your own image using httpstatic or create an endpoint using http-in -> read file -> http-response (there are examples in the cookbook)

What I always do to keep my web resources (images etc.) self-contained and not rely on external connectivity, is to specify one or more local httpStatic hosting roots in settings.js, and load from there.
For example, in settings.js define something like:

httpStatic:[ {path:"C:/ProgramData/Node-red/WebRoot", root:"assets"} ]

then refer to it as

/assets/images/pic1.jpg

You should not use the dashboard's native dist location as it gets wiped out upon dashboard version upgrades

just replace

background-image: url('/subfolder/images/img.jpg');

you cannot "just" specify a subfolder

It has to be served (either by http-in~http-response nodes or httpStatic setting)

@omrid provided a working example of httpStatic. The cookbook has examples of using http-in/response nodes for doing it via your flows.

yes @Steve-Mcl , absolutely correct, I had the httpstatic setting for a while and forgot it .. it just woked :slight_smile:

Do you have a solution to load/change dynamically during runtime?

To you really mean "at runtime" or do you mean via updating the flows in Node-RED editor without modifying settings httpStatic?

You could of course create an endpoint (http-in ~ http-response) that accepts all url paths then you use code/flows to parse the path, check it against some dynamic context or database variable, if it matches your dynamic path then retrieve the file requested and serve it but - it i struggle to see a fitting use case. I could certainly understand if you want to serve a directory based on a static value (like an env var - which is also possible)

If on the other hand you mean in the node-red editor (without having to modify settings file) then again yes, just add more endpoints.

Thanks to all. With your suggestions I made it work: using httpstatic and two template node type CSS (Single Page) containing

.v-main {
    background-image: url("/image.jpg") !important;
    background-size: contain !important;
    background-position: center !important;
    background-repeat: no-repeat !important;
    background-attachment: fixed !important;
}