diff --git a/app/components/InstrumentPage.test.ts b/app/components/InstrumentPage.test.ts index 90c200d..e7630ee 100644 --- a/app/components/InstrumentPage.test.ts +++ b/app/components/InstrumentPage.test.ts @@ -49,7 +49,7 @@ test("toPrecision truncates block if it has precision", () => { precision: precision, }; expect(toPrecision(aBlock, originalValue)).toBe( - originalValue.toPrecision(precision), + originalValue.toFixed(precision), ); }); diff --git a/app/components/InstrumentPage.tsx b/app/components/InstrumentPage.tsx index c5c67dd..24455aa 100644 --- a/app/components/InstrumentPage.tsx +++ b/app/components/InstrumentPage.tsx @@ -15,7 +15,10 @@ import { IfcPVWSMessage, IfcPVWSRequest, } from "@/app/types"; -import { findPVByAddress } from "@/app/components/PVutils"; +import { + findPVByAddress, + ExponentialOnThresholdFormat, +} from "@/app/components/PVutils"; import CheckToggle from "@/app/components/CheckToggle"; let lastUpdate: string = ""; @@ -91,8 +94,8 @@ export function toPrecision( block: IfcBlock, pvVal: number | string, ): string | number { - return block.precision && typeof pvVal == "number" - ? pvVal.toPrecision(block.precision) + return block.precision + ? ExponentialOnThresholdFormat(pvVal, block.precision) : pvVal; } diff --git a/app/components/PVutils.test.ts b/app/components/PVutils.test.ts index efa7f07..209916c 100644 --- a/app/components/PVutils.test.ts +++ b/app/components/PVutils.test.ts @@ -2,6 +2,7 @@ import { IfcPV } from "@/app/types"; import { findPVByAddress, findPVByHumanReadableName, + ExponentialOnThresholdFormat, } from "@/app/components/PVutils"; test("findPVByAddress finds a PV and returns it", () => { @@ -46,3 +47,123 @@ test("findPVByHumanReadableName does not find a nonexistant PV and returns undef expect(result).toBe(undefined); }); + +// Test of ExponentialOnThresholdFormat ported from ibex_gui Java code +test("GIVEN value 0.1 which is above lower threshold WHEN formatting with precision 3 THEN no exponential notation used", () => { + expect(ExponentialOnThresholdFormat(0.1)).toBe("0.100"); +}); + +test("GIVEN negative value 0.1 which is above lower threshold WHEN formatting with precision 3 THEN no exponential notation used", () => { + expect(ExponentialOnThresholdFormat(-0.1)).toBe("-0.100"); +}); + +test("GIVEN value 0.01 which is above lower threshold WHEN formatting with precision 3 THEN no exponential notation used", () => { + expect(ExponentialOnThresholdFormat(0.01)).toBe("0.010"); +}); + +test("GIVEN value equal to lower threshold WHEN formatting with precision 3 THEN no exponential notation used", () => { + expect(ExponentialOnThresholdFormat(0.001)).toBe("0.001"); +}); + +test("GIVEN negative value equal to lower threshold WHEN formatting with precision 3 THEN no exponential notation used", () => { + expect(ExponentialOnThresholdFormat(-0.001)).toBe("-0.001"); +}); + +test("GIVEN value above lower threshold with extra fractioanl digits WHEN formatting with precision 3 THEN no exponential notation used and some digits are lost", () => { + expect(ExponentialOnThresholdFormat(0.01234)).toBe("0.012"); +}); + +test("GIVEN value above lower threshold with integer part WHEN formatting with precision 5 THEN no exponential notation used", () => { + expect(ExponentialOnThresholdFormat(1234.56, 5)).toBe("1234.56000"); +}); + +test("GIVEN value above lower threshold with integer part and extra fractional digits WHEN formatting with precision 3 THEN no exponential notation used", () => { + expect(ExponentialOnThresholdFormat(12.5678)).toBe("12.568"); +}); + +test("GIVEN value below lower threshold WHEN formatting with precision 3 THEN exponential notation used", () => { + expect(ExponentialOnThresholdFormat(0.0009)).toBe("9.000E-4"); +}); + +test("GIVEN very small value WHEN formatting with precision 5 THEN exponential notation used", () => { + expect(ExponentialOnThresholdFormat(0.000000001234567, 5)).toBe("1.23457E-9"); +}); + +test("GIVEN very small negative value WHEN formatting with precision 5 THEN exponential notation used", () => { + expect(ExponentialOnThresholdFormat(-0.000000001234567, 5)).toBe( + "-1.23457E-9", + ); +}); + +test("GIVEN value just below higher threshold WHEN formatting with precision 3 THEN no exponential notation used", () => { + expect(ExponentialOnThresholdFormat(999999.1234)).toBe("999999.123"); +}); + +test("GIVEN negative value just below higher threshold WHEN formatting with precision 3 THEN no exponential notation used", () => { + expect(ExponentialOnThresholdFormat(-999999.1234)).toBe("-999999.123"); +}); + +// TypeScript does not have separate integer/float types - for integers never use exponential so change test a bit +test("GIVEN value equal to higher threshold WHEN formatting with precision 3 THEN exponential notation used", () => { + //expect(ExponentialOnThresholdFormat(1000000)).toBe("1.000E6"); + expect(ExponentialOnThresholdFormat(1000000.1)).toBe("1.000E6"); +}); + +test("GIVEN negative value equal to higher threshold WHEN formatting with precision 3 THEN exponential notation used", () => { + expect(ExponentialOnThresholdFormat(-1000000.1)).toBe("-1.000E6"); +}); + +test("GIVEN value above higher threshold WHEN formatting with precision 5 THEN exponential notation used", () => { + //expect(ExponentialOnThresholdFormat(123456789, 5)).toBe("1.23457E8"); + expect(ExponentialOnThresholdFormat(123456789.1, 5)).toBe("1.23457E8"); +}); + +test("GIVEN negative value above higher threshold WHEN formatting with precision 5 THEN exponential notation used", () => { + //expect(ExponentialOnThresholdFormat(-123456789, 5)).toBe("-1.23457E8"); + expect(ExponentialOnThresholdFormat(-123456789.1, 5)).toBe("-1.23457E8"); +}); + +// TypeScript does not have separate integer/float types - so ignore next two tests. +//it("GIVEN value 0 WHEN formatting THEN no exponential notation used", () => { +// expect(ExponentialOnThresholdFormat(0)).toBe("0.000"); +//}); +// +//it("GIVEN negative value 0 WHEN formatting THEN no exponential notation used", () => { +// expect(ExponentialOnThresholdFormat(-0)).toBe("0.000"); +//}); + +test("GIVEN integer below higher threshold WHEN formatting THEN no exponential notation used", () => { + expect(ExponentialOnThresholdFormat(13)).toBe("13"); +}); + +test("GIVEN negative integer below higher threshold WHEN formatting THEN no exponential notation used", () => { + expect(ExponentialOnThresholdFormat(-13)).toBe("-13"); +}); + +test("GIVEN integer just below higher threshold WHEN formatting THEN no exponential notation used", () => { + expect(ExponentialOnThresholdFormat(999999)).toBe("999999"); +}); + +test("GIVEN integer equal to higher threshold WHEN formatting THEN no exponential notation used", () => { + expect(ExponentialOnThresholdFormat(1000000)).toBe("1000000"); +}); + +test("GIVEN negative integer equal to higher threshold WHEN formatting THEN no exponential notation used", () => { + expect(ExponentialOnThresholdFormat(-1000000)).toBe("-1000000"); +}); + +test("GIVEN integer above higher threshold WHEN formatting THEN no exponential notation used", () => { + expect(ExponentialOnThresholdFormat(123456789)).toBe("123456789"); +}); + +test("GIVEN negative integer above higher threshold WHEN formatting THEN no exponential notation used", () => { + expect(ExponentialOnThresholdFormat(-123456789)).toBe("-123456789"); +}); + +test("GIVEN integer equal to 0 WHEN formatting THEN no exponential notation used", () => { + expect(ExponentialOnThresholdFormat(0)).toBe("0"); +}); + +test("GIVEN negative integer equal to 0 WHEN formatting THEN no exponential notation used", () => { + expect(ExponentialOnThresholdFormat(-0)).toBe("0"); +}); diff --git a/app/components/PVutils.ts b/app/components/PVutils.ts index d231121..7600649 100644 --- a/app/components/PVutils.ts +++ b/app/components/PVutils.ts @@ -19,3 +19,30 @@ export function findPVByAddress( ): IfcPV | undefined { return arr.find((b: IfcPV) => b.pvaddress == address); } + +/** + * Formats a given PV value input such that above or below a threshold value, + * it uses scientific (exponential) notation, matching behaviour of ibex_gui + */ +export function ExponentialOnThresholdFormat( + value: string | number, + precision: number = 3, +) { + var nValue: number = value == undefined ? NaN : +value; + if (isNaN(nValue)) { + return value; + } else { + if (nValue == 0) { + return "0"; + } else if (Number.isInteger(nValue)) { + return nValue.toString(); + } else if (Math.abs(nValue) < 0.001 || Math.abs(nValue) >= 1000000) { + return nValue + .toExponential(precision) + .replace("e+", "E") + .replace("e", "E"); + } else { + return nValue.toFixed(precision); + } + } +}