Add change gauge color (#2480)

This commit is contained in:
Vladyslav 2020-03-04 10:11:24 +02:00 committed by GitHub
parent 5933397e51
commit 4e16675ea4
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
4 changed files with 313 additions and 20 deletions

View File

@ -20,7 +20,7 @@ import BaseGauge = CanvasGauges.BaseGauge;
import { FontStyle, FontWeight } from '@home/components/widget/lib/settings.models';
import * as tinycolor_ from 'tinycolor2';
import { ColorFormats } from 'tinycolor2';
import { isDefined, isUndefined } from '@core/utils';
import { isDefined, isString, isUndefined } from '@core/utils';
const tinycolor = tinycolor_;
@ -32,13 +32,20 @@ export interface DigitalGaugeColorRange {
rgbString: string;
}
export interface colorLevelSetting {
value: number;
color: string;
}
export type levelColors = Array<string | colorLevelSetting>;
export interface CanvasDigitalGaugeOptions extends GenericOptions {
gaugeType?: GaugeType;
gaugeWithScale?: number;
dashThickness?: number;
roundedLineCap?: boolean;
gaugeColor?: string;
levelColors?: string[];
levelColors?: levelColors;
symbol?: string;
label?: string;
hideValue?: boolean;
@ -229,26 +236,30 @@ export class CanvasDigitalGauge extends BaseGauge {
}
const colorsCount = options.levelColors.length;
const isColorProperty = isString(options.levelColors[0]);
const inc = colorsCount > 1 ? (1 / (colorsCount - 1)) : 1;
options.colorsRange = [];
if (options.neonGlowBrightness) {
options.neonColorsRange = [];
}
for (let i = 0; i < options.levelColors.length; i++) {
const percentage = inc * i;
let tColor = tinycolor(options.levelColors[i]);
options.colorsRange[i] = {
pct: percentage,
color: tColor.toRgb(),
rgbString: tColor.toRgbString()
};
if (options.neonGlowBrightness) {
tColor = tinycolor(options.levelColors[i]).brighten(options.neonGlowBrightness);
options.neonColorsRange[i] = {
let levelColor: any = options.levelColors[i];
if (levelColor !== null) {
let percentage = isColorProperty ? inc * i : CanvasDigitalGauge.normalizeValue(levelColor.value, options.minValue, options.maxValue);
let tColor = tinycolor(isColorProperty ? levelColor : levelColor.color);
options.colorsRange[i] = {
pct: percentage,
color: tColor.toRgb(),
rgbString: tColor.toRgbString()
};
if (options.neonGlowBrightness) {
tColor = tinycolor(isColorProperty ? levelColor : levelColor.color).brighten(options.neonGlowBrightness);
options.neonColorsRange[i] = {
pct: percentage,
color: tColor.toRgb(),
rgbString: tColor.toRgbString()
};
}
}
}
@ -262,6 +273,17 @@ export class CanvasDigitalGauge extends BaseGauge {
return options;
}
static normalizeValue (value: number, min: number, max: number): number {
let normalValue = (value - min) / (max - min);
if (normalValue <= 0) {
return 0;
}
if (normalValue >= 1) {
return 1;
}
return normalValue;
}
private initValueClone() {
const canvas = this.canvas;
this.elementValueClone = canvas.element.cloneNode(true) as HTMLCanvasElementClone;

View File

@ -19,6 +19,26 @@ import { GaugeType } from '@home/components/widget/lib/canvas-digital-gauge';
import { AnimationRule } from '@home/components/widget/lib/analogue-gauge.models';
import { FontSettings } from '@home/components/widget/lib/settings.models';
export interface colorLevelProperty {
valueSource: string;
entityAlias?: string;
attribute?: string;
value?: number;
}
export interface fixedLevelColors {
from?: colorLevelProperty;
to?: colorLevelProperty;
color: string;
}
export interface colorLevelSetting {
value: number;
color: string;
}
export type colorLevel = Array<string | colorLevelSetting>;
export interface DigitalGaugeSettings {
minValue?: number;
maxValue?: number;
@ -38,7 +58,9 @@ export interface DigitalGaugeSettings {
gaugeWidthScale?: number;
defaultColor?: string;
gaugeColor?: string;
levelColors?: string[];
useFixedLevelColor?: boolean;
levelColors?: colorLevel;
fixedLevelColors?: fixedLevelColors[];
animation?: boolean;
animationDuration?: number;
animationRule?: AnimationRule;
@ -147,6 +169,11 @@ export const digitalGaugeSettingsSchema: JsonSettingsSchema = {
type: 'string',
default: null
},
useFixedLevelColor: {
title: 'Use precise value for the color indicator',
type: 'boolean',
default: false
},
levelColors: {
title: 'Colors of indicator, from lower to upper',
type: 'array',
@ -155,6 +182,66 @@ export const digitalGaugeSettingsSchema: JsonSettingsSchema = {
type: 'string'
}
},
fixedLevelColors: {
title: 'The colors for the indicator using boundary values',
type: 'array',
items: {
title: 'levelColor',
type: 'object',
properties: {
from: {
title: 'From',
type: 'object',
properties: {
valueSource: {
title: '[From] Value source',
type: 'string',
default: 'predefinedValue'
},
entityAlias: {
title: '[From] Source entity alias',
type: 'string'
},
attribute: {
title: '[From] Source entity attribute',
type: 'string'
},
value: {
title: '[From] Value (if predefined value is selected)',
type: 'number'
}
}
},
to: {
title: 'To',
type: 'object',
properties: {
valueSource: {
title: '[To] Value source',
type: 'string',
default: 'predefinedValue'
},
entityAlias: {
title: '[To] Source entity alias',
type: 'string'
},
attribute: {
title: '[To] Source entity attribute',
type: 'string'
},
value: {
title: '[To] Value (if predefined value is selected)',
type: 'number'
}
}
},
color: {
title: 'Color',
type: 'string'
}
}
}
},
animation: {
title: 'Enable animation',
type: 'boolean',
@ -343,8 +430,10 @@ export const digitalGaugeSettingsSchema: JsonSettingsSchema = {
key: 'gaugeColor',
type: 'color'
},
'useFixedLevelColor',
{
key: 'levelColors',
condition: 'model.useFixedLevelColor !== true',
items: [
{
key: 'levelColors[]',
@ -352,6 +441,52 @@ export const digitalGaugeSettingsSchema: JsonSettingsSchema = {
}
]
},
{
key: 'fixedLevelColors',
condition: 'model.useFixedLevelColor === true',
items: [
{
key: 'fixedLevelColors[].from.valueSource',
type: 'rc-select',
multiple: false,
items: [
{
value: 'predefinedValue',
label: 'Predefined value (Default)'
},
{
value: 'entityAttribute',
label: 'Value taken from entity attribute'
}
]
},
'fixedLevelColors[].from.value',
'fixedLevelColors[].from.entityAlias',
'fixedLevelColors[].from.attribute',
{
key: 'fixedLevelColors[].to.valueSource',
type: 'rc-select',
multiple: false,
items: [
{
value: 'predefinedValue',
label: 'Predefined value (Default)'
},
{
value: 'entityAttribute',
label: 'Value taken from entity attribute'
}
]
},
'fixedLevelColors[].to.value',
'fixedLevelColors[].to.entityAlias',
'fixedLevelColors[].to.attribute',
{
key: 'fixedLevelColors[].color',
type: 'color'
}
]
},
'animation',
'animationDuration',
{

View File

@ -16,14 +16,20 @@
import * as CanvasGauges from 'canvas-gauges';
import { WidgetContext } from '@home/models/widget-component.models';
import { DigitalGaugeSettings, digitalGaugeSettingsSchema } from '@home/components/widget/lib/digital-gauge.models';
import {
colorLevelSetting,
DigitalGaugeSettings,
digitalGaugeSettingsSchema
} from '@home/components/widget/lib/digital-gauge.models';
import * as tinycolor_ from 'tinycolor2';
import { isDefined } from '@core/utils';
import { prepareFontSettings } from '@home/components/widget/lib/settings.models';
import { CanvasDigitalGauge, CanvasDigitalGaugeOptions } from '@home/components/widget/lib/canvas-digital-gauge';
import { DatePipe } from '@angular/common';
import { JsonSettingsSchema } from '@shared/models/widget.models';
import {DataKey, Datasource, DatasourceType, JsonSettingsSchema, widgetType} from '@shared/models/widget.models';
import GenericOptions = CanvasGauges.GenericOptions;
import {IWidgetSubscription, WidgetSubscriptionOptions} from "@core/api/widget-api.models";
import {DataKeyType} from "@shared/models/telemetry/telemetry.models";
const tinycolor = tinycolor_;
@ -32,6 +38,7 @@ const digitalGaugeSettingsSchemaValue = digitalGaugeSettingsSchema;
export class TbCanvasDigitalGauge {
private localSettings: DigitalGaugeSettings;
private levelColorsSourcesSubscription: IWidgetSubscription;
private gauge: CanvasDigitalGauge;
@ -65,10 +72,16 @@ export class TbCanvasDigitalGauge {
this.localSettings.gaugeWidthScale = settings.gaugeWidthScale || 0.75;
this.localSettings.gaugeColor = settings.gaugeColor || tinycolor(keyColor).setAlpha(0.2).toRgbString();
if (!settings.levelColors || settings.levelColors.length <= 0) {
this.localSettings.levelColors = [keyColor];
this.localSettings.useFixedLevelColor = settings.useFixedLevelColor || false;
if (!settings.useFixedLevelColor) {
if (!settings.levelColors || settings.levelColors.length <= 0) {
this.localSettings.levelColors = [keyColor];
} else {
this.localSettings.levelColors = settings.levelColors.slice();
}
} else {
this.localSettings.levelColors = settings.levelColors.slice();
this.localSettings.levelColors = [keyColor];
this.localSettings.fixedLevelColors = settings.fixedLevelColors || [];
}
this.localSettings.decimals = isDefined(dataKey.decimals) ? dataKey.decimals :
@ -176,6 +189,130 @@ export class TbCanvasDigitalGauge {
};
this.gauge = new CanvasDigitalGauge(gaugeData).draw();
this.init();
}
init() {
if (this.localSettings.useFixedLevelColor) {
if (this.localSettings.fixedLevelColors && this.localSettings.fixedLevelColors.length > 0) {
this.localSettings.levelColors = this.settingLevelColorsSubscribe(this.localSettings.fixedLevelColors);
this.updateLevelColors(this.localSettings.levelColors);
}
}
}
settingLevelColorsSubscribe(options) {
let levelColorsDatasource: Datasource[] = [];
let predefineLevelColors: colorLevelSetting[] = [];
function setLevelColor(levelSetting, color) {
if (levelSetting.valueSource === 'predefinedValue' && isFinite(levelSetting.value)) {
predefineLevelColors.push({
value: levelSetting.value,
color: color
})
} else if (levelSetting.entityAlias && levelSetting.attribute) {
let entityAliasId = this.ctx.aliasController.getEntityAliasId(levelSetting.entityAlias);
if (!entityAliasId) {
return;
}
let datasource = levelColorsDatasource.find((datasource) => {
return datasource.entityAliasId === entityAliasId;
});
let dataKey: DataKey = {
type: DataKeyType.attribute,
name: levelSetting.attribute,
label: levelSetting.attribute,
settings: [{
color: color,
index: predefineLevelColors.length
}],
_hash: Math.random()
};
if (datasource) {
let findDataKey = datasource.dataKeys.find((dataKey) => {
return dataKey.name === levelSetting.attribute;
});
if (findDataKey) {
findDataKey.settings.push({
color: color,
index: predefineLevelColors.length
});
} else {
datasource.dataKeys.push(dataKey)
}
} else {
let datasource: Datasource = {
type: DatasourceType.entity,
name: levelSetting.entityAlias,
aliasName: levelSetting.entityAlias,
entityAliasId: entityAliasId,
dataKeys: [dataKey]
};
levelColorsDatasource.push(datasource);
}
predefineLevelColors.push(null);
}
}
for (let i = 0; i < options.length; i++) {
let levelColor = options[i];
if (levelColor.from) {
setLevelColor.call(this, levelColor.from, levelColor.color);
}
if (levelColor.to) {
setLevelColor.call(this, levelColor.to, levelColor.color);
}
}
this.subscribeLevelColorsAttributes(levelColorsDatasource);
return predefineLevelColors;
}
updateLevelColors(levelColors) {
(this.gauge.options as CanvasDigitalGaugeOptions).levelColors = levelColors;
this.gauge.options = CanvasDigitalGauge.configure(this.gauge.options);
this.gauge.update({} as CanvasDigitalGaugeOptions);
}
subscribeLevelColorsAttributes(datasources: Datasource[]) {
let TbCanvasDigitalGauge = this;
let levelColorsSourcesSubscriptionOptions: WidgetSubscriptionOptions = {
datasources: datasources,
useDashboardTimewindow: false,
type: widgetType.latest,
callbacks: {
onDataUpdated: (subscription) => {
for (let i = 0; i < subscription.data.length; i++) {
let keyData = subscription.data[i];
if (keyData && keyData.data && keyData.data[0]) {
let attrValue = keyData.data[0][1];
if (isFinite(attrValue)) {
for (let i = 0; i < keyData.dataKey.settings.length; i++) {
let setting = keyData.dataKey.settings[i];
this.localSettings.levelColors[setting.index] = {
value: attrValue,
color: setting.color
};
}
}
}
}
this.updateLevelColors(this.localSettings.levelColors);
}
}
};
this.ctx.subscriptionApi.createSubscription(levelColorsSourcesSubscriptionOptions, true).subscribe(
(subscription) => {
TbCanvasDigitalGauge.levelColorsSourcesSubscription = subscription;
}
);
}
update() {

View File

@ -186,7 +186,6 @@ export class JsonFormComponent implements OnInit, ControlValueAccessor, Validato
val = undefined;
}
if (JsonFormUtils.updateValue(key, this.model, val) || forceUpdate) {
this.formProps.model = this.model;
this.isModelValid = this.validateModel();
this.updateView();
}
@ -233,7 +232,7 @@ export class JsonFormComponent implements OnInit, ControlValueAccessor, Validato
this.formProps.schema = this.schema;
this.formProps.form = this.form;
this.formProps.groupInfoes = this.groupInfoes;
this.formProps.model = deepClone(this.model);
this.formProps.model = this.model;
this.renderReactSchemaForm();
}