Bladeren bron

refactoring the format & delta_format

namnguyen 11 maanden geleden
bovenliggende
commit
95c19d18fe
2 gewijzigde bestanden met toevoegingen van 96 en 73 verwijderingen
  1. 7 7
      frontend/taipy-gui/src/components/Taipy/Metric.tsx
  2. 89 66
      frontend/taipy-gui/src/utils/formatConversion.ts

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

@@ -14,7 +14,7 @@
 import React, {CSSProperties, lazy, Suspense, useMemo} from 'react';
 import {Data} from "plotly.js";
 import {useClassNames, useDynamicJsonProperty, useDynamicProperty} from "../../utils/hooks";
-import {extractPrefix, extractSuffix, extractFormatSpecifier} from "../../utils/formatConversion";
+import {extractPrefix, extractSuffix, sprintfToD3Converter} from "../../utils/formatConversion";
 import {TaipyBaseProps, TaipyHoverProps} from "./utils";
 import Box from "@mui/material/Box";
 import Skeleton from "@mui/material/Skeleton";
@@ -67,15 +67,15 @@ const Metric = (props: MetricProps) => {
                 type: "indicator",
                 mode: "gauge" + (showValue ? "+number" : "") + (delta !== undefined ? "+delta" : ""),
                 number: {
-                    prefix: extractPrefix(props.format),
-                    suffix: extractSuffix(props.format),
-                    valueformat: extractFormatSpecifier(props.format),
+                    prefix: extractPrefix(props.format !== undefined ? props.format : ""),
+                    suffix: extractSuffix(props.format !== undefined ? props.format : ""),
+                    valueformat: sprintfToD3Converter(props.format !== undefined ? props.format : ""),
                 },
                 delta: {
                     reference: typeof value === 'number' && typeof delta === 'number' ? value - delta : undefined,
-                    prefix: extractPrefix(props.deltaFormat),
-                    suffix: extractSuffix(props.deltaFormat),
-                    valueformat: extractFormatSpecifier(props.deltaFormat)
+                    prefix: extractPrefix(props.deltaFormat !== undefined ? props.deltaFormat : ""),
+                    suffix: extractSuffix(props.deltaFormat !== undefined ? props.deltaFormat : ""),
+                    valueformat: sprintfToD3Converter(props.deltaFormat !== undefined ? props.deltaFormat : "")
                 },
                 gauge: {
                     axis: {

+ 89 - 66
frontend/taipy-gui/src/utils/formatConversion.ts

@@ -12,86 +12,109 @@
  */
 
 /**
- * Convert sprintf-like format string to D3 format string.
- *
- * @param format - The sprintf-like format string.
- * @returns The converted D3 format string or undefined if an error occurs.
+ * Regular expressions used for parsing sprintf format strings.
  */
-const sprintfToD3Converter = (format: string) => {
-    /**
-     * Helper function to handle precision formatting.
-     *
-     * @param precision - The precision part of the format string.
-     * @param specifier - The type of formatting.
-     * @returns The D3 precision format string.
-     */
-    const precisionFormat = (precision: string | undefined, specifier: string) => {
-        // Default to precision of 2 if not specified
-        return "." + (precision?.slice(1) ?? "2") + specifier;
-    }
+const re = {
+    text: /^[^\x25]+/,                         // Matches non-placeholder text
+    modulo: /^\x25{2}/,                        // Matches the '%%' escape sequence
+    placeholder: /^\x25?(?:\.(\d+))?([b-giostuvxX])/, // Matches placeholders
+};
 
-        return format?.replace(/%([0-9]*)([.][0-9]+)?([bdieufgoxX])/g, (match, width, precision, type) => {
-            console.log(`Match: ${match}, Width: ${width}, Precision: ${precision}, Type: ${type}`)
-            switch (type) {
-                case "b":
-                case "d":
-                case "i":
-                case "e":
-                case "o":
-                case "x":
-                case "X":
-                    return type;
-                case "f":
-                    return precisionFormat(precision, "f");
-                case "g":
-                    return precisionFormat(precision, "g");
-                case "u":
-                    return "("
-                default:
-                    return "";
+/**
+ * Parses a sprintf format string and returns a parse tree.
+ * @param fmt The sprintf format string.
+ * @returns The parse tree representing the structure of the format string.
+ */
+const sprintf_parse = (fmt: string) => {
+    let _fmt = fmt;
+    let match;
+    const parse_tree = [];
+
+    while (_fmt) {
+        if ((match = re.text.exec(_fmt)) !== null) {
+            // Non-placeholder text
+            parse_tree.push(match[0]);
+        } else if ((match = re.modulo.exec(_fmt)) !== null) {
+            // '%%' escape sequence
+            parse_tree.push('%');
+        } else if ((match = re.placeholder.exec(_fmt)) !== null) {
+            // Placeholder
+            if (match && match[0]) {
+                parse_tree.push({
+                    placeholder: match[0],
+                });
             }
-        });
+        }
+
+        if (match) {
+            _fmt = _fmt.substring(match[0].length);
+        }
+    }
+
+    return parse_tree;
 }
 
 /**
- * Extracts the prefix from the format string.
- * @param format - The format string.
- * @returns The extracted prefix, or undefined if the format is undefined.
+ * Converts sprintf format string to a D3 format string.
+ * @param format The sprintf format string.
+ * @returns The D3 format string.
  */
-export const extractPrefix = (format: string | undefined): string | undefined => {
-    if (format === undefined) {
-        return undefined;
+export const sprintfToD3Converter = (format: string) => {
+    const precisionFormat = (precision: string | undefined, specifier: string) => {
+        // Default to precision of 2 if not specified
+        return "." + (precision?.slice(1) ?? "2") + specifier;
+    }
+
+    const sprintf_fmt_arr = sprintf_parse(format);
+    const objectIndex = sprintf_fmt_arr.findIndex((element) => typeof element === 'object');
+    let placeholderValue;
+
+    if (typeof sprintf_fmt_arr[objectIndex] === 'object' && sprintf_fmt_arr[objectIndex] !== null) {
+        placeholderValue = (sprintf_fmt_arr[objectIndex] as { placeholder: string }).placeholder;
     }
-        const PREFIX_MATCH_REGEX: RegExp = /.*?(?=%)/;
-        return format.match(PREFIX_MATCH_REGEX)?.[0] ?? "";
+
+    return placeholderValue?.replace(/%([0-9]*)([.][0-9]+)?([bdieufgoxX])/g, (match, width, precision, type) => {
+        switch (type) {
+            case "b":
+            case "d":
+            case "e":
+            case "o":
+            case "x":
+            case "X":
+                return type;
+            case "i":
+                return "d";
+            case "f":
+                return precisionFormat(precision, "f");
+            case "g":
+                return precisionFormat(precision, "g");
+            case "u":
+                return "("
+            default:
+                return "";
+        }
+    });
 }
 
 /**
- * Extracts the suffix from the format string.
- * @param format - The format string.
- * @returns The extracted suffix, or undefined if the format is undefined.
+ * Extracts the prefix from a sprintf format string.
+ * @param format The sprintf format string.
+ * @returns The prefix.
  */
-export const extractSuffix = (format: string | undefined): string | undefined => {
-    if (format === undefined) {
-        return undefined;
-    }
-        const SURFIX_MATCH_REGEX: RegExp = /(?<=[bdieufgsxX])./;
-        return format.match(SURFIX_MATCH_REGEX)?.[0] ?? "";
+export const extractPrefix = (format: string) => {
+    const sprintf_fmt_arr = sprintf_parse(format);
+    const objectIndex = sprintf_fmt_arr.findIndex((element) => typeof element === 'object');
+    return sprintf_fmt_arr.slice(0, objectIndex).join('');
 }
 
 /**
- * Extracts the format specifier from the input string.
- * The input string is expected to be in sprintf format.
- * The function returns the format specifier (one of 'b', 'd', 'i', 'e', 'u', 'f', 'g', 'o', 'x', 'X') if it exists, or undefined otherwise.
- * @param input - The input string in sprintf format.
- * @returns The extracted format specifier, or undefined if no specifier is found or if the input is undefined.
+ * Extracts the suffix from a sprintf format string.
+ * @param format The sprintf format string.
+ * @returns The suffix.
  */
-export const extractFormatSpecifier = (input: string | undefined): string | undefined => {
-    if (input === undefined) {
-        return undefined;
-    }
-        const regex: RegExp = /%.*\.?[bdieufgoxX]/;
-        const match = input.match(regex);
-        const format = match ? match[0] : undefined;
-        return format ? sprintfToD3Converter(format) : undefined;
+export const extractSuffix = (format: string) => {
+    const sprintf_fmt_arr = sprintf_parse(format);
+    const objectIndex = sprintf_fmt_arr.findIndex((element) => typeof element === 'object');
+    return sprintf_fmt_arr.slice(objectIndex + 1).join('');
 }
+