UI: Improve image pipe. Improve widgets background style function.

This commit is contained in:
Igor Kulikov 2023-11-28 12:53:01 +02:00
parent 751ebc0d03
commit 13447338cf
14 changed files with 71 additions and 28 deletions

View File

@ -52,6 +52,7 @@ import { formatNumberValue, formatValue, isDefined, isDefinedAndNotNull, isNumer
import { map } from 'rxjs/operators';
import { ResizeObserver } from '@juggle/resize-observer';
import { ImagePipe } from '@shared/pipe/image.pipe';
import { DomSanitizer } from '@angular/platform-browser';
const valuesLayoutHeight = 66;
const valuesLayoutVerticalPadding = 16;
@ -111,6 +112,7 @@ export class AggregatedValueCardWidgetComponent implements OnInit, AfterViewInit
private panelResize$: ResizeObserver;
constructor(private imagePipe: ImagePipe,
private sanitizer: DomSanitizer,
private renderer: Renderer2,
private cd: ChangeDetectorRef) {
}
@ -153,7 +155,7 @@ export class AggregatedValueCardWidgetComponent implements OnInit, AfterViewInit
this.dateStyle = textStyle(this.settings.dateFont);
this.dateColor = this.settings.dateColor;
this.backgroundStyle$ = backgroundStyle(this.settings.background, this.imagePipe);
this.backgroundStyle$ = backgroundStyle(this.settings.background, this.imagePipe, this.sanitizer);
this.overlayStyle = overlayStyle(this.settings.background.overlay);
}

View File

@ -45,6 +45,7 @@ import { progressBarDefaultSettings, ProgressBarLayout, ProgressBarWidgetSetting
import { ResizeObserver } from '@juggle/resize-observer';
import { Observable } from 'rxjs';
import { ImagePipe } from '@shared/pipe/image.pipe';
import { DomSanitizer } from '@angular/platform-browser';
const defaultLayoutHeight = 80;
const simplifiedLayoutHeight = 75;
@ -105,6 +106,7 @@ export class ProgressBarWidgetComponent implements OnInit, OnDestroy, AfterViewI
constructor(private date: DatePipe,
private imagePipe: ImagePipe,
private sanitizer: DomSanitizer,
private widgetComponent: WidgetComponent,
private renderer: Renderer2,
private cd: ChangeDetectorRef) {
@ -147,7 +149,7 @@ export class ProgressBarWidgetComponent implements OnInit, OnDestroy, AfterViewI
this.ticksStyle.color = this.settings.ticksColor;
}
this.backgroundStyle$ = backgroundStyle(this.settings.background, this.imagePipe);
this.backgroundStyle$ = backgroundStyle(this.settings.background, this.imagePipe, this.sanitizer);
this.overlayStyle = overlayStyle(this.settings.background.overlay);
}

View File

@ -45,6 +45,7 @@ import { WidgetComponent } from '@home/components/widget/widget.component';
import { Observable } from 'rxjs';
import { ResizeObserver } from '@juggle/resize-observer';
import { ImagePipe } from '@shared/pipe/image.pipe';
import { DomSanitizer } from '@angular/platform-browser';
const squareLayoutSize = 160;
const squareLayoutPadding = 48;
@ -103,6 +104,7 @@ export class ValueCardWidgetComponent implements OnInit, AfterViewInit, OnDestro
private units = '';
constructor(private imagePipe: ImagePipe,
private sanitizer: DomSanitizer,
private renderer: Renderer2,
private widgetComponent: WidgetComponent,
private cd: ChangeDetectorRef) {
@ -144,7 +146,7 @@ export class ValueCardWidgetComponent implements OnInit, AfterViewInit, OnDestro
this.dateStyle = textStyle(this.settings.dateFont);
this.dateColor = ColorProcessor.fromSettings(this.settings.dateColor);
this.backgroundStyle$ = backgroundStyle(this.settings.background, this.imagePipe);
this.backgroundStyle$ = backgroundStyle(this.settings.background, this.imagePipe, this.sanitizer);
this.overlayStyle = overlayStyle(this.settings.background.overlay);
}

View File

@ -50,6 +50,7 @@ import { TbFlotKeySettings, TbFlotSettings } from '@home/components/widget/lib/f
import { getTsValueByLatestDataKey } from '@home/components/widget/lib/cards/aggregated-value-card.models';
import { Observable } from 'rxjs';
import { ImagePipe } from '@shared/pipe/image.pipe';
import { DomSanitizer } from '@angular/platform-browser';
const layoutHeight = 56;
const valueRelativeMaxWidth = 0.5;
@ -101,6 +102,7 @@ export class ValueChartCardWidgetComponent implements OnInit, AfterViewInit, OnD
private valueFontSize: number;
constructor(private imagePipe: ImagePipe,
private sanitizer: DomSanitizer,
private renderer: Renderer2,
private widgetComponent: WidgetComponent,
private cd: ChangeDetectorRef) {
@ -132,7 +134,7 @@ export class ValueChartCardWidgetComponent implements OnInit, AfterViewInit, OnD
this.valueStyle = textStyle(this.settings.valueFont);
this.valueColor = ColorProcessor.fromSettings(this.settings.valueColor);
this.backgroundStyle$ = backgroundStyle(this.settings.background, this.imagePipe);
this.backgroundStyle$ = backgroundStyle(this.settings.background, this.imagePipe, this.sanitizer);
this.overlayStyle = overlayStyle(this.settings.background.overlay);
if (this.ctx.defaultSubscription.firstDatasource?.dataKeys?.length) {

View File

@ -55,6 +55,7 @@ import { PieChart, PieSeriesOption } from 'echarts/charts';
import { SVGRenderer } from 'echarts/renderers';
import { Observable } from 'rxjs';
import { ImagePipe } from '@shared/pipe/image.pipe';
import { DomSanitizer } from '@angular/platform-browser';
echarts.use([
TooltipComponent,
@ -148,6 +149,7 @@ export class DoughnutWidgetComponent implements OnInit, OnDestroy, AfterViewInit
private totalTextNode: Text;
constructor(private imagePipe: ImagePipe,
private sanitizer: DomSanitizer,
private widgetComponent: WidgetComponent,
private renderer: Renderer2,
private translate: TranslateService,
@ -170,7 +172,7 @@ export class DoughnutWidgetComponent implements OnInit, OnDestroy, AfterViewInit
this.totalValueColor = ColorProcessor.fromSettings(this.settings.totalValueColor);
}
this.backgroundStyle$ = backgroundStyle(this.settings.background, this.imagePipe);
this.backgroundStyle$ = backgroundStyle(this.settings.background, this.imagePipe, this.sanitizer);
this.overlayStyle = overlayStyle(this.settings.background.overlay);
if (this.showLegend) {

View File

@ -59,6 +59,7 @@ import { rangeChartDefaultSettings, RangeChartWidgetSettings } from './range-cha
import { DataSet } from '@shared/models/widget.models';
import { Observable } from 'rxjs';
import { ImagePipe } from '@shared/pipe/image.pipe';
import { DomSanitizer } from '@angular/platform-browser';
echarts.use([
TooltipComponent,
@ -249,6 +250,7 @@ export class RangeChartWidgetComponent implements OnInit, OnDestroy, AfterViewIn
private tooltipDateFormat: DateFormatProcessor;
constructor(private imagePipe: ImagePipe,
private sanitizer: DomSanitizer,
private renderer: Renderer2,
private cd: ChangeDetectorRef) {
}
@ -268,7 +270,7 @@ export class RangeChartWidgetComponent implements OnInit, OnDestroy, AfterViewIn
}
this.backgroundStyle$ = backgroundStyle(this.settings.background, this.imagePipe);
this.backgroundStyle$ = backgroundStyle(this.settings.background, this.imagePipe, this.sanitizer);
this.overlayStyle = overlayStyle(this.settings.background.overlay);
this.rangeItems = toRangeItems(this.settings.rangeColors);

View File

@ -48,6 +48,7 @@ import {
import { ResizeObserver } from '@juggle/resize-observer';
import { Observable } from 'rxjs';
import { ImagePipe } from '@shared/pipe/image.pipe';
import { DomSanitizer } from '@angular/platform-browser';
const verticalBatteryDimensions = {
shapeAspectRatio: 64 / 113,
@ -139,6 +140,7 @@ export class BatteryLevelWidgetComponent implements OnInit, OnDestroy, AfterView
constructor(private date: DatePipe,
private imagePipe: ImagePipe,
private sanitizer: DomSanitizer,
private widgetComponent: WidgetComponent,
private renderer: Renderer2,
private cd: ChangeDetectorRef) {
@ -193,7 +195,7 @@ export class BatteryLevelWidgetComponent implements OnInit, OnDestroy, AfterView
this.batteryShapeColor = ColorProcessor.fromSettings(this.settings.batteryShapeColor);
this.backgroundStyle$ = backgroundStyle(this.settings.background, this.imagePipe);
this.backgroundStyle$ = backgroundStyle(this.settings.background, this.imagePipe, this.sanitizer);
this.overlayStyle = overlayStyle(this.settings.background.overlay);
this.hasCardClickAction = this.ctx.actionsApi.getActionDescriptors('cardClick').length > 0;

View File

@ -59,6 +59,7 @@ import { NULL_UUID } from '@shared/models/id/has-uuid';
import { TranslateService } from '@ngx-translate/core';
import ITooltipsterInstance = JQueryTooltipster.ITooltipsterInstance;
import { ImagePipe } from '@shared/pipe/image.pipe';
import { DomSanitizer } from '@angular/platform-browser';
@Component({
selector: 'tb-liquid-level-widget',
@ -108,6 +109,7 @@ export class LiquidLevelWidgetComponent implements OnInit {
private capacityUnits = Object.values(CapacityUnits);
constructor(private imagePipe: ImagePipe,
private sanitizer: DomSanitizer,
private cd: ChangeDetectorRef,
private resourcesService: ResourcesService,
private translate: TranslateService) {
@ -118,7 +120,7 @@ export class LiquidLevelWidgetComponent implements OnInit {
this.settings = {...levelCardDefaultSettings, ...this.ctx.settings};
this.declareStyles();
this.backgroundStyle$ = backgroundStyle(this.settings.background, this.imagePipe);
this.backgroundStyle$ = backgroundStyle(this.settings.background, this.imagePipe, this.sanitizer);
this.overlayStyle = overlayStyle(this.settings.background.overlay);
this.hasCardClickAction = this.ctx.actionsApi.getActionDescriptors('cardClick').length > 0;

View File

@ -53,6 +53,7 @@ import tinycolor from 'tinycolor2';
import { TranslateService } from '@ngx-translate/core';
import { Observable } from 'rxjs';
import { ImagePipe } from '@shared/pipe/image.pipe';
import { DomSanitizer } from '@angular/platform-browser';
const shapeWidth = 149;
const shapeHeight = 113;
@ -131,6 +132,7 @@ export class SignalStrengthWidgetComponent implements OnInit, OnDestroy, AfterVi
constructor(public widgetComponent: WidgetComponent,
private imagePipe: ImagePipe,
private sanitizer: DomSanitizer,
private translate: TranslateService,
private renderer: Renderer2,
private cd: ChangeDetectorRef) {
@ -189,7 +191,7 @@ export class SignalStrengthWidgetComponent implements OnInit, OnDestroy, AfterVi
this.tooltipDateLabelStyle = {...this.tooltipDateStyle, ...this.tooltipDateLabelStyle};
}
this.backgroundStyle$ = backgroundStyle(this.settings.background, this.imagePipe);
this.backgroundStyle$ = backgroundStyle(this.settings.background, this.imagePipe, this.sanitizer);
this.overlayStyle = overlayStyle(this.settings.background.overlay);
this.hasCardClickAction = this.ctx.actionsApi.getActionDescriptors('cardClick').length > 0;

View File

@ -14,7 +14,7 @@
/// limitations under the License.
///
import { Component, EventEmitter, Input, OnInit, Output, ViewEncapsulation } from '@angular/core';
import { ChangeDetectorRef, Component, EventEmitter, Input, OnInit, Output, ViewEncapsulation } from '@angular/core';
import { PageComponent } from '@shared/components/page.component';
import {
backgroundStyle,
@ -29,6 +29,7 @@ import { Store } from '@ngrx/store';
import { AppState } from '@core/core.state';
import { Observable } from 'rxjs';
import { ImagePipe } from '@shared/pipe/image.pipe';
import { DomSanitizer } from '@angular/platform-browser';
@Component({
selector: 'tb-background-settings-panel',
@ -61,7 +62,9 @@ export class BackgroundSettingsPanelComponent extends PageComponent implements O
constructor(private fb: UntypedFormBuilder,
private imagePipe: ImagePipe,
protected store: Store<AppState>) {
private sanitizer: DomSanitizer,
protected store: Store<AppState>,
private cd: ChangeDetectorRef) {
super(store);
}
@ -103,11 +106,11 @@ export class BackgroundSettingsPanelComponent extends PageComponent implements O
private updateValidators() {
const overlayEnabled: boolean = this.backgroundSettingsFormGroup.get('overlay').get('enabled').value;
if (overlayEnabled) {
this.backgroundSettingsFormGroup.get('overlay').get('color').enable();
this.backgroundSettingsFormGroup.get('overlay').get('blur').enable();
this.backgroundSettingsFormGroup.get('overlay').get('color').enable({emitEvent: false});
this.backgroundSettingsFormGroup.get('overlay').get('blur').enable({emitEvent: false});
} else {
this.backgroundSettingsFormGroup.get('overlay').get('color').disable();
this.backgroundSettingsFormGroup.get('overlay').get('blur').disable();
this.backgroundSettingsFormGroup.get('overlay').get('color').disable({emitEvent: false});
this.backgroundSettingsFormGroup.get('overlay').get('blur').disable({emitEvent: false});
}
this.backgroundSettingsFormGroup.get('overlay').get('color').updateValueAndValidity({emitEvent: false});
this.backgroundSettingsFormGroup.get('overlay').get('blur').updateValueAndValidity({emitEvent: false});
@ -115,8 +118,9 @@ export class BackgroundSettingsPanelComponent extends PageComponent implements O
private updateBackgroundStyle() {
const background: BackgroundSettings = this.backgroundSettingsFormGroup.value;
this.backgroundStyle$ = backgroundStyle(background, this.imagePipe);
this.backgroundStyle$ = backgroundStyle(background, this.imagePipe, this.sanitizer, true);
this.overlayStyle = overlayStyle(background.overlay);
this.cd.markForCheck();
}
}

View File

@ -14,7 +14,16 @@
/// limitations under the License.
///
import { Component, forwardRef, Input, OnInit, Renderer2, ViewContainerRef, ViewEncapsulation } from '@angular/core';
import {
ChangeDetectorRef,
Component,
forwardRef,
Input,
OnInit,
Renderer2,
ViewContainerRef,
ViewEncapsulation
} from '@angular/core';
import { ControlValueAccessor, NG_VALUE_ACCESSOR } from '@angular/forms';
import {
BackgroundSettings,
@ -30,6 +39,7 @@ import {
} from '@home/components/widget/lib/settings/common/background-settings-panel.component';
import { Observable, of } from 'rxjs';
import { ImagePipe } from '@shared/pipe/image.pipe';
import { DomSanitizer } from '@angular/platform-browser';
@Component({
selector: 'tb-background-settings',
@ -47,7 +57,7 @@ import { ImagePipe } from '@shared/pipe/image.pipe';
export class BackgroundSettingsComponent implements OnInit, ControlValueAccessor {
@Input()
disabled: boolean;
disabled = false;
backgroundType = BackgroundType;
@ -60,9 +70,11 @@ export class BackgroundSettingsComponent implements OnInit, ControlValueAccessor
private propagateChange = null;
constructor(private imagePipe: ImagePipe,
private sanitizer: DomSanitizer,
private popoverService: TbPopoverService,
private renderer: Renderer2,
private viewContainerRef: ViewContainerRef) {}
private viewContainerRef: ViewContainerRef,
private cd: ChangeDetectorRef) {}
ngOnInit(): void {
}
@ -75,8 +87,10 @@ export class BackgroundSettingsComponent implements OnInit, ControlValueAccessor
}
setDisabledState(isDisabled: boolean): void {
this.disabled = isDisabled;
this.updateBackgroundStyle();
if (this.disabled !== isDisabled) {
this.disabled = isDisabled;
this.updateBackgroundStyle();
}
}
writeValue(value: BackgroundSettings): void {
@ -112,12 +126,13 @@ export class BackgroundSettingsComponent implements OnInit, ControlValueAccessor
private updateBackgroundStyle() {
if (!this.disabled) {
this.backgroundStyle$ = backgroundStyle(this.modelValue, this.imagePipe);
this.backgroundStyle$ = backgroundStyle(this.modelValue, this.imagePipe, this.sanitizer, true);
this.overlayStyle = overlayStyle(this.modelValue.overlay);
} else {
this.backgroundStyle$ = of({});
this.overlayStyle = {};
}
this.cd.markForCheck();
}
}

View File

@ -49,6 +49,7 @@ import { Path, Svg, SVG, Text } from '@svgdotjs/svg.js';
import { DataKey } from '@shared/models/widget.models';
import { Observable } from 'rxjs';
import { ImagePipe } from '@shared/pipe/image.pipe';
import { DomSanitizer } from '@angular/platform-browser';
const shapeSize = 180;
const cx = shapeSize / 2;
@ -112,6 +113,7 @@ export class WindSpeedDirectionWidgetComponent implements OnInit, OnDestroy, Aft
constructor(private widgetComponent: WidgetComponent,
private imagePipe: ImagePipe,
private sanitizer: DomSanitizer,
private renderer: Renderer2,
private cd: ChangeDetectorRef) {
}
@ -138,7 +140,7 @@ export class WindSpeedDirectionWidgetComponent implements OnInit, OnDestroy, Aft
this.centerValueColor = ColorProcessor.fromSettings(this.settings.centerValueColor);
this.backgroundStyle$ = backgroundStyle(this.settings.background, this.imagePipe);
this.backgroundStyle$ = backgroundStyle(this.settings.background, this.imagePipe, this.sanitizer);
this.overlayStyle = overlayStyle(this.settings.background.overlay);
this.hasCardClickAction = this.ctx.actionsApi.getActionDescriptors('cardClick').length > 0;

View File

@ -25,6 +25,7 @@ import { AlarmSearchStatus } from '@shared/models/alarm.models';
import { Observable, of } from 'rxjs';
import { ImagePipe } from '@shared/pipe/image.pipe';
import { map } from 'rxjs/operators';
import { DomSanitizer } from '@angular/platform-browser';
export type ComponentStyle = {[klass: string]: any};
@ -520,7 +521,8 @@ export const validateAndUpdateBackgroundSettings = (background: BackgroundSettin
return background;
};
export const backgroundStyle = (background: BackgroundSettings, imagePipe: ImagePipe): Observable<ComponentStyle> => {
export const backgroundStyle = (background: BackgroundSettings, imagePipe: ImagePipe,
sanitizer: DomSanitizer, preview = false): Observable<ComponentStyle> => {
background = validateAndUpdateBackgroundSettings(background);
if (background.type === BackgroundType.color) {
return of({
@ -529,9 +531,9 @@ export const backgroundStyle = (background: BackgroundSettings, imagePipe: Image
} else {
const imageUrl = background.imageUrl;
if (imageUrl) {
return imagePipe.transform(imageUrl, {asString: true, ignoreLoadingImage: true}).pipe(
return imagePipe.transform(imageUrl, {asString: true, ignoreLoadingImage: true, preview}).pipe(
map((transformedUrl) => ({
background: `url(${transformedUrl}) no-repeat 50% 50% / cover`
background: sanitizer.bypassSecurityTrustStyle(`url(${transformedUrl}) no-repeat 50% 50% / cover`)
}))
);
} else {

View File

@ -17,7 +17,7 @@
import { Pipe, PipeTransform } from '@angular/core';
import { ImageService } from '@core/http/image.service';
import { DomSanitizer, SafeUrl } from '@angular/platform-browser';
import { BehaviorSubject, Observable, Subject } from 'rxjs';
import { AsyncSubject, BehaviorSubject, Observable } from 'rxjs';
import { isDefinedAndNotNull } from '@core/utils';
import { NO_IMAGE_DATA_URI } from '@shared/models/resource.models';
@ -41,7 +41,9 @@ export class ImagePipe implements PipeTransform {
const ignoreLoadingImage = !!args?.ignoreLoadingImage;
const asString = !!args?.asString;
const emptyUrl = args?.emptyUrl || NO_IMAGE_DATA_URI;
const image$ = ignoreLoadingImage ? new Subject<SafeUrl | string>() : new BehaviorSubject<SafeUrl | string>(LOADING_IMAGE_DATA_URI);
const image$ = ignoreLoadingImage
? new AsyncSubject<SafeUrl | string>()
: new BehaviorSubject<SafeUrl | string>(LOADING_IMAGE_DATA_URI);
const url = (typeof urlData === 'string') ? urlData : urlData?.url;
if (isDefinedAndNotNull(url)) {
const preview = !!args?.preview;