-
diff --git a/ui-ngx/src/app/modules/home/components/widget/lib/svg/iot-svg-widget.component.scss b/ui-ngx/src/app/modules/home/components/widget/lib/scada/scada-symbol-widget.component.scss
similarity index 82%
rename from ui-ngx/src/app/modules/home/components/widget/lib/svg/iot-svg-widget.component.scss
rename to ui-ngx/src/app/modules/home/components/widget/lib/scada/scada-symbol-widget.component.scss
index b109bac863..13543851ad 100644
--- a/ui-ngx/src/app/modules/home/components/widget/lib/svg/iot-svg-widget.component.scss
+++ b/ui-ngx/src/app/modules/home/components/widget/lib/scada/scada-symbol-widget.component.scss
@@ -14,18 +14,20 @@
* limitations under the License.
*/
-.tb-iot-svg-panel {
+.tb-scada-symbol-panel {
width: 100%;
height: 100%;
position: relative;
display: flex;
flex-direction: column;
- gap: 16px;
- padding: 20px 24px 24px 24px;
- > div:not(.tb-iot-svg-overlay) {
+ gap: 8px;
+ &.overlay {
+ padding: 20px 24px 24px 24px;
+ }
+ > div:not(.tb-scada-symbol-overlay) {
z-index: 1;
}
- .tb-iot-svg-overlay {
+ .tb-scada-symbol-overlay {
position: absolute;
top: 12px;
left: 12px;
@@ -35,11 +37,11 @@
div.tb-widget-title {
padding: 0;
}
- .tb-iot-svg-content {
+ .tb-scada-symbol-content {
flex: 1;
min-width: 0;
min-height: 0;
- .tb-iot-svg-shape {
+ .tb-scada-symbol-shape {
width: 100%;
height: 100%;
display: flex;
diff --git a/ui-ngx/src/app/modules/home/components/widget/lib/svg/iot-svg-widget.component.ts b/ui-ngx/src/app/modules/home/components/widget/lib/scada/scada-symbol-widget.component.ts
similarity index 52%
rename from ui-ngx/src/app/modules/home/components/widget/lib/svg/iot-svg-widget.component.ts
rename to ui-ngx/src/app/modules/home/components/widget/lib/scada/scada-symbol-widget.component.ts
index 52f40152a0..7f275cd09a 100644
--- a/ui-ngx/src/app/modules/home/components/widget/lib/svg/iot-svg-widget.component.ts
+++ b/ui-ngx/src/app/modules/home/components/widget/lib/scada/scada-symbol-widget.component.ts
@@ -22,36 +22,35 @@ import {
Input,
OnDestroy,
OnInit,
- Renderer2,
TemplateRef,
ViewChild,
ViewEncapsulation
} from '@angular/core';
import { ImagePipe } from '@shared/pipe/image.pipe';
import { DomSanitizer } from '@angular/platform-browser';
-import { HttpClient } from '@angular/common/http';
-import { IotSvgObject, IotSvgObjectCallbacks } from '@home/components/widget/lib/svg/iot-svg.models';
+import { ScadaSymbolObject, ScadaSymbolObjectCallbacks } from '@home/components/widget/lib/scada/scada-symbol.models';
import {
- iotSvgWidgetDefaultSettings,
- IotSvgWidgetSettings
-} from '@home/components/widget/lib/svg/iot-svg-widget.models';
-import { Observable, of } from 'rxjs';
+ scadaSymbolWidgetDefaultSettings,
+ ScadaSymbolWidgetSettings
+} from '@home/components/widget/lib/scada/scada-symbol-widget.models';
+import { BehaviorSubject, Observable, of } from 'rxjs';
import { backgroundStyle, ComponentStyle, overlayStyle } from '@shared/models/widget-settings.models';
import { ImageService } from '@core/http/image.service';
import { WidgetComponent } from '@home/components/widget/widget.component';
import { isDefinedAndNotNull, mergeDeep } from '@core/utils';
import { WidgetContext } from '@home/models/widget-component.models';
+import { catchError, share } from 'rxjs/operators';
@Component({
- selector: 'tb-iot-svg-widget',
- templateUrl: './iot-svg-widget.component.html',
- styleUrls: ['../action/action-widget.scss', './iot-svg-widget.component.scss'],
+ selector: 'tb-scada-symbol-widget',
+ templateUrl: './scada-symbol-widget.component.html',
+ styleUrls: ['../action/action-widget.scss', './scada-symbol-widget.component.scss'],
encapsulation: ViewEncapsulation.None
})
-export class IotSvgWidgetComponent implements OnInit, AfterViewInit, OnDestroy, IotSvgObjectCallbacks {
+export class ScadaSymbolWidgetComponent implements OnInit, AfterViewInit, OnDestroy, ScadaSymbolObjectCallbacks {
- @ViewChild('iotSvgShape', {static: false})
- iotSvgShape: ElementRef
;
+ @ViewChild('scadaSymbolShape', {static: false})
+ scadaSymbolShape: ElementRef;
@Input()
ctx: WidgetContext;
@@ -59,47 +58,57 @@ export class IotSvgWidgetComponent implements OnInit, AfterViewInit, OnDestroy,
@Input()
widgetTitlePanel: TemplateRef;
- private settings: IotSvgWidgetSettings;
- private svgContent$: Observable;
+ private loadingSubject = new BehaviorSubject(false);
+ private settings: ScadaSymbolWidgetSettings;
+ private scadaSymbolContent$: Observable;
backgroundStyle$: Observable;
overlayStyle: ComponentStyle = {};
- iotSvgObject: IotSvgObject;
+ overlayEnabled: boolean;
+ padding: string;
+
+ loading$ = this.loadingSubject.asObservable().pipe(share());
+
+ scadaSymbolObject: ScadaSymbolObject;
constructor(public widgetComponent: WidgetComponent,
protected imagePipe: ImagePipe,
protected sanitizer: DomSanitizer,
private imageService: ImageService,
- protected cd: ChangeDetectorRef,
- private http: HttpClient) {
+ protected cd: ChangeDetectorRef) {
}
ngOnInit(): void {
this.ctx.$scope.actionWidget = this;
- this.settings = mergeDeep({} as IotSvgWidgetSettings, iotSvgWidgetDefaultSettings, this.ctx.settings || {});
+ this.settings = mergeDeep({} as ScadaSymbolWidgetSettings, scadaSymbolWidgetDefaultSettings, this.ctx.settings || {});
this.backgroundStyle$ = backgroundStyle(this.settings.background, this.imagePipe, this.sanitizer);
this.overlayStyle = overlayStyle(this.settings.background.overlay);
-
- if (this.settings.iotSvgContent) {
- this.svgContent$ = of(this.settings.iotSvgContent);
- } else if (this.settings.iotSvgUrl) {
- this.svgContent$ = this.imageService.getImageString(this.settings.iotSvgUrl);
+ this.overlayEnabled = this.settings.background.overlay.enabled;
+ this.padding = this.overlayEnabled ? undefined : this.settings.padding;
+
+ if (this.settings.scadaSymbolContent) {
+ this.scadaSymbolContent$ = of(this.settings.scadaSymbolContent);
+ } else if (this.settings.scadaSymbolUrl) {
+ this.scadaSymbolContent$ = this.imageService.getImageString(this.settings.scadaSymbolUrl)
+ .pipe(catchError(() => of('')));
} else {
- this.svgContent$ = this.http.get(this.settings.iotSvg, {responseType: 'text'});
+ this.scadaSymbolContent$ = of('');
}
}
ngAfterViewInit(): void {
- this.svgContent$.subscribe((content) => {
- this.initObject(this.iotSvgShape.nativeElement, content);
+ this.scadaSymbolContent$.subscribe((content) => {
+ this.initObject(this.scadaSymbolShape.nativeElement, content);
});
}
ngOnDestroy() {
- if (this.iotSvgObject) {
- this.iotSvgObject.destroy();
+ if (this.scadaSymbolObject) {
+ this.scadaSymbolObject.destroy();
}
+ this.loadingSubject.complete();
+ this.loadingSubject.unsubscribe();
}
public onInit() {
@@ -108,19 +117,24 @@ export class IotSvgWidgetComponent implements OnInit, AfterViewInit, OnDestroy,
this.cd.detectChanges();
}
- onSvgObjectError(error: string) {
+ onScadaSymbolObjectLoadingState(loading: boolean) {
+ this.loadingSubject.next(loading);
+ }
+
+ onScadaSymbolObjectError(error: string) {
this.ctx.showErrorToast(error, 'bottom', 'center', this.ctx.toastTargetId, true);
}
- onSvgObjectMessage(message: string) {
+ onScadaSymbolObjectMessage(message: string) {
this.ctx.showSuccessToast(message, 3000, 'bottom', 'center', this.ctx.toastTargetId, true);
}
private initObject(rootElement: HTMLElement,
- svgContent: string) {
+ content: string) {
const simulated = this.ctx.utilsService.widgetEditMode ||
this.ctx.isPreview || (isDefinedAndNotNull(this.settings.simulated) ? this.settings.simulated : false);
- this.iotSvgObject = new IotSvgObject(rootElement, this.ctx, svgContent, this.settings.iotSvgObject, this, simulated);
+ this.scadaSymbolObject = new ScadaSymbolObject(rootElement, this.ctx, content,
+ this.settings.scadaSymbolObjectSettings, this, simulated);
}
}
diff --git a/ui-ngx/src/app/modules/home/components/widget/lib/svg/iot-svg-widget.models.ts b/ui-ngx/src/app/modules/home/components/widget/lib/scada/scada-symbol-widget.models.ts
similarity index 70%
rename from ui-ngx/src/app/modules/home/components/widget/lib/svg/iot-svg-widget.models.ts
rename to ui-ngx/src/app/modules/home/components/widget/lib/scada/scada-symbol-widget.models.ts
index 6d25e94c71..691bffd1c0 100644
--- a/ui-ngx/src/app/modules/home/components/widget/lib/svg/iot-svg-widget.models.ts
+++ b/ui-ngx/src/app/modules/home/components/widget/lib/scada/scada-symbol-widget.models.ts
@@ -14,21 +14,20 @@
/// limitations under the License.
///
-import { IotSvgObjectSettings } from '@home/components/widget/lib/svg/iot-svg.models';
+import { ScadaSymbolObjectSettings } from '@home/components/widget/lib/scada/scada-symbol.models';
import { BackgroundSettings, BackgroundType } from '@shared/models/widget-settings.models';
-export interface IotSvgWidgetSettings {
- iotSvg?: string;
- iotSvgUrl?: string;
- iotSvgContent?: string;
+export interface ScadaSymbolWidgetSettings {
+ scadaSymbolUrl?: string;
+ scadaSymbolContent?: string;
simulated?: boolean;
- iotSvgObject: IotSvgObjectSettings;
+ scadaSymbolObjectSettings: ScadaSymbolObjectSettings;
background: BackgroundSettings;
+ padding: string;
}
-export const iotSvgWidgetDefaultSettings: IotSvgWidgetSettings = {
- iotSvg: '/assets/widget/svg/drawing.svg',
- iotSvgObject: {
+export const scadaSymbolWidgetDefaultSettings: ScadaSymbolWidgetSettings = {
+ scadaSymbolObjectSettings: {
behavior: {},
properties: {}
},
@@ -40,5 +39,6 @@ export const iotSvgWidgetDefaultSettings: IotSvgWidgetSettings = {
color: 'rgba(255,255,255,0.72)',
blur: 3
}
- }
+ },
+ padding: '12px'
};
diff --git a/ui-ngx/src/app/modules/home/components/widget/lib/svg/iot-svg.models.ts b/ui-ngx/src/app/modules/home/components/widget/lib/scada/scada-symbol.models.ts
similarity index 73%
rename from ui-ngx/src/app/modules/home/components/widget/lib/svg/iot-svg.models.ts
rename to ui-ngx/src/app/modules/home/components/widget/lib/scada/scada-symbol.models.ts
index f2ed7c201b..82dd2de1cc 100644
--- a/ui-ngx/src/app/modules/home/components/widget/lib/svg/iot-svg.models.ts
+++ b/ui-ngx/src/app/modules/home/components/widget/lib/scada/scada-symbol.models.ts
@@ -33,8 +33,7 @@ import {
mergeDeep,
parseFunction
} from '@core/utils';
-import { BehaviorSubject, forkJoin, Observable, Observer } from 'rxjs';
-import { share } from 'rxjs/operators';
+import { BehaviorSubject, forkJoin, Observable, Observer, Subject } from 'rxjs';
import { ValueAction, ValueGetter, ValueSetter } from '@home/components/widget/lib/action/action-widget.models';
import { WidgetContext } from '@home/models/widget-component.models';
import { ColorProcessor, constantColor, Font } from '@shared/models/widget-settings.models';
@@ -42,8 +41,9 @@ import { AttributeScope } from '@shared/models/telemetry/telemetry.models';
import { UtilsService } from '@core/services/utils.service';
import { WidgetAction, WidgetActionType, widgetActionTypeTranslationMap } from '@shared/models/widget.models';
import { ResizeObserver } from '@juggle/resize-observer';
+import { takeUntil } from 'rxjs/operators';
-export interface IotSvgApi {
+export interface ScadaSymbolApi {
formatValue: (value: any, dec?: number, units?: string, showZeroDecimals?: boolean) => string | undefined;
text: (element: Element | Element[], text: string) => void;
font: (element: Element | Element[], font: Font, color: string) => void;
@@ -54,57 +54,57 @@ export interface IotSvgApi {
setValue: (valueId: string, value: any) => void;
}
-export interface IotSvgContext {
- api: IotSvgApi;
+export interface ScadaSymbolContext {
+ api: ScadaSymbolApi;
tags: {[id: string]: Element[]};
values: {[id: string]: any};
properties: {[id: string]: any};
}
-export type IotSvgStateRenderFunction = (ctx: IotSvgContext, svg: Svg) => void;
+export type ScadaSymbolStateRenderFunction = (ctx: ScadaSymbolContext, svg: Svg) => void;
-export type IotSvgTagStateRenderFunction = (ctx: IotSvgContext, element: Element) => void;
+export type ScadaSymbolTagStateRenderFunction = (ctx: ScadaSymbolContext, element: Element) => void;
-export type IotSvgActionTrigger = 'click';
+export type ScadaSymbolActionTrigger = 'click';
-export type IotSvgActionFunction = (ctx: IotSvgContext, element: Element, event: Event) => void;
-export interface IotSvgAction {
+export type ScadaSymbolActionFunction = (ctx: ScadaSymbolContext, element: Element, event: Event) => void;
+export interface ScadaSymbolAction {
actionFunction?: string;
- action?: IotSvgActionFunction;
+ action?: ScadaSymbolActionFunction;
}
-export interface IotSvgTag {
+export interface ScadaSymbolTag {
tag: string;
stateRenderFunction?: string;
- stateRender?: IotSvgTagStateRenderFunction;
- actions?: {[trigger: string]: IotSvgAction};
+ stateRender?: ScadaSymbolTagStateRenderFunction;
+ actions?: {[trigger: string]: ScadaSymbolAction};
}
-export enum IotSvgBehaviorType {
+export enum ScadaSymbolBehaviorType {
value = 'value',
action = 'action',
widgetAction = 'widgetAction'
}
-export const iotSvgBehaviorTypes = Object.keys(IotSvgBehaviorType) as IotSvgBehaviorType[];
+export const scadaSymbolBehaviorTypes = Object.keys(ScadaSymbolBehaviorType) as ScadaSymbolBehaviorType[];
-export const iotSvgBehaviorTypeTranslations = new Map(
+export const scadaSymbolBehaviorTypeTranslations = new Map(
[
- [IotSvgBehaviorType.value, 'scada.behavior.type-value'],
- [IotSvgBehaviorType.action, 'scada.behavior.type-action'],
- [IotSvgBehaviorType.widgetAction, 'scada.behavior.type-widget-action']
+ [ScadaSymbolBehaviorType.value, 'scada.behavior.type-value'],
+ [ScadaSymbolBehaviorType.action, 'scada.behavior.type-action'],
+ [ScadaSymbolBehaviorType.widgetAction, 'scada.behavior.type-widget-action']
]
);
-export interface IotSvgBehaviorBase {
+export interface ScadaSymbolBehaviorBase {
id: string;
name: string;
hint?: string;
- type: IotSvgBehaviorType;
+ type: ScadaSymbolBehaviorType;
}
-export interface IotSvgBehaviorValue extends IotSvgBehaviorBase {
+export interface ScadaSymbolBehaviorValue extends ScadaSymbolBehaviorBase {
valueType: ValueType;
defaultValue: any;
trueLabel?: string;
@@ -112,16 +112,16 @@ export interface IotSvgBehaviorValue extends IotSvgBehaviorBase {
stateLabel?: string;
}
-export interface IotSvgBehaviorAction extends IotSvgBehaviorBase {
+export interface ScadaSymbolBehaviorAction extends ScadaSymbolBehaviorBase {
valueType: ValueType;
valueToDataType: ValueToDataType;
constantValue: any;
valueToDataFunction: string;
}
-export type IotSvgBehavior = IotSvgBehaviorValue & IotSvgBehaviorAction;
+export type ScadaSymbolBehavior = ScadaSymbolBehaviorValue & ScadaSymbolBehaviorAction;
-export enum IotSvgPropertyType {
+export enum ScadaSymbolPropertyType {
text = 'text',
number = 'number',
switch = 'switch',
@@ -131,30 +131,30 @@ export enum IotSvgPropertyType {
units = 'units'
}
-export const iotSvgPropertyTypes = Object.keys(IotSvgPropertyType) as IotSvgPropertyType[];
+export const scadaSymbolPropertyTypes = Object.keys(ScadaSymbolPropertyType) as ScadaSymbolPropertyType[];
-export const iotSvgPropertyTypeTranslations = new Map(
+export const scadaSymbolPropertyTypeTranslations = new Map(
[
- [IotSvgPropertyType.text, 'scada.property.type-text'],
- [IotSvgPropertyType.number, 'scada.property.type-number'],
- [IotSvgPropertyType.switch, 'scada.property.type-switch'],
- [IotSvgPropertyType.color, 'scada.property.type-color'],
- [IotSvgPropertyType.color_settings, 'scada.property.type-color-settings'],
- [IotSvgPropertyType.font, 'scada.property.type-font'],
- [IotSvgPropertyType.units, 'scada.property.type-units']
+ [ScadaSymbolPropertyType.text, 'scada.property.type-text'],
+ [ScadaSymbolPropertyType.number, 'scada.property.type-number'],
+ [ScadaSymbolPropertyType.switch, 'scada.property.type-switch'],
+ [ScadaSymbolPropertyType.color, 'scada.property.type-color'],
+ [ScadaSymbolPropertyType.color_settings, 'scada.property.type-color-settings'],
+ [ScadaSymbolPropertyType.font, 'scada.property.type-font'],
+ [ScadaSymbolPropertyType.units, 'scada.property.type-units']
]
);
-export const iotSvgPropertyRowClasses =
+export const scadaSymbolPropertyRowClasses =
['column', 'column-xs', 'column-lt-md', 'align-start', 'no-border', 'no-gap', 'no-padding', 'same-padding'];
-export const iotSvgPropertyFieldClasses =
+export const scadaSymbolPropertyFieldClasses =
['medium-width', 'flex', 'flex-xs', 'flex-lt-md'];
-export interface IotSvgPropertyBase {
+export interface ScadaSymbolPropertyBase {
id: string;
name: string;
- type: IotSvgPropertyType;
+ type: ScadaSymbolPropertyType;
default: any;
required?: boolean;
subLabel?: string;
@@ -165,24 +165,24 @@ export interface IotSvgPropertyBase {
fieldClass?: string;
}
-export interface IotSvgNumberProperty extends IotSvgPropertyBase {
+export interface ScadaSymbolNumberProperty extends ScadaSymbolPropertyBase {
min?: number;
max?: number;
step?: number;
}
-export type IotSvgProperty = IotSvgPropertyBase & IotSvgNumberProperty;
+export type ScadaSymbolProperty = ScadaSymbolPropertyBase & ScadaSymbolNumberProperty;
-export interface IotSvgMetadata {
+export interface ScadaSymbolMetadata {
title: string;
stateRenderFunction?: string;
- stateRender?: IotSvgStateRenderFunction;
- tags: IotSvgTag[];
- behavior: IotSvgBehavior[];
- properties: IotSvgProperty[];
+ stateRender?: ScadaSymbolStateRenderFunction;
+ tags: ScadaSymbolTag[];
+ behavior: ScadaSymbolBehavior[];
+ properties: ScadaSymbolProperty[];
}
-export const emptyMetadata = (): IotSvgMetadata => ({
+export const emptyMetadata = (): ScadaSymbolMetadata => ({
title: '',
tags: [],
behavior: [],
@@ -190,16 +190,16 @@ export const emptyMetadata = (): IotSvgMetadata => ({
});
-export const parseIotSvgMetadataFromContent = (svgContent: string): IotSvgMetadata => {
+export const parseScadaSymbolMetadataFromContent = (svgContent: string): ScadaSymbolMetadata => {
try {
const svgDoc = new DOMParser().parseFromString(svgContent, 'image/svg+xml');
- return parseIotSvgMetadataFromDom(svgDoc);
+ return parseScadaSymbolMetadataFromDom(svgDoc);
} catch (_e) {
return emptyMetadata();
}
};
-const parseIotSvgMetadataFromDom = (svgDoc: Document): IotSvgMetadata => {
+const parseScadaSymbolMetadataFromDom = (svgDoc: Document): ScadaSymbolMetadata => {
try {
const elements = svgDoc.getElementsByTagName('tb:metadata');
if (elements.length) {
@@ -213,13 +213,13 @@ const parseIotSvgMetadataFromDom = (svgDoc: Document): IotSvgMetadata => {
}
};
-export const updateIotSvgMetadataInContent = (svgContent: string, metadata: IotSvgMetadata): string => {
+export const updateScadaSymbolMetadataInContent = (svgContent: string, metadata: ScadaSymbolMetadata): string => {
const svgDoc = new DOMParser().parseFromString(svgContent, 'image/svg+xml');
- updateIotSvgMetadataInDom(svgDoc, metadata);
+ updateScadaSymbolMetadataInDom(svgDoc, metadata);
return svgDoc.documentElement.outerHTML;
};
-const updateIotSvgMetadataInDom = (svgDoc: Document, metadata: IotSvgMetadata) => {
+const updateScadaSymbolMetadataInDom = (svgDoc: Document, metadata: ScadaSymbolMetadata) => {
svgDoc.documentElement.setAttribute('xmlns:tb', 'https://thingsboard.io/svg');
let metadataElement: Node;
const elements = svgDoc.getElementsByTagName('tb:metadata');
@@ -238,13 +238,13 @@ const updateIotSvgMetadataInDom = (svgDoc: Document, metadata: IotSvgMetadata) =
const svgPartsRegex = /(