Compare commits

...
1 Commits
Author SHA1 Message Date
saherelm 398f098b8b simulate chart toolbar actions ... 2026-08-24 09:15:11 +03:30
2 changed files with 501 additions and 214 deletions
@@ -2,8 +2,8 @@ import {
Component,
ViewChild,
ElementRef,
ChangeDetectionStrategy,
HostListener,
ChangeDetectionStrategy,
} from '@angular/core';
import {
nameof,
@@ -122,6 +122,40 @@ export class XChartComponent extends XChartContainerComponent {
this.registerActionProvider();
}
//
// Available Action Bar Items Changed ...
const isAvailableActionBarItemsChanged = changeKeys.includes(
nameof<XChartComponent>('availableActionBarItems')
);
if (isAvailableActionBarItemsChanged) {
//
if (isNullOrUndefined(this.availableActionBarItems)) {
this.availableActionBarItems = this.propertyProvider.availableActionBarItems;
}
//
await this.prepareActionBar();
}
//
// Zoom Step ...
const isZoomStepChanged = changeKeys.includes(
nameof<XChartComponent>('zoomStep')
);
if (isZoomStepChanged) {
//
let zoomStep = await this.getValueAsync(this.zoomStep);
if (isNullOrUndefined(zoomStep) ||
zoomStep < 0 ||
zoomStep > 1
) {
this.zoomStep = 0.125;
}
//
zoomStep = await this.getValueAsync(this.zoomStep);
}
//
// Check Auto Update ...
var autoUpdate = await this.getValueAsync(this.autoUpdate);
@@ -207,47 +241,82 @@ export class XChartComponent extends XChartContainerComponent {
}
//
switch (
model.action
switch (model.action) {
//
// case this.ActionBarItems.ChangeMode:
// this.handleActionModeFired(model.event);
// break;
// Print ...
case XChartActionBarItem.Print:
await this.handlePrint();
break;
// //
// case this.ActionBarItems.ChangeTheme:
// this.handleActionThemFired(model.event);
// break;
//
// Export As CSV ...
case XChartActionBarItem.ExportAsCSV:
await this.handleExportAsCSV();
break;
// //
// case this.ActionBarItems.Close:
// this.closeTab(this.currentTab);
// break;
//
// Export As PNG ...
case XChartActionBarItem.ExportAsPNG:
await this.handleExportAsPng();
break;
// //
// case this.ActionBarItems.Undo:
// this.undo();
// break;
//
// Export As SVG ...
case XChartActionBarItem.ExportAsSVG:
await this.handleExportAsSVG();
break;
// //
// case this.ActionBarItems.Redo:
// this.redo();
// break;
//
// Zoom In ...
case XChartActionBarItem.ZoomIn:
await this.handleZoomIn();
break;
// //
// case this.ActionBarItems.Beautify:
// await this.beautifyCode();
// break;
//
// Zoom Out ...
case XChartActionBarItem.ZoomOut:
await this.handleZoomOut();
break;
// //
// case this.ActionBarItems.Save:
// //
// this.updateCurrentTabDescriptor({
// canSave: false,
// });
// this.prepareActionBar();
// break;
) {
//
// Zoom Selection ...
case XChartActionBarItem.ZoomSelection:
break;
//
// X Selection ...
case XChartActionBarItem.XSelection:
break;
//
// Y Selection ...
case XChartActionBarItem.YSelection:
break;
//
// XY Selection ...
case XChartActionBarItem.XYSelection:
break;
//
// Pan ...
case XChartActionBarItem.Pan:
await this.handlePan();
break;
//
// ResetChart ...
case XChartActionBarItem.ResetChart:
await this.handleResetChart();
break;
//
// ToggleFullScreen ...
case XChartActionBarItem.ToggleFullScreen:
await this.handleToggleFullscreen();
break;
//
}
//
@@ -308,6 +377,222 @@ export class XChartComponent extends XChartContainerComponent {
}
//#endregion
//
//#region Toolbar Actions ...
async handleExportAsPng() {
//
if (isNullOrUndefined(this.chartInstance)) {
return;
}
//
await this.export('png');
}
async handleExportAsSVG() {
//
if (isNullOrUndefined(this.chartInstance)) {
return;
}
//
await this.export('svg');
}
async handleExportAsCSV() {
//
if (isNullOrUndefined(this.chartInstance)) {
return;
}
//
await this.export('csv');
}
async handleZoomIn() {
//
if (isNullOrUndefined(this.chartInstance)) {
return;
}
//
var zoomStep = await this.getValueAsync(this.zoomStep);
//
const state = this.chartInstance.getState();
const minX = state.minX;
const maxX = state.maxX;
const rangeIn = maxX - minX;
//
await this.chartInstance.zoomX(minX + rangeIn * zoomStep, maxX - rangeIn * zoomStep);
}
async handleZoomOut() {
//
if (isNullOrUndefined(this.chartInstance)) {
return;
}
//
var zoomStep = await this.getValueAsync(this.zoomStep);
//
const state = this.chartInstance.getState();
const minX = state.minX;
const maxX = state.maxX;
const rangeIn = maxX - minX;
//
await this.chartInstance.zoomX(minX - rangeIn * zoomStep, maxX + rangeIn * zoomStep);
}
async handlePan() {
//
if (isNullOrUndefined(this.chartInstance)) {
return;
}
//
await this.chartInstance.updateOptions({
chart: {
zoom: {
enabled: false
},
selection: {
type: 'x',
enabled: true,
},
}
});
}
async handleResetChart() {
//
if (isNullOrUndefined(this.chartInstance)) {
return;
}
//
this.chartInstance.resetSeries(true, true);
}
async handlePrint() {
//
if (isNullOrUndefined(this.chartInstance)) {
return;
}
//
try {
//
const result = await this.chartInstance.dataURI();
if ('imgURI' in result) {
//
const imgURI = result.imgURI;
const printWindow = window.open('', '_blank');
if (printWindow) {
//
// Write Data Uri on a Page for Printing ...
printWindow.document.write(`
<!DOCTYPE html>
<html>
<head>
<title>Print Chart</title>
<style>
body {
margin: 0;
padding: 20px;
display: flex;
justify-content: center;
align-items: center;
min-height: 100vh;
}
img {
max-width: 100%;
height: auto;
}
@media print {
body {
margin: 0;
}
img {
max-width: 100%;
page-break-inside: avoid;
}
}
</style>
</head>
<body>
<img src="${imgURI}" alt="Chart" />
<script>
window.onload = function() {
window.print();
window.onafterprint = function() {
window.close();
};
};
</script>
</body>
</html>
`);
//
printWindow.document.close();
}
}
} catch (error) {
}
}
async handleToggleFullscreen() {
//
if (isNullOrUndefined(this.chartInstance) ||
isNullOrUndefined(this.chartContainer) ||
isNullOrUndefined(this.chartContainer.nativeElement)
) {
return;
}
//
const chartWrapper = this.chartContainer.nativeElement;
const doc = document as any;
//
// Check if the chart wrapper is currently in fullscreen mode
const isFullscreen =
doc.fullscreenElement === chartWrapper ||
doc.msFullscreenElement === chartWrapper ||
doc.mozFullScreenElement === chartWrapper ||
doc.webkitFullscreenElement === chartWrapper;
if (!isFullscreen) {
//
// Enter Fullscreen
if (chartWrapper.requestFullscreen) {
await chartWrapper.requestFullscreen();
} else if (chartWrapper.webkitRequestFullscreen) {
await chartWrapper.webkitRequestFullscreen();
} else if (chartWrapper.mozRequestFullScreen) {
await chartWrapper.mozRequestFullScreen();
} else if (chartWrapper.msRequestFullscreen) {
await chartWrapper.msRequestFullscreen();
}
} else {
//
// Exit Fullscreen
if (doc.exitFullscreen) {
await doc.exitFullscreen();
} else if (doc.webkitExitFullscreen) {
await doc.webkitExitFullscreen();
} else if (doc.mozCancelFullScreen) {
await doc.mozCancelFullScreen();
} else if (doc.msExitFullscreen) {
await doc.msExitFullscreen();
}
}
}
//#endregion
//
//#region Private ...
private async initializeComponent() {
@@ -22,27 +22,26 @@ import {
XCardActionModel,
XComponentCardContainer,
IXComponentCardContainer,
XComponentCardContainerComponent,
} from '../x-card/x-card.typings';
import { concatMap, map } from 'rxjs/operators';
import { map } from 'rxjs/operators';
import {
XBaseContainer,
XBaseContainerComponent,
} from '../classes/i-x-base.container';
import {
XActionBarItem,
XActionBarActionModel,
XActionBarActionFiredModel,
XComponentActionBarContainer,
IXComponentActionBarContainer,
} from '../x-action-bar/x-action-bar.typings';
import { forkJoin, Observable, Subject } from 'rxjs';
import { ViewportRuler } from '@angular/cdk/overlay';
import { XManagerService } from 'x-framework-services';
import { XBaseActionModel } from '../classes/x-base-action.model';
import { X_FRAMEWORK_COMPONENTS_CONFIG } from '../tokens/x-injectable-tokens';
import { XFrameworkComponentsConfig } from '../config/x-framework-components.config';
import {
IXComponentActionBarContainer,
XActionBarActionFiredModel,
XActionBarActionModel,
XActionBarItem,
XComponentActionBarContainer,
} from '../x-action-bar/x-action-bar.typings';
import { XPopoverPresentOptions } from '../dialogs/x-popover/x-popover.typings';
import {
XBaseContainer,
XBaseContainerComponent,
} from '../classes/i-x-base.container';
import { XFrameworkComponentsConfig } from '../config/x-framework-components.config';
//
//#region Chart ...
@@ -3300,8 +3299,7 @@ export interface IXChartContainer extends TXChartContainer {
autoUpdate: XStandardType<boolean>;
options: XStandardType<XChartOptions>;
series: XStandardType<XChartSeriesType>;
//
zoomStep: XStandardType<number>;
type: XStandardType<XChartTypeIdentifier>;
//
@@ -3324,14 +3322,16 @@ export interface IXChartContainer extends TXChartContainer {
})
export class XChartContainer
extends XBaseContainer
implements Readonly<IXChartContainer>
{
implements Readonly<IXChartContainer> {
//
readonly actionProvider = new Subject<XChartActionModel>();
readonly cssClass: XStandardType<XOneOrManyType<string>>;
//
readonly options: XStandardType<XChartOptions>;
readonly zoomStep: XStandardType<number> = 0.125;
readonly series: XStandardType<XChartSeriesType>;
readonly autoUpdate: XStandardType<boolean> = true;
readonly cssClass: XStandardType<XOneOrManyType<string>>;
readonly actionProvider = new Subject<XChartActionModel>();
readonly type: XStandardType<XChartTypeIdentifier> = XChartType.Line;
//
@@ -3403,8 +3403,7 @@ export class XChartContainer
@Component({ template: `` })
export abstract class XChartContainerComponent
extends XBaseContainerComponent
implements IXChartContainer
{
implements IXChartContainer {
//
//#region Props ...
@Input()
@@ -3427,6 +3426,9 @@ export abstract class XChartContainerComponent
@Input()
series: XStandardType<XChartSeriesType> = this.propertyProvider.series;
@Input()
zoomStep: XStandardType<number> = this.propertyProvider.zoomStep;
@Input()
autoUpdate: XStandardType<boolean> = this.propertyProvider.autoUpdate;