Implement Analogue gauges

This commit is contained in:
Igor Kulikov 2020-02-13 12:52:44 +02:00
parent 3378aa1d77
commit 8771a6f754
22 changed files with 1884 additions and 26 deletions

View File

@ -3037,6 +3037,12 @@
}
}
},
"@types/canvas-gauges": {
"version": "2.1.2",
"resolved": "https://registry.npmjs.org/@types/canvas-gauges/-/canvas-gauges-2.1.2.tgz",
"integrity": "sha512-oWCq0XjsTBXPtMKXoW23ORbMWguC2Fa8o5NiZVYiUoQMMrpNLKj1E+LDznlMpcib3iyWVIy+TEpc/ea6LMbW3Q==",
"dev": true
},
"@types/estree": {
"version": "0.0.42",
"resolved": "https://registry.npmjs.org/@types/estree/-/estree-0.0.42.tgz",
@ -4435,6 +4441,11 @@
"integrity": "sha512-feylzsbDxi1gPZ1IjystzIQZagYYLvfKrSuygUCgf7z6x790VEzze5QEkdSV1U58RA7Hi0+v6fv4K54atOzATg==",
"dev": true
},
"canvas-gauges": {
"version": "2.1.5",
"resolved": "https://registry.npmjs.org/canvas-gauges/-/canvas-gauges-2.1.5.tgz",
"integrity": "sha512-7GUd1uukePQPQPIoM8Sh4UrG8om+2RG+D8WN5BCkIp9wAfByzPuZZinsUkfFCyRrEOZ/rhuwBfFnb1ld8IfNrw=="
},
"caseless": {
"version": "0.12.0",
"resolved": "https://registry.npmjs.org/caseless/-/caseless-0.12.0.tgz",

View File

@ -42,6 +42,7 @@
"angular-gridster2": "^9.0.0",
"angular2-hotkeys": "^2.1.5",
"base64-js": "^1.3.1",
"canvas-gauges": "^2.1.5",
"compass-sass-mixins": "^0.12.7",
"core-js": "^3.6.4",
"date-fns": "^2.9.0",
@ -91,6 +92,7 @@
"@angular/cli": "^9.0.1",
"@angular/compiler-cli": "~9.0.0",
"@angular/language-service": "~9.0.0",
"@types/canvas-gauges": "^2.1.2",
"@types/flot": "0.0.31",
"@types/jasmine": "^3.5.3",
"@types/jasminewd2": "~2.0.8",

View File

@ -0,0 +1,357 @@
///
/// Copyright © 2016-2019 The Thingsboard Authors
///
/// Licensed under the Apache License, Version 2.0 (the "License");
/// you may not use this file except in compliance with the License.
/// You may obtain a copy of the License at
///
/// http://www.apache.org/licenses/LICENSE-2.0
///
/// Unless required by applicable law or agreed to in writing, software
/// distributed under the License is distributed on an "AS IS" BASIS,
/// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
/// See the License for the specific language governing permissions and
/// limitations under the License.
///
import { JsonSettingsSchema } from '@shared/models/widget.models';
import { FontSettings } from '@home/components/widget/lib/settings.models';
import { AnimationRule, AnimationTarget } from '@home/components/widget/lib/analogue-gauge.models';
export interface AnalogueCompassSettings {
majorTicks: string[];
minorTicks: number;
showStrokeTicks: boolean;
needleCircleSize: number;
showBorder: boolean;
borderOuterWidth: number;
colorPlate: string;
colorMajorTicks: string;
colorMinorTicks: string;
colorNeedle: string;
colorNeedleCircle: string;
colorBorder: string;
majorTickFont: FontSettings;
animation: boolean;
animationDuration: number;
animationRule: AnimationRule;
animationTarget: AnimationTarget;
}
export const analogueCompassSettingsSchema: JsonSettingsSchema = {
schema: {
type: 'object',
title: 'Settings',
properties: {
majorTicks: {
title: 'Major ticks names',
type: 'array',
items: {
title: 'Tick name',
type: 'string'
}
},
minorTicks: {
title: 'Minor ticks count',
type: 'number',
default: 22
},
showStrokeTicks: {
title: 'Show ticks stroke',
type: 'boolean',
default: false
},
needleCircleSize: {
title: 'Needle circle size',
type: 'number',
default: 15
},
showBorder: {
title: 'Show border',
type: 'boolean',
default: true
},
borderOuterWidth: {
title: 'Border width',
type: 'number',
default: 10
},
colorPlate: {
title: 'Plate color',
type: 'string',
default: '#222'
},
colorMajorTicks: {
title: 'Major ticks color',
type: 'string',
default: '#f5f5f5'
},
colorMinorTicks: {
title: 'Minor ticks color',
type: 'string',
default: '#ddd'
},
colorNeedle: {
title: 'Needle color',
type: 'string',
default: '#f08080'
},
colorNeedleCircle: {
title: 'Needle circle color',
type: 'string',
default: '#e8e8e8'
},
colorBorder: {
title: 'Border color',
type: 'string',
default: '#ccc'
},
majorTickFont: {
title: 'Major tick font',
type: 'object',
properties: {
family: {
title: 'Font family',
type: 'string',
default: 'Roboto'
},
size: {
title: 'Size',
type: 'number',
default: 20
},
style: {
title: 'Style',
type: 'string',
default: 'normal'
},
weight: {
title: 'Weight',
type: 'string',
default: '500'
},
color: {
title: 'color',
type: 'string',
default: '#ccc'
}
}
},
animation: {
title: 'Enable animation',
type: 'boolean',
default: true
},
animationDuration: {
title: 'Animation duration',
type: 'number',
default: 500
},
animationRule: {
title: 'Animation rule',
type: 'string',
default: 'cycle'
},
animationTarget: {
title: 'Animation target',
type: 'string',
default: 'needle'
}
},
required: []
},
form: [
{
key: 'majorTicks',
items:[
'majorTicks[]'
]
},
'minorTicks',
'showStrokeTicks',
'needleCircleSize',
'showBorder',
'borderOuterWidth',
{
key: 'colorPlate',
type: 'color'
},
{
key: 'colorMajorTicks',
type: 'color'
},
{
key: 'colorMinorTicks',
type: 'color'
},
{
key: 'colorNeedle',
type: 'color'
},
{
key: 'colorNeedleCircle',
type: 'color'
},
{
key: 'colorBorder',
type: 'color'
},
{
key: 'majorTickFont',
items: [
'majorTickFont.family',
'majorTickFont.size',
{
key: 'majorTickFont.style',
type: 'rc-select',
multiple: false,
items: [
{
value: 'normal',
label: 'Normal'
},
{
value: 'italic',
label: 'Italic'
},
{
value: 'oblique',
label: 'Oblique'
}
]
},
{
key: 'majorTickFont.weight',
type: 'rc-select',
multiple: false,
items: [
{
value: 'normal',
label: 'Normal'
},
{
value: 'bold',
label: 'Bold'
},
{
value: 'bolder',
label: 'Bolder'
},
{
value: 'lighter',
label: 'Lighter'
},
{
value: '100',
label: '100'
},
{
value: '200',
label: '200'
},
{
value: '300',
label: '300'
},
{
value: '400',
label: '400'
},
{
value: '500',
label: '500'
},
{
value: '600',
label: '600'
},
{
value: '700',
label: '800'
},
{
value: '800',
label: '800'
},
{
value: '900',
label: '900'
}
]
},
{
key: 'majorTickFont.color',
type: 'color'
}
]
},
'animation',
'animationDuration',
{
key: 'animationRule',
type: 'rc-select',
multiple: false,
items: [
{
value: 'linear',
label: 'Linear'
},
{
value: 'quad',
label: 'Quad'
},
{
value: 'quint',
label: 'Quint'
},
{
value: 'cycle',
label: 'Cycle'
},
{
value: 'bounce',
label: 'Bounce'
},
{
value: 'elastic',
label: 'Elastic'
},
{
value: 'dequad',
label: 'Dequad'
},
{
value: 'dequint',
label: 'Dequint'
},
{
value: 'decycle',
label: 'Decycle'
},
{
value: 'debounce',
label: 'Debounce'
},
{
value: 'delastic',
label: 'Delastic'
}
]
},
{
key: 'animationTarget',
type: 'rc-select',
multiple: false,
items: [
{
value: 'needle',
label: 'Needle'
},
{
value: 'plate',
label: 'Plate'
}
]
}
]
};

View File

@ -0,0 +1,108 @@
///
/// Copyright © 2016-2019 The Thingsboard Authors
///
/// Licensed under the Apache License, Version 2.0 (the "License");
/// you may not use this file except in compliance with the License.
/// You may obtain a copy of the License at
///
/// http://www.apache.org/licenses/LICENSE-2.0
///
/// Unless required by applicable law or agreed to in writing, software
/// distributed under the License is distributed on an "AS IS" BASIS,
/// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
/// See the License for the specific language governing permissions and
/// limitations under the License.
///
import { WidgetContext } from '@home/models/widget-component.models';
import * as CanvasGauges from 'canvas-gauges';
import {
AnalogueCompassSettings,
analogueCompassSettingsSchema
} from '@home/components/widget/lib/analogue-compass.models';
import { deepClone, isDefined } from '@core/utils';
import { JsonSettingsSchema } from '@shared/models/widget.models';
import { getFontFamily } from '@home/components/widget/lib/settings.models';
import { TbBaseGauge } from '@home/components/widget/lib/analogue-gauge.models';
import RadialGaugeOptions = CanvasGauges.RadialGaugeOptions;
import BaseGauge = CanvasGauges.BaseGauge;
import RadialGauge = CanvasGauges.RadialGauge;
const analogueCompassSettingsSchemaValue = analogueCompassSettingsSchema;
export class TbAnalogueCompass extends TbBaseGauge<AnalogueCompassSettings, RadialGaugeOptions> {
static get settingsSchema(): JsonSettingsSchema {
return analogueCompassSettingsSchemaValue;
}
constructor(ctx: WidgetContext, canvasId: string) {
super(ctx, canvasId);
}
protected createGaugeOptions(gaugeElement: HTMLElement, settings: AnalogueCompassSettings): RadialGaugeOptions {
const majorTicks = (settings.majorTicks && settings.majorTicks.length > 0) ? deepClone(settings.majorTicks) :
['N','NE','E','SE','S','SW','W','NW'];
majorTicks.push(majorTicks[0]);
return {
renderTo: gaugeElement,
// Generic options
minValue: 0,
maxValue: 360,
majorTicks,
minorTicks: settings.minorTicks || 22,
ticksAngle: 360,
startAngle: 180,
strokeTicks: settings.showStrokeTicks || false,
highlights: [],
valueBox: false,
// needle
needleCircleSize: settings.needleCircleSize || 15,
needleType: 'line',
needleStart: 75,
needleEnd: 99,
needleWidth: 3,
needleCircleOuter: false,
// borders
borders: settings.showBorder || false,
borderInnerWidth: 0,
borderMiddleWidth: 0,
borderOuterWidth: settings.borderOuterWidth || 10,
borderShadowWidth: 0,
// colors
colorPlate: settings.colorPlate || '#222',
colorMajorTicks: settings.colorMajorTicks || '#f5f5f5',
colorMinorTicks: settings.colorMinorTicks || '#ddd',
colorNeedle: settings.colorNeedle || '#f08080',
colorNeedleEnd: settings.colorNeedle || '#f08080',
colorNeedleCircleInner: settings.colorNeedleCircle || '#e8e8e8',
colorNeedleCircleInnerEnd: settings.colorNeedleCircle || '#e8e8e8',
colorBorderOuter: settings.colorBorder || '#ccc',
colorBorderOuterEnd: settings.colorBorder || '#ccc',
colorNeedleShadowDown: '#222',
// fonts
fontNumbers: getFontFamily(settings.majorTickFont),
fontNumbersSize: settings.majorTickFont && settings.majorTickFont.size ? settings.majorTickFont.size : 20,
fontNumbersStyle: settings.majorTickFont && settings.majorTickFont.style ? settings.majorTickFont.style : 'normal',
fontNumbersWeight: settings.majorTickFont && settings.majorTickFont.weight ? settings.majorTickFont.weight : '500',
colorNumbers: settings.majorTickFont && settings.majorTickFont.color ? settings.majorTickFont.color : '#ccc',
// animations
animation: settings.animation !== false && !this.ctx.isMobile,
animationDuration: (isDefined(settings.animationDuration) && settings.animationDuration !== null) ? settings.animationDuration : 500,
animationRule: settings.animationRule || 'cycle',
animationTarget: settings.animationTarget || 'needle'
};
}
protected createGauge(gaugeData: RadialGaugeOptions): BaseGauge {
return new RadialGauge(gaugeData);
}
}

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,88 @@
///
/// Copyright © 2016-2019 The Thingsboard Authors
///
/// Licensed under the Apache License, Version 2.0 (the "License");
/// you may not use this file except in compliance with the License.
/// You may obtain a copy of the License at
///
/// http://www.apache.org/licenses/LICENSE-2.0
///
/// Unless required by applicable law or agreed to in writing, software
/// distributed under the License is distributed on an "AS IS" BASIS,
/// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
/// See the License for the specific language governing permissions and
/// limitations under the License.
///
import { JsonSettingsSchema } from '@shared/models/widget.models';
import { AnalogueGaugeSettings, analogueGaugeSettingsSchema } from '@home/components/widget/lib/analogue-gauge.models';
import { deepClone } from '@core/utils';
export interface AnalogueLinearGaugeSettings extends AnalogueGaugeSettings {
barStrokeWidth: number;
colorBarStroke: string;
colorBar: string;
colorBarEnd: string;
colorBarProgress: string;
colorBarProgressEnd: string;
}
export function getAnalogueLinearGaugeSettingsSchema(): JsonSettingsSchema {
const analogueLinearGaugeSettingsSchema = deepClone(analogueGaugeSettingsSchema);
analogueLinearGaugeSettingsSchema.schema.properties =
{...analogueLinearGaugeSettingsSchema.schema.properties, ...{
barStrokeWidth: {
title: 'Bar stroke width',
type: 'number',
default: 2.5
},
colorBarStroke: {
title: 'Bar stroke color',
type: 'string',
default: null
},
colorBar: {
title: 'Bar background color',
type: 'string',
default: '#fff'
},
colorBarEnd: {
title: 'Bar background color - end gradient',
type: 'string',
default: '#ddd'
},
colorBarProgress: {
title: 'Progress bar color',
type: 'string',
default: null
},
colorBarProgressEnd: {
title: 'Progress bar color - end gradient',
type: 'string',
default: null
}}};
analogueLinearGaugeSettingsSchema.form.unshift(
'barStrokeWidth',
{
key: 'colorBarStroke',
type: 'color'
},
{
key: 'colorBar',
type: 'color'
},
{
key: 'colorBarEnd',
type: 'color'
},
{
key: 'colorBarProgress',
type: 'color'
},
{
key: 'colorBarProgressEnd',
type: 'color'
}
);
return analogueLinearGaugeSettingsSchema;
}

View File

@ -0,0 +1,65 @@
///
/// Copyright © 2016-2019 The Thingsboard Authors
///
/// Licensed under the Apache License, Version 2.0 (the "License");
/// you may not use this file except in compliance with the License.
/// You may obtain a copy of the License at
///
/// http://www.apache.org/licenses/LICENSE-2.0
///
/// Unless required by applicable law or agreed to in writing, software
/// distributed under the License is distributed on an "AS IS" BASIS,
/// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
/// See the License for the specific language governing permissions and
/// limitations under the License.
///
import * as CanvasGauges from 'canvas-gauges';
import { JsonSettingsSchema } from '@shared/models/widget.models';
import { WidgetContext } from '@home/models/widget-component.models';
import { TbAnalogueGauge } from '@home/components/widget/lib/analogue-gauge.models';
import {
AnalogueLinearGaugeSettings,
getAnalogueLinearGaugeSettingsSchema
} from '@home/components/widget/lib/analogue-linear-gauge.models';
import { isDefined } from '@core/utils';
import * as tinycolor_ from 'tinycolor2';
import LinearGaugeOptions = CanvasGauges.LinearGaugeOptions;
import LinearGauge = CanvasGauges.LinearGauge;
import BaseGauge = CanvasGauges.BaseGauge;
const tinycolor = tinycolor_;
const analogueLinearGaugeSettingsSchemaValue = getAnalogueLinearGaugeSettingsSchema();
export class TbAnalogueLinearGauge extends TbAnalogueGauge<AnalogueLinearGaugeSettings,LinearGaugeOptions>{
static get settingsSchema(): JsonSettingsSchema {
return analogueLinearGaugeSettingsSchemaValue;
}
constructor(ctx: WidgetContext, canvasId: string) {
super(ctx, canvasId);
}
protected prepareGaugeOptions(settings: AnalogueLinearGaugeSettings, gaugeData: LinearGaugeOptions) {
const dataKey = this.ctx.data[0].dataKey;
const keyColor = settings.defaultColor || dataKey.color;
const barStrokeColor = tinycolor(keyColor).darken().setAlpha(0.6).toRgbString();
const progressColorStart = tinycolor(keyColor).setAlpha(0.05).toRgbString();
const progressColorEnd = tinycolor(keyColor).darken().toRgbString();
gaugeData.barStrokeWidth = (isDefined(settings.barStrokeWidth) && settings.barStrokeWidth !== null) ? settings.barStrokeWidth : 2.5;
gaugeData.colorBarStroke = settings.colorBarStroke || barStrokeColor;
gaugeData.colorBar = settings.colorBar || '#fff';
gaugeData.colorBarEnd = settings.colorBarEnd || '#ddd';
gaugeData.colorBarProgress = settings.colorBarProgress || progressColorStart;
gaugeData.colorBarProgressEnd = settings.colorBarProgressEnd || progressColorEnd;
}
protected createGauge(gaugeData: LinearGaugeOptions): BaseGauge {
return new LinearGauge(gaugeData);
}
}

View File

@ -0,0 +1,52 @@
///
/// Copyright © 2016-2019 The Thingsboard Authors
///
/// Licensed under the Apache License, Version 2.0 (the "License");
/// you may not use this file except in compliance with the License.
/// You may obtain a copy of the License at
///
/// http://www.apache.org/licenses/LICENSE-2.0
///
/// Unless required by applicable law or agreed to in writing, software
/// distributed under the License is distributed on an "AS IS" BASIS,
/// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
/// See the License for the specific language governing permissions and
/// limitations under the License.
///
import { JsonSettingsSchema } from '@shared/models/widget.models';
import { AnalogueGaugeSettings, analogueGaugeSettingsSchema } from '@home/components/widget/lib/analogue-gauge.models';
import { deepClone } from '@core/utils';
export interface AnalogueRadialGaugeSettings extends AnalogueGaugeSettings {
startAngle: number;
ticksAngle: number;
needleCircleSize: number;
}
export function getAnalogueRadialGaugeSettingsSchema(): JsonSettingsSchema {
const analogueRadialGaugeSettingsSchema = deepClone(analogueGaugeSettingsSchema);
analogueRadialGaugeSettingsSchema.schema.properties =
{...analogueRadialGaugeSettingsSchema.schema.properties, ...{
startAngle: {
title: 'Start ticks angle',
type: 'number',
default: 45
},
ticksAngle: {
title: 'Ticks angle',
type: 'number',
default: 270
},
needleCircleSize: {
title: 'Needle circle size',
type: 'number',
default: 10
}}};
analogueRadialGaugeSettingsSchema.form.unshift(
'startAngle',
'ticksAngle',
'needleCircleSize'
);
return analogueRadialGaugeSettingsSchema;
}

View File

@ -0,0 +1,64 @@
///
/// Copyright © 2016-2019 The Thingsboard Authors
///
/// Licensed under the Apache License, Version 2.0 (the "License");
/// you may not use this file except in compliance with the License.
/// You may obtain a copy of the License at
///
/// http://www.apache.org/licenses/LICENSE-2.0
///
/// Unless required by applicable law or agreed to in writing, software
/// distributed under the License is distributed on an "AS IS" BASIS,
/// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
/// See the License for the specific language governing permissions and
/// limitations under the License.
///
import * as CanvasGauges from 'canvas-gauges';
import {
AnalogueRadialGaugeSettings, getAnalogueRadialGaugeSettingsSchema
} from '@home/components/widget/lib/analogue-radial-gauge.models';
import { JsonSettingsSchema } from '@shared/models/widget.models';
import { WidgetContext } from '@home/models/widget-component.models';
import { TbAnalogueGauge } from '@home/components/widget/lib/analogue-gauge.models';
import RadialGauge = CanvasGauges.RadialGauge;
import RadialGaugeOptions = CanvasGauges.RadialGaugeOptions;
import BaseGauge = CanvasGauges.BaseGauge;
const analogueRadialGaugeSettingsSchemaValue = getAnalogueRadialGaugeSettingsSchema();
export class TbAnalogueRadialGauge extends TbAnalogueGauge<AnalogueRadialGaugeSettings,RadialGaugeOptions>{
static get settingsSchema(): JsonSettingsSchema {
return analogueRadialGaugeSettingsSchemaValue;
}
constructor(ctx: WidgetContext, canvasId: string) {
super(ctx, canvasId);
}
protected prepareGaugeOptions(settings: AnalogueRadialGaugeSettings, gaugeData: RadialGaugeOptions) {
gaugeData.ticksAngle = settings.ticksAngle || 270;
gaugeData.startAngle = settings.startAngle || 45;
// colors
gaugeData.colorNeedleCircleOuter = '#f0f0f0';
gaugeData.colorNeedleCircleOuterEnd = '#ccc';
gaugeData.colorNeedleCircleInner = '#e8e8e8'; // tinycolor(keyColor).lighten(30).toRgbString(),//'#e8e8e8',
gaugeData.colorNeedleCircleInnerEnd = '#f5f5f5';
// needle
gaugeData.needleCircleSize = settings.needleCircleSize || 10;
gaugeData.needleCircleInner = true;
gaugeData.needleCircleOuter = true;
// custom animations
gaugeData.animationTarget = 'needle'; // 'needle' or 'plate'
}
protected createGauge(gaugeData: RadialGaugeOptions): BaseGauge {
return new RadialGauge(gaugeData);
}
}

View File

@ -0,0 +1,38 @@
///
/// Copyright © 2016-2019 The Thingsboard Authors
///
/// Licensed under the Apache License, Version 2.0 (the "License");
/// you may not use this file except in compliance with the License.
/// You may obtain a copy of the License at
///
/// http://www.apache.org/licenses/LICENSE-2.0
///
/// Unless required by applicable law or agreed to in writing, software
/// distributed under the License is distributed on an "AS IS" BASIS,
/// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
/// See the License for the specific language governing permissions and
/// limitations under the License.
///
export type FontStyle = 'normal' | 'italic' | 'oblique';
export type FontWeight = 'normal' | 'bold' | 'bolder' | 'lighter'
| '100' | '200' | '300' | '400' | '500'
| '600' | '700' | '800' | '900';
export interface FontSettings {
family: string;
size: number;
style: FontStyle;
weight: FontWeight;
color: string;
shadowColor?: string;
}
export function getFontFamily(fontSettings: FontSettings): string {
let family = fontSettings && fontSettings.family ? fontSettings.family : 'Roboto';
if (family === 'RobotoDraft') {
family = 'Roboto';
}
return family;
}

View File

@ -37,17 +37,11 @@ import { DynamicWidgetComponent } from '@home/components/widget/dynamic-widget.c
import { WidgetComponentsModule } from '@home/components/widget/widget-components.module';
import { WINDOW } from '@core/services/window.service';
import * as tinycolor_ from 'tinycolor2';
import { TbFlot } from './lib/flot-widget';
import { NULL_UUID } from '@shared/models/id/has-uuid';
import { WidgetTypeId } from '@app/shared/models/id/widget-type-id';
import { TenantId } from '@app/shared/models/id/tenant-id';
import { SharedModule } from '@shared/shared.module';
const tinycolor = tinycolor_;
// declare var jQuery: any;
// @dynamic
@Injectable()
export class WidgetComponentService {
@ -70,12 +64,6 @@ export class WidgetComponentService {
private utils: UtilsService,
private resources: ResourcesService,
private translate: TranslateService) {
// @ts-ignore
this.window.tinycolor = tinycolor;
// @ts-ignore
this.window.cssjs = cssjs;
// @ts-ignore
this.window.TbFlot = TbFlot;
this.cssParser.testMode = false;

View File

@ -168,11 +168,11 @@ export class JsonFormComponent implements OnInit, ControlValueAccessor, Validato
}
}
private onModelChange(key: (string | number)[], val: any) {
private onModelChange(key: (string | number)[], val: any, forceUpdate = false) {
if (isString(val) && val === '') {
val = undefined;
}
if (JsonFormUtils.updateValue(key, this.model, val)) {
if (JsonFormUtils.updateValue(key, this.model, val) || forceUpdate) {
this.formProps.model = this.model;
this.isModelValid = this.validateModel();
this.updateView();

View File

@ -96,7 +96,7 @@ class ThingsboardArray extends React.Component<JsonFormFieldProps, ThingsboardAr
keys: newKeys
}
);
this.props.onChangeValidate(this.state.model);
this.props.onChangeValidate(this.state.model, true);
}
onDelete(index: number) {
@ -110,7 +110,7 @@ class ThingsboardArray extends React.Component<JsonFormFieldProps, ThingsboardAr
keys: newKeys
}
);
this.props.onChangeValidate(this.state.model);
this.props.onChangeValidate(this.state.model, true);
}
setIndex(index: number) {

View File

@ -38,7 +38,7 @@ export default ThingsboardBaseComponent => class<P extends JsonFormFieldProps>
}*/
}
onChangeValidate(e) {
onChangeValidate(e, forceUpdate?: boolean) {
let value = null;
if (this.props.form.schema.type === 'integer' || this.props.form.schema.type === 'number') {
if (e.target.value === null || e.target.value === '') {
@ -61,7 +61,7 @@ export default ThingsboardBaseComponent => class<P extends JsonFormFieldProps>
valid: validationResult.valid,
error: validationResult.valid ? null : validationResult.error.message
});
this.props.onChange(this.props.form.key, value);
this.props.onChange(this.props.form.key, value, forceUpdate);
}
defaultValue() {

View File

@ -6,7 +6,6 @@ import FormControl from '@material-ui/core/FormControl';
import ThingsboardBaseComponent from '@shared/components/json-form/react/json-form-base-component';
class ThingsboardRadios extends React.Component<JsonFormFieldProps, JsonFormFieldState> {
render() {
const items = this.props.form.titleMap.map((item, index) => {
return (
@ -19,7 +18,9 @@ class ThingsboardRadios extends React.Component<JsonFormFieldProps, JsonFormFiel
className={this.props.form.htmlClass}
disabled={this.props.form.readonly}>
<FormLabel component='legend'>{this.props.form.title}</FormLabel>
<RadioGroup name={this.props.form.title} value={this.props.value} onChange={this.props.onChangeValidate}>
<RadioGroup name={this.props.form.title} value={this.props.value} onChange={(e) => {
this.props.onChangeValidate(e);
}}>
{items}
</RadioGroup>
</FormControl>

View File

@ -73,8 +73,8 @@ class ThingsboardSchemaForm extends React.Component<JsonFormProps, any> {
this.hasConditions = false;
}
onChange(key: (string | number)[], val: any) {
this.props.onModelChange(key, val);
onChange(key: (string | number)[], val: any, forceUpdate?: boolean) {
this.props.onModelChange(key, val, forceUpdate);
if (this.hasConditions) {
this.forceUpdate();
}

View File

@ -68,7 +68,9 @@ class ThingsboardText extends React.Component<JsonFormFieldProps, ThingsboardTex
multiline={multiline}
error={!this.props.valid}
helperText={this.props.valid ? this.props.form.placeholder : this.props.error}
onChange={this.props.onChangeValidate}
onChange={(e) => {
this.props.onChangeValidate(e);
}}
defaultValue={this.props.value}
disabled={this.props.form.readonly}
rows={rows}

View File

@ -50,7 +50,7 @@ export interface GroupInfo {
GroupTitle: string;
}
export type onChangeFn = (key: (string | number)[], val: any) => void;
export type onChangeFn = (key: (string | number)[], val: any, forceUpdate?: boolean) => void;
export type OnColorClickFn = (key: (string | number)[], val: tinycolor.ColorFormats.RGBA,
colorSelectedFn: (color: tinycolor.ColorFormats.RGBA) => void) => void;
export type onToggleFullscreenFn = (element: HTMLElement, fullscreenFinishFn?: () => void) => void;
@ -122,7 +122,7 @@ export interface JsonFormFieldProps {
mapper?: {[type: string]: any};
onChange?: onChangeFn;
onColorClick?: OnColorClickFn;
onChangeValidate?: (e: any) => void;
onChangeValidate?: (e: any, forceUpdate?: boolean) => void;
onToggleFullscreen?: onToggleFullscreenFn;
valid?: boolean;
error?: string;

View File

@ -81,3 +81,24 @@ import 'core-js/es/array';
*/
(window as any).global = window;
/***************************************************************************************************
* WIDGETS IMPORTS
*/
import cssjs from '@core/css/css';
import { TbFlot } from '@home/components/widget/lib/flot-widget';
import { TbAnalogueCompass } from '@home/components/widget/lib/analogue-compass';
import { TbAnalogueRadialGauge } from '@home/components/widget/lib/analogue-radial-gauge';
import { TbAnalogueLinearGauge } from '@home/components/widget/lib/analogue-linear-gauge';
import * as tinycolor_ from 'tinycolor2';
const tinycolor = tinycolor_;
(window as any).tinycolor = tinycolor;
(window as any).cssjs = cssjs;
(window as any).TbFlot = TbFlot;
(window as any).TbAnalogueCompass = TbAnalogueCompass;
(window as any).TbAnalogueRadialGauge = TbAnalogueRadialGauge;
(window as any).TbAnalogueLinearGauge = TbAnalogueLinearGauge;

File diff suppressed because one or more lines are too long

View File

@ -22,6 +22,7 @@
@import './scss/constants';
@import './scss/animations';
@import './scss/mixins';
@import './scss/fonts';
body, html {
height: 100%;

View File

@ -2,7 +2,7 @@
"extends": "../tsconfig.json",
"compilerOptions": {
"outDir": "../out-tsc/app",
"types": ["node", "jquery", "flot", "tooltipster", "tinycolor2", "js-beautify", "react", "react-dom", "jstree", "raphael"]
"types": ["node", "jquery", "flot", "tooltipster", "tinycolor2", "js-beautify", "react", "react-dom", "jstree", "raphael", "canvas-gauges"]
},
"angularCompilerOptions": {
"fullTemplateTypeCheck": true