eChart: how can I make the tooltip visible?

I have managed to create an echart with the template node. However, i am not able to display the tooltip with the legend. Can anybody help?
Here my node:

[
    {
        "id": "c4f7b79d0d16995b",
        "type": "ui-template",
        "z": "1c6c6bc511cd2d54",
        "group": "459ee3e2b7fa9235",
        "page": "",
        "ui": "",
        "name": "",
        "order": 1,
        "width": "6",
        "height": "6",
        "head": "",
        "format": "<template>\n    <div ref=\"charttpw\" style=\"width: 500px; height: 400px\" id=\"chart-container\"></div>\n</template>\n\n<script type=\"text/javascript\" src=\"https://fastly.jsdelivr.net/npm/echarts@5.4.3/dist/echarts.min.js\"></script>\n<!-- <script type=\"text/javascript\" src=\"http://debiancloud:8090/f/524\"></script> -->\n<style lang=\"css\">\n    .chart-container {\n        width: 100%;\n        height: auto;\n    }\n</style>\n<script>\n    //import * as echarts from 'echarts';\n    export default {\n        data() {\n            return {\n                myChart: null\n            }\n        },\n        watch: {\n            msg: function () {\n            // check if echart is already instantiated\n            let interval = setInterval(()=>{\n                if(this.myChart){\n                    clearInterval(interval)\n                    // if (this.msg.topic === \"data\") {\n                    //     this.update(this.msg.payload.labels, this.msg.payload.Temp_series, this.msg.payload.RH_series, this.msg.payload.title)\n                    // }            \n                    }\n                },200);\n            }\n        },\n        mounted() {\n                this.etheme = {\n                \"version\": 1,\n                \"themeName\": \"shine\",\n                \"theme\": {\n                \"seriesCnt\": \"4\",\n                \"backgroundColor\": \"rgba(0,0,0,0)\",\n                \"titleColor\": \"#333333\",\n                \"subtitleColor\": \"#aaa\",\n                \"textColorShow\": false,\n                \"textColor\": \"#333\",\n                \"markTextColor\": \"#eee\",\n                \"color\": [\n                \"#c12e34\",\n                \"#e6b600\",\n                \"#0098d9\",\n                \"#2b821d\",\n                \"#005eaa\",\n                \"#339ca8\",\n                \"#cda819\",\n                \"#32a487\"\n                ],\n                \"borderColor\": \"#ccc\",\n                \"borderWidth\": 0,\n                \"visualMapColor\": [\n                \"#1790cf\",\n                \"#a2d4e6\"\n                ],\n                \"legendTextColor\": \"#333333\",\n                \"kColor\": \"#c12e34\",\n                \"kColor0\": \"#2b821d\",\n                \"kBorderColor\": \"#c12e34\",\n                \"kBorderColor0\": \"#2b821d\",\n                \"kBorderWidth\": 1,\n                \"lineWidth\": 2,\n                \"symbolSize\": 4,\n                \"symbol\": \"emptyCircle\",\n                \"symbolBorderWidth\": 1,\n                \"lineSmooth\": false,\n                \"graphLineWidth\": 1,\n                \"graphLineColor\": \"#aaa\",\n                \"mapLabelColor\": \"#c12e34\",\n                \"mapLabelColorE\": \"#c12e34\",\n                \"mapBorderColor\": \"#eee\",\n                \"mapBorderColorE\": \"#ddd\",\n                \"mapBorderWidth\": 0.5,\n                \"mapBorderWidthE\": 1,\n                \"mapAreaColor\": \"#ddd\",\n                \"mapAreaColorE\": \"#e6b600\",\n                \"axes\": [\n                {\n                \"type\": \"all\",\n                \"name\": \"myAxis\",\n                \"axisLineShow\": true,\n                \"axisLineColor\": \"#333\",\n                \"axisTickShow\": true,\n                \"axisTickColor\": \"#333\",\n                \"axisLabelShow\": true,\n                \"axisLabelColor\": \"#333\",\n                \"splitLineShow\": true,\n                \"splitLineColor\": [\n                \"#ccc\"\n                ],\n                \"splitAreaShow\": false,\n                \"splitAreaColor\": [\n                \"rgba(250,250,250,0.3)\",\n                \"rgba(200,200,200,0.3)\"\n                ]\n                }\n                ],\n                \"axisSeperateSetting\": true,\n                \"toolboxColor\": \"#06467c\",\n                \"toolboxEmphasisColor\": \"#4187c2\",\n                \"tooltipAxisColor\": \"#cccccc\",\n                \"tooltipAxisWidth\": 1,\n                \"timelineLineColor\": \"#005eaa\",\n                \"timelineLineWidth\": 1,\n                \"timelineItemColor\": \"#005eaa\",\n                \"timelineItemColorE\": \"#005eaa\",\n                \"timelineCheckColor\": \"#005eaa\",\n                \"timelineCheckBorderColor\": \"rgba(49,107,194,0.5)\",\n                \"timelineItemBorderWidth\": 1,\n                \"timelineControlColor\": \"#005eaa\",\n                \"timelineControlBorderColor\": \"#005eaa\",\n                \"timelineControlBorderWidth\": 0.5,\n                \"timelineLabelColor\": \"#005eaa\",\n                \"gridLeft\": \"10%\",\n                \"gridRight\": \"10%\",\n                \"gridTop\": 60,\n                \"gridBottom\": 70,\n                \"legendLeft\": \"center\",\n                \"legendRight\": \"\",\n                \"legendTop\": 0,\n                \"legendBottom\": \"\"\n                \n                }\n                }\n            let interval = setInterval(() => {\n                const el = this.$refs.charttpw\n                if (el && typeof echarts !== \"undefined\") {\n                    clearInterval(interval);\n                    // now it is loaded, we can initialise and use it\n                    this.init();\n                }\n            }, 200);\n        },\n        methods: {\n            init: function () {\n                this.myChart = echarts.init(this.$refs.charttpw, this.etheme);\n                if (!this.myChart) {\n                    console.error(\"echarts not initialized\");\n                    return;\n                }\n                // dummy / test data\n                const labels = ['07:00', '08:00', '09:00', '10:00', '11:00', '12:00'];\n                const data_temp = [15, 15.5, 16, 20, 18, 17];\n                const data_rh = [55, 75, 80, 85, 70, 72];\n                const title = \"\";\n                const data_ppm = [800, 750, 800, 850, 610, 620];\n                this.update(labels, data_temp, data_rh, data_ppm, title);\n                \n            },\n            update: function (xAxisData, data_temp, data_rh, data_ppm, title) {\n                this.myChart.setOption({\n                    title: {\n                        text: title,\n                    },\n                    tooltip: {\n                        show: true,\n                        trigger: \"axis\",\n                    },\n                    legend: {\n                        data: ['Temperatur', 'RH in %', 'PPM']\n                    },                    \n                    grid: {\n                        left: \"3%\",\n                        right: \"4%\",\n                        //top: '30%',\n                        containLabel: true,\n                    },\n                    xAxis: {\n                        type: \"category\",\n                        boundaryGap: false,\n                        data: xAxisData,\n                    },\n                    yAxis: [\n                        {\n                            type: \"value\",\n                            name: \"Temperature\",\n                            min: 10,\n                            splitLine:{\n                                show:true,\n                            },\n                            axisLabel: {\n                                formatter: \"{value}°C\",\n                            },\n                            axisLine:{\n                                show:true,\n                                lineStyle: {\n                                    color: this.etheme.theme.color[2],\n                                }\n                            },\n                            axisPointer: {\n                                snap: true,\n                            },\n                        },\n                        {\n                            type: \"value\",\n                            name: \"Humidity\",\n                            position: 'right',\n                            splitLine:{show:false,\n                            },\n                            axisLine: {\n                                show: true,\n                            },\n                            axisTick: {\n                                show: true,\n                            },\n                            min: 40,\n                        },\n                        {\n                            type: \"value\",\n                            name: \"ppm\",\n                            splitLine:{\n                                show:false,\n                            },\n                            nameGap: 15,\n                            nameMoveOverlap: true,\n                            position: 'right',\n                            offset: 45,\n                            axisLine: {\n                                show: true,\n                                lineStyle: {\n                                    color: this.etheme.theme.color[1]\n                                },                            \n                            },\n                            axisTick: {\n                                show: true,\n                            },\n                            min: 400,\n                        }                    \n                      ],\n                    series: [\n                        {\n                        name: \"Temperatur\",\n                        type: \"line\",\n                        smooth: true,\n                        showSymbol: true,\n                        data: data_temp,\n                        yAxisIndex: 0,\n                        symbolSize: 2,\n                        tooltip: {\n                            valueFormatter: '{value} °C',\n                        },\n                        lineStyle: {\n                            width: 1,\n                            }\n                        },\n                        {\n                        name: \"RH in %\",\n                        type: \"line\",\n                        smooth: true,\n                        showSymbol: true,\n                        symbolSize: 2,\n                        splitLine: {\n                            show: false,\n                        lineStyle: {\n                            width: 1,\n                            }\n                        },\n                        data: data_rh,\n                        yAxisIndex: 1,\n                        },\n                        {\n                        name: \"PPM\",\n                        type: \"line\",\n                        smooth: true,\n                        showSymbol: true,\n                        symbolSize: 2,\n                        data: data_ppm,\n                        yAxisIndex: 2,\n                        }                                        \n                      ],\n                });\n            }\n        }\n    }\n</script>",
        "storeOutMessages": true,
        "passthru": true,
        "resendOnRefresh": true,
        "templateScope": "local",
        "className": "",
        "x": 560,
        "y": 520,
        "wires": [
            []
        ]
    },
    {
        "id": "459ee3e2b7fa9235",
        "type": "ui-group",
        "name": "Klimadaten",
        "page": "b1366025f77b8dd4",
        "width": 6,
        "height": 1,
        "order": 1,
        "showTitle": true,
        "className": "",
        "visible": "true",
        "disabled": "false",
        "groupType": "default"
    },
    {
        "id": "b1366025f77b8dd4",
        "type": "ui-page",
        "name": "Seite 1",
        "ui": "6a50f35f2ffe099b",
        "path": "/page1",
        "icon": "home",
        "layout": "grid",
        "theme": "dfda5a006f3f7e59",
        "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": 2,
        "className": "",
        "visible": "true",
        "disabled": "false"
    },
    {
        "id": "6a50f35f2ffe099b",
        "type": "ui-base",
        "name": "Mein Dashboard",
        "path": "/dashboard",
        "appIcon": "",
        "includeClientData": true,
        "acceptsClientConfig": [
            "ui-notification",
            "ui-control"
        ],
        "showPathInSidebar": false,
        "headerContent": "page",
        "navigationStyle": "default",
        "titleBarStyle": "default",
        "showReconnectNotification": true,
        "notificationDisplayTime": 1,
        "showDisconnectNotification": true,
        "allowInstall": false
    },
    {
        "id": "dfda5a006f3f7e59",
        "type": "ui-theme",
        "name": "Standardthema",
        "colors": {
            "surface": "#ffffff",
            "primary": "#0094CE",
            "bgPage": "#eeeeee",
            "groupBg": "#ffffff",
            "groupOutline": "#cccccc"
        },
        "sizes": {
            "density": "default",
            "pagePadding": "12px",
            "groupGap": "12px",
            "groupBorderRadius": "4px",
            "widgetGap": "12px"
        }
    },
    {
        "id": "f8e370b5d5d6a457",
        "type": "global-config",
        "env": [],
        "modules": {
            "@flowfuse/node-red-dashboard": "1.30.0"
        }
    }
]

I am also looking for a way to use the colors from the theme within my chart, but where do the line colors actually come from? I want the Y-Axis lines in the same color.

At least for the tooltip, I may have a workaround.
I stumbled across the same problem some time ago. It cost me a night with Gemini.
I couldn't get EChart 3 axes and trigger "Axis" to work either. I then came up with a rather complex workaround and, luckily, had it documented :wink:
Maybe you can do something with it.
Markdown to PDF.pdf (98.2 KB)

[
    {
        "id": "c4f7b79d0d16995b",
        "type": "ui-template",
        "z": "bdbccae28956855e",
        "group": "459ee3e2b7fa9235",
        "page": "",
        "ui": "",
        "name": "",
        "order": 1,
        "width": "6",
        "height": "6",
        "head": "",
        "format": "<template>\n    <div ref=\"charttpw\" style=\"width: 500px; height: 400px; position: relative;\" id=\"chart-container\"></div>\n</template>\n\n<script type=\"text/javascript\" src=\"https://fastly.jsdelivr.net/npm/echarts@5.4.3/dist/echarts.min.js\"></script>\n<!-- <script type=\"text/javascript\" src=\"http://debiancloud:8090/f/524\"></script> -->\n<style lang=\"css\">\n    .chart-container {\n        width: 100%;\n        height: auto;\n    }\n</style>\n<script>\n    //import * as echarts from 'echarts';\n    export default {\n        data() {\n            return {\n                myChart: null,\n                chartData: {},\n                customTooltipDiv: null,\n                currentNearestValues: {},\n                currentCategory: '',\n                seriesOrder: ['temp', 'rh', 'ppm']\n            }\n        },\n        watch: {\n            msg: function () {\n            // check if echart is already instantiated\n            let interval = setInterval(()=>{\n                if(this.myChart){\n                    clearInterval(interval)\n                    // if (this.msg.topic === \"data\") {\n                    //     this.update(this.msg.payload.labels, this.msg.payload.Temp_series, this.msg.payload.RH_series, this.msg.payload.title)\n                    // }            \n                    }\n                },200);\n            }\n        },\n        mounted() {\n                this.etheme = {\n                \"version\": 1,\n                \"themeName\": \"shine\",\n                \"theme\": {\n                \"seriesCnt\": \"4\",\n                \"backgroundColor\": \"rgba(0,0,0,0)\",\n                \"titleColor\": \"#333333\",\n                \"subtitleColor\": \"#aaa\",\n                \"textColorShow\": false,\n                \"textColor\": \"#333\",\n                \"markTextColor\": \"#eee\",\n                \"color\": [\n                \"#c12e34\",\n                \"#e6b600\",\n                \"#0098d9\",\n                \"#2b821d\",\n                \"#005eaa\",\n                \"#339ca8\",\n                \"#cda819\",\n                \"#32a487\"\n                ],\n                \"borderColor\": \"#ccc\",\n                \"borderWidth\": 0,\n                \"visualMapColor\": [\n                \"#1790cf\",\n                \"#a2d4e6\"\n                ],\n                \"legendTextColor\": \"#333333\",\n                \"kColor\": \"#c12e34\",\n                \"kColor0\": \"#2b821d\",\n                \"kBorderColor\": \"#c12e34\",\n                \"kBorderColor0\": \"#2b821d\",\n                \"kBorderWidth\": 1,\n                \"lineWidth\": 2,\n                \"symbolSize\": 4,\n                \"symbol\": \"emptyCircle\",\n                \"symbolBorderWidth\": 1,\n                \"lineSmooth\": false,\n                \"graphLineWidth\": 1,\n                \"graphLineColor\": \"#aaa\",\n                \"mapLabelColor\": \"#c12e34\",\n                \"mapLabelColorE\": \"#c12e34\",\n                \"mapBorderColor\": \"#eee\",\n                \"mapBorderColorE\": \"#ddd\",\n                \"mapBorderWidth\": 0.5,\n                \"mapBorderWidthE\": 1,\n                \"mapAreaColor\": \"#ddd\",\n                \"mapAreaColorE\": \"#e6b600\",\n                \"axes\": [\n                {\n                \"type\": \"all\",\n                \"name\": \"myAxis\",\n                \"axisLineShow\": true,\n                \"axisLineColor\": \"#333\",\n                \"axisTickShow\": true,\n                \"axisTickColor\": \"#333\",\n                \"axisLabelShow\": true,\n                \"axisLabelColor\": \"#333\",\n                \"splitLineShow\": true,\n                \"splitLineColor\": [\n                \"#ccc\"\n                ],\n                \"splitAreaShow\": false,\n                \"splitAreaColor\": [\n                \"rgba(250,250,250,0.3)\",\n                \"rgba(200,200,200,0.3)\"\n                ]\n                }\n                ],\n                \"axisSeperateSetting\": true,\n                \"toolboxColor\": \"#06467c\",\n                \"toolboxEmphasisColor\": \"#4187c2\",\n                \"tooltipAxisColor\": \"#cccccc\",\n                \"tooltipAxisWidth\": 1,\n                \"timelineLineColor\": \"#005eaa\",\n                \"timelineLineWidth\": 1,\n                \"timelineItemColor\": \"#005eaa\",\n                \"timelineItemColorE\": \"#005eaa\",\n                \"timelineCheckColor\": \"#005eaa\",\n                \"timelineCheckBorderColor\": \"rgba(49,107,194,0.5)\",\n                \"timelineItemBorderWidth\": 1,\n                \"timelineControlColor\": \"#005eaa\",\n                \"timelineControlBorderColor\": \"#005eaa\",\n                \"timelineControlBorderWidth\": 0.5,\n                \"timelineLabelColor\": \"#005eaa\",\n                \"gridLeft\": \"10%\",\n                \"gridRight\": \"10%\",\n                \"gridTop\": 60,\n                \"gridBottom\": 70,\n                \"legendLeft\": \"center\",\n                \"legendRight\": \"\",\n                \"legendTop\": 0,\n                \"legendBottom\": \"\"\n                \n                }\n                }\n            let interval = setInterval(() => {\n                const el = this.$refs.charttpw\n                if (el && typeof echarts !== \"undefined\") {\n                    clearInterval(interval);\n                    // now it is loaded, we can initialise and use it\n                    this.init();\n                }\n            }, 200);\n        },\n        methods: {\n            init: function () {\n                this.myChart = echarts.init(this.$refs.charttpw, this.etheme);\n                if (!this.myChart) {\n                    console.error(\"echarts not initialized\");\n                    return;\n                }\n                \n                // Initialize Custom Tooltip\n                this.createCustomTooltip();\n\n                // dummy / test data\n                const labels = ['07:00', '08:00', '09:00', '10:00', '11:00', '12:00'];\n                const data_temp = [15, 15.5, 16, 20, 18, 17];\n                const data_rh = [55, 75, 80, 85, 70, 72];\n                const title = \"\";\n                const data_ppm = [800, 750, 800, 850, 610, 620];\n                this.update(labels, data_temp, data_rh, data_ppm, title);\n                \n            },\n            createCustomTooltip() {\n                this.customTooltipDiv = document.createElement('div');\n                this.customTooltipDiv.style.cssText = `\n                    position: absolute;\n                    display: none;\n                    background-color: rgba(50, 50, 50, 0.9);\n                    border: 1px solid #333;\n                    padding: 10px;\n                    border-radius: 4px;\n                    color: #fff;\n                    font-size: 12px;\n                    pointer-events: none;\n                    z-index: 9999;\n                    max-width: 300px;\n                    box-shadow: 0 2px 8px rgba(0,0,0,0.3);\n                `;\n                this.$refs.charttpw.appendChild(this.customTooltipDiv);\n                \n                let updateTimeout = null;\n                this.myChart.getZr().on('mousemove', (params) => {\n                    const pointInPixel = [params.offsetX, params.offsetY];\n                    if (this.myChart.containPixel('grid', pointInPixel)) {\n                        if (updateTimeout) clearTimeout(updateTimeout);\n                        updateTimeout = setTimeout(() => {\n                            this.updateCustomTooltip(params.offsetX, params.offsetY);\n                        }, 50);\n                    } else {\n                        if (updateTimeout) clearTimeout(updateTimeout);\n                        this.customTooltipDiv.style.display = 'none';\n                    }\n                });\n            },\n            updateCustomTooltip(x, y) {\n                console.log('updateCustomTooltip called', this.currentNearestValues);\n                if (!this.currentNearestValues || Object.keys(this.currentNearestValues).length === 0) {\n                     console.log('No values to show');\n                     return;\n                }\n                \n                this.customTooltipDiv.innerHTML = this.buildTooltipHTML(this.currentCategory, this.currentNearestValues);\n                this.customTooltipDiv.style.display = 'block';\n                this.positionTooltip(x, y);\n            },\n            buildTooltipHTML(category, values) {\n                // ... same implementation ...\n                let html = `<div style=\"font-weight: bold; margin-bottom: 8px; font-size: 13px;\">\n                    ${category}\n                </div>`;\n                \n                const orderedTopics = this.seriesOrder.filter(topic => values[topic]);\n                \n                orderedTopics.forEach(topic => {\n                    const item = values[topic];\n                    html += `<div style=\"line-height: 20px;\">\n                    <span style=\"display: inline-block; width: 10px; height: 10px; \n                                background-color: ${item.color}; border-radius: 50%; \n                                margin-right: 5px;\"></span>\n                    <span style=\"color: #ddd;\">${item.label}:</span>\n                    <span style=\"font-weight: bold; margin-left: 5px;\">\n                        ${item.value} ${item.unit}\n                    </span>\n                    </div>`;\n                });\n                \n                return html;\n            },\n            positionTooltip(mouseX, mouseY) {\n                // ... same implementation ...\n                requestAnimationFrame(() => {\n                    const chartRect = this.$refs.charttpw.getBoundingClientRect();\n                    const tooltipWidth = this.customTooltipDiv.offsetWidth;\n                    const tooltipHeight = this.customTooltipDiv.offsetHeight;\n                    \n                    // Horizontal: Left or right of the mouse\n                    let left = mouseX < chartRect.width / 2 \n                    ? Math.min(mouseX + 20, chartRect.width - tooltipWidth - 10)  // Right\n                    : Math.max(mouseX - tooltipWidth - 20, 10);                   // Left\n                    \n                    // Vertical: Centered, but within visible area\n                    let top = Math.max(10, Math.min(mouseY - tooltipHeight / 2, \n                                                    chartRect.height - tooltipHeight - 10));\n                    \n                    this.customTooltipDiv.style.left = left + 'px';\n                    this.customTooltipDiv.style.top = top + 'px';\n                });\n            },\n            update: function (xAxisData, data_temp, data_rh, data_ppm, title) {\n                // Save data for tooltip\n                this.chartData = {\n                    xAxis: xAxisData,\n                    temp: data_temp,\n                    rh: data_rh,\n                    ppm: data_ppm\n                };\n                \n                this.myChart.setOption({\n                    title: {\n                        text: title,\n                    },\n                    tooltip: {\n                        show: true,\n                        trigger: \"axis\",\n                        formatter: function() { return ''; }, // Hide default tooltip content\n                        backgroundColor: 'rgba(0,0,0,0)', // Transparent background\n                        borderColor: 'rgba(0,0,0,0)', // Transparent border\n                        textStyle: { color: 'rgba(0,0,0,0)' } // Transparent text\n                    },\n                    axisPointer: {\n                        link: [{ xAxisIndex: \"all\" }],\n                        label: {\n                            show: true,\n                            formatter: (params) => {\n                                console.log('Formatter called', params);\n                                if (params.axisDimension === \"x\" && this.chartData.xAxis) {\n                                    const category = params.value;\n                                    const index = this.chartData.xAxis.indexOf(category);\n                                    \n                                    if (index !== -1) {\n                                        this.currentNearestValues = {\n                                            temp: { value: this.chartData.temp[index], unit: '°C', color: this.etheme.theme.color[0], label: 'Temperatur' },\n                                            rh: { value: this.chartData.rh[index], unit: '%', color: this.etheme.theme.color[1], label: 'RH in %' },\n                                            ppm: { value: this.chartData.ppm[index], unit: 'ppm', color: this.etheme.theme.color[2], label: 'PPM' }\n                                        };\n                                        this.currentCategory = category;\n                                        console.log('Values updated', this.currentNearestValues);\n                                    }\n                                    return \"\";\n                                }\n                                return null;\n                            },\n                            backgroundColor: \"transparent\",\n                            borderColor: \"transparent\",\n                            color: \"transparent\",\n                        }\n                    },\n                    legend: {\n                        data: ['Temperatur', 'RH in %', 'PPM']\n                    },                    \n                    grid: {\n                        left: \"3%\",\n                        right: \"4%\",\n                        containLabel: true,\n                    },\n                    xAxis: {\n                        type: \"category\",\n                        boundaryGap: false,\n                        data: xAxisData,\n                        axisPointer: {\n                            show: true\n                        }\n                    },\n                    yAxis: [\n                        {\n                            type: \"value\",\n                            name: \"Temperature\",\n                            min: 10,\n                            splitLine:{\n                                show:true,\n                            },\n                            axisLabel: {\n                                formatter: \"{value}°C\",\n                            },\n                            axisLine:{\n                                show:true,\n                                lineStyle: {\n                                    color: this.etheme.theme.color[2],\n                                }\n                            },\n                            axisPointer: {\n                                snap: true,\n                            },\n                        },\n                        {\n                            type: \"value\",\n                            name: \"Humidity\",\n                            position: 'right',\n                            splitLine:{show:false,\n                            },\n                            axisLine: {\n                                show: true,\n                            },\n                            axisTick: {\n                                show: true,\n                            },\n                            min: 40,\n                        },\n                        {\n                            type: \"value\",\n                            name: \"ppm\",\n                            splitLine:{\n                                show:false,\n                            },\n                            nameGap: 15,\n                            nameMoveOverlap: true,\n                            position: 'right',\n                            offset: 45,\n                            axisLine: {\n                                show: true,\n                                lineStyle: {\n                                    color: this.etheme.theme.color[1]\n                                },                            \n                            },\n                            axisTick: {\n                                show: true,\n                            },\n                            min: 400,\n                        }                    \n                      ],\n                    series: [\n                        {\n                        name: \"Temperatur\",\n                        type: \"line\",\n                        smooth: true,\n                        showSymbol: true,\n                        data: data_temp,\n                        yAxisIndex: 0,\n                        symbolSize: 2,\n                        tooltip: {\n                            valueFormatter: '{value} °C',\n                        },\n                        lineStyle: {\n                            width: 1,\n                            }\n                        },\n                        {\n                        name: \"RH in %\",\n                        type: \"line\",\n                        smooth: true,\n                        showSymbol: true,\n                        symbolSize: 2,\n                        splitLine: {\n                            show: false,\n                        lineStyle: {\n                            width: 1,\n                            }\n                        },\n                        data: data_rh,\n                        yAxisIndex: 1,\n                        },\n                        {\n                        name: \"PPM\",\n                        type: \"line\",\n                        smooth: true,\n                        showSymbol: true,\n                        symbolSize: 2,\n                        data: data_ppm,\n                        yAxisIndex: 2,\n                        }                                        \n                      ],\n                });\n            }\n        }\n    }\n</script>",
        "storeOutMessages": true,
        "passthru": true,
        "resendOnRefresh": true,
        "templateScope": "local",
        "className": "",
        "x": 400,
        "y": 160,
        "wires": [
            []
        ]
    },
    {
        "id": "459ee3e2b7fa9235",
        "type": "ui-group",
        "name": "Klimadaten",
        "page": "b1366025f77b8dd4",
        "width": 6,
        "height": 1,
        "order": 1,
        "showTitle": true,
        "className": "",
        "visible": "true",
        "disabled": "false",
        "groupType": "default"
    },
    {
        "id": "b1366025f77b8dd4",
        "type": "ui-page",
        "name": "Seite 1",
        "ui": "6a50f35f2ffe099b",
        "path": "/page1",
        "icon": "home",
        "layout": "grid",
        "theme": "dfda5a006f3f7e59",
        "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": "",
        "visible": "true",
        "disabled": "false"
    },
    {
        "id": "6a50f35f2ffe099b",
        "type": "ui-base",
        "name": "Mein Dashboard",
        "path": "/dashboard",
        "appIcon": "",
        "includeClientData": true,
        "acceptsClientConfig": [
            "ui-notification",
            "ui-control"
        ],
        "showPathInSidebar": false,
        "headerContent": "page",
        "navigationStyle": "default",
        "titleBarStyle": "default",
        "showReconnectNotification": true,
        "notificationDisplayTime": 1,
        "showDisconnectNotification": true,
        "allowInstall": false
    },
    {
        "id": "dfda5a006f3f7e59",
        "type": "ui-theme",
        "name": "Standardthema",
        "colors": {
            "surface": "#ffffff",
            "primary": "#0094CE",
            "bgPage": "#eeeeee",
            "groupBg": "#ffffff",
            "groupOutline": "#cccccc"
        },
        "sizes": {
            "density": "default",
            "pagePadding": "12px",
            "groupGap": "12px",
            "groupBorderRadius": "4px",
            "widgetGap": "12px"
        }
    },
    {
        "id": "11a64c107b8911be",
        "type": "global-config",
        "env": [],
        "modules": {
            "@flowfuse/node-red-dashboard": "1.30.1"
        }
    }
]

These are some of the methods I use with the eChart tooltip. They come from what I have tried and found work, there are undoubtedly many other ways of achieving the same effect.

The first line of the tooltip comes from the xAxis, the second from the option tooltip or series tooltip (or just the series name)

				option = {
		  			tooltip: { 	
						trigger: 'axis',

						axisPointer: {
      						type: 'none',									// Other possible types are 'line', 'shadow' & 'cross'
      						snap: true,
    					},

					},

		  			xAxis: {
						type: 'category',
						
    					// This is a label on the axis line
						axisPointer: {
							snap: true,
							label: {
        						show: false,								// Do not show label on axis line
        						// Format the tooltip first line. 
								// Show the weather synopsis.
								formatter: function(params) {
          										// The weather description is in the data of series 0
												return params.value + 'hrs ' +  params.seriesData[0].data.weather
        									},
      						},

      					},
						
						
					},
					
		  			series: [
						{
							name: 'Temperature',                  			// Used in the the 'tooltip'
							type: 'line',
							symbol: 'none',                     			// Shape of data point on graph
							animation: false,

							itemStyle: {									// Chart line colour
      							color: this.itemColours[0],
							
							},
																		
      						tooltip: {
        						valueFormatter: function (value) {
          							return value.toFixed(1) + '°C'

        						}

							},

							data: [],
	
		  				},
						
					],
					
				}

This also works with a single chart series

				option = {

		  			tooltip: { 
							trigger: 'axis',
							valueFormatter: (value) => this.formatToolTip(value),

							axisPointer: {
      							type: "none",
      							snap: true,
    						},
								
						},
					},
					
		  			xAxis: {
						type: 'time',
	
    					axisPointer: {
							snap: true,
							label: {
        						show: false,
        						formatter: function(params) {
          										return 'Time: ' + echarts.format.formatTime('hh:mm', params.value)
        									}
      						},

      					},
						
					},
					
				},

and you can omit anything tooltip related other than the tooltip section and just use a series name. The colour of the series line (and therefore the tooltip circle colour) can be defined in the series section


		  			series: [{
						name: this.seriesName,                  		// Used in the the 'tooltip'
						type: 'bar',
						symbol: 'none',                     			// Shape of data point on graph
						animation: false,

						itemStyle: {
      						color: this.barColour[this.barColourNumber],
							
						},
	
		  			}]

you can also use a function for the xAxis tooltip but it has to be called with an => type function call

    					// This is a label on the axis line. Only required (by me) if the 1st line of the toolTip needs formatting
    					axisPointer: {
							snap: true,
							label: {
        						show: false,
								// The function(params) cannot call a 'this' function (no 'this') so use an arrow function
        						formatter: (params) => this.formatToolTipFirstLine(params)
								
      						},

      					},

B. that particular chart has a tooltip option of

				option = {
		  			tooltip: {
						trigger: 'axis',

						axisPointer: {
      						type: 'none',
      						snap: true,

    					},

					},

and a series

		  			series: [{
						name: this.seriesName[0],                 		// Used in the the 'tooltip'
						type: 'bar',
						symbol: 'none',                     			// Shape of data point on graph
						animation: false,

						itemStyle: {
      						color: this.itemColours[0]					// Colour of line or bar
							
						},

      					tooltip: {
							valueFormatter: (value) => this.formatToolTip(value, 1)

						},

		  			}]
  • So the important points, format using option tooltip and series name for simple tooltips.
  • ALL tooltip options have the basic option tooltip setup ( as B above)
  • To format the tooltip differently for each series use the series tooltip
  • To use a formula for the tooltip use an => function type as the 'this' of an external formula is not available in the option Object
  • The colour of series tooltip circle is the same as the series (line, bar) unless otherwise defined.
  • An easy way to format x axis time is to use the echarts function echarts.format.formatTime('hh:mm', params.value)

This is an example of the params Object in the xAxis tooltip (left unformatted for space)

{"value":"12 October","axisDimension":"x","axisIndex":0,"seriesData":[{"componentType":"series","componentSubType":"bar","componentIndex":0,"seriesType":"bar","seriesIndex":0,"seriesId":"\u0000Oil Level\u00000","seriesName":"Oil Level","name":"12 October","dataIndex":14,"data":{"x":"12 October","y":48},"value":{"x":"12 October","y":48},"color":"GoldenRod","dimensionNames":["x","y"],"encode":{"x":[0],"y":[1]},"$vars":["seriesName","name","value"]}]}

The tooltip issue is caused by vue/vuetify, is it documented in the echarts documentation and vue documentation.

Those issues refer to the chart being proxied, I couldn't find any reference to tooltips.

I think the only issue mentioned that I have seen using Vue in the ui-template is the declaration of the echart in the data section i.e. do not use chart: {} etc as a data initialiser always generate the chart Object in the code, and remember that the option Object is NOT dynamic, you always have to re-run chart.setOption(option) after any change.

i.e.

		mounted() {
	  		let interval = setInterval(() => {
				if (window.echarts) {
					clearInterval(interval)
					
					// get a reference to the div element
					const element = this.$refs.echart

					/**
					* Render chart using 'svg' rather than 'canvas'
					*/
					const chart = echarts.init(element, null, { renderer: 'svg' })

					this.isChartLoaded = true
				
					// Initialize with basic option structure
					this.option = this.generateChartOptions()

					this.chart = chart

					this.chart.setOption(this.option)

				}

	  		}, 25)
			

		}, // End of mounted

not

<script>
    export default {
        data() {
            // define variables available component-wide
            // (in <template> and component functions)
            return {
                 chart: {},
            },

        },  // End of data

but this affects the whole chart not just tooltips.

Thanks a lot all of you! That is great help! I will go through all of your suggestions! Actually I found that there are also browser related issues. Just by deactivating the ad blocker, suddenly the tooltip came up on 2 lines, but only for 'item'. There might also be a difference if you load the echart from a cdn or from your local machine which I am also investigating.

Would you be so kind to share the code that produced "Klimadaten" with me? This is exactly what I am looking for! Danke!
Cheers, Uwe

Sure! Do you mean the javascript generating the echart? That is at the top in my first post. Just import the Node. As soon as I have fixed all the remaining problems I will post the updated code of the Node.

I missed that, sorry. Looking forward to seeing this! Uwe

Looks like I miss something … or a lot. What am I supposed to do to see

Sorry, I miss something … or a lot. What do I have to do with this node in order to see something?

Upps ... Here it is ... Now I will figure out how I can feed real data into it.

I read the data from an influxdb and then use this function to format the data for the graph:

var obj = {};
obj.RH_series=[]
obj.Temp_series=[]
obj.CO2_series=[] 
obj.TimeLabels=[];
var element;
for (const [index, el] of msg.payload.entries()) {
    obj.RH_series.push(el.RH);
    obj.CO2_series.push(el.CO2);
    obj.Temp_series.push(el.Temp);
    obj.TimeLabels.push(el._time)
  if ( index === 5 ) break; // first five entries for testing
}
//    temp.push(element.temp);
//    ppm.push(element.ppm)
    //labels.push(new Date(element._time).getTime())

msg.payload = obj;
msg.topic = "data";
return msg;

I have come with my chart to a stage where it works for me (for now ;-)).

Here is my template code:

<template>
    <div ref="chartklima1" style="width: auto; height: auto; position: relative;" id="chart-klima1"></div>
</template>

<script type="text/javascript" src="/echarts.min.js"></script>
<script type="text/javascript" src="/tooltiphelper.js"></script>
<style lang="css">
    .chart-container {
        width: 100%;
        height: auto;
    }
</style>

<script>
    // import * as echarts from 'echarts';
    // import tthelper from './tooltiphelper';
    export default {
        data() {
            return {
                myChart: null,
                chartData: {},
                customTooltipDiv: null,
                currentNearestValues: {},
                currentCategory: '',
                seriesOrder: ['temp', 'rh', 'ppm']
            }
        },
        watch: {
            msg: function () {
                // check if echart is already instantiated
                //console.error("msg watch", this.msg)
                let interval = setInterval(()=>{
                    if(this.myChart){
                        clearInterval(interval)
                        if (this.msg.topic === "data") {
                            //console.error(this.msg)
                            this.update(this.msg.payload.TimeLabels, this.msg.payload.Temp_series, this.msg.payload.RH_series, this.msg.payload.CO2_series, this.msg.title)
                        }            
                    }
                },200);
            }
        },
        mounted() {
                this.etheme = {
                "version": 1,
                "themeName": "shine",
                "theme": {
                "seriesCnt": "4",
                "backgroundColor": "rgba(0,0,0,0)",
                "titleColor": "#333333",
                "subtitleColor": "#aaa",
                "textColorShow": false,
                "textColor": "#333",
                "markTextColor": "#eee",
                "color": [
                "#c12e34",
                "#e6b600",
                "#0098d9",
                "#2b821d",
                "#005eaa",
                "#339ca8",
                "#cda819",
                "#32a487"
                ],
                "borderColor": "#ccc",
                "borderWidth": 0,
                "visualMapColor": [
                "#1790cf",
                "#a2d4e6"
                ],
                "legendTextColor": "#333333",
                "kColor": "#c12e34",
                "kColor0": "#2b821d",
                "kBorderColor": "#c12e34",
                "kBorderColor0": "#2b821d",
                "kBorderWidth": 1,
                "lineWidth": 2,
                "symbolSize": 4,
                "symbol": "emptyCircle",
                "symbolBorderWidth": 1,
                "lineSmooth": false,
                "graphLineWidth": 1,
                "graphLineColor": "#aaa",
                "mapLabelColor": "#c12e34",
                "mapLabelColorE": "#c12e34",
                "mapBorderColor": "#eee",
                "mapBorderColorE": "#ddd",
                "mapBorderWidth": 0.5,
                "mapBorderWidthE": 1,
                "mapAreaColor": "#ddd",
                "mapAreaColorE": "#e6b600",
                "axes": [
                {
                "type": "all",
                "name": "myAxis",
                "axisLineShow": true,
                "axisLineColor": "#333",
                "axisTickShow": true,
                "axisTickColor": "#333",
                "axisLabelShow": true,
                "axisLabelColor": "#333",
                "splitLineShow": true,
                "splitLineColor": [
                "#ccc"
                ],
                "splitAreaShow": false,
                "splitAreaColor": [
                "rgba(250,250,250,0.3)",
                "rgba(200,200,200,0.3)"
                ]
                }
                ],
                "axisSeperateSetting": true,
                "toolboxColor": "#06467c",
                "toolboxEmphasisColor": "#4187c2",
                "tooltipAxisColor": "#cccccc",
                "tooltipAxisWidth": 1,
                "timelineLineColor": "#005eaa",
                "timelineLineWidth": 1,
                "timelineItemColor": "#005eaa",
                "timelineItemColorE": "#005eaa",
                "timelineCheckColor": "#005eaa",
                "timelineCheckBorderColor": "rgba(49,107,194,0.5)",
                "timelineItemBorderWidth": 1,
                "timelineControlColor": "#005eaa",
                "timelineControlBorderColor": "#005eaa",
                "timelineControlBorderWidth": 0.5,
                "timelineLabelColor": "#005eaa",
                "gridLeft": "10%",
                "gridRight": "10%",
                "gridTop": 60,
                "gridBottom": 70,
                "legendLeft": "center",
                "legendRight": "",
                "legendTop": 0,
                "legendBottom": ""
                
                }
                }
            let interval = setInterval(() => {
                const el = this.$refs.chartklima1
                if (el && typeof echarts !== "undefined") {
                    clearInterval(interval);
                    // now it is loaded, we can initialise and use it
                    this.init();
                }
            }, 200);
        },
        methods: {
            init: function () {
                const chartDom = document.getElementById("chart-klima1");
                if(!chartDom){
                    console.error("chart element not yet rendered")
                    return;
                }
                this.myChart = echarts.init(chartDom, this.etheme.theme);
                if (!this.myChart) {
                    console.error("echarts not initialized");
                    return;
                }
                
                // Initialize Custom Tooltip
                tthelper.createCustomTooltip(this, this.$refs.chartklima1, this.myChart);
                // dummy / test data
                const labels = ['07:00', '08:00', '09:00', '10:00', '11:00', '12:00'];
                const data_temp = [15, 15.5, 16, 20, 18, 17];
                const data_rh = [55, 75, 80, 85, 70, 72];
                const title = "Raum 1";
                const data_ppm = [800, 750, 800, 850, 610, 620];
                this.update(labels, data_temp, data_rh, data_ppm, title);
                
            },
         
            update: function (xAxisData, data_temp, data_rh, data_ppm, title) {
                // Save data for tooltip
                this.chartData = {
                    xAxis: xAxisData,
                    temp: data_temp,
                    rh: data_rh,
                    ppm: data_ppm
                };
                
                this.myChart.setOption({
                    title: {
                        text: title,
                    },
                    tooltip: {
                        show: true,
                        trigger: "axis",
                        formatter: function() { return ''; }, // Hide default tooltip content
                        backgroundColor: 'rgba(0,0,0,0)', // Transparent background
                        borderColor: 'rgba(0,0,0,0)', // Transparent border
                        textStyle: { color: 'rgba(0,0,0,0)' } // Transparent text
                    },
                    axisPointer: {
                        link: [{ xAxisIndex: "all" }],
                        label: {
                            show: true,
                            formatter: (params) => {
                                console.log('Formatter called', params);
                                if (params.axisDimension === "x" && this.chartData.xAxis) {
                                    const category = params.value;
                                    const index = this.chartData.xAxis.indexOf(category);
                                    
                                    if (index !== -1) {
                                        this.currentNearestValues = {
                                            temp: { value: this.chartData.temp[index], unit: '°C', color: this.etheme.theme.color[0], label: 'Temperatur' },
                                            rh: { value: this.chartData.rh[index], unit: '%', color: this.etheme.theme.color[2], label: 'RH in %' },
                                            ppm: { value: this.chartData.ppm[index], unit: 'ppm', color: this.etheme.theme.color[1], label: 'CO2' }
                                        };
                                        this.currentCategory = category;
                                        console.log('Values updated', this.currentNearestValues);
                                    }
                                    return "";
                                }
                                return null;
                            },
                            backgroundColor: "transparent",
                            borderColor: "transparent",
                            color: "transparent",
                        }
                    },
                    legend: {
                        data: ['Temperatur', 'RH in %', 'CO2 (ppm)']
                    },                    
                    grid: {
                        left: "3%",
                        right: "4%",
                        containLabel: true,
                    },
                    xAxis: {
                        type: "category",
                        boundaryGap: false,
                        data: xAxisData,
                        axisPointer: {
                            show: true
                        }
                    },
                    yAxis: [
                        {
                            type: "value",
                            name: "Temperatur",
                            min: 10,
                            max: 24,
                            splitLine:{
                                show:true,
                            },
                            axisLabel: {
                                formatter: "{value}°C",
                            },
                            axisLine:{
                                show:true,
                                lineStyle: {
                                    color: this.etheme.theme.color[0],
                                }
                            },
                            axisPointer: {
                                snap: true,
                            },
                        },
                        {
                            type: "value",
                            name: "CO2",
                            splitLine:{
                                show:false,
                            },
                            nameGap: 15,
                            nameMoveOverlap: true,
                            position: 'right',
                            offset: 45,
                            axisLine: {
                                show: true,
                                lineStyle: {
                                    color: this.etheme.theme.color[1]
                                },                            
                            },
                            axisTick: {
                                show: true,
                            },
                            min: 400,
                            max: 1500,
                        },
                        {
                        type: "value",
                        name: "% RH",
                        position: 'right',
                        splitLine:{show:false,
                        },
                        axisLine:{
                        show:true,
                        lineStyle: {
                        color: this.etheme.theme.color[2],
                        }
                        },
                        axisTick: {
                        show: true,
                        },
                        min: 40,
                        max: 100,
                        },
                      ],
                    series: [
                        {
                        name: "Temperatur",
                        type: "line",
                        smooth: true,
                        showSymbol: true,
                        data: data_temp,
                        yAxisIndex: 0,
                        symbolSize: 2,
                        tooltip: {
                            valueFormatter: '{value} °C',
                        },
                        lineStyle: {
                            width: 1,
                            }
                        },
                        {
                        name: "CO2 (ppm)",
                        type: "line",
                        smooth: true,
                        showSymbol: true,
                        symbolSize: 2,
                        data: data_ppm,
                        yAxisIndex: 1,
                        },                                        
                        {
                        name: "RH in %",
                        type: "line",
                        smooth: true,
                        showSymbol: true,
                        symbolSize: 2,
                        splitLine: {
                        show: false,
                        lineStyle: {
                        width: 1,
                        }
                        },
                        data: data_rh,
                        yAxisIndex: 2,
                        },                      ],
                });
            }
        }
    }
</script>

I moved the tooltip code into an external js file which I load through the 'httpStatic' property in settings.js. This allows me to use the code for other (similar) charts in my nodes. Here is the code of 'tooltiphelper.js':

var tthelper = {
    createCustomTooltip(that, chartElement, myechart) {
    that.customTooltipDiv = document.createElement("div");
    that.customTooltipDiv.style.cssText = `
                    position: absolute;
                    display: none;
                    background-color: rgba(50, 50, 50, 0.8);
                    border: 1px solid #333;
                    padding: 10px;
                    border-radius: 4px;
                    color: #fff;
                    font-size: 12px;
                    pointer-events: none;
                    z-index: 9999;
                    max-width: 300px;
                    box-shadow: 0 2px 8px rgba(0,0,0,0.3);
                `;
    chartElement.appendChild(that.customTooltipDiv);

    let updateTimeout = null;
    myechart.getZr().on("mousemove", (params) => {
      const pointInPixel = [params.offsetX, params.offsetY];
      if (myechart.containPixel("grid", pointInPixel)) {
        if (updateTimeout) clearTimeout(updateTimeout);
        updateTimeout = setTimeout(() => {
          tthelper.updateCustomTooltip(that, params.offsetX, params.offsetY);
        }, 50);
      } else {
        if (updateTimeout) clearTimeout(updateTimeout);
        that.customTooltipDiv.style.display = "none";
      }
    });
  },

  updateCustomTooltip(that, x, y) {
    //console.log('updateCustomTooltip called', this.currentNearestValues);
    if (
      !that.currentNearestValues ||
      Object.keys(that.currentNearestValues).length === 0
    ) {
      console.log("No values to show");
      return;
    }

    that.customTooltipDiv.innerHTML = tthelper.buildTooltipHTML(
      that.currentCategory,
      that.currentNearestValues,
      that.seriesOrder,
    );
    that.customTooltipDiv.style.display = "block";
    //this.customTooltipDiv.style.left = '0px';
    //this.customTooltipDiv.style.top = '0px';
    tthelper.positionTooltip(
      that.$refs.chartklima1,
      that.customTooltipDiv,
      x,
      y,
    );
  },
  buildTooltipHTML(category, values, seriesOrder) {
    // ... same implementation ...
    let html = `<div style="font-weight: bold; margin-bottom: 8px; font-size: 13px;">
                    ${category}
                </div>`;

    const orderedTopics = seriesOrder.filter((topic) => values[topic]);

    orderedTopics.forEach((topic) => {
      const item = values[topic];
      html += `<div style="line-height: 20px;">
                    <span style="display: inline-block; width: 10px; height: 10px; 
                                background-color: ${item.color}; border-radius: 50%; 
                                margin-right: 5px;"></span>
                    <span style="color: #ddd;">${item.label}:</span>
                    <span style="font-weight: bold; margin-left: 5px;">
                        ${item.value} ${item.unit}
                    </span>
                    </div>`;
    });

    return html;
  },

  positionTooltip(chartelement, cTooltipDiv, mouseX, mouseY) {
    // ... same implementation ...
    //requestAnimationFrame(() => {
    const chartRect = chartelement.getBoundingClientRect();
    const tooltipWidth = cTooltipDiv.offsetWidth;
    const tooltipHeight = cTooltipDiv.offsetHeight;

    // Horizontal: Left or right of the mouse
    let left =
      mouseX < chartRect.width / 2
        ? Math.min(mouseX + 20, chartRect.width - tooltipWidth - 10) // Right
        : Math.max(mouseX - tooltipWidth - 20, 10); // Left

    // Vertical: Centered, but within visible area
    let top = Math.max(
      10,
      Math.min(
        mouseY - tooltipHeight / 2,
        chartRect.height - tooltipHeight - 10,
      ),
    );
    tthelper.animateToNewLocation(cTooltipDiv, left, top);
    //this.customTooltipDiv.style.left = left + 'px';
    //this.customTooltipDiv.style.top = top + 'px';
    //});
  },

  animateToNewLocation(element, targetX, targetY, duration = 200) {
    const startTime = performance.now();
    const startX = element.offsetLeft;
    const startY = element.offsetTop;

    function animate(currentTime) {
      const elapsed = currentTime - startTime;
      const progress = Math.min(elapsed / duration, 1);

      // Easing function (ease-in-out)
      const easeProgress =
        progress < 0.5
          ? 2 * progress * progress
          : -1 + (4 - 2 * progress) * progress;

      // Calculate new position
      const newX = startX + (targetX - startX) * easeProgress;
      const newY = startY + (targetY - startY) * easeProgress;

      element.style.left = newX + "px";
      element.style.top = newY + "px";

      if (progress < 1) {
        requestAnimationFrame(animate);
      }
    }

    requestAnimationFrame(animate.bind(this));
  },
};

//export default tthelper;

The code of the tooltip is rewegit´s code with a little tweaking here and there. Thanks very much for that, rewegit!
I wonder if there is a way to make the ticks of the x-Axis show only full hours!

That's a clever idea. Thank you for that.

However, I still hope that this workaround will be made obsolete with a future eCharts update.

Has a feature request been raised asking for it?

That seems to me to be more of a bug in eCharts. I don't know what flowfuse could do about it.
But I'm not that deeply involved in it. It's quite possible that I'm implementing the tooltip incorrectly in this specific constellation. However, apart from me, all the LLMs I've consulted have also failed at this :wink:

I haven't followed the thread in full detail, what exactly is it that you need? The built in chart node does this

Oh, is it the third y axis that is causing the problem?

I'm not sure about that. Have you tried implementing the chart in @joachim_bl's original post in the standard node? I haven't been able to do that yet.

Could you post your best effort at achieving that? I haven't got much time at the moment.