Browse Source

UI: Improve widget layout settings: Add preserve aspect ratio and resizable options.

pull/11580/head
Igor Kulikov 2 years ago
parent
commit
1c2d1f8780
  1. 7
      ui-ngx/src/app/core/services/dashboard-utils.service.ts
  2. 2
      ui-ngx/src/app/modules/home/components/dashboard-page/add-widget-dialog.component.ts
  3. 2
      ui-ngx/src/app/modules/home/components/dashboard-page/dashboard-page.component.ts
  4. 36
      ui-ngx/src/app/modules/home/components/widget/widget-config.component.html
  5. 22
      ui-ngx/src/app/modules/home/components/widget/widget-config.component.ts
  6. 176
      ui-ngx/src/app/modules/home/models/dashboard-component.models.ts
  7. 2
      ui-ngx/src/app/shared/models/dashboard.models.ts
  8. 2
      ui-ngx/src/app/shared/models/widget.models.ts
  9. 6
      ui-ngx/src/assets/locale/locale.constant-en_US.json

7
ui-ngx/src/app/core/services/dashboard-utils.service.ts

@ -345,10 +345,11 @@ export class DashboardUtilsService {
return widgetConfig; return widgetConfig;
} }
public prepareWidgetForScadaLayout(widget: Widget): Widget { public prepareWidgetForScadaLayout(widget: Widget, isScada: boolean): Widget {
const config = widget.config; const config = widget.config;
config.showTitle = false; config.showTitle = false;
config.dropShadow = false; config.dropShadow = false;
config.preserveAspectRatio = isScada;
config.padding = '0'; config.padding = '0';
config.margin = '0'; config.margin = '0';
config.backgroundColor = 'rgba(0,0,0,0)'; config.backgroundColor = 'rgba(0,0,0,0)';
@ -654,7 +655,9 @@ export class DashboardUtilsService {
mobileOrder: widget.config.mobileOrder, mobileOrder: widget.config.mobileOrder,
mobileHeight: widget.config.mobileHeight, mobileHeight: widget.config.mobileHeight,
mobileHide: widget.config.mobileHide, mobileHide: widget.config.mobileHide,
desktopHide: widget.config.desktopHide desktopHide: widget.config.desktopHide,
preserveAspectRatio: widget.config.preserveAspectRatio,
resizable: widget.config.resizable
}; };
if (isUndefined(originalColumns)) { if (isUndefined(originalColumns)) {
originalColumns = 24; originalColumns = 24;

2
ui-ngx/src/app/modules/home/components/dashboard-page/add-widget-dialog.component.ts

@ -187,6 +187,8 @@ export class AddWidgetDialogComponent extends DialogComponent<AddWidgetDialogCom
this.widget.config.mobileHeight = widgetConfig.layout.mobileHeight; this.widget.config.mobileHeight = widgetConfig.layout.mobileHeight;
this.widget.config.mobileHide = widgetConfig.layout.mobileHide; this.widget.config.mobileHide = widgetConfig.layout.mobileHide;
this.widget.config.desktopHide = widgetConfig.layout.desktopHide; this.widget.config.desktopHide = widgetConfig.layout.desktopHide;
this.widget.config.preserveAspectRatio = widgetConfig.layout.preserveAspectRatio;
this.widget.config.resizable = widgetConfig.layout.resizable;
this.dialogRef.close(this.widget); this.dialogRef.close(this.widget);
} }
} }

2
ui-ngx/src/app/modules/home/components/dashboard-page/dashboard-page.component.ts

@ -1351,7 +1351,7 @@ export class DashboardPageComponent extends PageComponent implements IDashboardC
} }
const scada = this.isAddingToScadaLayout(); const scada = this.isAddingToScadaLayout();
if (scada) { if (scada) {
newWidget = this.dashboardUtils.prepareWidgetForScadaLayout(newWidget); newWidget = this.dashboardUtils.prepareWidgetForScadaLayout(newWidget, widgetTypeInfo.scada);
} }
let showLayoutConfig = true; let showLayoutConfig = true;
if (scada || this.layouts.right.show || !this.showLayoutConfigInEdit(this.layouts.main.layoutCtx)) { if (scada || this.layouts.right.show || !this.showLayoutConfigInEdit(this.layouts.main.layoutCtx)) {

36
ui-ngx/src/app/modules/home/components/widget/widget-config.component.html

@ -168,18 +168,32 @@
</tb-manage-widget-actions> </tb-manage-widget-actions>
</div> </div>
</div> </div>
<div [fxShow]="selectedOption === 'mobile'" [formGroup]="layoutSettings" class="mat-content"> <div [fxShow]="selectedOption === 'layout'" [formGroup]="layoutSettings" class="mat-content">
<div class="tb-form-panel" *ngIf="isDefaultBreakpoint"> <div class="tb-form-panel" *ngIf="!showLayoutConfig || isDefaultBreakpoint">
<mat-slide-toggle class="mat-slide" formControlName="mobileHide"> <div class="tb-form-panel-title" translate>widget-config.resize-options</div>
{{ 'widget-config.mobile-hide' | translate }} <div class="tb-form-row">
</mat-slide-toggle> <mat-slide-toggle class="mat-slide" formControlName="resizable">
</div> {{ 'widget-config.resizable' | translate }}
<div class="tb-form-panel" *ngIf="isDefaultBreakpoint"> </mat-slide-toggle>
<mat-slide-toggle class="mat-slide" formControlName="desktopHide"> </div>
{{ 'widget-config.desktop-hide' | translate }} <div class="tb-form-row">
</mat-slide-toggle> <mat-slide-toggle class="mat-slide" formControlName="preserveAspectRatio">
{{ 'widget-config.preserve-aspect-ratio' | translate }}
</mat-slide-toggle>
</div>
</div> </div>
<div class="tb-form-panel"> <div class="tb-form-panel" *ngIf="showLayoutConfig">
<div class="tb-form-panel-title">{{ (isDefaultBreakpoint ? 'widget-config.mobile' : 'widget-config.list-layout') | translate }}</div>
<div class="tb-form-row" *ngIf="isDefaultBreakpoint">
<mat-slide-toggle class="mat-slide" formControlName="mobileHide">
{{ 'widget-config.mobile-hide' | translate }}
</mat-slide-toggle>
</div>
<div class="tb-form-row" *ngIf="isDefaultBreakpoint">
<mat-slide-toggle class="mat-slide" formControlName="desktopHide">
{{ 'widget-config.desktop-hide' | translate }}
</mat-slide-toggle>
</div>
<div class="tb-form-row space-between"> <div class="tb-form-row space-between">
<div translate>widget-config.order</div> <div translate>widget-config.order</div>
<mat-form-field appearance="outline" class="number" subscriptSizing="dynamic"> <mat-form-field appearance="outline" class="number" subscriptSizing="dynamic">

22
ui-ngx/src/app/modules/home/components/widget/widget-config.component.ts

@ -256,6 +256,8 @@ export class WidgetConfigComponent extends PageComponent implements OnInit, OnDe
}); });
this.layoutSettings = this.fb.group({ this.layoutSettings = this.fb.group({
resizable: [true],
preserveAspectRatio: [false],
mobileOrder: [null, [Validators.pattern(/^-?[0-9]+$/)]], mobileOrder: [null, [Validators.pattern(/^-?[0-9]+$/)]],
mobileHeight: [null, [Validators.min(1), Validators.pattern(/^\d*$/)]], mobileHeight: [null, [Validators.min(1), Validators.pattern(/^\d*$/)]],
mobileHide: [false], mobileHide: [false],
@ -349,16 +351,12 @@ export class WidgetConfigComponent extends PageComponent implements OnInit, OnDe
value: 'actions' value: 'actions'
} }
); );
if (this.showLayoutConfig) { this.headerOptions.push(
this.headerOptions.push( {
{ name: this.translate.instant('widget-config.layout'),
name: this.isDefaultBreakpoint value: 'layout'
? this.translate.instant('widget-config.mobile') }
: this.translate.instant('widget-config.list-layout'), );
value: 'mobile'
}
);
}
if (!this.selectedOption || !this.headerOptions.find(o => o.value === this.selectedOption)) { if (!this.selectedOption || !this.headerOptions.find(o => o.value === this.selectedOption)) {
this.selectedOption = this.headerOptions[0].value; this.selectedOption = this.headerOptions[0].value;
} }
@ -569,6 +567,8 @@ export class WidgetConfigComponent extends PageComponent implements OnInit, OnDe
if (layout) { if (layout) {
this.layoutSettings.patchValue( this.layoutSettings.patchValue(
{ {
resizable: isDefined(layout.resizable) ? layout.resizable : true,
preserveAspectRatio: layout.preserveAspectRatio,
mobileOrder: layout.mobileOrder, mobileOrder: layout.mobileOrder,
mobileHeight: layout.mobileHeight, mobileHeight: layout.mobileHeight,
mobileHide: layout.mobileHide, mobileHide: layout.mobileHide,
@ -579,6 +579,8 @@ export class WidgetConfigComponent extends PageComponent implements OnInit, OnDe
} else { } else {
this.layoutSettings.patchValue( this.layoutSettings.patchValue(
{ {
resizable: true,
preserveAspectRatio: false,
mobileOrder: null, mobileOrder: null,
mobileHeight: null, mobileHeight: null,
mobileHide: false, mobileHide: false,

176
ui-ngx/src/app/modules/home/models/dashboard-component.models.ts

@ -343,6 +343,10 @@ export class DashboardWidget implements GridsterItem, IDashboardWidget {
private selectedValue = false; private selectedValue = false;
private selectedCallback: (selected: boolean) => void = () => {}; private selectedCallback: (selected: boolean) => void = () => {};
resizableHandles = {} as any;
resizeEnabled = true;
isFullscreen = false; isFullscreen = false;
isReference = false; isReference = false;
@ -387,6 +391,15 @@ export class DashboardWidget implements GridsterItem, IDashboardWidget {
private gridsterItemComponentSubject = new Subject<GridsterItemComponentInterface>(); private gridsterItemComponentSubject = new Subject<GridsterItemComponentInterface>();
private gridsterItemComponentValue: GridsterItemComponentInterface; private gridsterItemComponentValue: GridsterItemComponentInterface;
private readonly aspectRatio: number;
private heightValue: number;
private widthValue: number;
private rowsValue: number;
private colsValue: number;
get mobileHide(): boolean { get mobileHide(): boolean {
return this.widgetLayout ? this.widgetLayout.mobileHide === true : false; return this.widgetLayout ? this.widgetLayout.mobileHide === true : false;
} }
@ -397,10 +410,96 @@ export class DashboardWidget implements GridsterItem, IDashboardWidget {
set gridsterItemComponent(item: GridsterItemComponentInterface) { set gridsterItemComponent(item: GridsterItemComponentInterface) {
this.gridsterItemComponentValue = item; this.gridsterItemComponentValue = item;
if (this.widgetLayout?.preserveAspectRatio) {
this.applyPreserveAspectRatio(item);
}
this.gridsterItemComponentSubject.next(this.gridsterItemComponentValue); this.gridsterItemComponentSubject.next(this.gridsterItemComponentValue);
this.gridsterItemComponentSubject.complete(); this.gridsterItemComponentSubject.complete();
} }
private applyPreserveAspectRatio(item: GridsterItemComponentInterface) {
this.resizableHandles.ne = false;
this.resizableHandles.sw = false;
this.resizableHandles.nw = false;
const $item = item.$item;
this.rowsValue = $item.rows;
this.colsValue = $item.cols;
Object.defineProperty($item, 'rows', {
get: () => this.rowsValue,
set: v => {
if (this.rowsValue !== v) {
if (this.preserveAspectRatio) {
this.colsValue = v * this.aspectRatio;
}
this.rowsValue = v;
}
}
});
Object.defineProperty($item, 'cols', {
get: () => this.colsValue,
set: v => {
if (this.colsValue !== v) {
if (this.preserveAspectRatio) {
this.rowsValue = v / this.aspectRatio;
}
this.colsValue = v;
}
}
});
const resizable = item.resize;
this.heightValue = resizable.height;
this.widthValue = resizable.width;
const setItemHeight = resizable.setItemHeight.bind(resizable);
const setItemWidth = resizable.setItemWidth.bind(resizable);
resizable.setItemHeight = (height) => {
setItemHeight(height);
this.heightValue = height;
if (this.preserveAspectRatio) {
setItemWidth(height * this.aspectRatio);
}
};
resizable.setItemWidth = (width) => {
setItemWidth(width);
this.widthValue = width;
if (this.preserveAspectRatio) {
setItemHeight(width / this.aspectRatio);
}
};
Object.defineProperty(resizable, 'height', {
get: () => this.heightValue,
set: v => {
if (this.heightValue !== v) {
if (this.preserveAspectRatio) {
this.widthValue = v * this.aspectRatio;
}
this.heightValue = v;
}
}
});
Object.defineProperty(resizable, 'width', {
get: () => this.widthValue,
set: v => {
if (this.widthValue !== v) {
if (this.preserveAspectRatio) {
this.heightValue = v / this.aspectRatio;
}
this.widthValue = v;
}
}
});
}
get highlighted() { get highlighted() {
return this.highlightedValue; return this.highlightedValue;
} }
@ -434,6 +533,13 @@ export class DashboardWidget implements GridsterItem, IDashboardWidget {
public widgetLayout?: WidgetLayout, public widgetLayout?: WidgetLayout,
private parentDashboard?: IDashboardComponent, private parentDashboard?: IDashboardComponent,
private popoverComponent?: TbPopoverComponent) { private popoverComponent?: TbPopoverComponent) {
if (isDefined(widgetLayout?.resizable)) {
this.resizeEnabled = widgetLayout.resizable;
}
if (widgetLayout?.preserveAspectRatio) {
this.aspectRatio = this.widgetLayout.sizeX / this.widgetLayout.sizeY;
}
if (!widget.id) { if (!widget.id) {
widget.id = guid(); widget.id = guid();
} }
@ -603,30 +709,28 @@ export class DashboardWidget implements GridsterItem, IDashboardWidget {
} }
} }
@enumerable(true) get preserveAspectRatio(): boolean {
get cols(): number { if (!this.dashboard.isMobileSize && this.widgetLayout) {
let res; return this.widgetLayout.preserveAspectRatio;
if (this.widgetLayout) {
res = this.widgetLayout.sizeX;
} else { } else {
res = this.widget.sizeX; return false;
} }
return Math.floor(res); }
@enumerable(true)
get cols(): number {
return Math.floor(this.sizeX);
} }
set cols(cols: number) { set cols(cols: number) {
if (!this.dashboard.isMobileSize) { if (!this.dashboard.isMobileSize) {
if (this.widgetLayout) { this.sizeX = cols;
this.widgetLayout.sizeX = cols;
} else {
this.widget.sizeX = cols;
}
} }
} }
@enumerable(true) @enumerable(true)
get rows(): number { get rows(): number {
let res; let res: number;
if (this.dashboard.isMobileSize) { if (this.dashboard.isMobileSize) {
let mobileHeight; let mobileHeight;
if (this.widgetLayout) { if (this.widgetLayout) {
@ -638,26 +742,50 @@ export class DashboardWidget implements GridsterItem, IDashboardWidget {
if (mobileHeight) { if (mobileHeight) {
res = mobileHeight; res = mobileHeight;
} else { } else {
const sizeY = this.widgetLayout ? this.widgetLayout.sizeY : this.widget.sizeY; const sizeY = this.sizeY;
res = sizeY * 24 / this.dashboard.gridsterOpts.minCols; res = sizeY * 24 / this.dashboard.gridsterOpts.minCols;
} }
} else { } else {
if (this.widgetLayout) { res = this.sizeY;
res = this.widgetLayout.sizeY;
} else {
res = this.widget.sizeY;
}
} }
return Math.floor(res); return Math.floor(res);
} }
set rows(rows: number) { set rows(rows: number) {
if (!this.dashboard.isMobileSize && !this.dashboard.autofillHeight) { if (!this.dashboard.isMobileSize && !this.dashboard.autofillHeight) {
if (this.widgetLayout) { this.sizeY = rows;
this.widgetLayout.sizeY = rows; }
} else { }
this.widget.sizeY = rows;
} get sizeX(): number {
if (this.widgetLayout) {
return this.widgetLayout.sizeX;
} else {
return this.widget.sizeX;
}
}
set sizeX(sizeX: number) {
if (this.widgetLayout) {
this.widgetLayout.sizeX = sizeX;
} else {
this.widget.sizeX = sizeX;
}
}
get sizeY(): number {
if (this.widgetLayout) {
return this.widgetLayout.sizeY;
} else {
return this.widget.sizeY;
}
}
set sizeY(sizeY: number) {
if (this.widgetLayout) {
this.widgetLayout.sizeY = sizeY;
} else {
this.widget.sizeY = sizeY;
} }
} }

2
ui-ngx/src/app/shared/models/dashboard.models.ts

@ -43,6 +43,8 @@ export interface WidgetLayout {
mobileOrder?: number; mobileOrder?: number;
col?: number; col?: number;
row?: number; row?: number;
resizable?: boolean;
preserveAspectRatio?: boolean;
} }
export interface WidgetLayouts { export interface WidgetLayouts {

2
ui-ngx/src/app/shared/models/widget.models.ts

@ -761,6 +761,8 @@ export interface WidgetConfig {
displayTimewindow?: boolean; displayTimewindow?: boolean;
timewindow?: Timewindow; timewindow?: Timewindow;
timewindowStyle?: TimewindowStyle; timewindowStyle?: TimewindowStyle;
resizable?: boolean;
preserveAspectRatio?: boolean;
desktopHide?: boolean; desktopHide?: boolean;
mobileHide?: boolean; mobileHide?: boolean;
mobileHeight?: number; mobileHeight?: number;

6
ui-ngx/src/assets/locale/locale.constant-en_US.json

@ -6045,7 +6045,11 @@
"color": "Color", "color": "Color",
"tooltip": "Tooltip", "tooltip": "Tooltip",
"units-required": "Unit is required.", "units-required": "Unit is required.",
"list-layout": "List layout" "list-layout": "List layout",
"layout": "Layout",
"resize-options": "Resize options",
"resizable": "Resizable",
"preserve-aspect-ratio": "Preserve aspect ratio"
}, },
"widget-type": { "widget-type": {
"import": "Import widget type", "import": "Import widget type",

Loading…
Cancel
Save