Commit adc7194669d4a8ee0b38ac99f37dcb663e8a62ee
Committed by
GitHub
1 parent
c55ddd9f
[3.0] Add support ticks to digital gauge (#2508)
* Add support ticks to digital gauge * Add link code
Showing
3 changed files
with
329 additions
and
103 deletions
@@ -15,12 +15,12 @@ | @@ -15,12 +15,12 @@ | ||
15 | /// | 15 | /// |
16 | 16 | ||
17 | import * as CanvasGauges from 'canvas-gauges'; | 17 | import * as CanvasGauges from 'canvas-gauges'; |
18 | -import GenericOptions = CanvasGauges.GenericOptions; | ||
19 | -import BaseGauge = CanvasGauges.BaseGauge; | ||
20 | import { FontStyle, FontWeight } from '@home/components/widget/lib/settings.models'; | 18 | import { FontStyle, FontWeight } from '@home/components/widget/lib/settings.models'; |
21 | import * as tinycolor_ from 'tinycolor2'; | 19 | import * as tinycolor_ from 'tinycolor2'; |
22 | import { ColorFormats } from 'tinycolor2'; | 20 | import { ColorFormats } from 'tinycolor2'; |
23 | import { isDefined, isString, isUndefined } from '@core/utils'; | 21 | import { isDefined, isString, isUndefined } from '@core/utils'; |
22 | +import GenericOptions = CanvasGauges.GenericOptions; | ||
23 | +import BaseGauge = CanvasGauges.BaseGauge; | ||
24 | 24 | ||
25 | const tinycolor = tinycolor_; | 25 | const tinycolor = tinycolor_; |
26 | 26 | ||
@@ -32,12 +32,12 @@ export interface DigitalGaugeColorRange { | @@ -32,12 +32,12 @@ export interface DigitalGaugeColorRange { | ||
32 | rgbString: string; | 32 | rgbString: string; |
33 | } | 33 | } |
34 | 34 | ||
35 | -export interface colorLevelSetting { | 35 | +export interface ColorLevelSetting { |
36 | value: number; | 36 | value: number; |
37 | color: string; | 37 | color: string; |
38 | } | 38 | } |
39 | 39 | ||
40 | -export type levelColors = Array<string | colorLevelSetting>; | 40 | +export type levelColors = Array<string | ColorLevelSetting>; |
41 | 41 | ||
42 | export interface CanvasDigitalGaugeOptions extends GenericOptions { | 42 | export interface CanvasDigitalGaugeOptions extends GenericOptions { |
43 | gaugeType?: GaugeType; | 43 | gaugeType?: GaugeType; |
@@ -81,6 +81,11 @@ export interface CanvasDigitalGaugeOptions extends GenericOptions { | @@ -81,6 +81,11 @@ export interface CanvasDigitalGaugeOptions extends GenericOptions { | ||
81 | fontValueHeight?: FontHeightInfo; | 81 | fontValueHeight?: FontHeightInfo; |
82 | fontMinMaxHeight?: FontHeightInfo; | 82 | fontMinMaxHeight?: FontHeightInfo; |
83 | 83 | ||
84 | + ticksValue?: number[]; | ||
85 | + ticks?: number[]; | ||
86 | + colorTicks?: string; | ||
87 | + tickWidth?: number; | ||
88 | + | ||
84 | showTimestamp?: boolean; | 89 | showTimestamp?: boolean; |
85 | } | 90 | } |
86 | 91 | ||
@@ -117,6 +122,10 @@ const defaultDigitalGaugeOptions: CanvasDigitalGaugeOptions = { ...GenericOption | @@ -117,6 +122,10 @@ const defaultDigitalGaugeOptions: CanvasDigitalGaugeOptions = { ...GenericOption | ||
117 | 122 | ||
118 | neonGlowBrightness: 0, | 123 | neonGlowBrightness: 0, |
119 | 124 | ||
125 | + colorTicks: 'gray', | ||
126 | + tickWidth: 4, | ||
127 | + ticks: [], | ||
128 | + | ||
120 | isMobile: false | 129 | isMobile: false |
121 | } | 130 | } |
122 | }; | 131 | }; |
@@ -243,9 +252,14 @@ export class CanvasDigitalGauge extends BaseGauge { | @@ -243,9 +252,14 @@ export class CanvasDigitalGauge extends BaseGauge { | ||
243 | options.neonColorsRange = []; | 252 | options.neonColorsRange = []; |
244 | } | 253 | } |
245 | for (let i = 0; i < options.levelColors.length; i++) { | 254 | for (let i = 0; i < options.levelColors.length; i++) { |
246 | - let levelColor: any = options.levelColors[i]; | 255 | + const levelColor: any = options.levelColors[i]; |
247 | if (levelColor !== null) { | 256 | if (levelColor !== null) { |
248 | - let percentage = isColorProperty ? inc * i : CanvasDigitalGauge.normalizeValue(levelColor.value, options.minValue, options.maxValue); | 257 | + let percentage: number; |
258 | + if(isColorProperty){ | ||
259 | + percentage = inc * i; | ||
260 | + } else { | ||
261 | + percentage = CanvasDigitalGauge.normalizeValue(levelColor.value, options.minValue, options.maxValue); | ||
262 | + } | ||
249 | let tColor = tinycolor(isColorProperty ? levelColor : levelColor.color); | 263 | let tColor = tinycolor(isColorProperty ? levelColor : levelColor.color); |
250 | options.colorsRange.push({ | 264 | options.colorsRange.push({ |
251 | pct: percentage, | 265 | pct: percentage, |
@@ -263,6 +277,13 @@ export class CanvasDigitalGauge extends BaseGauge { | @@ -263,6 +277,13 @@ export class CanvasDigitalGauge extends BaseGauge { | ||
263 | } | 277 | } |
264 | } | 278 | } |
265 | 279 | ||
280 | + options.ticksValue = []; | ||
281 | + for (const tick of options.ticks) { | ||
282 | + if (tick !== null) { | ||
283 | + options.ticksValue.push(CanvasDigitalGauge.normalizeValue(tick, options.minValue, options.maxValue)) | ||
284 | + } | ||
285 | + } | ||
286 | + | ||
266 | if (options.neonGlowBrightness) { | 287 | if (options.neonGlowBrightness) { |
267 | options.neonColorTitle = tinycolor(options.colorTitle).brighten(options.neonGlowBrightness).toHexString(); | 288 | options.neonColorTitle = tinycolor(options.colorTitle).brighten(options.neonGlowBrightness).toHexString(); |
268 | options.neonColorLabel = tinycolor(options.colorLabel).brighten(options.neonGlowBrightness).toHexString(); | 289 | options.neonColorLabel = tinycolor(options.colorLabel).brighten(options.neonGlowBrightness).toHexString(); |
@@ -274,7 +295,7 @@ export class CanvasDigitalGauge extends BaseGauge { | @@ -274,7 +295,7 @@ export class CanvasDigitalGauge extends BaseGauge { | ||
274 | } | 295 | } |
275 | 296 | ||
276 | static normalizeValue (value: number, min: number, max: number): number { | 297 | static normalizeValue (value: number, min: number, max: number): number { |
277 | - let normalValue = (value - min) / (max - min); | 298 | + const normalValue = (value - min) / (max - min); |
278 | if (normalValue <= 0) { | 299 | if (normalValue <= 0) { |
279 | return 0; | 300 | return 0; |
280 | } | 301 | } |
@@ -657,7 +678,7 @@ function determineFontHeight (options: CanvasDigitalGaugeOptions, target: string | @@ -657,7 +678,7 @@ function determineFontHeight (options: CanvasDigitalGaugeOptions, target: string | ||
657 | fontStyle: options['font' + target + 'Style'] | 678 | fontStyle: options['font' + target + 'Style'] |
658 | }; | 679 | }; |
659 | const text = $('<span>Hg</span>').css(fontStyle); | 680 | const text = $('<span>Hg</span>').css(fontStyle); |
660 | - const block = $('<div style="display: inline-block; width: 1px; height: 0px;"></div>'); | 681 | + const block = $('<div style="display: inline-block; width: 1px; height: 0;"></div>'); |
661 | 682 | ||
662 | const div = $('<div></div>'); | 683 | const div = $('<div></div>'); |
663 | div.append(text, block); | 684 | div.append(text, block); |
@@ -884,6 +905,52 @@ function drawBarGlow(context: DigitalGaugeCanvasRenderingContext2D, startX: numb | @@ -884,6 +905,52 @@ function drawBarGlow(context: DigitalGaugeCanvasRenderingContext2D, startX: numb | ||
884 | context.stroke(); | 905 | context.stroke(); |
885 | } | 906 | } |
886 | 907 | ||
908 | +function drawTickArc(context: DigitalGaugeCanvasRenderingContext2D, tickValues: number[], Cx: number, Cy: number, | ||
909 | + Ri: number, Rm: number, Ro: number, startAngle: number, endAngle: number, | ||
910 | + color: string, tickWidth: number) { | ||
911 | + if (!tickValues.length) { | ||
912 | + return; | ||
913 | + } | ||
914 | + | ||
915 | + const strokeWidth = Ro - Ri; | ||
916 | + context.beginPath(); | ||
917 | + context.lineWidth = tickWidth; | ||
918 | + context.strokeStyle = color; | ||
919 | + for (const tick of tickValues) { | ||
920 | + const angle = startAngle + tick * endAngle; | ||
921 | + const x1 = Cx + (Ri + strokeWidth) * Math.cos(angle); | ||
922 | + const y1 = Cy + (Ri + strokeWidth) * Math.sin(angle); | ||
923 | + const x2 = Cx + Ri * Math.cos(angle); | ||
924 | + const y2 = Cy + Ri * Math.sin(angle); | ||
925 | + context.moveTo(x1, y1); | ||
926 | + context.lineTo(x2, y2); | ||
927 | + } | ||
928 | + context.stroke(); | ||
929 | +} | ||
930 | + | ||
931 | +function drawTickBar(context: DigitalGaugeCanvasRenderingContext2D, tickValues: number[], startX: number, startY: number, | ||
932 | + distanceBar: number, strokeWidth: number, isVertical: boolean, color: string, tickWidth: number) { | ||
933 | + if (!tickValues.length) { | ||
934 | + return; | ||
935 | + } | ||
936 | + | ||
937 | + context.beginPath(); | ||
938 | + context.lineWidth = tickWidth; | ||
939 | + context.strokeStyle = color; | ||
940 | + for (const tick of tickValues) { | ||
941 | + const tickValue = tick * distanceBar; | ||
942 | + if (isVertical) { | ||
943 | + context.moveTo(startX - strokeWidth / 2, startY + tickValue - distanceBar); | ||
944 | + context.lineTo(startX + strokeWidth / 2, startY + tickValue - distanceBar); | ||
945 | + } else { | ||
946 | + context.moveTo(startX + tickValue, startY); | ||
947 | + context.lineTo(startX + tickValue, startY + strokeWidth); | ||
948 | + } | ||
949 | + } | ||
950 | + context.stroke(); | ||
951 | +} | ||
952 | + | ||
953 | + | ||
887 | function drawProgress(context: DigitalGaugeCanvasRenderingContext2D, | 954 | function drawProgress(context: DigitalGaugeCanvasRenderingContext2D, |
888 | options: CanvasDigitalGaugeOptions, progress: number) { | 955 | options: CanvasDigitalGaugeOptions, progress: number) { |
889 | let neonColor; | 956 | let neonColor; |
@@ -917,6 +984,8 @@ function drawProgress(context: DigitalGaugeCanvasRenderingContext2D, | @@ -917,6 +984,8 @@ function drawProgress(context: DigitalGaugeCanvasRenderingContext2D, | ||
917 | drawArcGlow(context, Cx, Cy, Ri, Rm, Ro, neonColor, progress, true, | 984 | drawArcGlow(context, Cx, Cy, Ri, Rm, Ro, neonColor, progress, true, |
918 | options.donutStartAngle, options.donutEndAngle); | 985 | options.donutStartAngle, options.donutEndAngle); |
919 | } | 986 | } |
987 | + drawTickArc(context, options.ticksValue, Cx, Cy, Ri, Rm, Ro, options.donutStartAngle, | ||
988 | + options.donutEndAngle - options.donutStartAngle, options.colorTicks, options.tickWidth); | ||
920 | } else if (options.gaugeType === 'arc') { | 989 | } else if (options.gaugeType === 'arc') { |
921 | if (options.neonGlowBrightness) { | 990 | if (options.neonGlowBrightness) { |
922 | context.strokeStyle = neonColor; | 991 | context.strokeStyle = neonColor; |
@@ -927,6 +996,7 @@ function drawProgress(context: DigitalGaugeCanvasRenderingContext2D, | @@ -927,6 +996,7 @@ function drawProgress(context: DigitalGaugeCanvasRenderingContext2D, | ||
927 | if (options.neonGlowBrightness && !options.isMobile) { | 996 | if (options.neonGlowBrightness && !options.isMobile) { |
928 | drawArcGlow(context, Cx, Cy, Ri, Rm, Ro, neonColor, progress, false); | 997 | drawArcGlow(context, Cx, Cy, Ri, Rm, Ro, neonColor, progress, false); |
929 | } | 998 | } |
999 | + drawTickArc(context, options.ticksValue, Cx, Cy, Ri, Rm, Ro, Math.PI, Math.PI, options.colorTicks, options.tickWidth); | ||
930 | } else if (options.gaugeType === 'horizontalBar') { | 1000 | } else if (options.gaugeType === 'horizontalBar') { |
931 | if (options.neonGlowBrightness) { | 1001 | if (options.neonGlowBrightness) { |
932 | context.strokeStyle = neonColor; | 1002 | context.strokeStyle = neonColor; |
@@ -940,6 +1010,8 @@ function drawProgress(context: DigitalGaugeCanvasRenderingContext2D, | @@ -940,6 +1010,8 @@ function drawProgress(context: DigitalGaugeCanvasRenderingContext2D, | ||
940 | barLeft + (barRight-barLeft)*progress, barTop + strokeWidth/2, | 1010 | barLeft + (barRight-barLeft)*progress, barTop + strokeWidth/2, |
941 | neonColor, strokeWidth, false); | 1011 | neonColor, strokeWidth, false); |
942 | } | 1012 | } |
1013 | + drawTickBar(context, options.ticksValue, barLeft, barTop, barRight - barLeft, strokeWidth, | ||
1014 | + false, options.colorTicks, options.tickWidth); | ||
943 | } else if (options.gaugeType === 'verticalBar') { | 1015 | } else if (options.gaugeType === 'verticalBar') { |
944 | if (options.neonGlowBrightness) { | 1016 | if (options.neonGlowBrightness) { |
945 | context.strokeStyle = neonColor; | 1017 | context.strokeStyle = neonColor; |
@@ -953,6 +1025,8 @@ function drawProgress(context: DigitalGaugeCanvasRenderingContext2D, | @@ -953,6 +1025,8 @@ function drawProgress(context: DigitalGaugeCanvasRenderingContext2D, | ||
953 | baseX + width/2, barBottom - (barBottom-barTop)*progress, | 1025 | baseX + width/2, barBottom - (barBottom-barTop)*progress, |
954 | neonColor, strokeWidth, true); | 1026 | neonColor, strokeWidth, true); |
955 | } | 1027 | } |
1028 | + drawTickBar(context, options.ticksValue, baseX + width / 2, barTop, barTop - barBottom, strokeWidth, | ||
1029 | + true, options.colorTicks, options.tickWidth); | ||
956 | } | 1030 | } |
957 | 1031 | ||
958 | } | 1032 | } |
@@ -19,25 +19,27 @@ import { GaugeType } from '@home/components/widget/lib/canvas-digital-gauge'; | @@ -19,25 +19,27 @@ import { GaugeType } from '@home/components/widget/lib/canvas-digital-gauge'; | ||
19 | import { AnimationRule } from '@home/components/widget/lib/analogue-gauge.models'; | 19 | import { AnimationRule } from '@home/components/widget/lib/analogue-gauge.models'; |
20 | import { FontSettings } from '@home/components/widget/lib/settings.models'; | 20 | import { FontSettings } from '@home/components/widget/lib/settings.models'; |
21 | 21 | ||
22 | -export interface colorLevelProperty { | 22 | +export interface AttributeSourceProperty { |
23 | valueSource: string; | 23 | valueSource: string; |
24 | entityAlias?: string; | 24 | entityAlias?: string; |
25 | attribute?: string; | 25 | attribute?: string; |
26 | value?: number; | 26 | value?: number; |
27 | } | 27 | } |
28 | 28 | ||
29 | -export interface fixedLevelColors { | ||
30 | - from?: colorLevelProperty; | ||
31 | - to?: colorLevelProperty; | 29 | +export interface FixedLevelColors { |
30 | + from?: AttributeSourceProperty; | ||
31 | + to?: AttributeSourceProperty; | ||
32 | color: string; | 32 | color: string; |
33 | } | 33 | } |
34 | 34 | ||
35 | -export interface colorLevelSetting { | 35 | +export interface ColorLevelSetting { |
36 | value: number; | 36 | value: number; |
37 | color: string; | 37 | color: string; |
38 | } | 38 | } |
39 | 39 | ||
40 | -export type colorLevel = Array<string | colorLevelSetting>; | 40 | +export type colorLevel = Array<string | ColorLevelSetting>; |
41 | + | ||
42 | +export type attributesGaugeType = 'levelColors' | 'ticks'; | ||
41 | 43 | ||
42 | export interface DigitalGaugeSettings { | 44 | export interface DigitalGaugeSettings { |
43 | minValue?: number; | 45 | minValue?: number; |
@@ -60,7 +62,7 @@ export interface DigitalGaugeSettings { | @@ -60,7 +62,7 @@ export interface DigitalGaugeSettings { | ||
60 | gaugeColor?: string; | 62 | gaugeColor?: string; |
61 | useFixedLevelColor?: boolean; | 63 | useFixedLevelColor?: boolean; |
62 | levelColors?: colorLevel; | 64 | levelColors?: colorLevel; |
63 | - fixedLevelColors?: fixedLevelColors[]; | 65 | + fixedLevelColors?: FixedLevelColors[]; |
64 | animation?: boolean; | 66 | animation?: boolean; |
65 | animationDuration?: number; | 67 | animationDuration?: number; |
66 | animationRule?: AnimationRule; | 68 | animationRule?: AnimationRule; |
@@ -72,6 +74,11 @@ export interface DigitalGaugeSettings { | @@ -72,6 +74,11 @@ export interface DigitalGaugeSettings { | ||
72 | units?: string; | 74 | units?: string; |
73 | hideValue?: boolean; | 75 | hideValue?: boolean; |
74 | hideMinMax?: boolean; | 76 | hideMinMax?: boolean; |
77 | + showTicks?: boolean; | ||
78 | + ticksValue?: AttributeSourceProperty[]; | ||
79 | + ticks?: number[]; | ||
80 | + colorTicks?: string; | ||
81 | + tickWidth?: number; | ||
75 | } | 82 | } |
76 | 83 | ||
77 | export const digitalGaugeSettingsSchema: JsonSettingsSchema = { | 84 | export const digitalGaugeSettingsSchema: JsonSettingsSchema = { |
@@ -242,6 +249,48 @@ export const digitalGaugeSettingsSchema: JsonSettingsSchema = { | @@ -242,6 +249,48 @@ export const digitalGaugeSettingsSchema: JsonSettingsSchema = { | ||
242 | } | 249 | } |
243 | } | 250 | } |
244 | }, | 251 | }, |
252 | + showTicks: { | ||
253 | + title: 'Show ticks', | ||
254 | + type: 'boolean', | ||
255 | + default: false | ||
256 | + }, | ||
257 | + tickWidth: { | ||
258 | + title: 'Width ticks', | ||
259 | + type: 'number', | ||
260 | + default: 4 | ||
261 | + }, | ||
262 | + colorTicks: { | ||
263 | + title: 'Color ticks', | ||
264 | + type: 'string', | ||
265 | + default: '#666' | ||
266 | + }, | ||
267 | + ticksValue: { | ||
268 | + title: 'The ticks predefined value', | ||
269 | + type: 'array', | ||
270 | + items: { | ||
271 | + title: 'tickValue', | ||
272 | + type: 'object', | ||
273 | + properties: { | ||
274 | + valueSource: { | ||
275 | + title: 'Value source', | ||
276 | + type: 'string', | ||
277 | + default: 'predefinedValue' | ||
278 | + }, | ||
279 | + entityAlias: { | ||
280 | + title: 'Source entity alias', | ||
281 | + type: 'string' | ||
282 | + }, | ||
283 | + attribute: { | ||
284 | + title: 'Source entity attribute', | ||
285 | + type: 'string' | ||
286 | + }, | ||
287 | + value: { | ||
288 | + title: 'Value (if predefined value is selected)', | ||
289 | + type: 'number' | ||
290 | + } | ||
291 | + } | ||
292 | + } | ||
293 | + }, | ||
245 | animation: { | 294 | animation: { |
246 | title: 'Enable animation', | 295 | title: 'Enable animation', |
247 | type: 'boolean', | 296 | type: 'boolean', |
@@ -487,6 +536,40 @@ export const digitalGaugeSettingsSchema: JsonSettingsSchema = { | @@ -487,6 +536,40 @@ export const digitalGaugeSettingsSchema: JsonSettingsSchema = { | ||
487 | } | 536 | } |
488 | ] | 537 | ] |
489 | }, | 538 | }, |
539 | + 'showTicks', | ||
540 | + { | ||
541 | + key: 'tickWidth', | ||
542 | + condition: 'model.showTicks === true' | ||
543 | + }, | ||
544 | + { | ||
545 | + key: 'colorTicks', | ||
546 | + condition: 'model.showTicks === true', | ||
547 | + type: 'color' | ||
548 | + }, | ||
549 | + { | ||
550 | + key: 'ticksValue', | ||
551 | + condition: 'model.showTicks === true', | ||
552 | + items: [ | ||
553 | + { | ||
554 | + key: 'ticksValue[].valueSource', | ||
555 | + type: 'rc-select', | ||
556 | + multiple: false, | ||
557 | + items: [ | ||
558 | + { | ||
559 | + value: 'predefinedValue', | ||
560 | + label: 'Predefined value (Default)' | ||
561 | + }, | ||
562 | + { | ||
563 | + value: 'entityAttribute', | ||
564 | + label: 'Value taken from entity attribute' | ||
565 | + } | ||
566 | + ] | ||
567 | + }, | ||
568 | + 'ticksValue[].value', | ||
569 | + 'ticksValue[].entityAlias', | ||
570 | + 'ticksValue[].attribute' | ||
571 | + ] | ||
572 | + }, | ||
490 | 'animation', | 573 | 'animation', |
491 | 'animationDuration', | 574 | 'animationDuration', |
492 | { | 575 | { |
@@ -17,19 +17,30 @@ | @@ -17,19 +17,30 @@ | ||
17 | import * as CanvasGauges from 'canvas-gauges'; | 17 | import * as CanvasGauges from 'canvas-gauges'; |
18 | import { WidgetContext } from '@home/models/widget-component.models'; | 18 | import { WidgetContext } from '@home/models/widget-component.models'; |
19 | import { | 19 | import { |
20 | - colorLevelSetting, | 20 | + attributesGaugeType, |
21 | + AttributeSourceProperty, | ||
22 | + ColorLevelSetting, | ||
21 | DigitalGaugeSettings, | 23 | DigitalGaugeSettings, |
22 | - digitalGaugeSettingsSchema | 24 | + digitalGaugeSettingsSchema, |
25 | + FixedLevelColors | ||
23 | } from '@home/components/widget/lib/digital-gauge.models'; | 26 | } from '@home/components/widget/lib/digital-gauge.models'; |
24 | import * as tinycolor_ from 'tinycolor2'; | 27 | import * as tinycolor_ from 'tinycolor2'; |
25 | import { isDefined } from '@core/utils'; | 28 | import { isDefined } from '@core/utils'; |
26 | import { prepareFontSettings } from '@home/components/widget/lib/settings.models'; | 29 | import { prepareFontSettings } from '@home/components/widget/lib/settings.models'; |
27 | import { CanvasDigitalGauge, CanvasDigitalGaugeOptions } from '@home/components/widget/lib/canvas-digital-gauge'; | 30 | import { CanvasDigitalGauge, CanvasDigitalGaugeOptions } from '@home/components/widget/lib/canvas-digital-gauge'; |
28 | import { DatePipe } from '@angular/common'; | 31 | import { DatePipe } from '@angular/common'; |
29 | -import {DataKey, Datasource, DatasourceType, JsonSettingsSchema, widgetType} from '@shared/models/widget.models'; | 32 | +import { |
33 | + DataKey, | ||
34 | + Datasource, | ||
35 | + DatasourceData, | ||
36 | + DatasourceType, | ||
37 | + JsonSettingsSchema, | ||
38 | + widgetType | ||
39 | +} from '@shared/models/widget.models'; | ||
40 | +import { IWidgetSubscription, WidgetSubscriptionOptions } from '@core/api/widget-api.models'; | ||
41 | +import { DataKeyType } from '@shared/models/telemetry/telemetry.models'; | ||
42 | +import { EMPTY, Observable } from 'rxjs'; | ||
30 | import GenericOptions = CanvasGauges.GenericOptions; | 43 | import GenericOptions = CanvasGauges.GenericOptions; |
31 | -import {IWidgetSubscription, WidgetSubscriptionOptions} from "@core/api/widget-api.models"; | ||
32 | -import {DataKeyType} from "@shared/models/telemetry/telemetry.models"; | ||
33 | 44 | ||
34 | const tinycolor = tinycolor_; | 45 | const tinycolor = tinycolor_; |
35 | 46 | ||
@@ -37,11 +48,6 @@ const digitalGaugeSettingsSchemaValue = digitalGaugeSettingsSchema; | @@ -37,11 +48,6 @@ const digitalGaugeSettingsSchemaValue = digitalGaugeSettingsSchema; | ||
37 | 48 | ||
38 | export class TbCanvasDigitalGauge { | 49 | export class TbCanvasDigitalGauge { |
39 | 50 | ||
40 | - private localSettings: DigitalGaugeSettings; | ||
41 | - private levelColorsSourcesSubscription: IWidgetSubscription; | ||
42 | - | ||
43 | - private gauge: CanvasDigitalGauge; | ||
44 | - | ||
45 | static get settingsSchema(): JsonSettingsSchema { | 51 | static get settingsSchema(): JsonSettingsSchema { |
46 | return digitalGaugeSettingsSchemaValue; | 52 | return digitalGaugeSettingsSchemaValue; |
47 | } | 53 | } |
@@ -84,6 +90,12 @@ export class TbCanvasDigitalGauge { | @@ -84,6 +90,12 @@ export class TbCanvasDigitalGauge { | ||
84 | this.localSettings.fixedLevelColors = settings.fixedLevelColors || []; | 90 | this.localSettings.fixedLevelColors = settings.fixedLevelColors || []; |
85 | } | 91 | } |
86 | 92 | ||
93 | + this.localSettings.showTicks = settings.showTicks || false; | ||
94 | + this.localSettings.ticks = []; | ||
95 | + this.localSettings.ticksValue = settings.ticksValue || []; | ||
96 | + this.localSettings.tickWidth = settings.tickWidth || 4; | ||
97 | + this.localSettings.colorTicks = settings.colorTicks || '#666'; | ||
98 | + | ||
87 | this.localSettings.decimals = isDefined(dataKey.decimals) ? dataKey.decimals : | 99 | this.localSettings.decimals = isDefined(dataKey.decimals) ? dataKey.decimals : |
88 | ((isDefined(settings.decimals) && settings.decimals !== null) | 100 | ((isDefined(settings.decimals) && settings.decimals !== null) |
89 | ? settings.decimals : ctx.decimals); | 101 | ? settings.decimals : ctx.decimals); |
@@ -137,6 +149,10 @@ export class TbCanvasDigitalGauge { | @@ -137,6 +149,10 @@ export class TbCanvasDigitalGauge { | ||
137 | gaugeColor: this.localSettings.gaugeColor, | 149 | gaugeColor: this.localSettings.gaugeColor, |
138 | levelColors: this.localSettings.levelColors, | 150 | levelColors: this.localSettings.levelColors, |
139 | 151 | ||
152 | + colorTicks: this.localSettings.colorTicks, | ||
153 | + tickWidth: this.localSettings.tickWidth, | ||
154 | + ticks: this.localSettings.ticks, | ||
155 | + | ||
140 | title: this.localSettings.title, | 156 | title: this.localSettings.title, |
141 | 157 | ||
142 | fontTitleSize: this.localSettings.titleFont.size, | 158 | fontTitleSize: this.localSettings.titleFont.size, |
@@ -192,76 +208,92 @@ export class TbCanvasDigitalGauge { | @@ -192,76 +208,92 @@ export class TbCanvasDigitalGauge { | ||
192 | this.init(); | 208 | this.init(); |
193 | } | 209 | } |
194 | 210 | ||
211 | + private localSettings: DigitalGaugeSettings; | ||
212 | + private levelColorsSourcesSubscription: IWidgetSubscription; | ||
213 | + private ticksSourcesSubscription: IWidgetSubscription; | ||
214 | + | ||
215 | + private gauge: CanvasDigitalGauge; | ||
216 | + | ||
217 | + static generateDatasource(ctx: WidgetContext, datasources: Datasource[], entityAlias: string, | ||
218 | + attribute: string, settings: any): Datasource[]{ | ||
219 | + const entityAliasId = ctx.aliasController.getEntityAliasId(entityAlias); | ||
220 | + if (!entityAliasId) { | ||
221 | + throw new Error('Not valid entity aliase name ' + entityAlias); | ||
222 | + } | ||
223 | + | ||
224 | + const datasource = datasources.find((datasourceIteration) => { | ||
225 | + return datasourceIteration.entityAliasId === entityAliasId; | ||
226 | + }); | ||
227 | + | ||
228 | + const dataKey: DataKey = { | ||
229 | + type: DataKeyType.attribute, | ||
230 | + name: attribute, | ||
231 | + label: attribute, | ||
232 | + settings: [settings], | ||
233 | + _hash: Math.random() | ||
234 | + }; | ||
235 | + | ||
236 | + if (datasource) { | ||
237 | + const findDataKey = datasource.dataKeys.find((dataKeyIteration) => { | ||
238 | + return dataKeyIteration.name === attribute; | ||
239 | + }); | ||
240 | + | ||
241 | + if (findDataKey) { | ||
242 | + findDataKey.settings.push(settings); | ||
243 | + } else { | ||
244 | + datasource.dataKeys.push(dataKey) | ||
245 | + } | ||
246 | + } else { | ||
247 | + const datasourceAttribute: Datasource = { | ||
248 | + type: DatasourceType.entity, | ||
249 | + name: entityAlias, | ||
250 | + aliasName: entityAlias, | ||
251 | + entityAliasId, | ||
252 | + dataKeys: [dataKey] | ||
253 | + }; | ||
254 | + datasources.push(datasourceAttribute); | ||
255 | + } | ||
256 | + | ||
257 | + return datasources; | ||
258 | + } | ||
259 | + | ||
195 | init() { | 260 | init() { |
196 | if (this.localSettings.useFixedLevelColor) { | 261 | if (this.localSettings.useFixedLevelColor) { |
197 | if (this.localSettings.fixedLevelColors && this.localSettings.fixedLevelColors.length > 0) { | 262 | if (this.localSettings.fixedLevelColors && this.localSettings.fixedLevelColors.length > 0) { |
198 | this.localSettings.levelColors = this.settingLevelColorsSubscribe(this.localSettings.fixedLevelColors); | 263 | this.localSettings.levelColors = this.settingLevelColorsSubscribe(this.localSettings.fixedLevelColors); |
199 | - this.updateLevelColors(this.localSettings.levelColors); | ||
200 | } | 264 | } |
265 | + | ||
266 | + if (this.localSettings.showTicks) { | ||
267 | + if (this.localSettings.ticksValue && this.localSettings.ticksValue.length) { | ||
268 | + this.localSettings.ticks = this.settingTicksSubscribe(this.localSettings.ticksValue); | ||
269 | + } | ||
270 | + } | ||
271 | + this.updateSetting(); | ||
201 | } | 272 | } |
202 | } | 273 | } |
203 | 274 | ||
204 | - settingLevelColorsSubscribe(options) { | 275 | + settingLevelColorsSubscribe(options: FixedLevelColors[]): ColorLevelSetting[] { |
205 | let levelColorsDatasource: Datasource[] = []; | 276 | let levelColorsDatasource: Datasource[] = []; |
206 | - let predefineLevelColors: colorLevelSetting[] = []; | 277 | + const predefineLevelColors: ColorLevelSetting[] = []; |
207 | 278 | ||
208 | - function setLevelColor(levelSetting, color) { | 279 | + function setLevelColor(levelSetting: AttributeSourceProperty, color: string) { |
209 | if (levelSetting.valueSource === 'predefinedValue' && isFinite(levelSetting.value)) { | 280 | if (levelSetting.valueSource === 'predefinedValue' && isFinite(levelSetting.value)) { |
210 | predefineLevelColors.push({ | 281 | predefineLevelColors.push({ |
211 | value: levelSetting.value, | 282 | value: levelSetting.value, |
212 | - color: color | 283 | + color |
213 | }) | 284 | }) |
214 | } else if (levelSetting.entityAlias && levelSetting.attribute) { | 285 | } else if (levelSetting.entityAlias && levelSetting.attribute) { |
215 | - let entityAliasId = this.ctx.aliasController.getEntityAliasId(levelSetting.entityAlias); | ||
216 | - if (!entityAliasId) { | 286 | + try { |
287 | + levelColorsDatasource = TbCanvasDigitalGauge.generateDatasource(this.ctx, levelColorsDatasource, | ||
288 | + levelSetting.entityAlias, levelSetting.attribute, {color, index: predefineLevelColors.length}); | ||
289 | + } catch (e) { | ||
217 | return; | 290 | return; |
218 | } | 291 | } |
219 | - | ||
220 | - let datasource = levelColorsDatasource.find((datasource) => { | ||
221 | - return datasource.entityAliasId === entityAliasId; | ||
222 | - }); | ||
223 | - | ||
224 | - let dataKey: DataKey = { | ||
225 | - type: DataKeyType.attribute, | ||
226 | - name: levelSetting.attribute, | ||
227 | - label: levelSetting.attribute, | ||
228 | - settings: [{ | ||
229 | - color: color, | ||
230 | - index: predefineLevelColors.length | ||
231 | - }], | ||
232 | - _hash: Math.random() | ||
233 | - }; | ||
234 | - | ||
235 | - if (datasource) { | ||
236 | - let findDataKey = datasource.dataKeys.find((dataKey) => { | ||
237 | - return dataKey.name === levelSetting.attribute; | ||
238 | - }); | ||
239 | - | ||
240 | - if (findDataKey) { | ||
241 | - findDataKey.settings.push({ | ||
242 | - color: color, | ||
243 | - index: predefineLevelColors.length | ||
244 | - }); | ||
245 | - } else { | ||
246 | - datasource.dataKeys.push(dataKey) | ||
247 | - } | ||
248 | - } else { | ||
249 | - let datasource: Datasource = { | ||
250 | - type: DatasourceType.entity, | ||
251 | - name: levelSetting.entityAlias, | ||
252 | - aliasName: levelSetting.entityAlias, | ||
253 | - entityAliasId: entityAliasId, | ||
254 | - dataKeys: [dataKey] | ||
255 | - }; | ||
256 | - levelColorsDatasource.push(datasource); | ||
257 | - } | ||
258 | - | ||
259 | predefineLevelColors.push(null); | 292 | predefineLevelColors.push(null); |
260 | } | 293 | } |
261 | } | 294 | } |
262 | 295 | ||
263 | - for (let i = 0; i < options.length; i++) { | ||
264 | - let levelColor = options[i]; | 296 | + for(const levelColor of options){ |
265 | if (levelColor.from) { | 297 | if (levelColor.from) { |
266 | setLevelColor.call(this, levelColor.from, levelColor.color); | 298 | setLevelColor.call(this, levelColor.from, levelColor.color); |
267 | } | 299 | } |
@@ -270,49 +302,86 @@ export class TbCanvasDigitalGauge { | @@ -270,49 +302,86 @@ export class TbCanvasDigitalGauge { | ||
270 | } | 302 | } |
271 | } | 303 | } |
272 | 304 | ||
273 | - this.subscribeLevelColorsAttributes(levelColorsDatasource); | 305 | + this.subscribeAttributes(levelColorsDatasource, 'levelColors').subscribe((subscription) => { |
306 | + this.levelColorsSourcesSubscription = subscription; | ||
307 | + }); | ||
274 | 308 | ||
275 | return predefineLevelColors; | 309 | return predefineLevelColors; |
276 | } | 310 | } |
277 | 311 | ||
278 | - updateLevelColors(levelColors) { | ||
279 | - (this.gauge.options as CanvasDigitalGaugeOptions).levelColors = levelColors; | ||
280 | - this.gauge.options = CanvasDigitalGauge.configure(this.gauge.options); | ||
281 | - this.gauge.update({} as CanvasDigitalGaugeOptions); | 312 | + settingTicksSubscribe(options: AttributeSourceProperty[]): number[] { |
313 | + let ticksDatasource: Datasource[] = []; | ||
314 | + const predefineTicks: number[] = []; | ||
315 | + | ||
316 | + for(const tick of options){ | ||
317 | + if (tick.valueSource === 'predefinedValue' && isFinite(tick.value)) { | ||
318 | + predefineTicks.push(tick.value) | ||
319 | + } else if (tick.entityAlias && tick.attribute) { | ||
320 | + try { | ||
321 | + ticksDatasource = TbCanvasDigitalGauge | ||
322 | + .generateDatasource(this.ctx, ticksDatasource, tick.entityAlias, tick.attribute, predefineTicks.length); | ||
323 | + } catch (e) { | ||
324 | + continue; | ||
325 | + } | ||
326 | + predefineTicks.push(null); | ||
327 | + } | ||
328 | + } | ||
329 | + | ||
330 | + this.subscribeAttributes(ticksDatasource, 'ticks').subscribe((subscription) => { | ||
331 | + this.ticksSourcesSubscription = subscription; | ||
332 | + }); | ||
333 | + | ||
334 | + return predefineTicks; | ||
282 | } | 335 | } |
283 | 336 | ||
284 | - subscribeLevelColorsAttributes(datasources: Datasource[]) { | ||
285 | - let TbCanvasDigitalGauge = this; | ||
286 | - let levelColorsSourcesSubscriptionOptions: WidgetSubscriptionOptions = { | ||
287 | - datasources: datasources, | 337 | + subscribeAttributes(datasource: Datasource[], typeAttributes: attributesGaugeType): Observable<IWidgetSubscription> { |
338 | + if (!datasource.length) { | ||
339 | + return EMPTY; | ||
340 | + } | ||
341 | + | ||
342 | + const levelColorsSourcesSubscriptionOptions: WidgetSubscriptionOptions = { | ||
343 | + datasources: datasource, | ||
288 | useDashboardTimewindow: false, | 344 | useDashboardTimewindow: false, |
289 | type: widgetType.latest, | 345 | type: widgetType.latest, |
290 | callbacks: { | 346 | callbacks: { |
291 | onDataUpdated: (subscription) => { | 347 | onDataUpdated: (subscription) => { |
292 | - for (let i = 0; i < subscription.data.length; i++) { | ||
293 | - let keyData = subscription.data[i]; | ||
294 | - if (keyData && keyData.data && keyData.data[0]) { | ||
295 | - let attrValue = keyData.data[0][1]; | ||
296 | - if (isFinite(attrValue)) { | ||
297 | - for (let i = 0; i < keyData.dataKey.settings.length; i++) { | ||
298 | - let setting = keyData.dataKey.settings[i]; | ||
299 | - this.localSettings.levelColors[setting.index] = { | ||
300 | - value: attrValue, | ||
301 | - color: setting.color | ||
302 | - }; | ||
303 | - } | ||
304 | - } | ||
305 | - } | ||
306 | - } | ||
307 | - this.updateLevelColors(this.localSettings.levelColors); | 348 | + this.updateAttribute(subscription.data, typeAttributes); |
308 | } | 349 | } |
309 | } | 350 | } |
310 | }; | 351 | }; |
311 | - this.ctx.subscriptionApi.createSubscription(levelColorsSourcesSubscriptionOptions, true).subscribe( | ||
312 | - (subscription) => { | ||
313 | - TbCanvasDigitalGauge.levelColorsSourcesSubscription = subscription; | 352 | + |
353 | + return this.ctx.subscriptionApi.createSubscription(levelColorsSourcesSubscriptionOptions, true); | ||
354 | + } | ||
355 | + | ||
356 | + updateAttribute(data: Array<DatasourceData>, typeAttributes: attributesGaugeType) { | ||
357 | + for (const keyData of data) { | ||
358 | + if (keyData && keyData.data && keyData.data[0]) { | ||
359 | + const attrValue = keyData.data[0][1]; | ||
360 | + if (isFinite(attrValue)) { | ||
361 | + for (const setting of keyData.dataKey.settings) { | ||
362 | + switch (typeAttributes) { | ||
363 | + case 'levelColors': | ||
364 | + this.localSettings.levelColors[setting.index] = { | ||
365 | + value: attrValue, | ||
366 | + color: setting.color | ||
367 | + }; | ||
368 | + break; | ||
369 | + case 'ticks': | ||
370 | + this.localSettings.ticks[setting] = attrValue; | ||
371 | + break; | ||
372 | + } | ||
373 | + } | ||
374 | + } | ||
314 | } | 375 | } |
315 | - ); | 376 | + } |
377 | + this.updateSetting(); | ||
378 | + } | ||
379 | + | ||
380 | + updateSetting() { | ||
381 | + (this.gauge.options as CanvasDigitalGaugeOptions).ticks = this.localSettings.ticks; | ||
382 | + (this.gauge.options as CanvasDigitalGaugeOptions).levelColors = this.localSettings.levelColors; | ||
383 | + this.gauge.options = CanvasDigitalGauge.configure(this.gauge.options); | ||
384 | + this.gauge.update({} as CanvasDigitalGaugeOptions); | ||
316 | } | 385 | } |
317 | 386 | ||
318 | update() { | 387 | update() { |