Quellcode durchsuchen

add bar_color prop to Metric component

namnguyen vor 9 Monaten
Ursprung
Commit
00844cab4f

+ 74 - 80
frontend/taipy-gui/src/components/Taipy/Metric.tsx

@@ -11,33 +11,33 @@
  * specific language governing permissions and limitations under the License.
  */
 
-import React, {CSSProperties, lazy, Suspense, useMemo} from 'react';
-import {Data, Delta, Layout} from "plotly.js";
+import React, { CSSProperties, lazy, Suspense, useMemo } from "react";
+import { Data, Delta, Layout } from "plotly.js";
 import Box from "@mui/material/Box";
 import Skeleton from "@mui/material/Skeleton";
 import Tooltip from "@mui/material/Tooltip";
-import {useTheme} from "@mui/material";
-import {useClassNames, useDynamicJsonProperty, useDynamicProperty} from "../../utils/hooks";
-import {extractPrefix, extractSuffix, sprintfToD3Converter} from "../../utils/formatConversion";
-import {TaipyBaseProps, TaipyHoverProps} from "./utils";
-import {darkThemeTemplate} from "../../themes/darkThemeTemplate";
+import { useTheme } from "@mui/material";
+import { useClassNames, useDynamicJsonProperty, useDynamicProperty } from "../../utils/hooks";
+import { extractPrefix, extractSuffix, sprintfToD3Converter } from "../../utils/formatConversion";
+import { TaipyBaseProps, TaipyHoverProps } from "./utils";
+import { darkThemeTemplate } from "../../themes/darkThemeTemplate";
 
 const Plot = lazy(() => import("react-plotly.js"));
 
 interface MetricProps extends TaipyBaseProps, TaipyHoverProps {
-    title?: string
-    type?: string
-    min?: number
-    max?: number
-    value?: number
-    defaultValue?: number
-    delta?: number
-    defaultDelta?: number
-    deltaColor?: string
-    negativeDeltaColor?: string
-    threshold?: number
-    defaultThreshold?: number
-    testId?: string
+    title?: string;
+    type?: string;
+    min?: number;
+    max?: number;
+    value?: number;
+    defaultValue?: number;
+    delta?: number;
+    defaultDelta?: number;
+    deltaColor?: string;
+    negativeDeltaColor?: string;
+    threshold?: number;
+    defaultThreshold?: number;
+    testId?: string;
     defaultLayout?: string;
     layout?: string;
     defaultStyle?: string;
@@ -48,25 +48,20 @@ interface MetricProps extends TaipyBaseProps, TaipyHoverProps {
     format?: string;
     deltaFormat?: string;
     colorMap?: string;
+    barColor?: string;
     template?: string;
     template_Dark_?: string;
     template_Light_?: string;
 }
 
 const emptyLayout = {} as Partial<Layout>;
-const defaultStyle = {position: "relative", display: "inline-block"};
+const defaultStyle = { position: "relative", display: "inline-block" };
 
 const Metric = (props: MetricProps) => {
-    const {
-        width = "100%",
-        height,
-        showValue = true,
-        deltaColor,
-        negativeDeltaColor
-    } = props;
-    const value = useDynamicProperty(props.value, props.defaultValue, 0)
-    const threshold = useDynamicProperty(props.threshold, props.defaultThreshold, undefined)
-    const delta = useDynamicProperty(props.delta, props.defaultDelta, undefined)
+    const { width = "100%", height, showValue = true, deltaColor, negativeDeltaColor } = props;
+    const value = useDynamicProperty(props.value, props.defaultValue, 0);
+    const threshold = useDynamicProperty(props.threshold, props.defaultThreshold, undefined);
+    const delta = useDynamicProperty(props.delta, props.defaultDelta, undefined);
     const className = useClassNames(props.libClassName, props.dynamicClassName, props.className);
     const baseLayout = useDynamicJsonProperty(props.layout, props.defaultLayout || "", emptyLayout);
     const hover = useDynamicProperty(props.hoverText, props.defaultHoverText, undefined);
@@ -75,31 +70,42 @@ const Metric = (props: MetricProps) => {
     const colorMap = useMemo(() => {
         try {
             const obj = props.colorMap ? JSON.parse(props.colorMap) : null;
-            if (obj && typeof obj === 'object') {
+            if (obj && typeof obj === "object") {
                 const keys = Object.keys(obj);
-                return keys.sort((a, b) => Number(a) - Number(b)).map((key, index) => {
-                    const nextKey = keys[index + 1] !== undefined ? Number(keys[index + 1]) : props.max || 100;
-                    return {range: [Number(key), nextKey], color: obj[key]};
-                }).filter(item => item.color !== null)
+                return keys
+                    .sort((a, b) => Number(a) - Number(b))
+                    .map((key, index) => {
+                        const nextKey = keys[index + 1] !== undefined ? Number(keys[index + 1]) : props.max || 100;
+                        return { range: [Number(key), nextKey], color: obj[key] };
+                    })
+                    .filter((item) => item.color !== null);
             }
         } catch (e) {
             console.info(`Error parsing color_map value (metric).\n${(e as Error).message || e}`);
         }
         return undefined;
-    }, [props.colorMap, props.max])
+    }, [props.colorMap, props.max]);
 
     const data = useMemo(() => {
-        const mode = (props.type === "none") ? [] : ["gauge"];
+        const mode = props.type === "none" ? [] : ["gauge"];
         showValue && mode.push("number");
-        (delta !== undefined) && mode.push("delta");
-        const deltaIncreasing = deltaColor ? {
-            color: deltaColor == "invert" ? "#FF4136" : deltaColor } : undefined
-        const deltaDecreasing = deltaColor == "invert" ? {
-                color: "#3D9970"
-            } : negativeDeltaColor ? { color: negativeDeltaColor } : undefined;
+        delta !== undefined && mode.push("delta");
+        const deltaIncreasing = deltaColor
+            ? {
+                  color: deltaColor == "invert" ? "#FF4136" : deltaColor,
+              }
+            : undefined;
+        const deltaDecreasing =
+            deltaColor == "invert"
+                ? {
+                      color: "#3D9970",
+                  }
+                : negativeDeltaColor
+                  ? { color: negativeDeltaColor }
+                  : undefined;
         return [
             {
-                domain: {x: [0, 1], y: [0, 1]},
+                domain: { x: [0, 1], y: [0, 1] },
                 value: value,
                 type: "indicator",
                 mode: mode.join("+"),
@@ -109,32 +115,32 @@ const Metric = (props: MetricProps) => {
                     valueformat: sprintfToD3Converter(props.format),
                 },
                 delta: {
-                    reference: typeof value === 'number' && typeof delta === 'number' ? value - delta : undefined,
+                    reference: typeof value === "number" && typeof delta === "number" ? value - delta : undefined,
                     prefix: extractPrefix(props.deltaFormat),
                     suffix: extractSuffix(props.deltaFormat),
                     valueformat: sprintfToD3Converter(props.deltaFormat),
                     increasing: deltaIncreasing,
-                    decreasing: deltaDecreasing
-
+                    decreasing: deltaDecreasing,
                 } as Partial<Delta>,
                 gauge: {
                     axis: {
-                        range: [
-                            props.min || 0,
-                            props.max || 100
-                        ]
+                        range: [props.min || 0, props.max || 100],
+                    },
+                    bar: {
+                        color: props.barColor,
                     },
                     steps: colorMap,
                     shape: props.type === "linear" ? "bullet" : "angular",
                     threshold: {
-                        line: {color: "red", width: 4},
+                        line: { color: "red", width: 4 },
                         thickness: 0.75,
-                        value: threshold
-                    }
+                        value: threshold,
+                    },
                 },
-            }
+            },
         ] as Data[];
     }, [
+        props.barColor,
         props.format,
         props.deltaFormat,
         props.min,
@@ -146,21 +152,21 @@ const Metric = (props: MetricProps) => {
         negativeDeltaColor,
         delta,
         threshold,
-        colorMap
+        colorMap,
     ]);
 
     const style = useMemo(
         () =>
             height === undefined
-                ? ({...defaultStyle, width: width} as CSSProperties)
-                : ({...defaultStyle, width: width, height: height} as CSSProperties),
+                ? ({ ...defaultStyle, width: width } as CSSProperties)
+                : ({ ...defaultStyle, width: width, height: height } as CSSProperties),
         [height, width]
     );
 
-    const skelStyle = useMemo(() => ({...style, minHeight: "7em"}), [style]);
+    const skelStyle = useMemo(() => ({ ...style, minHeight: "7em" }), [style]);
 
     const layout = useMemo(() => {
-        const layout = {...baseLayout};
+        const layout = { ...baseLayout };
         let template = undefined;
         try {
             const tpl = props.template && JSON.parse(props.template);
@@ -170,7 +176,7 @@ const Metric = (props: MetricProps) => {
                         ? JSON.parse(props.template_Dark_)
                         : darkTemplate
                     : props.template_Light_ && JSON.parse(props.template_Light_);
-            template = tpl ? (tplTheme ? {...tpl, ...tplTheme} : tpl) : tplTheme ? tplTheme : undefined;
+            template = tpl ? (tplTheme ? { ...tpl, ...tplTheme } : tpl) : tplTheme ? tplTheme : undefined;
         } catch (e) {
             console.info(`Error while parsing Metric.template\n${(e as Error).message || e}`);
         }
@@ -183,34 +189,22 @@ const Metric = (props: MetricProps) => {
         }
 
         return layout as Partial<Layout>;
-    }, [
-        props.title,
-        props.template,
-        props.template_Dark_,
-        props.template_Light_,
-        theme.palette.mode,
-        baseLayout,
-    ])
+    }, [props.title, props.template, props.template_Dark_, props.template_Light_, theme.palette.mode, baseLayout]);
 
     return (
         <Tooltip title={hover || ""}>
             <Box data-testid={props.testId} className={className}>
-                <Suspense fallback={<Skeleton key="skeleton" sx={skelStyle}/>}>
-                    <Plot
-                        data={data}
-                        layout={layout}
-                        style={style}
-                        useResizeHandler
-                    />
+                <Suspense fallback={<Skeleton key="skeleton" sx={skelStyle} />}>
+                    <Plot data={data} layout={layout} style={style} useResizeHandler />
                 </Suspense>
             </Box>
         </Tooltip>
     );
-}
+};
 
 export default Metric;
 
-const {colorscale, colorway, font} = darkThemeTemplate.layout;
+const { colorscale, colorway, font } = darkThemeTemplate.layout;
 const darkTemplate = {
     layout: {
         colorscale,
@@ -218,4 +212,4 @@ const darkTemplate = {
         font,
         paper_bgcolor: "rgb(31,47,68)",
     },
-}
+};

+ 1 - 0
taipy/gui/_renderers/factory.py

@@ -361,6 +361,7 @@ class _Factory:
                 ("show_value", PropertyType.boolean, True),
                 ("format", PropertyType.string),
                 ("delta_format", PropertyType.string),
+                ("bar_color", PropertyType.string),
                 ("color_map", PropertyType.dict),
                 ("hover_text", PropertyType.dynamic_string),
                 ("template", PropertyType.dict),

+ 5 - 0
taipy/gui/viselements.json

@@ -1221,6 +1221,11 @@
                         "type": "str",
                         "doc": "The format to use when displaying the delta value.<br/>This uses the <code>printf</code> syntax."
                     },
+                    {
+                        "name": "bar_color",
+                        "type": "str",
+                        "doc": "The color of the bar."
+                    },
                     {
                         "name": "color_map",
                         "type": "dict",