UI: Improve widget layout settings: Add preserve aspect ratio and resizable options.
This commit is contained in:
parent
bf6bd064b7
commit
1c2d1f8780
@ -345,10 +345,11 @@ export class DashboardUtilsService {
|
||||
return widgetConfig;
|
||||
}
|
||||
|
||||
public prepareWidgetForScadaLayout(widget: Widget): Widget {
|
||||
public prepareWidgetForScadaLayout(widget: Widget, isScada: boolean): Widget {
|
||||
const config = widget.config;
|
||||
config.showTitle = false;
|
||||
config.dropShadow = false;
|
||||
config.preserveAspectRatio = isScada;
|
||||
config.padding = '0';
|
||||
config.margin = '0';
|
||||
config.backgroundColor = 'rgba(0,0,0,0)';
|
||||
@ -654,7 +655,9 @@ export class DashboardUtilsService {
|
||||
mobileOrder: widget.config.mobileOrder,
|
||||
mobileHeight: widget.config.mobileHeight,
|
||||
mobileHide: widget.config.mobileHide,
|
||||
desktopHide: widget.config.desktopHide
|
||||
desktopHide: widget.config.desktopHide,
|
||||
preserveAspectRatio: widget.config.preserveAspectRatio,
|
||||
resizable: widget.config.resizable
|
||||
};
|
||||
if (isUndefined(originalColumns)) {
|
||||
originalColumns = 24;
|
||||
|
||||
@ -187,6 +187,8 @@ export class AddWidgetDialogComponent extends DialogComponent<AddWidgetDialogCom
|
||||
this.widget.config.mobileHeight = widgetConfig.layout.mobileHeight;
|
||||
this.widget.config.mobileHide = widgetConfig.layout.mobileHide;
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
||||
@ -1351,7 +1351,7 @@ export class DashboardPageComponent extends PageComponent implements IDashboardC
|
||||
}
|
||||
const scada = this.isAddingToScadaLayout();
|
||||
if (scada) {
|
||||
newWidget = this.dashboardUtils.prepareWidgetForScadaLayout(newWidget);
|
||||
newWidget = this.dashboardUtils.prepareWidgetForScadaLayout(newWidget, widgetTypeInfo.scada);
|
||||
}
|
||||
let showLayoutConfig = true;
|
||||
if (scada || this.layouts.right.show || !this.showLayoutConfigInEdit(this.layouts.main.layoutCtx)) {
|
||||
|
||||
@ -168,18 +168,32 @@
|
||||
</tb-manage-widget-actions>
|
||||
</div>
|
||||
</div>
|
||||
<div [fxShow]="selectedOption === 'mobile'" [formGroup]="layoutSettings" class="mat-content">
|
||||
<div class="tb-form-panel" *ngIf="isDefaultBreakpoint">
|
||||
<mat-slide-toggle class="mat-slide" formControlName="mobileHide">
|
||||
{{ 'widget-config.mobile-hide' | translate }}
|
||||
</mat-slide-toggle>
|
||||
<div [fxShow]="selectedOption === 'layout'" [formGroup]="layoutSettings" class="mat-content">
|
||||
<div class="tb-form-panel" *ngIf="!showLayoutConfig || isDefaultBreakpoint">
|
||||
<div class="tb-form-panel-title" translate>widget-config.resize-options</div>
|
||||
<div class="tb-form-row">
|
||||
<mat-slide-toggle class="mat-slide" formControlName="resizable">
|
||||
{{ 'widget-config.resizable' | translate }}
|
||||
</mat-slide-toggle>
|
||||
</div>
|
||||
<div class="tb-form-row">
|
||||
<mat-slide-toggle class="mat-slide" formControlName="preserveAspectRatio">
|
||||
{{ 'widget-config.preserve-aspect-ratio' | translate }}
|
||||
</mat-slide-toggle>
|
||||
</div>
|
||||
</div>
|
||||
<div class="tb-form-panel" *ngIf="isDefaultBreakpoint">
|
||||
<mat-slide-toggle class="mat-slide" formControlName="desktopHide">
|
||||
{{ 'widget-config.desktop-hide' | translate }}
|
||||
</mat-slide-toggle>
|
||||
</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 translate>widget-config.order</div>
|
||||
<mat-form-field appearance="outline" class="number" subscriptSizing="dynamic">
|
||||
|
||||
@ -256,6 +256,8 @@ export class WidgetConfigComponent extends PageComponent implements OnInit, OnDe
|
||||
});
|
||||
|
||||
this.layoutSettings = this.fb.group({
|
||||
resizable: [true],
|
||||
preserveAspectRatio: [false],
|
||||
mobileOrder: [null, [Validators.pattern(/^-?[0-9]+$/)]],
|
||||
mobileHeight: [null, [Validators.min(1), Validators.pattern(/^\d*$/)]],
|
||||
mobileHide: [false],
|
||||
@ -349,16 +351,12 @@ export class WidgetConfigComponent extends PageComponent implements OnInit, OnDe
|
||||
value: 'actions'
|
||||
}
|
||||
);
|
||||
if (this.showLayoutConfig) {
|
||||
this.headerOptions.push(
|
||||
{
|
||||
name: this.isDefaultBreakpoint
|
||||
? this.translate.instant('widget-config.mobile')
|
||||
: this.translate.instant('widget-config.list-layout'),
|
||||
value: 'mobile'
|
||||
}
|
||||
);
|
||||
}
|
||||
this.headerOptions.push(
|
||||
{
|
||||
name: this.translate.instant('widget-config.layout'),
|
||||
value: 'layout'
|
||||
}
|
||||
);
|
||||
if (!this.selectedOption || !this.headerOptions.find(o => o.value === this.selectedOption)) {
|
||||
this.selectedOption = this.headerOptions[0].value;
|
||||
}
|
||||
@ -569,6 +567,8 @@ export class WidgetConfigComponent extends PageComponent implements OnInit, OnDe
|
||||
if (layout) {
|
||||
this.layoutSettings.patchValue(
|
||||
{
|
||||
resizable: isDefined(layout.resizable) ? layout.resizable : true,
|
||||
preserveAspectRatio: layout.preserveAspectRatio,
|
||||
mobileOrder: layout.mobileOrder,
|
||||
mobileHeight: layout.mobileHeight,
|
||||
mobileHide: layout.mobileHide,
|
||||
@ -579,6 +579,8 @@ export class WidgetConfigComponent extends PageComponent implements OnInit, OnDe
|
||||
} else {
|
||||
this.layoutSettings.patchValue(
|
||||
{
|
||||
resizable: true,
|
||||
preserveAspectRatio: false,
|
||||
mobileOrder: null,
|
||||
mobileHeight: null,
|
||||
mobileHide: false,
|
||||
|
||||
@ -343,6 +343,10 @@ export class DashboardWidget implements GridsterItem, IDashboardWidget {
|
||||
private selectedValue = false;
|
||||
private selectedCallback: (selected: boolean) => void = () => {};
|
||||
|
||||
resizableHandles = {} as any;
|
||||
|
||||
resizeEnabled = true;
|
||||
|
||||
isFullscreen = false;
|
||||
isReference = false;
|
||||
|
||||
@ -387,6 +391,15 @@ export class DashboardWidget implements GridsterItem, IDashboardWidget {
|
||||
private gridsterItemComponentSubject = new Subject<GridsterItemComponentInterface>();
|
||||
private gridsterItemComponentValue: GridsterItemComponentInterface;
|
||||
|
||||
private readonly aspectRatio: number;
|
||||
|
||||
private heightValue: number;
|
||||
private widthValue: number;
|
||||
|
||||
private rowsValue: number;
|
||||
private colsValue: number;
|
||||
|
||||
|
||||
get mobileHide(): boolean {
|
||||
return this.widgetLayout ? this.widgetLayout.mobileHide === true : false;
|
||||
}
|
||||
@ -397,10 +410,96 @@ export class DashboardWidget implements GridsterItem, IDashboardWidget {
|
||||
|
||||
set gridsterItemComponent(item: GridsterItemComponentInterface) {
|
||||
this.gridsterItemComponentValue = item;
|
||||
|
||||
if (this.widgetLayout?.preserveAspectRatio) {
|
||||
this.applyPreserveAspectRatio(item);
|
||||
}
|
||||
|
||||
this.gridsterItemComponentSubject.next(this.gridsterItemComponentValue);
|
||||
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() {
|
||||
return this.highlightedValue;
|
||||
}
|
||||
@ -434,6 +533,13 @@ export class DashboardWidget implements GridsterItem, IDashboardWidget {
|
||||
public widgetLayout?: WidgetLayout,
|
||||
private parentDashboard?: IDashboardComponent,
|
||||
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) {
|
||||
widget.id = guid();
|
||||
}
|
||||
@ -603,30 +709,28 @@ export class DashboardWidget implements GridsterItem, IDashboardWidget {
|
||||
}
|
||||
}
|
||||
|
||||
get preserveAspectRatio(): boolean {
|
||||
if (!this.dashboard.isMobileSize && this.widgetLayout) {
|
||||
return this.widgetLayout.preserveAspectRatio;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
@enumerable(true)
|
||||
get cols(): number {
|
||||
let res;
|
||||
if (this.widgetLayout) {
|
||||
res = this.widgetLayout.sizeX;
|
||||
} else {
|
||||
res = this.widget.sizeX;
|
||||
}
|
||||
return Math.floor(res);
|
||||
return Math.floor(this.sizeX);
|
||||
}
|
||||
|
||||
set cols(cols: number) {
|
||||
if (!this.dashboard.isMobileSize) {
|
||||
if (this.widgetLayout) {
|
||||
this.widgetLayout.sizeX = cols;
|
||||
} else {
|
||||
this.widget.sizeX = cols;
|
||||
}
|
||||
this.sizeX = cols;
|
||||
}
|
||||
}
|
||||
|
||||
@enumerable(true)
|
||||
get rows(): number {
|
||||
let res;
|
||||
let res: number;
|
||||
if (this.dashboard.isMobileSize) {
|
||||
let mobileHeight;
|
||||
if (this.widgetLayout) {
|
||||
@ -638,26 +742,50 @@ export class DashboardWidget implements GridsterItem, IDashboardWidget {
|
||||
if (mobileHeight) {
|
||||
res = mobileHeight;
|
||||
} else {
|
||||
const sizeY = this.widgetLayout ? this.widgetLayout.sizeY : this.widget.sizeY;
|
||||
const sizeY = this.sizeY;
|
||||
res = sizeY * 24 / this.dashboard.gridsterOpts.minCols;
|
||||
}
|
||||
} else {
|
||||
if (this.widgetLayout) {
|
||||
res = this.widgetLayout.sizeY;
|
||||
} else {
|
||||
res = this.widget.sizeY;
|
||||
}
|
||||
res = this.sizeY;
|
||||
}
|
||||
return Math.floor(res);
|
||||
}
|
||||
|
||||
set rows(rows: number) {
|
||||
if (!this.dashboard.isMobileSize && !this.dashboard.autofillHeight) {
|
||||
if (this.widgetLayout) {
|
||||
this.widgetLayout.sizeY = rows;
|
||||
} else {
|
||||
this.widget.sizeY = rows;
|
||||
}
|
||||
this.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;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -43,6 +43,8 @@ export interface WidgetLayout {
|
||||
mobileOrder?: number;
|
||||
col?: number;
|
||||
row?: number;
|
||||
resizable?: boolean;
|
||||
preserveAspectRatio?: boolean;
|
||||
}
|
||||
|
||||
export interface WidgetLayouts {
|
||||
|
||||
@ -761,6 +761,8 @@ export interface WidgetConfig {
|
||||
displayTimewindow?: boolean;
|
||||
timewindow?: Timewindow;
|
||||
timewindowStyle?: TimewindowStyle;
|
||||
resizable?: boolean;
|
||||
preserveAspectRatio?: boolean;
|
||||
desktopHide?: boolean;
|
||||
mobileHide?: boolean;
|
||||
mobileHeight?: number;
|
||||
|
||||
@ -6045,7 +6045,11 @@
|
||||
"color": "Color",
|
||||
"tooltip": "Tooltip",
|
||||
"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": {
|
||||
"import": "Import widget type",
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user