@acorex/modules 19.3.1 → 19.3.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/common/lib/common.module.d.ts +2 -1
- package/dashboard-management/lib/entities/dashboard/dashboard.types.d.ts +2 -2
- package/dashboard-management/lib/features/home-dashboard/dashboard-home/home-dashboard.d.ts +7 -7
- package/dashboard-management/lib/features/home-dashboard/dashboard-home/home-dashboard.store.d.ts +6 -6
- package/dashboard-management/lib/features/home-dashboard/dashboard-home/home-dashboard.type.d.ts +3 -3
- package/dashboard-management/lib/features/home-dashboard/dashboard-popups/add-dashboard-popup.d.ts +3 -3
- package/dashboard-management/lib/features/home-dashboard/dashboard-popups/configuration-popup.d.ts +3 -3
- package/dashboard-management/lib/features/home-dashboard/dashboard-popups/dashboard-popup.service.d.ts +5 -5
- package/dashboard-management/lib/features/home-dashboard/widget-wrapper/dashboard-widget-wrapper.d.ts +4 -3
- package/dashboard-management/lib/features/shared/widgets/bar-chart/bar-chart-widget.component.d.ts +9 -64
- package/dashboard-management/lib/features/shared/widgets/clock-calendar/clock-calendar-widget.component.d.ts +0 -1
- package/dashboard-management/lib/features/shared/widgets/donut-chart/donut-chart-widget.component.d.ts +9 -50
- package/dashboard-management/lib/features/shared/widgets/gauge-chart/gauge-chart-widget.component.d.ts +8 -67
- package/dashboard-management/lib/features/shared/widgets/gauge-chart/index.d.ts +0 -1
- package/dashboard-management/lib/features/shared/widgets/index.d.ts +0 -2
- package/dashboard-management/lib/features/shared/widgets/line-chart/index.d.ts +0 -1
- package/dashboard-management/lib/features/shared/widgets/line-chart/line-chart-widget.component.d.ts +9 -68
- package/fesm2022/{acorex-modules-auth-acorex-modules-auth-B1HTJdsE.mjs → acorex-modules-auth-acorex-modules-auth-DJZcD1j3.mjs} +23 -83
- package/fesm2022/acorex-modules-auth-acorex-modules-auth-DJZcD1j3.mjs.map +1 -0
- package/fesm2022/acorex-modules-auth-app-chooser.component-DlYxDGQr.mjs +65 -0
- package/fesm2022/acorex-modules-auth-app-chooser.component-DlYxDGQr.mjs.map +1 -0
- package/fesm2022/{acorex-modules-auth-login.module-TtdNj0aL.mjs → acorex-modules-auth-login.module-D-XgzifC.mjs} +4 -4
- package/fesm2022/{acorex-modules-auth-login.module-TtdNj0aL.mjs.map → acorex-modules-auth-login.module-D-XgzifC.mjs.map} +1 -1
- package/fesm2022/{acorex-modules-auth-master.layout-CtVrY1hn.mjs → acorex-modules-auth-master.layout-ZaCb3CED.mjs} +2 -2
- package/fesm2022/{acorex-modules-auth-master.layout-CtVrY1hn.mjs.map → acorex-modules-auth-master.layout-ZaCb3CED.mjs.map} +1 -1
- package/fesm2022/{acorex-modules-auth-password.component-Dmj9zZSI.mjs → acorex-modules-auth-password.component-C-xRIhrM.mjs} +2 -2
- package/fesm2022/{acorex-modules-auth-password.component-Dmj9zZSI.mjs.map → acorex-modules-auth-password.component-C-xRIhrM.mjs.map} +1 -1
- package/fesm2022/{acorex-modules-auth-password.component-BXm2NAaN.mjs → acorex-modules-auth-password.component-CLTZoufP.mjs} +2 -2
- package/fesm2022/{acorex-modules-auth-password.component-BXm2NAaN.mjs.map → acorex-modules-auth-password.component-CLTZoufP.mjs.map} +1 -1
- package/fesm2022/{acorex-modules-auth-routes-DkgsKi3a.mjs → acorex-modules-auth-routes-4T5jq7su.mjs} +2 -2
- package/fesm2022/{acorex-modules-auth-routes-DkgsKi3a.mjs.map → acorex-modules-auth-routes-4T5jq7su.mjs.map} +1 -1
- package/fesm2022/acorex-modules-auth-tenant-chooser.component-Ow7QtAWc.mjs +98 -0
- package/fesm2022/acorex-modules-auth-tenant-chooser.component-Ow7QtAWc.mjs.map +1 -0
- package/fesm2022/{acorex-modules-auth-two-factor.module-DDOSqjYs.mjs → acorex-modules-auth-two-factor.module-D72KIpvA.mjs} +2 -2
- package/fesm2022/{acorex-modules-auth-two-factor.module-DDOSqjYs.mjs.map → acorex-modules-auth-two-factor.module-D72KIpvA.mjs.map} +1 -1
- package/fesm2022/{acorex-modules-auth-user-sessions.component-B3i44VC5.mjs → acorex-modules-auth-user-sessions.component-Btnu_Oeq.mjs} +2 -2
- package/fesm2022/{acorex-modules-auth-user-sessions.component-B3i44VC5.mjs.map → acorex-modules-auth-user-sessions.component-Btnu_Oeq.mjs.map} +1 -1
- package/fesm2022/acorex-modules-auth.mjs +1 -1
- package/fesm2022/acorex-modules-common.mjs +3 -5
- package/fesm2022/acorex-modules-common.mjs.map +1 -1
- package/fesm2022/{acorex-modules-dashboard-management-acorex-modules-dashboard-management-CReOsVhq.mjs → acorex-modules-dashboard-management-acorex-modules-dashboard-management-VORBD1g-.mjs} +846 -2174
- package/fesm2022/acorex-modules-dashboard-management-acorex-modules-dashboard-management-VORBD1g-.mjs.map +1 -0
- package/fesm2022/{acorex-modules-dashboard-management-home-dashboard-CHXDeuSF.mjs → acorex-modules-dashboard-management-home-dashboard-DiPn_RhH.mjs} +49 -48
- package/fesm2022/acorex-modules-dashboard-management-home-dashboard-DiPn_RhH.mjs.map +1 -0
- package/fesm2022/acorex-modules-dashboard-management.mjs +1 -1
- package/fesm2022/{acorex-modules-issue-management-acorex-modules-issue-management-Q47ZZSSE.mjs → acorex-modules-issue-management-acorex-modules-issue-management-U5EJyG5e.mjs} +42 -42
- package/fesm2022/{acorex-modules-issue-management-acorex-modules-issue-management-Q47ZZSSE.mjs.map → acorex-modules-issue-management-acorex-modules-issue-management-U5EJyG5e.mjs.map} +1 -1
- package/fesm2022/{acorex-modules-issue-management-capture-screen.component-Dns1Wrkd.mjs → acorex-modules-issue-management-capture-screen.component-3ZAOJBfn.mjs} +2 -2
- package/fesm2022/{acorex-modules-issue-management-capture-screen.component-Dns1Wrkd.mjs.map → acorex-modules-issue-management-capture-screen.component-3ZAOJBfn.mjs.map} +1 -1
- package/fesm2022/acorex-modules-issue-management.mjs +1 -1
- package/fesm2022/acorex-modules-notification-management.mjs +621 -52
- package/fesm2022/acorex-modules-notification-management.mjs.map +1 -1
- package/fesm2022/{acorex-modules-platform-management-acorex-modules-platform-management-DIsYLKbA.mjs → acorex-modules-platform-management-acorex-modules-platform-management-5lToZD6T.mjs} +6 -6
- package/fesm2022/acorex-modules-platform-management-acorex-modules-platform-management-5lToZD6T.mjs.map +1 -0
- package/fesm2022/{acorex-modules-platform-management-list-version.component-D83yTFAm.mjs → acorex-modules-platform-management-list-version.component-BElZjmXr.mjs} +2 -2
- package/fesm2022/{acorex-modules-platform-management-list-version.component-D83yTFAm.mjs.map → acorex-modules-platform-management-list-version.component-BElZjmXr.mjs.map} +1 -1
- package/fesm2022/{acorex-modules-platform-management-settings.provider-DKkXCwrd.mjs → acorex-modules-platform-management-settings.provider-CemrvnbH.mjs} +2 -2
- package/fesm2022/{acorex-modules-platform-management-settings.provider-DKkXCwrd.mjs.map → acorex-modules-platform-management-settings.provider-CemrvnbH.mjs.map} +1 -1
- package/fesm2022/acorex-modules-platform-management.mjs +1 -1
- package/fesm2022/acorex-modules-project-management.mjs +218 -155
- package/fesm2022/acorex-modules-project-management.mjs.map +1 -1
- package/fesm2022/acorex-modules-security-management.mjs +472 -787
- package/fesm2022/acorex-modules-security-management.mjs.map +1 -1
- package/fesm2022/acorex-modules-training-management.mjs +5574 -0
- package/fesm2022/acorex-modules-training-management.mjs.map +1 -0
- package/notification-management/index.d.ts +1 -0
- package/notification-management/lib/entities/notification/notification.service.d.ts +6 -6
- package/notification-management/lib/features/components/admin-notification-panel/admin-notification-panel.component.d.ts +13 -7
- package/{dashboard-management/lib/features/shared/widgets/notification → notification-management/lib/features/dashboard/widgets/my-notification}/index.d.ts +0 -1
- package/{dashboard-management/lib/features/shared/widgets/notification → notification-management/lib/features/dashboard/widgets/my-notification}/notification-widget.component.d.ts +37 -9
- package/notification-management/lib/features/dashboard/widgets/my-notification/notification-widget.config.d.ts +5 -0
- package/notification-management/lib/features/shared/notification-connector.service.d.ts +57 -0
- package/notification-management/lib/notification-management.module.d.ts +2 -1
- package/notification-management/lib/notification-management.type.d.ts +3 -0
- package/package.json +5 -1
- package/security-management/lib/entities/index.d.ts +1 -2
- package/security-management/lib/entities/profile/index.d.ts +0 -1
- package/security-management/lib/entities/users/users.service.d.ts +2 -2
- package/security-management/lib/entities/users/users.types.d.ts +2 -2
- package/security-management/lib/user-avatar.provider.d.ts +5 -0
- package/training-management/README.md +3 -0
- package/training-management/index.d.ts +7 -0
- package/training-management/lib/const.d.ts +85 -0
- package/training-management/lib/entities/certificate/certificate.entity.d.ts +3 -0
- package/training-management/lib/entities/certificate/certificate.service.d.ts +10 -0
- package/training-management/lib/entities/certificate/certificate.types.d.ts +12 -0
- package/training-management/lib/entities/certificate/index.d.ts +3 -0
- package/training-management/lib/entities/course/course.entity.d.ts +3 -0
- package/training-management/lib/entities/course/course.service.d.ts +10 -0
- package/training-management/lib/entities/course/course.types.d.ts +8 -0
- package/training-management/lib/entities/course/index.d.ts +3 -0
- package/training-management/lib/entities/course-location/course-location.entity.d.ts +3 -0
- package/training-management/lib/entities/course-location/course-location.service.d.ts +10 -0
- package/training-management/lib/entities/course-location/course-location.types.d.ts +6 -0
- package/training-management/lib/entities/course-location/index.d.ts +3 -0
- package/training-management/lib/entities/course-period/course-period.entity.d.ts +3 -0
- package/training-management/lib/entities/course-period/course-period.service.d.ts +10 -0
- package/training-management/lib/entities/course-period/course-period.types.d.ts +6 -0
- package/training-management/lib/entities/course-period/index.d.ts +3 -0
- package/training-management/lib/entities/course-type/course-type.entity.d.ts +3 -0
- package/training-management/lib/entities/course-type/course-type.service.d.ts +10 -0
- package/training-management/lib/entities/course-type/course-type.types.d.ts +5 -0
- package/training-management/lib/entities/course-type/index.d.ts +3 -0
- package/training-management/lib/entities/facilitator-type/facilitator-type.entity.d.ts +3 -0
- package/training-management/lib/entities/facilitator-type/facilitator-type.service.d.ts +10 -0
- package/training-management/lib/entities/facilitator-type/facilitator-type.types.d.ts +6 -0
- package/training-management/lib/entities/facilitator-type/index.d.ts +3 -0
- package/training-management/lib/entities/index.d.ts +12 -0
- package/training-management/lib/entities/location/index.d.ts +3 -0
- package/training-management/lib/entities/location/location.entity.d.ts +3 -0
- package/training-management/lib/entities/location/location.service.d.ts +10 -0
- package/training-management/lib/entities/location/location.types.d.ts +7 -0
- package/training-management/lib/entities/period/index.d.ts +3 -0
- package/training-management/lib/entities/period/period.entity.d.ts +3 -0
- package/training-management/lib/entities/period/period.service.d.ts +10 -0
- package/training-management/lib/entities/period/period.types.d.ts +6 -0
- package/training-management/lib/entities/training/index.d.ts +3 -0
- package/training-management/lib/entities/training/training.entity.d.ts +3 -0
- package/training-management/lib/entities/training/training.service.d.ts +10 -0
- package/training-management/lib/entities/training/training.types.d.ts +13 -0
- package/training-management/lib/entities/training-facilitator/index.d.ts +3 -0
- package/training-management/lib/entities/training-facilitator/training-facilitator.entity.d.ts +3 -0
- package/training-management/lib/entities/training-facilitator/training-facilitator.service.d.ts +10 -0
- package/training-management/lib/entities/training-facilitator/training-facilitator.types.d.ts +7 -0
- package/training-management/lib/entities/training-participant/index.d.ts +3 -0
- package/training-management/lib/entities/training-participant/training-participant.entity.d.ts +3 -0
- package/training-management/lib/entities/training-participant/training-participant.service.d.ts +10 -0
- package/training-management/lib/entities/training-participant/training-participant.types.d.ts +7 -0
- package/training-management/lib/entities/training-type/index.d.ts +3 -0
- package/training-management/lib/entities/training-type/training-type.entity.d.ts +3 -0
- package/training-management/lib/entities/training-type/training-type.service.d.ts +10 -0
- package/training-management/lib/entities/training-type/training-type.types.d.ts +7 -0
- package/training-management/lib/entity.provider.d.ts +10 -0
- package/training-management/lib/menu.provider.d.ts +5 -0
- package/training-management/lib/permission-definition.provider.d.ts +4 -0
- package/training-management/lib/search-command.provider.d.ts +4 -0
- package/training-management/lib/setting.provider.d.ts +4 -0
- package/training-management/lib/training-management.module.d.ts +6 -0
- package/auth/lib/pages/account/avatar/avatar.component.d.ts +0 -20
- package/dashboard-management/lib/features/shared/widgets/bar-chart/bar-chart.type.d.ts +0 -34
- package/dashboard-management/lib/features/shared/widgets/donut-chart/donut-chart.type.d.ts +0 -67
- package/dashboard-management/lib/features/shared/widgets/gauge-chart/gauge-chart.type.d.ts +0 -29
- package/dashboard-management/lib/features/shared/widgets/line-chart/line-chart.type.d.ts +0 -41
- package/dashboard-management/lib/features/shared/widgets/notification/notification-widget.config.d.ts +0 -10
- package/dashboard-management/lib/features/shared/widgets/notification/notification.type.d.ts +0 -47
- package/dashboard-management/lib/features/shared/widgets/shared/chart-base.component.d.ts +0 -44
- package/dashboard-management/lib/features/shared/widgets/shared/chart-base.type.d.ts +0 -37
- package/dashboard-management/lib/features/shared/widgets/shared/components/chart-tooltip/chart-tooltip.component.d.ts +0 -28
- package/dashboard-management/lib/features/shared/widgets/shared/components/chart-tooltip/index.d.ts +0 -1
- package/dashboard-management/lib/features/shared/widgets/shared/index.d.ts +0 -3
- package/fesm2022/acorex-modules-auth-acorex-modules-auth-B1HTJdsE.mjs.map +0 -1
- package/fesm2022/acorex-modules-auth-app-chooser.component-Ct-vco0y.mjs +0 -64
- package/fesm2022/acorex-modules-auth-app-chooser.component-Ct-vco0y.mjs.map +0 -1
- package/fesm2022/acorex-modules-auth-tenant-chooser.component-D9C6LCjn.mjs +0 -97
- package/fesm2022/acorex-modules-auth-tenant-chooser.component-D9C6LCjn.mjs.map +0 -1
- package/fesm2022/acorex-modules-dashboard-management-acorex-modules-dashboard-management-CReOsVhq.mjs.map +0 -1
- package/fesm2022/acorex-modules-dashboard-management-home-dashboard-CHXDeuSF.mjs.map +0 -1
- package/fesm2022/acorex-modules-platform-management-acorex-modules-platform-management-DIsYLKbA.mjs.map +0 -1
- package/security-management/lib/entities/profile/profile.service.d.ts +0 -13
@@ -1,47 +1,48 @@
|
|
1
|
+
import { AXPSessionService, AXPAuthGuard } from '@acorex/platform/auth';
|
1
2
|
import { createAllQueryView, AXPEntityCommandScope, AXPEntityQueryType, AXP_HOME_PAGES, AXP_MENU_PROVIDER, AXP_HOME_PAGE_DEFAULT_KEY } from '@acorex/platform/common';
|
3
|
+
import * as i3$1 from '@acorex/platform/layout/builder';
|
4
|
+
import { AXPWidgetsCatalog, AXPValueWidgetComponent, cloneProperty, AXPWidgetGroupEnum, AXPLayoutWidgetComponent, AXPLayoutBuilderModule } from '@acorex/platform/layout/builder';
|
2
5
|
import { AXMEntityCrudServiceImpl, AXP_ENTITY_CONFIG_TOKEN, AXP_ENTITY_DEFINITION_LOADER } from '@acorex/platform/layout/entity';
|
6
|
+
import { AXP_APPEARANCE_PROPERTY_GROUP, AXP_STYLING_PROPERTY_GROUP, AXP_NAME_PROPERTY, AXP_DATA_PATH_PROPERTY, AXP_BEHAVIOR_PROPERTY_GROUP, AXP_BG_COLOR_PROPERTY, plainTextDefaultProperty, AXP_DATA_PROPERTY_GROUP, AXP_COLOR_PROPERTY, AXPWidgetsModule } from '@acorex/platform/widgets';
|
3
7
|
import * as i0 from '@angular/core';
|
4
|
-
import { inject, Injector,
|
5
|
-
import {
|
6
|
-
import
|
7
|
-
import { AXP_COLOR_PROPERTY, AXP_STYLING_PROPERTY_GROUP, AXP_APPEARANCE_PROPERTY_GROUP, AXP_BEHAVIOR_PROPERTY_GROUP, AXP_DATA_PATH_PROPERTY, AXP_BG_COLOR_PROPERTY, plainTextDefaultProperty, AXP_DATA_PROPERTY_GROUP, AXPWidgetsModule } from '@acorex/platform/widgets';
|
8
|
-
import * as i3 from '@acorex/platform/layout/builder';
|
9
|
-
import { AXPWidgetsCatalog, AXPLayoutWidgetComponent, AXPWidgetGroupEnum, AXPValueWidgetComponent, cloneProperty, AXPLayoutBuilderModule } from '@acorex/platform/layout/builder';
|
10
|
-
import { AXPopupService } from '@acorex/components/popup';
|
11
|
-
import * as i2 from '@acorex/core/translation';
|
12
|
-
import { AXTranslationModule } from '@acorex/core/translation';
|
13
|
-
import { AXPDataGenerator } from '@acorex/platform/core';
|
14
|
-
import { AXP_GLOBAL_SEARCH_CONFIG_TOKEN } from '@acorex/platform/layout/search';
|
15
|
-
import { AXPWorkflowService } from '@acorex/platform/workflow';
|
16
|
-
import * as i1 from '@angular/common';
|
17
|
-
import { CommonModule, DatePipe } from '@angular/common';
|
18
|
-
import * as i2$3 from '@acorex/components/decorators';
|
8
|
+
import { Injectable, inject, Injector, computed, ChangeDetectionStrategy, Component, ChangeDetectorRef, signal, viewChild, ElementRef, HostListener, output, InjectionToken, effect, HostBinding, NgModule } from '@angular/core';
|
9
|
+
import { AXBarChartComponent } from '@acorex/charts/bar-chart';
|
10
|
+
import * as i2$2 from '@acorex/components/decorators';
|
19
11
|
import { AXDecoratorModule } from '@acorex/components/decorators';
|
20
12
|
import { AXTagModule } from '@acorex/components/tag';
|
21
13
|
import { AXDateTimeModule } from '@acorex/core/date-time';
|
22
|
-
import * as i2
|
14
|
+
import * as i2 from '@acorex/core/format';
|
23
15
|
import { AXFormatModule } from '@acorex/core/format';
|
24
|
-
import * as
|
25
|
-
import {
|
26
|
-
import
|
27
|
-
import {
|
28
|
-
import {
|
29
|
-
import
|
30
|
-
import { AXImageModule } from '@acorex/components/image';
|
31
|
-
import * as i2$2 from '@acorex/components/tabs';
|
32
|
-
import { AXTabsModule } from '@acorex/components/tabs';
|
16
|
+
import * as i1 from '@angular/common';
|
17
|
+
import { CommonModule, DatePipe } from '@angular/common';
|
18
|
+
import { interval, map, Observable, catchError, throwError, switchMap, firstValueFrom } from 'rxjs';
|
19
|
+
import { AXDonutChartComponent } from '@acorex/charts/donut-chart';
|
20
|
+
import { AXGaugeChartComponent } from '@acorex/charts/gauge-chart';
|
21
|
+
import { AXLineChartComponent } from '@acorex/charts/line-chart';
|
33
22
|
import { AXColorBoxModule } from '@acorex/components/color-box';
|
34
23
|
import { AXGridLayoutWidgetComponent } from '@acorex/components/grid-layout-builder';
|
35
24
|
import { AXPopoverModule } from '@acorex/components/popover';
|
36
25
|
import { AXToolBarModule } from '@acorex/components/toolbar';
|
37
26
|
import * as i1$1 from '@acorex/components/wysiwyg';
|
38
27
|
import { AXWysiwygModule } from '@acorex/components/wysiwyg';
|
39
|
-
import * as i2$
|
28
|
+
import * as i2$1 from '@angular/forms';
|
40
29
|
import { FormsModule } from '@angular/forms';
|
41
|
-
import
|
30
|
+
import { AXAvatarModule } from '@acorex/components/avatar';
|
31
|
+
import * as i3 from '@acorex/components/badge';
|
32
|
+
import { AXBadgeModule } from '@acorex/components/badge';
|
33
|
+
import { AXButtonModule } from '@acorex/components/button';
|
34
|
+
import * as i4 from '@acorex/components/check-box';
|
42
35
|
import { AXCheckBoxModule } from '@acorex/components/check-box';
|
36
|
+
import { AXImageModule } from '@acorex/components/image';
|
43
37
|
import { AXLabelModule } from '@acorex/components/label';
|
38
|
+
import { AXTabsModule } from '@acorex/components/tabs';
|
39
|
+
import * as i5 from '@acorex/core/translation';
|
40
|
+
import { AXTranslationModule } from '@acorex/core/translation';
|
44
41
|
import { HttpClient, HttpClientModule } from '@angular/common/http';
|
42
|
+
import { AXPopupService } from '@acorex/components/popup';
|
43
|
+
import { AXPDataGenerator } from '@acorex/platform/core';
|
44
|
+
import { AXP_GLOBAL_SEARCH_CONFIG_TOKEN } from '@acorex/platform/layout/search';
|
45
|
+
import { AXPWorkflowService } from '@acorex/platform/workflow';
|
45
46
|
|
46
47
|
const config = {
|
47
48
|
i18n: 'common',
|
@@ -64,48 +65,6 @@ const RootConfig = {
|
|
64
65
|
},
|
65
66
|
};
|
66
67
|
|
67
|
-
class AXMEntityProvider {
|
68
|
-
constructor() {
|
69
|
-
this.injector = inject(Injector);
|
70
|
-
}
|
71
|
-
preload() {
|
72
|
-
const module = RootConfig.module.name;
|
73
|
-
return Array.from(Object.values(RootConfig.entities)).map((entity) => ({
|
74
|
-
module: module,
|
75
|
-
entity: entity.name,
|
76
|
-
}));
|
77
|
-
}
|
78
|
-
async get(moduleName, entityName) {
|
79
|
-
if (moduleName == RootConfig.module.name) {
|
80
|
-
switch (entityName) {
|
81
|
-
case RootConfig.entities.dashboard.name:
|
82
|
-
return (await Promise.resolve().then(function () { return dashboard_entity; })).dashboardFactory(this.injector);
|
83
|
-
}
|
84
|
-
}
|
85
|
-
return null;
|
86
|
-
}
|
87
|
-
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.0.3", ngImport: i0, type: AXMEntityProvider, deps: [], target: i0.ɵɵFactoryTarget.Injectable }); }
|
88
|
-
static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "19.0.3", ngImport: i0, type: AXMEntityProvider }); }
|
89
|
-
}
|
90
|
-
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.0.3", ngImport: i0, type: AXMEntityProvider, decorators: [{
|
91
|
-
type: Injectable
|
92
|
-
}] });
|
93
|
-
|
94
|
-
class AXMMenuProvider {
|
95
|
-
constructor() {
|
96
|
-
this.sessionService = inject(AXPSessionService);
|
97
|
-
}
|
98
|
-
async provide(context) {
|
99
|
-
const scope = RootConfig.config.i18n;
|
100
|
-
const module = RootConfig.module;
|
101
|
-
const appName = this.sessionService.application?.name;
|
102
|
-
const isAuthorized = await firstValueFrom(this.sessionService.isAuthorized$);
|
103
|
-
if (!isAuthorized) {
|
104
|
-
return;
|
105
|
-
}
|
106
|
-
}
|
107
|
-
}
|
108
|
-
|
109
68
|
class AXMDashboardService extends AXMEntityCrudServiceImpl {
|
110
69
|
}
|
111
70
|
class AXMDashboardServiceImpl extends AXMDashboardService {
|
@@ -439,134 +398,57 @@ var dashboard_entity = /*#__PURE__*/Object.freeze({
|
|
439
398
|
dashboardFactory: dashboardFactory
|
440
399
|
});
|
441
400
|
|
442
|
-
class
|
401
|
+
class AXMEntityProvider {
|
443
402
|
constructor() {
|
444
|
-
|
445
|
-
this.popupService = inject(AXPopupService);
|
446
|
-
this.workflow = inject(AXPWorkflowService);
|
447
|
-
this.searchConfig = inject(AXP_GLOBAL_SEARCH_CONFIG_TOKEN);
|
448
|
-
this.item = computed(() => this.options()['item']);
|
449
|
-
this.color = computed(() => this.options()['color']);
|
450
|
-
}
|
451
|
-
ngOnInit() {
|
452
|
-
super.ngOnInit();
|
453
|
-
if (!this.color()) {
|
454
|
-
this.setOptions({
|
455
|
-
color: AXPDataGenerator.color()
|
456
|
-
});
|
457
|
-
}
|
403
|
+
this.injector = inject(Injector);
|
458
404
|
}
|
459
|
-
|
460
|
-
|
461
|
-
|
462
|
-
|
405
|
+
preload() {
|
406
|
+
const module = RootConfig.module.name;
|
407
|
+
return Array.from(Object.values(RootConfig.entities)).map((entity) => ({
|
408
|
+
module: module,
|
409
|
+
entity: entity.name,
|
410
|
+
}));
|
463
411
|
}
|
464
|
-
async
|
465
|
-
|
466
|
-
|
467
|
-
|
468
|
-
|
469
|
-
closeOnBackdropClick: true,
|
470
|
-
header: false,
|
471
|
-
});
|
472
|
-
if (popup.data) {
|
473
|
-
const result = popup.data;
|
474
|
-
if (result && result.command) {
|
475
|
-
this.setOptions({
|
476
|
-
item: {
|
477
|
-
name: result.name,
|
478
|
-
title: result.title,
|
479
|
-
description: result.description,
|
480
|
-
icon: result.icon,
|
481
|
-
command: result.command
|
482
|
-
}
|
483
|
-
});
|
412
|
+
async get(moduleName, entityName) {
|
413
|
+
if (moduleName == RootConfig.module.name) {
|
414
|
+
switch (entityName) {
|
415
|
+
case RootConfig.entities.dashboard.name:
|
416
|
+
return (await Promise.resolve().then(function () { return dashboard_entity; })).dashboardFactory(this.injector);
|
484
417
|
}
|
485
418
|
}
|
419
|
+
return null;
|
486
420
|
}
|
487
|
-
|
488
|
-
|
489
|
-
|
490
|
-
|
491
|
-
|
492
|
-
|
493
|
-
|
494
|
-
|
495
|
-
|
496
|
-
|
497
|
-
|
498
|
-
|
499
|
-
|
500
|
-
|
501
|
-
|
502
|
-
|
503
|
-
cls[`ax-text-white`] = true;
|
504
|
-
return cls;
|
421
|
+
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.0.3", ngImport: i0, type: AXMEntityProvider, deps: [], target: i0.ɵɵFactoryTarget.Injectable }); }
|
422
|
+
static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "19.0.3", ngImport: i0, type: AXMEntityProvider }); }
|
423
|
+
}
|
424
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.0.3", ngImport: i0, type: AXMEntityProvider, decorators: [{
|
425
|
+
type: Injectable
|
426
|
+
}] });
|
427
|
+
|
428
|
+
/**
|
429
|
+
* Bar Chart Widget Component
|
430
|
+
* Renders data as vertical bars with interactive hover effects and animations
|
431
|
+
*/
|
432
|
+
class AXPBarChartWidgetViewComponent extends AXPValueWidgetComponent {
|
433
|
+
constructor() {
|
434
|
+
super(...arguments);
|
435
|
+
this.barChartData = computed(() => this.getValue());
|
436
|
+
this.barChartOptions = computed(() => this.options());
|
505
437
|
}
|
506
|
-
|
507
|
-
|
508
|
-
@if(item()) {
|
509
|
-
<div
|
510
|
-
class="ax-group ax-flex ax-flex-col ax-items-center ax-justify-center ax-p-3 ax-w-full ax-h-full ax-relative ax-overflow-hidden "
|
511
|
-
(click)="executeCommand()">
|
512
|
-
<div class="ax-absolute ax-inset-0 ax-bg-black/0 hover:ax-bg-black/10 ax-transition-opacity"></div>
|
513
|
-
<i [class]="item().icon + ' ax-text-3xl'"></i>
|
514
|
-
<span class="ax-text-xl ax-font-semibold">{{ item().title | translate | async }}</span>
|
515
|
-
@if(item().description) {
|
516
|
-
<span class="ax-text-sm ax-opacity-90 ax-text-center ax-px-2">{{ item().description! | translate | async }}</span>
|
517
|
-
}
|
518
|
-
</div>
|
519
|
-
} @else {
|
520
|
-
<div
|
521
|
-
(click)="setCommand()"
|
522
|
-
class="ax-group ax-flex ax-flex-col ax-items-center ax-justify-center ax-p-3 ax-w-full ax-h-full ax-relative ax-overflow-hidden">
|
523
|
-
<div class="ax-absolute ax-inset-0 ax-bg-black/0 hover:ax-bg-black/5 ax-transition-opacity"></div>
|
524
|
-
<i class="fa-light fa-plus ax-text-3xl"></i>
|
525
|
-
<span class="ax-text-xl ax-font-semibold">Add Shortcut</span>
|
526
|
-
</div>
|
438
|
+
handleBarClick(event) {
|
439
|
+
//console.log(event);
|
527
440
|
}
|
528
|
-
|
441
|
+
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.0.3", ngImport: i0, type: AXPBarChartWidgetViewComponent, deps: null, target: i0.ɵɵFactoryTarget.Component }); }
|
442
|
+
static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "19.0.3", type: AXPBarChartWidgetViewComponent, isStandalone: true, selector: "ng-component", usesInheritance: true, ngImport: i0, template: "<ax-bar-chart [data]=\"barChartData()\" [options]=\"barChartOptions()\" (barClick)=\"handleBarClick($event)\"></ax-bar-chart>\n", styles: [":host{display:block;width:100%;height:100%}\n"], dependencies: [{ kind: "component", type: AXBarChartComponent, selector: "ax-bar-chart", inputs: ["data", "options"], outputs: ["barClick"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
|
529
443
|
}
|
530
|
-
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.0.3", ngImport: i0, type:
|
444
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.0.3", ngImport: i0, type: AXPBarChartWidgetViewComponent, decorators: [{
|
531
445
|
type: Component,
|
532
|
-
args: [{
|
533
|
-
|
534
|
-
@if(item()) {
|
535
|
-
<div
|
536
|
-
class="ax-group ax-flex ax-flex-col ax-items-center ax-justify-center ax-p-3 ax-w-full ax-h-full ax-relative ax-overflow-hidden "
|
537
|
-
(click)="executeCommand()">
|
538
|
-
<div class="ax-absolute ax-inset-0 ax-bg-black/0 hover:ax-bg-black/10 ax-transition-opacity"></div>
|
539
|
-
<i [class]="item().icon + ' ax-text-3xl'"></i>
|
540
|
-
<span class="ax-text-xl ax-font-semibold">{{ item().title | translate | async }}</span>
|
541
|
-
@if(item().description) {
|
542
|
-
<span class="ax-text-sm ax-opacity-90 ax-text-center ax-px-2">{{ item().description! | translate | async }}</span>
|
543
|
-
}
|
544
|
-
</div>
|
545
|
-
} @else {
|
546
|
-
<div
|
547
|
-
(click)="setCommand()"
|
548
|
-
class="ax-group ax-flex ax-flex-col ax-items-center ax-justify-center ax-p-3 ax-w-full ax-h-full ax-relative ax-overflow-hidden">
|
549
|
-
<div class="ax-absolute ax-inset-0 ax-bg-black/0 hover:ax-bg-black/5 ax-transition-opacity"></div>
|
550
|
-
<i class="fa-light fa-plus ax-text-3xl"></i>
|
551
|
-
<span class="ax-text-xl ax-font-semibold">Add Shortcut</span>
|
552
|
-
</div>
|
553
|
-
}
|
554
|
-
`,
|
555
|
-
standalone: true,
|
556
|
-
changeDetection: ChangeDetectionStrategy.OnPush,
|
557
|
-
imports: [CommonModule, AXTranslationModule]
|
558
|
-
}]
|
559
|
-
}], propDecorators: { __style: [{
|
560
|
-
type: HostBinding,
|
561
|
-
args: ['style']
|
562
|
-
}], __class: [{
|
563
|
-
type: HostBinding,
|
564
|
-
args: ['class']
|
565
|
-
}] } });
|
446
|
+
args: [{ imports: [AXBarChartComponent], changeDetection: ChangeDetectionStrategy.OnPush, template: "<ax-bar-chart [data]=\"barChartData()\" [options]=\"barChartOptions()\" (barClick)=\"handleBarClick($event)\"></ax-bar-chart>\n", styles: [":host{display:block;width:100%;height:100%}\n"] }]
|
447
|
+
}] });
|
566
448
|
|
567
|
-
var
|
449
|
+
var barChartWidget_component = /*#__PURE__*/Object.freeze({
|
568
450
|
__proto__: null,
|
569
|
-
|
451
|
+
AXPBarChartWidgetViewComponent: AXPBarChartWidgetViewComponent
|
570
452
|
});
|
571
453
|
|
572
454
|
const AXP_WIDGETS_CHART_CATEGORY = {
|
@@ -580,537 +462,75 @@ const AXP_WIDGETS_UTILITY_CATEGORY = {
|
|
580
462
|
title: 'Utilities',
|
581
463
|
};
|
582
464
|
|
583
|
-
const
|
584
|
-
name:
|
585
|
-
title:
|
586
|
-
|
587
|
-
type: 'view',
|
588
|
-
categories: [AXP_WIDGETS_UTILITY_CATEGORY],
|
465
|
+
const AXPBarChartWidget = {
|
466
|
+
name: 'bar-chart',
|
467
|
+
title: 'Bar Chart Widget',
|
468
|
+
categories: [AXP_WIDGETS_CHART_CATEGORY],
|
589
469
|
groups: [AXPWidgetGroupEnum.DashboardWidget],
|
590
|
-
|
470
|
+
type: 'dashboard',
|
471
|
+
icon: 'fa-light fa-chart-bar',
|
591
472
|
properties: [
|
592
|
-
|
593
|
-
|
594
|
-
|
595
|
-
|
596
|
-
|
597
|
-
|
598
|
-
|
599
|
-
|
600
|
-
|
601
|
-
|
602
|
-
|
603
|
-
|
604
|
-
|
605
|
-
|
606
|
-
|
473
|
+
cloneProperty(AXP_NAME_PROPERTY, { visible: false }),
|
474
|
+
cloneProperty(AXP_DATA_PATH_PROPERTY, { visible: false }),
|
475
|
+
// ====== Chart Title ======
|
476
|
+
{
|
477
|
+
name: 'title',
|
478
|
+
title: 'Chart Title',
|
479
|
+
group: AXP_APPEARANCE_PROPERTY_GROUP,
|
480
|
+
schema: {
|
481
|
+
defaultValue: '',
|
482
|
+
dataType: 'string',
|
483
|
+
interface: {
|
484
|
+
name: 'title',
|
485
|
+
path: 'options.title',
|
486
|
+
type: AXPWidgetsCatalog.text,
|
487
|
+
options: {
|
488
|
+
placeholder: 'Enter chart title',
|
489
|
+
},
|
490
|
+
},
|
491
|
+
},
|
492
|
+
visible: true,
|
607
493
|
},
|
608
|
-
}
|
609
|
-
};
|
610
|
-
|
611
|
-
/**
|
612
|
-
* Common base types and utilities for all chart components
|
613
|
-
*/
|
614
|
-
/**
|
615
|
-
* Color utility functions for charts
|
616
|
-
*/
|
617
|
-
const AXPChartColors = {
|
618
|
-
// Modern color palette suitable for data visualization
|
619
|
-
defaultColors: [
|
620
|
-
'#4361ee', // Blue
|
621
|
-
'#3a0ca3', // Purple
|
622
|
-
'#7209b7', // Violet
|
623
|
-
'#f72585', // Pink
|
624
|
-
'#4cc9f0', // Light Blue
|
625
|
-
'#4895ef', // Sky Blue
|
626
|
-
'#560bad', // Deep Purple
|
627
|
-
'#f15bb5', // Light Pink
|
628
|
-
'#00bbf9', // Cyan
|
629
|
-
'#00f5d4', // Teal
|
630
|
-
],
|
631
|
-
// Get a color from the palette by index with wraparound
|
632
|
-
getColor: (index, customPalette) => {
|
633
|
-
const palette = customPalette || AXPChartColors.defaultColors;
|
634
|
-
return palette[index % palette.length];
|
635
|
-
},
|
636
|
-
// Generate a continuous color palette from a base color
|
637
|
-
generatePalette: (baseColor, count) => {
|
638
|
-
// Simple implementation - in real usage you might want a more sophisticated algorithm
|
639
|
-
const colors = [];
|
640
|
-
for (let i = 0; i < count; i++) {
|
641
|
-
// This is simplistic - a real implementation would use HSL or other color manipulation
|
642
|
-
const opacity = 0.4 + (0.6 * i) / count;
|
643
|
-
colors.push(`${baseColor}${Math.floor(opacity * 255)
|
644
|
-
.toString(16)
|
645
|
-
.padStart(2, '0')}`);
|
646
|
-
}
|
647
|
-
return colors;
|
648
|
-
},
|
649
|
-
};
|
650
|
-
/**
|
651
|
-
* Shared utility for loading D3.js dynamically
|
652
|
-
*/
|
653
|
-
async function loadD3() {
|
654
|
-
try {
|
655
|
-
// Dynamic import of d3 without relying on d3 being imported at the top
|
656
|
-
return await import('d3');
|
657
|
-
}
|
658
|
-
catch (error) {
|
659
|
-
console.error('Failed to load D3.js:', error);
|
660
|
-
throw error;
|
661
|
-
}
|
662
|
-
}
|
663
|
-
|
664
|
-
/**
|
665
|
-
* Base component class for all chart components with common chart functionality
|
666
|
-
*/
|
667
|
-
class AXPChartBaseComponent extends AXPValueWidgetComponent {
|
668
|
-
// Constructor with protected change detector
|
669
|
-
constructor(cdr) {
|
670
|
-
super();
|
671
|
-
this.cdr = cdr;
|
672
|
-
// Get injector for running effects
|
673
|
-
this.injector = inject(Injector);
|
674
|
-
// Track component lifecycle
|
675
|
-
this.isInitialized = signal(false);
|
676
|
-
this.isRendered = signal(false);
|
677
|
-
// Internal chart data storage with fallback logic
|
678
|
-
this._internalData = signal(null);
|
679
|
-
// Accessor for chart data with fallback to getValue() or defaultValue
|
680
|
-
this.chartData = computed(() => {
|
681
|
-
if (this._internalData()) {
|
682
|
-
return this._internalData();
|
683
|
-
}
|
684
|
-
return this.getValue() || this.defaultValue;
|
685
|
-
});
|
686
|
-
// Options tracker for detecting changes
|
687
|
-
this._lastOptionsSnapshot = '';
|
688
|
-
// Store the effect cleanup function
|
689
|
-
this.effectRef = null;
|
690
|
-
}
|
691
|
-
ngOnInit() {
|
692
|
-
super.ngOnInit();
|
693
|
-
this.loadD3();
|
694
|
-
}
|
695
|
-
ngAfterViewInit() {
|
696
|
-
this.isRendered.set(true);
|
697
|
-
this.setupEffects();
|
698
|
-
}
|
699
|
-
ngOnDestroy() {
|
700
|
-
// Clean up effect if it exists
|
701
|
-
if (this.effectRef) {
|
702
|
-
this.effectRef.destroy();
|
703
|
-
}
|
704
|
-
this.cleanupChart();
|
705
|
-
}
|
706
|
-
/**
|
707
|
-
* Load D3.js library asynchronously
|
708
|
-
*/
|
709
|
-
async loadD3() {
|
710
|
-
try {
|
711
|
-
this.d3 = await loadD3();
|
712
|
-
this.isInitialized.set(true);
|
713
|
-
// Initialize chart data once D3 is loaded
|
714
|
-
const initialData = this.getValue() || this.defaultValue;
|
715
|
-
if (initialData) {
|
716
|
-
this._internalData.set(initialData);
|
717
|
-
}
|
718
|
-
// Create chart once D3 is loaded and if we're already rendered
|
719
|
-
if (this.isRendered()) {
|
720
|
-
this.createChart();
|
721
|
-
}
|
722
|
-
}
|
723
|
-
catch (error) {
|
724
|
-
console.error('Error loading D3.js:', error);
|
725
|
-
}
|
726
|
-
}
|
727
|
-
/**
|
728
|
-
* Set up reactive effects to track data and option changes
|
729
|
-
*/
|
730
|
-
setupEffects() {
|
731
|
-
// Run effect in injection context to avoid NG0203 error
|
732
|
-
this.effectRef = runInInjectionContext(this.injector, () => {
|
733
|
-
return effect(() => {
|
734
|
-
// Only update if D3 is loaded and component is rendered
|
735
|
-
if (!this.isInitialized() || !this.isRendered())
|
736
|
-
return;
|
737
|
-
// Track dependencies explicitly
|
738
|
-
const data = this.getValue();
|
739
|
-
const options = this.options();
|
740
|
-
// Store current options snapshot for comparison
|
741
|
-
const currentOptions = JSON.stringify(options);
|
742
|
-
const optionsChanged = currentOptions !== this._lastOptionsSnapshot;
|
743
|
-
this._lastOptionsSnapshot = currentOptions;
|
744
|
-
// Check if data changed
|
745
|
-
const dataChanged = data && JSON.stringify(data) !== JSON.stringify(this._internalData());
|
746
|
-
// Update internal data if it changed
|
747
|
-
if (dataChanged && data) {
|
748
|
-
this._internalData.set(data);
|
749
|
-
}
|
750
|
-
// Update chart if either data or options changed
|
751
|
-
if (dataChanged || optionsChanged) {
|
752
|
-
this.updateChart();
|
753
|
-
}
|
754
|
-
});
|
755
|
-
});
|
756
|
-
}
|
757
|
-
/**
|
758
|
-
* Get dimensions of the container element
|
759
|
-
*/
|
760
|
-
getContainerDimensions(containerElement) {
|
761
|
-
if (!containerElement?.nativeElement) {
|
762
|
-
return { width: 300, height: 300 }; // Default fallback
|
763
|
-
}
|
764
|
-
const { clientWidth, clientHeight } = containerElement.nativeElement;
|
765
|
-
return {
|
766
|
-
width: clientWidth || 300,
|
767
|
-
height: clientHeight || 300,
|
768
|
-
};
|
769
|
-
}
|
770
|
-
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.0.3", ngImport: i0, type: AXPChartBaseComponent, deps: [{ token: i0.ChangeDetectorRef }], target: i0.ɵɵFactoryTarget.Directive }); }
|
771
|
-
static { this.ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "19.0.3", type: AXPChartBaseComponent, isStandalone: true, usesInheritance: true, ngImport: i0 }); }
|
772
|
-
}
|
773
|
-
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.0.3", ngImport: i0, type: AXPChartBaseComponent, decorators: [{
|
774
|
-
type: Directive
|
775
|
-
}], ctorParameters: () => [{ type: i0.ChangeDetectorRef }] });
|
776
|
-
|
777
|
-
class AXPChartTooltipComponent {
|
778
|
-
constructor() {
|
779
|
-
this.data = input(null);
|
780
|
-
this.position = input({ x: 0, y: 0 });
|
781
|
-
this.visible = input(false);
|
782
|
-
/**
|
783
|
-
* Whether to show the tooltip's percentage badge
|
784
|
-
*/
|
785
|
-
this.showPercentage = input(true);
|
786
|
-
/**
|
787
|
-
* Optional custom styling for the tooltip
|
788
|
-
*/
|
789
|
-
this.style = input({});
|
790
|
-
}
|
791
|
-
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.0.3", ngImport: i0, type: AXPChartTooltipComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
|
792
|
-
static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "19.0.3", type: AXPChartTooltipComponent, isStandalone: true, selector: "ax-chart-tooltip", inputs: { data: { classPropertyName: "data", publicName: "data", isSignal: true, isRequired: false, transformFunction: null }, position: { classPropertyName: "position", publicName: "position", isSignal: true, isRequired: false, transformFunction: null }, visible: { classPropertyName: "visible", publicName: "visible", isSignal: true, isRequired: false, transformFunction: null }, showPercentage: { classPropertyName: "showPercentage", publicName: "showPercentage", isSignal: true, isRequired: false, transformFunction: null }, style: { classPropertyName: "style", publicName: "style", isSignal: true, isRequired: false, transformFunction: null } }, ngImport: i0, template: "@if (visible() && data()) {\n<div class=\"chart-tooltip\" [style.left.px]=\"position().x\" [style.top.px]=\"position().y\" [ngStyle]=\"style()\">\n <div class=\"chart-tooltip-title\">{{ data()!.title }}</div>\n <div class=\"chart-tooltip-content\">\n @if (data()!.color) {\n <div class=\"chart-tooltip-color\" [style.background-color]=\"data()!.color\"></div>\n }\n <div class=\"chart-tooltip-value\">{{ data()!.value }}</div>\n @if (showPercentage() && data()!.percentage) {\n <div class=\"chart-tooltip-percentage\">{{ data()!.percentage }}</div>\n }\n </div>\n</div>\n}\n", styles: [".chart-tooltip{position:absolute;pointer-events:none;background-color:rgba(33,33,33,.9);color:#fff;padding:.5rem .75rem;border-radius:.375rem;font-size:.8rem;z-index:10;box-shadow:0 4px 12px rgba(0,0,0,.15);-webkit-backdrop-filter:blur(4px);backdrop-filter:blur(4px);border:1px solid rgba(255,255,255,.1);transform:translate(10px,-50%);max-width:200px;font-family:var(--ax-font-family, system-ui, -apple-system, BlinkMacSystemFont, \"Segoe UI\", Roboto, sans-serif);transition:opacity .15s ease,transform .15s ease}.chart-tooltip-title{font-weight:600;padding-bottom:.5rem;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}.chart-tooltip-content{display:flex;justify-content:space-between;align-items:center;gap:.5rem}.chart-tooltip-color{width:10px;height:10px;border-radius:2px;flex-shrink:0;box-shadow:0 1px 2px rgba(0,0,0,.2)}.chart-tooltip-value{font-weight:500;flex-grow:1}.chart-tooltip-percentage{background-color:rgba(255,255,255,.2);padding:.125rem .375rem;border-radius:1rem;font-size:.7rem;font-weight:500;flex-shrink:0}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "directive", type: i1.NgStyle, selector: "[ngStyle]", inputs: ["ngStyle"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
|
793
|
-
}
|
794
|
-
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.0.3", ngImport: i0, type: AXPChartTooltipComponent, decorators: [{
|
795
|
-
type: Component,
|
796
|
-
args: [{ selector: 'ax-chart-tooltip', standalone: true, imports: [CommonModule], changeDetection: ChangeDetectionStrategy.OnPush, template: "@if (visible() && data()) {\n<div class=\"chart-tooltip\" [style.left.px]=\"position().x\" [style.top.px]=\"position().y\" [ngStyle]=\"style()\">\n <div class=\"chart-tooltip-title\">{{ data()!.title }}</div>\n <div class=\"chart-tooltip-content\">\n @if (data()!.color) {\n <div class=\"chart-tooltip-color\" [style.background-color]=\"data()!.color\"></div>\n }\n <div class=\"chart-tooltip-value\">{{ data()!.value }}</div>\n @if (showPercentage() && data()!.percentage) {\n <div class=\"chart-tooltip-percentage\">{{ data()!.percentage }}</div>\n }\n </div>\n</div>\n}\n", styles: [".chart-tooltip{position:absolute;pointer-events:none;background-color:rgba(33,33,33,.9);color:#fff;padding:.5rem .75rem;border-radius:.375rem;font-size:.8rem;z-index:10;box-shadow:0 4px 12px rgba(0,0,0,.15);-webkit-backdrop-filter:blur(4px);backdrop-filter:blur(4px);border:1px solid rgba(255,255,255,.1);transform:translate(10px,-50%);max-width:200px;font-family:var(--ax-font-family, system-ui, -apple-system, BlinkMacSystemFont, \"Segoe UI\", Roboto, sans-serif);transition:opacity .15s ease,transform .15s ease}.chart-tooltip-title{font-weight:600;padding-bottom:.5rem;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}.chart-tooltip-content{display:flex;justify-content:space-between;align-items:center;gap:.5rem}.chart-tooltip-color{width:10px;height:10px;border-radius:2px;flex-shrink:0;box-shadow:0 1px 2px rgba(0,0,0,.2)}.chart-tooltip-value{font-weight:500;flex-grow:1}.chart-tooltip-percentage{background-color:rgba(255,255,255,.2);padding:.125rem .375rem;border-radius:1rem;font-size:.7rem;font-weight:500;flex-shrink:0}\n"] }]
|
797
|
-
}] });
|
798
|
-
|
799
|
-
/**
|
800
|
-
* Bar Chart Widget Component
|
801
|
-
* Renders data as vertical bars with interactive hover effects and animations
|
802
|
-
*/
|
803
|
-
class AXPBarChartWidgetViewComponent extends AXPChartBaseComponent {
|
804
|
-
constructor() {
|
805
|
-
super(...arguments);
|
806
|
-
this.barClick = output();
|
807
|
-
// Chart container reference
|
808
|
-
this.chartContainerEl = viewChild.required('chartContainer');
|
809
|
-
this.margin = { top: 20, right: 20, bottom: 30, left: 40 };
|
810
|
-
// Tooltip state
|
811
|
-
this._tooltipVisible = signal(false);
|
812
|
-
this._tooltipPosition = signal({ x: 0, y: 0 });
|
813
|
-
this._tooltipData = signal({
|
814
|
-
title: '',
|
815
|
-
value: '0',
|
816
|
-
percentage: '0%',
|
817
|
-
color: '',
|
818
|
-
});
|
819
|
-
// Tooltip accessors
|
820
|
-
this.tooltipVisible = computed(() => this._tooltipVisible());
|
821
|
-
this.tooltipPosition = computed(() => this._tooltipPosition());
|
822
|
-
this.tooltipData = computed(() => this._tooltipData());
|
823
|
-
// Bar appearance options
|
824
|
-
this.barWidth = computed(() => this.options()['barWidth'] ?? 80);
|
825
|
-
this.cornerRadius = computed(() => this.options()['cornerRadius'] ?? 4);
|
826
|
-
}
|
827
|
-
// Chart lifecycle methods
|
828
|
-
/**
|
829
|
-
* Creates the bar chart SVG and renders all elements
|
830
|
-
*/
|
831
|
-
createChart() {
|
832
|
-
if (!this.d3 || !this.chartContainerEl()?.nativeElement)
|
833
|
-
return;
|
834
|
-
const containerElement = this.chartContainerEl().nativeElement;
|
835
|
-
const data = this.chartData() || [];
|
836
|
-
// Clear existing chart
|
837
|
-
this.d3.select(containerElement).selectAll('svg').remove();
|
838
|
-
// Early return if no data
|
839
|
-
if (!data.length) {
|
840
|
-
this.showNoDataMessage(containerElement);
|
841
|
-
return;
|
842
|
-
}
|
843
|
-
// Get options and setup dimensions
|
844
|
-
const options = this.options();
|
845
|
-
this.setupDimensions(containerElement, options);
|
846
|
-
// No need to create SVG here as it's now done in setupDimensions
|
847
|
-
// Create scales and axes
|
848
|
-
this.setupScales(data);
|
849
|
-
this.createAxes(options);
|
850
|
-
// Render the bars
|
851
|
-
this.renderBars(data);
|
852
|
-
}
|
853
|
-
updateChart() {
|
854
|
-
this.createChart();
|
855
|
-
}
|
856
|
-
cleanupChart() {
|
857
|
-
if (this.svg) {
|
858
|
-
this.d3.select(this.chartContainerEl()?.nativeElement).selectAll('svg').remove();
|
859
|
-
this.svg = null;
|
860
|
-
this.chart = null;
|
861
|
-
}
|
862
|
-
this._tooltipVisible.set(false);
|
863
|
-
}
|
864
|
-
// Private chart creation methods
|
865
|
-
/**
|
866
|
-
* Sets up chart dimensions and creates SVG with responsive attributes
|
867
|
-
*/
|
868
|
-
setupDimensions(containerElement, options) {
|
869
|
-
// Get container dimensions
|
870
|
-
const containerWidth = containerElement.clientWidth;
|
871
|
-
const containerHeight = containerElement.clientHeight;
|
872
|
-
// If options specify width and height, use those, otherwise default to container size
|
873
|
-
const minDim = Math.min(200, containerWidth, containerHeight); // Ensure reasonable minimum
|
874
|
-
if (options.width && options.height) {
|
875
|
-
// Explicit dimensions provided
|
876
|
-
this.width = options.width - this.margin.left - this.margin.right;
|
877
|
-
this.height = options.height - this.margin.top - this.margin.bottom;
|
878
|
-
}
|
879
|
-
else {
|
880
|
-
// Responsive dimensions
|
881
|
-
this.width = Math.max(containerWidth, minDim) - this.margin.left - this.margin.right;
|
882
|
-
this.height = Math.max(containerHeight, minDim) - this.margin.top - this.margin.bottom;
|
883
|
-
}
|
884
|
-
// Create responsive SVG that scales with its container
|
885
|
-
const svg = this.d3
|
886
|
-
.select(containerElement)
|
887
|
-
.append('svg')
|
888
|
-
.attr('width', '100%')
|
889
|
-
.attr('height', '100%')
|
890
|
-
.attr('viewBox', `0 0 ${this.width + this.margin.left + this.margin.right} ${this.height + this.margin.top + this.margin.bottom}`)
|
891
|
-
.attr('preserveAspectRatio', 'xMidYMid meet');
|
892
|
-
this.svg = svg;
|
893
|
-
// Create chart group with margins
|
894
|
-
this.chart = this.svg.append('g').attr('transform', `translate(${this.margin.left},${this.margin.top})`);
|
895
|
-
}
|
896
|
-
/**
|
897
|
-
* Creates x and y scales for the chart
|
898
|
-
*/
|
899
|
-
setupScales(data) {
|
900
|
-
// Get the bar width percentage (default 80%)
|
901
|
-
const barWidthPercent = this.barWidth() / 100;
|
902
|
-
// Calculate padding based on barWidth (inverse relationship)
|
903
|
-
const padding = Math.max(0.1, 1 - barWidthPercent);
|
904
|
-
// Create x scale (band scale for categorical data)
|
905
|
-
this.xScale = this.d3
|
906
|
-
.scaleBand()
|
907
|
-
.domain(data.map((d) => d.label))
|
908
|
-
.range([0, this.width])
|
909
|
-
.padding(padding);
|
910
|
-
// Create y scale (linear scale for values)
|
911
|
-
this.yScale = this.d3
|
912
|
-
.scaleLinear()
|
913
|
-
.domain([0, this.d3.max(data, (d) => d.value) || 0])
|
914
|
-
.nice()
|
915
|
-
.range([this.height, 0]);
|
916
|
-
}
|
917
|
-
/**
|
918
|
-
* Creates x and y axes with grid lines
|
919
|
-
*/
|
920
|
-
createAxes(options) {
|
921
|
-
// Only create axes if they are enabled in options
|
922
|
-
const showXAxis = options.showXAxis !== false;
|
923
|
-
const showYAxis = options.showYAxis !== false;
|
924
|
-
const showGrid = options.showGrid !== false;
|
925
|
-
if (showXAxis) {
|
926
|
-
// Create X axis
|
927
|
-
this.xAxis = this.chart
|
928
|
-
.append('g')
|
929
|
-
.attr('class', 'axp-bar-chart-axis-x')
|
930
|
-
.attr('transform', `translate(0,${this.height})`)
|
931
|
-
.call(this.d3.axisBottom(this.xScale));
|
932
|
-
}
|
933
|
-
if (showYAxis) {
|
934
|
-
// Create Y axis
|
935
|
-
this.yAxis = this.chart.append('g').attr('class', 'axp-bar-chart-axis-y').call(this.d3.axisLeft(this.yScale));
|
936
|
-
}
|
937
|
-
if (showGrid) {
|
938
|
-
// Add horizontal grid lines
|
939
|
-
this.chart
|
940
|
-
.append('g')
|
941
|
-
.attr('class', 'axp-bar-chart-grid')
|
942
|
-
.call(this.d3
|
943
|
-
.axisLeft(this.yScale)
|
944
|
-
.tickSize(-this.width)
|
945
|
-
.tickFormat(() => ''))
|
946
|
-
.selectAll('.tick')
|
947
|
-
.style('color', 'rgb(153 153 153 / 30%)'); // Add gray color to ticks
|
948
|
-
}
|
949
|
-
}
|
950
|
-
/**
|
951
|
-
* Renders the bars with animations
|
952
|
-
*/
|
953
|
-
renderBars(data) {
|
954
|
-
// Get corner radius from options
|
955
|
-
const radius = this.cornerRadius();
|
956
|
-
// Add bars with modern colors
|
957
|
-
const bars = this.chart
|
958
|
-
.selectAll('.axp-bar-chart-bar')
|
959
|
-
.data(data)
|
960
|
-
.enter()
|
961
|
-
.append('rect')
|
962
|
-
.attr('class', 'axp-bar-chart-bar')
|
963
|
-
.attr('x', (d) => this.xScale(d.label))
|
964
|
-
.attr('width', this.xScale.bandwidth())
|
965
|
-
.attr('y', this.height) // Start from bottom for animation
|
966
|
-
.attr('height', 0) // Start with height 0 for animation
|
967
|
-
.attr('rx', radius) // Rounded corners
|
968
|
-
.attr('ry', radius) // Rounded corners
|
969
|
-
.attr('fill', (d, i) => d.color || AXPChartColors.getColor(i))
|
970
|
-
.on('mouseenter', (event, d) => this.handleBarHover(event, d))
|
971
|
-
.on('mousemove', (event) => this.updateTooltipPosition(event))
|
972
|
-
.on('mouseleave', () => this._tooltipVisible.set(false))
|
973
|
-
.on('click', (event, d) => this.handleBarClick(event, d));
|
974
|
-
// Add animation
|
975
|
-
bars
|
976
|
-
.transition()
|
977
|
-
.duration(800)
|
978
|
-
.delay((d, i) => i * 50) // Stagger each bar animation
|
979
|
-
.attr('y', (d) => this.yScale(d.value))
|
980
|
-
.attr('height', (d) => this.height - this.yScale(d.value))
|
981
|
-
.ease(this.d3.easeQuadOut); // Simple quadratic ease-out animation
|
982
|
-
}
|
983
|
-
// Event handlers
|
984
|
-
/**
|
985
|
-
* Handles bar hover event and shows tooltip
|
986
|
-
*/
|
987
|
-
handleBarHover(event, datum) {
|
988
|
-
if (this.options().showTooltip !== false) {
|
989
|
-
const index = this.chartData().findIndex((item) => item.id === datum.id);
|
990
|
-
const color = datum.color || AXPChartColors.getColor(index);
|
991
|
-
// Calculate percentage of total
|
992
|
-
const total = this.chartData().reduce((sum, item) => sum + item.value, 0);
|
993
|
-
const percentage = total > 0 ? ((datum.value / total) * 100).toFixed(1) : '0';
|
994
|
-
this._tooltipData.set({
|
995
|
-
title: datum.label,
|
996
|
-
value: datum.value.toString(),
|
997
|
-
percentage: `${percentage}%`,
|
998
|
-
color: color,
|
999
|
-
});
|
1000
|
-
this.updateTooltipPosition(event);
|
1001
|
-
this._tooltipVisible.set(true);
|
1002
|
-
}
|
1003
|
-
}
|
1004
|
-
/**
|
1005
|
-
* Updates tooltip position based on mouse coordinates
|
1006
|
-
*/
|
1007
|
-
updateTooltipPosition(event) {
|
1008
|
-
const container = this.chartContainerEl().nativeElement.getBoundingClientRect();
|
1009
|
-
const x = event.clientX - container.left;
|
1010
|
-
const y = event.clientY - container.top;
|
1011
|
-
this._tooltipPosition.set({
|
1012
|
-
x: x,
|
1013
|
-
y: y,
|
1014
|
-
});
|
1015
|
-
}
|
1016
|
-
/**
|
1017
|
-
* Handles bar click event
|
1018
|
-
*/
|
1019
|
-
handleBarClick(event, datum) {
|
1020
|
-
this.barClick.emit(datum);
|
1021
|
-
}
|
1022
|
-
/**
|
1023
|
-
* Shows a message when no data is available
|
1024
|
-
*/
|
1025
|
-
showNoDataMessage(containerElement) {
|
1026
|
-
const messageContainer = this.d3
|
1027
|
-
.select(containerElement)
|
1028
|
-
.append('div')
|
1029
|
-
.attr('class', 'axp-bar-chart-no-data-message')
|
1030
|
-
.style('width', '100%')
|
1031
|
-
.style('height', '100%')
|
1032
|
-
.style('display', 'flex')
|
1033
|
-
.style('flex-direction', 'column')
|
1034
|
-
.style('align-items', 'center')
|
1035
|
-
.style('justify-content', 'center')
|
1036
|
-
.style('text-align', 'center');
|
1037
|
-
// Add an icon
|
1038
|
-
messageContainer
|
1039
|
-
.append('div')
|
1040
|
-
.attr('class', 'axp-bar-chart-no-data-icon')
|
1041
|
-
.style('margin-bottom', '10px')
|
1042
|
-
.style('color', 'var(--ax-text-muted, #999)')
|
1043
|
-
.html('<i class="fa-light fa-chart-bar fa-2x"></i>');
|
1044
|
-
// Add text message
|
1045
|
-
messageContainer
|
1046
|
-
.append('div')
|
1047
|
-
.attr('class', 'axp-bar-chart-no-data-text')
|
1048
|
-
.style('font-size', '16px')
|
1049
|
-
.style('font-weight', '600')
|
1050
|
-
.style('color', 'var(--ax-text-color, #333)')
|
1051
|
-
.text('No data available');
|
1052
|
-
}
|
1053
|
-
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.0.3", ngImport: i0, type: AXPBarChartWidgetViewComponent, deps: null, target: i0.ɵɵFactoryTarget.Component }); }
|
1054
|
-
static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.2.0", version: "19.0.3", type: AXPBarChartWidgetViewComponent, isStandalone: true, selector: "ng-component", outputs: { barClick: "barClick" }, viewQueries: [{ propertyName: "chartContainerEl", first: true, predicate: ["chartContainer"], descendants: true, isSignal: true }], usesInheritance: true, ngImport: i0, template: "<div class=\"axp-bar-chart\" #chartContainer>\n <!-- Shared tooltip component -->\n <ax-chart-tooltip\n [visible]=\"tooltipVisible()\"\n [position]=\"tooltipPosition()\"\n [data]=\"tooltipData()\"\n [showPercentage]=\"true\"\n ></ax-chart-tooltip>\n</div>\n", styles: [":host{display:block;width:100%;height:100%;min-height:200px}.axp-bar-chart{width:100%;height:100%;position:relative;display:flex;align-items:center;justify-content:center;border-radius:.5rem;overflow:hidden}.axp-bar-chart svg{width:100%;height:100%;max-width:100%;max-height:100%;overflow:visible}.axp-bar-chart-bar{transition:all .3s cubic-bezier(.4,0,.2,1);cursor:pointer}.axp-bar-chart-bar:hover{filter:brightness(.9);transform:translateY(-3px)}.axp-bar-chart-axis-x path,.axp-bar-chart-axis-y path{stroke:var(--ax-border-color, #e0e0e0)}.axp-bar-chart-axis-x line,.axp-bar-chart-axis-y line,.axp-bar-chart-grid line{stroke:var(--ax-border-color, #e0e0e0);stroke-dasharray:2,2;stroke-opacity:.5}.axp-bar-chart-grid path{stroke-width:0}.axp-bar-chart-axis-x text,.axp-bar-chart-axis-y text{fill:var(--ax-text-muted, #666);font-size:clamp(8px,2vmin,12px)}.axp-bar-chart-no-data-message{font-family:var(--ax-font-family, system-ui, sans-serif);display:flex;flex-direction:column;align-items:center;justify-content:center;text-align:center;padding:1rem;width:100%;height:100%}.axp-bar-chart-no-data-icon{margin-bottom:.75rem;color:var(--ax-text-muted, #999)}.axp-bar-chart-no-data-text{font-weight:600;color:var(--ax-text-color, #333)}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "component", type: AXPChartTooltipComponent, selector: "ax-chart-tooltip", inputs: ["data", "position", "visible", "showPercentage", "style"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
|
1055
|
-
}
|
1056
|
-
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.0.3", ngImport: i0, type: AXPBarChartWidgetViewComponent, decorators: [{
|
1057
|
-
type: Component,
|
1058
|
-
args: [{ standalone: true, imports: [CommonModule, AXPChartTooltipComponent], changeDetection: ChangeDetectionStrategy.OnPush, template: "<div class=\"axp-bar-chart\" #chartContainer>\n <!-- Shared tooltip component -->\n <ax-chart-tooltip\n [visible]=\"tooltipVisible()\"\n [position]=\"tooltipPosition()\"\n [data]=\"tooltipData()\"\n [showPercentage]=\"true\"\n ></ax-chart-tooltip>\n</div>\n", styles: [":host{display:block;width:100%;height:100%;min-height:200px}.axp-bar-chart{width:100%;height:100%;position:relative;display:flex;align-items:center;justify-content:center;border-radius:.5rem;overflow:hidden}.axp-bar-chart svg{width:100%;height:100%;max-width:100%;max-height:100%;overflow:visible}.axp-bar-chart-bar{transition:all .3s cubic-bezier(.4,0,.2,1);cursor:pointer}.axp-bar-chart-bar:hover{filter:brightness(.9);transform:translateY(-3px)}.axp-bar-chart-axis-x path,.axp-bar-chart-axis-y path{stroke:var(--ax-border-color, #e0e0e0)}.axp-bar-chart-axis-x line,.axp-bar-chart-axis-y line,.axp-bar-chart-grid line{stroke:var(--ax-border-color, #e0e0e0);stroke-dasharray:2,2;stroke-opacity:.5}.axp-bar-chart-grid path{stroke-width:0}.axp-bar-chart-axis-x text,.axp-bar-chart-axis-y text{fill:var(--ax-text-muted, #666);font-size:clamp(8px,2vmin,12px)}.axp-bar-chart-no-data-message{font-family:var(--ax-font-family, system-ui, sans-serif);display:flex;flex-direction:column;align-items:center;justify-content:center;text-align:center;padding:1rem;width:100%;height:100%}.axp-bar-chart-no-data-icon{margin-bottom:.75rem;color:var(--ax-text-muted, #999)}.axp-bar-chart-no-data-text{font-weight:600;color:var(--ax-text-color, #333)}\n"] }]
|
1059
|
-
}] });
|
1060
|
-
|
1061
|
-
var barChartWidget_component = /*#__PURE__*/Object.freeze({
|
1062
|
-
__proto__: null,
|
1063
|
-
AXPBarChartWidgetViewComponent: AXPBarChartWidgetViewComponent
|
1064
|
-
});
|
1065
|
-
|
1066
|
-
const AXPBarChartWidget = {
|
1067
|
-
name: 'bar-chart',
|
1068
|
-
title: 'Bar Chart Widget',
|
1069
|
-
categories: [AXP_WIDGETS_CHART_CATEGORY],
|
1070
|
-
groups: [AXPWidgetGroupEnum.DashboardWidget],
|
1071
|
-
type: 'dashboard',
|
1072
|
-
icon: 'fa-light fa-chart-bar',
|
1073
|
-
properties: [
|
1074
494
|
// ====== Layout & Dimensions ======
|
1075
495
|
{
|
1076
|
-
name: '
|
1077
|
-
title: '
|
496
|
+
name: 'width',
|
497
|
+
title: 'Width',
|
1078
498
|
group: AXP_STYLING_PROPERTY_GROUP,
|
1079
499
|
schema: {
|
1080
|
-
defaultValue:
|
500
|
+
defaultValue: null,
|
1081
501
|
dataType: 'number',
|
1082
502
|
interface: {
|
1083
|
-
name: '
|
1084
|
-
path: 'options.
|
503
|
+
name: 'width',
|
504
|
+
path: 'options.width',
|
1085
505
|
type: AXPWidgetsCatalog.number,
|
1086
506
|
options: {
|
1087
507
|
minValue: 0,
|
1088
|
-
maxValue:
|
508
|
+
maxValue: 1200,
|
1089
509
|
},
|
1090
510
|
},
|
1091
511
|
},
|
1092
512
|
visible: true,
|
1093
513
|
},
|
1094
514
|
{
|
1095
|
-
name: '
|
1096
|
-
title: '
|
515
|
+
name: 'height',
|
516
|
+
title: 'Height',
|
1097
517
|
group: AXP_STYLING_PROPERTY_GROUP,
|
1098
518
|
schema: {
|
1099
|
-
defaultValue:
|
519
|
+
defaultValue: 300,
|
1100
520
|
dataType: 'number',
|
1101
521
|
interface: {
|
1102
|
-
name: '
|
1103
|
-
path: 'options.
|
522
|
+
name: 'height',
|
523
|
+
path: 'options.height',
|
1104
524
|
type: AXPWidgetsCatalog.number,
|
1105
525
|
options: {
|
1106
526
|
minValue: 0,
|
1107
|
-
maxValue:
|
527
|
+
maxValue: 800,
|
1108
528
|
},
|
1109
529
|
},
|
1110
530
|
},
|
1111
531
|
visible: true,
|
1112
532
|
},
|
1113
|
-
// ====== Axis Settings ======
|
533
|
+
// ====== X Axis Settings ======
|
1114
534
|
{
|
1115
535
|
name: 'showXAxis',
|
1116
536
|
title: 'Show X Axis',
|
@@ -1126,6 +546,22 @@ const AXPBarChartWidget = {
|
|
1126
546
|
},
|
1127
547
|
visible: true,
|
1128
548
|
},
|
549
|
+
{
|
550
|
+
name: 'xAxisLabel',
|
551
|
+
title: 'X Axis Label',
|
552
|
+
group: AXP_APPEARANCE_PROPERTY_GROUP,
|
553
|
+
schema: {
|
554
|
+
defaultValue: '',
|
555
|
+
dataType: 'string',
|
556
|
+
interface: {
|
557
|
+
name: 'xAxisLabel',
|
558
|
+
path: 'options.xAxisLabel',
|
559
|
+
type: AXPWidgetsCatalog.text,
|
560
|
+
},
|
561
|
+
},
|
562
|
+
visible: true,
|
563
|
+
},
|
564
|
+
// ====== Y Axis Settings ======
|
1129
565
|
{
|
1130
566
|
name: 'showYAxis',
|
1131
567
|
title: 'Show Y Axis',
|
@@ -1141,6 +577,63 @@ const AXPBarChartWidget = {
|
|
1141
577
|
},
|
1142
578
|
visible: true,
|
1143
579
|
},
|
580
|
+
{
|
581
|
+
name: 'yAxisLabel',
|
582
|
+
title: 'Y Axis Label',
|
583
|
+
group: AXP_APPEARANCE_PROPERTY_GROUP,
|
584
|
+
schema: {
|
585
|
+
defaultValue: '',
|
586
|
+
dataType: 'string',
|
587
|
+
interface: {
|
588
|
+
name: 'yAxisLabel',
|
589
|
+
path: 'options.yAxisLabel',
|
590
|
+
type: AXPWidgetsCatalog.text,
|
591
|
+
},
|
592
|
+
},
|
593
|
+
visible: true,
|
594
|
+
},
|
595
|
+
// ====== Bar Appearance ======
|
596
|
+
{
|
597
|
+
name: 'barWidth',
|
598
|
+
title: 'Bar Width',
|
599
|
+
group: AXP_APPEARANCE_PROPERTY_GROUP,
|
600
|
+
schema: {
|
601
|
+
defaultValue: 80,
|
602
|
+
dataType: 'number',
|
603
|
+
interface: {
|
604
|
+
name: 'barWidth',
|
605
|
+
path: 'options.barWidth',
|
606
|
+
type: AXPWidgetsCatalog.number,
|
607
|
+
options: {
|
608
|
+
placeholder: '1-100',
|
609
|
+
minValue: 1,
|
610
|
+
maxValue: 100,
|
611
|
+
},
|
612
|
+
},
|
613
|
+
},
|
614
|
+
visible: true,
|
615
|
+
},
|
616
|
+
{
|
617
|
+
name: 'cornerRadius',
|
618
|
+
title: 'Corner Radius',
|
619
|
+
group: AXP_APPEARANCE_PROPERTY_GROUP,
|
620
|
+
schema: {
|
621
|
+
defaultValue: 4,
|
622
|
+
dataType: 'number',
|
623
|
+
interface: {
|
624
|
+
name: 'cornerRadius',
|
625
|
+
path: 'options.cornerRadius',
|
626
|
+
type: AXPWidgetsCatalog.number,
|
627
|
+
options: {
|
628
|
+
placeholder: '0-20',
|
629
|
+
minValue: 0,
|
630
|
+
maxValue: 20,
|
631
|
+
},
|
632
|
+
},
|
633
|
+
},
|
634
|
+
visible: true,
|
635
|
+
},
|
636
|
+
// ====== Grid Settings ======
|
1144
637
|
{
|
1145
638
|
name: 'showGrid',
|
1146
639
|
title: 'Show Grid Lines',
|
@@ -1172,42 +665,52 @@ const AXPBarChartWidget = {
|
|
1172
665
|
},
|
1173
666
|
visible: true,
|
1174
667
|
},
|
1175
|
-
// ======
|
668
|
+
// ====== Animation Settings ======
|
1176
669
|
{
|
1177
|
-
name: '
|
1178
|
-
title: '
|
670
|
+
name: 'animationEasing',
|
671
|
+
title: 'Animation Easing',
|
1179
672
|
group: AXP_APPEARANCE_PROPERTY_GROUP,
|
1180
673
|
schema: {
|
1181
|
-
defaultValue:
|
1182
|
-
dataType: '
|
674
|
+
defaultValue: 'cubic-out',
|
675
|
+
dataType: 'string',
|
1183
676
|
interface: {
|
1184
|
-
name: '
|
1185
|
-
path: 'options.
|
1186
|
-
type: AXPWidgetsCatalog.
|
677
|
+
name: 'animationEasing',
|
678
|
+
path: 'options.animationEasing',
|
679
|
+
type: AXPWidgetsCatalog.select,
|
1187
680
|
options: {
|
1188
|
-
|
1189
|
-
|
1190
|
-
|
681
|
+
dataSource: [
|
682
|
+
{ value: 'linear', text: 'Linear' },
|
683
|
+
{ value: 'ease', text: 'Ease' },
|
684
|
+
{ value: 'ease-in', text: 'Ease In' },
|
685
|
+
{ value: 'ease-out', text: 'Ease Out' },
|
686
|
+
{ value: 'ease-in-out', text: 'Ease In Out' },
|
687
|
+
{ value: 'cubic', text: 'Cubic' },
|
688
|
+
{ value: 'cubic-in', text: 'Cubic In' },
|
689
|
+
{ value: 'cubic-out', text: 'Cubic Out' },
|
690
|
+
{ value: 'cubic-in-out', text: 'Cubic In Out' },
|
691
|
+
],
|
692
|
+
textField: 'text',
|
693
|
+
valueField: 'value',
|
1191
694
|
},
|
1192
695
|
},
|
1193
696
|
},
|
1194
697
|
visible: true,
|
1195
698
|
},
|
1196
699
|
{
|
1197
|
-
name: '
|
1198
|
-
title: '
|
700
|
+
name: 'animationDuration',
|
701
|
+
title: 'Animation Duration',
|
1199
702
|
group: AXP_APPEARANCE_PROPERTY_GROUP,
|
1200
703
|
schema: {
|
1201
|
-
defaultValue:
|
704
|
+
defaultValue: 800,
|
1202
705
|
dataType: 'number',
|
1203
706
|
interface: {
|
1204
|
-
name: '
|
1205
|
-
path: 'options.
|
707
|
+
name: 'animationDuration',
|
708
|
+
path: 'options.animationDuration',
|
1206
709
|
type: AXPWidgetsCatalog.number,
|
1207
710
|
options: {
|
1208
|
-
placeholder: '0-
|
711
|
+
placeholder: '0-2000',
|
1209
712
|
minValue: 0,
|
1210
|
-
maxValue:
|
713
|
+
maxValue: 2000,
|
1211
714
|
},
|
1212
715
|
},
|
1213
716
|
},
|
@@ -1266,7 +769,7 @@ class AXPClockCalendarWidgetViewComponent extends AXPValueWidgetComponent {
|
|
1266
769
|
this.showSeconds = computed(() => this.options()?.showSeconds !== false);
|
1267
770
|
this.dateFormat = computed(() => this.options()?.dateFormat?.id ?? 'dd MMM yyyy');
|
1268
771
|
this.timezone = computed(() => this.options()?.timezone?.id ?? 'local');
|
1269
|
-
|
772
|
+
// protected readonly showTimezoneIndicator: Signal<boolean> = computed(() => this.timezone() !== 'local');
|
1270
773
|
this.displayTimezone = computed(() => {
|
1271
774
|
const tz = this.timezone();
|
1272
775
|
if (tz === 'local')
|
@@ -1354,11 +857,11 @@ class AXPClockCalendarWidgetViewComponent extends AXPValueWidgetComponent {
|
|
1354
857
|
return days[this.currentDate.getDay()];
|
1355
858
|
}
|
1356
859
|
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.0.3", ngImport: i0, type: AXPClockCalendarWidgetViewComponent, deps: null, target: i0.ɵɵFactoryTarget.Component }); }
|
1357
|
-
static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "19.0.3", type: AXPClockCalendarWidgetViewComponent, isStandalone: true, selector: "ng-component", usesInheritance: true, ngImport: i0, template: "<div class=\"axp-clock-calendar-container\">\n <!-- Timezone indicator (only shown when not local) -->\n @if (showTimezoneIndicator()) {\n <div class=\"axp-clock-calendar-timezone-badge\"><i class=\"fa-solid fa-globe\"></i> {{ displayTimezone() }}</div>\n }
|
860
|
+
static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "19.0.3", type: AXPClockCalendarWidgetViewComponent, isStandalone: true, selector: "ng-component", usesInheritance: true, ngImport: i0, template: "<div class=\"axp-clock-calendar-container\">\n <!-- Timezone indicator (only shown when not local) -->\n <!-- @if (showTimezoneIndicator()) {\n <div class=\"axp-clock-calendar-timezone-badge\"><i class=\"fa-solid fa-globe\"></i> {{ displayTimezone() }}</div>\n } -->\n\n <!-- Day of week display -->\n @if (showDayOfWeek()) {\n <div class=\"axp-clock-calendar-day-label\">{{ getDayOfWeek() }}</div>\n }\n\n <div class=\"axp-clock-calendar-content\">\n <!-- Digital Clock Display -->\n @if (showDigitalClock()) {\n <div class=\"axp-clock-calendar-digital-clock\">\n {{ currentTime | format : 'datetime' : timeFormat() | async }}\n </div>\n }\n\n <!-- Analog Clock Display -->\n @if (showAnalogClock()) {\n <div class=\"axp-clock-calendar-analog-clock\">\n <!-- Hour markers -->\n @for (hour of clockHours; track hour) {\n <div\n class=\"axp-clock-calendar-hour-marker\"\n [style.transform]=\"'rotate(' + hour * 30 + 'deg) translateY(-80px)'\"\n ></div>\n }\n\n <!-- Clock Numbers -->\n <div class=\"axp-clock-calendar-numbers-container\">\n @for (hour of clockHourNumbers; track hour) {\n <div\n class=\"axp-clock-calendar-hour-number\"\n [style.transform]=\"'rotate(' + hour.angle + 'deg) translateY(-82px)'\"\n >\n <span [style.transform]=\"'rotate(' + -hour.angle + 'deg)'\">{{ hour.number }}</span>\n </div>\n }\n </div>\n\n <!-- Clock Hands -->\n <div class=\"axp-clock-calendar-hands-container\">\n <div class=\"axp-clock-calendar-hour-hand\" [style.transform]=\"'rotate(' + hourRotation + 'deg)'\"></div>\n <div class=\"axp-clock-calendar-minute-hand\" [style.transform]=\"'rotate(' + minuteRotation + 'deg)'\"></div>\n @if (showSeconds()) {\n <div class=\"axp-clock-calendar-second-hand\" [style.transform]=\"'rotate(' + secondRotation + 'deg)'\"></div>\n }\n <div class=\"axp-clock-calendar-center-dot\"></div>\n </div>\n </div>\n }\n\n <!-- Date Display -->\n @if (showDate()) {\n <div class=\"axp-clock-calendar-date-display\">\n <i class=\"fa-regular fa-calendar\"></i>\n {{ currentDate | format : 'datetime' : dateFormat() | async }}\n </div>\n }\n </div>\n</div>\n", styles: [":host{display:block;width:100%;height:100%}.axp-clock-calendar-container{display:flex;flex-direction:column;align-items:center;justify-content:center;width:100%;height:100%;padding:1rem;position:relative;overflow:hidden;box-shadow:var(--ax-shadow-sm);background-color:var(--ax-surface-color);color:var(--ax-text-color)}.axp-clock-calendar-content{display:flex;flex-direction:column;align-items:center;justify-content:center;gap:.75rem;width:100%;height:100%;position:relative}.axp-clock-calendar-timezone-badge{position:absolute;top:.5rem;right:.5rem;font-size:.75rem;padding:.25rem;border-radius:1rem;border-width:1px;border-color:rgba(23,23,23,.5)}.axp-clock-calendar-timezone-badge:is(.ax-dark *){border-color:rgba(245,245,245,.5)}.axp-clock-calendar-timezone-badge{display:flex;align-items:center;gap:.25rem}.axp-clock-calendar-timezone-badge i{font-size:.75rem}.axp-clock-calendar-day-label{font-size:.9rem;font-weight:600;text-transform:uppercase;letter-spacing:.05rem;margin-bottom:.25rem}.axp-clock-calendar-digital-clock{font-size:1.5rem;font-weight:500;letter-spacing:.05rem;font-family:monospace;padding:.5rem .75rem;border-radius:.25rem}.axp-clock-calendar-analog-clock{position:relative;border-radius:50%;border-width:1px;border-color:rgba(23,23,23,.5)}.axp-clock-calendar-analog-clock:is(.ax-dark *){border-color:rgba(245,245,245,.5)}.axp-clock-calendar-analog-clock{display:flex;align-items:center;justify-content:center;background:var(--ax-surface-color);width:min(180px,100%);height:0;padding-bottom:min(180px,100%);margin:.5rem auto;min-width:120px;min-height:120px;box-shadow:var(--ax-shadow-sm)}.axp-clock-calendar-hands-container,.axp-clock-calendar-numbers-container{position:absolute;top:0;left:0;width:100%;height:100%;border-radius:50%}.axp-clock-calendar-hour-marker{position:absolute;left:50%;top:50%;width:2px;height:4%;margin-left:-1px;border-radius:1px;background-color:var(--ax-text-muted);transform-origin:50% 0}.axp-clock-calendar-hour-number{position:absolute;left:50%;top:50%;transform-origin:50% 0;font-size:clamp(.7rem,2.5vw,.9rem);font-weight:600;color:var(--ax-text-color)}.axp-clock-calendar-hour-number span{display:block}.axp-clock-calendar-hour-hand{position:absolute;top:50%;left:50%;width:4px;height:25%;margin-left:-2px;background-color:rgba(23,23,23,.75)}.axp-clock-calendar-hour-hand:is(.ax-dark *){background-color:rgba(245,245,245,.75)}.axp-clock-calendar-hour-hand{transform-origin:50% 0;border-radius:3px;box-shadow:0 0 4px rgba(0,0,0,.3)}.axp-clock-calendar-minute-hand{position:absolute;top:50%;left:50%;width:3px;height:38%;margin-left:-1.5px;background-color:rgba(23,23,23,.5)}.axp-clock-calendar-minute-hand:is(.ax-dark *){background-color:rgba(245,245,245,.5)}.axp-clock-calendar-minute-hand{transform-origin:50% 0;border-radius:2px;box-shadow:0 0 4px rgba(0,0,0,.3)}.axp-clock-calendar-second-hand{position:absolute;top:50%;left:50%;width:2px;height:42%;margin-left:-1px;--tw-bg-opacity: 1;background-color:rgba(var(--ax-sys-color-danger-500),var(--tw-bg-opacity, 1))}.axp-clock-calendar-second-hand:is(.ax-dark *){--tw-bg-opacity: 1;background-color:rgba(var(--ax-sys-color-danger-400),var(--tw-bg-opacity, 1))}.axp-clock-calendar-second-hand{transform-origin:50% 0;border-radius:1px;box-shadow:0 0 3px rgba(0,0,0,.2)}.axp-clock-calendar-center-dot{position:absolute;top:50%;left:50%;width:10px;height:10px;border-radius:50%;margin-top:-5px;margin-left:-5px;background-color:#d81159;border:2px solid var(--ax-surface-color);box-shadow:0 0 4px rgba(0,0,0,.3)}.axp-clock-calendar-date-display{display:flex;align-items:center;gap:.5rem;font-size:.85rem;padding:.25rem .6rem;border-radius:.25rem;background-color:var(--ax-surface-hover);color:var(--ax-text-color)}.axp-clock-calendar-date-display i{font-size:.85rem;opacity:.7}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "pipe", type: i1.AsyncPipe, name: "async" }, { kind: "ngmodule", type: AXDateTimeModule }, { kind: "ngmodule", type: AXFormatModule }, { kind: "pipe", type: i2.AXFormatPipe, name: "format" }, { kind: "ngmodule", type: AXTagModule }, { kind: "ngmodule", type: AXDecoratorModule }], changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
|
1358
861
|
}
|
1359
862
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.0.3", ngImport: i0, type: AXPClockCalendarWidgetViewComponent, decorators: [{
|
1360
863
|
type: Component,
|
1361
|
-
args: [{ standalone: true, imports: [CommonModule, AXDateTimeModule, AXFormatModule, AXTagModule, AXDecoratorModule], changeDetection: ChangeDetectionStrategy.OnPush, template: "<div class=\"axp-clock-calendar-container\">\n <!-- Timezone indicator (only shown when not local) -->\n @if (showTimezoneIndicator()) {\n <div class=\"axp-clock-calendar-timezone-badge\"><i class=\"fa-solid fa-globe\"></i> {{ displayTimezone() }}</div>\n }
|
864
|
+
args: [{ standalone: true, imports: [CommonModule, AXDateTimeModule, AXFormatModule, AXTagModule, AXDecoratorModule], changeDetection: ChangeDetectionStrategy.OnPush, template: "<div class=\"axp-clock-calendar-container\">\n <!-- Timezone indicator (only shown when not local) -->\n <!-- @if (showTimezoneIndicator()) {\n <div class=\"axp-clock-calendar-timezone-badge\"><i class=\"fa-solid fa-globe\"></i> {{ displayTimezone() }}</div>\n } -->\n\n <!-- Day of week display -->\n @if (showDayOfWeek()) {\n <div class=\"axp-clock-calendar-day-label\">{{ getDayOfWeek() }}</div>\n }\n\n <div class=\"axp-clock-calendar-content\">\n <!-- Digital Clock Display -->\n @if (showDigitalClock()) {\n <div class=\"axp-clock-calendar-digital-clock\">\n {{ currentTime | format : 'datetime' : timeFormat() | async }}\n </div>\n }\n\n <!-- Analog Clock Display -->\n @if (showAnalogClock()) {\n <div class=\"axp-clock-calendar-analog-clock\">\n <!-- Hour markers -->\n @for (hour of clockHours; track hour) {\n <div\n class=\"axp-clock-calendar-hour-marker\"\n [style.transform]=\"'rotate(' + hour * 30 + 'deg) translateY(-80px)'\"\n ></div>\n }\n\n <!-- Clock Numbers -->\n <div class=\"axp-clock-calendar-numbers-container\">\n @for (hour of clockHourNumbers; track hour) {\n <div\n class=\"axp-clock-calendar-hour-number\"\n [style.transform]=\"'rotate(' + hour.angle + 'deg) translateY(-82px)'\"\n >\n <span [style.transform]=\"'rotate(' + -hour.angle + 'deg)'\">{{ hour.number }}</span>\n </div>\n }\n </div>\n\n <!-- Clock Hands -->\n <div class=\"axp-clock-calendar-hands-container\">\n <div class=\"axp-clock-calendar-hour-hand\" [style.transform]=\"'rotate(' + hourRotation + 'deg)'\"></div>\n <div class=\"axp-clock-calendar-minute-hand\" [style.transform]=\"'rotate(' + minuteRotation + 'deg)'\"></div>\n @if (showSeconds()) {\n <div class=\"axp-clock-calendar-second-hand\" [style.transform]=\"'rotate(' + secondRotation + 'deg)'\"></div>\n }\n <div class=\"axp-clock-calendar-center-dot\"></div>\n </div>\n </div>\n }\n\n <!-- Date Display -->\n @if (showDate()) {\n <div class=\"axp-clock-calendar-date-display\">\n <i class=\"fa-regular fa-calendar\"></i>\n {{ currentDate | format : 'datetime' : dateFormat() | async }}\n </div>\n }\n </div>\n</div>\n", styles: [":host{display:block;width:100%;height:100%}.axp-clock-calendar-container{display:flex;flex-direction:column;align-items:center;justify-content:center;width:100%;height:100%;padding:1rem;position:relative;overflow:hidden;box-shadow:var(--ax-shadow-sm);background-color:var(--ax-surface-color);color:var(--ax-text-color)}.axp-clock-calendar-content{display:flex;flex-direction:column;align-items:center;justify-content:center;gap:.75rem;width:100%;height:100%;position:relative}.axp-clock-calendar-timezone-badge{position:absolute;top:.5rem;right:.5rem;font-size:.75rem;padding:.25rem;border-radius:1rem;border-width:1px;border-color:rgba(23,23,23,.5)}.axp-clock-calendar-timezone-badge:is(.ax-dark *){border-color:rgba(245,245,245,.5)}.axp-clock-calendar-timezone-badge{display:flex;align-items:center;gap:.25rem}.axp-clock-calendar-timezone-badge i{font-size:.75rem}.axp-clock-calendar-day-label{font-size:.9rem;font-weight:600;text-transform:uppercase;letter-spacing:.05rem;margin-bottom:.25rem}.axp-clock-calendar-digital-clock{font-size:1.5rem;font-weight:500;letter-spacing:.05rem;font-family:monospace;padding:.5rem .75rem;border-radius:.25rem}.axp-clock-calendar-analog-clock{position:relative;border-radius:50%;border-width:1px;border-color:rgba(23,23,23,.5)}.axp-clock-calendar-analog-clock:is(.ax-dark *){border-color:rgba(245,245,245,.5)}.axp-clock-calendar-analog-clock{display:flex;align-items:center;justify-content:center;background:var(--ax-surface-color);width:min(180px,100%);height:0;padding-bottom:min(180px,100%);margin:.5rem auto;min-width:120px;min-height:120px;box-shadow:var(--ax-shadow-sm)}.axp-clock-calendar-hands-container,.axp-clock-calendar-numbers-container{position:absolute;top:0;left:0;width:100%;height:100%;border-radius:50%}.axp-clock-calendar-hour-marker{position:absolute;left:50%;top:50%;width:2px;height:4%;margin-left:-1px;border-radius:1px;background-color:var(--ax-text-muted);transform-origin:50% 0}.axp-clock-calendar-hour-number{position:absolute;left:50%;top:50%;transform-origin:50% 0;font-size:clamp(.7rem,2.5vw,.9rem);font-weight:600;color:var(--ax-text-color)}.axp-clock-calendar-hour-number span{display:block}.axp-clock-calendar-hour-hand{position:absolute;top:50%;left:50%;width:4px;height:25%;margin-left:-2px;background-color:rgba(23,23,23,.75)}.axp-clock-calendar-hour-hand:is(.ax-dark *){background-color:rgba(245,245,245,.75)}.axp-clock-calendar-hour-hand{transform-origin:50% 0;border-radius:3px;box-shadow:0 0 4px rgba(0,0,0,.3)}.axp-clock-calendar-minute-hand{position:absolute;top:50%;left:50%;width:3px;height:38%;margin-left:-1.5px;background-color:rgba(23,23,23,.5)}.axp-clock-calendar-minute-hand:is(.ax-dark *){background-color:rgba(245,245,245,.5)}.axp-clock-calendar-minute-hand{transform-origin:50% 0;border-radius:2px;box-shadow:0 0 4px rgba(0,0,0,.3)}.axp-clock-calendar-second-hand{position:absolute;top:50%;left:50%;width:2px;height:42%;margin-left:-1px;--tw-bg-opacity: 1;background-color:rgba(var(--ax-sys-color-danger-500),var(--tw-bg-opacity, 1))}.axp-clock-calendar-second-hand:is(.ax-dark *){--tw-bg-opacity: 1;background-color:rgba(var(--ax-sys-color-danger-400),var(--tw-bg-opacity, 1))}.axp-clock-calendar-second-hand{transform-origin:50% 0;border-radius:1px;box-shadow:0 0 3px rgba(0,0,0,.2)}.axp-clock-calendar-center-dot{position:absolute;top:50%;left:50%;width:10px;height:10px;border-radius:50%;margin-top:-5px;margin-left:-5px;background-color:#d81159;border:2px solid var(--ax-surface-color);box-shadow:0 0 4px rgba(0,0,0,.3)}.axp-clock-calendar-date-display{display:flex;align-items:center;gap:.5rem;font-size:.85rem;padding:.25rem .6rem;border-radius:.25rem;background-color:var(--ax-surface-hover);color:var(--ax-text-color)}.axp-clock-calendar-date-display i{font-size:.85rem;opacity:.7}\n"] }]
|
1362
865
|
}] });
|
1363
866
|
|
1364
867
|
var clockCalendarWidget_component = /*#__PURE__*/Object.freeze({
|
@@ -1407,6 +910,25 @@ const AXPClockCalendarWidget = {
|
|
1407
910
|
type: 'dashboard',
|
1408
911
|
icon: 'fa-light fa-clock',
|
1409
912
|
properties: [
|
913
|
+
// ====== Title ======
|
914
|
+
{
|
915
|
+
name: 'title',
|
916
|
+
title: 'Chart Title',
|
917
|
+
group: AXP_APPEARANCE_PROPERTY_GROUP,
|
918
|
+
schema: {
|
919
|
+
defaultValue: '',
|
920
|
+
dataType: 'string',
|
921
|
+
interface: {
|
922
|
+
name: 'title',
|
923
|
+
path: 'options.title',
|
924
|
+
type: AXPWidgetsCatalog.text,
|
925
|
+
options: {
|
926
|
+
placeholder: 'Enter chart title',
|
927
|
+
},
|
928
|
+
},
|
929
|
+
},
|
930
|
+
visible: true,
|
931
|
+
},
|
1410
932
|
// ====== Display Settings ======
|
1411
933
|
{
|
1412
934
|
name: 'displayLayout',
|
@@ -1564,407 +1086,21 @@ const AXPClockCalendarWidget = {
|
|
1564
1086
|
* Donut Chart Widget Component
|
1565
1087
|
* Displays data in a circular donut chart with interactive segments
|
1566
1088
|
*/
|
1567
|
-
class AXPDonutChartWidgetViewComponent extends
|
1089
|
+
class AXPDonutChartWidgetViewComponent extends AXPValueWidgetComponent {
|
1568
1090
|
constructor() {
|
1569
1091
|
super(...arguments);
|
1570
|
-
this.
|
1571
|
-
|
1572
|
-
this.cdr = inject(ChangeDetectorRef);
|
1573
|
-
this.chartContainerEl = viewChild.required('chartContainer');
|
1574
|
-
this.pieData = [];
|
1575
|
-
// State management
|
1576
|
-
this.hiddenSegments = new Set();
|
1577
|
-
// Tooltip state
|
1578
|
-
this._tooltipVisible = signal(false);
|
1579
|
-
this._tooltipPosition = signal({ x: 0, y: 0 });
|
1580
|
-
this._tooltipData = signal({
|
1581
|
-
title: '',
|
1582
|
-
value: 0,
|
1583
|
-
percentage: '0%',
|
1584
|
-
color: '',
|
1585
|
-
});
|
1586
|
-
// Public computed properties for the template
|
1587
|
-
this.tooltipVisible = computed(() => this._tooltipVisible());
|
1588
|
-
this.tooltipPosition = computed(() => this._tooltipPosition());
|
1589
|
-
this.tooltipData = computed(() => this._tooltipData());
|
1590
|
-
// Computed configuration options
|
1591
|
-
this.showLegend = computed(() => this.options()['showLegend'] !== false);
|
1592
|
-
this.showTooltip = computed(() => this.options()['showTooltip'] !== false);
|
1593
|
-
this.legendPosition = computed(() => this.options()['legendPosition']?.id || 'right');
|
1594
|
-
this.donutWidth = computed(() => this.options()['donutWidth'] ?? 35);
|
1595
|
-
this.cornerRadius = computed(() => this.options()['cornerRadius'] ?? 4);
|
1596
|
-
// Data accessor for handling different incoming data formats
|
1597
|
-
this.chartDataArray = computed(() => {
|
1598
|
-
const data = this.chartData();
|
1599
|
-
if (data === null || data === undefined) {
|
1600
|
-
return [];
|
1601
|
-
}
|
1602
|
-
// Handle both array format and object format with data property
|
1603
|
-
return Array.isArray(data) ? data : data.data || [];
|
1604
|
-
});
|
1605
|
-
}
|
1606
|
-
getColor(index) {
|
1607
|
-
return AXPChartColors.getColor(index);
|
1608
|
-
}
|
1609
|
-
isSegmentHidden(id) {
|
1610
|
-
return this.hiddenSegments.has(id);
|
1611
|
-
}
|
1612
|
-
// Event handlers
|
1613
|
-
onSegmentClick(item) {
|
1614
|
-
this.toggleSegment(item);
|
1615
|
-
this.segmentClick.emit(item);
|
1616
|
-
}
|
1617
|
-
onLegendMouseEnter(item) {
|
1618
|
-
if (!this.svg)
|
1619
|
-
return;
|
1620
|
-
// Highlight the target segment
|
1621
|
-
this.svg
|
1622
|
-
.selectAll('path')
|
1623
|
-
.filter((d) => d?.data?.id === item.id)
|
1624
|
-
.classed('axp-donut-chart-highlighted', true)
|
1625
|
-
.attr('transform', 'scale(1.02)');
|
1626
|
-
// Dim other segments
|
1627
|
-
this.svg
|
1628
|
-
.selectAll('path')
|
1629
|
-
.filter((d) => d?.data?.id !== item.id)
|
1630
|
-
.classed('axp-donut-chart-dimmed', true);
|
1631
|
-
}
|
1632
|
-
onLegendMouseLeave() {
|
1633
|
-
if (!this.svg)
|
1634
|
-
return;
|
1635
|
-
// Reset all segments
|
1636
|
-
this.svg
|
1637
|
-
.selectAll('path')
|
1638
|
-
.classed('axp-donut-chart-highlighted', false)
|
1639
|
-
.classed('axp-donut-chart-dimmed', false)
|
1640
|
-
.attr('transform', 'scale(1)');
|
1641
|
-
}
|
1642
|
-
// Chart lifecycle methods (implementation of base class abstract methods)
|
1643
|
-
createChart() {
|
1644
|
-
if (!this.d3 || !this.chartContainerEl()?.nativeElement)
|
1645
|
-
return;
|
1646
|
-
try {
|
1647
|
-
const containerElement = this.chartContainerEl().nativeElement;
|
1648
|
-
const chartElement = containerElement.querySelector('div');
|
1649
|
-
this.clearChart(chartElement);
|
1650
|
-
const data = this.chartDataArray();
|
1651
|
-
if (!data || data.length === 0) {
|
1652
|
-
this.showNoDataMessage(chartElement);
|
1653
|
-
return;
|
1654
|
-
}
|
1655
|
-
const options = this.options();
|
1656
|
-
const { width, height } = this.setupDimensions(containerElement, options);
|
1657
|
-
this.renderDonutChart(chartElement, width, height);
|
1658
|
-
}
|
1659
|
-
catch (error) {
|
1660
|
-
console.error('Error creating donut chart:', error);
|
1661
|
-
this.handleChartError();
|
1662
|
-
}
|
1663
|
-
}
|
1664
|
-
updateChart() {
|
1665
|
-
this.createChart();
|
1666
|
-
}
|
1667
|
-
cleanupChart() {
|
1668
|
-
if (this.svg) {
|
1669
|
-
this.d3.select(this.chartContainerEl()?.nativeElement).selectAll('svg').remove();
|
1670
|
-
this.svg = null;
|
1671
|
-
this.pieData = [];
|
1672
|
-
}
|
1673
|
-
this.hiddenSegments.clear();
|
1674
|
-
this._tooltipVisible.set(false);
|
1675
|
-
}
|
1676
|
-
// Private helper methods
|
1677
|
-
clearChart(element) {
|
1678
|
-
this.d3.select(element).selectAll('*').remove();
|
1679
|
-
}
|
1680
|
-
handleChartError() {
|
1681
|
-
try {
|
1682
|
-
const containerElement = this.chartContainerEl()?.nativeElement;
|
1683
|
-
if (containerElement) {
|
1684
|
-
const chartElement = containerElement.querySelector('div');
|
1685
|
-
if (chartElement) {
|
1686
|
-
this.showNoDataMessage(chartElement);
|
1687
|
-
}
|
1688
|
-
}
|
1689
|
-
}
|
1690
|
-
catch (e) {
|
1691
|
-
console.error('Failed to show no data message:', e);
|
1692
|
-
}
|
1693
|
-
}
|
1694
|
-
setupDimensions(containerElement, options) {
|
1695
|
-
const containerWidth = containerElement.clientWidth;
|
1696
|
-
const containerHeight = containerElement.clientHeight;
|
1697
|
-
// Ensure minimum dimensions for the chart
|
1698
|
-
const minDim = 200;
|
1699
|
-
const width = Math.max(options['width'] || containerWidth, minDim);
|
1700
|
-
const height = Math.max(options['height'] || containerHeight, minDim);
|
1701
|
-
return { width, height };
|
1702
|
-
}
|
1703
|
-
renderDonutChart(chartElement, width, height) {
|
1704
|
-
const data = this.chartDataArray();
|
1705
|
-
// Filter out hidden segments
|
1706
|
-
const visibleData = data.filter((item) => !this.hiddenSegments.has(item.id));
|
1707
|
-
// If all segments are hidden, show no data message and return
|
1708
|
-
if (visibleData.length === 0) {
|
1709
|
-
this.showAllSegmentsHiddenMessage(chartElement);
|
1710
|
-
return;
|
1711
|
-
}
|
1712
|
-
const total = this.calculateTotal();
|
1713
|
-
// Calculate chart dimensions based on legend position
|
1714
|
-
const { chartWidth, chartHeight, translateX, translateY } = this.calculateChartLayout(width, height);
|
1715
|
-
// Create SVG container with filters
|
1716
|
-
const svg = this.createSvgWithFilters(chartElement, width, height);
|
1717
|
-
// Create main chart group
|
1718
|
-
this.svg = svg.append('g').attr('transform', `translate(${translateX}, ${translateY})`);
|
1719
|
-
// Create donut segments
|
1720
|
-
this.createDonutSegments(chartWidth, chartHeight, visibleData, total);
|
1721
|
-
// Add total in center
|
1722
|
-
this.addTotalDisplay(total);
|
1092
|
+
this.donutChartData = computed(() => this.getValue());
|
1093
|
+
this.donutChartOptions = computed(() => this.options());
|
1723
1094
|
}
|
1724
|
-
|
1725
|
-
|
1726
|
-
let chartWidth = width;
|
1727
|
-
let chartHeight = height;
|
1728
|
-
let translateX = width / 2;
|
1729
|
-
let translateY = height / 2;
|
1730
|
-
if (this.showLegend()) {
|
1731
|
-
if (legendPosition === 'right') {
|
1732
|
-
// Reserve space for right legend
|
1733
|
-
const legendWidth = Math.min(width * 0.3, 150);
|
1734
|
-
chartWidth = width - legendWidth - 20;
|
1735
|
-
translateX = (width - chartWidth) / 3 + chartWidth / 2;
|
1736
|
-
}
|
1737
|
-
else if (legendPosition === 'bottom') {
|
1738
|
-
// Reserve space for bottom legend
|
1739
|
-
const legendHeight = Math.min(height * 0.2, 80);
|
1740
|
-
chartHeight = height - legendHeight - 20;
|
1741
|
-
translateY = (height - chartHeight) / 3 + chartHeight / 2;
|
1742
|
-
}
|
1743
|
-
}
|
1744
|
-
return { chartWidth, chartHeight, translateX, translateY };
|
1745
|
-
}
|
1746
|
-
createSvgWithFilters(chartElement, width, height) {
|
1747
|
-
const svg = this.d3
|
1748
|
-
.select(chartElement)
|
1749
|
-
.append('svg')
|
1750
|
-
.attr('width', width)
|
1751
|
-
.attr('height', height)
|
1752
|
-
.attr('viewBox', `0 0 ${width} ${height}`)
|
1753
|
-
.attr('preserveAspectRatio', 'xMidYMid meet');
|
1754
|
-
// Add drop shadow filter
|
1755
|
-
const defs = svg.append('defs');
|
1756
|
-
const filter = defs.append('filter').attr('id', 'axp-donut-chart-segment-shadow').attr('height', '130%');
|
1757
|
-
filter.append('feGaussianBlur').attr('in', 'SourceAlpha').attr('stdDeviation', 2).attr('result', 'blur');
|
1758
|
-
filter.append('feOffset').attr('in', 'blur').attr('dx', 1).attr('dy', 1).attr('result', 'offsetBlur');
|
1759
|
-
const feComponentTransfer = filter
|
1760
|
-
.append('feComponentTransfer')
|
1761
|
-
.attr('in', 'offsetBlur')
|
1762
|
-
.attr('result', 'offsetBlur');
|
1763
|
-
feComponentTransfer.append('feFuncA').attr('type', 'linear').attr('slope', 0.3);
|
1764
|
-
const feMerge = filter.append('feMerge');
|
1765
|
-
feMerge.append('feMergeNode').attr('in', 'offsetBlur');
|
1766
|
-
feMerge.append('feMergeNode').attr('in', 'SourceGraphic');
|
1767
|
-
return svg;
|
1768
|
-
}
|
1769
|
-
createDonutSegments(chartWidth, chartHeight, data, total) {
|
1770
|
-
// Create pie layout
|
1771
|
-
const pie = this.d3
|
1772
|
-
.pie()
|
1773
|
-
.value((d) => d.value)
|
1774
|
-
.sort(null)
|
1775
|
-
.padAngle(0.02);
|
1776
|
-
// Calculate the radius of the donut chart
|
1777
|
-
const radius = (Math.min(chartWidth, chartHeight) / 2) * 0.85;
|
1778
|
-
// Calculate inner radius based on donutWidth percentage
|
1779
|
-
const donutWidthPercent = this.donutWidth() / 100;
|
1780
|
-
const innerRadius = radius * (1 - donutWidthPercent);
|
1781
|
-
// Create arc generator with the configured radius and corner radius
|
1782
|
-
const arc = this.d3
|
1783
|
-
.arc()
|
1784
|
-
.innerRadius(innerRadius)
|
1785
|
-
.outerRadius(radius * 0.95)
|
1786
|
-
.cornerRadius(this.cornerRadius());
|
1787
|
-
// Generate pie data
|
1788
|
-
this.pieData = pie(data);
|
1789
|
-
// Create color scale
|
1790
|
-
const colorScale = this.setupColorScale(this.chartDataArray());
|
1791
|
-
// Add segments with animation
|
1792
|
-
this.addSegmentsWithAnimation(arc, colorScale, total);
|
1793
|
-
}
|
1794
|
-
setupColorScale(data) {
|
1795
|
-
return this.d3
|
1796
|
-
.scaleOrdinal()
|
1797
|
-
.domain(data.map((_, i) => i.toString()))
|
1798
|
-
.range(data.map((_, i) => this.getColor(i)));
|
1799
|
-
}
|
1800
|
-
addSegmentsWithAnimation(arc, colorScale, total) {
|
1801
|
-
// Add segments
|
1802
|
-
const segments = this.svg
|
1803
|
-
.selectAll('path')
|
1804
|
-
.data(this.pieData)
|
1805
|
-
.enter()
|
1806
|
-
.append('path')
|
1807
|
-
.attr('class', 'axp-donut-chart-segment')
|
1808
|
-
.attr('fill', (d, i) => colorScale(i.toString()))
|
1809
|
-
.style('opacity', 0)
|
1810
|
-
.on('click', (event, d) => this.onSegmentClick(d.data))
|
1811
|
-
.on('mousemove', (event, d) => this.handleSegmentHover(event, d, total))
|
1812
|
-
.on('mouseleave', () => this._tooltipVisible.set(false));
|
1813
|
-
// Animate segments
|
1814
|
-
segments
|
1815
|
-
.transition()
|
1816
|
-
.duration(800)
|
1817
|
-
.ease(this.d3.easeCubicOut)
|
1818
|
-
.delay((d, i) => i * 50)
|
1819
|
-
.style('opacity', 1)
|
1820
|
-
.attrTween('d', (d) => {
|
1821
|
-
const interpolate = this.d3.interpolate({ startAngle: d.startAngle, endAngle: d.startAngle }, d);
|
1822
|
-
return (t) => arc(interpolate(t));
|
1823
|
-
});
|
1824
|
-
}
|
1825
|
-
handleSegmentHover(event, datum, total) {
|
1826
|
-
if (!this.showTooltip())
|
1827
|
-
return;
|
1828
|
-
const percentage = ((datum.data.value / total) * 100).toFixed(1);
|
1829
|
-
const segmentColor = this.getColor(this.chartDataArray().findIndex((item) => item.id === datum.data.id));
|
1830
|
-
this._tooltipData.set({
|
1831
|
-
title: datum.data.name,
|
1832
|
-
value: datum.data.value,
|
1833
|
-
percentage: `${percentage}%`,
|
1834
|
-
color: segmentColor,
|
1835
|
-
});
|
1836
|
-
this.updateTooltipPosition(event);
|
1837
|
-
this._tooltipVisible.set(true);
|
1838
|
-
}
|
1839
|
-
updateTooltipPosition(event) {
|
1840
|
-
const container = this.chartContainerEl().nativeElement.getBoundingClientRect();
|
1841
|
-
const x = event.clientX - container.left;
|
1842
|
-
const y = event.clientY - container.top;
|
1843
|
-
this._tooltipPosition.set({
|
1844
|
-
x: x,
|
1845
|
-
y: y,
|
1846
|
-
});
|
1847
|
-
}
|
1848
|
-
toggleSegment(item) {
|
1849
|
-
if (this.hiddenSegments.has(item.id)) {
|
1850
|
-
this.hiddenSegments.delete(item.id);
|
1851
|
-
}
|
1852
|
-
else {
|
1853
|
-
this.hiddenSegments.add(item.id);
|
1854
|
-
}
|
1855
|
-
// Hide tooltip when toggling segments
|
1856
|
-
this._tooltipVisible.set(false);
|
1857
|
-
this.updateChart();
|
1858
|
-
}
|
1859
|
-
calculateTotal() {
|
1860
|
-
return this.chartDataArray()
|
1861
|
-
.filter((item) => !this.hiddenSegments.has(item.id))
|
1862
|
-
.reduce((sum, item) => sum + item.value, 0);
|
1863
|
-
}
|
1864
|
-
showNoDataMessage(containerElement) {
|
1865
|
-
const messageContainer = this.d3
|
1866
|
-
.select(containerElement)
|
1867
|
-
.append('div')
|
1868
|
-
.attr('class', 'axp-donut-chart-no-data-message')
|
1869
|
-
.style('width', 'auto')
|
1870
|
-
.style('text-align', 'center');
|
1871
|
-
// Add an icon
|
1872
|
-
messageContainer
|
1873
|
-
.append('div')
|
1874
|
-
.attr('class', 'axp-donut-chart-no-data-icon')
|
1875
|
-
.html('<i class="fa-light fa-chart-pie-simple fa-2x"></i>');
|
1876
|
-
// Add text message and help text
|
1877
|
-
messageContainer.append('div').attr('class', 'axp-donut-chart-no-data-text').text('No data available');
|
1878
|
-
messageContainer
|
1879
|
-
.append('div')
|
1880
|
-
.attr('class', 'axp-donut-chart-no-data-help')
|
1881
|
-
.text('Please provide data in the correct format');
|
1882
|
-
// Position in center
|
1883
|
-
const container = containerElement.getBoundingClientRect();
|
1884
|
-
messageContainer.style('left', `${container.width / 2}px`).style('top', `${container.height / 2}px`);
|
1885
|
-
}
|
1886
|
-
// Add method to show message when all segments are hidden
|
1887
|
-
showAllSegmentsHiddenMessage(containerElement) {
|
1888
|
-
this.clearChart(containerElement);
|
1889
|
-
// Add a simple div to ensure proper positioning
|
1890
|
-
const wrapper = this.d3
|
1891
|
-
.select(containerElement)
|
1892
|
-
.append('div')
|
1893
|
-
.style('position', 'relative')
|
1894
|
-
.style('width', '100%')
|
1895
|
-
.style('height', '100%');
|
1896
|
-
const messageContainer = wrapper
|
1897
|
-
.append('div')
|
1898
|
-
.attr('class', 'axp-donut-chart-no-data-message')
|
1899
|
-
.style('position', 'absolute')
|
1900
|
-
.style('left', '50%')
|
1901
|
-
.style('top', '50%')
|
1902
|
-
.style('transform', 'translate(-50%, -50%)')
|
1903
|
-
.style('text-align', 'center')
|
1904
|
-
.style('z-index', '10')
|
1905
|
-
.style('background-color', 'rgba(255, 255, 255, 0.95)')
|
1906
|
-
.style('padding', '1.5rem')
|
1907
|
-
.style('border-radius', '0.5rem')
|
1908
|
-
.style('box-shadow', '0 2px 12px rgba(0, 0, 0, 0.08)')
|
1909
|
-
.style('width', '80%')
|
1910
|
-
.style('max-width', '300px');
|
1911
|
-
// Add an icon
|
1912
|
-
messageContainer
|
1913
|
-
.append('div')
|
1914
|
-
.attr('class', 'axp-donut-chart-no-data-icon')
|
1915
|
-
.style('color', 'var(--ax-text-muted, #999)')
|
1916
|
-
.style('margin-bottom', '0.75rem')
|
1917
|
-
.html('<i class="fa-light fa-eye-slash fa-2x"></i>');
|
1918
|
-
// Add text message and help text
|
1919
|
-
messageContainer
|
1920
|
-
.append('div')
|
1921
|
-
.attr('class', 'axp-donut-chart-no-data-text')
|
1922
|
-
.style('font-size', '1rem')
|
1923
|
-
.style('font-weight', '600')
|
1924
|
-
.style('color', 'var(--ax-text-color, #333)')
|
1925
|
-
.style('margin-bottom', '0.5rem')
|
1926
|
-
.text('All segments are hidden');
|
1927
|
-
messageContainer
|
1928
|
-
.append('div')
|
1929
|
-
.attr('class', 'axp-donut-chart-no-data-help')
|
1930
|
-
.style('font-size', '0.8rem')
|
1931
|
-
.style('color', 'var(--ax-text-muted, #999)')
|
1932
|
-
.text('Click on a legend item to show data');
|
1933
|
-
}
|
1934
|
-
addTotalDisplay(total) {
|
1935
|
-
if (!this.svg)
|
1936
|
-
return;
|
1937
|
-
// Remove any existing total display
|
1938
|
-
this.svg.selectAll('.axp-donut-chart-total-display').remove();
|
1939
|
-
// Create group for the total display
|
1940
|
-
const totalDisplay = this.svg
|
1941
|
-
.append('g')
|
1942
|
-
.attr('class', 'axp-donut-chart-total-display')
|
1943
|
-
.attr('text-anchor', 'middle');
|
1944
|
-
// Add total value
|
1945
|
-
totalDisplay
|
1946
|
-
.append('text')
|
1947
|
-
.attr('class', 'axp-donut-chart-total-value')
|
1948
|
-
.style('font-size', '1.8rem')
|
1949
|
-
.style('font-weight', '600')
|
1950
|
-
.style('fill', 'currentColor')
|
1951
|
-
.text(total.toLocaleString());
|
1952
|
-
// Add "Total" label
|
1953
|
-
totalDisplay
|
1954
|
-
.append('text')
|
1955
|
-
.attr('class', 'axp-donut-chart-total-label')
|
1956
|
-
.attr('dy', '1.4em')
|
1957
|
-
.style('font-size', '0.9rem')
|
1958
|
-
.style('fill', 'currentColor')
|
1959
|
-
.style('fill-opacity', '0.8')
|
1960
|
-
.text('Total');
|
1095
|
+
handleDonutChartSegmentClick(event) {
|
1096
|
+
//console.log(event);
|
1961
1097
|
}
|
1962
1098
|
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.0.3", ngImport: i0, type: AXPDonutChartWidgetViewComponent, deps: null, target: i0.ɵɵFactoryTarget.Component }); }
|
1963
|
-
static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "
|
1099
|
+
static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "19.0.3", type: AXPDonutChartWidgetViewComponent, isStandalone: true, selector: "ng-component", usesInheritance: true, ngImport: i0, template: "<ax-donut-chart\n [data]=\"donutChartData()\"\n [options]=\"donutChartOptions()\"\n (segmentClick)=\"handleDonutChartSegmentClick($event)\"\n></ax-donut-chart>\n", styles: [":host{display:block;width:100%;height:100%}\n"], dependencies: [{ kind: "component", type: AXDonutChartComponent, selector: "ax-donut-chart", inputs: ["data", "options"], outputs: ["segmentClick", "segmentHover"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
|
1964
1100
|
}
|
1965
1101
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.0.3", ngImport: i0, type: AXPDonutChartWidgetViewComponent, decorators: [{
|
1966
1102
|
type: Component,
|
1967
|
-
args: [{
|
1103
|
+
args: [{ imports: [AXDonutChartComponent], changeDetection: ChangeDetectionStrategy.OnPush, template: "<ax-donut-chart\n [data]=\"donutChartData()\"\n [options]=\"donutChartOptions()\"\n (segmentClick)=\"handleDonutChartSegmentClick($event)\"\n></ax-donut-chart>\n", styles: [":host{display:block;width:100%;height:100%}\n"] }]
|
1968
1104
|
}] });
|
1969
1105
|
|
1970
1106
|
var donutChartWidget_component = /*#__PURE__*/Object.freeze({
|
@@ -1980,79 +1116,141 @@ const AXPDonutChartWidget = {
|
|
1980
1116
|
type: 'dashboard',
|
1981
1117
|
icon: 'fa-light fa-donut',
|
1982
1118
|
properties: [
|
1119
|
+
cloneProperty(AXP_NAME_PROPERTY, { visible: false }),
|
1120
|
+
cloneProperty(AXP_DATA_PATH_PROPERTY, { visible: false }),
|
1121
|
+
// ====== Chart Title ======
|
1122
|
+
{
|
1123
|
+
name: 'title',
|
1124
|
+
title: 'Chart Title',
|
1125
|
+
group: AXP_APPEARANCE_PROPERTY_GROUP,
|
1126
|
+
schema: {
|
1127
|
+
defaultValue: '',
|
1128
|
+
dataType: 'string',
|
1129
|
+
interface: {
|
1130
|
+
name: 'title',
|
1131
|
+
path: 'options.title',
|
1132
|
+
type: AXPWidgetsCatalog.text,
|
1133
|
+
options: {
|
1134
|
+
placeholder: 'Enter chart title',
|
1135
|
+
},
|
1136
|
+
},
|
1137
|
+
},
|
1138
|
+
visible: true,
|
1139
|
+
},
|
1983
1140
|
// ====== Size & Layout ======
|
1984
1141
|
{
|
1985
|
-
name: '
|
1986
|
-
title: '
|
1142
|
+
name: 'width',
|
1143
|
+
title: 'Width',
|
1987
1144
|
group: AXP_STYLING_PROPERTY_GROUP,
|
1988
1145
|
schema: {
|
1989
1146
|
defaultValue: 300,
|
1990
1147
|
dataType: 'number',
|
1991
1148
|
interface: {
|
1992
|
-
name: '
|
1993
|
-
path: 'options.
|
1149
|
+
name: 'width',
|
1150
|
+
path: 'options.width',
|
1994
1151
|
type: AXPWidgetsCatalog.number,
|
1995
1152
|
options: {
|
1996
1153
|
minValue: 200,
|
1997
|
-
maxValue:
|
1154
|
+
maxValue: 1200,
|
1998
1155
|
},
|
1999
1156
|
},
|
2000
1157
|
},
|
2001
1158
|
visible: true,
|
2002
1159
|
},
|
2003
1160
|
{
|
2004
|
-
name: '
|
2005
|
-
title: '
|
1161
|
+
name: 'height',
|
1162
|
+
title: 'Height',
|
2006
1163
|
group: AXP_STYLING_PROPERTY_GROUP,
|
2007
1164
|
schema: {
|
2008
1165
|
defaultValue: 300,
|
2009
1166
|
dataType: 'number',
|
2010
1167
|
interface: {
|
2011
|
-
name: '
|
2012
|
-
path: 'options.
|
1168
|
+
name: 'height',
|
1169
|
+
path: 'options.height',
|
2013
1170
|
type: AXPWidgetsCatalog.number,
|
2014
1171
|
options: {
|
2015
1172
|
minValue: 200,
|
2016
|
-
maxValue:
|
1173
|
+
maxValue: 800,
|
2017
1174
|
},
|
2018
1175
|
},
|
2019
1176
|
},
|
2020
1177
|
visible: true,
|
2021
1178
|
},
|
2022
|
-
// ======
|
1179
|
+
// ====== Donut Appearance ======
|
2023
1180
|
{
|
2024
|
-
name: '
|
2025
|
-
title: '
|
1181
|
+
name: 'donutWidth',
|
1182
|
+
title: 'Donut Width',
|
2026
1183
|
group: AXP_APPEARANCE_PROPERTY_GROUP,
|
2027
1184
|
schema: {
|
2028
|
-
defaultValue:
|
2029
|
-
dataType: '
|
1185
|
+
defaultValue: 35,
|
1186
|
+
dataType: 'number',
|
2030
1187
|
interface: {
|
2031
|
-
name: '
|
2032
|
-
path: 'options.
|
2033
|
-
type: AXPWidgetsCatalog.
|
1188
|
+
name: 'donutWidth',
|
1189
|
+
path: 'options.donutWidth',
|
1190
|
+
type: AXPWidgetsCatalog.number,
|
1191
|
+
options: {
|
1192
|
+
placeholder: '10-80',
|
1193
|
+
minValue: 10,
|
1194
|
+
maxValue: 80,
|
1195
|
+
},
|
2034
1196
|
},
|
2035
1197
|
},
|
2036
1198
|
visible: true,
|
2037
1199
|
},
|
2038
1200
|
{
|
2039
|
-
name: '
|
2040
|
-
title: '
|
1201
|
+
name: 'cornerRadius',
|
1202
|
+
title: 'Corner Radius',
|
2041
1203
|
group: AXP_APPEARANCE_PROPERTY_GROUP,
|
2042
1204
|
schema: {
|
2043
|
-
defaultValue:
|
2044
|
-
dataType: '
|
1205
|
+
defaultValue: 4,
|
1206
|
+
dataType: 'number',
|
2045
1207
|
interface: {
|
2046
|
-
name: '
|
2047
|
-
path: 'options.
|
2048
|
-
type: AXPWidgetsCatalog.
|
1208
|
+
name: 'cornerRadius',
|
1209
|
+
path: 'options.cornerRadius',
|
1210
|
+
type: AXPWidgetsCatalog.number,
|
2049
1211
|
options: {
|
2050
|
-
|
1212
|
+
placeholder: '0-20',
|
1213
|
+
minValue: 0,
|
1214
|
+
maxValue: 20,
|
2051
1215
|
},
|
2052
1216
|
},
|
2053
1217
|
},
|
2054
1218
|
visible: true,
|
2055
1219
|
},
|
1220
|
+
// ====== Legend ======
|
1221
|
+
// {
|
1222
|
+
// name: 'showLegend',
|
1223
|
+
// title: 'Show Legend',
|
1224
|
+
// group: AXP_APPEARANCE_PROPERTY_GROUP,
|
1225
|
+
// schema: {
|
1226
|
+
// defaultValue: true,
|
1227
|
+
// dataType: 'boolean',
|
1228
|
+
// interface: {
|
1229
|
+
// name: 'showLegend',
|
1230
|
+
// path: 'options.showLegend',
|
1231
|
+
// type: AXPWidgetsCatalog.toggle,
|
1232
|
+
// },
|
1233
|
+
// },
|
1234
|
+
// visible: true,
|
1235
|
+
// },
|
1236
|
+
// {
|
1237
|
+
// name: 'legendPosition',
|
1238
|
+
// title: 'Legend Position',
|
1239
|
+
// group: AXP_APPEARANCE_PROPERTY_GROUP,
|
1240
|
+
// schema: {
|
1241
|
+
// defaultValue: 'right',
|
1242
|
+
// dataType: 'string',
|
1243
|
+
// interface: {
|
1244
|
+
// name: 'legendPosition',
|
1245
|
+
// path: 'options.legendPosition',
|
1246
|
+
// type: AXPWidgetsCatalog.select,
|
1247
|
+
// options: {
|
1248
|
+
// dataSource: ['right', 'bottom'],
|
1249
|
+
// },
|
1250
|
+
// },
|
1251
|
+
// },
|
1252
|
+
// visible: true,
|
1253
|
+
// },
|
2056
1254
|
// ====== Tooltip ======
|
2057
1255
|
{
|
2058
1256
|
name: 'showTooltip',
|
@@ -2069,42 +1267,52 @@ const AXPDonutChartWidget = {
|
|
2069
1267
|
},
|
2070
1268
|
visible: true,
|
2071
1269
|
},
|
2072
|
-
// ======
|
1270
|
+
// ====== Animation Settings ======
|
2073
1271
|
{
|
2074
|
-
name: '
|
2075
|
-
title: '
|
1272
|
+
name: 'animationEasing',
|
1273
|
+
title: 'Animation Easing',
|
2076
1274
|
group: AXP_APPEARANCE_PROPERTY_GROUP,
|
2077
1275
|
schema: {
|
2078
|
-
defaultValue:
|
2079
|
-
dataType: '
|
1276
|
+
defaultValue: 'cubic-out',
|
1277
|
+
dataType: 'string',
|
2080
1278
|
interface: {
|
2081
|
-
name: '
|
2082
|
-
path: 'options.
|
2083
|
-
type: AXPWidgetsCatalog.
|
1279
|
+
name: 'animationEasing',
|
1280
|
+
path: 'options.animationEasing',
|
1281
|
+
type: AXPWidgetsCatalog.select,
|
2084
1282
|
options: {
|
2085
|
-
|
2086
|
-
|
2087
|
-
|
1283
|
+
dataSource: [
|
1284
|
+
{ value: 'linear', text: 'Linear' },
|
1285
|
+
{ value: 'ease', text: 'Ease' },
|
1286
|
+
{ value: 'ease-in', text: 'Ease In' },
|
1287
|
+
{ value: 'ease-out', text: 'Ease Out' },
|
1288
|
+
{ value: 'ease-in-out', text: 'Ease In Out' },
|
1289
|
+
{ value: 'cubic', text: 'Cubic' },
|
1290
|
+
{ value: 'cubic-in', text: 'Cubic In' },
|
1291
|
+
{ value: 'cubic-out', text: 'Cubic Out' },
|
1292
|
+
{ value: 'cubic-in-out', text: 'Cubic In Out' },
|
1293
|
+
],
|
1294
|
+
textField: 'text',
|
1295
|
+
valueField: 'value',
|
2088
1296
|
},
|
2089
1297
|
},
|
2090
1298
|
},
|
2091
1299
|
visible: true,
|
2092
1300
|
},
|
2093
1301
|
{
|
2094
|
-
name: '
|
2095
|
-
title: '
|
1302
|
+
name: 'animationDuration',
|
1303
|
+
title: 'Animation Duration',
|
2096
1304
|
group: AXP_APPEARANCE_PROPERTY_GROUP,
|
2097
1305
|
schema: {
|
2098
|
-
defaultValue:
|
1306
|
+
defaultValue: 800,
|
2099
1307
|
dataType: 'number',
|
2100
1308
|
interface: {
|
2101
|
-
name: '
|
2102
|
-
path: 'options.
|
1309
|
+
name: 'animationDuration',
|
1310
|
+
path: 'options.animationDuration',
|
2103
1311
|
type: AXPWidgetsCatalog.number,
|
2104
1312
|
options: {
|
2105
|
-
placeholder: '0-
|
1313
|
+
placeholder: '0-2000',
|
2106
1314
|
minValue: 0,
|
2107
|
-
maxValue:
|
1315
|
+
maxValue: 2000,
|
2108
1316
|
},
|
2109
1317
|
},
|
2110
1318
|
},
|
@@ -2132,370 +1340,18 @@ const AXPDonutChartWidget = {
|
|
2132
1340
|
* Gauge Chart Widget Component
|
2133
1341
|
* Renders a semi-circular gauge chart with animated needle and thresholds
|
2134
1342
|
*/
|
2135
|
-
class AXPGaugeChartWidgetViewComponent extends
|
1343
|
+
class AXPGaugeChartWidgetViewComponent extends AXPValueWidgetComponent {
|
2136
1344
|
constructor() {
|
2137
1345
|
super(...arguments);
|
2138
|
-
this.
|
2139
|
-
this.
|
2140
|
-
this.chartEl = viewChild.required('chart');
|
2141
|
-
// Default values
|
2142
|
-
this.backgroundColor = 'transparent';
|
2143
|
-
this.baseColor = '#e2e8f0';
|
2144
|
-
this.labelFontSize = 16;
|
2145
|
-
this.showValue = true;
|
2146
|
-
this.valueColor = '#6366f1';
|
2147
|
-
this.valueFontSize = 24;
|
2148
|
-
// Default values as computed properties
|
2149
|
-
this.minValue = computed(() => this.options()['minValue'] ?? 0);
|
2150
|
-
this.maxValue = computed(() => this.options()['maxValue'] ?? 100);
|
2151
|
-
this.thresholds = computed(() => this.options()['thresholds'] ?? []);
|
2152
|
-
this.label = computed(() => this.options()['label'] ?? '');
|
2153
|
-
this.width = computed(() => this.options()['width'] ?? 300);
|
2154
|
-
this.height = computed(() => this.options()['height'] ?? 300);
|
2155
|
-
this.gaugeWidth = computed(() => this.options()['gaugeWidth'] ?? 22);
|
2156
|
-
this.cornerRadius = computed(() => this.options()['cornerRadius'] ?? 5);
|
2157
|
-
}
|
2158
|
-
/**
|
2159
|
-
* Creates the gauge chart with all elements
|
2160
|
-
*/
|
2161
|
-
createChart() {
|
2162
|
-
// Clear any existing chart
|
2163
|
-
this.d3.select(this.chartEl().nativeElement).selectAll('*').remove();
|
2164
|
-
// Calculate responsive dimensions
|
2165
|
-
const containerElement = this.chartContainerEl().nativeElement;
|
2166
|
-
const containerWidth = containerElement.clientWidth;
|
2167
|
-
const containerHeight = containerElement.clientHeight;
|
2168
|
-
// Determine size based on explicit dimensions or container size
|
2169
|
-
const options = this.options();
|
2170
|
-
let size;
|
2171
|
-
if (options.width && options.height) {
|
2172
|
-
// Use explicit dimensions if provided
|
2173
|
-
size = Math.min(options.width, options.height * 2);
|
2174
|
-
}
|
2175
|
-
else {
|
2176
|
-
// Use container dimensions with minimum constraints
|
2177
|
-
const minDim = Math.max(200, Math.min(containerWidth, containerHeight));
|
2178
|
-
size = Math.min(containerWidth, containerHeight * 2, minDim * 2);
|
2179
|
-
}
|
2180
|
-
const margin = size * 0.1;
|
2181
|
-
// Set up SVG with responsive viewBox
|
2182
|
-
const svg = this.d3
|
2183
|
-
.select(this.chartEl().nativeElement)
|
2184
|
-
.attr('width', '100%')
|
2185
|
-
.attr('height', '100%')
|
2186
|
-
.attr('viewBox', `0 0 ${size} ${size / 2}`)
|
2187
|
-
.attr('preserveAspectRatio', 'xMidYMid meet');
|
2188
|
-
// Create a group for the chart with margin and move it to show only the top half
|
2189
|
-
const chartGroup = svg.append('g').attr('transform', `translate(${size / 2}, ${size / 2 - margin})`);
|
2190
|
-
// Define gauge parameters
|
2191
|
-
const radius = size / 2 - margin;
|
2192
|
-
const innerRadius = radius - this.gaugeWidth();
|
2193
|
-
const outerRadius = radius;
|
2194
|
-
// Create gradient definitions
|
2195
|
-
this.createGradients(svg, this.thresholds());
|
2196
|
-
// Draw the background arc
|
2197
|
-
this.drawBackgroundArc(chartGroup, innerRadius, outerRadius, this.cornerRadius());
|
2198
|
-
// Draw the threshold arcs if thresholds exist
|
2199
|
-
if (this.thresholds().length > 0) {
|
2200
|
-
this.drawThresholds(chartGroup, innerRadius, outerRadius, this.minValue(), this.maxValue(), this.thresholds(), this.cornerRadius());
|
2201
|
-
}
|
2202
|
-
// Draw tick marks
|
2203
|
-
this.drawTicks(chartGroup, outerRadius, this.minValue(), this.maxValue());
|
2204
|
-
// Draw the dial/needle with animation
|
2205
|
-
this.drawDial(chartGroup, radius, this.chartData() ?? 0, this.minValue(), this.maxValue());
|
2206
|
-
// Draw the value display (after the dial so it's on top)
|
2207
|
-
if (this.showValue) {
|
2208
|
-
this.drawValueDisplay(chartGroup, this.chartData() ?? 0, this.label(), radius);
|
2209
|
-
}
|
2210
|
-
}
|
2211
|
-
updateChart() {
|
2212
|
-
this.createChart();
|
2213
|
-
}
|
2214
|
-
cleanupChart() {
|
2215
|
-
if (this.chartEl()?.nativeElement) {
|
2216
|
-
this.d3.select(this.chartEl().nativeElement).selectAll('*').remove();
|
2217
|
-
}
|
2218
|
-
}
|
2219
|
-
/**
|
2220
|
-
* Creates gradient definitions for thresholds
|
2221
|
-
*/
|
2222
|
-
createGradients(svg, thresholds) {
|
2223
|
-
const defs = svg.append('defs');
|
2224
|
-
// Create a radial gradient for the background
|
2225
|
-
const bgGradient = defs
|
2226
|
-
.append('radialGradient')
|
2227
|
-
.attr('id', 'gauge-bg-gradient')
|
2228
|
-
.attr('cx', '50%')
|
2229
|
-
.attr('cy', '50%')
|
2230
|
-
.attr('r', '50%')
|
2231
|
-
.attr('gradientUnits', 'userSpaceOnUse');
|
2232
|
-
if (thresholds.length === 0) {
|
2233
|
-
// Default gradient when no thresholds are provided
|
2234
|
-
bgGradient
|
2235
|
-
.append('stop')
|
2236
|
-
.attr('offset', '0%')
|
2237
|
-
.attr('stop-color', this.d3.color(this.valueColor)?.brighter(0.5).toString() || this.valueColor);
|
2238
|
-
bgGradient.append('stop').attr('offset', '100%').attr('stop-color', this.valueColor);
|
2239
|
-
}
|
2240
|
-
else {
|
2241
|
-
bgGradient
|
2242
|
-
.append('stop')
|
2243
|
-
.attr('offset', '0%')
|
2244
|
-
.attr('stop-color', this.d3.color(this.baseColor)?.brighter(0.5).toString() || this.baseColor);
|
2245
|
-
bgGradient.append('stop').attr('offset', '100%').attr('stop-color', this.baseColor);
|
2246
|
-
// Create gradients for each threshold
|
2247
|
-
thresholds.forEach((threshold, i) => {
|
2248
|
-
const gradient = defs
|
2249
|
-
.append('linearGradient')
|
2250
|
-
.attr('id', `threshold-gradient-${i}`)
|
2251
|
-
.attr('gradientUnits', 'userSpaceOnUse')
|
2252
|
-
.attr('x1', '-1')
|
2253
|
-
.attr('y1', '0')
|
2254
|
-
.attr('x2', '1')
|
2255
|
-
.attr('y2', '0');
|
2256
|
-
gradient
|
2257
|
-
.append('stop')
|
2258
|
-
.attr('offset', '0%')
|
2259
|
-
.attr('stop-color', this.d3.color(threshold.color)?.brighter(0.5).toString() || threshold.color);
|
2260
|
-
gradient.append('stop').attr('offset', '100%').attr('stop-color', threshold.color);
|
2261
|
-
});
|
2262
|
-
}
|
2263
|
-
}
|
2264
|
-
/**
|
2265
|
-
* Draws the background arc
|
2266
|
-
*/
|
2267
|
-
drawBackgroundArc(chartGroup, innerRadius, outerRadius, cornerRadius) {
|
2268
|
-
const backgroundArc = this.d3
|
2269
|
-
.arc()
|
2270
|
-
.innerRadius(innerRadius)
|
2271
|
-
.outerRadius(outerRadius)
|
2272
|
-
.startAngle(-Math.PI / 2) // Start from bottom (-90 degrees)
|
2273
|
-
.endAngle(Math.PI / 2) // End at top (90 degrees)
|
2274
|
-
.cornerRadius(cornerRadius);
|
2275
|
-
chartGroup
|
2276
|
-
.append('path')
|
2277
|
-
.attr('d', backgroundArc({
|
2278
|
-
innerRadius,
|
2279
|
-
outerRadius,
|
2280
|
-
startAngle: -Math.PI / 2,
|
2281
|
-
endAngle: Math.PI / 2,
|
2282
|
-
}))
|
2283
|
-
.attr('fill', this.backgroundColor === 'transparent' ? 'url(#gauge-bg-gradient)' : this.backgroundColor)
|
2284
|
-
.attr('filter', 'drop-shadow(0px 2px 3px rgba(0,0,0,0.1))');
|
2285
|
-
}
|
2286
|
-
/**
|
2287
|
-
* Draws the threshold arcs with colors
|
2288
|
-
*/
|
2289
|
-
drawThresholds(chartGroup, innerRadius, outerRadius, minValue, maxValue, thresholds, cornerRadius) {
|
2290
|
-
const arc = this.d3
|
2291
|
-
.arc()
|
2292
|
-
.innerRadius(innerRadius)
|
2293
|
-
.outerRadius(outerRadius * 0.98)
|
2294
|
-
.cornerRadius(cornerRadius);
|
2295
|
-
// Sort thresholds by value in ascending order
|
2296
|
-
const sortedThresholds = [...thresholds].sort((a, b) => a.value - b.value);
|
2297
|
-
// Calculate all angles first using the color angle calculation
|
2298
|
-
const angles = sortedThresholds.map((t) => this.scaleValueToColorAngle(t.value, minValue, maxValue));
|
2299
|
-
// Start from the minimum value angle
|
2300
|
-
let previousEndAngle = this.scaleValueToColorAngle(minValue, minValue, maxValue);
|
2301
|
-
sortedThresholds.forEach((threshold, i) => {
|
2302
|
-
const endAngle = angles[i];
|
2303
|
-
chartGroup
|
2304
|
-
.append('path')
|
2305
|
-
.attr('d', arc({
|
2306
|
-
innerRadius,
|
2307
|
-
outerRadius,
|
2308
|
-
startAngle: previousEndAngle,
|
2309
|
-
endAngle,
|
2310
|
-
}))
|
2311
|
-
.attr('fill', `url(#threshold-gradient-${i})`)
|
2312
|
-
.attr('stroke', 'rgba(255,255,255,0.3)')
|
2313
|
-
.attr('stroke-width', 1);
|
2314
|
-
previousEndAngle = endAngle;
|
2315
|
-
});
|
2316
|
-
// Fill the remaining space to maxValue if needed
|
2317
|
-
const lastEndAngle = this.scaleValueToColorAngle(maxValue, minValue, maxValue);
|
2318
|
-
if (previousEndAngle < lastEndAngle) {
|
2319
|
-
chartGroup
|
2320
|
-
.append('path')
|
2321
|
-
.attr('d', arc({
|
2322
|
-
innerRadius,
|
2323
|
-
outerRadius,
|
2324
|
-
startAngle: previousEndAngle,
|
2325
|
-
endAngle: lastEndAngle,
|
2326
|
-
}))
|
2327
|
-
.attr('fill', `url(#threshold-gradient-${sortedThresholds.length - 1})`)
|
2328
|
-
.attr('stroke', 'rgba(255,255,255,0.3)')
|
2329
|
-
.attr('stroke-width', 1);
|
2330
|
-
}
|
2331
|
-
}
|
2332
|
-
/**
|
2333
|
-
* Draws tick marks around the gauge
|
2334
|
-
*/
|
2335
|
-
drawTicks(chartGroup, radius, minValue, maxValue) {
|
2336
|
-
const tickCount = 10;
|
2337
|
-
const minorTickCount = 40;
|
2338
|
-
// Draw minor ticks
|
2339
|
-
for (let i = 0; i <= minorTickCount; i++) {
|
2340
|
-
const value = minValue + (i / minorTickCount) * (maxValue - minValue);
|
2341
|
-
const angle = this.scaleValueToAngle(value, minValue, maxValue);
|
2342
|
-
const outerPoint = {
|
2343
|
-
x: radius * 0.9 * Math.cos(angle),
|
2344
|
-
y: radius * 0.9 * Math.sin(angle),
|
2345
|
-
};
|
2346
|
-
const innerPoint = {
|
2347
|
-
x: radius * 0.87 * Math.cos(angle),
|
2348
|
-
y: radius * 0.87 * Math.sin(angle),
|
2349
|
-
};
|
2350
|
-
chartGroup
|
2351
|
-
.append('line')
|
2352
|
-
.attr('x1', innerPoint.x)
|
2353
|
-
.attr('y1', innerPoint.y)
|
2354
|
-
.attr('x2', outerPoint.x)
|
2355
|
-
.attr('y2', outerPoint.y)
|
2356
|
-
.attr('stroke', '#adb5bd')
|
2357
|
-
.attr('stroke-width', 0.5);
|
2358
|
-
}
|
2359
|
-
// Draw major ticks and labels
|
2360
|
-
for (let i = 0; i <= tickCount; i++) {
|
2361
|
-
const value = minValue + (i / tickCount) * (maxValue - minValue);
|
2362
|
-
const angle = this.scaleValueToAngle(value, minValue, maxValue);
|
2363
|
-
const outerPoint = {
|
2364
|
-
x: radius * 0.92 * Math.cos(angle),
|
2365
|
-
y: radius * 0.92 * Math.sin(angle),
|
2366
|
-
};
|
2367
|
-
const innerPoint = {
|
2368
|
-
x: radius * 0.85 * Math.cos(angle),
|
2369
|
-
y: radius * 0.85 * Math.sin(angle),
|
2370
|
-
};
|
2371
|
-
// Major tick line
|
2372
|
-
chartGroup
|
2373
|
-
.append('line')
|
2374
|
-
.attr('x1', innerPoint.x)
|
2375
|
-
.attr('y1', innerPoint.y)
|
2376
|
-
.attr('x2', outerPoint.x)
|
2377
|
-
.attr('y2', outerPoint.y)
|
2378
|
-
.attr('stroke', '#adb5bd')
|
2379
|
-
.attr('stroke-width', 2);
|
2380
|
-
// Label position with offset
|
2381
|
-
const labelRadius = radius * 1.15;
|
2382
|
-
const labelX = labelRadius * Math.cos(angle);
|
2383
|
-
const labelY = labelRadius * Math.sin(angle);
|
2384
|
-
// Add tick value label
|
2385
|
-
chartGroup
|
2386
|
-
.append('text')
|
2387
|
-
.attr('x', labelX)
|
2388
|
-
.attr('y', labelY)
|
2389
|
-
.attr('text-anchor', 'middle')
|
2390
|
-
.style('font-size', `${radius * 0.1}px`)
|
2391
|
-
.style('font-weight', '500')
|
2392
|
-
.style('fill', 'currentColor')
|
2393
|
-
.text(value.toFixed(0));
|
2394
|
-
}
|
2395
|
-
}
|
2396
|
-
/**
|
2397
|
-
* Draws the value display in the center
|
2398
|
-
*/
|
2399
|
-
drawValueDisplay(chartGroup, value, label, radius) {
|
2400
|
-
// Value text - positioned below the needle pivot
|
2401
|
-
chartGroup
|
2402
|
-
.append('text')
|
2403
|
-
.attr('class', 'gauge-value')
|
2404
|
-
.attr('x', 0)
|
2405
|
-
.attr('y', radius * 0.25) // Moved up from 0.3
|
2406
|
-
.attr('text-anchor', 'middle')
|
2407
|
-
.attr('dominant-baseline', 'central')
|
2408
|
-
.style('font-size', `${this.valueFontSize}px`)
|
2409
|
-
.style('font-weight', 'bold')
|
2410
|
-
.style('fill', 'currentColor')
|
2411
|
-
.text(value.toFixed(1));
|
2412
|
-
// Label text
|
2413
|
-
chartGroup
|
2414
|
-
.append('text')
|
2415
|
-
.attr('class', 'gauge-label')
|
2416
|
-
.attr('x', 0)
|
2417
|
-
.attr('y', radius * 0.45) // Keeping this position to create more space
|
2418
|
-
.attr('text-anchor', 'middle')
|
2419
|
-
.attr('dominant-baseline', 'central')
|
2420
|
-
.style('font-size', `${this.labelFontSize}px`)
|
2421
|
-
.style('fill', '#6c757d')
|
2422
|
-
.text(label);
|
2423
|
-
}
|
2424
|
-
/**
|
2425
|
-
* Draws the dial/needle with animation
|
2426
|
-
*/
|
2427
|
-
drawDial(chartGroup, radius, value, minValue, maxValue) {
|
2428
|
-
const needleGroup = chartGroup.append('g');
|
2429
|
-
const valueAngle = this.scaleValueToAngle(value, minValue, maxValue); // Use regular angle for needle
|
2430
|
-
// Draw needle base (circle)
|
2431
|
-
needleGroup
|
2432
|
-
.append('circle')
|
2433
|
-
.attr('cx', 0)
|
2434
|
-
.attr('cy', 0)
|
2435
|
-
.attr('r', radius * 0.08)
|
2436
|
-
.attr('fill', 'url(#gauge-bg-gradient)')
|
2437
|
-
.attr('stroke', '#6c757d')
|
2438
|
-
.attr('stroke-width', 1);
|
2439
|
-
// Inner circle
|
2440
|
-
needleGroup
|
2441
|
-
.append('circle')
|
2442
|
-
.attr('cx', 0)
|
2443
|
-
.attr('cy', 0)
|
2444
|
-
.attr('r', radius * 0.04)
|
2445
|
-
.attr('fill', '#495057');
|
2446
|
-
// Create needle
|
2447
|
-
const needlePath = needleGroup
|
2448
|
-
.append('path')
|
2449
|
-
.attr('d', this.createNeedlePath(radius))
|
2450
|
-
.attr('fill', '#dc3545')
|
2451
|
-
.attr('transform', `rotate(${this.radiansToDegrees(-Math.PI)})`) // Start at left (-180 degrees)
|
2452
|
-
.attr('filter', 'drop-shadow(0px 1px 2px rgba(0,0,0,0.3))');
|
2453
|
-
// Animate the needle
|
2454
|
-
needlePath
|
2455
|
-
.transition()
|
2456
|
-
.duration(800)
|
2457
|
-
.ease(this.d3.easeCubicOut)
|
2458
|
-
.attrTween('transform', () => {
|
2459
|
-
const interpolate = this.d3.interpolate(-Math.PI, valueAngle);
|
2460
|
-
return (t) => `rotate(${this.radiansToDegrees(interpolate(t))})`;
|
2461
|
-
});
|
2462
|
-
}
|
2463
|
-
/**
|
2464
|
-
* Creates a path for the needle
|
2465
|
-
*/
|
2466
|
-
createNeedlePath(radius) {
|
2467
|
-
const needleLength = radius * 0.75;
|
2468
|
-
const needleBaseWidth = radius * 0.04;
|
2469
|
-
return `M 0 -${needleBaseWidth} L ${needleLength} 0 L 0 ${needleBaseWidth} Z`;
|
2470
|
-
}
|
2471
|
-
/**
|
2472
|
-
* Scales a value to an angle for needle positioning
|
2473
|
-
*/
|
2474
|
-
scaleValueToAngle(value, min, max) {
|
2475
|
-
const scaledValue = (value - min) / (max - min);
|
2476
|
-
// Map from -180 to 0 degrees in radians, starting from the left
|
2477
|
-
return -Math.PI + scaledValue * Math.PI;
|
2478
|
-
}
|
2479
|
-
/**
|
2480
|
-
* Scales a value to an angle for threshold colors
|
2481
|
-
*/
|
2482
|
-
scaleValueToColorAngle(value, min, max) {
|
2483
|
-
const scaledValue = (value - min) / (max - min);
|
2484
|
-
// Map from -90 to 90 degrees in radians (-π/2 to π/2), starting from the bottom
|
2485
|
-
return -Math.PI / 2 + scaledValue * Math.PI;
|
2486
|
-
}
|
2487
|
-
/**
|
2488
|
-
* Converts radians to degrees
|
2489
|
-
*/
|
2490
|
-
radiansToDegrees(radians) {
|
2491
|
-
return radians * (180 / Math.PI);
|
1346
|
+
this.gaugeChartValue = computed(() => this.getValue());
|
1347
|
+
this.gaugeChartOptions = computed(() => this.options());
|
2492
1348
|
}
|
2493
1349
|
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.0.3", ngImport: i0, type: AXPGaugeChartWidgetViewComponent, deps: null, target: i0.ɵɵFactoryTarget.Component }); }
|
2494
|
-
static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "
|
1350
|
+
static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "19.0.3", type: AXPGaugeChartWidgetViewComponent, isStandalone: true, selector: "ng-component", usesInheritance: true, ngImport: i0, template: "<ax-gauge-chart [value]=\"gaugeChartValue()\" [options]=\"gaugeChartOptions()\"></ax-gauge-chart>\n", styles: [":host{display:block;width:100%;height:100%}\n"], dependencies: [{ kind: "component", type: AXGaugeChartComponent, selector: "ax-gauge-chart", inputs: ["value", "options"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
|
2495
1351
|
}
|
2496
1352
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.0.3", ngImport: i0, type: AXPGaugeChartWidgetViewComponent, decorators: [{
|
2497
1353
|
type: Component,
|
2498
|
-
args: [{
|
1354
|
+
args: [{ imports: [AXGaugeChartComponent], changeDetection: ChangeDetectionStrategy.OnPush, template: "<ax-gauge-chart [value]=\"gaugeChartValue()\" [options]=\"gaugeChartOptions()\"></ax-gauge-chart>\n", styles: [":host{display:block;width:100%;height:100%}\n"] }]
|
2499
1355
|
}] });
|
2500
1356
|
|
2501
1357
|
var gaugeChartWidget_component = /*#__PURE__*/Object.freeze({
|
@@ -2510,27 +1366,28 @@ const AXPGaugeChartWidget = {
|
|
2510
1366
|
type: 'dashboard',
|
2511
1367
|
icon: 'fa-light fa-gauge',
|
2512
1368
|
properties: [
|
2513
|
-
|
1369
|
+
cloneProperty(AXP_NAME_PROPERTY, { visible: false }),
|
1370
|
+
cloneProperty(AXP_DATA_PATH_PROPERTY, { visible: false }),
|
1371
|
+
// ====== Chart Title ======
|
2514
1372
|
{
|
2515
|
-
name: '
|
2516
|
-
title: '
|
2517
|
-
group:
|
1373
|
+
name: 'title',
|
1374
|
+
title: 'Chart Title',
|
1375
|
+
group: AXP_APPEARANCE_PROPERTY_GROUP,
|
2518
1376
|
schema: {
|
2519
|
-
defaultValue:
|
2520
|
-
dataType: '
|
1377
|
+
defaultValue: '',
|
1378
|
+
dataType: 'string',
|
2521
1379
|
interface: {
|
2522
|
-
name: '
|
2523
|
-
path: 'options.
|
2524
|
-
type: AXPWidgetsCatalog.
|
1380
|
+
name: 'title',
|
1381
|
+
path: 'options.title',
|
1382
|
+
type: AXPWidgetsCatalog.text,
|
2525
1383
|
options: {
|
2526
|
-
placeholder: '
|
2527
|
-
minValue: 1,
|
2528
|
-
maxValue: 800,
|
1384
|
+
placeholder: 'Enter chart title',
|
2529
1385
|
},
|
2530
1386
|
},
|
2531
1387
|
},
|
2532
1388
|
visible: true,
|
2533
1389
|
},
|
1390
|
+
// ====== Layout & Dimensions ======
|
2534
1391
|
{
|
2535
1392
|
name: 'width',
|
2536
1393
|
title: 'Width',
|
@@ -2551,6 +1408,26 @@ const AXPGaugeChartWidget = {
|
|
2551
1408
|
},
|
2552
1409
|
visible: true,
|
2553
1410
|
},
|
1411
|
+
{
|
1412
|
+
name: 'height',
|
1413
|
+
title: 'Height',
|
1414
|
+
group: AXP_STYLING_PROPERTY_GROUP,
|
1415
|
+
schema: {
|
1416
|
+
defaultValue: 300,
|
1417
|
+
dataType: 'number',
|
1418
|
+
interface: {
|
1419
|
+
name: 'height',
|
1420
|
+
path: 'options.height',
|
1421
|
+
type: AXPWidgetsCatalog.number,
|
1422
|
+
options: {
|
1423
|
+
placeholder: '1-800',
|
1424
|
+
minValue: 1,
|
1425
|
+
maxValue: 800,
|
1426
|
+
},
|
1427
|
+
},
|
1428
|
+
},
|
1429
|
+
visible: true,
|
1430
|
+
},
|
2554
1431
|
// ====== Gauge Configuration ======
|
2555
1432
|
{
|
2556
1433
|
name: 'minValue',
|
@@ -2639,11 +1516,62 @@ const AXPGaugeChartWidget = {
|
|
2639
1516
|
},
|
2640
1517
|
visible: true,
|
2641
1518
|
},
|
2642
|
-
|
2643
|
-
|
2644
|
-
|
2645
|
-
|
2646
|
-
|
1519
|
+
// ====== Animation Settings ======
|
1520
|
+
{
|
1521
|
+
name: 'animationEasing',
|
1522
|
+
title: 'Animation Easing',
|
1523
|
+
group: AXP_APPEARANCE_PROPERTY_GROUP,
|
1524
|
+
schema: {
|
1525
|
+
defaultValue: 'cubic-out',
|
1526
|
+
dataType: 'string',
|
1527
|
+
interface: {
|
1528
|
+
name: 'animationEasing',
|
1529
|
+
path: 'options.animationEasing',
|
1530
|
+
type: AXPWidgetsCatalog.select,
|
1531
|
+
options: {
|
1532
|
+
dataSource: [
|
1533
|
+
{ value: 'linear', text: 'Linear' },
|
1534
|
+
{ value: 'ease', text: 'Ease' },
|
1535
|
+
{ value: 'ease-in', text: 'Ease In' },
|
1536
|
+
{ value: 'ease-out', text: 'Ease Out' },
|
1537
|
+
{ value: 'ease-in-out', text: 'Ease In Out' },
|
1538
|
+
{ value: 'cubic', text: 'Cubic' },
|
1539
|
+
{ value: 'cubic-in', text: 'Cubic In' },
|
1540
|
+
{ value: 'cubic-out', text: 'Cubic Out' },
|
1541
|
+
{ value: 'cubic-in-out', text: 'Cubic In Out' },
|
1542
|
+
],
|
1543
|
+
textField: 'text',
|
1544
|
+
valueField: 'value',
|
1545
|
+
},
|
1546
|
+
},
|
1547
|
+
},
|
1548
|
+
visible: true,
|
1549
|
+
},
|
1550
|
+
{
|
1551
|
+
name: 'animationDuration',
|
1552
|
+
title: 'Animation Duration',
|
1553
|
+
group: AXP_APPEARANCE_PROPERTY_GROUP,
|
1554
|
+
schema: {
|
1555
|
+
defaultValue: 800,
|
1556
|
+
dataType: 'number',
|
1557
|
+
interface: {
|
1558
|
+
name: 'animationDuration',
|
1559
|
+
path: 'options.animationDuration',
|
1560
|
+
type: AXPWidgetsCatalog.number,
|
1561
|
+
options: {
|
1562
|
+
placeholder: '0-2000',
|
1563
|
+
minValue: 0,
|
1564
|
+
maxValue: 2000,
|
1565
|
+
},
|
1566
|
+
},
|
1567
|
+
},
|
1568
|
+
visible: true,
|
1569
|
+
},
|
1570
|
+
],
|
1571
|
+
components: {
|
1572
|
+
view: {
|
1573
|
+
component: () => Promise.resolve().then(function () { return gaugeChartWidget_component; }).then((c) => c.AXPGaugeChartWidgetViewComponent),
|
1574
|
+
},
|
2647
1575
|
},
|
2648
1576
|
meta: {
|
2649
1577
|
dimensions: {
|
@@ -2661,399 +1589,21 @@ const AXPGaugeChartWidget = {
|
|
2661
1589
|
* Line Chart Widget Component
|
2662
1590
|
* Renders data as lines with interactive hover effects and animations
|
2663
1591
|
*/
|
2664
|
-
class AXPLineChartWidgetViewComponent extends
|
1592
|
+
class AXPLineChartWidgetViewComponent extends AXPValueWidgetComponent {
|
2665
1593
|
constructor() {
|
2666
1594
|
super(...arguments);
|
2667
|
-
this.
|
2668
|
-
|
2669
|
-
this.chartContainerEl = viewChild.required('chartContainer');
|
2670
|
-
this.margin = { top: 20, right: 20, bottom: 30, left: 40 };
|
2671
|
-
// Tooltip state
|
2672
|
-
this._tooltipVisible = signal(false);
|
2673
|
-
this._tooltipPosition = signal({ x: 0, y: 0 });
|
2674
|
-
this._tooltipData = signal({
|
2675
|
-
title: '',
|
2676
|
-
value: '0',
|
2677
|
-
percentage: '0%',
|
2678
|
-
color: '',
|
2679
|
-
});
|
2680
|
-
// Tooltip accessors
|
2681
|
-
this.tooltipVisible = computed(() => this._tooltipVisible());
|
2682
|
-
this.tooltipPosition = computed(() => this._tooltipPosition());
|
2683
|
-
this.tooltipData = computed(() => this._tooltipData());
|
2684
|
-
// Line appearance options
|
2685
|
-
this.lineWidth = computed(() => this.options()['lineWidth'] ?? 2);
|
2686
|
-
this.showPoints = computed(() => this.options()['showPoints'] !== false);
|
2687
|
-
this.pointRadius = computed(() => this.options()['pointRadius'] ?? 4);
|
2688
|
-
this.smoothLine = computed(() => this.options()['smoothLine'] !== false);
|
2689
|
-
this.fillArea = computed(() => this.options()['fillArea'] === true);
|
2690
|
-
this.fillOpacity = computed(() => (this.options()['fillOpacity'] ?? 20) / 100);
|
2691
|
-
}
|
2692
|
-
// Chart lifecycle methods
|
2693
|
-
/**
|
2694
|
-
* Creates the line chart SVG and renders all elements
|
2695
|
-
*/
|
2696
|
-
createChart() {
|
2697
|
-
if (!this.d3 || !this.chartContainerEl()?.nativeElement)
|
2698
|
-
return;
|
2699
|
-
const containerElement = this.chartContainerEl().nativeElement;
|
2700
|
-
let data = this.chartData() || [];
|
2701
|
-
// Clear existing chart
|
2702
|
-
this.d3.select(containerElement).selectAll('svg').remove();
|
2703
|
-
// Normalize data structure to array of arrays (multi-series format)
|
2704
|
-
let normalizedData = [];
|
2705
|
-
// Handle both flat array and array of arrays formats
|
2706
|
-
if (data.length > 0) {
|
2707
|
-
if (Array.isArray(data[0])) {
|
2708
|
-
// Already in multi-series format
|
2709
|
-
normalizedData = data;
|
2710
|
-
}
|
2711
|
-
else {
|
2712
|
-
// Single series or flat array with seriesName
|
2713
|
-
const dataPoints = data;
|
2714
|
-
// Check if this is multi-series data (has seriesName property)
|
2715
|
-
const hasSeriesNames = dataPoints.some((d) => d.seriesName !== undefined);
|
2716
|
-
if (hasSeriesNames) {
|
2717
|
-
// Organize by series name
|
2718
|
-
const seriesMap = new Map();
|
2719
|
-
dataPoints.forEach((d) => {
|
2720
|
-
const seriesName = d.seriesName || 'default';
|
2721
|
-
if (!seriesMap.has(seriesName)) {
|
2722
|
-
seriesMap.set(seriesName, []);
|
2723
|
-
}
|
2724
|
-
seriesMap.get(seriesName).push(d);
|
2725
|
-
});
|
2726
|
-
// Convert to array of arrays
|
2727
|
-
normalizedData = Array.from(seriesMap.values());
|
2728
|
-
}
|
2729
|
-
else {
|
2730
|
-
// Single series, wrap it in an array
|
2731
|
-
normalizedData = [dataPoints];
|
2732
|
-
}
|
2733
|
-
}
|
2734
|
-
}
|
2735
|
-
// Early return if no data
|
2736
|
-
if (normalizedData.length === 0 || normalizedData.flat().length === 0) {
|
2737
|
-
this.showNoDataMessage(containerElement);
|
2738
|
-
return;
|
2739
|
-
}
|
2740
|
-
// Get options and setup dimensions
|
2741
|
-
const options = this.options();
|
2742
|
-
this.setupDimensions(containerElement, options);
|
2743
|
-
// Flatten data for scale calculation
|
2744
|
-
const flatData = normalizedData.flat();
|
2745
|
-
// Create scales with the flattened data
|
2746
|
-
this.setupScales(flatData);
|
2747
|
-
this.createAxes(options);
|
2748
|
-
// Render the lines using the structured data (array of arrays)
|
2749
|
-
this.renderLines(normalizedData);
|
2750
|
-
}
|
2751
|
-
updateChart() {
|
2752
|
-
this.createChart();
|
2753
|
-
}
|
2754
|
-
cleanupChart() {
|
2755
|
-
if (this.svg) {
|
2756
|
-
this.d3.select(this.chartContainerEl()?.nativeElement).selectAll('svg').remove();
|
2757
|
-
this.svg = null;
|
2758
|
-
this.chart = null;
|
2759
|
-
}
|
2760
|
-
this._tooltipVisible.set(false);
|
2761
|
-
}
|
2762
|
-
// Private chart creation methods
|
2763
|
-
/**
|
2764
|
-
* Sets up chart dimensions and creates SVG with responsive attributes
|
2765
|
-
*/
|
2766
|
-
setupDimensions(containerElement, options) {
|
2767
|
-
// Get container dimensions
|
2768
|
-
const containerWidth = containerElement.clientWidth;
|
2769
|
-
const containerHeight = containerElement.clientHeight;
|
2770
|
-
// If options specify width and height, use those, otherwise default to container size
|
2771
|
-
const minDim = Math.min(200, containerWidth, containerHeight); // Ensure reasonable minimum
|
2772
|
-
if (options.width && options.height) {
|
2773
|
-
// Explicit dimensions provided
|
2774
|
-
this.width = options.width - this.margin.left - this.margin.right;
|
2775
|
-
this.height = options.height - this.margin.top - this.margin.bottom;
|
2776
|
-
}
|
2777
|
-
else {
|
2778
|
-
// Responsive dimensions
|
2779
|
-
this.width = Math.max(containerWidth, minDim) - this.margin.left - this.margin.right;
|
2780
|
-
this.height = Math.max(containerHeight, minDim) - this.margin.top - this.margin.bottom;
|
2781
|
-
}
|
2782
|
-
// Create responsive SVG that scales with its container
|
2783
|
-
const svg = this.d3
|
2784
|
-
.select(containerElement)
|
2785
|
-
.append('svg')
|
2786
|
-
.attr('width', '100%')
|
2787
|
-
.attr('height', '100%')
|
2788
|
-
.attr('viewBox', `0 0 ${this.width + this.margin.left + this.margin.right} ${this.height + this.margin.top + this.margin.bottom}`)
|
2789
|
-
.attr('preserveAspectRatio', 'xMidYMid meet');
|
2790
|
-
this.svg = svg;
|
2791
|
-
// Create chart group with margins
|
2792
|
-
this.chart = this.svg.append('g').attr('transform', `translate(${this.margin.left},${this.margin.top})`);
|
2793
|
-
}
|
2794
|
-
/**
|
2795
|
-
* Creates x and y scales for the chart
|
2796
|
-
*/
|
2797
|
-
setupScales(data) {
|
2798
|
-
// Determine x-axis type based on data
|
2799
|
-
const allNumericX = data.every((d) => typeof d.xValue === 'number');
|
2800
|
-
const allDates = data.every((d) => !isNaN(new Date(d.xValue).getTime()));
|
2801
|
-
// Create appropriate x scale based on data type
|
2802
|
-
if (allNumericX) {
|
2803
|
-
// Numeric x-axis
|
2804
|
-
this.xScale = this.d3
|
2805
|
-
.scaleLinear()
|
2806
|
-
.domain([
|
2807
|
-
this.d3.min(data, (d) => d.xValue) || 0,
|
2808
|
-
this.d3.max(data, (d) => d.xValue) || 0,
|
2809
|
-
])
|
2810
|
-
.range([0, this.width]);
|
2811
|
-
}
|
2812
|
-
else if (allDates) {
|
2813
|
-
// Date x-axis
|
2814
|
-
this.xScale = this.d3
|
2815
|
-
.scaleTime()
|
2816
|
-
.domain([
|
2817
|
-
this.d3.min(data, (d) => new Date(d.xValue)) || new Date(),
|
2818
|
-
this.d3.max(data, (d) => new Date(d.xValue)) || new Date(),
|
2819
|
-
])
|
2820
|
-
.range([0, this.width]);
|
2821
|
-
}
|
2822
|
-
else {
|
2823
|
-
// Categorical x-axis
|
2824
|
-
this.xScale = this.d3
|
2825
|
-
.scaleBand()
|
2826
|
-
.domain(data.map((d) => d.xValue.toString()))
|
2827
|
-
.range([0, this.width])
|
2828
|
-
.padding(0.1);
|
2829
|
-
}
|
2830
|
-
// Create y scale (linear scale for values)
|
2831
|
-
this.yScale = this.d3
|
2832
|
-
.scaleLinear()
|
2833
|
-
.domain([0, this.d3.max(data, (d) => d.value) || 0])
|
2834
|
-
.nice()
|
2835
|
-
.range([this.height, 0]);
|
2836
|
-
}
|
2837
|
-
/**
|
2838
|
-
* Creates x and y axes with grid lines
|
2839
|
-
*/
|
2840
|
-
createAxes(options) {
|
2841
|
-
// Only create axes if they are enabled in options
|
2842
|
-
const showXAxis = options.showXAxis !== false;
|
2843
|
-
const showYAxis = options.showYAxis !== false;
|
2844
|
-
const showGrid = options.showGrid !== false;
|
2845
|
-
if (showXAxis) {
|
2846
|
-
// Create X axis
|
2847
|
-
this.xAxis = this.chart
|
2848
|
-
.append('g')
|
2849
|
-
.attr('class', 'axp-line-chart-axis-x')
|
2850
|
-
.attr('transform', `translate(0,${this.height})`)
|
2851
|
-
.call(this.d3.axisBottom(this.xScale));
|
2852
|
-
}
|
2853
|
-
if (showYAxis) {
|
2854
|
-
// Create Y axis
|
2855
|
-
this.yAxis = this.chart.append('g').attr('class', 'axp-line-chart-axis-y').call(this.d3.axisLeft(this.yScale));
|
2856
|
-
}
|
2857
|
-
if (showGrid) {
|
2858
|
-
// Add horizontal grid lines
|
2859
|
-
this.chart
|
2860
|
-
.append('g')
|
2861
|
-
.attr('class', 'axp-line-chart-grid')
|
2862
|
-
.call(this.d3
|
2863
|
-
.axisLeft(this.yScale)
|
2864
|
-
.tickSize(-this.width)
|
2865
|
-
.tickFormat(() => ''))
|
2866
|
-
.selectAll('.tick')
|
2867
|
-
.style('color', 'rgb(153 153 153 / 30%)'); // Add gray color to ticks
|
2868
|
-
}
|
2869
|
-
}
|
2870
|
-
/**
|
2871
|
-
* Renders the lines with animations
|
2872
|
-
*/
|
2873
|
-
renderLines(data) {
|
2874
|
-
// Get line options
|
2875
|
-
const lineWidth = this.lineWidth();
|
2876
|
-
const useSmooth = this.smoothLine();
|
2877
|
-
const shouldFill = this.fillArea();
|
2878
|
-
const fillOpacity = this.fillOpacity();
|
2879
|
-
// Create line generator
|
2880
|
-
const getX = (d) => {
|
2881
|
-
// Handle different x scale types
|
2882
|
-
if (this.xScale.bandwidth) {
|
2883
|
-
// band scale for categorical
|
2884
|
-
return this.xScale(d.xValue.toString()) + this.xScale.bandwidth() / 2;
|
2885
|
-
}
|
2886
|
-
else {
|
2887
|
-
// linear or time scale
|
2888
|
-
return this.xScale(d.xValue);
|
2889
|
-
}
|
2890
|
-
};
|
2891
|
-
// Define line generator function
|
2892
|
-
const lineGenerator = useSmooth
|
2893
|
-
? this.d3
|
2894
|
-
.line()
|
2895
|
-
.x(getX)
|
2896
|
-
.y((d) => this.yScale(d.value))
|
2897
|
-
.curve(this.d3.curveMonotoneX) // Smooth curve
|
2898
|
-
: this.d3
|
2899
|
-
.line()
|
2900
|
-
.x(getX)
|
2901
|
-
.y((d) => this.yScale(d.value))
|
2902
|
-
.curve(this.d3.curveLinear); // Straight lines
|
2903
|
-
// Define area generator if we should fill
|
2904
|
-
const areaGenerator = useSmooth
|
2905
|
-
? this.d3
|
2906
|
-
.area()
|
2907
|
-
.x(getX)
|
2908
|
-
.y0(this.height)
|
2909
|
-
.y1((d) => this.yScale(d.value))
|
2910
|
-
.curve(this.d3.curveMonotoneX)
|
2911
|
-
: this.d3
|
2912
|
-
.area()
|
2913
|
-
.x(getX)
|
2914
|
-
.y0(this.height)
|
2915
|
-
.y1((d) => this.yScale(d.value))
|
2916
|
-
.curve(this.d3.curveLinear);
|
2917
|
-
// Render each series
|
2918
|
-
data.forEach((seriesData, seriesIndex) => {
|
2919
|
-
// Skip empty series
|
2920
|
-
if (!seriesData.length)
|
2921
|
-
return;
|
2922
|
-
// Sort data within series by x value
|
2923
|
-
seriesData.sort((a, b) => {
|
2924
|
-
if (typeof a.xValue === 'number' && typeof b.xValue === 'number') {
|
2925
|
-
return a.xValue - b.xValue;
|
2926
|
-
}
|
2927
|
-
else {
|
2928
|
-
return a.xValue.toString().localeCompare(b.xValue.toString());
|
2929
|
-
}
|
2930
|
-
});
|
2931
|
-
// Get series name and color
|
2932
|
-
const seriesName = seriesData[0].seriesName || `Series ${seriesIndex + 1}`;
|
2933
|
-
// Get color for this series - prefer the color from data point, otherwise use palette
|
2934
|
-
const seriesColor = seriesData[0]?.color || AXPChartColors.getColor(seriesIndex);
|
2935
|
-
// Draw the area if fill is enabled
|
2936
|
-
if (shouldFill) {
|
2937
|
-
this.chart
|
2938
|
-
.append('path')
|
2939
|
-
.datum(seriesData)
|
2940
|
-
.attr('class', 'axp-line-chart-area')
|
2941
|
-
.attr('fill', seriesColor)
|
2942
|
-
.attr('fill-opacity', fillOpacity)
|
2943
|
-
.attr('d', areaGenerator);
|
2944
|
-
}
|
2945
|
-
// Draw the line with animation
|
2946
|
-
const path = this.chart
|
2947
|
-
.append('path')
|
2948
|
-
.datum(seriesData)
|
2949
|
-
.attr('class', 'axp-line-chart-line')
|
2950
|
-
.attr('stroke', seriesColor)
|
2951
|
-
.attr('stroke-width', lineWidth)
|
2952
|
-
.attr('fill', 'none') // Ensure no fill on the line
|
2953
|
-
.attr('d', lineGenerator);
|
2954
|
-
// Animate the line drawing
|
2955
|
-
const pathLength = path.node().getTotalLength();
|
2956
|
-
path
|
2957
|
-
.attr('stroke-dasharray', pathLength)
|
2958
|
-
.attr('stroke-dashoffset', pathLength)
|
2959
|
-
.transition()
|
2960
|
-
.duration(1000)
|
2961
|
-
.attr('stroke-dashoffset', 0)
|
2962
|
-
.ease(this.d3.easeQuadOut);
|
2963
|
-
// Add data points if enabled
|
2964
|
-
if (this.showPoints()) {
|
2965
|
-
this.chart
|
2966
|
-
.selectAll(`.axp-line-chart-point-${seriesIndex}`)
|
2967
|
-
.data(seriesData)
|
2968
|
-
.enter()
|
2969
|
-
.append('circle')
|
2970
|
-
.attr('class', `axp-line-chart-point axp-line-chart-point-${seriesIndex}`)
|
2971
|
-
.attr('cx', (d) => getX(d))
|
2972
|
-
.attr('cy', (d) => this.yScale(d.value))
|
2973
|
-
.attr('r', 0) // Start with radius 0 for animation
|
2974
|
-
.attr('fill', seriesColor)
|
2975
|
-
.attr('stroke', 'white')
|
2976
|
-
.attr('stroke-width', 1)
|
2977
|
-
.on('mouseenter', (event, d) => this.handlePointHover(event, d, seriesName))
|
2978
|
-
.on('mousemove', (event) => this.updateTooltipPosition(event))
|
2979
|
-
.on('mouseleave', () => this._tooltipVisible.set(false))
|
2980
|
-
.on('click', (event, d) => this.handlePointClick(event, d))
|
2981
|
-
.transition()
|
2982
|
-
.delay((d, i) => i * 50 + 300) // Stagger with delay after line animation
|
2983
|
-
.duration(300)
|
2984
|
-
.attr('r', this.pointRadius())
|
2985
|
-
.ease(this.d3.easeBackOut); // Bouncy animation
|
2986
|
-
}
|
2987
|
-
});
|
2988
|
-
}
|
2989
|
-
// Event handlers
|
2990
|
-
/**
|
2991
|
-
* Handles point hover event and shows tooltip
|
2992
|
-
*/
|
2993
|
-
handlePointHover(event, datum, seriesName) {
|
2994
|
-
if (this.options().showTooltip !== false) {
|
2995
|
-
const data = this.chartData();
|
2996
|
-
let index = 0;
|
2997
|
-
// Find index based on data structure
|
2998
|
-
if (Array.isArray(data)) {
|
2999
|
-
if (Array.isArray(data[0])) {
|
3000
|
-
// Multi-series data (array of arrays)
|
3001
|
-
const flatData = data.flat();
|
3002
|
-
index = flatData.findIndex((item) => item.id === datum.id);
|
3003
|
-
}
|
3004
|
-
else {
|
3005
|
-
// Single series (array of data points)
|
3006
|
-
index = data.findIndex((item) => item.id === datum.id);
|
3007
|
-
}
|
3008
|
-
}
|
3009
|
-
const color = datum.color || AXPChartColors.getColor(index);
|
3010
|
-
// Update tooltip data
|
3011
|
-
this._tooltipData.set({
|
3012
|
-
title: datum.label || seriesName,
|
3013
|
-
value: datum.value.toString(),
|
3014
|
-
percentage: '', // Not showing percentage for line charts
|
3015
|
-
color,
|
3016
|
-
});
|
3017
|
-
// Position tooltip near the point
|
3018
|
-
this.updateTooltipPosition(event);
|
3019
|
-
this._tooltipVisible.set(true);
|
3020
|
-
}
|
3021
|
-
}
|
3022
|
-
/**
|
3023
|
-
* Updates tooltip position based on mouse coordinates
|
3024
|
-
*/
|
3025
|
-
updateTooltipPosition(event) {
|
3026
|
-
const rect = event.target.getBoundingClientRect();
|
3027
|
-
const containerRect = this.chartContainerEl().nativeElement.getBoundingClientRect();
|
3028
|
-
// Position relative to the container
|
3029
|
-
const x = event.clientX - containerRect.left;
|
3030
|
-
const y = event.clientY - containerRect.top;
|
3031
|
-
this._tooltipPosition.set({ x, y });
|
3032
|
-
}
|
3033
|
-
/**
|
3034
|
-
* Handles point click event
|
3035
|
-
*/
|
3036
|
-
handlePointClick(event, datum) {
|
3037
|
-
// Emit click event with the data point
|
3038
|
-
this.pointClick.emit(datum);
|
1595
|
+
this.lineChartData = computed(() => this.getValue());
|
1596
|
+
this.lineChartOptions = computed(() => this.options());
|
3039
1597
|
}
|
3040
|
-
|
3041
|
-
|
3042
|
-
*/
|
3043
|
-
showNoDataMessage(containerElement) {
|
3044
|
-
const noDataDiv = this.d3.select(containerElement).append('div').attr('class', 'axp-line-chart-no-data-message');
|
3045
|
-
noDataDiv
|
3046
|
-
.append('div')
|
3047
|
-
.attr('class', 'axp-line-chart-no-data-icon')
|
3048
|
-
.html('<i class="fa-light fa-chart-line fa-3x"></i>');
|
3049
|
-
noDataDiv.append('div').attr('class', 'axp-line-chart-no-data-text').text('No data available');
|
1598
|
+
handleLineChartPointClick(event) {
|
1599
|
+
//console.log(event);
|
3050
1600
|
}
|
3051
1601
|
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.0.3", ngImport: i0, type: AXPLineChartWidgetViewComponent, deps: null, target: i0.ɵɵFactoryTarget.Component }); }
|
3052
|
-
static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "
|
1602
|
+
static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "19.0.3", type: AXPLineChartWidgetViewComponent, isStandalone: true, selector: "ng-component", usesInheritance: true, ngImport: i0, template: "<ax-line-chart\n (pointClick)=\"handleLineChartPointClick($event)\"\n [data]=\"lineChartData()\"\n [options]=\"lineChartOptions()\"\n></ax-line-chart>\n", styles: [":host{display:block;width:100%;height:100%}\n"], dependencies: [{ kind: "component", type: AXLineChartComponent, selector: "ax-line-chart", inputs: ["data", "options"], outputs: ["pointClick"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
|
3053
1603
|
}
|
3054
1604
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.0.3", ngImport: i0, type: AXPLineChartWidgetViewComponent, decorators: [{
|
3055
1605
|
type: Component,
|
3056
|
-
args: [{ standalone: true, imports: [
|
1606
|
+
args: [{ standalone: true, imports: [AXLineChartComponent], changeDetection: ChangeDetectionStrategy.OnPush, template: "<ax-line-chart\n (pointClick)=\"handleLineChartPointClick($event)\"\n [data]=\"lineChartData()\"\n [options]=\"lineChartOptions()\"\n></ax-line-chart>\n", styles: [":host{display:block;width:100%;height:100%}\n"] }]
|
3057
1607
|
}] });
|
3058
1608
|
|
3059
1609
|
var lineChartWidget_component = /*#__PURE__*/Object.freeze({
|
@@ -3069,26 +1619,28 @@ const AXPLineChartWidget = {
|
|
3069
1619
|
type: 'dashboard',
|
3070
1620
|
icon: 'fa-light fa-chart-line',
|
3071
1621
|
properties: [
|
3072
|
-
|
1622
|
+
cloneProperty(AXP_NAME_PROPERTY, { visible: false }),
|
1623
|
+
cloneProperty(AXP_DATA_PATH_PROPERTY, { visible: false }),
|
1624
|
+
// ====== Chart Title ======
|
3073
1625
|
{
|
3074
|
-
name: '
|
3075
|
-
title: '
|
3076
|
-
group:
|
1626
|
+
name: 'title',
|
1627
|
+
title: 'Chart Title',
|
1628
|
+
group: AXP_APPEARANCE_PROPERTY_GROUP,
|
3077
1629
|
schema: {
|
3078
|
-
defaultValue:
|
3079
|
-
dataType: '
|
1630
|
+
defaultValue: '',
|
1631
|
+
dataType: 'string',
|
3080
1632
|
interface: {
|
3081
|
-
name: '
|
3082
|
-
path: 'options.
|
3083
|
-
type: AXPWidgetsCatalog.
|
1633
|
+
name: 'title',
|
1634
|
+
path: 'options.title',
|
1635
|
+
type: AXPWidgetsCatalog.text,
|
3084
1636
|
options: {
|
3085
|
-
|
3086
|
-
maxValue: 800,
|
1637
|
+
placeholder: 'Enter chart title',
|
3087
1638
|
},
|
3088
1639
|
},
|
3089
1640
|
},
|
3090
1641
|
visible: true,
|
3091
1642
|
},
|
1643
|
+
// ====== Layout & Dimensions ======
|
3092
1644
|
{
|
3093
1645
|
name: 'width',
|
3094
1646
|
title: 'Width',
|
@@ -3108,6 +1660,25 @@ const AXPLineChartWidget = {
|
|
3108
1660
|
},
|
3109
1661
|
visible: true,
|
3110
1662
|
},
|
1663
|
+
{
|
1664
|
+
name: 'height',
|
1665
|
+
title: 'Height',
|
1666
|
+
group: AXP_STYLING_PROPERTY_GROUP,
|
1667
|
+
schema: {
|
1668
|
+
defaultValue: 300,
|
1669
|
+
dataType: 'number',
|
1670
|
+
interface: {
|
1671
|
+
name: 'height',
|
1672
|
+
path: 'options.height',
|
1673
|
+
type: AXPWidgetsCatalog.number,
|
1674
|
+
options: {
|
1675
|
+
minValue: 0,
|
1676
|
+
maxValue: 800,
|
1677
|
+
},
|
1678
|
+
},
|
1679
|
+
},
|
1680
|
+
visible: true,
|
1681
|
+
},
|
3111
1682
|
// ====== Axis Settings ======
|
3112
1683
|
{
|
3113
1684
|
name: 'showXAxis',
|
@@ -3124,6 +1695,21 @@ const AXPLineChartWidget = {
|
|
3124
1695
|
},
|
3125
1696
|
visible: true,
|
3126
1697
|
},
|
1698
|
+
{
|
1699
|
+
name: 'xAxisLabel',
|
1700
|
+
title: 'X Axis Label',
|
1701
|
+
group: AXP_APPEARANCE_PROPERTY_GROUP,
|
1702
|
+
schema: {
|
1703
|
+
defaultValue: '',
|
1704
|
+
dataType: 'string',
|
1705
|
+
interface: {
|
1706
|
+
name: 'xAxisLabel',
|
1707
|
+
path: 'options.xAxisLabel',
|
1708
|
+
type: AXPWidgetsCatalog.text,
|
1709
|
+
},
|
1710
|
+
},
|
1711
|
+
visible: true,
|
1712
|
+
},
|
3127
1713
|
{
|
3128
1714
|
name: 'showYAxis',
|
3129
1715
|
title: 'Show Y Axis',
|
@@ -3140,82 +1726,95 @@ const AXPLineChartWidget = {
|
|
3140
1726
|
visible: true,
|
3141
1727
|
},
|
3142
1728
|
{
|
3143
|
-
name: '
|
3144
|
-
title: '
|
1729
|
+
name: 'yAxisLabel',
|
1730
|
+
title: 'Y Axis Label',
|
3145
1731
|
group: AXP_APPEARANCE_PROPERTY_GROUP,
|
3146
1732
|
schema: {
|
3147
|
-
defaultValue:
|
3148
|
-
dataType: '
|
1733
|
+
defaultValue: '',
|
1734
|
+
dataType: 'string',
|
3149
1735
|
interface: {
|
3150
|
-
name: '
|
3151
|
-
path: 'options.
|
3152
|
-
type: AXPWidgetsCatalog.
|
1736
|
+
name: 'yAxisLabel',
|
1737
|
+
path: 'options.yAxisLabel',
|
1738
|
+
type: AXPWidgetsCatalog.text,
|
3153
1739
|
},
|
3154
1740
|
},
|
3155
1741
|
visible: true,
|
3156
1742
|
},
|
3157
|
-
// ====== Tooltip Settings ======
|
3158
1743
|
{
|
3159
|
-
name: '
|
3160
|
-
title: '
|
1744
|
+
name: 'yAxisStartsAtZero',
|
1745
|
+
title: 'Y Axis Starts At Zero',
|
3161
1746
|
group: AXP_APPEARANCE_PROPERTY_GROUP,
|
3162
1747
|
schema: {
|
3163
1748
|
defaultValue: true,
|
3164
1749
|
dataType: 'boolean',
|
3165
1750
|
interface: {
|
3166
|
-
name: '
|
3167
|
-
path: 'options.
|
1751
|
+
name: 'yAxisStartsAtZero',
|
1752
|
+
path: 'options.yAxisStartsAtZero',
|
3168
1753
|
type: AXPWidgetsCatalog.toggle,
|
3169
1754
|
},
|
3170
1755
|
},
|
3171
1756
|
visible: true,
|
3172
1757
|
},
|
3173
|
-
// ====== Line Appearance ======
|
3174
1758
|
{
|
3175
|
-
name: '
|
3176
|
-
title: '
|
1759
|
+
name: 'axisPadding',
|
1760
|
+
title: 'Axis Padding',
|
3177
1761
|
group: AXP_APPEARANCE_PROPERTY_GROUP,
|
3178
1762
|
schema: {
|
3179
|
-
defaultValue:
|
1763
|
+
defaultValue: 5,
|
3180
1764
|
dataType: 'number',
|
3181
1765
|
interface: {
|
3182
|
-
name: '
|
3183
|
-
path: 'options.
|
1766
|
+
name: 'axisPadding',
|
1767
|
+
path: 'options.axisPadding',
|
3184
1768
|
type: AXPWidgetsCatalog.number,
|
3185
1769
|
options: {
|
3186
|
-
|
3187
|
-
|
3188
|
-
maxValue: 10,
|
1770
|
+
minValue: 0,
|
1771
|
+
maxValue: 50,
|
3189
1772
|
},
|
3190
1773
|
},
|
3191
1774
|
},
|
3192
1775
|
visible: true,
|
3193
1776
|
},
|
3194
1777
|
{
|
3195
|
-
name: '
|
3196
|
-
title: 'Show
|
1778
|
+
name: 'showGrid',
|
1779
|
+
title: 'Show Grid Lines',
|
3197
1780
|
group: AXP_APPEARANCE_PROPERTY_GROUP,
|
3198
1781
|
schema: {
|
3199
1782
|
defaultValue: true,
|
3200
1783
|
dataType: 'boolean',
|
3201
1784
|
interface: {
|
3202
|
-
name: '
|
3203
|
-
path: 'options.
|
1785
|
+
name: 'showGrid',
|
1786
|
+
path: 'options.showGrid',
|
3204
1787
|
type: AXPWidgetsCatalog.toggle,
|
3205
1788
|
},
|
3206
1789
|
},
|
3207
1790
|
visible: true,
|
3208
1791
|
},
|
3209
1792
|
{
|
3210
|
-
name: '
|
3211
|
-
title: '
|
1793
|
+
name: 'showVerticalGrid',
|
1794
|
+
title: 'Show Vertical Grid',
|
3212
1795
|
group: AXP_APPEARANCE_PROPERTY_GROUP,
|
3213
1796
|
schema: {
|
3214
|
-
defaultValue:
|
1797
|
+
defaultValue: true,
|
1798
|
+
dataType: 'boolean',
|
1799
|
+
interface: {
|
1800
|
+
name: 'showVerticalGrid',
|
1801
|
+
path: 'options.showVerticalGrid',
|
1802
|
+
type: AXPWidgetsCatalog.toggle,
|
1803
|
+
},
|
1804
|
+
},
|
1805
|
+
visible: true,
|
1806
|
+
},
|
1807
|
+
// ====== Line Appearance ======
|
1808
|
+
{
|
1809
|
+
name: 'lineWidth',
|
1810
|
+
title: 'Line Width',
|
1811
|
+
group: AXP_APPEARANCE_PROPERTY_GROUP,
|
1812
|
+
schema: {
|
1813
|
+
defaultValue: 2,
|
3215
1814
|
dataType: 'number',
|
3216
1815
|
interface: {
|
3217
|
-
name: '
|
3218
|
-
path: 'options.
|
1816
|
+
name: 'lineWidth',
|
1817
|
+
path: 'options.lineWidth',
|
3219
1818
|
type: AXPWidgetsCatalog.number,
|
3220
1819
|
options: {
|
3221
1820
|
placeholder: '1-10',
|
@@ -3242,287 +1841,170 @@ const AXPLineChartWidget = {
|
|
3242
1841
|
visible: true,
|
3243
1842
|
},
|
3244
1843
|
{
|
3245
|
-
name: '
|
3246
|
-
title: '
|
1844
|
+
name: 'showPoints',
|
1845
|
+
title: 'Show Points',
|
3247
1846
|
group: AXP_APPEARANCE_PROPERTY_GROUP,
|
3248
1847
|
schema: {
|
3249
|
-
defaultValue:
|
1848
|
+
defaultValue: true,
|
3250
1849
|
dataType: 'boolean',
|
3251
1850
|
interface: {
|
3252
|
-
name: '
|
3253
|
-
path: 'options.
|
1851
|
+
name: 'showPoints',
|
1852
|
+
path: 'options.showPoints',
|
3254
1853
|
type: AXPWidgetsCatalog.toggle,
|
3255
1854
|
},
|
3256
1855
|
},
|
3257
1856
|
visible: true,
|
3258
1857
|
},
|
3259
1858
|
{
|
3260
|
-
name: '
|
3261
|
-
title: '
|
1859
|
+
name: 'pointRadius',
|
1860
|
+
title: 'Point Size',
|
3262
1861
|
group: AXP_APPEARANCE_PROPERTY_GROUP,
|
3263
1862
|
schema: {
|
3264
|
-
defaultValue:
|
1863
|
+
defaultValue: 4,
|
3265
1864
|
dataType: 'number',
|
3266
1865
|
interface: {
|
3267
|
-
name: '
|
3268
|
-
path: 'options.
|
1866
|
+
name: 'pointRadius',
|
1867
|
+
path: 'options.pointRadius',
|
3269
1868
|
type: AXPWidgetsCatalog.number,
|
3270
1869
|
options: {
|
3271
|
-
placeholder: '
|
3272
|
-
minValue:
|
3273
|
-
maxValue:
|
1870
|
+
placeholder: '1-10',
|
1871
|
+
minValue: 1,
|
1872
|
+
maxValue: 10,
|
3274
1873
|
},
|
3275
1874
|
},
|
3276
1875
|
},
|
3277
1876
|
visible: true,
|
3278
1877
|
},
|
3279
|
-
],
|
3280
|
-
components: {
|
3281
|
-
view: {
|
3282
|
-
component: () => Promise.resolve().then(function () { return lineChartWidget_component; }).then((c) => c.AXPLineChartWidgetViewComponent),
|
3283
|
-
},
|
3284
|
-
},
|
3285
|
-
meta: {
|
3286
|
-
dimensions: {
|
3287
|
-
width: 5,
|
3288
|
-
height: 6,
|
3289
|
-
minWidth: 2,
|
3290
|
-
minHeight: 2,
|
3291
|
-
maxWidth: 6,
|
3292
|
-
maxHeight: 7,
|
3293
|
-
},
|
3294
|
-
},
|
3295
|
-
};
|
3296
|
-
|
3297
|
-
/**
|
3298
|
-
* Notification Widget Component
|
3299
|
-
* Displays notifications in a card with tabs
|
3300
|
-
*/
|
3301
|
-
class AXPNotificationWidgetViewComponent extends AXPValueWidgetComponent {
|
3302
|
-
constructor() {
|
3303
|
-
super(...arguments);
|
3304
|
-
// Outputs
|
3305
|
-
this.notificationClick = output();
|
3306
|
-
this.markAsRead = output();
|
3307
|
-
// Dependencies
|
3308
|
-
this.cdr = inject(ChangeDetectorRef);
|
3309
|
-
this.datePipe = inject(DatePipe);
|
3310
|
-
// State
|
3311
|
-
this.activeTab = signal('new');
|
3312
|
-
// Configuration
|
3313
|
-
this.maxItems = computed(() => this.options()?.maxItems ?? 10);
|
3314
|
-
this.showAvatar = computed(() => this.options()?.showAvatar ?? true);
|
3315
|
-
this.showDate = computed(() => this.options()?.showDate ?? true);
|
3316
|
-
// Computed data
|
3317
|
-
this.notificationItems = computed(() => {
|
3318
|
-
const value = this.getValue();
|
3319
|
-
if (!value?.data?.length)
|
3320
|
-
return [];
|
3321
|
-
// Filter by active tab
|
3322
|
-
const filtered = this.activeTab() === 'new' ? value.data.filter((n) => !n.readAt) : value.data;
|
3323
|
-
return filtered.slice(0, this.maxItems());
|
3324
|
-
});
|
3325
|
-
}
|
3326
|
-
/**
|
3327
|
-
* Get the count of new messages for the badge
|
3328
|
-
*/
|
3329
|
-
getNewMessageCount() {
|
3330
|
-
const value = this.getValue();
|
3331
|
-
if (!value?.data?.length)
|
3332
|
-
return 0;
|
3333
|
-
return value.data.filter((n) => !n.readAt).length;
|
3334
|
-
}
|
3335
|
-
/**
|
3336
|
-
* Handle tab change event from ax-tabs component
|
3337
|
-
* @param index The index of the tab that was activated
|
3338
|
-
*/
|
3339
|
-
handleTabChange(data) {
|
3340
|
-
const index = data.index;
|
3341
|
-
// Map index to tab name: 0 = 'new', 1 = 'all'
|
3342
|
-
const tabName = index === 0 ? 'new' : 'all';
|
3343
|
-
this.onTabChange(tabName);
|
3344
|
-
}
|
3345
|
-
/**
|
3346
|
-
* Mark all notifications as read
|
3347
|
-
*/
|
3348
|
-
markAllAsRead() {
|
3349
|
-
const value = this.getValue();
|
3350
|
-
if (!value?.data?.length)
|
3351
|
-
return;
|
3352
|
-
const now = new Date();
|
3353
|
-
const updatedNotifications = value.data.map((n) => {
|
3354
|
-
if (n.readAt)
|
3355
|
-
return n;
|
3356
|
-
return { ...n, readAt: now };
|
3357
|
-
});
|
3358
|
-
this.setValue({
|
3359
|
-
...value,
|
3360
|
-
data: updatedNotifications,
|
3361
|
-
});
|
3362
|
-
this.cdr.detectChanges();
|
3363
|
-
}
|
3364
|
-
/**
|
3365
|
-
* Change the active tab
|
3366
|
-
*/
|
3367
|
-
onTabChange(tabName) {
|
3368
|
-
this.activeTab.set(tabName);
|
3369
|
-
this.cdr.detectChanges();
|
3370
|
-
}
|
3371
|
-
/**
|
3372
|
-
* Handle notification click event
|
3373
|
-
*/
|
3374
|
-
onNotificationClick(notification) {
|
3375
|
-
this.markAsReadIfNeeded(notification);
|
3376
|
-
this.notificationClick.emit(notification);
|
3377
|
-
}
|
3378
|
-
/**
|
3379
|
-
* Format the timestamp in a user-friendly way
|
3380
|
-
*/
|
3381
|
-
formatTime(date) {
|
3382
|
-
if (!date)
|
3383
|
-
return '';
|
3384
|
-
const dateObj = typeof date === 'string' ? new Date(date) : date;
|
3385
|
-
const diffDays = this.getDaysDifference(dateObj);
|
3386
|
-
// Format based on how recent the date is
|
3387
|
-
if (diffDays === 0)
|
3388
|
-
return this.datePipe.transform(dateObj, 'h:mm a') || ''; // Today
|
3389
|
-
if (diffDays === 1)
|
3390
|
-
return 'Yesterday';
|
3391
|
-
if (diffDays < 7)
|
3392
|
-
return this.datePipe.transform(dateObj, 'EEE') || ''; // Day of week
|
3393
|
-
return this.datePipe.transform(dateObj, 'MM/dd/yyyy') || ''; // Older date
|
3394
|
-
}
|
3395
|
-
/**
|
3396
|
-
* Mark notification as read if needed
|
3397
|
-
*/
|
3398
|
-
markAsReadIfNeeded(notification) {
|
3399
|
-
// Only mark as read if not already read
|
3400
|
-
if (notification.readAt)
|
3401
|
-
return;
|
3402
|
-
const updatedNotification = {
|
3403
|
-
...notification,
|
3404
|
-
readAt: new Date(),
|
3405
|
-
};
|
3406
|
-
// Update the model
|
3407
|
-
const value = this.getValue();
|
3408
|
-
if (!value?.data)
|
3409
|
-
return;
|
3410
|
-
const updatedNotifications = value.data.map((n) => (n.id === notification.id ? updatedNotification : n));
|
3411
|
-
this.setValue({
|
3412
|
-
...value,
|
3413
|
-
data: updatedNotifications,
|
3414
|
-
});
|
3415
|
-
// Notify about the change
|
3416
|
-
this.markAsRead.emit(updatedNotification);
|
3417
|
-
}
|
3418
|
-
/**
|
3419
|
-
* Calculate days difference from now
|
3420
|
-
*/
|
3421
|
-
getDaysDifference(date) {
|
3422
|
-
const now = new Date();
|
3423
|
-
const diffMs = now.getTime() - date.getTime();
|
3424
|
-
return Math.floor(diffMs / (1000 * 60 * 60 * 24));
|
3425
|
-
}
|
3426
|
-
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.0.3", ngImport: i0, type: AXPNotificationWidgetViewComponent, deps: null, target: i0.ɵɵFactoryTarget.Component }); }
|
3427
|
-
static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "19.0.3", type: AXPNotificationWidgetViewComponent, isStandalone: true, selector: "ng-component", outputs: { notificationClick: "notificationClick", markAsRead: "markAsRead" }, providers: [DatePipe], usesInheritance: true, ngImport: i0, template: "<div class=\"ax-p-4 ax-size-full\">\n <ax-tabs\n class=\"ax-bg-light-start ax-border-b ax-border-default\"\n [fitParent]=\"true\"\n location=\"bottom\"\n (onActiveTabChanged)=\"handleTabChange($event)\"\n >\n <ax-tab-item [text]=\"('widget.notification.new' | translate | async) ?? 'New'\" class=\"ax-font-medium\">\n <ax-suffix>\n @if (getNewMessageCount() > 0) {\n <ax-badge color=\"primary\" [text]=\"getNewMessageCount().toString()\" size=\"sm\" class=\"ax-ml-1\"></ax-badge>\n }\n </ax-suffix>\n </ax-tab-item>\n <ax-tab-item [text]=\"('widget.notification.all' | translate | async) ?? 'All'\" class=\"ax-font-medium\"></ax-tab-item>\n </ax-tabs>\n <div class=\"ax-space-y-4 ax-mt-4 ax-px-2\">\n @for (item of notificationItems(); track item.id) {\n <ng-container [ngTemplateOutlet]=\"chatItemTemplateRef\" [ngTemplateOutletContext]=\"{ $implicit: item }\">\n </ng-container>\n } @empty {\n <div class=\"ax-flex ax-flex-col ax-items-center ax-justify-center ax-py-12 ax-px-4 ax-text-gray-400\">\n <ax-icon class=\"ax-text-4xl ax-mb-3 ax-text-gray-300\">\n <i class=\"fa-light fa-bell-slash\"></i>\n </ax-icon>\n <p class=\"ax-text-center\">{{ 'widget.notification.noNotifications' | translate | async }}</p>\n </div>\n }\n </div>\n</div>\n\n<ng-template #chatItemTemplateRef let-data>\n <div class=\"ax-flex ax-gap-3\">\n @if(showAvatar()){\n <div class=\"ax-rounded-full ax-size-10\">\n <ax-avatar shape=\"rounded\" class=\"ax-shrink-0\" [size]=\"40\">\n @if(data.user?.image){\n <ax-image\n [src]=\"data.user.image\"\n [alt]=\"data.user?.name || ('widget.notification.user' | translate | async)\"\n ></ax-image>\n } @else {\n <ax-icon>\n <i class=\"fa-light fa-user\"></i>\n </ax-icon>\n }\n </ax-avatar>\n </div>\n }\n <div class=\"ax-overflow-hidden ax-grow ax-text-start\">\n <h6 class=\"ax-pb-2 ax-font-semibold ax-truncate\">{{ data.user?.name || data.title }}</h6>\n <p class=\"ax-text-xs ax-truncate\">{{ data.body }}</p>\n </div>\n @if(showDate()){\n <div class=\"ax-text-xs ax-shrink-0\">\n <span>\n {{ formatTime(data.createdAt) }}\n </span>\n </div>\n }\n </div>\n</ng-template>\n", styles: [":host{display:block;width:100%;height:100%}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "directive", type: i1.NgTemplateOutlet, selector: "[ngTemplateOutlet]", inputs: ["ngTemplateOutletContext", "ngTemplateOutlet", "ngTemplateOutletInjector"] }, { kind: "pipe", type: i1.AsyncPipe, name: "async" }, { kind: "ngmodule", type: AXTabsModule }, { kind: "component", type: i2$2.AXTabsComponent, selector: "ax-tabs", inputs: ["look", "location", "fitParent", "minWidth", "content"], outputs: ["onActiveTabChanged"] }, { kind: "component", type: i2$2.AXTabItemComponent, selector: "ax-tab-item", inputs: ["disabled", "text", "key", "headerTemplate", "active"], outputs: ["disabledChange", "onClick", "onBlur", "onFocus", "activeChange"] }, { kind: "ngmodule", type: AXDecoratorModule }, { kind: "component", type: i2$3.AXDecoratorIconComponent, selector: "ax-icon", inputs: ["icon"] }, { kind: "component", type: i2$3.AXDecoratorGenericComponent, selector: "ax-footer, ax-header, ax-content, ax-divider, ax-form-hint, ax-prefix, ax-suffix, ax-text, ax-title, ax-subtitle, ax-placeholder, ax-overlay" }, { kind: "ngmodule", type: AXButtonModule }, { kind: "ngmodule", type: AXBadgeModule }, { kind: "component", type: i4.AXBadgeComponent, selector: "ax-badge", inputs: ["color", "look", "text"] }, { kind: "ngmodule", type: AXAvatarModule }, { kind: "component", type: i5.AXAvatarComponent, selector: "ax-avatar", inputs: ["color", "size", "shape", "look"], outputs: ["sizeChange"] }, { kind: "ngmodule", type: AXImageModule }, { kind: "component", type: i6.AXImageComponent, selector: "ax-image", inputs: ["width", "height", "overlayMode", "src", "alt", "priority", "lazy"], outputs: ["onLoad", "onError"] }, { kind: "ngmodule", type: AXTranslationModule }, { kind: "pipe", type: i2.AXTranslatorPipe, name: "translate" }], changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
|
3428
|
-
}
|
3429
|
-
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.0.3", ngImport: i0, type: AXPNotificationWidgetViewComponent, decorators: [{
|
3430
|
-
type: Component,
|
3431
|
-
args: [{ standalone: true, imports: [
|
3432
|
-
CommonModule,
|
3433
|
-
AXTabsModule,
|
3434
|
-
AXDecoratorModule,
|
3435
|
-
AXButtonModule,
|
3436
|
-
AXBadgeModule,
|
3437
|
-
AXAvatarModule,
|
3438
|
-
AXImageModule,
|
3439
|
-
AXTranslationModule,
|
3440
|
-
], providers: [DatePipe], changeDetection: ChangeDetectionStrategy.OnPush, template: "<div class=\"ax-p-4 ax-size-full\">\n <ax-tabs\n class=\"ax-bg-light-start ax-border-b ax-border-default\"\n [fitParent]=\"true\"\n location=\"bottom\"\n (onActiveTabChanged)=\"handleTabChange($event)\"\n >\n <ax-tab-item [text]=\"('widget.notification.new' | translate | async) ?? 'New'\" class=\"ax-font-medium\">\n <ax-suffix>\n @if (getNewMessageCount() > 0) {\n <ax-badge color=\"primary\" [text]=\"getNewMessageCount().toString()\" size=\"sm\" class=\"ax-ml-1\"></ax-badge>\n }\n </ax-suffix>\n </ax-tab-item>\n <ax-tab-item [text]=\"('widget.notification.all' | translate | async) ?? 'All'\" class=\"ax-font-medium\"></ax-tab-item>\n </ax-tabs>\n <div class=\"ax-space-y-4 ax-mt-4 ax-px-2\">\n @for (item of notificationItems(); track item.id) {\n <ng-container [ngTemplateOutlet]=\"chatItemTemplateRef\" [ngTemplateOutletContext]=\"{ $implicit: item }\">\n </ng-container>\n } @empty {\n <div class=\"ax-flex ax-flex-col ax-items-center ax-justify-center ax-py-12 ax-px-4 ax-text-gray-400\">\n <ax-icon class=\"ax-text-4xl ax-mb-3 ax-text-gray-300\">\n <i class=\"fa-light fa-bell-slash\"></i>\n </ax-icon>\n <p class=\"ax-text-center\">{{ 'widget.notification.noNotifications' | translate | async }}</p>\n </div>\n }\n </div>\n</div>\n\n<ng-template #chatItemTemplateRef let-data>\n <div class=\"ax-flex ax-gap-3\">\n @if(showAvatar()){\n <div class=\"ax-rounded-full ax-size-10\">\n <ax-avatar shape=\"rounded\" class=\"ax-shrink-0\" [size]=\"40\">\n @if(data.user?.image){\n <ax-image\n [src]=\"data.user.image\"\n [alt]=\"data.user?.name || ('widget.notification.user' | translate | async)\"\n ></ax-image>\n } @else {\n <ax-icon>\n <i class=\"fa-light fa-user\"></i>\n </ax-icon>\n }\n </ax-avatar>\n </div>\n }\n <div class=\"ax-overflow-hidden ax-grow ax-text-start\">\n <h6 class=\"ax-pb-2 ax-font-semibold ax-truncate\">{{ data.user?.name || data.title }}</h6>\n <p class=\"ax-text-xs ax-truncate\">{{ data.body }}</p>\n </div>\n @if(showDate()){\n <div class=\"ax-text-xs ax-shrink-0\">\n <span>\n {{ formatTime(data.createdAt) }}\n </span>\n </div>\n }\n </div>\n</ng-template>\n", styles: [":host{display:block;width:100%;height:100%}\n"] }]
|
3441
|
-
}] });
|
3442
|
-
|
3443
|
-
var notificationWidget_component = /*#__PURE__*/Object.freeze({
|
3444
|
-
__proto__: null,
|
3445
|
-
AXPNotificationWidgetViewComponent: AXPNotificationWidgetViewComponent
|
3446
|
-
});
|
3447
|
-
|
3448
|
-
/**
|
3449
|
-
* Configuration for the Notification Widget
|
3450
|
-
*/
|
3451
|
-
const AXPNotificationWidget = {
|
3452
|
-
name: 'notification',
|
3453
|
-
title: 'Notification Widget',
|
3454
|
-
categories: [AXP_WIDGETS_UTILITY_CATEGORY],
|
3455
|
-
groups: [AXPWidgetGroupEnum.DashboardWidget],
|
3456
|
-
type: 'dashboard',
|
3457
|
-
description: 'Displays notifications in a widget format',
|
3458
|
-
icon: 'fa-regular fa-bell',
|
3459
|
-
properties: [
|
3460
|
-
cloneProperty(AXP_DATA_PATH_PROPERTY, { visible: false }),
|
3461
1878
|
{
|
3462
|
-
name: '
|
3463
|
-
title: '
|
3464
|
-
|
3465
|
-
|
1879
|
+
name: 'fillArea',
|
1880
|
+
title: 'Fill Area',
|
1881
|
+
group: AXP_APPEARANCE_PROPERTY_GROUP,
|
1882
|
+
schema: {
|
1883
|
+
defaultValue: false,
|
1884
|
+
dataType: 'boolean',
|
1885
|
+
interface: {
|
1886
|
+
name: 'fillArea',
|
1887
|
+
path: 'options.fillArea',
|
1888
|
+
type: AXPWidgetsCatalog.toggle,
|
1889
|
+
},
|
1890
|
+
},
|
1891
|
+
visible: true,
|
1892
|
+
},
|
1893
|
+
{
|
1894
|
+
name: 'fillOpacity',
|
1895
|
+
title: 'Fill Opacity',
|
1896
|
+
group: AXP_APPEARANCE_PROPERTY_GROUP,
|
3466
1897
|
schema: {
|
3467
1898
|
defaultValue: 10,
|
3468
1899
|
dataType: 'number',
|
3469
1900
|
interface: {
|
3470
|
-
name: '
|
3471
|
-
path: 'options.
|
1901
|
+
name: 'fillOpacity',
|
1902
|
+
path: 'options.fillOpacity',
|
3472
1903
|
type: AXPWidgetsCatalog.number,
|
3473
1904
|
options: {
|
3474
|
-
|
1905
|
+
placeholder: '0-100',
|
1906
|
+
minValue: 0,
|
3475
1907
|
maxValue: 100,
|
3476
1908
|
},
|
3477
1909
|
},
|
3478
1910
|
},
|
3479
1911
|
visible: true,
|
3480
1912
|
},
|
1913
|
+
// ====== Tooltip Settings ======
|
3481
1914
|
{
|
3482
|
-
name: '
|
3483
|
-
title: 'Show
|
3484
|
-
description: 'Whether to show avatars in notifications',
|
1915
|
+
name: 'showTooltip',
|
1916
|
+
title: 'Show Tooltip',
|
3485
1917
|
group: AXP_APPEARANCE_PROPERTY_GROUP,
|
3486
1918
|
schema: {
|
3487
1919
|
defaultValue: true,
|
3488
1920
|
dataType: 'boolean',
|
3489
1921
|
interface: {
|
3490
|
-
name: '
|
3491
|
-
path: 'options.
|
1922
|
+
name: 'showTooltip',
|
1923
|
+
path: 'options.showTooltip',
|
3492
1924
|
type: AXPWidgetsCatalog.toggle,
|
3493
1925
|
},
|
3494
1926
|
},
|
3495
1927
|
visible: true,
|
3496
1928
|
},
|
3497
1929
|
{
|
3498
|
-
name: '
|
3499
|
-
title: 'Show
|
3500
|
-
description: 'Whether to show date in notifications',
|
1930
|
+
name: 'showCrosshair',
|
1931
|
+
title: 'Show Crosshair',
|
3501
1932
|
group: AXP_APPEARANCE_PROPERTY_GROUP,
|
3502
1933
|
schema: {
|
3503
|
-
defaultValue:
|
1934
|
+
defaultValue: false,
|
3504
1935
|
dataType: 'boolean',
|
3505
1936
|
interface: {
|
3506
|
-
name: '
|
3507
|
-
path: 'options.
|
1937
|
+
name: 'showCrosshair',
|
1938
|
+
path: 'options.showCrosshair',
|
3508
1939
|
type: AXPWidgetsCatalog.toggle,
|
3509
1940
|
},
|
3510
1941
|
},
|
3511
1942
|
visible: true,
|
3512
1943
|
},
|
1944
|
+
// ====== Animation Settings ======
|
1945
|
+
{
|
1946
|
+
name: 'animationEasing',
|
1947
|
+
title: 'Animation Easing',
|
1948
|
+
group: AXP_APPEARANCE_PROPERTY_GROUP,
|
1949
|
+
schema: {
|
1950
|
+
defaultValue: 'cubic-out',
|
1951
|
+
dataType: 'string',
|
1952
|
+
interface: {
|
1953
|
+
name: 'animationEasing',
|
1954
|
+
path: 'options.animationEasing',
|
1955
|
+
type: AXPWidgetsCatalog.select,
|
1956
|
+
options: {
|
1957
|
+
dataSource: [
|
1958
|
+
{ value: 'linear', text: 'Linear' },
|
1959
|
+
{ value: 'ease', text: 'Ease' },
|
1960
|
+
{ value: 'ease-in', text: 'Ease In' },
|
1961
|
+
{ value: 'ease-out', text: 'Ease Out' },
|
1962
|
+
{ value: 'ease-in-out', text: 'Ease In Out' },
|
1963
|
+
{ value: 'cubic', text: 'Cubic' },
|
1964
|
+
{ value: 'cubic-in', text: 'Cubic In' },
|
1965
|
+
{ value: 'cubic-out', text: 'Cubic Out' },
|
1966
|
+
{ value: 'cubic-in-out', text: 'Cubic In Out' },
|
1967
|
+
],
|
1968
|
+
textField: 'text',
|
1969
|
+
valueField: 'value',
|
1970
|
+
},
|
1971
|
+
},
|
1972
|
+
},
|
1973
|
+
visible: true,
|
1974
|
+
},
|
1975
|
+
{
|
1976
|
+
name: 'animationDuration',
|
1977
|
+
title: 'Animation Duration',
|
1978
|
+
group: AXP_APPEARANCE_PROPERTY_GROUP,
|
1979
|
+
schema: {
|
1980
|
+
defaultValue: 800,
|
1981
|
+
dataType: 'number',
|
1982
|
+
interface: {
|
1983
|
+
name: 'animationDuration',
|
1984
|
+
path: 'options.animationDuration',
|
1985
|
+
type: AXPWidgetsCatalog.number,
|
1986
|
+
options: {
|
1987
|
+
placeholder: '0-2000',
|
1988
|
+
minValue: 0,
|
1989
|
+
maxValue: 2000,
|
1990
|
+
},
|
1991
|
+
},
|
1992
|
+
},
|
1993
|
+
visible: true,
|
1994
|
+
},
|
3513
1995
|
],
|
3514
1996
|
components: {
|
3515
1997
|
view: {
|
3516
|
-
component: () => Promise.resolve().then(function () { return
|
1998
|
+
component: () => Promise.resolve().then(function () { return lineChartWidget_component; }).then((c) => c.AXPLineChartWidgetViewComponent),
|
3517
1999
|
},
|
3518
2000
|
},
|
3519
2001
|
meta: {
|
3520
2002
|
dimensions: {
|
3521
|
-
width:
|
3522
|
-
height:
|
2003
|
+
width: 5,
|
2004
|
+
height: 6,
|
3523
2005
|
minWidth: 2,
|
3524
|
-
minHeight:
|
3525
|
-
maxWidth:
|
2006
|
+
minHeight: 2,
|
2007
|
+
maxWidth: 6,
|
3526
2008
|
maxHeight: 7,
|
3527
2009
|
},
|
3528
2010
|
},
|
@@ -3583,7 +2065,7 @@ class AXPStickyNoteWidgetViewComponent extends AXPValueWidgetComponent {
|
|
3583
2065
|
provide: AXGridLayoutWidgetComponent,
|
3584
2066
|
useExisting: AXPStickyNoteWidgetViewComponent,
|
3585
2067
|
},
|
3586
|
-
], viewQueries: [{ propertyName: "wysiwyg", first: true, predicate: ["wysiwyg"], descendants: true, isSignal: true }], usesInheritance: true, ngImport: i0, template: "<div\n class=\"sticky-note-container ax-size-full ax-rounded-lg ax-flex ax-flex-col ax-p-4 ax-shadow-md ax-transition-all ax-duration-300 hover:ax-shadow-lg\"\n [style.background-color]=\"bgColor()\"\n [style.color]=\"color()\"\n [class.ax-shadow-lg]=\"isEditing()\"\n [class.ax-scale-[1.02]]=\"isEditing()\"\n (dblclick)=\"activateEdit()\"\n>\n <!-- Header with timestamp -->\n <div class=\"ax-flex ax-justify-between ax-items-center ax-mb-3\">\n <div class=\"ax-text-xs ax-opacity-70 ax-font-medium ax-flex ax-items-center ax-gap-1\">\n <i class=\"fa-regular fa-clock ax-text-[0.65rem]\"></i>\n {{ date() | format : 'datetime' : 'dd MMM, YY HH:mm' | async }}\n </div>\n </div>\n\n <!-- Content area -->\n <div class=\"ax-flex-1 ax-overflow-auto\">\n <ax-wysiwyg-container\n #wysiwyg\n [class]=\"isEditing() ? 'ax-pointer-events-auto ax-cursor-text' : 'ax-pointer-events-none !ax-cursor-pointer'\"\n class=\"ax-h-full\"\n placeHolder=\"start writing with double click...\"\n look=\"none\"\n (onValueChanged)=\"valueChange($event)\"\n [ngModel]=\"value()\"\n >\n <ax-wysiwyg-view class=\"!ax-size-full ax-border-b-0\"></ax-wysiwyg-view>\n </ax-wysiwyg-container>\n </div>\n\n <!-- Footer with color selector and save button -->\n @if (isEditing()) {\n <div class=\"ax-absolute ax-bottom-2 ax-left-2 ax-right-2 ax-flex ax-flex-wrap ax-gap-1 ax-text-xs\">\n <!-- Color selection bar when in edit mode -->\n <div class=\"ax-flex ax-w-full ax-mt-2 ax-border ax-border-gray-200 ax-overflow-hidden ax-rounded-md\">\n @for (preset of colorPresets; track preset) {\n <div\n class=\"ax-h-6 ax-flex-1 ax-cursor-pointer ax-transition-all ax-duration-200 ax-border-r ax-border-gray-200 last:ax-border-r-0 hover:ax-brightness-95\"\n [style.background-color]=\"preset\"\n [class.ax-ring-inset]=\"bgColor() === preset\"\n [class.ax-ring-2]=\"bgColor() === preset\"\n [class.ax-ring-primary]=\"bgColor() === preset\"\n (click)=\"setColor(preset)\"\n ></div>\n }\n </div>\n </div>\n }\n</div>\n", styles: [":host{display:block;width:100%;height:100%}:host ::ng-deep ax-wysiwyg-view{color:#2e2e2e!important}\n"], dependencies: [{ kind: "ngmodule", type: AXWysiwygModule }, { kind: "component", type: i1$1.AXWysiwygContainerComponent, selector: "ax-wysiwyg-container", inputs: ["look", "placeHolder"], outputs: ["onValueChanged"] }, { kind: "component", type: i1$1.AXWysiwygViewComponent, selector: "ax-wysiwyg-view", inputs: ["class"] }, { kind: "ngmodule", type: AXDecoratorModule }, { kind: "ngmodule", type: AXToolBarModule }, { kind: "ngmodule", type: FormsModule }, { kind: "directive", type: i2$
|
2068
|
+
], viewQueries: [{ propertyName: "wysiwyg", first: true, predicate: ["wysiwyg"], descendants: true, isSignal: true }], usesInheritance: true, ngImport: i0, template: "<div\n class=\"sticky-note-container ax-size-full ax-rounded-lg ax-flex ax-flex-col ax-p-4 ax-shadow-md ax-transition-all ax-duration-300 hover:ax-shadow-lg\"\n [style.background-color]=\"bgColor()\"\n [style.color]=\"color()\"\n [class.ax-shadow-lg]=\"isEditing()\"\n [class.ax-scale-[1.02]]=\"isEditing()\"\n (dblclick)=\"activateEdit()\"\n>\n <!-- Header with timestamp -->\n <div class=\"ax-flex ax-justify-between ax-items-center ax-mb-3\">\n <div class=\"ax-text-xs ax-opacity-70 ax-font-medium ax-flex ax-items-center ax-gap-1\">\n <i class=\"fa-regular fa-clock ax-text-[0.65rem]\"></i>\n {{ date() | format : 'datetime' : 'dd MMM, YY HH:mm' | async }}\n </div>\n </div>\n\n <!-- Content area -->\n <div class=\"ax-flex-1 ax-overflow-auto\">\n <ax-wysiwyg-container\n #wysiwyg\n [class]=\"isEditing() ? 'ax-pointer-events-auto ax-cursor-text' : 'ax-pointer-events-none !ax-cursor-pointer'\"\n class=\"ax-h-full\"\n placeHolder=\"start writing with double click...\"\n look=\"none\"\n (onValueChanged)=\"valueChange($event)\"\n [ngModel]=\"value()\"\n >\n <ax-wysiwyg-view class=\"!ax-size-full ax-border-b-0\"></ax-wysiwyg-view>\n </ax-wysiwyg-container>\n </div>\n\n <!-- Footer with color selector and save button -->\n @if (isEditing()) {\n <div class=\"ax-absolute ax-bottom-2 ax-left-2 ax-right-2 ax-flex ax-flex-wrap ax-gap-1 ax-text-xs\">\n <!-- Color selection bar when in edit mode -->\n <div class=\"ax-flex ax-w-full ax-mt-2 ax-border ax-border-gray-200 ax-overflow-hidden ax-rounded-md\">\n @for (preset of colorPresets; track preset) {\n <div\n class=\"ax-h-6 ax-flex-1 ax-cursor-pointer ax-transition-all ax-duration-200 ax-border-r ax-border-gray-200 last:ax-border-r-0 hover:ax-brightness-95\"\n [style.background-color]=\"preset\"\n [class.ax-ring-inset]=\"bgColor() === preset\"\n [class.ax-ring-2]=\"bgColor() === preset\"\n [class.ax-ring-primary]=\"bgColor() === preset\"\n (click)=\"setColor(preset)\"\n ></div>\n }\n </div>\n </div>\n }\n</div>\n", styles: [":host{display:block;width:100%;height:100%}:host ::ng-deep ax-wysiwyg-view{color:#2e2e2e!important}\n"], dependencies: [{ kind: "ngmodule", type: AXWysiwygModule }, { kind: "component", type: i1$1.AXWysiwygContainerComponent, selector: "ax-wysiwyg-container", inputs: ["look", "placeHolder"], outputs: ["onValueChanged"] }, { kind: "component", type: i1$1.AXWysiwygViewComponent, selector: "ax-wysiwyg-view", inputs: ["class"] }, { kind: "ngmodule", type: AXDecoratorModule }, { kind: "ngmodule", type: AXToolBarModule }, { kind: "ngmodule", type: FormsModule }, { kind: "directive", type: i2$1.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i2$1.NgModel, selector: "[ngModel]:not([formControlName]):not([formControl])", inputs: ["name", "disabled", "ngModel", "ngModelOptions"], outputs: ["ngModelChange"], exportAs: ["ngModel"] }, { kind: "ngmodule", type: AXDateTimeModule }, { kind: "ngmodule", type: AXFormatModule }, { kind: "pipe", type: i2.AXFormatPipe, name: "format" }, { kind: "ngmodule", type: AXPopoverModule }, { kind: "ngmodule", type: CommonModule }, { kind: "pipe", type: i1.AsyncPipe, name: "async" }, { kind: "ngmodule", type: AXColorBoxModule }], changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
|
3587
2069
|
}
|
3588
2070
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.0.3", ngImport: i0, type: AXPStickyNoteWidgetViewComponent, decorators: [{
|
3589
2071
|
type: Component,
|
@@ -3762,7 +2244,7 @@ class AXPTaskListWidgetViewComponent extends AXPValueWidgetComponent {
|
|
3762
2244
|
return Math.floor(diffMs / (1000 * 60 * 60 * 24));
|
3763
2245
|
}
|
3764
2246
|
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.0.3", ngImport: i0, type: AXPTaskListWidgetViewComponent, deps: null, target: i0.ɵɵFactoryTarget.Component }); }
|
3765
|
-
static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "19.0.3", type: AXPTaskListWidgetViewComponent, isStandalone: true, selector: "ng-component", outputs: { taskClick: "taskClick", taskCompleted: "taskCompleted" }, providers: [DatePipe], usesInheritance: true, ngImport: i0, template: "<div class=\"ax-size-full ax-p-4\">\n <!-- Header -->\n <div class=\"ax-flex ax-justify-between ax-items-center ax-mb-3\">\n <h3 class=\"ax-text-lg ax-font-semibold\">{{ 'widget.tasklist.title' | translate | async }}</h3>\n <div class=\"ax-flex ax-gap-2\">\n @if(getPendingTaskCount() > 0){\n <ax-badge\n [text]=\"getPendingTaskCount() + ' ' + ('widget.tasklist.pending' | translate | async)\"\n [color]=\"'warning'\"\n size=\"sm\"\n class=\"ax-ml-1\"\n >\n </ax-badge>\n } @if(getCompletedTaskCount() > 0){\n <ax-badge\n [text]=\"getCompletedTaskCount() + ' ' + ('widget.tasklist.completed' | translate | async)\"\n [color]=\"'success'\"\n size=\"sm\"\n class=\"ax-ml-1\"\n >\n </ax-badge>\n }\n </div>\n </div>\n\n <!-- Task List -->\n <div class=\"ax-space-y-4 ax-my-4 ax-px-2\">\n @if (showCategories() && hasCategories()) {\n <!-- Categorized Tasks -->\n @for (category of getCategories(); track category) {\n <div class=\"ax-mb-3\">\n <!-- Category Header -->\n <div class=\"ax-flex ax-justify-between ax-items-center ax-mb-2 ax-h-5\">\n <h4 class=\"ax-font-medium ax-text-gray-700\">{{ category }}</h4>\n @if(getCategoryTaskCount(category)){\n <ax-badge [text]=\"getCategoryTaskCount(category).toString()\" [color]=\"'primary'\" size=\"sm\"></ax-badge>\n }\n </div>\n <!-- Tasks in Category -->\n @for (task of getTasksByCategory(category); track task.id) {\n <ng-container\n [ngTemplateOutlet]=\"taskItemTemplateRef\"\n [ngTemplateOutletContext]=\"{ $implicit: task }\"\n ></ng-container>\n }\n </div>\n } } @else {\n <!-- Uncategorized Tasks -->\n @for (task of taskItems(); track task.id) {\n <ng-container\n [ngTemplateOutlet]=\"taskItemTemplateRef\"\n [ngTemplateOutletContext]=\"{ $implicit: task }\"\n ></ng-container>\n } @empty {\n <!-- Empty State -->\n <div class=\"ax-flex ax-flex-col ax-items-center ax-justify-center ax-py-12 ax-px-4 ax-text-gray-400\">\n <ax-icon class=\"ax-text-4xl ax-mb-3 ax-text-gray-300\">\n <i class=\"fa-light fa-clipboard-list-check\"></i>\n </ax-icon>\n <p class=\"ax-text-center\">{{ 'widget.tasklist.noTasks' | translate | async }}</p>\n </div>\n } }\n </div>\n</div>\n\n<!-- Task Item Template -->\n<ng-template #taskItemTemplateRef let-task>\n <div class=\"ax-flex ax-gap-3 ax-items-center ax-py-2 ax-border-b ax-border-gray-100 last:ax-border-0\">\n <!-- Checkbox -->\n <ax-check-box\n class=\"ax-flex-shrink-0\"\n [value]=\"task.completed\"\n [disabled]=\"!allowMarkComplete()\"\n (valueChange)=\"onTaskCompletionChange(task, $event)\"\n >\n </ax-check-box>\n\n <!-- Task Details -->\n <div class=\"ax-overflow-hidden ax-grow ax-text-start\" (click)=\"onTaskClick(task)\">\n <!-- Title and Priority -->\n <div class=\"ax-flex ax-items-center ax-gap-2\">\n <h6\n class=\"ax-font-semibold ax-truncate ax-pb-1\"\n [class.ax-line-through]=\"task.completed\"\n [class.ax-text-gray-400]=\"task.completed\"\n >\n {{ task.title }}\n </h6>\n @if(showPriority() && task.priority) {\n <ax-badge [color]=\"getPriorityColor(task.priority)\" [text]=\"task.priority\" size=\"sm\" class=\"ax-ml-1\"></ax-badge>\n }\n </div>\n\n <!-- Metadata -->\n <div class=\"ax-flex ax-flex-wrap ax-gap-x-3 ax-gap-y-1 ax-mt-1 ax-text-xs ax-text-gray-500\">\n @if(showDate() && task.dueDate) {\n <span class=\"ax-flex ax-items-center ax-gap-1\" [class.ax-text-danger-500]=\"getDaysDifference(task.dueDate) < 0\">\n <ax-icon><i class=\"fa-light fa-calendar\"></i></ax-icon>\n {{ formatDueDate(task.dueDate) }}\n </span>\n } @if(showAssignee() && task.assignedTo) {\n <span class=\"ax-flex ax-items-center ax-gap-1\">\n <ax-icon><i class=\"fa-light fa-user\"></i></ax-icon>\n {{ task.assignedTo.name }}\n </span>\n }\n </div>\n </div>\n </div>\n</ng-template>\n", styles: [":host{display:block;height:100%;width:100%}.task-completed{text-decoration:line-through;color:var(--ax-text-secondary)}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "directive", type: i1.NgTemplateOutlet, selector: "[ngTemplateOutlet]", inputs: ["ngTemplateOutletContext", "ngTemplateOutlet", "ngTemplateOutletInjector"] }, { kind: "pipe", type: i1.AsyncPipe, name: "async" }, { kind: "ngmodule", type: AXTabsModule }, { kind: "ngmodule", type: AXDecoratorModule }, { kind: "component", type: i2$
|
2247
|
+
static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "19.0.3", type: AXPTaskListWidgetViewComponent, isStandalone: true, selector: "ng-component", outputs: { taskClick: "taskClick", taskCompleted: "taskCompleted" }, providers: [DatePipe], usesInheritance: true, ngImport: i0, template: "<div class=\"ax-size-full ax-p-4\">\n <!-- Header -->\n <div class=\"ax-flex ax-justify-between ax-items-center ax-mb-3\">\n <h3 class=\"ax-text-lg ax-font-semibold\">{{ 'widget.tasklist.title' | translate | async }}</h3>\n <div class=\"ax-flex ax-gap-2\">\n @if(getPendingTaskCount() > 0){\n <ax-badge\n [text]=\"getPendingTaskCount() + ' ' + ('widget.tasklist.pending' | translate | async)\"\n [color]=\"'warning'\"\n size=\"sm\"\n class=\"ax-ml-1\"\n >\n </ax-badge>\n } @if(getCompletedTaskCount() > 0){\n <ax-badge\n [text]=\"getCompletedTaskCount() + ' ' + ('widget.tasklist.completed' | translate | async)\"\n [color]=\"'success'\"\n size=\"sm\"\n class=\"ax-ml-1\"\n >\n </ax-badge>\n }\n </div>\n </div>\n\n <!-- Task List -->\n <div class=\"ax-space-y-4 ax-my-4 ax-px-2\">\n @if (showCategories() && hasCategories()) {\n <!-- Categorized Tasks -->\n @for (category of getCategories(); track category) {\n <div class=\"ax-mb-3\">\n <!-- Category Header -->\n <div class=\"ax-flex ax-justify-between ax-items-center ax-mb-2 ax-h-5\">\n <h4 class=\"ax-font-medium ax-text-gray-700\">{{ category }}</h4>\n @if(getCategoryTaskCount(category)){\n <ax-badge [text]=\"getCategoryTaskCount(category).toString()\" [color]=\"'primary'\" size=\"sm\"></ax-badge>\n }\n </div>\n <!-- Tasks in Category -->\n @for (task of getTasksByCategory(category); track task.id) {\n <ng-container\n [ngTemplateOutlet]=\"taskItemTemplateRef\"\n [ngTemplateOutletContext]=\"{ $implicit: task }\"\n ></ng-container>\n }\n </div>\n } } @else {\n <!-- Uncategorized Tasks -->\n @for (task of taskItems(); track task.id) {\n <ng-container\n [ngTemplateOutlet]=\"taskItemTemplateRef\"\n [ngTemplateOutletContext]=\"{ $implicit: task }\"\n ></ng-container>\n } @empty {\n <!-- Empty State -->\n <div class=\"ax-flex ax-flex-col ax-items-center ax-justify-center ax-py-12 ax-px-4 ax-text-gray-400\">\n <ax-icon class=\"ax-text-4xl ax-mb-3 ax-text-gray-300\">\n <i class=\"fa-light fa-clipboard-list-check\"></i>\n </ax-icon>\n <p class=\"ax-text-center\">{{ 'widget.tasklist.noTasks' | translate | async }}</p>\n </div>\n } }\n </div>\n</div>\n\n<!-- Task Item Template -->\n<ng-template #taskItemTemplateRef let-task>\n <div class=\"ax-flex ax-gap-3 ax-items-center ax-py-2 ax-border-b ax-border-gray-100 last:ax-border-0\">\n <!-- Checkbox -->\n <ax-check-box\n class=\"ax-flex-shrink-0\"\n [value]=\"task.completed\"\n [disabled]=\"!allowMarkComplete()\"\n (valueChange)=\"onTaskCompletionChange(task, $event)\"\n >\n </ax-check-box>\n\n <!-- Task Details -->\n <div class=\"ax-overflow-hidden ax-grow ax-text-start\" (click)=\"onTaskClick(task)\">\n <!-- Title and Priority -->\n <div class=\"ax-flex ax-items-center ax-gap-2\">\n <h6\n class=\"ax-font-semibold ax-truncate ax-pb-1\"\n [class.ax-line-through]=\"task.completed\"\n [class.ax-text-gray-400]=\"task.completed\"\n >\n {{ task.title }}\n </h6>\n @if(showPriority() && task.priority) {\n <ax-badge [color]=\"getPriorityColor(task.priority)\" [text]=\"task.priority\" size=\"sm\" class=\"ax-ml-1\"></ax-badge>\n }\n </div>\n\n <!-- Metadata -->\n <div class=\"ax-flex ax-flex-wrap ax-gap-x-3 ax-gap-y-1 ax-mt-1 ax-text-xs ax-text-gray-500\">\n @if(showDate() && task.dueDate) {\n <span class=\"ax-flex ax-items-center ax-gap-1\" [class.ax-text-danger-500]=\"getDaysDifference(task.dueDate) < 0\">\n <ax-icon><i class=\"fa-light fa-calendar\"></i></ax-icon>\n {{ formatDueDate(task.dueDate) }}\n </span>\n } @if(showAssignee() && task.assignedTo) {\n <span class=\"ax-flex ax-items-center ax-gap-1\">\n <ax-icon><i class=\"fa-light fa-user\"></i></ax-icon>\n {{ task.assignedTo.name }}\n </span>\n }\n </div>\n </div>\n </div>\n</ng-template>\n", styles: [":host{display:block;height:100%;width:100%}.task-completed{text-decoration:line-through;color:var(--ax-text-secondary)}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "directive", type: i1.NgTemplateOutlet, selector: "[ngTemplateOutlet]", inputs: ["ngTemplateOutletContext", "ngTemplateOutlet", "ngTemplateOutletInjector"] }, { kind: "pipe", type: i1.AsyncPipe, name: "async" }, { kind: "ngmodule", type: AXTabsModule }, { kind: "ngmodule", type: AXDecoratorModule }, { kind: "component", type: i2$2.AXDecoratorIconComponent, selector: "ax-icon", inputs: ["icon"] }, { kind: "ngmodule", type: AXButtonModule }, { kind: "ngmodule", type: AXBadgeModule }, { kind: "component", type: i3.AXBadgeComponent, selector: "ax-badge", inputs: ["color", "look", "text"] }, { kind: "ngmodule", type: AXAvatarModule }, { kind: "ngmodule", type: AXImageModule }, { kind: "ngmodule", type: AXCheckBoxModule }, { kind: "component", type: i4.AXCheckBoxComponent, selector: "ax-check-box", inputs: ["disabled", "tabIndex", "readonly", "color", "value", "name", "id", "checked", "indeterminate"], outputs: ["onBlur", "onFocus", "valueChange", "onValueChanged"] }, { kind: "ngmodule", type: AXLabelModule }, { kind: "ngmodule", type: AXTranslationModule }, { kind: "pipe", type: i5.AXTranslatorPipe, name: "translate" }], changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
|
3766
2248
|
}
|
3767
2249
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.0.3", ngImport: i0, type: AXPTaskListWidgetViewComponent, decorators: [{
|
3768
2250
|
type: Component,
|
@@ -3794,6 +2276,25 @@ const AXPTaskListWidget = {
|
|
3794
2276
|
icon: 'fa-light fa-clipboard-list-check',
|
3795
2277
|
properties: [
|
3796
2278
|
cloneProperty(AXP_DATA_PATH_PROPERTY, { visible: false }),
|
2279
|
+
// ====== Title ======
|
2280
|
+
{
|
2281
|
+
name: 'title',
|
2282
|
+
title: 'Chart Title',
|
2283
|
+
group: AXP_APPEARANCE_PROPERTY_GROUP,
|
2284
|
+
schema: {
|
2285
|
+
defaultValue: '',
|
2286
|
+
dataType: 'string',
|
2287
|
+
interface: {
|
2288
|
+
name: 'title',
|
2289
|
+
path: 'options.title',
|
2290
|
+
type: AXPWidgetsCatalog.text,
|
2291
|
+
options: {
|
2292
|
+
placeholder: 'Enter chart title',
|
2293
|
+
},
|
2294
|
+
},
|
2295
|
+
},
|
2296
|
+
visible: true,
|
2297
|
+
},
|
3797
2298
|
// Display options
|
3798
2299
|
{
|
3799
2300
|
name: 'maxItems',
|
@@ -4944,6 +3445,179 @@ const AXPWeatherWidget = {
|
|
4944
3445
|
},
|
4945
3446
|
};
|
4946
3447
|
|
3448
|
+
class AXPDashboardShortcutWidgetViewComponent extends AXPLayoutWidgetComponent {
|
3449
|
+
constructor() {
|
3450
|
+
super(...arguments);
|
3451
|
+
this.popupService = inject(AXPopupService);
|
3452
|
+
this.workflow = inject(AXPWorkflowService);
|
3453
|
+
this.searchConfig = inject(AXP_GLOBAL_SEARCH_CONFIG_TOKEN);
|
3454
|
+
this.item = computed(() => this.options()['item']);
|
3455
|
+
this.color = computed(() => this.options()['color']);
|
3456
|
+
}
|
3457
|
+
ngOnInit() {
|
3458
|
+
super.ngOnInit();
|
3459
|
+
if (!this.color()) {
|
3460
|
+
this.setOptions({
|
3461
|
+
color: AXPDataGenerator.color()
|
3462
|
+
});
|
3463
|
+
}
|
3464
|
+
}
|
3465
|
+
async executeCommand() {
|
3466
|
+
if (this.item()?.command) {
|
3467
|
+
await this.workflow.execute(this.item().command.name, this.item().command.options);
|
3468
|
+
}
|
3469
|
+
}
|
3470
|
+
async setCommand() {
|
3471
|
+
const component = await this.searchConfig.window();
|
3472
|
+
const popup = await this.popupService.open(component, {
|
3473
|
+
title: 'Choose command...',
|
3474
|
+
size: 'fit',
|
3475
|
+
closeOnBackdropClick: true,
|
3476
|
+
header: false,
|
3477
|
+
});
|
3478
|
+
if (popup.data) {
|
3479
|
+
const result = popup.data;
|
3480
|
+
if (result && result.command) {
|
3481
|
+
this.setOptions({
|
3482
|
+
item: {
|
3483
|
+
name: result.name,
|
3484
|
+
title: result.title,
|
3485
|
+
description: result.description,
|
3486
|
+
icon: result.icon,
|
3487
|
+
command: result.command
|
3488
|
+
}
|
3489
|
+
});
|
3490
|
+
}
|
3491
|
+
}
|
3492
|
+
}
|
3493
|
+
get __style() {
|
3494
|
+
const cls = {};
|
3495
|
+
cls[`background-color`] = this.color();
|
3496
|
+
return cls;
|
3497
|
+
}
|
3498
|
+
get __class() {
|
3499
|
+
const cls = {};
|
3500
|
+
cls[`ax-flex`] = true;
|
3501
|
+
cls[`ax-flex-col`] = true;
|
3502
|
+
cls[`ax-items-center`] = true;
|
3503
|
+
cls[`ax-justify-center`] = true;
|
3504
|
+
cls[`ax-w-full`] = true;
|
3505
|
+
cls[`ax-h-full`] = true;
|
3506
|
+
cls[`ax-text-center`] = true;
|
3507
|
+
cls[`ax-overflow-hidden`] = true;
|
3508
|
+
cls[`ax-cursor-pointer`] = true;
|
3509
|
+
cls[`ax-text-white`] = true;
|
3510
|
+
return cls;
|
3511
|
+
}
|
3512
|
+
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.0.3", ngImport: i0, type: AXPDashboardShortcutWidgetViewComponent, deps: null, target: i0.ɵɵFactoryTarget.Component }); }
|
3513
|
+
static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "19.0.3", type: AXPDashboardShortcutWidgetViewComponent, isStandalone: true, selector: "ng-component", host: { properties: { "style": "this.__style", "class": "this.__class" } }, usesInheritance: true, ngImport: i0, template: `
|
3514
|
+
@if(item()) {
|
3515
|
+
<div
|
3516
|
+
class="ax-group ax-flex ax-flex-col ax-items-center ax-justify-center ax-p-3 ax-w-full ax-h-full ax-relative ax-overflow-hidden "
|
3517
|
+
(click)="executeCommand()">
|
3518
|
+
<div class="ax-absolute ax-inset-0 ax-bg-black/0 hover:ax-bg-black/10 ax-transition-opacity"></div>
|
3519
|
+
<i [class]="item().icon + ' ax-text-3xl'"></i>
|
3520
|
+
<span class="ax-text-xl ax-font-semibold">{{ item().title | translate | async }}</span>
|
3521
|
+
@if(item().description) {
|
3522
|
+
<span class="ax-text-sm ax-opacity-90 ax-text-center ax-px-2">{{ item().description! | translate | async }}</span>
|
3523
|
+
}
|
3524
|
+
</div>
|
3525
|
+
} @else {
|
3526
|
+
<div
|
3527
|
+
(click)="setCommand()"
|
3528
|
+
class="ax-group ax-flex ax-flex-col ax-items-center ax-justify-center ax-p-3 ax-w-full ax-h-full ax-relative ax-overflow-hidden">
|
3529
|
+
<div class="ax-absolute ax-inset-0 ax-bg-black/0 hover:ax-bg-black/5 ax-transition-opacity"></div>
|
3530
|
+
<i class="fa-light fa-plus ax-text-3xl"></i>
|
3531
|
+
<span class="ax-text-xl ax-font-semibold">Add Shortcut</span>
|
3532
|
+
</div>
|
3533
|
+
}
|
3534
|
+
`, isInline: true, dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "pipe", type: i1.AsyncPipe, name: "async" }, { kind: "ngmodule", type: AXTranslationModule }, { kind: "pipe", type: i5.AXTranslatorPipe, name: "translate" }], changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
|
3535
|
+
}
|
3536
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.0.3", ngImport: i0, type: AXPDashboardShortcutWidgetViewComponent, decorators: [{
|
3537
|
+
type: Component,
|
3538
|
+
args: [{
|
3539
|
+
template: `
|
3540
|
+
@if(item()) {
|
3541
|
+
<div
|
3542
|
+
class="ax-group ax-flex ax-flex-col ax-items-center ax-justify-center ax-p-3 ax-w-full ax-h-full ax-relative ax-overflow-hidden "
|
3543
|
+
(click)="executeCommand()">
|
3544
|
+
<div class="ax-absolute ax-inset-0 ax-bg-black/0 hover:ax-bg-black/10 ax-transition-opacity"></div>
|
3545
|
+
<i [class]="item().icon + ' ax-text-3xl'"></i>
|
3546
|
+
<span class="ax-text-xl ax-font-semibold">{{ item().title | translate | async }}</span>
|
3547
|
+
@if(item().description) {
|
3548
|
+
<span class="ax-text-sm ax-opacity-90 ax-text-center ax-px-2">{{ item().description! | translate | async }}</span>
|
3549
|
+
}
|
3550
|
+
</div>
|
3551
|
+
} @else {
|
3552
|
+
<div
|
3553
|
+
(click)="setCommand()"
|
3554
|
+
class="ax-group ax-flex ax-flex-col ax-items-center ax-justify-center ax-p-3 ax-w-full ax-h-full ax-relative ax-overflow-hidden">
|
3555
|
+
<div class="ax-absolute ax-inset-0 ax-bg-black/0 hover:ax-bg-black/5 ax-transition-opacity"></div>
|
3556
|
+
<i class="fa-light fa-plus ax-text-3xl"></i>
|
3557
|
+
<span class="ax-text-xl ax-font-semibold">Add Shortcut</span>
|
3558
|
+
</div>
|
3559
|
+
}
|
3560
|
+
`,
|
3561
|
+
standalone: true,
|
3562
|
+
changeDetection: ChangeDetectionStrategy.OnPush,
|
3563
|
+
imports: [CommonModule, AXTranslationModule]
|
3564
|
+
}]
|
3565
|
+
}], propDecorators: { __style: [{
|
3566
|
+
type: HostBinding,
|
3567
|
+
args: ['style']
|
3568
|
+
}], __class: [{
|
3569
|
+
type: HostBinding,
|
3570
|
+
args: ['class']
|
3571
|
+
}] } });
|
3572
|
+
|
3573
|
+
var dashboardShortcutWidgetView_component = /*#__PURE__*/Object.freeze({
|
3574
|
+
__proto__: null,
|
3575
|
+
AXPDashboardShortcutWidgetViewComponent: AXPDashboardShortcutWidgetViewComponent
|
3576
|
+
});
|
3577
|
+
|
3578
|
+
const AXPDashboardShortcutWidget = {
|
3579
|
+
name: "dashboard-shortcut",
|
3580
|
+
title: "Shortcut",
|
3581
|
+
description: 'Quick access to your key features.',
|
3582
|
+
type: 'view',
|
3583
|
+
categories: [AXP_WIDGETS_UTILITY_CATEGORY],
|
3584
|
+
groups: [AXPWidgetGroupEnum.DashboardWidget],
|
3585
|
+
icon: "fa-light fa-link",
|
3586
|
+
properties: [
|
3587
|
+
AXP_COLOR_PROPERTY
|
3588
|
+
],
|
3589
|
+
meta: {
|
3590
|
+
dimensions: {
|
3591
|
+
width: 2,
|
3592
|
+
height: 2,
|
3593
|
+
minWidth: 1,
|
3594
|
+
minHeight: 1,
|
3595
|
+
maxWidth: 3,
|
3596
|
+
maxHeight: 2,
|
3597
|
+
},
|
3598
|
+
},
|
3599
|
+
components: {
|
3600
|
+
view: {
|
3601
|
+
component: () => Promise.resolve().then(function () { return dashboardShortcutWidgetView_component; }).then((c) => c.AXPDashboardShortcutWidgetViewComponent),
|
3602
|
+
},
|
3603
|
+
}
|
3604
|
+
};
|
3605
|
+
|
3606
|
+
class AXMMenuProvider {
|
3607
|
+
constructor() {
|
3608
|
+
this.sessionService = inject(AXPSessionService);
|
3609
|
+
}
|
3610
|
+
async provide(context) {
|
3611
|
+
const scope = RootConfig.config.i18n;
|
3612
|
+
const module = RootConfig.module;
|
3613
|
+
const appName = this.sessionService.application?.name;
|
3614
|
+
const isAuthorized = await firstValueFrom(this.sessionService.isAuthorized$);
|
3615
|
+
if (!isAuthorized) {
|
3616
|
+
return;
|
3617
|
+
}
|
3618
|
+
}
|
3619
|
+
}
|
3620
|
+
|
4947
3621
|
function routesFactory() {
|
4948
3622
|
const config = inject(AXP_ENTITY_CONFIG_TOKEN);
|
4949
3623
|
return {
|
@@ -4955,14 +3629,14 @@ function routesFactory() {
|
|
4955
3629
|
children: [
|
4956
3630
|
{
|
4957
3631
|
path: 'dashboard',
|
4958
|
-
loadComponent: () => import('./acorex-modules-dashboard-management-home-dashboard-
|
3632
|
+
loadComponent: () => import('./acorex-modules-dashboard-management-home-dashboard-DiPn_RhH.mjs').then((c) => c.AXMDashboardHomeComponent),
|
4959
3633
|
},
|
4960
3634
|
],
|
4961
3635
|
};
|
4962
3636
|
}
|
4963
3637
|
class AXMDashboardManagementModule {
|
4964
3638
|
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.0.3", ngImport: i0, type: AXMDashboardManagementModule, deps: [], target: i0.ɵɵFactoryTarget.NgModule }); }
|
4965
|
-
static { this.ɵmod = i0.ɵɵngDeclareNgModule({ minVersion: "14.0.0", version: "19.0.3", ngImport: i0, type: AXMDashboardManagementModule, imports: [i3.AXPLayoutBuilderModule] }); }
|
3639
|
+
static { this.ɵmod = i0.ɵɵngDeclareNgModule({ minVersion: "14.0.0", version: "19.0.3", ngImport: i0, type: AXMDashboardManagementModule, imports: [i3$1.AXPLayoutBuilderModule] }); }
|
4966
3640
|
static { this.ɵinj = i0.ɵɵngDeclareInjector({ minVersion: "12.0.0", version: "19.0.3", ngImport: i0, type: AXMDashboardManagementModule, providers: [
|
4967
3641
|
{
|
4968
3642
|
provide: AXMDashboardService,
|
@@ -4975,8 +3649,8 @@ class AXMDashboardManagementModule {
|
|
4975
3649
|
{
|
4976
3650
|
key: 'dashboard',
|
4977
3651
|
title: 'Dashboard',
|
4978
|
-
route: routesFactory()
|
4979
|
-
}
|
3652
|
+
route: routesFactory(),
|
3653
|
+
},
|
4980
3654
|
],
|
4981
3655
|
},
|
4982
3656
|
AXPWidgetsModule,
|
@@ -5009,7 +3683,6 @@ class AXMDashboardManagementModule {
|
|
5009
3683
|
AXPStickyNoteWidget,
|
5010
3684
|
AXPClockCalendarWidget,
|
5011
3685
|
AXPWeatherWidget,
|
5012
|
-
AXPNotificationWidget,
|
5013
3686
|
AXPTaskListWidget,
|
5014
3687
|
],
|
5015
3688
|
})] }); }
|
@@ -5029,7 +3702,6 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.0.3", ngImpor
|
|
5029
3702
|
AXPStickyNoteWidget,
|
5030
3703
|
AXPClockCalendarWidget,
|
5031
3704
|
AXPWeatherWidget,
|
5032
|
-
AXPNotificationWidget,
|
5033
3705
|
AXPTaskListWidget,
|
5034
3706
|
],
|
5035
3707
|
}),
|
@@ -5048,8 +3720,8 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.0.3", ngImpor
|
|
5048
3720
|
{
|
5049
3721
|
key: 'dashboard',
|
5050
3722
|
title: 'Dashboard',
|
5051
|
-
route: routesFactory()
|
5052
|
-
}
|
3723
|
+
route: routesFactory(),
|
3724
|
+
},
|
5053
3725
|
],
|
5054
3726
|
},
|
5055
3727
|
AXPWidgetsModule,
|
@@ -5079,5 +3751,5 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.0.3", ngImpor
|
|
5079
3751
|
* Generated bundle index. Do not edit.
|
5080
3752
|
*/
|
5081
3753
|
|
5082
|
-
export { AXMDashboardService as A,
|
5083
|
-
//# sourceMappingURL=acorex-modules-dashboard-management-acorex-modules-dashboard-management-
|
3754
|
+
export { AXMDashboardService as A, RootConfig as R, AXMDashboardManagementModule as a, AXPBarChartWidgetViewComponent as b, AXPBarChartWidget as c, AXP_WIDGETS_CHART_CATEGORY as d, AXP_WIDGETS_UTILITY_CATEGORY as e, AXPClockCalendarWidgetViewComponent as f, AXPClockCalendarWidget as g, AXP_TIMEZONE_OPTIONS as h, AXP_DATE_FORMAT_OPTIONS as i, AXPDonutChartWidgetViewComponent as j, AXPDonutChartWidget as k, AXPGaugeChartWidgetViewComponent as l, AXPGaugeChartWidget as m, AXPLineChartWidgetViewComponent as n, AXPLineChartWidget as o, AXPStickyNoteWidgetViewComponent as p, AXPStickyNoteWidget as q, AXPTaskListWidgetViewComponent as r, AXPTaskListWidget as s, AXPWeatherApiAbstract as t, AXPWeatherApiMockService as u, AXPWeatherApiService as v, AXPWeatherWidgetViewComponent as w, AXPWeatherWidget as x };
|
3755
|
+
//# sourceMappingURL=acorex-modules-dashboard-management-acorex-modules-dashboard-management-VORBD1g-.mjs.map
|