From 174300d9f1cfaf48a5bba467fc09fcff4e1f7865 Mon Sep 17 00:00:00 2001 From: Hadi Khazaee Asl Date: Sun, 30 Aug 2026 23:59:21 +0330 Subject: [PATCH] last works on xChart component ... --- .../src/lib/x-card/x-card.component.ts | 99 +++++++--- .../src/lib/x-card/x-card.typings.ts | 60 ++++--- .../src/lib/x-chart/x-chart.component.html | 2 + .../src/lib/x-chart/x-chart.component.ts | 170 +++++++++++++----- 4 files changed, 236 insertions(+), 95 deletions(-) diff --git a/projects/x-framework-components/src/lib/x-card/x-card.component.ts b/projects/x-framework-components/src/lib/x-card/x-card.component.ts index 7933066..653c29f 100644 --- a/projects/x-framework-components/src/lib/x-card/x-card.component.ts +++ b/projects/x-framework-components/src/lib/x-card/x-card.component.ts @@ -6,8 +6,17 @@ import { import { Subject, Subscription } from 'rxjs'; import { concatMap, map } from 'rxjs/operators'; import { XSizeModel } from '../classes/x-size.model.'; -import { nameof, isNullOrEmptyString, isNullOrUndefined } from 'x-framework-core'; -import { Component, ChangeDetectionStrategy, ElementRef, ViewChild } from '@angular/core'; +import { + nameof, + isNullOrEmptyString, + isNullOrUndefined, +} from 'x-framework-core'; +import { + Component, + ChangeDetectionStrategy, + ElementRef, + ViewChild, +} from '@angular/core'; @Component({ // tslint:disable-next-line:component-selector @@ -74,18 +83,28 @@ export class XCardComponent extends XCardContainerComponent { get cardActions() { return this.CARD_ACTIONS; } - //#endregion + //#endregion // //#region Full Screen ... + // private IS_FULLSCREEN: boolean = false; + set isFullscreen(v: boolean) { // const isChanged = v != this.IS_FULLSCREEN; + if (isChanged) { + // + this.actionProvider.next({ + action: XCardAction.FullScreenToggled, + payload: v, + }); + } // this.IS_FULLSCREEN = v; } + get isFullscreen() { return this.IS_FULLSCREEN; } @@ -100,9 +119,18 @@ export class XCardComponent extends XCardContainerComponent { // // Listen for fullscreen change events (handles ESC key and browser UI) document.addEventListener('fullscreenchange', this.fullscreenChangeHandler); - document.addEventListener('webkitfullscreenchange', this.fullscreenChangeHandler); - document.addEventListener('mozfullscreenchange', this.fullscreenChangeHandler); - document.addEventListener('MSFullscreenChange', this.fullscreenChangeHandler); + document.addEventListener( + 'webkitfullscreenchange', + this.fullscreenChangeHandler, + ); + document.addEventListener( + 'mozfullscreenchange', + this.fullscreenChangeHandler, + ); + document.addEventListener( + 'MSFullscreenChange', + this.fullscreenChangeHandler, + ); } onChange(changeKeys: string[]) { @@ -127,10 +155,22 @@ export class XCardComponent extends XCardContainerComponent { this.unregisterActionProvider(); // - document.removeEventListener('fullscreenchange', this.fullscreenChangeHandler); - document.removeEventListener('webkitfullscreenchange', this.fullscreenChangeHandler); - document.removeEventListener('mozfullscreenchange', this.fullscreenChangeHandler); - document.removeEventListener('MSFullscreenChange', this.fullscreenChangeHandler); + document.removeEventListener( + 'fullscreenchange', + this.fullscreenChangeHandler, + ); + document.removeEventListener( + 'webkitfullscreenchange', + this.fullscreenChangeHandler, + ); + document.removeEventListener( + 'mozfullscreenchange', + this.fullscreenChangeHandler, + ); + document.removeEventListener( + 'MSFullscreenChange', + this.fullscreenChangeHandler, + ); } registerViewHandlers() { @@ -192,7 +232,7 @@ export class XCardComponent extends XCardContainerComponent { // this.isFullscreen = true; this.detectChanges(); - } catch { } + } catch {} } public async exitFullscreen() { @@ -211,7 +251,7 @@ export class XCardComponent extends XCardContainerComponent { // this.isFullscreen = false; this.detectChanges(); - } catch { } + } catch {} } public async toggleFullscreen() { @@ -231,14 +271,17 @@ export class XCardComponent extends XCardContainerComponent { // // Validate ... - if (isNullOrUndefined(this.CARD_IMAGE) || isNullOrUndefined(this.CARD_IMAGE.nativeElement)) { + if ( + isNullOrUndefined(this.CARD_IMAGE) || + isNullOrUndefined(this.CARD_IMAGE.nativeElement) + ) { return result; } // result = { width: this.CARD_IMAGE.nativeElement.offsetWidth, - height: this.CARD_IMAGE.nativeElement.offsetHeight + height: this.CARD_IMAGE.nativeElement.offsetHeight, }; // @@ -251,14 +294,17 @@ export class XCardComponent extends XCardContainerComponent { // // Validate ... - if (isNullOrUndefined(this.CARD_HEADER) || isNullOrUndefined(this.CARD_HEADER.nativeElement)) { + if ( + isNullOrUndefined(this.CARD_HEADER) || + isNullOrUndefined(this.CARD_HEADER.nativeElement) + ) { return result; } // result = { width: this.CARD_HEADER.nativeElement.offsetWidth, - height: this.CARD_HEADER.nativeElement.offsetHeight + height: this.CARD_HEADER.nativeElement.offsetHeight, }; // @@ -271,14 +317,17 @@ export class XCardComponent extends XCardContainerComponent { // // Validate ... - if (isNullOrUndefined(this.CARD_FOOTER) || isNullOrUndefined(this.CARD_FOOTER.nativeElement)) { + if ( + isNullOrUndefined(this.CARD_FOOTER) || + isNullOrUndefined(this.CARD_FOOTER.nativeElement) + ) { return result; } // result = { width: this.CARD_FOOTER.nativeElement.offsetWidth, - height: this.CARD_FOOTER.nativeElement.offsetHeight + height: this.CARD_FOOTER.nativeElement.offsetHeight, }; // @@ -291,14 +340,17 @@ export class XCardComponent extends XCardContainerComponent { // // Validate ... - if (isNullOrUndefined(this.CARD_CONTENT) || isNullOrUndefined(this.CARD_CONTENT.nativeElement)) { + if ( + isNullOrUndefined(this.CARD_CONTENT) || + isNullOrUndefined(this.CARD_CONTENT.nativeElement) + ) { return result; } // result = { width: this.CARD_CONTENT.nativeElement.offsetWidth, - height: this.CARD_CONTENT.nativeElement.offsetHeight + height: this.CARD_CONTENT.nativeElement.offsetHeight, }; // @@ -311,14 +363,17 @@ export class XCardComponent extends XCardContainerComponent { // // Validate ... - if (isNullOrUndefined(this.CARD_ACTIONS) || isNullOrUndefined(this.CARD_ACTIONS.nativeElement)) { + if ( + isNullOrUndefined(this.CARD_ACTIONS) || + isNullOrUndefined(this.CARD_ACTIONS.nativeElement) + ) { return result; } // result = { width: this.CARD_ACTIONS.nativeElement.offsetWidth, - height: this.CARD_ACTIONS.nativeElement.offsetHeight + height: this.CARD_ACTIONS.nativeElement.offsetHeight, }; // diff --git a/projects/x-framework-components/src/lib/x-card/x-card.typings.ts b/projects/x-framework-components/src/lib/x-card/x-card.typings.ts index 9c91123..e46a6d0 100644 --- a/projects/x-framework-components/src/lib/x-card/x-card.typings.ts +++ b/projects/x-framework-components/src/lib/x-card/x-card.typings.ts @@ -33,16 +33,19 @@ import { X_FRAMEWORK_COMPONENTS_CONFIG } from '../tokens/x-injectable-tokens'; import { XFrameworkComponentsConfig } from '../config/x-framework-components.config'; export enum XCardAction { + // Refresh = 'refresh', + // ExitFullScreen = 'exit_full_screen', EnterFullScreen = 'enter_full_screen', ToggleFullScreen = 'toggle_full_screen', + // + FullScreenToggled = 'full_screen_toggled', } export type XCardActionIdentifier = XCardAction | string; -export interface XCardActionModel - extends XBaseActionModel {} +export interface XCardActionModel extends XBaseActionModel {} // //#region Container ... @@ -190,7 +193,7 @@ export abstract class XCardContainerComponent public ruler: ViewportRuler, public zone: NgZone, public changeDetector: ChangeDetectorRef, - protected propertyProvider: XCardContainer + protected propertyProvider: XCardContainer, ) { super( config, @@ -199,7 +202,7 @@ export abstract class XCardContainerComponent renderer, ruler, zone, - changeDetector + changeDetector, ); } //#endregion @@ -207,37 +210,37 @@ export abstract class XCardContainerComponent // //#region Abstract ... public extractProps( - container?: IXCardContainer + container?: IXCardContainer, ): Observable { return forkJoin({ // cssClass: this.getArrayValue( - container ? container.cssClass : this.cssClass + container ? container.cssClass : this.cssClass, ), // color: this.getValue(container ? container.color : this.color), foregroundColor: this.getValue( - container ? container.foregroundColor : this.foregroundColor + container ? container.foregroundColor : this.foregroundColor, ), // showHeader: this.getValue( - container ? container.showHeader : this.showHeader + container ? container.showHeader : this.showHeader, ), title: this.getValue(container ? container.title : this.title), subTitle: this.getValue(container ? container.subTitle : this.subTitle), avatarUrl: this.getValue( - container ? container.avatarUrl : this.avatarUrl + container ? container.avatarUrl : this.avatarUrl, ), avatarTemplate: this.getValue( - container ? container.avatarTemplate : this.avatarTemplate + container ? container.avatarTemplate : this.avatarTemplate, ), // imageUrl: this.getValue(container ? container.imageUrl : this.imageUrl), imageDescription: this.getValue( - container ? container.imageDescription : this.imageDescription + container ? container.imageDescription : this.imageDescription, ), // @@ -245,13 +248,13 @@ export abstract class XCardContainerComponent // showContent: this.getValue( - container ? container.showContent : this.showContent + container ? container.showContent : this.showContent, ), showActions: this.getValue( - container ? container.showActions : this.showActions + container ? container.showActions : this.showActions, ), showFooter: this.getValue( - container ? container.showFooter : this.showFooter + container ? container.showFooter : this.showFooter, ), }).pipe( map((data) => { @@ -264,7 +267,7 @@ export abstract class XCardContainerComponent ? container.actionProvider : this.actionProvider, }; - }) + }), ); } //#endregion @@ -288,8 +291,7 @@ type TXComponentCardContainer = { }; export interface IXComponentCardContainer - extends TXComponentCardContainer, - IXBaseComponentContainer { + extends TXComponentCardContainer, IXBaseComponentContainer { isInPage: XStandardType; wrapWithCard: XStandardType; } @@ -403,7 +405,7 @@ export abstract class XComponentCardContainerComponent public ruler: ViewportRuler, public zone: NgZone, public changeDetector: ChangeDetectorRef, - protected propertyProvider: XComponentCardContainer + protected propertyProvider: XComponentCardContainer, ) { super( config, @@ -412,7 +414,7 @@ export abstract class XComponentCardContainerComponent renderer, ruler, zone, - changeDetector + changeDetector, ); } //#endregion @@ -420,34 +422,34 @@ export abstract class XComponentCardContainerComponent // //#region Abstract ... public extractProps( - container?: IXComponentCardContainer + container?: IXComponentCardContainer, ): Observable { return forkJoin({ // isInPage: this.getValue(container ? container.isInPage : this.isInPage), wrapWithCard: this.getValue( - container ? container.wrapWithCard : this.wrapWithCard + container ? container.wrapWithCard : this.wrapWithCard, ), cardCssClass: this.getValue( - container ? container.cardCssClass : this.cardCssClass + container ? container.cardCssClass : this.cardCssClass, ), cardColor: this.getValue( - container ? container.cardColor : this.cardColor + container ? container.cardColor : this.cardColor, ), cardForegroundColor: this.getValue( - container ? container.cardForegroundColor : this.cardForegroundColor + container ? container.cardForegroundColor : this.cardForegroundColor, ), cardTitle: this.getValue( - container ? container.cardTitle : this.cardTitle + container ? container.cardTitle : this.cardTitle, ), cardSubTitle: this.getValue( - container ? container.cardSubTitle : this.cardSubTitle + container ? container.cardSubTitle : this.cardSubTitle, ), cardShowFooter: this.getValue( - container ? container.cardShowFooter : this.cardShowFooter + container ? container.cardShowFooter : this.cardShowFooter, ), cardShowActions: this.getValue( - container ? container.cardShowActions : this.cardShowActions + container ? container.cardShowActions : this.cardShowActions, ), }).pipe( map((data) => { @@ -460,7 +462,7 @@ export abstract class XComponentCardContainerComponent ? container.cardActionProvider : this.cardActionProvider, }; - }) + }), ); } //#endregion diff --git a/projects/x-framework-components/src/lib/x-chart/x-chart.component.html b/projects/x-framework-components/src/lib/x-chart/x-chart.component.html index f23664f..7ad392c 100644 --- a/projects/x-framework-components/src/lib/x-chart/x-chart.component.html +++ b/projects/x-framework-components/src/lib/x-chart/x-chart.component.html @@ -4,6 +4,7 @@ #chartCard class="x-card" [showActions]="true" + [actionProvider]="cardActionProvider" [color]="getValue(cardColor) | async" [ngClass]="getValue(cssClass) | async" [isInPage]="getValue(isInPage) | async" @@ -42,6 +43,7 @@ > = undefined; + //#region Chart ActionBar ... + // + private CHART_ACTIONBAR: XActionBarComponent = undefined; + + @ViewChild('chartActionBar', { static: false }) + set chartActionBar(v: XActionBarComponent) { + this.CHART_ACTIONBAR = v; + } + + get chartActionBar() { + return this.CHART_ACTIONBAR; + } + //#endregion + + // + //#region Chart Card ... + // + private CHART_CARD: XCardComponent = undefined; @ViewChild('chartCard', { static: false }) - set chartCard(el: ElementRef) { - this.CHART_CARD = el; - } - - get chartCard() { - return this.CHART_CARD;; + set chartCard(v: XCardComponent) { + // + if (!isNullOrUndefined(v)) { + this.registerCardActionProvider(); + } else { + this.unregisterCardActionProvider(); + } + + // + this.CHART_CARD = v; } + get chartCard() { + return this.CHART_CARD; + } + //#endregion + // + private ORIGINAL_HEIGHT: string = '300px'; private RESIZE_SUBJECT = new Subject(); // @@ -95,6 +124,7 @@ export class XChartComponent extends XChartContainerComponent { // private ACTION_PROVIDER_SUBSCRIPTION: Subscription; + private CARD_ACTION_PROVIDER_SUBSCRIPTION: Subscription; // readonly IconNames = Object.assign({}, XIconNames); @@ -109,7 +139,6 @@ export class XChartComponent extends XChartContainerComponent { // await this.initializeComponent(); - this.registerResizeHandler(); } async onChange(changeKeys: string[]) { @@ -349,6 +378,7 @@ export class XChartComponent extends XChartContainerComponent { // this.destroyComponent(); this.unregisterActionProvider(); + this.unregisterCardActionProvider(); } //#endregion @@ -667,7 +697,7 @@ export class XChartComponent extends XChartContainerComponent { printWindow.document.close(); } } - } catch (error) { } + } catch (error) {} } async handleToggleFullscreen() { @@ -1361,6 +1391,10 @@ export class XChartComponent extends XChartContainerComponent { this.CHART_OPTIONS, ); + // + // Storing Original Height ... + this.ORIGINAL_HEIGHT = this.CHART_OPTIONS.chart?.height?.toString(); + // await this.prepareActionBar(); @@ -2045,40 +2079,52 @@ export class XChartComponent extends XChartContainerComponent { this.chartInstance = null; } - private registerResizeHandler() { + private async handleFullscreenMode(isFullscreen: boolean) { // - fromEvent(window, 'resize') - .pipe( - debounceTime(200), - takeUntil(this.RESIZE_SUBJECT) - ) - .subscribe(() => { - // - if (isNullOrUndefined(this.chartInstance) || isNullOrUndefined(this.chartCard) || isNullOrUndefined(this.chartCard.nativeElement) || !this.chartCard.nativeElement.isFullscreen) { - return; - } + if ( + isNullOrUndefined(this.chartCard) || + isNullOrUndefined(this.chartInstance) + ) { + return; + } - // - var height = this.chartCard.nativeElement.calculateContentSize(); + // + let height = this.ORIGINAL_HEIGHT; + if (isFullscreen) { + // + const cardImageElement = document.querySelector('.x-card .x-image'); + const cardHeaderElement = document.querySelector('.x-card .x-header'); + const cardFooterElement = document.querySelector('.x-card .x-footer'); + const cardContentElement = document.querySelector('.x-card .x-content'); + const cardActionsElement = document.querySelector('.x-card .x-actions'); + const actionBarHeight = + (this.chartActionBar?.element?.nativeElement as HTMLElement) + ?.offsetHeight || 0; - // - // Reading Height ... - this.CHART_OPTIONS = { - ...this.CHART_OPTIONS, - chart: { - height: `${height}px` - } - }; + // + const offset = 24; + height = `${ + window.innerHeight - + offset - + (actionBarHeight + + (cardImageElement?.clientHeight || 0) + + (cardHeaderElement?.clientHeight || 0) + + (cardActionsElement?.clientHeight || 0) + + (cardFooterElement?.clientHeight || 0)) + }px`; + } - // - // TODO: - // Only Apply when Full Screen Mode ... - // Add FullScreen Event Handler in XCard Component ... - console.log('chart resize: ', height); + // + this.CHART_OPTIONS = { + ...this.CHART_OPTIONS, + chart: { + height: height, + }, + }; - // - this.chartInstance.updateOptions(this.CHART_OPTIONS, false, false); - }); + // + this.chartInstance.updateOptions(this.CHART_OPTIONS, false, true, false, false); + this.managerService.dispatchResizeEvent(); } private registerActionProvider() { @@ -2151,5 +2197,41 @@ export class XChartComponent extends XChartContainerComponent { this.ACTION_PROVIDER_SUBSCRIPTION.unsubscribe(); this.ACTION_PROVIDER_SUBSCRIPTION = null; } + + private registerCardActionProvider() { + // + if (!isNullOrUndefined(this.CARD_ACTION_PROVIDER_SUBSCRIPTION)) { + this.unregisterCardActionProvider(); + } + + // + this.CARD_ACTION_PROVIDER_SUBSCRIPTION = this.cardActionProvider + .asObservable() + .subscribe(async (model) => { + // + if (isNullOrUndefined(model) || isNullOrEmptyString(model.action)) { + return; + } + + // + // Handle Full Screen Toggled ... + if (model.action == XCardAction.FullScreenToggled) { + // + const isFullscreen = isNullOrUndefined(model.payload) ? false : true; + await this.handleFullscreenMode(isFullscreen); + } + }); + } + + private unregisterCardActionProvider() { + // + if (isNullOrUndefined(this.CARD_ACTION_PROVIDER_SUBSCRIPTION)) { + return; + } + + // + this.CARD_ACTION_PROVIDER_SUBSCRIPTION.unsubscribe(); + this.CARD_ACTION_PROVIDER_SUBSCRIPTION = null; + } //#endregion }