From 4df26fa4e11e6c917cf3ddc0feef429d5ecad6c4 Mon Sep 17 00:00:00 2001 From: Gayan Sandamal Date: Mon, 26 Aug 2024 17:13:41 +0530 Subject: [PATCH 01/11] Dynamic props support for gauge --- ui/src/widgets/ui-gauge/UIGauge.vue | 59 ++++++++++++++++++++++++++--- 1 file changed, 53 insertions(+), 6 deletions(-) diff --git a/ui/src/widgets/ui-gauge/UIGauge.vue b/ui/src/widgets/ui-gauge/UIGauge.vue index 2269cfd03..9fb5b1dc2 100644 --- a/ui/src/widgets/ui-gauge/UIGauge.vue +++ b/ui/src/widgets/ui-gauge/UIGauge.vue @@ -1,8 +1,5 @@ From 9771ca73ea5295bae2e90d4183669aeeb4f367b8 Mon Sep 17 00:00:00 2001 From: Gayan Sandamal Date: Tue, 27 Aug 2024 11:49:12 +0530 Subject: [PATCH 02/11] Dynamic props support for gauge --- ui/src/widgets/ui-gauge/UIGauge.vue | 17 ++++++++++++++++- 1 file changed, 16 insertions(+), 1 deletion(-) diff --git a/ui/src/widgets/ui-gauge/UIGauge.vue b/ui/src/widgets/ui-gauge/UIGauge.vue index 9fb5b1dc2..695cf1d62 100644 --- a/ui/src/widgets/ui-gauge/UIGauge.vue +++ b/ui/src/widgets/ui-gauge/UIGauge.vue @@ -53,6 +53,15 @@ export default { icon () { return this.getProperty('icon') }, + segments () { + return this.getProperty('segments') + }, + min () { + return this.getProperty('min') + }, + max () { + return this.getProperty('max') + }, dynamicProps () { const props = { ...this.props, @@ -62,7 +71,10 @@ export default { prefix: this.prefix, suffix: this.suffix, units: this.units, - icon: this.icon + icon: this.icon, + segments: this.segments, + min: this.min, + max: this.max } console.log('props', this.props, props) return props @@ -84,6 +96,9 @@ export default { this.updateDynamicProperty('suffix', updates.suffix) this.updateDynamicProperty('units', updates.units) this.updateDynamicProperty('icon', updates.icon) + this.updateDynamicProperty('segments', updates.segments) + this.updateDynamicProperty('min', updates.min) + this.updateDynamicProperty('max', updates.max) } } } From adf6be151e96afd4e60a5221068e1deee2767ffc Mon Sep 17 00:00:00 2001 From: Gayan Sandamal Date: Tue, 27 Aug 2024 11:51:59 +0530 Subject: [PATCH 03/11] Updated chart when style, segment, min and max changed & readability imprvements --- ui/src/widgets/ui-gauge/types/UIGaugeDial.vue | 35 ++++++++++++++----- 1 file changed, 26 insertions(+), 9 deletions(-) diff --git a/ui/src/widgets/ui-gauge/types/UIGaugeDial.vue b/ui/src/widgets/ui-gauge/types/UIGaugeDial.vue index 88f765fdd..04e6b70f0 100644 --- a/ui/src/widgets/ui-gauge/types/UIGaugeDial.vue +++ b/ui/src/widgets/ui-gauge/types/UIGaugeDial.vue @@ -77,12 +77,29 @@ export default { }, iconOnly () { return this.props.icon && !this.props.units + }, + gaugeStyle () { + return this.props.gstyle + }, + updateOn () { + return `${this.segments} ${this.gaugeStyle} ${this.min} ${this.max}` + }, + min () { + return this.props.min + }, + max () { + return this.props.max } }, watch: { - value: function (val, oldVal) { + value: function (val) { this.resize() this.update(val) + }, + updateOn: { + handler () { + this.update(this.value) + } } }, mounted () { @@ -94,7 +111,7 @@ export default { // initial SVG size setting this.resize() if (this.value === undefined) { - this.update(this.props.min, 0) + this.update(this.min, 0) } else { this.update(this.value, 0) } @@ -148,7 +165,7 @@ export default { .startAngle(-this.sizes.angle / 2) .endAngle(this.sizes.angle / 2) .cornerRadius(() => { - return this.props.gstyle === 'rounded' ? this.sizes.gaugeThickness : 0 + return this.gaugeStyle === 'rounded' ? this.sizes.gaugeThickness : 0 }) const backdrop = this.svg.select('#backdrop') @@ -188,7 +205,7 @@ export default { .outerRadius(gaugeR) .startAngle(-this.sizes.angle / 2) .cornerRadius(() => { - return this.props.gstyle === 'rounded' ? this.sizes.gaugeThickness : 0 + return this.gaugeStyle === 'rounded' ? this.sizes.gaugeThickness : 0 }) const arcTween = function (to) { @@ -247,7 +264,7 @@ export default { const needle = this.svg.select('#needle') .style('opacity', () => { - return this.props.gstyle === 'needle' ? 1 : 0 + return this.gaugeStyle === 'needle' ? 1 : 0 }) .style('transform', () => { const x = (this.width / 2) - this.r @@ -297,7 +314,7 @@ export default { // in radians valueToAngle (value) { const angle = this.sizes.angle - return angle * (value - this.props.min) / (this.props.max - this.props.min) + return angle * (value - this.min) / (this.max - this.min) }, // in radians valueToNeedleAngle (value) { @@ -351,8 +368,8 @@ export default { }, updateSegmentArc () { const segments = this.segments - const minValue = this.props.min - const maxValue = this.props.max + const minValue = this.min + const maxValue = this.max let cAngle = -this.sizes.angle / 2 this.arcs.sections = d3.arc() @@ -380,7 +397,7 @@ export default { this.$nextTick(() => { this.resize() if (this.value === undefined) { - this.update(this.props.min, 0) + this.update(this.min, 0) } else { this.update(this.value, 0) } From dffec9684f538ec87b294bfaf37024ffd40183d6 Mon Sep 17 00:00:00 2001 From: Gayan Sandamal Date: Tue, 27 Aug 2024 12:56:42 +0530 Subject: [PATCH 04/11] ui-gauge docs improvements --- docs/nodes/widgets/ui-gauge.md | 83 ++++++++++++++++++++++++++++++---- 1 file changed, 73 insertions(+), 10 deletions(-) diff --git a/docs/nodes/widgets/ui-gauge.md b/docs/nodes/widgets/ui-gauge.md index 3455a5132..b02650abc 100644 --- a/docs/nodes/widgets/ui-gauge.md +++ b/docs/nodes/widgets/ui-gauge.md @@ -3,19 +3,74 @@ description: Display real-time metrics with ui-gauge in Node-RED Dashboard 2.0 f props: Group: Defines which group of the UI Dashboard this widget will render in. Size: Controls the width of the dropdown with respect to the parent group. Maximum value is the width of the group. - Type: Defines the shape of the gauge, "Tile", "Battery", "Water Tank", "Half Gauge" or "3/4 Gauge" - Style: Defines the style of arc rendered, "Needle" or "Rounded" - Range (min): The smallest value that can be shown on the gauge - Range (max): The largest value that can be shown on the gauge - Segments: Defines the barriers by which the arc is color coded. These segments can also be shown on the gauge. - Label: Text shown above the gauge, labelling what the gauge is showing. - Prefix: Text to be added _before_ the value in the middle of the gauge. - Suffix: Text to be shown _after_ the value in the middle of the gauge. - Units: Small text to be shown below the value in the middle of the gauge. - Icon: Icon to be shown below the value in the middle of the gauge. Uses Material Designs Icon, no need to include the mdi- prefix. + Type: + description: Defines the shape of the gauge, "Tile", "Battery", "Water Tank", "Half Gauge" or "3/4 Gauge" + dynamic: true + Style: + description: Defines the style of arc rendered, "Needle" or "Rounded" + dynamic: true + Range (min): + description: The smallest value that can be shown on the gauge + dynamic: true + Range (max): + description: The largest value that can be shown on the gauge + dynamic: true + Segments: + description: Defines the barriers by which the arc is color coded. These segments can also be shown on the gauge. + dynamic: true + Label: + description: Text shown above the gauge, labelling what the gauge is showing. + dynamic: true + Prefix: + description: Text to be added _before_ the value in the middle of the gauge. + dynamic: true + Suffix: + description: Text to be shown _after_ the value in the middle of the gauge. + dynamic: true + Units: + description: Small text to be shown below the value in the middle of the gauge. + dynamic: true + Icon: + description: Icon to be shown below the value in the middle of the gauge. Uses Material Designs Icon, no need to include the mdi- prefix. + dynamic: true Sizes (Gauge): (px) How thick the arc and backdrop of the gauge are rendered. Sizes (Gap): (px) How big the gap/padding is between the Gauge and the "Segments" Sizes (Segments): (px) How thick the segments are rendered. +controls: + enabled: + example: true | false + description: Allow control over whether or not the number-input is enabled +dynamic: + Label: + payload: msg.ui_update.title + structure: ["String"] + Icon: + payload: msg.ui_update.icon + structure: ["String"] + Type: + payload: msg.ui_update.gtype + structure: ["String"] + Style: + payload: msg.ui_update.gstyle + structure: ["String"] + Min: + payload: msg.ui_update.min + structure: ["Number"] + Max: + payload: msg.ui_update.max + structure: ["Number"] + Segments: + payload: msg.ui_update.segments + structure: ["Array<{color: String, from: Number}>"] + Prefix: + payload: msg.ui_update.prefix + structure: ["String"] + Suffix: + payload: msg.ui_update.suffix + structure: ["String"] + Units: + payload: msg.ui_update.units + structure: ["String"] --- @@ -43,6 +98,14 @@ Values for the gauges can be set by sending a numerical value in `msg.payload`. +## Dynamic Properties + + + +## Controls + + + ## Examples ### Half Gauge - Rounded From cc04849688147c4c0e41a5d7cc9c00a5e8493424 Mon Sep 17 00:00:00 2001 From: Gayan Sandamal Date: Tue, 27 Aug 2024 13:52:42 +0530 Subject: [PATCH 05/11] 3/4 and half gauge rendering issue fix --- ui/src/widgets/ui-gauge/UIGauge.vue | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/ui/src/widgets/ui-gauge/UIGauge.vue b/ui/src/widgets/ui-gauge/UIGauge.vue index 695cf1d62..e6f2ed8a9 100644 --- a/ui/src/widgets/ui-gauge/UIGauge.vue +++ b/ui/src/widgets/ui-gauge/UIGauge.vue @@ -1,5 +1,6 @@ \ No newline at end of file From be9989116f19ee0e6f0e5cf34cb973734541c03b Mon Sep 17 00:00:00 2001 From: Joe Pavitt Date: Thu, 29 Aug 2024 16:34:54 +0100 Subject: [PATCH 09/11] Ensure dynamic properties docs are reflective of those actually available --- nodes/widgets/locales/en-US/ui_gauge.html | 35 +++++++++++++++-------- 1 file changed, 23 insertions(+), 12 deletions(-) diff --git a/nodes/widgets/locales/en-US/ui_gauge.html b/nodes/widgets/locales/en-US/ui_gauge.html index ca3d77216..611f37a08 100644 --- a/nodes/widgets/locales/en-US/ui_gauge.html +++ b/nodes/widgets/locales/en-US/ui_gauge.html @@ -31,26 +31,37 @@

Properties (Half & 3/4 Gauges Only)

Dynamic Properties (Inputs)

Any of the following can be appended to a msg.ui_update in order to override or set properties on this node at runtime.

-
label array
-
Update the label rendered with the Radio Group
-
options array
+
title string
+
Update the label rendered above the Gauge
+
segments array
Change the options available in the dropdown at runtime
    -
  • Array<string>
  • -
  • Array<{value: String}>
  • -
  • Array<{value: String, label: String}>
  • +
  • Array<{color: String, from: Number}>
-
columns array
-
- Change the options available in the dropdown at runtime +
gstyle see detail
+
Modify the type of Gauge rendered, with the following options:
    -
  • Array<string>
  • -
  • Array<{value: String}>
  • -
  • Array<{value: String, label: String}>
  • +
  • gauge-battery
  • +
  • gauge-34
  • +
  • gauge-half
  • +
  • gauge-tile
  • +
  • gauge-tank
+
min number
+
Change the minimum value the gauge supports
+
max number
+
Change the maximum value the gauge supports
+
prefix string
+
Change the text rendered after the Gauge's value
+
suffix string
+
Change the text rendered after the Gauge's value
+
units array
+
Controls the "unit" display underneath the gauge's value for 3/4 and Half gauges.
+
icon string
+
Modify which icon is rendered within the gauge (must be a Material Design icon)
class string
Add a CSS class, or more, to the Button at runtime.
From 28953b9c4e46b57ae0e5ee6b6df3bc14ec9781fd Mon Sep 17 00:00:00 2001 From: Gayan Sandamal Date: Fri, 30 Aug 2024 19:11:21 +0530 Subject: [PATCH 10/11] Fixed: segment color mapping issue happens when the new segments are lesser than the existing once --- ui/src/widgets/ui-gauge/types/UIGaugeDial.vue | 27 +++++++++++++++---- 1 file changed, 22 insertions(+), 5 deletions(-) diff --git a/ui/src/widgets/ui-gauge/types/UIGaugeDial.vue b/ui/src/widgets/ui-gauge/types/UIGaugeDial.vue index 03358bee4..2abfde6bf 100644 --- a/ui/src/widgets/ui-gauge/types/UIGaugeDial.vue +++ b/ui/src/widgets/ui-gauge/types/UIGaugeDial.vue @@ -230,12 +230,29 @@ export default { // update sections this.updateSegmentArc() + const svgPaths = this.svg.select('#sections').selectAll('path') + const pathNodes = svgPaths._groups[0] const segments = this.segments - this.svg.select('#sections') - .selectAll('path') - .data(segments) - .enter() - .append('path') + + // check there are more paths than segments + if (pathNodes.length !== 0 && pathNodes.length > segments.length) { + this.svg.select('#sections') + .selectAll('path') + .data(segments) + .enter() + .append('path') + // remove any extra paths + .filter((_d, i) => { + return i > segments.length - 1 + }) + .remove() + } else { + this.svg.select('#sections') + .selectAll('path') + .data(segments) + .enter() + .append('path') + } this.svg.select('#sections').selectAll('path') .attr('d', this.arcs.sections) From d035a588fbc659550b1f255af263427441ff12bd Mon Sep 17 00:00:00 2001 From: Gayan Sandamal Date: Tue, 3 Sep 2024 16:38:39 +0530 Subject: [PATCH 11/11] Optional chaining fix --- ui/src/widgets/ui-gauge/types/UIGaugeDial.vue | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ui/src/widgets/ui-gauge/types/UIGaugeDial.vue b/ui/src/widgets/ui-gauge/types/UIGaugeDial.vue index 2abfde6bf..dbccaea03 100644 --- a/ui/src/widgets/ui-gauge/types/UIGaugeDial.vue +++ b/ui/src/widgets/ui-gauge/types/UIGaugeDial.vue @@ -257,7 +257,7 @@ export default { this.svg.select('#sections').selectAll('path') .attr('d', this.arcs.sections) .attr('transform', transform) - .style('fill', (d) => d.color) + .style('fill', (d) => d?.color) // update needle const needleMask = this.svg.select('#needle-mask')