@gemini86/node-red-contrib-chart-image issue with font

I'm using the module node-red-contrib-chart-image from @gemini86 . The charts are rendered correctly except for any text (scales, data labels, title, etc). Instead, rectangular symbols are show. This seems to indicate that a font is missing. I've tried using different font families in the chart options with no change in behavior. I've also tried creating a chart (chart.js) in a template node to see if the same behavior occurs. In this case the text renders without issue.

I'm seeing other posts with similar issues that have required installing fonts on the OS. Unfortunately I am using a pre-packaged version of Node-RED on an embedded system and don't have easy access to the underlying operating system. Is there a different way of accessing the correct font? And why does a normal chart with chart.js render text correctly but this module does not?

I'm using Node-RED version 4.0.9.

Welcome to the forum @bdkautzman

Are you using node-red-contrib-chart-image or @gemini86/node-red-contrib-chart-image. Check in Manage Palette to find out. According the readme the original one has been superseded by the latter.

Hello Collin, thank you for the welcome.

I am using @gemini86/node-red-contrib-chart-image.

So is it this issue you are seeing? Fonts missing · Issue #7 · gemini86/node-red-contrib-chart-image · GitHub

Yes, or this one is the same as well.

I think you will have to find out how to get the fonts installed on your system. Or possibly contact the node's author and ask if there is a way to specify a basic font.

@gemini86 Any feedback on this topic?

Hello,

This seems to be limitation of chartjs-node-canvas, or at least node-canvas in general. Your browser is able to pull in many fonts that are not on your system, but canvas is using a headless renderer which is dependent on system fonts being installed.

When I can find time I will work to see if there is a work-around, maybe passing the fonts in as a plugin?

Can you tell me what font you're trying to use so I may test? an example flow would help.

Ahh, I see. The headless rendering was the piece I was missing. That makes complete sense now why chart.js works without issue. I was hoping this was something simple that I was doing incorrectly, but it sounds like the environment I have Node-RED deployed in will cause more issues that I anticipated. I will investigate whether there is a different way for me to load fonts.

The flow I was testing with is based on your annotation example, which doesn't specify a font. I have also tried to set the font family options to Helevetica Neue, Helvetica, Arial and sans-serif.

Unfortunately I'm too new for attachments, so I will have to paste the json below.

Thank you for your work on this module, it is appreciated!

[
    {
        "id": "257416e5d7b66760",
        "type": "inject",
        "z": "8c3415e03fc5e694",
        "name": "",
        "props": [
            {
                "p": "payload"
            },
            {
                "p": "topic",
                "vt": "str"
            }
        ],
        "repeat": "",
        "crontab": "",
        "once": false,
        "onceDelay": 0.1,
        "topic": "",
        "payload": "",
        "payloadType": "date",
        "x": 290,
        "y": 120,
        "wires": [
            [
                "777fec3be9a48f28"
            ]
        ]
    },
    {
        "id": "777fec3be9a48f28",
        "type": "function",
        "z": "8c3415e03fc5e694",
        "name": "example",
        "func": "msg.payload = {\n    type: 'bar',\n    data: {\n        labels: ['Jan', 'Feb', 'Mar'],\n        datasets: [{\n            label: 'Sales',\n            data: [12, 19, 15]\n        }]\n    },\n    options: {\n        plugins: {\n            annotation: {\n                annotations: {\n                    myImportantLine: {\n                        type: 'line',\n                        yMin: 15,\n                        yMax: 15,\n                        borderColor: 'red',\n                        borderWidth: 2,\n                        scaleID: 'y'\n                    }\n                }\n            }\n        }\n    }\n};\nreturn msg;\n",
        "outputs": 1,
        "timeout": 0,
        "noerr": 0,
        "initialize": "",
        "finalize": "",
        "libs": [],
        "x": 480,
        "y": 120,
        "wires": [
            [
                "58a9581123964cd3"
            ]
        ]
    },
    {
        "id": "58a9581123964cd3",
        "type": "chart-image",
        "z": "8c3415e03fc5e694",
        "name": "",
        "width": "",
        "height": "",
        "debug": false,
        "x": 670,
        "y": 120,
        "wires": [
            [
                "8625cca462f380c2"
            ]
        ]
    },
    {
        "id": "8625cca462f380c2",
        "type": "function",
        "z": "8c3415e03fc5e694",
        "name": "function 8",
        "func": "const buffer = msg.payload;\nmsg.payload = buffer.toString('base64');\n// global.set(\"ChartBuffer\", msg.payload);\nreturn msg;",
        "outputs": 1,
        "timeout": 0,
        "noerr": 0,
        "initialize": "",
        "finalize": "",
        "libs": [],
        "x": 860,
        "y": 120,
        "wires": [
            [
                "be712014751d5d66"
            ]
        ]
    },
    {
        "id": "be712014751d5d66",
        "type": "ui_template",
        "z": "8c3415e03fc5e694",
        "group": "7c014f53d28beb23",
        "name": "",
        "order": 0,
        "width": "4",
        "height": "4",
        "format": "<img src=\"data:image/jpeg;base64,{{msg.payload}}\" style=\"max-width: 50%; height: auto;\">",
        "storeOutMessages": true,
        "fwdInMessages": true,
        "resendOnRefresh": true,
        "templateScope": "local",
        "className": "",
        "x": 1040,
        "y": 120,
        "wires": [
            []
        ]
    },
    {
        "id": "7c014f53d28beb23",
        "type": "ui_group",
        "name": "chart-image",
        "tab": "2fc1ffece0d082f3",
        "order": 1,
        "disp": true,
        "width": 20,
        "collapse": false,
        "className": ""
    },
    {
        "id": "2fc1ffece0d082f3",
        "type": "ui_tab",
        "name": "Home",
        "icon": "dashboard",
        "disabled": false,
        "hidden": false
    }
]

That is the recommended way of posting flows unless they are very large :slight_smile:
It makes it very easy to copy to clipboard and Import into node red.

1 Like

oh, gotcha... those are not open fonts, they're commercial. Not likely to find them on any embedded system. What's weird is that it's not resorting to a fallback.

So to make sure I'm clearly understanding your issue; using just the node with supplied examples on an embedded system, you're not able to see any text rendering? Can I ask what device you're using?

Yes, that is correct. I'm using a product from Bosch Rexroth called a ctrlX Core. It's based on Ubuntu Core. They provide a Linux snap version of Node-RED. Access to the underlying Ubuntu OS is limited, which is why I'm unable to directly install the relevant font packages.

so, I hate to be THAT guy and ask, why are you trying to do this with your PLC? are you trying to just use chartJS in a dashboard? If so, I'd use the template node or the ui-chart node- as that is what they're for. My node is useful for embedding a render of a chart within an email or pdf file or something that needs to be rendered server-side. If you're trying to display data on a dashboard, let the client browser do the rendering, which is what the dashboard template is good at.

Haha, no need to apologize for being THAT guy. I think anyone who develops something for free gains that right.

To answer your question, I am intending to embed this chart within a PDF that I email to a user. This is meant to be an example of production data or machine diagnostic information that is sent on command or at a certain time. The data collection, PDF generation and email functionality is already set up.

I had considered using a different module/method to embed a chart as HTML in the email, but I thought a PDF report was a cleaner approach that mirrored what a 'true' production report would look like.

I am aware that the template/ui-chart nodes are better examples for a dashboard. I used a template node with Chart.js to confirm fonts were rendering correctly with the default chart configuration.

yeah that's something I built this for specifically, but I would not have a PLC generating charts and PDFs. I strongly recommend offloading this task to another edge device that lives with the PLC (raspberry pi based, I like sfera labs for this), or move it entirely into the OT sphere, which is much more common. Factory floor (PLC --> edge data collection (if serial or other data conversion is needed) --> operation technology layer (web apps that collect aggregate data, generate reports). If you're not collecting all that much, you can use one RPI to collect the data from the PLC and present a web interface to view/manage reports.

Again, awesome that you're using your machine data, but don't have the machine directly report to the user, segment those secondary tasks to protect your PLC from weird failures or worse- cyber attacks.