try to use x-chart component ...

This commit is contained in:
2026-08-21 18:44:46 +03:30
parent 203c09a0e8
commit 0f37e94ac9
8 changed files with 3498 additions and 98 deletions
-1
View File
@@ -73,7 +73,6 @@
"libphonenumber-js": "^1.9.22",
"md5-typescript": "^1.0.5",
"moment": "^2.29.1",
"ng-apexcharts": "^3.0.0",
"ng-packagr": "^12.0.0",
"ngx-device-detector": "^2.1.1",
"ngx-markdown": "^12.0.1",
@@ -42,6 +42,7 @@ import {
} from './x-description-list.component.templates';
import { XMapModule } from '../x-map/x-map.module';
import { XFabModule } from '../x-fab/x-fab.module';
import { XIDEModule } from '../x-ide/x-ide.module';
import { XFormModule } from '../x-form/x-form.module';
import { XGridModule } from '../x-grid/x-grid.module';
import { XIconModule } from '../x-icon/x-icon.module';
@@ -53,8 +54,10 @@ import { XTableModule } from '../x-table/x-table.module';
import { XThemeModule } from '../x-theme/x-theme.module';
import { XColorModule } from '../x-color/x-color.module';
import { XEmptyModule } from '../x-empty/x-empty.module';
import { XChartModule } from '../x-chart/x-chart.module';
import { XSliderModule } from '../x-slider/x-slider.module';
import { XButtonModule } from '../x-button/x-button.module';
import { XIdeTestComponent } from './x-ide.component.template';
import { XCounterModule } from '../x-counter/x-counter.module';
import { XSlotterModule } from '../x-slotter/x-slotter.module';
import { XSpinnerModule } from '../x-spinner/x-spinner.module';
@@ -66,6 +69,7 @@ import { XMarkdownModule } from '../x-markdown/x-markdown.module';
import { XFormTestComponent } from './x-form.component.templates';
import { XGridTestComponent } from './x-grid.component.templates';
import { XIconTestComponent } from './x-icon.component.templates';
import { XChartTestComponent } from './x-chart.component.template';
import { XTableTestComponent } from './x-table.component.templates';
import { XColorTestComponent } from './x-color.component.templates';
import { XThumbnailModule } from '../x-thumbnail/x-thumbnail.module';
@@ -119,6 +123,12 @@ import { XExpandablePandelTestComponent } from './x-expandable-panel.component.t
// x-button ...
XButtonTestComponent,
//
// x-ide ...
XIdeTestComponent,
//
// x-chart ...
XChartTestComponent,
//
// x-card ...
XCardTestComponent,
XComponentCardTestComponent,
@@ -245,6 +255,7 @@ import { XExpandablePandelTestComponent } from './x-expandable-panel.component.t
XBaseComponentModule,
//
XIDEModule,
XFabModule,
XMapModule,
XPageModule,
@@ -255,6 +266,7 @@ import { XExpandablePandelTestComponent } from './x-expandable-panel.component.t
XTabsModule,
XListModule,
XGridModule,
XChartModule,
XColorModule,
XTableModule,
XThemeModule,
@@ -0,0 +1,31 @@
import { Component } from '@angular/core';
import { XChartContainerComponent } from '../x-chart/x-chart.typings';
@Component({
template: `
<ng-container *ngIf="extractProps() | async as props">
<x-chart
[series]="props.series"
[options]="props.options"
[cssClass]="props.cssClass"
[isInPage]="props.isInPage"
[cardColor]="props.cardColor"
[cardTitle]="props.cardTitle"
[autoUpdate]="props.autoUpdate"
(zoomed)="props.zoomed($event)"
[wrapWithCard]="props.wrapWithCard"
[cardCssClass]="props.cardCssClass"
[cardSubTitle]="props.cardSubTitle"
[cardShowFooter]="props.cardShowFooter"
[actionProvider]="props.actionProvider"
[cardShowActions]="props.cardShowActions"
(chartRendered)="props.chartRendered($event)"
[cardActionProvider]="props.cardActionProvider"
[cardForegroundColor]="props.cardForegroundColor"
(dataPointSelected)="props.dataPointSelected($event)"
>
</x-chart>
</ng-container>
`,
})
export class XChartTestComponent extends XChartContainerComponent {}
@@ -0,0 +1,53 @@
import { Component } from '@angular/core';
import { XIDEContainerComponent } from '../x-ide/x-ide.typings';
@Component({
template: `
<ng-container *ngIf="extractProps() | async as props">
<x-ide
[mode]="props.mode"
[theme]="props.theme"
[content]="props.content"
[cssClass]="props.cssClass"
[minLines]="props.minLines"
[maxLines]="props.maxLines"
[fontSize]="props.fontSize"
[readonly]="props.readonly"
[isInPage]="props.isInPage"
[alignTabs]="props.alignTabs"
[cardColor]="props.cardColor"
[cardTitle]="props.cardTitle"
[cardSubTitle]="props.cardSubTitle"
[wordWrapping]="props.wordWrapping"
[wrapWithCard]="props.wrapWithCard"
[cardCssClass]="props.cardCssClass"
[showActionBar]="props.showActionBar"
[actionBarColor]="props.actionBarColor"
[cardShowFooter]="props.cardShowFooter"
[defaultTabName]="props.defaultTabName"
[actionProvider]="props.actionProvider"
[tabHeaderColor]="props.tabHeaderColor"
[activeTabColor]="props.activeTabColor"
[cardShowActions]="props.cardShowActions"
[showLineNumbers]="props.showLineNumbers"
[showPrintMargin]="props.showPrintMargin"
[showFoldWidgets]="props.showFoldWidgets"
[actionBarActions]="props.actionBarActions"
[actionBarCssClass]="props.actionBarCssClass"
(contentChange)="props.contentChange($event)"
[cardActionProvider]="props.cardActionProvider"
[highlightActiveLine]="props.highlightActiveLine"
[cardForegroundColor]="props.cardForegroundColor"
[basicAutocompletion]="props.basicAutocompletion"
[hasCloseOnDefaultTab]="props.hasCloseOnDefaultTab"
[availableActionBarItems]="props.availableActionBarItems"
[actionBarActionProvider]="props.actionBarActionProvider"
(actionBarActionFired)="props.actionBarActionFired($event)"
[actionBarForegroundColor]="props.actionBarForegroundColor"
[defaultActionBarItemColor]="props.defaultActionBarItemColor"
>
</x-ide>
</ng-container>
`,
})
export class XIdeTestComponent extends XIDEContainerComponent {}
@@ -1,7 +1,13 @@
:host {
display: block;
width: 100%;
height: 100%;
}
.x-chart-wrapper {
width: 100%;
height: 100%;
min-height: 300px; // ارتفاع پیش‌فرض
min-height: 300px; /* ارتفاع پیش‌فرض برای جلوگیری از فروپاشی layout */
}
.x-chart-container {
@@ -4,10 +4,16 @@ import {
ElementRef,
ChangeDetectionStrategy,
} from '@angular/core';
import {
isChartType,
XChartAction,
XChartOptions,
XChartSeriesType,
XChartContainerComponent,
} from './x-chart.typings';
import { Subscription } from 'rxjs';
import ApexCharts from 'apexcharts';
import { isNullOrUndefined, nameof } from 'x-framework-core';
import ApexCharts, { ApexAxisChartSeries, ApexOptions } from 'apexcharts';
import { XChartAction, XChartContainerComponent } from './x-chart.typings';
@Component({
selector: 'x-chart',
@@ -19,11 +25,31 @@ export class XChartComponent extends XChartContainerComponent {
//
//#region Props ...
//
@ViewChild('chartContainer', { static: true })
chartContainer!: ElementRef;
private CHART_CONTAINER: ElementRef | undefined;
@ViewChild('chartContainer', { static: false })
set chartContainer(el: ElementRef | undefined) {
//
if (isNullOrUndefined(el)) {
//
this.destroyComponent();
return;
}
//
private chartInstance: ApexCharts | null = null;
this.CHART_CONTAINER = el;
this.initializeComponent();
}
get chartContainer() {
return this.CHART_CONTAINER;
}
//
private CHART_OPTIONS: XChartOptions = null;
//
private chartInstance: ApexCharts = null;
//
private ACTION_PROVIDER_SUBSCRIPTION: Subscription;
@@ -31,11 +57,11 @@ export class XChartComponent extends XChartContainerComponent {
//
//#region LifeCycles ...
afterViewInit() {
async afterViewInit() {
super.afterViewInit();
//
this.initializeComponent();
await this.initializeComponent();
}
async onChange(changeKeys: string[]) {
@@ -54,12 +80,23 @@ export class XChartComponent extends XChartContainerComponent {
}
//
// Check Auto Update ...
var autoUpdate = await this.getValueAsync(this.autoUpdate);
if (!autoUpdate || isNullOrUndefined(this.chartInstance)) {
return;
// Action Provider Changed ...
const isActionProviderChanged = changeKeys.includes(
nameof<XChartComponent>('actionProvider'),
);
if (isActionProviderChanged) {
this.registerActionProvider();
}
//
// Check Auto Update ...
var autoUpdate = await this.getValueAsync(this.autoUpdate);
if (
autoUpdate &&
!isNullOrUndefined(this.chartInstance) &&
!isNullOrUndefined(this.chartContainer) &&
!isNullOrUndefined(this.chartContainer.nativeElement)
) {
//
// Options Changed ...
const isOptionsChanged = changeKeys.includes(
@@ -72,8 +109,30 @@ export class XChartComponent extends XChartContainerComponent {
}
//
const options = await this.getValueAsync(this.options);
await this.chartInstance.updateOptions(options);
await this.handleChartUpdate();
}
//
// Chart Type ...
const isTypeChanged = changeKeys.includes(
nameof<XChartComponent>('type'),
);
if (isTypeChanged) {
//
if (isNullOrUndefined(this.type)) {
this.type = this.propertyProvider.type;
}
//
var type = await this.getValueAsync(this.type);
if (!isChartType(type)) {
//
type = await this.getValueAsync(this.propertyProvider.type);
this.type = type;
}
//
await this.handleChartUpdate();
}
//
@@ -88,17 +147,8 @@ export class XChartComponent extends XChartContainerComponent {
}
//
const series = await this.getValueAsync(this.series);
await this.chartInstance.updateSeries(series);
await this.handleChartUpdate();
}
//
// Action Provider Changed ...
const isActionProviderChanged = changeKeys.includes(
nameof<XChartComponent>('actionProvider'),
);
if (isActionProviderChanged) {
this.registerActionProvider();
}
//
@@ -109,13 +159,7 @@ export class XChartComponent extends XChartContainerComponent {
super.onDestroy();
//
if (!isNullOrUndefined(this.chartInstance)) {
//
this.chartInstance.destroy();
this.chartInstance = null;
}
//
this.destroyComponent();
this.unregisterActionProvider();
}
//#endregion
@@ -123,18 +167,18 @@ export class XChartComponent extends XChartContainerComponent {
//
//#region Private ...
private async initializeComponent() {
//
if (isNullOrUndefined(this.CHART_CONTAINER)) {
return;
}
//
// Reading Requirement Properties ...
const type = await this.getValueAsync(this.type);
const chartId = await this.getValueAsync(this.uuid);
const series = await this.getValueAsync(this.series);
const options = await this.getValueAsync(this.options);
//
// Validate Options ...
if (isNullOrUndefined(options)) {
return;
}
//
const computedStyle = getComputedStyle(document.documentElement);
const primaryColor =
@@ -145,13 +189,15 @@ export class XChartComponent extends XChartContainerComponent {
const gridColor =
computedStyle.getPropertyValue('--x-color-light-shade').trim() ||
'#e0e0e0';
const finalOptions: ApexOptions = {
//
this.CHART_OPTIONS = {
...options,
series: series as any,
series: series || options.series,
chart: {
...options.chart,
id: chartId,
type: options.chart?.type || 'line',
type: type as any,
foreColor: textColor,
events: {
...options.chart?.events,
@@ -182,32 +228,57 @@ export class XChartComponent extends XChartContainerComponent {
...options.grid,
borderColor: gridColor,
},
xaxis: {
...options.xaxis,
labels: {
...options.xaxis?.labels,
style: { colors: textColor },
},
},
yaxis: {
...options.yaxis,
labels: {
...(options.yaxis as any).labels,
style: { colors: textColor },
},
},
};
//
this.chartInstance = new ApexCharts(
this.chartContainer.nativeElement,
finalOptions,
this.CHART_OPTIONS,
);
//
await this.chartInstance.render();
}
private async handleChartUpdate() {
//
if (
isNullOrUndefined(this.chartInstance) ||
isNullOrUndefined(this.CHART_OPTIONS) ||
isNullOrUndefined(this.chartContainer) ||
isNullOrUndefined(this.chartContainer.nativeElement)
) {
return;
}
//
// Reading Requirement Properties ...
const type = await this.getValueAsync(this.type);
const series = await this.getValueAsync(this.series);
//
const options = await this.getValueAsync(this.options);
this.CHART_OPTIONS = {
...options,
...this.CHART_OPTIONS,
};
//
await this.chartInstance.updateOptions(this.CHART_OPTIONS);
await this.chartInstance.updateSeries(series);
}
private destroyComponent() {
//
if (isNullOrUndefined(this.chartInstance)) {
return;
}
//
this.chartInstance.destroy();
this.chartInstance = null;
}
private registerActionProvider() {
//
this.unregisterActionProvider();
@@ -242,7 +313,7 @@ export class XChartComponent extends XChartContainerComponent {
) {
//
this.series = await this.getValueAsync(
model.payload as ApexAxisChartSeries,
model.payload as XChartSeriesType,
);
await this.chartInstance.updateSeries(this.series);
this.detectChanges();
@@ -258,7 +329,7 @@ export class XChartComponent extends XChartContainerComponent {
) {
//
this.options = await this.getValueAsync(
model.payload as ApexOptions,
model.payload as XChartOptions,
);
await this.chartInstance.updateOptions(this.options);
this.detectChanges();
File diff suppressed because it is too large Load Diff
@@ -1,7 +1,7 @@
<!-- Component Template -->
<ng-container *ngIf="getValue(wrapWithCard) | async; else componentsRef">
<x-card
class="v-card v-no-margin-card"
class="x-card"
[color]="getValue(cardColor) | async"
[ngClass]="getValue(cssClass) | async"
[isInPage]="getValue(isInPage) | async"
@@ -32,7 +32,11 @@
<!-- Component's itSelf Template -->
<ng-template #componentsRef>
<div class="x-component-wrapper" [ngClass]="getValue(cssClass) | async">
<div
class="x-component-wrapper"
[class.mobile]="isMobileUi$ | async"
[ngClass]="getValue(cssClass) | async"
>
<!-- Toolbar -->
<x-action-bar
[color]="actionBarColor"