Add change gauge color (#2480)
This commit is contained in:
parent
5933397e51
commit
4e16675ea4
@ -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;
|
||||
|
||||
@ -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',
|
||||
{
|
||||
|
||||
@ -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() {
|
||||
|
||||
@ -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();
|
||||
}
|
||||
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user