@@ -91,6 +94,7 @@ export function Gauge({ value, min, max, precision, unit, label }: GaugeProps) {
// fills and the active controls do.
style={{
pathLength: fraction,
+ opacity: drawn,
filter: "drop-shadow(0 0 4px var(--primary))",
}}
fill="none"
diff --git a/frontend/src/components/Dashboard/ui/material/Data.tsx b/frontend/src/components/Dashboard/ui/material/Data.tsx
index ce1911d..86b0cd2 100644
--- a/frontend/src/components/Dashboard/ui/material/Data.tsx
+++ b/frontend/src/components/Dashboard/ui/material/Data.tsx
@@ -62,6 +62,9 @@ export function Gauge({ value, min, max, precision, unit, label }: GaugeProps) {
? 0
: Math.min(1, Math.max(0, (value - min) / (max - min || 1))),
)
+ // At the minimum the reading is a zero-length dash, and its round caps would
+ // still paint a dot on the dial. Nothing reads there, so nothing is drawn.
+ const drawn = useTransform(fraction, (at) => (at > 0 ? 1 : 0))
const { label: reading, numeric } = useAnimatedNumber(value, precision)
return (
@@ -84,7 +87,7 @@ export function Gauge({ value, min, max, precision, unit, label }: GaugeProps) {
fraction itself. */}
`${flowName}.${name}`
/** Every tile the dashboard carries, including the deliberately unbound one. */
-const TILES = 9
+const TILES = 11
test.use({ storageState: "playwright/.auth/user.json" })
@@ -58,6 +58,7 @@ test.beforeAll(async ({ browser }) => {
{ name: "mode", dtype: "str" },
{ name: "lamp", dtype: "bool" },
{ name: "setpoint", dtype: "float" },
+ { name: "idle", dtype: "float" },
],
},
],
@@ -76,6 +77,7 @@ test.beforeAll(async ({ browser }) => {
await publish(page, w("grid"), 20)
await publish(page, w("condition"), "sun")
await publish(page, w("setpoint"), 21.5)
+ await publish(page, w("idle"), 0)
await publish(page, w("days"), [
{ label: "Mon", icon: "sun", value: "21°" },
{ label: "Tue", icon: "cloudy", value: "18°" },
@@ -197,6 +199,14 @@ test.beforeAll(async ({ browser }) => {
unit: "°C",
},
},
+ {
+ // At its minimum, where a gauge draws no reading at all.
+ id: "idle",
+ type: "gauge",
+ title: "Idle",
+ layout: { lg: { x: 4, y: 6, w: 2, h: 2 } },
+ config: { message: w("idle"), dtype: "float", min: 0, max: 100 },
+ },
{
id: "trend",
type: "chart",
@@ -716,6 +726,10 @@ for (const scheme of ["light", "dark"] as const) {
// Every widget still draws, whichever set is asked to draw it.
await expect(page.getByTestId("widget-frame")).toHaveCount(TILES)
await expect(loadTile(page).getByTestId("bar-row")).toHaveCount(2)
+ // The reading is a zero-length dash at the minimum, and round caps
+ // would still paint it as a dot at either end of the dial.
+ const dial = page.getByRole("img", { name: /^Idle:/ })
+ await expect(dial.locator("path").nth(1)).toHaveCSS("opacity", "0")
await page.screenshot({
path: `screenshots/widgets/${scheme}-${look}.png`,