try to implement Chart Toolbars using XActionBar implementation like XIDEComponent ...

This commit is contained in:
2026-08-22 00:07:04 +03:30
parent 0f37e94ac9
commit e768ba219c
4 changed files with 1056 additions and 45 deletions
@@ -10,10 +10,26 @@ import {
XChartOptions,
XChartSeriesType,
XChartContainerComponent,
XChartActionBarItem,
} from './x-chart.typings';
import { Subscription } from 'rxjs';
import ApexCharts from 'apexcharts';
import { isNullOrUndefined, nameof } from 'x-framework-core';
import {
downloadArrayBufferedFile,
downloadFile,
downloadFileByUrl,
generateUuid,
isNullOrEmptyString,
isNullOrUndefined,
nameof,
XMimeType,
} from 'x-framework-core';
import {
XActionBarActionFiredModel,
XActionBarItem,
XActionBarItemSlot,
} from '../x-action-bar/x-action-bar.typings';
import { XIconNames } from '../x-icon/x-icon.typings';
@Component({
selector: 'x-chart',
@@ -53,6 +69,11 @@ export class XChartComponent extends XChartContainerComponent {
//
private ACTION_PROVIDER_SUBSCRIPTION: Subscription;
//
readonly IconNames = Object.assign({}, XIconNames);
readonly ActionBarItems = Object.assign({}, XChartActionBarItem);
readonly ActionBarItemSlots = Object.assign({}, XActionBarItemSlot);
//#endregion
//
@@ -164,6 +185,116 @@ export class XChartComponent extends XChartContainerComponent {
}
//#endregion
//
//#region UI Handler ...
async handleActionBarActionFired(model: XActionBarActionFiredModel) {
//
if (isNullOrUndefined(model) || isNullOrEmptyString(model.action)) {
return;
}
//
switch (
model.action
//
// case this.ActionBarItems.ChangeMode:
// this.handleActionModeFired(model.event);
// break;
// //
// case this.ActionBarItems.ChangeTheme:
// this.handleActionThemFired(model.event);
// break;
// //
// case this.ActionBarItems.Close:
// this.closeTab(this.currentTab);
// break;
// //
// case this.ActionBarItems.Undo:
// this.undo();
// break;
// //
// case this.ActionBarItems.Redo:
// this.redo();
// break;
// //
// case this.ActionBarItems.Beautify:
// await this.beautifyCode();
// break;
// //
// case this.ActionBarItems.Save:
// //
// this.updateCurrentTabDescriptor({
// canSave: false,
// });
// this.prepareActionBar();
// break;
) {
}
//
this.actionBarActionFired.emit(model);
}
//#endregion
//
//#region Actions ...
/**
* Export Chart Data in Specified Format ...
*
* @param format Export Format ...
* @param fileName Provided File Name without Extension ...
*/
async export(format: 'png' | 'svg' | 'csv' = 'png', fileName: string = '') {
//
// Normalize File Name ...
if (isNullOrEmptyString(fileName)) {
fileName = generateUuid('XChart');
}
//
fileName += '.' + format;
//
switch (format) {
//
case 'png':
//
const dataObject = await this.chartInstance.dataURI();
//
if ('imgURI' in dataObject) {
downloadFileByUrl(dataObject.imgURI, fileName);
} else if ('blob' in dataObject) {
downloadArrayBufferedFile(fileName, dataObject.blob);
}
break;
//
case 'svg':
//
const svgString = this.chartInstance.exports.exportToSVG();
downloadFile(svgString, XMimeType.ImageSVG, fileName);
break;
//
case 'csv':
//
this.chartInstance.exports.exportToCSV({
fileName: fileName,
columnDelimiter: ',',
lineDelimiter: '\n',
});
break;
}
}
//#endregion
//
//#region Private ...
private async initializeComponent() {
@@ -199,6 +330,9 @@ export class XChartComponent extends XChartContainerComponent {
id: chartId,
type: type as any,
foreColor: textColor,
toolbar: {
show: false,
},
events: {
...options.chart?.events,
mounted: (chartContext, config) => {
@@ -240,6 +374,627 @@ export class XChartComponent extends XChartContainerComponent {
await this.chartInstance.render();
}
private async prepareActionBar() {
//
if (isNullOrUndefined(this.chartInstance)) {
return;
}
//
const showActionBar = await this.getValueAsync(this.showActionBar);
if (!showActionBar) {
return;
}
//
//#region DefaultActionBarActions ...
//
const defaultPrintItem: XActionBarItem = {
onlyIcon: true,
disabled: this.uiDisabled,
icon: this.IconNames.print,
title: this.ResourceIDs.print,
id: this.ActionBarItems.Print,
slot: this.ActionBarItemSlots.END,
iconColor: this.defaultActionBarItemColor,
};
//
const defaultExportPNGItem: XActionBarItem = {
onlyIcon: true,
disabled: this.uiDisabled,
icon: this.IconNames.image,
slot: this.ActionBarItemSlots.END,
title: this.ResourceIDs.export_png,
id: this.ActionBarItems.ExportAsPNG,
iconColor: this.defaultActionBarItemColor,
};
//
const defaultExportSVGItem: XActionBarItem = {
onlyIcon: true,
disabled: this.uiDisabled,
icon: this.IconNames.image,
slot: this.ActionBarItemSlots.END,
title: this.ResourceIDs.export_svg,
id: this.ActionBarItems.ExportAsSVG,
iconColor: this.defaultActionBarItemColor,
};
//
const defaultExportCSVItem: XActionBarItem = {
onlyIcon: true,
disabled: this.uiDisabled,
icon: this.IconNames.data_table,
slot: this.ActionBarItemSlots.END,
title: this.ResourceIDs.export_csv,
id: this.ActionBarItems.ExportAsCSV,
iconColor: this.defaultActionBarItemColor,
};
//
const defaultZoomInItem: XActionBarItem = {
onlyIcon: true,
disabled: this.uiDisabled,
icon: this.IconNames.add,
id: this.ActionBarItems.ZoomIn,
title: this.ResourceIDs.zoom_in,
slot: this.ActionBarItemSlots.START,
iconColor: this.defaultActionBarItemColor,
};
//
const defaultZoomOutItem: XActionBarItem = {
onlyIcon: true,
disabled: this.uiDisabled,
id: this.ActionBarItems.ZoomOut,
title: this.ResourceIDs.zoom_out,
slot: this.ActionBarItemSlots.START,
icon: this.IconNames.friendship_reject,
iconColor: this.defaultActionBarItemColor,
};
//
const defaultZoomSelectionItem: XActionBarItem = {
onlyIcon: true,
disabled: this.uiDisabled,
slot: this.ActionBarItemSlots.START,
id: this.ActionBarItems.ZoomSelection,
title: this.ResourceIDs.zoom_selection,
icon: this.IconNames.friendship_reject,
iconColor: this.defaultActionBarItemColor,
};
//
const defaultXAxisSelectionItem: XActionBarItem = {
onlyIcon: true,
disabled: this.uiDisabled,
icon: this.IconNames.x_axist,
title: this.ResourceIDs.x_axis,
id: this.ActionBarItems.XSelection,
slot: this.ActionBarItemSlots.START,
iconColor: this.defaultActionBarItemColor,
};
//
const defaultYAxisSelectionItem: XActionBarItem = {
onlyIcon: true,
disabled: this.uiDisabled,
icon: this.IconNames.y_axis,
title: this.ResourceIDs.y_axis,
id: this.ActionBarItems.YSelection,
slot: this.ActionBarItemSlots.START,
iconColor: this.defaultActionBarItemColor,
};
//
const defaultXYAxisSelectionItem: XActionBarItem = {
onlyIcon: true,
disabled: this.uiDisabled,
icon: this.IconNames.xy_axis,
title: this.ResourceIDs.xy_axis,
id: this.ActionBarItems.XYSelection,
slot: this.ActionBarItemSlots.START,
iconColor: this.defaultActionBarItemColor,
};
//
const defaultPanItem: XActionBarItem = {
onlyIcon: true,
disabled: this.uiDisabled,
icon: this.IconNames.touch,
title: this.ResourceIDs.pan,
id: this.ActionBarItems.Pan,
slot: this.ActionBarItemSlots.START,
iconColor: this.defaultActionBarItemColor,
};
//
const defaultResetItem: XActionBarItem = {
onlyIcon: true,
disabled: this.uiDisabled,
icon: this.IconNames.refresh,
title: this.ResourceIDs.reset,
slot: this.ActionBarItemSlots.END,
id: this.ActionBarItems.ResetChart,
iconColor: this.defaultActionBarItemColor,
};
//
const defaultFullscreenItem: XActionBarItem = {
onlyIcon: true,
disabled: this.uiDisabled,
icon: this.IconNames.fullscreen,
title: this.ResourceIDs.full_screen,
slot: this.ActionBarItemSlots.START,
id: this.ActionBarItems.ToggleFullScreen,
iconColor: this.defaultActionBarItemColor,
};
//#endregion
//
this.actionBarActions = [];
this.detectChanges();
//
const availableItems = await this.getArrayValueAsync(
this.availableActionBarItems,
);
if (!this.hasChild(availableItems)) {
return;
}
//
let hasItem = false;
const actionBarItems: XActionBarItem[] = [];
//
//#region Print ...
hasItem = availableItems
.map((ai) => ai.actionId)
.includes(this.ActionBarItems.Print);
//
if (hasItem) {
//
const selectedItem = availableItems.find(
(ai) => ai.actionId === this.ActionBarItems.Print,
);
const providedItem = selectedItem.descriptor;
let item = {
...defaultPrintItem,
};
if (!isNullOrUndefined(providedItem)) {
item = {
...item,
...providedItem,
};
}
//
item = {
...item,
disabled: this.uiDisabled,
};
//
actionBarItems.push(item);
}
//#endregion
//
//#region ExportAsPNG ...
hasItem = availableItems
.map((ai) => ai.actionId)
.includes(this.ActionBarItems.ExportAsPNG);
//
if (hasItem) {
//
const selectedItem = availableItems.find(
(ai) => ai.actionId === this.ActionBarItems.ExportAsPNG,
);
const providedItem = selectedItem.descriptor;
let item = {
...defaultExportPNGItem,
};
if (!isNullOrUndefined(providedItem)) {
item = {
...item,
...providedItem,
};
}
//
item = {
...item,
disabled: this.uiDisabled,
};
//
actionBarItems.push(item);
}
//#endregion
//
//#region ExportAsSVG ...
hasItem = availableItems
.map((ai) => ai.actionId)
.includes(this.ActionBarItems.ExportAsSVG);
//
if (hasItem) {
//
const selectedItem = availableItems.find(
(ai) => ai.actionId === this.ActionBarItems.ExportAsSVG,
);
const providedItem = selectedItem.descriptor;
let item = {
...defaultExportSVGItem,
};
if (!isNullOrUndefined(providedItem)) {
item = {
...item,
...providedItem,
};
}
//
item = {
...item,
disabled: this.uiDisabled,
};
//
actionBarItems.push(item);
}
//#endregion
//
//#region ExportAsCSV ...
hasItem = availableItems
.map((ai) => ai.actionId)
.includes(this.ActionBarItems.ExportAsCSV);
//
if (hasItem) {
//
const selectedItem = availableItems.find(
(ai) => ai.actionId === this.ActionBarItems.ExportAsCSV,
);
const providedItem = selectedItem.descriptor;
let item = {
...defaultExportCSVItem,
};
if (!isNullOrUndefined(providedItem)) {
item = {
...item,
...providedItem,
};
}
//
item = {
...item,
disabled: this.uiDisabled,
};
//
actionBarItems.push(item);
}
//#endregion
//
//#region ZoomIn ...
hasItem = availableItems
.map((ai) => ai.actionId)
.includes(this.ActionBarItems.ZoomIn);
//
if (hasItem) {
//
const selectedItem = availableItems.find(
(ai) => ai.actionId === this.ActionBarItems.ZoomIn,
);
const providedItem = selectedItem.descriptor;
let item = {
...defaultZoomInItem,
};
if (!isNullOrUndefined(providedItem)) {
item = {
...item,
...providedItem,
};
}
//
item = {
...item,
disabled: this.uiDisabled,
};
//
actionBarItems.push(item);
}
//#endregion
//
//#region ZoomOut ...
hasItem = availableItems
.map((ai) => ai.actionId)
.includes(this.ActionBarItems.ZoomOut);
//
if (hasItem) {
//
const selectedItem = availableItems.find(
(ai) => ai.actionId === this.ActionBarItems.ZoomOut,
);
const providedItem = selectedItem.descriptor;
let item = {
...defaultZoomOutItem,
};
if (!isNullOrUndefined(providedItem)) {
item = {
...item,
...providedItem,
};
}
//
item = {
...item,
disabled: this.uiDisabled,
};
//
actionBarItems.push(item);
}
//#endregion
//
//#region ZoomSelection ...
hasItem = availableItems
.map((ai) => ai.actionId)
.includes(this.ActionBarItems.ZoomSelection);
//
if (hasItem) {
//
const selectedItem = availableItems.find(
(ai) => ai.actionId === this.ActionBarItems.ZoomSelection,
);
const providedItem = selectedItem.descriptor;
let item = {
...defaultZoomSelectionItem,
};
if (!isNullOrUndefined(providedItem)) {
item = {
...item,
...providedItem,
};
}
//
item = {
...item,
disabled: this.uiDisabled,
};
//
actionBarItems.push(item);
}
//#endregion
//
//#region XSelection ...
hasItem = availableItems
.map((ai) => ai.actionId)
.includes(this.ActionBarItems.XSelection);
//
if (hasItem) {
//
const selectedItem = availableItems.find(
(ai) => ai.actionId === this.ActionBarItems.XSelection,
);
const providedItem = selectedItem.descriptor;
let item = {
...defaultXAxisSelectionItem,
};
if (!isNullOrUndefined(providedItem)) {
item = {
...item,
...providedItem,
};
}
//
item = {
...item,
disabled: this.uiDisabled,
};
//
actionBarItems.push(item);
}
//#endregion
//
//#region YSelection ...
hasItem = availableItems
.map((ai) => ai.actionId)
.includes(this.ActionBarItems.YSelection);
//
if (hasItem) {
//
const selectedItem = availableItems.find(
(ai) => ai.actionId === this.ActionBarItems.YSelection,
);
const providedItem = selectedItem.descriptor;
let item = {
...defaultYAxisSelectionItem,
};
if (!isNullOrUndefined(providedItem)) {
item = {
...item,
...providedItem,
};
}
//
item = {
...item,
disabled: this.uiDisabled,
};
//
actionBarItems.push(item);
}
//#endregion
//
//#region XYSelection ...
hasItem = availableItems
.map((ai) => ai.actionId)
.includes(this.ActionBarItems.XYSelection);
//
if (hasItem) {
//
const selectedItem = availableItems.find(
(ai) => ai.actionId === this.ActionBarItems.XYSelection,
);
const providedItem = selectedItem.descriptor;
let item = {
...defaultXYAxisSelectionItem,
};
if (!isNullOrUndefined(providedItem)) {
item = {
...item,
...providedItem,
};
}
//
item = {
...item,
disabled: this.uiDisabled,
};
//
actionBarItems.push(item);
}
//#endregion
//
//#region Pan ...
hasItem = availableItems
.map((ai) => ai.actionId)
.includes(this.ActionBarItems.Pan);
//
if (hasItem) {
//
const selectedItem = availableItems.find(
(ai) => ai.actionId === this.ActionBarItems.Pan,
);
const providedItem = selectedItem.descriptor;
let item = {
...defaultPanItem,
};
if (!isNullOrUndefined(providedItem)) {
item = {
...item,
...providedItem,
};
}
//
item = {
...item,
disabled: this.uiDisabled,
};
//
actionBarItems.push(item);
}
//#endregion
//
//#region Reset ...
hasItem = availableItems
.map((ai) => ai.actionId)
.includes(this.ActionBarItems.ResetChart);
//
if (hasItem) {
//
const selectedItem = availableItems.find(
(ai) => ai.actionId === this.ActionBarItems.ResetChart,
);
const providedItem = selectedItem.descriptor;
let item = {
...defaultResetItem,
};
if (!isNullOrUndefined(providedItem)) {
item = {
...item,
...providedItem,
};
}
//
item = {
...item,
disabled: this.uiDisabled,
};
//
actionBarItems.push(item);
}
//#endregion
//
//#region FullScreen ...
hasItem = availableItems
.map((ai) => ai.actionId)
.includes(this.ActionBarItems.ToggleFullScreen);
//
if (hasItem) {
//
const selectedItem = availableItems.find(
(ai) => ai.actionId === this.ActionBarItems.ToggleFullScreen,
);
const providedItem = selectedItem.descriptor;
let item = {
...defaultFullscreenItem,
};
if (!isNullOrUndefined(providedItem)) {
item = {
...item,
...providedItem,
};
}
//
item = {
...item,
disabled: this.uiDisabled,
};
//
actionBarItems.push(item);
}
//#endregion
//
this.actionBarActions = [...actionBarItems];
this.detectChanges();
}
private async handleChartUpdate() {
//
if (
@@ -261,6 +1016,10 @@ export class XChartComponent extends XChartContainerComponent {
this.CHART_OPTIONS = {
...options,
...this.CHART_OPTIONS,
chart: {
...this.CHART_OPTIONS.chart,
type: type as any,
},
};
//