From ae813e96bb20ee878aacb79be4fff63f8865ff2f Mon Sep 17 00:00:00 2001 From: Jason Buss Date: Tue, 20 Jun 2023 15:16:43 -0600 Subject: [PATCH] feat(visualizations): add significant digit configuration --- .../src/components.d.ts | 20 +++++++++++++++++++ .../src/components/charts/common/types.ts | 1 + .../charts/sc-bar-chart/sc-bar-chart.tsx | 2 ++ .../charts/sc-line-chart/sc-line-chart.tsx | 2 ++ .../sc-scatter-chart/sc-scatter-chart.tsx | 2 ++ .../sc-status-timeline-overlay-row.tsx | 3 ++- .../sc-status-timeline-overlay.tsx | 2 ++ .../sc-status-timeline/sc-status-timeline.tsx | 3 +++ .../charts/sc-tooltip/sc-tooltip-row.tsx | 3 ++- .../charts/sc-tooltip/sc-tooltip-rows.tsx | 2 ++ .../charts/sc-tooltip/sc-tooltip.tsx | 2 ++ .../sc-webgl-base-chart.tsx | 2 ++ .../src/components/value/Value.tsx | 14 +++++++++++-- .../src/utils/number.ts | 8 +++----- 14 files changed, 57 insertions(+), 9 deletions(-) diff --git a/packages/iot-app-kit-visualizations/src/components.d.ts b/packages/iot-app-kit-visualizations/src/components.d.ts index 53cc87151..6b43d5f3e 100644 --- a/packages/iot-app-kit-visualizations/src/components.d.ts +++ b/packages/iot-app-kit-visualizations/src/components.d.ts @@ -43,6 +43,7 @@ export namespace Components { "movement"?: MovementConfig; "scale"?: ScaleConfig; "setViewport": (viewport: AppKitViewport, lastUpdatedBy?: string) => void; + "significantDigits"?: number; "size"?: MinimalSizeConfig; "trends": Trend[]; /** @@ -138,6 +139,7 @@ export namespace Components { "movement"?: MovementConfig; "scale"?: ScaleConfig; "setViewport": (viewport: AppKitViewport, lastUpdatedBy?: string) => void; + "significantDigits"?: number; "size"?: MinimalSizeConfig; "trends": Trend[]; /** @@ -182,6 +184,7 @@ export namespace Components { "movement"?: MovementConfig; "scale"?: ScaleConfig; "setViewport": (viewport: AppKitViewport, lastUpdatedBy?: string) => void; + "significantDigits"?: number; "size"?: MinimalSizeConfig; "trends": Trend[]; /** @@ -246,6 +249,7 @@ export namespace Components { "movement"?: MovementConfig; "scale"?: ScaleConfig; "setViewport": (viewport: AppKitViewport, lastUpdatedBy?: string) => void; + "significantDigits"?: number; "size"?: MinimalSizeConfig; /** * Chart API @@ -257,6 +261,7 @@ export namespace Components { "dataStreams": DataStream[]; "date": Date; "isEditing": boolean; + "precision"?: number; "size": SizeConfig; "thresholds": Threshold[]; "widgetId": string; @@ -267,6 +272,7 @@ export namespace Components { "isEditing": boolean; "label": string; "onNameChange": (name: string) => void; + "precision"?: number; "unit"?: string; "value"?: Primitive; "valueColor"?: string; @@ -292,6 +298,7 @@ export namespace Components { "dataContainer": HTMLElement | null; "dataStreams": DataStream[]; "maxDurationFromDate"?: number; + "precision"?: number; "showBlankTooltipRows": boolean; "showDataStreamColor": boolean; "size": SizeConfig; @@ -314,6 +321,7 @@ export namespace Components { "label": string; "point": DataPoint | undefined; "pointType": POINT_TYPE; + "precision"?: number; "resolution": number | undefined; "showDataStreamColor": boolean; "valueColor"?: string; @@ -321,6 +329,7 @@ export namespace Components { interface IotAppKitVisTooltipRows { "aggregationType"?: string; "dataStreams": DataStream[]; + "precision"?: number; "selectedDate": Date; "showDataStreamColor": boolean; "size": SizeConfig; @@ -388,6 +397,7 @@ export namespace Components { * Optionally hooks to integrate custom logic into the base chart */ "onUpdateLifeCycle"?: (viewport: ViewPortConfig) => void; + "precision"?: number; "renderLegend": (props: Legend.Props) => HTMLElement; "renderTooltip": (props: Tooltip.Props) => HTMLElement; "setViewport": (viewport: AppKitViewport, lastUpdatedBy?: string) => void; @@ -1296,6 +1306,7 @@ declare namespace LocalJSX { "movement"?: MovementConfig; "scale"?: ScaleConfig; "setViewport"?: (viewport: AppKitViewport, lastUpdatedBy?: string) => void; + "significantDigits"?: number; "size"?: MinimalSizeConfig; "trends"?: Trend[]; /** @@ -1391,6 +1402,7 @@ declare namespace LocalJSX { "movement"?: MovementConfig; "scale"?: ScaleConfig; "setViewport"?: (viewport: AppKitViewport, lastUpdatedBy?: string) => void; + "significantDigits"?: number; "size"?: MinimalSizeConfig; "trends"?: Trend[]; /** @@ -1435,6 +1447,7 @@ declare namespace LocalJSX { "movement"?: MovementConfig; "scale"?: ScaleConfig; "setViewport"?: (viewport: AppKitViewport, lastUpdatedBy?: string) => void; + "significantDigits"?: number; "size"?: MinimalSizeConfig; "trends"?: Trend[]; /** @@ -1499,6 +1512,7 @@ declare namespace LocalJSX { "movement"?: MovementConfig; "scale"?: ScaleConfig; "setViewport"?: (viewport: AppKitViewport, lastUpdatedBy?: string) => void; + "significantDigits"?: number; "size"?: MinimalSizeConfig; /** * Chart API @@ -1511,6 +1525,7 @@ declare namespace LocalJSX { "date": Date; "isEditing": boolean; "onWidgetUpdated"?: (event: CustomEvent) => void; + "precision"?: number; "size": SizeConfig; "thresholds": Threshold[]; "widgetId": string; @@ -1521,6 +1536,7 @@ declare namespace LocalJSX { "isEditing": boolean; "label": string; "onNameChange": (name: string) => void; + "precision"?: number; "unit"?: string; "value"?: Primitive; "valueColor"?: string; @@ -1546,6 +1562,7 @@ declare namespace LocalJSX { "dataContainer"?: HTMLElement | null; "dataStreams": DataStream[]; "maxDurationFromDate"?: number; + "precision"?: number; "showBlankTooltipRows"?: boolean; "showDataStreamColor"?: boolean; "size": SizeConfig; @@ -1568,6 +1585,7 @@ declare namespace LocalJSX { "label": string; "point": DataPoint | undefined; "pointType": POINT_TYPE; + "precision"?: number; "resolution": number | undefined; "showDataStreamColor": boolean; "valueColor"?: string; @@ -1575,6 +1593,7 @@ declare namespace LocalJSX { interface IotAppKitVisTooltipRows { "aggregationType"?: string; "dataStreams": DataStream[]; + "precision"?: number; "selectedDate": Date; "showDataStreamColor"?: boolean; "size": SizeConfig; @@ -1643,6 +1662,7 @@ declare namespace LocalJSX { */ "onUpdateLifeCycle"?: (viewport: ViewPortConfig) => void; "onWidgetUpdated"?: (event: CustomEvent) => void; + "precision"?: number; "renderLegend"?: (props: Legend.Props) => HTMLElement; "renderTooltip"?: (props: Tooltip.Props) => HTMLElement; "setViewport"?: (viewport: AppKitViewport, lastUpdatedBy?: string) => void; diff --git a/packages/iot-app-kit-visualizations/src/components/charts/common/types.ts b/packages/iot-app-kit-visualizations/src/components/charts/common/types.ts index 3eb6ef941..4b8eaa03f 100644 --- a/packages/iot-app-kit-visualizations/src/components/charts/common/types.ts +++ b/packages/iot-app-kit-visualizations/src/components/charts/common/types.ts @@ -195,6 +195,7 @@ export namespace Tooltip { trendResults: TrendResult[]; visualizesAlarms: boolean; aggregationType?: string; + precision?: number; } } diff --git a/packages/iot-app-kit-visualizations/src/components/charts/sc-bar-chart/sc-bar-chart.tsx b/packages/iot-app-kit-visualizations/src/components/charts/sc-bar-chart/sc-bar-chart.tsx index 39e0a88ed..ee20db185 100644 --- a/packages/iot-app-kit-visualizations/src/components/charts/sc-bar-chart/sc-bar-chart.tsx +++ b/packages/iot-app-kit-visualizations/src/components/charts/sc-bar-chart/sc-bar-chart.tsx @@ -62,6 +62,7 @@ export class ScBarChart implements ChartConfig { @Prop() axis?: Axis.Options; @Prop() messageOverrides?: MessageOverrides; @Prop() aggregationType?: string; + @Prop() significantDigits?: number; /** Status */ @Prop() isEditing: boolean = false; @@ -105,6 +106,7 @@ export class ScBarChart implements ChartConfig { aggregationType={this.aggregationType} visualizesAlarms={false} messageOverrides={this.messageOverrides} + precision={this.significantDigits} /> )} /> diff --git a/packages/iot-app-kit-visualizations/src/components/charts/sc-line-chart/sc-line-chart.tsx b/packages/iot-app-kit-visualizations/src/components/charts/sc-line-chart/sc-line-chart.tsx index 22beb0187..59213a4ad 100644 --- a/packages/iot-app-kit-visualizations/src/components/charts/sc-line-chart/sc-line-chart.tsx +++ b/packages/iot-app-kit-visualizations/src/components/charts/sc-line-chart/sc-line-chart.tsx @@ -61,6 +61,7 @@ export class ScLineChart implements ChartConfig { @Prop() messageOverrides?: MessageOverrides; @Prop() setViewport: (viewport: AppKitViewport, lastUpdatedBy?: string) => void; @Prop() aggregationType?: string; + @Prop() significantDigits?: number; /** Status */ @Prop() isEditing: boolean = false; @@ -103,6 +104,7 @@ export class ScLineChart implements ChartConfig { aggregationType={this.aggregationType} visualizesAlarms={false} messageOverrides={this.messageOverrides} + precision={this.significantDigits} /> )} /> diff --git a/packages/iot-app-kit-visualizations/src/components/charts/sc-scatter-chart/sc-scatter-chart.tsx b/packages/iot-app-kit-visualizations/src/components/charts/sc-scatter-chart/sc-scatter-chart.tsx index 8ee82f9cc..f226c5727 100644 --- a/packages/iot-app-kit-visualizations/src/components/charts/sc-scatter-chart/sc-scatter-chart.tsx +++ b/packages/iot-app-kit-visualizations/src/components/charts/sc-scatter-chart/sc-scatter-chart.tsx @@ -61,6 +61,7 @@ export class ScScatterChart implements ChartConfig { @Prop() messageOverrides?: MessageOverrides; @Prop() setViewport: (viewport: AppKitViewport, lastUpdatedBy?: string) => void; @Prop() aggregationType?: string; + @Prop() significantDigits?: number; /** Status */ @Prop() isEditing: boolean = false; @@ -103,6 +104,7 @@ export class ScScatterChart implements ChartConfig { aggregationType={this.aggregationType} visualizesAlarms={false} messageOverrides={this.messageOverrides} + precision={this.significantDigits} /> )} /> diff --git a/packages/iot-app-kit-visualizations/src/components/charts/sc-status-timeline/sc-status-timeline-overlay/sc-status-timeline-overlay-row.tsx b/packages/iot-app-kit-visualizations/src/components/charts/sc-status-timeline/sc-status-timeline-overlay/sc-status-timeline-overlay-row.tsx index ce2d7d298..6b547ba3b 100644 --- a/packages/iot-app-kit-visualizations/src/components/charts/sc-status-timeline/sc-status-timeline-overlay/sc-status-timeline-overlay-row.tsx +++ b/packages/iot-app-kit-visualizations/src/components/charts/sc-status-timeline/sc-status-timeline-overlay/sc-status-timeline-overlay-row.tsx @@ -17,6 +17,7 @@ export class ScStatusTimelineOverlayRow { @Prop() value?: Primitive; @Prop() icon?: StatusIcon; @Prop() unit?: string; + @Prop() precision?: number; render() { return [ @@ -30,7 +31,7 @@ export class ScStatusTimelineOverlayRow {
{this.icon && } - +
,
, diff --git a/packages/iot-app-kit-visualizations/src/components/charts/sc-status-timeline/sc-status-timeline-overlay/sc-status-timeline-overlay.tsx b/packages/iot-app-kit-visualizations/src/components/charts/sc-status-timeline/sc-status-timeline-overlay/sc-status-timeline-overlay.tsx index bc0a3d5fa..f9361e165 100644 --- a/packages/iot-app-kit-visualizations/src/components/charts/sc-status-timeline/sc-status-timeline-overlay/sc-status-timeline-overlay.tsx +++ b/packages/iot-app-kit-visualizations/src/components/charts/sc-status-timeline/sc-status-timeline-overlay/sc-status-timeline-overlay.tsx @@ -22,6 +22,7 @@ export class ScStatusTimelineOverlay { @Prop() date!: Date; @Prop() widgetId!: string; @Prop() isEditing!: boolean; + @Prop() precision?: number; /** Widget data stream names */ @State() names: NameValue[] = []; @@ -110,6 +111,7 @@ export class ScStatusTimelineOverlay { valueColor={valueColor} icon={error == null ? threshold && threshold.icon : StatusIcon.ERROR} onNameChange={(name: string) => this.onChangeLabel({ streamId: dataStream.id, name })} + precision={this.precision} /> ); })} diff --git a/packages/iot-app-kit-visualizations/src/components/charts/sc-status-timeline/sc-status-timeline.tsx b/packages/iot-app-kit-visualizations/src/components/charts/sc-status-timeline/sc-status-timeline.tsx index 8cfc09b05..377e81d4f 100644 --- a/packages/iot-app-kit-visualizations/src/components/charts/sc-status-timeline/sc-status-timeline.tsx +++ b/packages/iot-app-kit-visualizations/src/components/charts/sc-status-timeline/sc-status-timeline.tsx @@ -91,6 +91,7 @@ export class ScStatusTimeline implements ChartConfig { @Prop() alarms?: AlarmsConfig; @Prop() setViewport: (viewport: AppKitViewport, lastUpdatedBy?: string) => void; @Prop() aggregationType?: string; + @Prop() significantDigits?: number; @State() componentViewport: MinimalViewPortConfig; @@ -173,6 +174,7 @@ export class ScStatusTimeline implements ChartConfig { visualizesAlarms displaysNoDataPresentMsg={false} messageOverrides={this.messageOverrides} + precision={this.significantDigits} />
,
diff --git a/packages/iot-app-kit-visualizations/src/components/charts/sc-tooltip/sc-tooltip-row.tsx b/packages/iot-app-kit-visualizations/src/components/charts/sc-tooltip/sc-tooltip-row.tsx index 302736fc6..5d2918453 100644 --- a/packages/iot-app-kit-visualizations/src/components/charts/sc-tooltip/sc-tooltip-row.tsx +++ b/packages/iot-app-kit-visualizations/src/components/charts/sc-tooltip/sc-tooltip-row.tsx @@ -28,6 +28,7 @@ export class ScTooltipRow { @Prop() valueColor?: string = baseColor; @Prop() aggregationType?: string; @Prop() icon?: StatusIcon; + @Prop() precision?: number; render() { const isTrendPoint = this.pointType === POINT_TYPE.TREND; @@ -52,7 +53,7 @@ export class ScTooltipRow { {this.icon && } - + {this.resolution != null && (
diff --git a/packages/iot-app-kit-visualizations/src/components/charts/sc-tooltip/sc-tooltip-rows.tsx b/packages/iot-app-kit-visualizations/src/components/charts/sc-tooltip/sc-tooltip-rows.tsx index c10ab14c6..aac68a64a 100644 --- a/packages/iot-app-kit-visualizations/src/components/charts/sc-tooltip/sc-tooltip-rows.tsx +++ b/packages/iot-app-kit-visualizations/src/components/charts/sc-tooltip/sc-tooltip-rows.tsx @@ -29,6 +29,7 @@ export class ScTooltipRows { @Prop() tooltipPoints: TooltipPoint[]; @Prop() toolTipPositioning!: TooltipPositioning; @Prop() aggregationType?: string; + @Prop() precision?: number; /** * Returns the color to display the value within a legend row. @@ -129,6 +130,7 @@ export class ScTooltipRows { pointType={tooltipPoint.type} valueColor={valueColor} icon={icon} + precision={this.precision} /> ); })} diff --git a/packages/iot-app-kit-visualizations/src/components/charts/sc-tooltip/sc-tooltip.tsx b/packages/iot-app-kit-visualizations/src/components/charts/sc-tooltip/sc-tooltip.tsx index 193277500..0e51a4667 100644 --- a/packages/iot-app-kit-visualizations/src/components/charts/sc-tooltip/sc-tooltip.tsx +++ b/packages/iot-app-kit-visualizations/src/components/charts/sc-tooltip/sc-tooltip.tsx @@ -42,6 +42,7 @@ export class ScTooltip { @Prop() showBlankTooltipRows: boolean = false; @Prop() widgetId: string; @Prop() aggregationType?: string; + @Prop() precision?: number; /** * If we are drawing data from the data timestamp to timestamp + resolution @@ -247,6 +248,7 @@ export class ScTooltip { tooltipPoints={this.getTooltipPoints(this.selectedDate)} toolTipPositioning={this.toolTipPositioning} aggregationType={this.aggregationType} + precision={this.precision} /> ); } diff --git a/packages/iot-app-kit-visualizations/src/components/charts/sc-webgl-base-chart/sc-webgl-base-chart.tsx b/packages/iot-app-kit-visualizations/src/components/charts/sc-webgl-base-chart/sc-webgl-base-chart.tsx index b744d22af..313f4b819 100644 --- a/packages/iot-app-kit-visualizations/src/components/charts/sc-webgl-base-chart/sc-webgl-base-chart.tsx +++ b/packages/iot-app-kit-visualizations/src/components/charts/sc-webgl-base-chart/sc-webgl-base-chart.tsx @@ -92,6 +92,7 @@ export class ScWebglBaseChart { @Prop() alarms?: AlarmsConfig; @Prop() supportedDataTypes: DataType[] = Object.values(DataType); @Prop() aggregationType?: string; + @Prop() precision?: number; /** if false, base chart will not display an empty state message when there is no data present. */ @Prop() displaysNoDataPresentMsg?: boolean; @@ -786,6 +787,7 @@ export class ScWebglBaseChart { trendResults: this.trendResults, visualizesAlarms: this.visualizesAlarms, aggregationType: this.aggregationType, + precision: this.precision, }); renderLegendComponent = ({ diff --git a/packages/iot-app-kit-visualizations/src/components/value/Value.tsx b/packages/iot-app-kit-visualizations/src/components/value/Value.tsx index 229fc60ad..b3d0443e0 100644 --- a/packages/iot-app-kit-visualizations/src/components/value/Value.tsx +++ b/packages/iot-app-kit-visualizations/src/components/value/Value.tsx @@ -6,14 +6,24 @@ import { NO_VALUE_PRESENT } from '../common/terms'; /** * Display value of a data point, supports all data types */ -export const Value = ({ isEnabled = true, value, unit }: { isEnabled?: boolean; value?: Primitive; unit?: string }) => { +export const Value = ({ + isEnabled = true, + value, + unit, + precision, +}: { + isEnabled?: boolean; + value?: Primitive; + unit?: string; + precision?: number; +}) => { if (!isEnabled || value == null) { return {NO_VALUE_PRESENT}; } if (typeof value === 'number') { /** Display Number */ - return [round(value), unit && {unit}]; + return [round(value, precision), unit && {unit}]; } /** Display String or Booleans */ diff --git a/packages/iot-app-kit-visualizations/src/utils/number.ts b/packages/iot-app-kit-visualizations/src/utils/number.ts index 6a1d63b7f..0c14249d3 100644 --- a/packages/iot-app-kit-visualizations/src/utils/number.ts +++ b/packages/iot-app-kit-visualizations/src/utils/number.ts @@ -1,7 +1,5 @@ import { ThresholdDataTypes } from './dataTypes'; -const MAX_PRECISION = 4; - /** * Rounds a number to a pre-determined precision * @@ -9,18 +7,18 @@ const MAX_PRECISION = 4; * round(100000.12345678) => 100000.1234 * round(.02345678) => 0.02346 */ -export const round = (num: number): number => { +export const round = (num: number, precision: number = 4): number => { if (Number.isNaN(num) || num === Infinity || num === -Infinity) { return num; } if (Math.abs(num) < 1) { - return Number(num.toPrecision(MAX_PRECISION)); + return Number(num.toPrecision(precision)); } const integer = Math.trunc(num); const decimal = num - integer; - return Number((integer + Number(decimal.toFixed(MAX_PRECISION))).toFixed(MAX_PRECISION)); + return Number((integer + Number(decimal.toFixed(precision))).toFixed(precision)); }; /**