Echarts Flexdash Gauges

My demos above are running in Flexdash, not ui_templates!

I mentioned 'Minimum bundle' because I noticed the below in the echart's code example;

echarts

1 Like

I know. My comment was towards:

It's not a FD issue, it's an Echarts issue. If davidz can show how to produce your gauges by:

then I can do the same with FD...
(The only difference that I'm aware of is that the Echarts online package builder produces UMD/CJS while the Vue-Echarts needs ESM, so there are some easier options there, but I can hack around that by now...)

I'm looking at that interface now to see whether it has the answer...

Update: there may be something to this... What's confusing is that when you flip to "minimal bundle" you get:

import { GaugeChart } from 'echarts/charts';
import { CanvasRenderer } from 'echarts/renderers';

echarts.use([GaugeChart, CanvasRenderer]);

and the GaugeChart and CanvasRenderer symbols are not present at all in the "full echarts" package. So it looked to me like they're not included. But in the options these symbols are not referenced, e.g., the only thing that refers to a gauge is type: 'gauge', and that's the same either way.

Adding to the confusion is that VueEcharts has import ... from "echarts/core" (vue-echarts/src/ECharts.ts at main Ā· ecomfe/vue-echarts Ā· GitHub) so it's kind'a locked into the minimal bundle path, it seems...

1 Like

Aha, so thanks to Paul for pointing out that UI which lead down the right path! I think the solution is to not use vue-echarts. Try this:

[{"id":"2582a4c3e5ae0e0e","type":"flexdash custom","z":"721f0a5cbd48a85d","fd_container":"db08ae42228b5a34","fd_cols":"3","fd_rows":"4","fd_array":false,"fd_array_max":10,"fd_output_topic":"","fd_loopback":false,"name":"Temp Echarts","title":"Temperature","sfc_source":"<template>\n  <div class=\"chart\" ref=\"echarts-container\">Loading echart...</div>\n</template>\n\n<style scoped>\n.chart {\n  height: 100%;\n  width: 100%;\n}\n</style>\n\n<script>\nimport * as echarts from 'echarts';\n\nexport default {\n  // Props are the inputs to the widget.\n  // They can be set dynamically using Node-RED messages using `msg.<prop>`.\n  // In a \"custom widget\" like this one they cannot be set via the Node-RED flow editor:\n  // use the default values in the lines below instead.\n  props: {\n    option: { default: {} },\n    random: { default: false }, // inject random data\n  },\n  mounted() {\n    const ec = this.$refs[\"echarts-container\"]\n    this.chart = echarts.init(ec) // this.chart is not reactive\n    console.log(\"Echart mounted\")\n  },\n  watch: {\n    option: {\n      immediate: true,\n      deep: true,\n      handler(val) {\n        console.log(\"got options\", JSON.stringify(val).substring(0,40))\n        if (this.chart) this.chart.setOption(val)\n      }\n    },\n  }\n}\n</script>\n","import_map":{"echarts":"https://cdn.jsdelivr.net/npm/echarts/dist/echarts.esm.js","resize-detector":"https://cdn.jsdelivr.net/npm/resize-detector@0.3.0/esm/index.js"},"x":300,"y":420,"wires":[[]]},{"id":"e58479387d184238","type":"function","z":"721f0a5cbd48a85d","name":"Temp Echarts Options","func":"const dataValue = msg.payload\nconst option = {\n    series: [\n        {\n            type: 'gauge',\n            center: ['50%', '60%'],\n            startAngle: 200,\n            endAngle: -20,\n            min: 0,\n            max: 30,\n            splitNumber: 6,\n            itemStyle: {\n                color: '#FFAB91'\n            },\n            progress: {\n                show: true,\n                width: 30\n            },\n            pointer: {\n                show: false\n            },\n            axisLine: {\n                lineStyle: {\n                    width: 30\n                }\n            },\n            axisTick: {\n                distance: -45,\n                splitNumber: 5,\n                lineStyle: {\n                    width: 2,\n                    color: '#999'\n                }\n            },\n            splitLine: {\n                distance: -52,\n                length: 14,\n                lineStyle: {\n                    width: 3,\n                    color: '#999'\n                }\n            },\n            axisLabel: {\n                distance: 0,\n                color: '#999',\n                fontSize: 14\n            },\n            anchor: {\n                show: false\n            },\n            title: {\n                show: false\n            },\n            detail: {\n                valueAnimation: true,\n                width: '60%',\n                lineHeight: 40,\n                borderRadius: 8,\n                offsetCenter: [0, '-15%'],\n                fontSize: 40,\n                fontWeight: 'bolder',\n                formatter: '{value}Ā°C',\n                color: 'auto'\n            },\n            data: [\n                {\n                    value: dataValue[0]\n                }\n            ]\n        },\n        {\n            type: 'gauge',\n            center: ['50%', '60%'],\n            startAngle: 200,\n            endAngle: -20,\n            min: 0,\n            max: 30,\n            itemStyle: {\n                color: '#FD7347'\n            },\n            progress: {\n                show: true,\n                width: 8\n            },\n            pointer: {\n                show: false\n            },\n            axisLine: {\n                show: false\n            },\n            axisTick: {\n                show: false\n            },\n            splitLine: {\n                show: false\n            },\n            axisLabel: {\n                show: false\n            },\n            detail: {\n                show: false\n            },\n            data: [\n                {\n                    value: dataValue[1]\n                }\n            ]\n        }\n    ]\n};\n\nreturn { option }","outputs":1,"noerr":0,"initialize":"","finalize":"","libs":[],"x":220,"y":340,"wires":[["2582a4c3e5ae0e0e"]]},{"id":"b5f4e4a81a8f611d","type":"function","z":"721f0a5cbd48a85d","name":"dummy data","func":"const arr = [[10,15],[11,15],[12,15],[13,15],[14,15],[15,15],[15,19],[16,19],[17,19],[18,19],[19,19],[19,13],[17,13],[15,13],[13,13],[12,13],[11,13],[10,14],[10,15]];\n\narr.map((element) => {\n    node.send({payload: element});\n});","outputs":1,"noerr":0,"initialize":"","finalize":"","libs":[],"x":125,"y":215,"wires":[["bb59284a87ad2e26"]]},{"id":"777a123d12f6cff9","type":"inject","z":"721f0a5cbd48a85d","name":"","props":[{"p":"payload"}],"repeat":"19","crontab":"","once":true,"onceDelay":0.1,"topic":"","payload":"","payloadType":"str","x":110,"y":170,"wires":[["b5f4e4a81a8f611d"]]},{"id":"bb59284a87ad2e26","type":"delay","z":"721f0a5cbd48a85d","name":"","pauseType":"rate","timeout":"5","timeoutUnits":"seconds","rate":"1","nbRateUnits":"1","rateUnits":"second","randomFirst":"1","randomLast":"5","randomUnits":"seconds","drop":false,"allowrate":false,"outputs":1,"x":120,"y":260,"wires":[["e58479387d184238"]]},{"id":"db08ae42228b5a34","type":"flexdash container","name":"Grid One","kind":"StdGrid","fd_children":",05665b48e63afba4,2582a4c3e5ae0e0e","title":"One","tab":"523e209a21919b0b","min_cols":"1","max_cols":"20","unicast":"ignore","parent":"","solid":false,"cols":"1","rows":"1"},{"id":"523e209a21919b0b","type":"flexdash tab","name":"Tab One","icon":"mdi-view-dashboard","title":"One","fd_children":",db08ae42228b5a34","fd":"5fec7c7287e94234"}]

This is just a minimal version, it probably doesn't resize well and there may be additional things that need to be handled. I didn't see that vue-echarts does a whole lot though.

(Ooops, I left the "random" prop in, it doesn't do anything...)

2 Likes

Wow!! that loads much faster than the example with vue-charts :smile: :smile: :smile:

echarts

1 Like

Yes, it downloads a single 700KB (compressed) file from jsdelivr. The old one was downloading hundreds of small source files. The new one should be improved by producing a minified package and hosting it locally in the static file area. "All" you need to do to host it locally is plop the package in the right place and change the URL in the custom widget config import map accordingly.

1 Like

There is also a 'minified' version in jsdelivr which loads really fast now I've loaded it as a static file.
https://cdn.jsdelivr.net/npm/echarts@5.4.1/dist/echarts.esm.min.js

1 Like

It is very easy to produce a gauge with Echarts minimum package and dashboard.
I think the Echarts.min.js has everything we need for different charts.

Please see below animated gauge:
Echarts gauge

The following are the codes used with Echarts.min.js and the template node:

<div id="EchartsGauge" style="width: 750px;height:610px;"></div>

<script>
var chartDom = document.getElementById('EchartsGauge');
var myChart = echarts.init(chartDom);
var option;

const gaugeData = [
{
value: 20,
name: 'Good',
title: {
offsetCenter: ['-40%', '80%']
},
detail: {
offsetCenter: ['-40%', '95%']
}
},
{
value: 40,
name: 'Better',
title: {
offsetCenter: ['0%', '80%']
},
detail: {
offsetCenter: ['0%', '95%']
}
},
{
value: 60,
name: 'Perfect',
title: {
offsetCenter: ['40%', '80%']
},
detail: {
offsetCenter: ['40%', '95%']
}
}
];
option = {
series: [
{
type: 'gauge',
anchor: {
show: true,
showAbove: true,
size: 18,
itemStyle: {
color: '#FAC858'
}
},
pointer: {
icon:
'path://M2.9,0.7L2.9,0.7c1.4,0,2.6,1.2,2.6,2.6v115c0,1.4-1.2,2.6-2.6,2.6l0,0c-1.4,0-2.6-1.2-2.6-2.6V3.3C0.3,1.9,1.4,0.7,2.9,0.7z',
width: 8,
length: '80%',
offsetCenter: [0, '8%']
},
progress: {
show: true,
overlap: true,
roundCap: true
},
axisLine: {
roundCap: true
},
data: gaugeData,
title: {
fontSize: 14
},
detail: {
width: 40,
height: 14,
fontSize: 14,
color: '#fff',
backgroundColor: 'auto',
borderRadius: 3,
formatter: '{value}%'
}
}
]
};
setInterval(function () {
gaugeData[0].value = +(Math.random() * 100).toFixed(2);
gaugeData[1].value = +(Math.random() * 100).toFixed(2);
gaugeData[2].value = +(Math.random() * 100).toFixed(2);
myChart.setOption({
series: [
{
data: gaugeData
}
]
});
}, 2000);

option && myChart.setOption(option);
</script>

This might be the right solution for combining Echarts with Flexdash.

We use Echarts since it runs faster, uses less CPU and memory than other charts when there are lots of lines in the line charts. This is very important for real-time display and data analysis.

You can also customize the charts easily due to Chart's flexibility. For example, you can define the spacing and location between legends easily. You can't do it with some other charts.

Echarts has excellent documentation and tons of example codes too.

Thanks for following up. If you read the thread, you can see that we figured out where the confusion came from and how to solve it using ESM.

Since you're such a fan of Echarts, maybe you could contribute a flexdash widget for it? :wink:

1 Like

Yes I saw this (pls see my last reply).

I need to find time looking into how to use Flexdash first :rofl: Extremely busy. But it is on my calendar in 2023. I may have lots of questions by that time. :grin:

As to the charts, we use whatever can meet our requirements and performs the best for our applications after comparing and testing multiple charts.

I really liked this (...for the first 20 seconds :laughing:)
It's drawn and animated by Echarts.

title

[{"id":"04ee1cf55b4bae93","type":"function","z":"1543d308b342690a","name":"function 7","func":"\nlet option = {\n    graphic: {\n        elements: [\n            {\n                type: 'text',\n                left: 'center',\n                top: 'center',\n                style: {\n                    text: 'node-RED',\n                    fontSize: 60,\n                    fontWeight: 'bold',\n                    lineDash: [0, 200],\n                    lineDashOffset: 0,\n                    fill: 'transparent',\n                    stroke: '#000',\n                    lineWidth: 1\n                },\n                keyframeAnimation: {\n                    duration: 6000,\n                    loop: true,\n                    keyframes: [\n                        {\n                            percent: 0.7,\n                            style: {\n                                fill: 'transparent',\n                                lineDashOffset: 200,\n                                lineDash: [200, 0]\n                            }\n                        },\n                        {\n                            // Stop for a while.\n                            percent: 0.8,\n                            style: {\n                                fill: 'transparent'\n                            }\n                        },\n                        {\n                            percent: 1,\n                            style: {\n                                fill: '#8F0000'\n                            }\n                        }\n                    ]\n                }\n            }\n        ]\n    }\n}\nreturn { option }","outputs":1,"noerr":0,"initialize":"","finalize":"","libs":[],"x":355,"y":2550,"wires":[["fe533afc4055b828"]]},{"id":"0bc40178161d4c73","type":"flexdash ctrl","z":"1543d308b342690a","name":"","fd":"e8f5aea52ab49500","weak_fd":"","fd_output_topic":"wakeup","x":205,"y":2550,"wires":[["04ee1cf55b4bae93"]]},{"id":"fe533afc4055b828","type":"flexdash custom","z":"1543d308b342690a","fd_container":"28d1859702cdf729","fd_cols":"3","fd_rows":"1","fd_array":false,"fd_array_max":10,"fd_output_topic":"","fd_loopback":false,"name":"Echarts","title":"","sfc_source":"<template>\n  <div class=\"chart\" ref=\"echarts-container\">Loading echart...</div>\n</template>\n\n<style scoped>\n.chart {\n  height: 100%;\n  width: 100%;\n}\n</style>\n\n<script>\nimport * as echarts from 'echarts';\n\nexport default {\n  // Props are the inputs to the widget.\n  // They can be set dynamically using Node-RED messages using `msg.<prop>`.\n  // In a \"custom widget\" like this one they cannot be set via the Node-RED flow editor:\n  // use the default values in the lines below instead.\n  props: {\n    option: { default: {} },\n    random: { default: false }, // inject random data\n  },\n  mounted() {\n    const ec = this.$refs[\"echarts-container\"]\n    this.chart = echarts.init(ec) // this.chart is not reactive\n    console.log(\"Echart mounted\")\n  },\n  watch: {\n    option: {\n      immediate: true,\n      deep: true,\n      handler(val) {\n        console.log(\"got options\", JSON.stringify(val).substring(0,40))\n        if (this.chart) this.chart.setOption(val)\n      }\n    },\n  }\n}\n</script>\n","import_map":{"echarts":"https://cdn.jsdelivr.net/npm/echarts/dist/echarts.esm.js","resize-detector":"https://cdn.jsdelivr.net/npm/resize-detector@0.3.0/esm/index.js"},"x":520,"y":2550,"wires":[[]]},{"id":"28d1859702cdf729","type":"flexdash container","name":"charts","kind":"StdGrid","fd_children":",d2dbe97c44f6fb5a,d2b3883a74adc563,ab904c40d22f83e1,527401ee602f4386,4f31b9c704e0b947,a8dfa00ae270ac88,b27685878ffe3711,8713c375979525c8,5021eeaf697e64c2,02a8193ebdb37b8f,4ba2dad94e5ffd6f,5aa2f5882d6d108c,99d0a46353e4f3f8,8db95e700c175b9c,27e8564637493f56,2582a4c3e5ae0e0e,d9247622bb479c73,3424215a05654cc1,fe533afc4055b828","title":"","tab":"9f23b0158f8280e3","min_cols":"1","max_cols":"20","unicast":"","parent":"","solid":false,"cols":"1","rows":"1"},{"id":"9f23b0158f8280e3","type":"flexdash tab","name":"charts","icon":"mdi-chart-line","title":"charts","fd_children":",28d1859702cdf729","fd":"e8f5aea52ab49500"}]

(Remember to select your dashboard from the drop down in the FD Control node)

4 Likes

No offence to those who have posted pictures of echarts gauges, but I doubt that anyone who has seen @hotNipi's enhanced dashboard gauges, or some other standard dashboard widget enhancements, will be too eager to switch to Flexdash based on them.

I think we need standard widgets and inspirational examples of beautifying them.

Almost perfect... - needs a capital N ... :slight_smile:

1 Like

Well considering that Flexdash is still in alpha, it's hardly surprising...
Can you remember when node-RED was launched? I can, and it was exactly the same, very limited, but look where it is now.

The shortcut to Flexdash producing great "standard widgets and inspirational examples of beautifying them" is for the community to contribute, and it won't be long before momentum & enthusiasm builds (and maybe @hotNipi hopefully comes onboard).

I've deleted my old dashboard & totally switched to Flexdash now, and even at this early stage I don't regret doing so.

4 Likes

At least I chose the correct colour - #8F0000 :roll_eyes:

1 Like

Remove maybe
Remove hopefully

5 Likes

With pleasure :laughing: :laughing: :laughing:

1 Like

How can I make it less so? :laughing:

Maybe I should spend a couple of hours extending my Vue primer - FlexDash ?

BTW, have you used TailwindCSS? I'm finding it awesome. Wish I had known about it when I started FlexDash, and/or that it was more compatible with Vuetify.

If you haven't looked at it, start with CSS Utility Classes and "Separation of Concerns". Vuetify has a subset of Tailwind built-in (well, unfortunately similar to TW but not exactly compatible) and initially it didn't make much sense to me, then I started using it, then I got comfortable, now I can't do markup without. I'm now using TW in another related NR project that doesn't use Vuetify...

I think it is ( or was) #910000 but close enough ā€¦

avengers-assemble