@akcelik/strct 0.28.0 → 0.30.0
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/fesm2022/akcelik-strct.mjs +794 -139
- package/fesm2022/akcelik-strct.mjs.map +1 -1
- package/package.json +3 -2
- package/types/akcelik-strct.d.ts +145 -14
|
@@ -1,7 +1,8 @@
|
|
|
1
1
|
import * as i0 from '@angular/core';
|
|
2
2
|
import { inject, DOCUMENT, signal, computed, Injectable, input, ViewEncapsulation, ChangeDetectionStrategy, Component, ElementRef, NgZone, afterNextRender, Directive, model, output, booleanAttribute, HostListener, contentChildren, effect, ApplicationRef, EnvironmentInjector, createComponent, forwardRef, DestroyRef, contentChild, viewChild, viewChildren, TemplateRef, untracked, Renderer2 } from '@angular/core';
|
|
3
3
|
import { DomSanitizer } from '@angular/platform-browser';
|
|
4
|
-
import { DOCUMENT as DOCUMENT$1
|
|
4
|
+
import { NgTemplateOutlet, DOCUMENT as DOCUMENT$1 } from '@angular/common';
|
|
5
|
+
import { RouterLink, RouterLinkActive } from '@angular/router';
|
|
5
6
|
import { NG_VALUE_ACCESSOR } from '@angular/forms';
|
|
6
7
|
|
|
7
8
|
/** All palettes the token system ships with, in display order. */
|
|
@@ -1039,16 +1040,90 @@ class StrctRail {
|
|
|
1039
1040
|
ariaLabel = input('Primary', ...(ngDevMode ? [{ debugName: "ariaLabel" }] : /* istanbul ignore next */ []));
|
|
1040
1041
|
/** Emitted when an item is chosen. */
|
|
1041
1042
|
select = output();
|
|
1042
|
-
|
|
1043
|
+
topItems = computed(() => this.items().filter((i) => i.placement !== 'bottom'), ...(ngDevMode ? [{ debugName: "topItems" }] : /* istanbul ignore next */ []));
|
|
1044
|
+
bottomItems = computed(() => this.items().filter((i) => i.placement === 'bottom'), ...(ngDevMode ? [{ debugName: "bottomItems" }] : /* istanbul ignore next */ []));
|
|
1045
|
+
/** Enabled item with a router destination → renders as `<a routerLink>`. */
|
|
1046
|
+
isRouted(item) {
|
|
1047
|
+
return item.routerLink != null && !item.disabled;
|
|
1048
|
+
}
|
|
1049
|
+
/**
|
|
1050
|
+
* Active state of a router-link item: an explicit `activeId` is authoritative;
|
|
1051
|
+
* without one, the router's own active state drives it.
|
|
1052
|
+
*/
|
|
1053
|
+
isActive(item, routerActive) {
|
|
1054
|
+
const id = this.activeId();
|
|
1055
|
+
return id !== null ? item.id === id : routerActive;
|
|
1056
|
+
}
|
|
1057
|
+
pick(item, event) {
|
|
1043
1058
|
if (item.disabled)
|
|
1044
1059
|
return;
|
|
1060
|
+
// A modified / non-primary click on a link is the browser's (new tab etc.) —
|
|
1061
|
+
// never ours: no activeId change, no (select).
|
|
1062
|
+
if (event &&
|
|
1063
|
+
(item.routerLink != null || item.href) &&
|
|
1064
|
+
(event.button !== 0 || event.metaKey || event.ctrlKey || event.shiftKey || event.altKey)) {
|
|
1065
|
+
return;
|
|
1066
|
+
}
|
|
1045
1067
|
this.activeId.set(item.id);
|
|
1046
1068
|
this.select.emit(item);
|
|
1047
1069
|
}
|
|
1048
1070
|
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.16", ngImport: i0, type: StrctRail, deps: [], target: i0.ɵɵFactoryTarget.Component });
|
|
1049
1071
|
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.16", type: StrctRail, isStandalone: true, selector: "strct-rail", inputs: { items: { classPropertyName: "items", publicName: "items", isSignal: true, isRequired: true, transformFunction: null }, activeId: { classPropertyName: "activeId", publicName: "activeId", isSignal: true, isRequired: false, transformFunction: null }, collapsed: { classPropertyName: "collapsed", publicName: "collapsed", isSignal: true, isRequired: false, transformFunction: null }, collapsible: { classPropertyName: "collapsible", publicName: "collapsible", isSignal: true, isRequired: false, transformFunction: null }, ariaLabel: { classPropertyName: "ariaLabel", publicName: "ariaLabel", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { activeId: "activeIdChange", collapsed: "collapsedChange", select: "select" }, host: { properties: { "class.strct-rail--collapsed": "collapsed()" }, classAttribute: "strct-rail" }, ngImport: i0, template: `
|
|
1050
|
-
|
|
1051
|
-
|
|
1072
|
+
<!-- Shared row content: icon, label, trailing indicator, badge / dot. -->
|
|
1073
|
+
<ng-template #rowContent let-item>
|
|
1074
|
+
<strct-icon class="strct-rail__icon" [name]="item.icon" [size]="18" [strokeWidth]="1.6" />
|
|
1075
|
+
@if (!collapsed()) {
|
|
1076
|
+
<span class="strct-rail__label">{{ item.label }}</span>
|
|
1077
|
+
@if (item.trailingIcon) {
|
|
1078
|
+
<strct-icon
|
|
1079
|
+
class="strct-rail__trailing"
|
|
1080
|
+
[name]="item.trailingIcon"
|
|
1081
|
+
[size]="14"
|
|
1082
|
+
[strokeWidth]="1.5"
|
|
1083
|
+
/>
|
|
1084
|
+
}
|
|
1085
|
+
}
|
|
1086
|
+
@if (item.badge !== undefined && item.badge !== null && item.badge !== '') {
|
|
1087
|
+
<span
|
|
1088
|
+
class="strct-rail__badge strct-rail__badge--{{ item.badgeStatus ?? 'accent' }}"
|
|
1089
|
+
[class.strct-rail__badge--dot]="collapsed()"
|
|
1090
|
+
>
|
|
1091
|
+
@if (!collapsed()) {
|
|
1092
|
+
{{ item.badge }}
|
|
1093
|
+
}
|
|
1094
|
+
</span>
|
|
1095
|
+
} @else if (item.dot) {
|
|
1096
|
+
<span class="strct-rail__dot strct-rail__dot--{{ item.dotStatus ?? 'accent' }}"></span>
|
|
1097
|
+
}
|
|
1098
|
+
</ng-template>
|
|
1099
|
+
|
|
1100
|
+
<!-- One rail row: a router link, a plain link, or a button (today's default). -->
|
|
1101
|
+
<ng-template #row let-item>
|
|
1102
|
+
@if (isRouted(item)) {
|
|
1103
|
+
<a
|
|
1104
|
+
class="strct-rail__item"
|
|
1105
|
+
[routerLink]="item.routerLink"
|
|
1106
|
+
routerLinkActive
|
|
1107
|
+
#rla="routerLinkActive"
|
|
1108
|
+
[class.strct-rail__item--active]="isActive(item, rla.isActive)"
|
|
1109
|
+
[attr.aria-current]="isActive(item, rla.isActive) ? 'page' : null"
|
|
1110
|
+
[attr.title]="collapsed() ? item.label : null"
|
|
1111
|
+
(click)="pick(item, $event)"
|
|
1112
|
+
>
|
|
1113
|
+
<ng-container *ngTemplateOutlet="rowContent; context: { $implicit: item }" />
|
|
1114
|
+
</a>
|
|
1115
|
+
} @else if (item.href && !item.disabled) {
|
|
1116
|
+
<a
|
|
1117
|
+
class="strct-rail__item"
|
|
1118
|
+
[href]="item.href"
|
|
1119
|
+
[class.strct-rail__item--active]="item.id === activeId()"
|
|
1120
|
+
[attr.aria-current]="item.id === activeId() ? 'page' : null"
|
|
1121
|
+
[attr.title]="collapsed() ? item.label : null"
|
|
1122
|
+
(click)="pick(item, $event)"
|
|
1123
|
+
>
|
|
1124
|
+
<ng-container *ngTemplateOutlet="rowContent; context: { $implicit: item }" />
|
|
1125
|
+
</a>
|
|
1126
|
+
} @else {
|
|
1052
1127
|
<button
|
|
1053
1128
|
type="button"
|
|
1054
1129
|
class="strct-rail__item"
|
|
@@ -1056,24 +1131,26 @@ class StrctRail {
|
|
|
1056
1131
|
[disabled]="item.disabled"
|
|
1057
1132
|
[attr.aria-current]="item.id === activeId() ? 'page' : null"
|
|
1058
1133
|
[attr.title]="collapsed() ? item.label : null"
|
|
1059
|
-
(click)="pick(item)"
|
|
1134
|
+
(click)="pick(item, $event)"
|
|
1060
1135
|
>
|
|
1061
|
-
<
|
|
1062
|
-
@if (!collapsed()) {
|
|
1063
|
-
<span class="strct-rail__label">{{ item.label }}</span>
|
|
1064
|
-
}
|
|
1065
|
-
@if (item.badge !== undefined && item.badge !== null && item.badge !== '') {
|
|
1066
|
-
<span
|
|
1067
|
-
class="strct-rail__badge strct-rail__badge--{{ item.badgeStatus ?? 'accent' }}"
|
|
1068
|
-
[class.strct-rail__badge--dot]="collapsed()"
|
|
1069
|
-
>
|
|
1070
|
-
@if (!collapsed()) {
|
|
1071
|
-
{{ item.badge }}
|
|
1072
|
-
}
|
|
1073
|
-
</span>
|
|
1074
|
-
}
|
|
1136
|
+
<ng-container *ngTemplateOutlet="rowContent; context: { $implicit: item }" />
|
|
1075
1137
|
</button>
|
|
1076
1138
|
}
|
|
1139
|
+
</ng-template>
|
|
1140
|
+
|
|
1141
|
+
<nav class="strct-rail__nav" [attr.aria-label]="ariaLabel()">
|
|
1142
|
+
<div class="strct-rail__group strct-rail__group--top">
|
|
1143
|
+
@for (item of topItems(); track item.id) {
|
|
1144
|
+
<ng-container *ngTemplateOutlet="row; context: { $implicit: item }" />
|
|
1145
|
+
}
|
|
1146
|
+
</div>
|
|
1147
|
+
@if (bottomItems().length) {
|
|
1148
|
+
<div class="strct-rail__group strct-rail__group--bottom">
|
|
1149
|
+
@for (item of bottomItems(); track item.id) {
|
|
1150
|
+
<ng-container *ngTemplateOutlet="row; context: { $implicit: item }" />
|
|
1151
|
+
}
|
|
1152
|
+
</div>
|
|
1153
|
+
}
|
|
1077
1154
|
</nav>
|
|
1078
1155
|
|
|
1079
1156
|
@if (collapsible()) {
|
|
@@ -1090,13 +1167,66 @@ class StrctRail {
|
|
|
1090
1167
|
}
|
|
1091
1168
|
</button>
|
|
1092
1169
|
}
|
|
1093
|
-
`, isInline: true, styles: [".strct-rail{display:flex;flex-direction:column;width:232px;flex-shrink:0;background:var(--bg-1);border-inline-end:1px solid var(--b2);overflow:hidden;transition:width .16s ease}.strct-rail--collapsed{width:60px}.strct-rail__nav{flex:1;display:flex;flex-direction:column;gap:2px;
|
|
1170
|
+
`, isInline: true, styles: [".strct-rail{display:flex;flex-direction:column;width:232px;flex-shrink:0;background:var(--bg-1);border-inline-end:1px solid var(--b2);overflow:hidden;transition:width .16s ease}.strct-rail--collapsed{width:60px}.strct-rail__nav{flex:1;min-height:0;display:flex;flex-direction:column;padding:8px}.strct-rail__group{display:flex;flex-direction:column;gap:2px}.strct-rail__group--top{flex:1;min-height:0;overflow-y:auto}.strct-rail__group--bottom{margin-top:8px;padding-top:8px;border-top:1px solid var(--b1)}.strct-rail__item{position:relative;display:flex;align-items:center;gap:11px;width:100%;box-sizing:border-box;padding:8px 10px;border:0;border-radius:8px;background:transparent;color:var(--t2);cursor:pointer;font-size:13.5px;font-family:var(--font);text-align:start;text-decoration:none;white-space:nowrap;transition:background .14s ease,color .14s ease}.strct-rail--collapsed .strct-rail__item{justify-content:center;padding:8px}.strct-rail__item:hover:not(:disabled){background:var(--bg-3);color:var(--t1)}.strct-rail__item--active{background:var(--acc-m);color:var(--acc)}.strct-rail__item--active .strct-rail__icon{color:var(--acc)}.strct-rail__item:disabled{opacity:.5;cursor:not-allowed}.strct-rail__item:focus-visible{outline:2px solid var(--acc50);outline-offset:-2px}.strct-rail__icon{flex-shrink:0}.strct-rail__label{flex:1;overflow:hidden;text-overflow:ellipsis}.strct-rail__badge{flex-shrink:0;min-width:18px;height:18px;padding:0 5px;display:inline-flex;align-items:center;justify-content:center;font-size:12px;font-weight:600;line-height:1;border-radius:9px;font-variant-numeric:tabular-nums}.strct-rail__badge--dot{position:absolute;top:5px;right:7px;min-width:8px;width:8px;height:8px;padding:0;border-radius:50%}.strct-rail__badge--accent{background:var(--acc-m);color:var(--acc)}.strct-rail__badge--success{background:var(--success-bg);color:var(--success)}.strct-rail__badge--warning{background:var(--warning-bg);color:var(--warning)}.strct-rail__badge--critical{background:var(--critical-bg);color:var(--critical)}.strct-rail__badge--dot.strct-rail__badge--accent{background:var(--acc)}.strct-rail__badge--dot.strct-rail__badge--success{background:var(--success)}.strct-rail__badge--dot.strct-rail__badge--warning{background:var(--warning)}.strct-rail__badge--dot.strct-rail__badge--critical{background:var(--critical)}.strct-rail__trailing{flex-shrink:0;color:var(--t3)}.strct-rail__dot{flex-shrink:0;width:7px;height:7px;border-radius:50%}.strct-rail--collapsed .strct-rail__dot{position:absolute;top:5px;right:7px}.strct-rail__dot--accent{background:var(--acc)}.strct-rail__dot--success{background:var(--success)}.strct-rail__dot--warning{background:var(--warning)}.strct-rail__dot--critical{background:var(--critical)}.strct-rail__toggle{display:flex;align-items:center;gap:10px;padding:9px 14px;border:0;border-top:1px solid var(--b1);background:transparent;color:var(--t3);cursor:pointer;font-size:12.5px;font-family:var(--font)}.strct-rail--collapsed .strct-rail__toggle{justify-content:center;padding:9px}.strct-rail__toggle:hover{color:var(--t1);background:var(--bg-3)}.strct-rail__toggle-icon{transition:transform .16s ease}.strct-rail:not(.strct-rail--collapsed) .strct-rail__toggle-icon{transform:rotate(180deg)}\n"], dependencies: [{ kind: "directive", type: NgTemplateOutlet, selector: "[ngTemplateOutlet]", inputs: ["ngTemplateOutletContext", "ngTemplateOutlet", "ngTemplateOutletInjector"] }, { kind: "directive", type: RouterLink, selector: "[routerLink]", inputs: ["target", "queryParams", "fragment", "queryParamsHandling", "state", "info", "relativeTo", "preserveFragment", "skipLocationChange", "replaceUrl", "routerLink"] }, { kind: "directive", type: RouterLinkActive, selector: "[routerLinkActive]", inputs: ["routerLinkActiveOptions", "ariaCurrentWhenActive", "routerLinkActive"], outputs: ["isActiveChange"], exportAs: ["routerLinkActive"] }, { kind: "component", type: StrctIcon, selector: "strct-icon", inputs: ["name", "size", "strokeWidth", "badge", "ariaLabel"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush, encapsulation: i0.ViewEncapsulation.None });
|
|
1094
1171
|
}
|
|
1095
1172
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.16", ngImport: i0, type: StrctRail, decorators: [{
|
|
1096
1173
|
type: Component,
|
|
1097
|
-
args: [{ selector: 'strct-rail', changeDetection: ChangeDetectionStrategy.OnPush, encapsulation: ViewEncapsulation.None, imports: [StrctIcon], template: `
|
|
1098
|
-
|
|
1099
|
-
|
|
1174
|
+
args: [{ selector: 'strct-rail', changeDetection: ChangeDetectionStrategy.OnPush, encapsulation: ViewEncapsulation.None, imports: [NgTemplateOutlet, RouterLink, RouterLinkActive, StrctIcon], template: `
|
|
1175
|
+
<!-- Shared row content: icon, label, trailing indicator, badge / dot. -->
|
|
1176
|
+
<ng-template #rowContent let-item>
|
|
1177
|
+
<strct-icon class="strct-rail__icon" [name]="item.icon" [size]="18" [strokeWidth]="1.6" />
|
|
1178
|
+
@if (!collapsed()) {
|
|
1179
|
+
<span class="strct-rail__label">{{ item.label }}</span>
|
|
1180
|
+
@if (item.trailingIcon) {
|
|
1181
|
+
<strct-icon
|
|
1182
|
+
class="strct-rail__trailing"
|
|
1183
|
+
[name]="item.trailingIcon"
|
|
1184
|
+
[size]="14"
|
|
1185
|
+
[strokeWidth]="1.5"
|
|
1186
|
+
/>
|
|
1187
|
+
}
|
|
1188
|
+
}
|
|
1189
|
+
@if (item.badge !== undefined && item.badge !== null && item.badge !== '') {
|
|
1190
|
+
<span
|
|
1191
|
+
class="strct-rail__badge strct-rail__badge--{{ item.badgeStatus ?? 'accent' }}"
|
|
1192
|
+
[class.strct-rail__badge--dot]="collapsed()"
|
|
1193
|
+
>
|
|
1194
|
+
@if (!collapsed()) {
|
|
1195
|
+
{{ item.badge }}
|
|
1196
|
+
}
|
|
1197
|
+
</span>
|
|
1198
|
+
} @else if (item.dot) {
|
|
1199
|
+
<span class="strct-rail__dot strct-rail__dot--{{ item.dotStatus ?? 'accent' }}"></span>
|
|
1200
|
+
}
|
|
1201
|
+
</ng-template>
|
|
1202
|
+
|
|
1203
|
+
<!-- One rail row: a router link, a plain link, or a button (today's default). -->
|
|
1204
|
+
<ng-template #row let-item>
|
|
1205
|
+
@if (isRouted(item)) {
|
|
1206
|
+
<a
|
|
1207
|
+
class="strct-rail__item"
|
|
1208
|
+
[routerLink]="item.routerLink"
|
|
1209
|
+
routerLinkActive
|
|
1210
|
+
#rla="routerLinkActive"
|
|
1211
|
+
[class.strct-rail__item--active]="isActive(item, rla.isActive)"
|
|
1212
|
+
[attr.aria-current]="isActive(item, rla.isActive) ? 'page' : null"
|
|
1213
|
+
[attr.title]="collapsed() ? item.label : null"
|
|
1214
|
+
(click)="pick(item, $event)"
|
|
1215
|
+
>
|
|
1216
|
+
<ng-container *ngTemplateOutlet="rowContent; context: { $implicit: item }" />
|
|
1217
|
+
</a>
|
|
1218
|
+
} @else if (item.href && !item.disabled) {
|
|
1219
|
+
<a
|
|
1220
|
+
class="strct-rail__item"
|
|
1221
|
+
[href]="item.href"
|
|
1222
|
+
[class.strct-rail__item--active]="item.id === activeId()"
|
|
1223
|
+
[attr.aria-current]="item.id === activeId() ? 'page' : null"
|
|
1224
|
+
[attr.title]="collapsed() ? item.label : null"
|
|
1225
|
+
(click)="pick(item, $event)"
|
|
1226
|
+
>
|
|
1227
|
+
<ng-container *ngTemplateOutlet="rowContent; context: { $implicit: item }" />
|
|
1228
|
+
</a>
|
|
1229
|
+
} @else {
|
|
1100
1230
|
<button
|
|
1101
1231
|
type="button"
|
|
1102
1232
|
class="strct-rail__item"
|
|
@@ -1104,24 +1234,26 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.16", ngImpo
|
|
|
1104
1234
|
[disabled]="item.disabled"
|
|
1105
1235
|
[attr.aria-current]="item.id === activeId() ? 'page' : null"
|
|
1106
1236
|
[attr.title]="collapsed() ? item.label : null"
|
|
1107
|
-
(click)="pick(item)"
|
|
1237
|
+
(click)="pick(item, $event)"
|
|
1108
1238
|
>
|
|
1109
|
-
<
|
|
1110
|
-
@if (!collapsed()) {
|
|
1111
|
-
<span class="strct-rail__label">{{ item.label }}</span>
|
|
1112
|
-
}
|
|
1113
|
-
@if (item.badge !== undefined && item.badge !== null && item.badge !== '') {
|
|
1114
|
-
<span
|
|
1115
|
-
class="strct-rail__badge strct-rail__badge--{{ item.badgeStatus ?? 'accent' }}"
|
|
1116
|
-
[class.strct-rail__badge--dot]="collapsed()"
|
|
1117
|
-
>
|
|
1118
|
-
@if (!collapsed()) {
|
|
1119
|
-
{{ item.badge }}
|
|
1120
|
-
}
|
|
1121
|
-
</span>
|
|
1122
|
-
}
|
|
1239
|
+
<ng-container *ngTemplateOutlet="rowContent; context: { $implicit: item }" />
|
|
1123
1240
|
</button>
|
|
1124
1241
|
}
|
|
1242
|
+
</ng-template>
|
|
1243
|
+
|
|
1244
|
+
<nav class="strct-rail__nav" [attr.aria-label]="ariaLabel()">
|
|
1245
|
+
<div class="strct-rail__group strct-rail__group--top">
|
|
1246
|
+
@for (item of topItems(); track item.id) {
|
|
1247
|
+
<ng-container *ngTemplateOutlet="row; context: { $implicit: item }" />
|
|
1248
|
+
}
|
|
1249
|
+
</div>
|
|
1250
|
+
@if (bottomItems().length) {
|
|
1251
|
+
<div class="strct-rail__group strct-rail__group--bottom">
|
|
1252
|
+
@for (item of bottomItems(); track item.id) {
|
|
1253
|
+
<ng-container *ngTemplateOutlet="row; context: { $implicit: item }" />
|
|
1254
|
+
}
|
|
1255
|
+
</div>
|
|
1256
|
+
}
|
|
1125
1257
|
</nav>
|
|
1126
1258
|
|
|
1127
1259
|
@if (collapsible()) {
|
|
@@ -1141,7 +1273,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.16", ngImpo
|
|
|
1141
1273
|
`, host: {
|
|
1142
1274
|
class: 'strct-rail',
|
|
1143
1275
|
'[class.strct-rail--collapsed]': 'collapsed()',
|
|
1144
|
-
}, styles: [".strct-rail{display:flex;flex-direction:column;width:232px;flex-shrink:0;background:var(--bg-1);border-inline-end:1px solid var(--b2);overflow:hidden;transition:width .16s ease}.strct-rail--collapsed{width:60px}.strct-rail__nav{flex:1;display:flex;flex-direction:column;gap:2px;
|
|
1276
|
+
}, styles: [".strct-rail{display:flex;flex-direction:column;width:232px;flex-shrink:0;background:var(--bg-1);border-inline-end:1px solid var(--b2);overflow:hidden;transition:width .16s ease}.strct-rail--collapsed{width:60px}.strct-rail__nav{flex:1;min-height:0;display:flex;flex-direction:column;padding:8px}.strct-rail__group{display:flex;flex-direction:column;gap:2px}.strct-rail__group--top{flex:1;min-height:0;overflow-y:auto}.strct-rail__group--bottom{margin-top:8px;padding-top:8px;border-top:1px solid var(--b1)}.strct-rail__item{position:relative;display:flex;align-items:center;gap:11px;width:100%;box-sizing:border-box;padding:8px 10px;border:0;border-radius:8px;background:transparent;color:var(--t2);cursor:pointer;font-size:13.5px;font-family:var(--font);text-align:start;text-decoration:none;white-space:nowrap;transition:background .14s ease,color .14s ease}.strct-rail--collapsed .strct-rail__item{justify-content:center;padding:8px}.strct-rail__item:hover:not(:disabled){background:var(--bg-3);color:var(--t1)}.strct-rail__item--active{background:var(--acc-m);color:var(--acc)}.strct-rail__item--active .strct-rail__icon{color:var(--acc)}.strct-rail__item:disabled{opacity:.5;cursor:not-allowed}.strct-rail__item:focus-visible{outline:2px solid var(--acc50);outline-offset:-2px}.strct-rail__icon{flex-shrink:0}.strct-rail__label{flex:1;overflow:hidden;text-overflow:ellipsis}.strct-rail__badge{flex-shrink:0;min-width:18px;height:18px;padding:0 5px;display:inline-flex;align-items:center;justify-content:center;font-size:12px;font-weight:600;line-height:1;border-radius:9px;font-variant-numeric:tabular-nums}.strct-rail__badge--dot{position:absolute;top:5px;right:7px;min-width:8px;width:8px;height:8px;padding:0;border-radius:50%}.strct-rail__badge--accent{background:var(--acc-m);color:var(--acc)}.strct-rail__badge--success{background:var(--success-bg);color:var(--success)}.strct-rail__badge--warning{background:var(--warning-bg);color:var(--warning)}.strct-rail__badge--critical{background:var(--critical-bg);color:var(--critical)}.strct-rail__badge--dot.strct-rail__badge--accent{background:var(--acc)}.strct-rail__badge--dot.strct-rail__badge--success{background:var(--success)}.strct-rail__badge--dot.strct-rail__badge--warning{background:var(--warning)}.strct-rail__badge--dot.strct-rail__badge--critical{background:var(--critical)}.strct-rail__trailing{flex-shrink:0;color:var(--t3)}.strct-rail__dot{flex-shrink:0;width:7px;height:7px;border-radius:50%}.strct-rail--collapsed .strct-rail__dot{position:absolute;top:5px;right:7px}.strct-rail__dot--accent{background:var(--acc)}.strct-rail__dot--success{background:var(--success)}.strct-rail__dot--warning{background:var(--warning)}.strct-rail__dot--critical{background:var(--critical)}.strct-rail__toggle{display:flex;align-items:center;gap:10px;padding:9px 14px;border:0;border-top:1px solid var(--b1);background:transparent;color:var(--t3);cursor:pointer;font-size:12.5px;font-family:var(--font)}.strct-rail--collapsed .strct-rail__toggle{justify-content:center;padding:9px}.strct-rail__toggle:hover{color:var(--t1);background:var(--bg-3)}.strct-rail__toggle-icon{transition:transform .16s ease}.strct-rail:not(.strct-rail--collapsed) .strct-rail__toggle-icon{transform:rotate(180deg)}\n"] }]
|
|
1145
1277
|
}], propDecorators: { items: [{ type: i0.Input, args: [{ isSignal: true, alias: "items", required: true }] }], activeId: [{ type: i0.Input, args: [{ isSignal: true, alias: "activeId", required: false }] }, { type: i0.Output, args: ["activeIdChange"] }], collapsed: [{ type: i0.Input, args: [{ isSignal: true, alias: "collapsed", required: false }] }, { type: i0.Output, args: ["collapsedChange"] }], collapsible: [{ type: i0.Input, args: [{ isSignal: true, alias: "collapsible", required: false }] }], ariaLabel: [{ type: i0.Input, args: [{ isSignal: true, alias: "ariaLabel", required: false }] }], select: [{ type: i0.Output, args: ["select"] }] } });
|
|
1146
1278
|
|
|
1147
1279
|
/**
|
|
@@ -3859,6 +3991,25 @@ class StrctSectionMenu {
|
|
|
3859
3991
|
/>
|
|
3860
3992
|
}
|
|
3861
3993
|
<span class="strct-sm__item-label">{{ item.label }}</span>
|
|
3994
|
+
@if (item.trailingIcon) {
|
|
3995
|
+
<strct-icon
|
|
3996
|
+
class="strct-sm__trailing"
|
|
3997
|
+
[name]="item.trailingIcon"
|
|
3998
|
+
[size]="14"
|
|
3999
|
+
[strokeWidth]="1.5"
|
|
4000
|
+
/>
|
|
4001
|
+
}
|
|
4002
|
+
@if (item.badge !== undefined && item.badge !== null && item.badge !== '') {
|
|
4003
|
+
<span
|
|
4004
|
+
class="strct-sm__badge strct-sm__badge--{{ item.badgeStatus ?? 'accent' }}"
|
|
4005
|
+
>
|
|
4006
|
+
{{ item.badge }}
|
|
4007
|
+
</span>
|
|
4008
|
+
} @else if (item.dot) {
|
|
4009
|
+
<span
|
|
4010
|
+
class="strct-sm__dot strct-sm__dot--{{ item.dotStatus ?? 'accent' }}"
|
|
4011
|
+
></span>
|
|
4012
|
+
}
|
|
3862
4013
|
</button>
|
|
3863
4014
|
}
|
|
3864
4015
|
</div>
|
|
@@ -3866,7 +4017,7 @@ class StrctSectionMenu {
|
|
|
3866
4017
|
</div>
|
|
3867
4018
|
}
|
|
3868
4019
|
</nav>
|
|
3869
|
-
`, isInline: true, styles: [".strct-sm{display:flex;flex-direction:column;gap:1px}.strct-sm__section--collapsible+.strct-sm__section--collapsible{margin-top:1px}.strct-sm__cat{display:flex;align-items:center;gap:8px;width:100%;padding:7px 9px;border:0;border-radius:6px;background:transparent;color:var(--t2);font-size:13px;font-weight:500;font-family:var(--font);cursor:pointer;text-align:start;transition:background .13s ease,color .13s ease}.strct-sm__cat:hover{background:var(--bg-3);color:var(--t1)}.strct-sm__cat:focus-visible,.strct-sm__item:focus-visible{outline:2px solid var(--acc50);outline-offset:-2px}.strct-sm__chevron{display:inline-flex;color:var(--t3);flex-shrink:0;transition:transform .15s ease}.strct-sm__chevron--open{transform:rotate(90deg)}.strct-sm__cat-icon{color:var(--t3);flex-shrink:0}.strct-sm__cat-label{flex:1;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}.strct-sm__cat-static{padding:11px 10px 5px;font-size:12px;font-weight:600;text-transform:uppercase;letter-spacing:.5px;color:var(--t3)}.strct-sm__items{display:flex;flex-direction:column}.strct-sm__item{display:flex;align-items:center;gap:9px;width:100%;padding:7px 10px;border:0;border-radius:6px;background:transparent;color:var(--t1);font-size:13px;font-family:var(--font);cursor:pointer;text-align:start;transition:background .13s ease}.strct-sm__section--collapsible .strct-sm__item{padding-inline-start:31px}.strct-sm__item:hover:not(:disabled){background:var(--bg-3)}.strct-sm__item--active{background:var(--acc-m);color:var(--acc);font-weight:500}.strct-sm__item--active .strct-sm__item-icon{color:var(--acc)}.strct-sm__item:disabled{opacity:.5;cursor:not-allowed}.strct-sm__item-icon{color:var(--t2);flex-shrink:0}.strct-sm__item-label{flex:1;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}\n"], dependencies: [{ kind: "component", type: StrctIcon, selector: "strct-icon", inputs: ["name", "size", "strokeWidth", "badge", "ariaLabel"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush, encapsulation: i0.ViewEncapsulation.None });
|
|
4020
|
+
`, isInline: true, styles: [".strct-sm{display:flex;flex-direction:column;gap:1px}.strct-sm__section--collapsible+.strct-sm__section--collapsible{margin-top:1px}.strct-sm__cat{display:flex;align-items:center;gap:8px;width:100%;padding:7px 9px;border:0;border-radius:6px;background:transparent;color:var(--t2);font-size:13px;font-weight:500;font-family:var(--font);cursor:pointer;text-align:start;transition:background .13s ease,color .13s ease}.strct-sm__cat:hover{background:var(--bg-3);color:var(--t1)}.strct-sm__cat:focus-visible,.strct-sm__item:focus-visible{outline:2px solid var(--acc50);outline-offset:-2px}.strct-sm__chevron{display:inline-flex;color:var(--t3);flex-shrink:0;transition:transform .15s ease}.strct-sm__chevron--open{transform:rotate(90deg)}.strct-sm__cat-icon{color:var(--t3);flex-shrink:0}.strct-sm__cat-label{flex:1;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}.strct-sm__cat-static{padding:11px 10px 5px;font-size:12px;font-weight:600;text-transform:uppercase;letter-spacing:.5px;color:var(--t3)}.strct-sm__items{display:flex;flex-direction:column}.strct-sm__item{display:flex;align-items:center;gap:9px;width:100%;padding:7px 10px;border:0;border-radius:6px;background:transparent;color:var(--t1);font-size:13px;font-family:var(--font);cursor:pointer;text-align:start;transition:background .13s ease}.strct-sm__section--collapsible .strct-sm__item{padding-inline-start:31px}.strct-sm__item:hover:not(:disabled){background:var(--bg-3)}.strct-sm__item--active{background:var(--acc-m);color:var(--acc);font-weight:500}.strct-sm__item--active .strct-sm__item-icon{color:var(--acc)}.strct-sm__item:disabled{opacity:.5;cursor:not-allowed}.strct-sm__item-icon{color:var(--t2);flex-shrink:0}.strct-sm__item-label{flex:1;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}.strct-sm__trailing{flex-shrink:0;color:var(--t3)}.strct-sm__badge{flex-shrink:0;min-width:18px;height:18px;padding:0 5px;display:inline-flex;align-items:center;justify-content:center;font-size:12px;font-weight:600;line-height:1;border-radius:9px;font-variant-numeric:tabular-nums}.strct-sm__badge--accent{background:var(--acc-m);color:var(--acc)}.strct-sm__badge--success{background:var(--success-bg);color:var(--success)}.strct-sm__badge--warning{background:var(--warning-bg);color:var(--warning)}.strct-sm__badge--critical{background:var(--critical-bg);color:var(--critical)}.strct-sm__dot{flex-shrink:0;width:7px;height:7px;border-radius:50%}.strct-sm__dot--accent{background:var(--acc)}.strct-sm__dot--success{background:var(--success)}.strct-sm__dot--warning{background:var(--warning)}.strct-sm__dot--critical{background:var(--critical)}\n"], dependencies: [{ kind: "component", type: StrctIcon, selector: "strct-icon", inputs: ["name", "size", "strokeWidth", "badge", "ariaLabel"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush, encapsulation: i0.ViewEncapsulation.None });
|
|
3870
4021
|
}
|
|
3871
4022
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.16", ngImport: i0, type: StrctSectionMenu, decorators: [{
|
|
3872
4023
|
type: Component,
|
|
@@ -3918,6 +4069,25 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.16", ngImpo
|
|
|
3918
4069
|
/>
|
|
3919
4070
|
}
|
|
3920
4071
|
<span class="strct-sm__item-label">{{ item.label }}</span>
|
|
4072
|
+
@if (item.trailingIcon) {
|
|
4073
|
+
<strct-icon
|
|
4074
|
+
class="strct-sm__trailing"
|
|
4075
|
+
[name]="item.trailingIcon"
|
|
4076
|
+
[size]="14"
|
|
4077
|
+
[strokeWidth]="1.5"
|
|
4078
|
+
/>
|
|
4079
|
+
}
|
|
4080
|
+
@if (item.badge !== undefined && item.badge !== null && item.badge !== '') {
|
|
4081
|
+
<span
|
|
4082
|
+
class="strct-sm__badge strct-sm__badge--{{ item.badgeStatus ?? 'accent' }}"
|
|
4083
|
+
>
|
|
4084
|
+
{{ item.badge }}
|
|
4085
|
+
</span>
|
|
4086
|
+
} @else if (item.dot) {
|
|
4087
|
+
<span
|
|
4088
|
+
class="strct-sm__dot strct-sm__dot--{{ item.dotStatus ?? 'accent' }}"
|
|
4089
|
+
></span>
|
|
4090
|
+
}
|
|
3921
4091
|
</button>
|
|
3922
4092
|
}
|
|
3923
4093
|
</div>
|
|
@@ -3925,7 +4095,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.16", ngImpo
|
|
|
3925
4095
|
</div>
|
|
3926
4096
|
}
|
|
3927
4097
|
</nav>
|
|
3928
|
-
`, host: { class: 'strct-sm-host' }, styles: [".strct-sm{display:flex;flex-direction:column;gap:1px}.strct-sm__section--collapsible+.strct-sm__section--collapsible{margin-top:1px}.strct-sm__cat{display:flex;align-items:center;gap:8px;width:100%;padding:7px 9px;border:0;border-radius:6px;background:transparent;color:var(--t2);font-size:13px;font-weight:500;font-family:var(--font);cursor:pointer;text-align:start;transition:background .13s ease,color .13s ease}.strct-sm__cat:hover{background:var(--bg-3);color:var(--t1)}.strct-sm__cat:focus-visible,.strct-sm__item:focus-visible{outline:2px solid var(--acc50);outline-offset:-2px}.strct-sm__chevron{display:inline-flex;color:var(--t3);flex-shrink:0;transition:transform .15s ease}.strct-sm__chevron--open{transform:rotate(90deg)}.strct-sm__cat-icon{color:var(--t3);flex-shrink:0}.strct-sm__cat-label{flex:1;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}.strct-sm__cat-static{padding:11px 10px 5px;font-size:12px;font-weight:600;text-transform:uppercase;letter-spacing:.5px;color:var(--t3)}.strct-sm__items{display:flex;flex-direction:column}.strct-sm__item{display:flex;align-items:center;gap:9px;width:100%;padding:7px 10px;border:0;border-radius:6px;background:transparent;color:var(--t1);font-size:13px;font-family:var(--font);cursor:pointer;text-align:start;transition:background .13s ease}.strct-sm__section--collapsible .strct-sm__item{padding-inline-start:31px}.strct-sm__item:hover:not(:disabled){background:var(--bg-3)}.strct-sm__item--active{background:var(--acc-m);color:var(--acc);font-weight:500}.strct-sm__item--active .strct-sm__item-icon{color:var(--acc)}.strct-sm__item:disabled{opacity:.5;cursor:not-allowed}.strct-sm__item-icon{color:var(--t2);flex-shrink:0}.strct-sm__item-label{flex:1;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}\n"] }]
|
|
4098
|
+
`, host: { class: 'strct-sm-host' }, styles: [".strct-sm{display:flex;flex-direction:column;gap:1px}.strct-sm__section--collapsible+.strct-sm__section--collapsible{margin-top:1px}.strct-sm__cat{display:flex;align-items:center;gap:8px;width:100%;padding:7px 9px;border:0;border-radius:6px;background:transparent;color:var(--t2);font-size:13px;font-weight:500;font-family:var(--font);cursor:pointer;text-align:start;transition:background .13s ease,color .13s ease}.strct-sm__cat:hover{background:var(--bg-3);color:var(--t1)}.strct-sm__cat:focus-visible,.strct-sm__item:focus-visible{outline:2px solid var(--acc50);outline-offset:-2px}.strct-sm__chevron{display:inline-flex;color:var(--t3);flex-shrink:0;transition:transform .15s ease}.strct-sm__chevron--open{transform:rotate(90deg)}.strct-sm__cat-icon{color:var(--t3);flex-shrink:0}.strct-sm__cat-label{flex:1;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}.strct-sm__cat-static{padding:11px 10px 5px;font-size:12px;font-weight:600;text-transform:uppercase;letter-spacing:.5px;color:var(--t3)}.strct-sm__items{display:flex;flex-direction:column}.strct-sm__item{display:flex;align-items:center;gap:9px;width:100%;padding:7px 10px;border:0;border-radius:6px;background:transparent;color:var(--t1);font-size:13px;font-family:var(--font);cursor:pointer;text-align:start;transition:background .13s ease}.strct-sm__section--collapsible .strct-sm__item{padding-inline-start:31px}.strct-sm__item:hover:not(:disabled){background:var(--bg-3)}.strct-sm__item--active{background:var(--acc-m);color:var(--acc);font-weight:500}.strct-sm__item--active .strct-sm__item-icon{color:var(--acc)}.strct-sm__item:disabled{opacity:.5;cursor:not-allowed}.strct-sm__item-icon{color:var(--t2);flex-shrink:0}.strct-sm__item-label{flex:1;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}.strct-sm__trailing{flex-shrink:0;color:var(--t3)}.strct-sm__badge{flex-shrink:0;min-width:18px;height:18px;padding:0 5px;display:inline-flex;align-items:center;justify-content:center;font-size:12px;font-weight:600;line-height:1;border-radius:9px;font-variant-numeric:tabular-nums}.strct-sm__badge--accent{background:var(--acc-m);color:var(--acc)}.strct-sm__badge--success{background:var(--success-bg);color:var(--success)}.strct-sm__badge--warning{background:var(--warning-bg);color:var(--warning)}.strct-sm__badge--critical{background:var(--critical-bg);color:var(--critical)}.strct-sm__dot{flex-shrink:0;width:7px;height:7px;border-radius:50%}.strct-sm__dot--accent{background:var(--acc)}.strct-sm__dot--success{background:var(--success)}.strct-sm__dot--warning{background:var(--warning)}.strct-sm__dot--critical{background:var(--critical)}\n"] }]
|
|
3929
4099
|
}], propDecorators: { sections: [{ type: i0.Input, args: [{ isSignal: true, alias: "sections", required: true }] }], activeId: [{ type: i0.Input, args: [{ isSignal: true, alias: "activeId", required: false }] }, { type: i0.Output, args: ["activeIdChange"] }], collapsible: [{ type: i0.Input, args: [{ isSignal: true, alias: "collapsible", required: false }] }], showIcons: [{ type: i0.Input, args: [{ isSignal: true, alias: "showIcons", required: false }] }], ariaLabel: [{ type: i0.Input, args: [{ isSignal: true, alias: "ariaLabel", required: false }] }], select: [{ type: i0.Output, args: ["select"] }] } });
|
|
3930
4100
|
|
|
3931
4101
|
/**
|
|
@@ -8330,6 +8500,64 @@ function smoothPath(p) {
|
|
|
8330
8500
|
function pathFor(pts, curve) {
|
|
8331
8501
|
return curve === 'linear' ? linearPath(pts) : curve === 'step' ? stepPath(pts) : smoothPath(pts);
|
|
8332
8502
|
}
|
|
8503
|
+
/** A real value — `null` and `NaN` both mark a data gap. */
|
|
8504
|
+
function isVal(v) {
|
|
8505
|
+
return v != null && !Number.isNaN(v);
|
|
8506
|
+
}
|
|
8507
|
+
/** Split a nullable point array into contiguous non-gap segments. */
|
|
8508
|
+
function segs(pts) {
|
|
8509
|
+
const out = [];
|
|
8510
|
+
let cur = [];
|
|
8511
|
+
for (const p of pts) {
|
|
8512
|
+
if (p)
|
|
8513
|
+
cur.push(p);
|
|
8514
|
+
else if (cur.length) {
|
|
8515
|
+
out.push(cur);
|
|
8516
|
+
cur = [];
|
|
8517
|
+
}
|
|
8518
|
+
}
|
|
8519
|
+
if (cur.length)
|
|
8520
|
+
out.push(cur);
|
|
8521
|
+
return out;
|
|
8522
|
+
}
|
|
8523
|
+
/** Line path that breaks at gaps (one sub-path per segment). */
|
|
8524
|
+
function pathForSegs(pts, curve) {
|
|
8525
|
+
return segs(pts)
|
|
8526
|
+
.map((s) => pathFor(s, curve))
|
|
8527
|
+
.join('');
|
|
8528
|
+
}
|
|
8529
|
+
/** Area path per segment — the fill drops to the baseline at gap edges, never across. */
|
|
8530
|
+
function areaForSegs(pts, curve, base) {
|
|
8531
|
+
return segs(pts)
|
|
8532
|
+
.map((s) => `${pathFor(s, curve)}L${round$1(s[s.length - 1].x)},${round$1(base)}L${round$1(s[0].x)},${round$1(base)}Z`)
|
|
8533
|
+
.join('');
|
|
8534
|
+
}
|
|
8535
|
+
/** Closed band between per-point upper and lower bounds (gap-aware). */
|
|
8536
|
+
function bandPath(upper, lower, curve) {
|
|
8537
|
+
let out = '';
|
|
8538
|
+
let u = [];
|
|
8539
|
+
let l = [];
|
|
8540
|
+
const flush = () => {
|
|
8541
|
+
if (u.length > 1) {
|
|
8542
|
+
const back = pathFor([...l].reverse(), curve).replace(/^M/, 'L');
|
|
8543
|
+
out += pathFor(u, curve) + back + 'Z';
|
|
8544
|
+
}
|
|
8545
|
+
u = [];
|
|
8546
|
+
l = [];
|
|
8547
|
+
};
|
|
8548
|
+
for (let i = 0; i < upper.length; i++) {
|
|
8549
|
+
const up = upper[i];
|
|
8550
|
+
const lo = lower[i];
|
|
8551
|
+
if (up && lo) {
|
|
8552
|
+
u.push(up);
|
|
8553
|
+
l.push(lo);
|
|
8554
|
+
}
|
|
8555
|
+
else
|
|
8556
|
+
flush();
|
|
8557
|
+
}
|
|
8558
|
+
flush();
|
|
8559
|
+
return out;
|
|
8560
|
+
}
|
|
8333
8561
|
/**
|
|
8334
8562
|
* Single- or multi-series chart (line / area / bar). Dependency-free SVG,
|
|
8335
8563
|
* token-coloured.
|
|
@@ -8346,7 +8574,7 @@ function pathFor(pts, curve) {
|
|
|
8346
8574
|
* <strct-chart [series]="[{data:inArr,label:'In'},{data:outArr,label:'Out'}]" legend />
|
|
8347
8575
|
*/
|
|
8348
8576
|
class StrctChart {
|
|
8349
|
-
/** Single-series data (or use `series`). */
|
|
8577
|
+
/** Single-series data (or use `series`). `null` / `NaN` marks a gap — the line breaks. */
|
|
8350
8578
|
data = input([], ...(ngDevMode ? [{ debugName: "data" }] : /* istanbul ignore next */ []));
|
|
8351
8579
|
/** Multiple series; when set it takes precedence over `data`. */
|
|
8352
8580
|
series = input(null, ...(ngDevMode ? [{ debugName: "series" }] : /* istanbul ignore next */ []));
|
|
@@ -8404,6 +8632,28 @@ class StrctChart {
|
|
|
8404
8632
|
* `[valueFormat]="v => v.toFixed(3) + ' %'"`. When null, the raw value is shown.
|
|
8405
8633
|
*/
|
|
8406
8634
|
valueFormat = input(null, ...(ngDevMode ? [{ debugName: "valueFormat" }] : /* istanbul ignore next */ []));
|
|
8635
|
+
/** Vertical event / annotation markers ("alarm raised", "deploy", …). */
|
|
8636
|
+
annotations = input([], ...(ngDevMode ? [{ debugName: "annotations" }] : /* istanbul ignore next */ []));
|
|
8637
|
+
/**
|
|
8638
|
+
* Drive the crosshair externally (e.g. mirror a sibling chart's hover for a
|
|
8639
|
+
* vCenter-style synced dashboard). A local pointer wins while over this chart.
|
|
8640
|
+
*/
|
|
8641
|
+
activeIndex = input(null, ...(ngDevMode ? [{ debugName: "activeIndex" }] : /* istanbul ignore next */ []));
|
|
8642
|
+
/** Drag-select a range; the selection is emitted through `brushChange`. */
|
|
8643
|
+
brush = input(false, { ...(ngDevMode ? { debugName: "brush" } : /* istanbul ignore next */ {}), transform: booleanAttribute });
|
|
8644
|
+
/**
|
|
8645
|
+
* Drag-select **zooms into** the selected range (implies `brush`).
|
|
8646
|
+
* Double-click, Escape or the reset chip zooms back out.
|
|
8647
|
+
*/
|
|
8648
|
+
zoom = input(false, { ...(ngDevMode ? { debugName: "zoom" } : /* istanbul ignore next */ {}), transform: booleanAttribute });
|
|
8649
|
+
/** Tooltip text for a gap (null) point. */
|
|
8650
|
+
gapText = input('no data', ...(ngDevMode ? [{ debugName: "gapText" }] : /* istanbul ignore next */ []));
|
|
8651
|
+
/** Accessible label of the reset-zoom chip (localizable). */
|
|
8652
|
+
resetLabel = input('Reset zoom', ...(ngDevMode ? [{ debugName: "resetLabel" }] : /* istanbul ignore next */ []));
|
|
8653
|
+
/** Emits the hovered point index (or null on leave) — wire cross-chart sync with it. */
|
|
8654
|
+
hoverIndex = output();
|
|
8655
|
+
/** Emits the brushed [startIndex, endIndex] (inclusive), or null when cleared. */
|
|
8656
|
+
brushChange = output();
|
|
8407
8657
|
pad = PAD;
|
|
8408
8658
|
color = computed(() => COLOR$1[this.status()], ...(ngDevMode ? [{ debugName: "color" }] : /* istanbul ignore next */ []));
|
|
8409
8659
|
showArea = computed(() => this.area() || this.type() === 'area', ...(ngDevMode ? [{ debugName: "showArea" }] : /* istanbul ignore next */ []));
|
|
@@ -8420,8 +8670,22 @@ class StrctChart {
|
|
|
8420
8670
|
firstData = true;
|
|
8421
8671
|
/** Reactive OS motion preference (tracks live changes, not just first load). */
|
|
8422
8672
|
reduceMotion = signal(typeof matchMedia !== 'undefined' && matchMedia('(prefers-reduced-motion: reduce)').matches, ...(ngDevMode ? [{ debugName: "reduceMotion" }] : /* istanbul ignore next */ []));
|
|
8423
|
-
// Hover state.
|
|
8673
|
+
// Hover state. `hoverIdx` is the local pointer/keyboard index; `dispIdx` is
|
|
8674
|
+
// what actually renders — local wins, else the externally driven activeIndex.
|
|
8424
8675
|
hoverIdx = signal(null, ...(ngDevMode ? [{ debugName: "hoverIdx" }] : /* istanbul ignore next */ []));
|
|
8676
|
+
dispIdx = computed(() => {
|
|
8677
|
+
const local = this.hoverIdx();
|
|
8678
|
+
const i = local ?? this.activeIndex();
|
|
8679
|
+
if (i == null)
|
|
8680
|
+
return null;
|
|
8681
|
+
const [s, e] = this.domain();
|
|
8682
|
+
return i >= s && i <= e ? i : null;
|
|
8683
|
+
}, ...(ngDevMode ? [{ debugName: "dispIdx" }] : /* istanbul ignore next */ []));
|
|
8684
|
+
// Zoom / brush state (indices are always in the full-data domain).
|
|
8685
|
+
viewRange = signal(null, ...(ngDevMode ? [{ debugName: "viewRange" }] : /* istanbul ignore next */ []));
|
|
8686
|
+
brushDrag = signal(null, ...(ngDevMode ? [{ debugName: "brushDrag" }] : /* istanbul ignore next */ []));
|
|
8687
|
+
brushEnabled = computed(() => this.brush() || this.zoom(), ...(ngDevMode ? [{ debugName: "brushEnabled" }] : /* istanbul ignore next */ []));
|
|
8688
|
+
zoomed = computed(() => this.viewRange() !== null, ...(ngDevMode ? [{ debugName: "zoomed" }] : /* istanbul ignore next */ []));
|
|
8425
8689
|
constructor() {
|
|
8426
8690
|
const destroyRef = inject(DestroyRef);
|
|
8427
8691
|
if (typeof matchMedia !== 'undefined') {
|
|
@@ -8481,6 +8745,16 @@ class StrctChart {
|
|
|
8481
8745
|
isEmpty = computed(() => this.allData().every((d) => d.length === 0), ...(ngDevMode ? [{ debugName: "isEmpty" }] : /* istanbul ignore next */ []));
|
|
8482
8746
|
/** Number of x slots. */
|
|
8483
8747
|
nx = computed(() => Math.max(1, ...this.allData().map((d) => d.length)), ...(ngDevMode ? [{ debugName: "nx" }] : /* istanbul ignore next */ []));
|
|
8748
|
+
/** Visible index window: the brush-zoom range, or the full data. */
|
|
8749
|
+
domain = computed(() => {
|
|
8750
|
+
const n = this.nx();
|
|
8751
|
+
const vr = this.viewRange();
|
|
8752
|
+
if (!vr)
|
|
8753
|
+
return [0, n - 1];
|
|
8754
|
+
const s = Math.max(0, Math.min(vr[0], n - 1));
|
|
8755
|
+
const e = Math.max(s, Math.min(vr[1], n - 1));
|
|
8756
|
+
return e > s ? [s, e] : [0, n - 1];
|
|
8757
|
+
}, ...(ngDevMode ? [{ debugName: "domain" }] : /* istanbul ignore next */ []));
|
|
8484
8758
|
/** Left padding: wider when the y-axis labels are shown. */
|
|
8485
8759
|
pl = computed(() => (this.yAxis() ? Y_AXIS_GUTTER : PAD.l), ...(ngDevMode ? [{ debugName: "pl" }] : /* istanbul ignore next */ []));
|
|
8486
8760
|
chartW() {
|
|
@@ -8489,16 +8763,46 @@ class StrctChart {
|
|
|
8489
8763
|
chartH() {
|
|
8490
8764
|
return this.height() - PAD.t - PAD.b;
|
|
8491
8765
|
}
|
|
8492
|
-
/** Horizontal gap between two data points, in px. */
|
|
8766
|
+
/** Horizontal gap between two data points, in px (of the visible window). */
|
|
8493
8767
|
stepX() {
|
|
8494
|
-
const
|
|
8495
|
-
return
|
|
8768
|
+
const [s, e] = this.domain();
|
|
8769
|
+
return e > s ? this.chartW() / (e - s) : 0;
|
|
8496
8770
|
}
|
|
8771
|
+
/** Real values inside the visible window (multi-aware; bands included). */
|
|
8772
|
+
visibleValues = computed(() => {
|
|
8773
|
+
const [s, e] = this.domain();
|
|
8774
|
+
const out = [];
|
|
8775
|
+
const push = (v) => {
|
|
8776
|
+
if (isVal(v))
|
|
8777
|
+
out.push(v);
|
|
8778
|
+
};
|
|
8779
|
+
const ser = this.seriesResolved();
|
|
8780
|
+
if (ser) {
|
|
8781
|
+
const N = this.nx();
|
|
8782
|
+
for (const x of ser) {
|
|
8783
|
+
const data = x.data ?? [];
|
|
8784
|
+
const offset = N - data.length;
|
|
8785
|
+
for (let gi = Math.max(s, offset); gi <= e; gi++) {
|
|
8786
|
+
const li = gi - offset;
|
|
8787
|
+
if (li < 0 || li >= data.length)
|
|
8788
|
+
continue;
|
|
8789
|
+
push(data[li]);
|
|
8790
|
+
push(x.upper?.[li]);
|
|
8791
|
+
}
|
|
8792
|
+
}
|
|
8793
|
+
}
|
|
8794
|
+
else {
|
|
8795
|
+
const d = this.data();
|
|
8796
|
+
for (let i = s; i <= Math.min(e, d.length - 1); i++)
|
|
8797
|
+
push(d[i]);
|
|
8798
|
+
}
|
|
8799
|
+
return out;
|
|
8800
|
+
}, ...(ngDevMode ? [{ debugName: "visibleValues" }] : /* istanbul ignore next */ []));
|
|
8497
8801
|
yMax = computed(() => {
|
|
8498
8802
|
const explicit = this.max();
|
|
8499
8803
|
if (explicit != null)
|
|
8500
8804
|
return explicit || 1;
|
|
8501
|
-
const m = Math.max(0, ...this.
|
|
8805
|
+
const m = Math.max(0, ...this.visibleValues());
|
|
8502
8806
|
return m === 0 ? 1 : m * 1.1;
|
|
8503
8807
|
}, ...(ngDevMode ? [{ debugName: "yMax" }] : /* istanbul ignore next */ []));
|
|
8504
8808
|
yMin = computed(() => this.min() ?? 0, ...(ngDevMode ? [{ debugName: "yMin" }] : /* istanbul ignore next */ []));
|
|
@@ -8509,50 +8813,46 @@ class StrctChart {
|
|
|
8509
8813
|
const c = Math.max(lo, Math.min(hi, v));
|
|
8510
8814
|
return PAD.t + (1 - (c - lo) / range) * this.chartH();
|
|
8511
8815
|
}
|
|
8512
|
-
// ── Single-series geometry (
|
|
8816
|
+
// ── Single-series geometry (gap-aware; null keeps its x-slot) ──
|
|
8513
8817
|
points = computed(() => {
|
|
8514
8818
|
const d = this.data();
|
|
8515
|
-
|
|
8516
|
-
const pl = this.pl();
|
|
8517
|
-
return d.map((v, i) => ({ x: pl + i * step, y: this.yOf(v) }));
|
|
8819
|
+
return d.map((v, i) => (isVal(v) ? { x: this.xOf(i), y: this.yOf(v) } : null));
|
|
8518
8820
|
}, ...(ngDevMode ? [{ debugName: "points" }] : /* istanbul ignore next */ []));
|
|
8821
|
+
/** Non-gap points only (dot rendering). */
|
|
8822
|
+
dotPts = computed(() => this.points().filter((p) => p !== null), ...(ngDevMode ? [{ debugName: "dotPts" }] : /* istanbul ignore next */ []));
|
|
8519
8823
|
head = computed(() => {
|
|
8520
8824
|
const p = this.points();
|
|
8521
|
-
|
|
8825
|
+
for (let i = p.length - 1; i >= 0; i--)
|
|
8826
|
+
if (p[i])
|
|
8827
|
+
return p[i];
|
|
8828
|
+
return null;
|
|
8522
8829
|
}, ...(ngDevMode ? [{ debugName: "head" }] : /* istanbul ignore next */ []));
|
|
8523
8830
|
plotPoints = computed(() => {
|
|
8524
8831
|
const p = this.points();
|
|
8525
|
-
if (!this.live() || p.length < 2)
|
|
8832
|
+
if (!this.live() || p.length < 2 || !p[0])
|
|
8526
8833
|
return p;
|
|
8527
8834
|
return [{ x: p[0].x - this.stepX(), y: p[0].y }, ...p];
|
|
8528
8835
|
}, ...(ngDevMode ? [{ debugName: "plotPoints" }] : /* istanbul ignore next */ []));
|
|
8529
|
-
linePath = computed(() =>
|
|
8530
|
-
areaPath = computed(() => {
|
|
8531
|
-
const line = this.linePath();
|
|
8532
|
-
const p = this.plotPoints();
|
|
8533
|
-
if (!line || !p.length)
|
|
8534
|
-
return '';
|
|
8535
|
-
const base = this.height() - PAD.b;
|
|
8536
|
-
return `${line}L${round$1(p[p.length - 1].x)},${round$1(base)}L${round$1(p[0].x)},${round$1(base)}Z`;
|
|
8537
|
-
}, ...(ngDevMode ? [{ debugName: "areaPath" }] : /* istanbul ignore next */ []));
|
|
8836
|
+
linePath = computed(() => pathForSegs(this.plotPoints(), this.curve()), ...(ngDevMode ? [{ debugName: "linePath" }] : /* istanbul ignore next */ []));
|
|
8837
|
+
areaPath = computed(() => areaForSegs(this.plotPoints(), this.curve(), this.height() - PAD.b), ...(ngDevMode ? [{ debugName: "areaPath" }] : /* istanbul ignore next */ []));
|
|
8538
8838
|
// ── Multi-series geometry ─────────────────────────────────────
|
|
8539
8839
|
multiSeries = computed(() => {
|
|
8540
8840
|
const s = this.seriesResolved();
|
|
8541
8841
|
if (!s)
|
|
8542
8842
|
return [];
|
|
8543
8843
|
const N = this.nx();
|
|
8544
|
-
const step = this.stepX();
|
|
8545
|
-
const pl = this.pl();
|
|
8546
8844
|
const base = this.height() - PAD.b;
|
|
8547
8845
|
return s.map((x) => {
|
|
8548
8846
|
const data = x.data ?? [];
|
|
8549
8847
|
const offset = N - data.length; // right-align shorter series
|
|
8550
|
-
const
|
|
8848
|
+
const ptOf = (v, i) => isVal(v) ? { x: this.xOf(offset + i), y: this.yOf(v) } : null;
|
|
8849
|
+
const pts = data.map((v, i) => ptOf(v, i));
|
|
8551
8850
|
const curve = x.curve ?? this.curve();
|
|
8552
|
-
const path =
|
|
8851
|
+
const path = pathForSegs(pts, curve);
|
|
8553
8852
|
const area = x.area ?? false;
|
|
8554
|
-
const areaPath = area
|
|
8555
|
-
|
|
8853
|
+
const areaPath = area ? areaForSegs(pts, curve, base) : '';
|
|
8854
|
+
const band = x.lower && x.upper
|
|
8855
|
+
? bandPath(x.upper.map((v, i) => ptOf(v, i)), x.lower.map((v, i) => ptOf(v, i)), curve)
|
|
8556
8856
|
: '';
|
|
8557
8857
|
return {
|
|
8558
8858
|
color: COLOR$1[x.status ?? this.status()],
|
|
@@ -8562,26 +8862,42 @@ class StrctChart {
|
|
|
8562
8862
|
pts,
|
|
8563
8863
|
path,
|
|
8564
8864
|
areaPath,
|
|
8865
|
+
bandPath: band,
|
|
8565
8866
|
offset,
|
|
8566
8867
|
data,
|
|
8868
|
+
lower: x.lower,
|
|
8869
|
+
upper: x.upper,
|
|
8567
8870
|
};
|
|
8568
8871
|
});
|
|
8569
8872
|
}, ...(ngDevMode ? [{ debugName: "multiSeries" }] : /* istanbul ignore next */ []));
|
|
8570
8873
|
legendItems = computed(() => this.multiSeries()
|
|
8571
8874
|
.filter((s) => s.label)
|
|
8572
8875
|
.map((s) => ({ label: s.label, color: s.color, dash: s.dash })), ...(ngDevMode ? [{ debugName: "legendItems" }] : /* istanbul ignore next */ []));
|
|
8573
|
-
// ── Bars (single-series only)
|
|
8876
|
+
// ── Bars (single-series only; gaps render no bar, keep their slot) ──
|
|
8574
8877
|
bars = computed(() => {
|
|
8575
8878
|
const d = this.data();
|
|
8879
|
+
const [s, e] = this.domain();
|
|
8576
8880
|
const chartW = this.chartW();
|
|
8577
8881
|
const base = this.height() - PAD.b;
|
|
8578
|
-
const
|
|
8882
|
+
const last = Math.min(e, d.length - 1);
|
|
8883
|
+
const count = Math.max(1, last - s + 1);
|
|
8884
|
+
const slot = chartW / count;
|
|
8579
8885
|
const w = slot * 0.6;
|
|
8580
8886
|
const pl = this.pl();
|
|
8581
|
-
|
|
8887
|
+
const out = [];
|
|
8888
|
+
for (let i = s; i <= last; i++) {
|
|
8889
|
+
const v = d[i];
|
|
8890
|
+
if (!isVal(v))
|
|
8891
|
+
continue;
|
|
8582
8892
|
const h = ((Math.max(0, v) - this.yMin()) / (this.yMax() - this.yMin() || 1)) * this.chartH();
|
|
8583
|
-
|
|
8584
|
-
|
|
8893
|
+
out.push({
|
|
8894
|
+
x: pl + (i - s) * slot + (slot - w) / 2,
|
|
8895
|
+
y: base - Math.max(0, h),
|
|
8896
|
+
w,
|
|
8897
|
+
h: Math.max(0, h),
|
|
8898
|
+
});
|
|
8899
|
+
}
|
|
8900
|
+
return out;
|
|
8585
8901
|
}, ...(ngDevMode ? [{ debugName: "bars" }] : /* istanbul ignore next */ []));
|
|
8586
8902
|
// ── Axes ───────────────────────────────────────────────────────
|
|
8587
8903
|
gridY = computed(() => {
|
|
@@ -8616,34 +8932,49 @@ class StrctChart {
|
|
|
8616
8932
|
const ls = this.labels();
|
|
8617
8933
|
const fmt = this.xFormat();
|
|
8618
8934
|
const xt = this.xTicks();
|
|
8619
|
-
|
|
8620
|
-
|
|
8621
|
-
|
|
8622
|
-
|
|
8623
|
-
|
|
8935
|
+
const [s, e] = this.domain();
|
|
8936
|
+
const last = Math.min(e, ls.length - 1);
|
|
8937
|
+
let idxs;
|
|
8938
|
+
if (xt && xt > 1 && last - s + 1 > xt) {
|
|
8939
|
+
const stepI = (last - s) / (xt - 1);
|
|
8940
|
+
idxs = Array.from(new Set(Array.from({ length: xt }, (_, k) => s + Math.round(k * stepI))));
|
|
8624
8941
|
}
|
|
8625
8942
|
else {
|
|
8626
|
-
|
|
8627
|
-
}
|
|
8628
|
-
return
|
|
8943
|
+
idxs = Array.from({ length: Math.max(0, last - s + 1) }, (_, k) => s + k);
|
|
8944
|
+
}
|
|
8945
|
+
return idxs
|
|
8946
|
+
.filter((i) => i >= 0 && i < ls.length)
|
|
8947
|
+
.map((i) => ({
|
|
8948
|
+
text: fmt ? fmt(ls[i], i) : ls[i],
|
|
8949
|
+
i,
|
|
8950
|
+
}));
|
|
8629
8951
|
}, ...(ngDevMode ? [{ debugName: "displayLabels" }] : /* istanbul ignore next */ []));
|
|
8630
|
-
// ── Hover
|
|
8952
|
+
// ── Hover (driven by dispIdx: local pointer, else external activeIndex) ──
|
|
8631
8953
|
hoverX = computed(() => {
|
|
8632
|
-
const i = this.
|
|
8954
|
+
const i = this.dispIdx();
|
|
8633
8955
|
if (i == null)
|
|
8634
8956
|
return null;
|
|
8635
|
-
return this.
|
|
8957
|
+
return this.xOf(i);
|
|
8636
8958
|
}, ...(ngDevMode ? [{ debugName: "hoverX" }] : /* istanbul ignore next */ []));
|
|
8637
8959
|
hoverPt = computed(() => {
|
|
8638
|
-
const i = this.
|
|
8960
|
+
const i = this.dispIdx();
|
|
8639
8961
|
const p = this.points();
|
|
8640
8962
|
return i != null && i >= 0 && i < p.length ? p[i] : null;
|
|
8641
8963
|
}, ...(ngDevMode ? [{ debugName: "hoverPt" }] : /* istanbul ignore next */ []));
|
|
8642
8964
|
hoverValue = computed(() => {
|
|
8643
|
-
const i = this.
|
|
8965
|
+
const i = this.dispIdx();
|
|
8644
8966
|
const d = this.data();
|
|
8645
|
-
|
|
8967
|
+
const v = i != null && i >= 0 && i < d.length ? d[i] : null;
|
|
8968
|
+
return isVal(v) ? v : '';
|
|
8646
8969
|
}, ...(ngDevMode ? [{ debugName: "hoverValue" }] : /* istanbul ignore next */ []));
|
|
8970
|
+
/** The hovered slot exists but holds a gap (single-series). */
|
|
8971
|
+
hoverGap = computed(() => {
|
|
8972
|
+
const i = this.dispIdx();
|
|
8973
|
+
if (i == null || this.isMulti())
|
|
8974
|
+
return false;
|
|
8975
|
+
const d = this.data();
|
|
8976
|
+
return i >= 0 && i < d.length && !isVal(d[i]);
|
|
8977
|
+
}, ...(ngDevMode ? [{ debugName: "hoverGap" }] : /* istanbul ignore next */ []));
|
|
8647
8978
|
/** hoverValue run through valueFormat (unit / precision), else the raw value. */
|
|
8648
8979
|
hoverValueText = computed(() => {
|
|
8649
8980
|
const v = this.hoverValue();
|
|
@@ -8658,20 +8989,24 @@ class StrctChart {
|
|
|
8658
8989
|
return f ? f(this.absDelta()) : String(this.absDelta());
|
|
8659
8990
|
}, ...(ngDevMode ? [{ debugName: "absDeltaText" }] : /* istanbul ignore next */ []));
|
|
8660
8991
|
hoverLabel = computed(() => {
|
|
8661
|
-
const i = this.
|
|
8992
|
+
const i = this.dispIdx();
|
|
8662
8993
|
const l = this.labels();
|
|
8663
8994
|
return i != null && i >= 0 && i < l.length ? l[i] : '';
|
|
8664
8995
|
}, ...(ngDevMode ? [{ debugName: "hoverLabel" }] : /* istanbul ignore next */ []));
|
|
8665
|
-
/** Change from the previous point (single-series; null at the first point). */
|
|
8996
|
+
/** Change from the previous point (single-series; null at the first point or across a gap). */
|
|
8666
8997
|
hoverDelta = computed(() => {
|
|
8667
|
-
const i = this.
|
|
8998
|
+
const i = this.dispIdx();
|
|
8668
8999
|
const d = this.data();
|
|
8669
|
-
|
|
9000
|
+
if (i == null || i <= 0 || i >= d.length)
|
|
9001
|
+
return null;
|
|
9002
|
+
const cur = d[i];
|
|
9003
|
+
const prev = d[i - 1];
|
|
9004
|
+
return isVal(cur) && isVal(prev) ? cur - prev : null;
|
|
8670
9005
|
}, ...(ngDevMode ? [{ debugName: "hoverDelta" }] : /* istanbul ignore next */ []));
|
|
8671
9006
|
absDelta = computed(() => Math.abs(this.hoverDelta() ?? 0), ...(ngDevMode ? [{ debugName: "absDelta" }] : /* istanbul ignore next */ []));
|
|
8672
9007
|
/** Second tooltip line: "Xs ago" while live, else the x label. */
|
|
8673
9008
|
hoverMeta = computed(() => {
|
|
8674
|
-
const i = this.
|
|
9009
|
+
const i = this.dispIdx();
|
|
8675
9010
|
if (i == null)
|
|
8676
9011
|
return '';
|
|
8677
9012
|
if (this.live()) {
|
|
@@ -8684,59 +9019,102 @@ class StrctChart {
|
|
|
8684
9019
|
const l = this.labels();
|
|
8685
9020
|
return i >= 0 && i < l.length ? l[i] : '';
|
|
8686
9021
|
}, ...(ngDevMode ? [{ debugName: "hoverMeta" }] : /* istanbul ignore next */ []));
|
|
8687
|
-
/** Per-series value at the hovered index (multi-series tooltip). */
|
|
9022
|
+
/** Per-series value at the hovered index (multi-series tooltip; bands as `avg (min–max)`). */
|
|
8688
9023
|
hoverRows = computed(() => {
|
|
8689
|
-
const i = this.
|
|
9024
|
+
const i = this.dispIdx();
|
|
8690
9025
|
const s = this.multiSeries();
|
|
8691
9026
|
if (i == null || !s.length)
|
|
8692
9027
|
return [];
|
|
8693
9028
|
const f = this.valueFormat();
|
|
9029
|
+
const fmt = (v) => (f ? f(v) : String(v));
|
|
8694
9030
|
return s
|
|
8695
9031
|
.map((x) => {
|
|
8696
9032
|
const li = i - x.offset;
|
|
8697
|
-
const
|
|
9033
|
+
const raw = li >= 0 && li < x.data.length ? x.data[li] : null;
|
|
9034
|
+
const v = isVal(raw) ? raw : null;
|
|
9035
|
+
const lo = x.lower?.[li];
|
|
9036
|
+
const hi = x.upper?.[li];
|
|
9037
|
+
const band = isVal(lo) && isVal(hi) ? ` (${fmt(lo)}–${fmt(hi)})` : '';
|
|
8698
9038
|
return {
|
|
8699
9039
|
label: x.label,
|
|
8700
9040
|
color: x.color,
|
|
8701
9041
|
value: v,
|
|
8702
|
-
text: v == null ? '' :
|
|
9042
|
+
text: v == null ? '' : fmt(v) + band,
|
|
8703
9043
|
};
|
|
8704
9044
|
})
|
|
8705
9045
|
.filter((r) => r.value !== null);
|
|
8706
9046
|
}, ...(ngDevMode ? [{ debugName: "hoverRows" }] : /* istanbul ignore next */ []));
|
|
8707
9047
|
/** Per-series hover dots (multi-series). */
|
|
8708
9048
|
hoverDots = computed(() => {
|
|
8709
|
-
const i = this.
|
|
9049
|
+
const i = this.dispIdx();
|
|
8710
9050
|
const s = this.multiSeries();
|
|
8711
9051
|
if (i == null || !s.length)
|
|
8712
9052
|
return [];
|
|
8713
9053
|
return s
|
|
8714
9054
|
.map((x) => {
|
|
8715
9055
|
const li = i - x.offset;
|
|
8716
|
-
|
|
8717
|
-
|
|
8718
|
-
: null;
|
|
9056
|
+
const p = li >= 0 && li < x.pts.length ? x.pts[li] : null;
|
|
9057
|
+
return p ? { x: p.x, y: p.y, color: x.color } : null;
|
|
8719
9058
|
})
|
|
8720
9059
|
.filter((d) => d !== null);
|
|
8721
9060
|
}, ...(ngDevMode ? [{ debugName: "hoverDots" }] : /* istanbul ignore next */ []));
|
|
9061
|
+
// ── Annotations ────────────────────────────────────────────────
|
|
9062
|
+
annotationLines = computed(() => {
|
|
9063
|
+
const [s, e] = this.domain();
|
|
9064
|
+
return this.annotations()
|
|
9065
|
+
.filter((a) => a.index >= s && a.index <= e)
|
|
9066
|
+
.map((a) => ({
|
|
9067
|
+
x: this.xOf(a.index),
|
|
9068
|
+
color: COLOR$1[a.status ?? 'accent'],
|
|
9069
|
+
dashed: a.dashed ?? true,
|
|
9070
|
+
label: a.label ?? '',
|
|
9071
|
+
index: a.index,
|
|
9072
|
+
}));
|
|
9073
|
+
}, ...(ngDevMode ? [{ debugName: "annotationLines" }] : /* istanbul ignore next */ []));
|
|
9074
|
+
/** The annotation sitting exactly under the crosshair, if any. */
|
|
9075
|
+
annAt = computed(() => {
|
|
9076
|
+
const i = this.dispIdx();
|
|
9077
|
+
if (i == null)
|
|
9078
|
+
return null;
|
|
9079
|
+
return this.annotationLines().find((a) => a.index === i && a.label) ?? null;
|
|
9080
|
+
}, ...(ngDevMode ? [{ debugName: "annAt" }] : /* istanbul ignore next */ []));
|
|
9081
|
+
// ── Brush / zoom ───────────────────────────────────────────────
|
|
9082
|
+
brushRect = computed(() => {
|
|
9083
|
+
const d = this.brushDrag();
|
|
9084
|
+
if (!d)
|
|
9085
|
+
return null;
|
|
9086
|
+
const x1 = this.xOf(Math.min(d.a, d.b));
|
|
9087
|
+
const x2 = this.xOf(Math.max(d.a, d.b));
|
|
9088
|
+
return { x: round$1(x1), w: round$1(Math.max(1, x2 - x1)) };
|
|
9089
|
+
}, ...(ngDevMode ? [{ debugName: "brushRect" }] : /* istanbul ignore next */ []));
|
|
9090
|
+
/** Zoom back out to the full data window (also emits `brushChange` null). */
|
|
9091
|
+
resetZoom() {
|
|
9092
|
+
this.brushDrag.set(null);
|
|
9093
|
+
if (this.viewRange() !== null) {
|
|
9094
|
+
this.viewRange.set(null);
|
|
9095
|
+
this.brushChange.emit(null);
|
|
9096
|
+
}
|
|
9097
|
+
}
|
|
8722
9098
|
/** Screen-reader summary of the whole chart (role="img" name). */
|
|
8723
9099
|
chartAria = computed(() => {
|
|
8724
9100
|
const f = this.valueFormat() ?? ((v) => String(Math.round(v * 100) / 100));
|
|
8725
9101
|
if (this.isMulti()) {
|
|
8726
9102
|
const parts = this.multiSeries().map((s) => {
|
|
8727
|
-
const
|
|
9103
|
+
const reals = s.data.filter(isVal);
|
|
9104
|
+
const last = reals.length ? f(reals[reals.length - 1]) : '';
|
|
8728
9105
|
return `${s.label || 'series'} latest ${last}`;
|
|
8729
9106
|
});
|
|
8730
9107
|
return `Chart, ${this.multiSeries().length} series: ${parts.join('; ')}`;
|
|
8731
9108
|
}
|
|
8732
9109
|
const d = this.data();
|
|
8733
|
-
|
|
9110
|
+
const reals = d.filter(isVal);
|
|
9111
|
+
if (!reals.length)
|
|
8734
9112
|
return this.emptyText();
|
|
8735
|
-
return `Chart, ${d.length} points. Min ${f(Math.min(...
|
|
9113
|
+
return `Chart, ${d.length} points. Min ${f(Math.min(...reals))}, max ${f(Math.max(...reals))}, latest ${f(reals[reals.length - 1])}`;
|
|
8736
9114
|
}, ...(ngDevMode ? [{ debugName: "chartAria" }] : /* istanbul ignore next */ []));
|
|
8737
9115
|
/** aria-live text announcing the hovered / keyboard-selected point. */
|
|
8738
9116
|
srText = computed(() => {
|
|
8739
|
-
const i = this.
|
|
9117
|
+
const i = this.dispIdx();
|
|
8740
9118
|
if (i == null)
|
|
8741
9119
|
return '';
|
|
8742
9120
|
if (this.isMulti()) {
|
|
@@ -8746,61 +9124,221 @@ class StrctChart {
|
|
|
8746
9124
|
return `${this.hoverMeta() || 'point ' + (i + 1)}: ${rows}`;
|
|
8747
9125
|
}
|
|
8748
9126
|
const meta = this.hoverMeta();
|
|
8749
|
-
|
|
9127
|
+
const value = this.hoverGap() ? this.gapText() : this.hoverValueText();
|
|
9128
|
+
return `${meta ? meta + ': ' : ''}${value}`;
|
|
8750
9129
|
}, ...(ngDevMode ? [{ debugName: "srText" }] : /* istanbul ignore next */ []));
|
|
8751
|
-
/** Pixel x of a data index (shared by the plot and
|
|
9130
|
+
/** Pixel x of a data index (shared by the plot, labels and annotations). */
|
|
8752
9131
|
xOf(i) {
|
|
8753
|
-
|
|
9132
|
+
const [s] = this.domain();
|
|
9133
|
+
return this.pl() + (i - s) * this.stepX();
|
|
9134
|
+
}
|
|
9135
|
+
/** Set the local hover index, emitting `hoverIndex` on change. */
|
|
9136
|
+
setHover(i) {
|
|
9137
|
+
if (i === this.hoverIdx())
|
|
9138
|
+
return;
|
|
9139
|
+
this.hoverIdx.set(i);
|
|
9140
|
+
this.hoverIndex.emit(i);
|
|
8754
9141
|
}
|
|
8755
|
-
|
|
9142
|
+
onLeave() {
|
|
9143
|
+
this.setHover(null);
|
|
9144
|
+
}
|
|
9145
|
+
/** Keyboard access: arrows walk the points; Escape unwinds brush → zoom → crosshair. */
|
|
8756
9146
|
onKey(event) {
|
|
8757
|
-
if (
|
|
9147
|
+
if (event.key === 'Escape') {
|
|
9148
|
+
if (this.brushDrag()) {
|
|
9149
|
+
this.brushDrag.set(null);
|
|
9150
|
+
}
|
|
9151
|
+
else if (this.zoomed()) {
|
|
9152
|
+
this.resetZoom();
|
|
9153
|
+
}
|
|
9154
|
+
else {
|
|
9155
|
+
this.setHover(null);
|
|
9156
|
+
}
|
|
8758
9157
|
return;
|
|
8759
|
-
|
|
8760
|
-
if (!
|
|
9158
|
+
}
|
|
9159
|
+
if (!this.interactive() || this.type() === 'bar')
|
|
8761
9160
|
return;
|
|
9161
|
+
const [s, e] = this.domain();
|
|
8762
9162
|
const cur = this.hoverIdx();
|
|
8763
9163
|
let next = null;
|
|
8764
9164
|
switch (event.key) {
|
|
8765
9165
|
case 'ArrowRight':
|
|
8766
|
-
next = cur == null ?
|
|
9166
|
+
next = cur == null ? s : Math.min(e, cur + 1);
|
|
8767
9167
|
break;
|
|
8768
9168
|
case 'ArrowLeft':
|
|
8769
|
-
next = cur == null ?
|
|
9169
|
+
next = cur == null ? e : Math.max(s, cur - 1);
|
|
8770
9170
|
break;
|
|
8771
9171
|
case 'Home':
|
|
8772
|
-
next =
|
|
9172
|
+
next = s;
|
|
8773
9173
|
break;
|
|
8774
9174
|
case 'End':
|
|
8775
|
-
next =
|
|
9175
|
+
next = e;
|
|
8776
9176
|
break;
|
|
8777
|
-
case 'Escape':
|
|
8778
|
-
this.hoverIdx.set(null);
|
|
8779
|
-
return;
|
|
8780
9177
|
default:
|
|
8781
9178
|
return;
|
|
8782
9179
|
}
|
|
8783
9180
|
event.preventDefault();
|
|
8784
|
-
this.
|
|
9181
|
+
this.setHover(next);
|
|
8785
9182
|
}
|
|
8786
|
-
|
|
8787
|
-
|
|
8788
|
-
return;
|
|
9183
|
+
/** Data index under the pointer, clamped to the visible window. */
|
|
9184
|
+
idxAt(event) {
|
|
8789
9185
|
const el = this.svgRef()?.nativeElement;
|
|
8790
|
-
const n = this.nx();
|
|
8791
9186
|
if (!el || this.isEmpty())
|
|
8792
|
-
return;
|
|
9187
|
+
return null;
|
|
8793
9188
|
const rect = el.getBoundingClientRect();
|
|
8794
9189
|
if (!rect.width)
|
|
8795
|
-
return;
|
|
9190
|
+
return null;
|
|
8796
9191
|
const plFrac = this.pl() / this.width();
|
|
8797
9192
|
const rFrac = PAD.r / this.width();
|
|
8798
9193
|
const fx = ((event.clientX - rect.left) / rect.width - plFrac) / (1 - plFrac - rFrac);
|
|
8799
|
-
const
|
|
8800
|
-
|
|
9194
|
+
const [s, e] = this.domain();
|
|
9195
|
+
return Math.max(s, Math.min(e, s + Math.round(fx * (e - s))));
|
|
9196
|
+
}
|
|
9197
|
+
onDown(event) {
|
|
9198
|
+
if (!this.brushEnabled() || this.isEmpty())
|
|
9199
|
+
return;
|
|
9200
|
+
const i = this.idxAt(event);
|
|
9201
|
+
if (i == null)
|
|
9202
|
+
return;
|
|
9203
|
+
event.currentTarget?.setPointerCapture?.(event.pointerId);
|
|
9204
|
+
this.brushDrag.set({ a: i, b: i });
|
|
9205
|
+
this.setHover(null);
|
|
9206
|
+
event.preventDefault();
|
|
9207
|
+
}
|
|
9208
|
+
onMove(event) {
|
|
9209
|
+
const drag = this.brushDrag();
|
|
9210
|
+
if (drag) {
|
|
9211
|
+
const i = this.idxAt(event);
|
|
9212
|
+
if (i != null && i !== drag.b)
|
|
9213
|
+
this.brushDrag.set({ a: drag.a, b: i });
|
|
9214
|
+
return;
|
|
9215
|
+
}
|
|
9216
|
+
if (!this.interactive() || (this.type() === 'bar' && !this.isMulti()))
|
|
9217
|
+
return;
|
|
9218
|
+
const i = this.idxAt(event);
|
|
9219
|
+
if (i != null)
|
|
9220
|
+
this.setHover(i);
|
|
9221
|
+
}
|
|
9222
|
+
onUp() {
|
|
9223
|
+
const d = this.brushDrag();
|
|
9224
|
+
if (!d)
|
|
9225
|
+
return;
|
|
9226
|
+
this.brushDrag.set(null);
|
|
9227
|
+
const lo = Math.min(d.a, d.b);
|
|
9228
|
+
const hi = Math.max(d.a, d.b);
|
|
9229
|
+
if (hi - lo < 1)
|
|
9230
|
+
return; // a click, not a selection
|
|
9231
|
+
if (this.zoom())
|
|
9232
|
+
this.viewRange.set([lo, hi]);
|
|
9233
|
+
this.brushChange.emit([lo, hi]);
|
|
9234
|
+
}
|
|
9235
|
+
onDblClick() {
|
|
9236
|
+
if (this.brushEnabled())
|
|
9237
|
+
this.resetZoom();
|
|
9238
|
+
}
|
|
9239
|
+
// ── Export (FR-CHART-13) ───────────────────────────────────────
|
|
9240
|
+
/**
|
|
9241
|
+
* The rendered chart as a standalone SVG string — theme colors resolved to
|
|
9242
|
+
* literals, background baked in, y-tick / x-label text included.
|
|
9243
|
+
*/
|
|
9244
|
+
toSVG() {
|
|
9245
|
+
const svg = this.svgRef()?.nativeElement;
|
|
9246
|
+
if (!svg || typeof getComputedStyle === 'undefined')
|
|
9247
|
+
return '';
|
|
9248
|
+
const doc = svg.ownerDocument;
|
|
9249
|
+
const NS = 'http://www.w3.org/2000/svg';
|
|
9250
|
+
const clone = svg.cloneNode(true);
|
|
9251
|
+
clone.setAttribute('xmlns', NS);
|
|
9252
|
+
clone.removeAttribute('class');
|
|
9253
|
+
clone.removeAttribute('style');
|
|
9254
|
+
clone.removeAttribute('tabindex');
|
|
9255
|
+
const PROPS = [
|
|
9256
|
+
'stroke',
|
|
9257
|
+
'fill',
|
|
9258
|
+
'stroke-width',
|
|
9259
|
+
'stroke-dasharray',
|
|
9260
|
+
'stroke-linecap',
|
|
9261
|
+
'stroke-linejoin',
|
|
9262
|
+
'opacity',
|
|
9263
|
+
'fill-opacity',
|
|
9264
|
+
'stroke-opacity',
|
|
9265
|
+
];
|
|
9266
|
+
const src = Array.from(svg.querySelectorAll('*'));
|
|
9267
|
+
const dst = Array.from(clone.querySelectorAll('*'));
|
|
9268
|
+
src.forEach((el, i) => {
|
|
9269
|
+
const cs = getComputedStyle(el);
|
|
9270
|
+
for (const p of PROPS) {
|
|
9271
|
+
const v = cs.getPropertyValue(p);
|
|
9272
|
+
if (v)
|
|
9273
|
+
dst[i].setAttribute(p, v);
|
|
9274
|
+
}
|
|
9275
|
+
dst[i].removeAttribute('class');
|
|
9276
|
+
});
|
|
9277
|
+
const rootCs = getComputedStyle(svg);
|
|
9278
|
+
const bg = rootCs.getPropertyValue('--bg-1').trim();
|
|
9279
|
+
const fg = rootCs.getPropertyValue('--t3').trim() || '#888';
|
|
9280
|
+
const hasLabels = this.displayLabels().length > 0;
|
|
9281
|
+
const w = this.width();
|
|
9282
|
+
const h = this.height() + (hasLabels ? 18 : 0);
|
|
9283
|
+
clone.setAttribute('viewBox', `0 0 ${w} ${h}`);
|
|
9284
|
+
clone.setAttribute('width', String(w));
|
|
9285
|
+
clone.setAttribute('height', String(h));
|
|
9286
|
+
if (bg) {
|
|
9287
|
+
const rect = doc.createElementNS(NS, 'rect');
|
|
9288
|
+
rect.setAttribute('width', String(w));
|
|
9289
|
+
rect.setAttribute('height', String(h));
|
|
9290
|
+
rect.setAttribute('fill', bg);
|
|
9291
|
+
clone.insertBefore(rect, clone.firstChild);
|
|
9292
|
+
}
|
|
9293
|
+
const text = (x, y, content, anchor) => {
|
|
9294
|
+
const t = doc.createElementNS(NS, 'text');
|
|
9295
|
+
t.setAttribute('x', String(round$1(x)));
|
|
9296
|
+
t.setAttribute('y', String(round$1(y)));
|
|
9297
|
+
t.setAttribute('fill', fg);
|
|
9298
|
+
t.setAttribute('font-size', '10');
|
|
9299
|
+
t.setAttribute('font-family', 'monospace');
|
|
9300
|
+
t.setAttribute('text-anchor', anchor);
|
|
9301
|
+
t.textContent = content;
|
|
9302
|
+
clone.appendChild(t);
|
|
9303
|
+
};
|
|
9304
|
+
for (const tick of this.yAxisTicks())
|
|
9305
|
+
text(this.pl() - 6, tick.y + 3.5, tick.text, 'end');
|
|
9306
|
+
if (hasLabels) {
|
|
9307
|
+
for (const l of this.displayLabels())
|
|
9308
|
+
text(this.xOf(l.i), this.height() + 12, l.text, 'middle');
|
|
9309
|
+
}
|
|
9310
|
+
return new XMLSerializer().serializeToString(clone);
|
|
9311
|
+
}
|
|
9312
|
+
/** The chart as a PNG data URL at the given scale (default 2×). */
|
|
9313
|
+
toPNG(scale = 2) {
|
|
9314
|
+
const s = this.toSVG();
|
|
9315
|
+
const w = this.width();
|
|
9316
|
+
const h = this.height() + (this.displayLabels().length ? 18 : 0);
|
|
9317
|
+
return new Promise((resolve, reject) => {
|
|
9318
|
+
if (!s) {
|
|
9319
|
+
reject(new Error('chart is not rendered'));
|
|
9320
|
+
return;
|
|
9321
|
+
}
|
|
9322
|
+
const img = new Image();
|
|
9323
|
+
img.onload = () => {
|
|
9324
|
+
const canvas = document.createElement('canvas');
|
|
9325
|
+
canvas.width = Math.round(w * scale);
|
|
9326
|
+
canvas.height = Math.round(h * scale);
|
|
9327
|
+
const ctx = canvas.getContext('2d');
|
|
9328
|
+
if (!ctx) {
|
|
9329
|
+
reject(new Error('no 2d canvas context'));
|
|
9330
|
+
return;
|
|
9331
|
+
}
|
|
9332
|
+
ctx.scale(scale, scale);
|
|
9333
|
+
ctx.drawImage(img, 0, 0);
|
|
9334
|
+
resolve(canvas.toDataURL('image/png'));
|
|
9335
|
+
};
|
|
9336
|
+
img.onerror = () => reject(new Error('SVG rasterization failed'));
|
|
9337
|
+
img.src = 'data:image/svg+xml;charset=utf-8,' + encodeURIComponent(s);
|
|
9338
|
+
});
|
|
8801
9339
|
}
|
|
8802
9340
|
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.16", ngImport: i0, type: StrctChart, deps: [], target: i0.ɵɵFactoryTarget.Component });
|
|
8803
|
-
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.16", type: StrctChart, isStandalone: true, selector: "strct-chart", inputs: { data: { classPropertyName: "data", publicName: "data", isSignal: true, isRequired: false, transformFunction: null }, series: { classPropertyName: "series", publicName: "series", isSignal: true, isRequired: false, transformFunction: null }, type: { classPropertyName: "type", publicName: "type", isSignal: true, isRequired: false, transformFunction: null }, curve: { classPropertyName: "curve", publicName: "curve", isSignal: true, isRequired: false, transformFunction: null }, area: { classPropertyName: "area", publicName: "area", isSignal: true, isRequired: false, transformFunction: null }, glow: { classPropertyName: "glow", publicName: "glow", isSignal: true, isRequired: false, transformFunction: null }, live: { classPropertyName: "live", publicName: "live", isSignal: true, isRequired: false, transformFunction: null }, interval: { classPropertyName: "interval", publicName: "interval", isSignal: true, isRequired: false, transformFunction: null }, interactive: { classPropertyName: "interactive", publicName: "interactive", isSignal: true, isRequired: false, transformFunction: null }, strokeWidth: { classPropertyName: "strokeWidth", publicName: "strokeWidth", isSignal: true, isRequired: false, transformFunction: null }, grid: { classPropertyName: "grid", publicName: "grid", isSignal: true, isRequired: false, transformFunction: null }, dots: { classPropertyName: "dots", publicName: "dots", isSignal: true, isRequired: false, transformFunction: null }, legend: { classPropertyName: "legend", publicName: "legend", isSignal: true, isRequired: false, transformFunction: null }, labels: { classPropertyName: "labels", publicName: "labels", isSignal: true, isRequired: false, transformFunction: null }, xTicks: { classPropertyName: "xTicks", publicName: "xTicks", isSignal: true, isRequired: false, transformFunction: null }, xFormat: { classPropertyName: "xFormat", publicName: "xFormat", isSignal: true, isRequired: false, transformFunction: null }, status: { classPropertyName: "status", publicName: "status", isSignal: true, isRequired: false, transformFunction: null }, height: { classPropertyName: "height", publicName: "height", isSignal: true, isRequired: false, transformFunction: null }, max: { classPropertyName: "max", publicName: "max", isSignal: true, isRequired: false, transformFunction: null }, min: { classPropertyName: "min", publicName: "min", isSignal: true, isRequired: false, transformFunction: null }, yAxis: { classPropertyName: "yAxis", publicName: "yAxis", isSignal: true, isRequired: false, transformFunction: null }, yTicks: { classPropertyName: "yTicks", publicName: "yTicks", isSignal: true, isRequired: false, transformFunction: null }, axisFormat: { classPropertyName: "axisFormat", publicName: "axisFormat", isSignal: true, isRequired: false, transformFunction: null }, thresholds: { classPropertyName: "thresholds", publicName: "thresholds", isSignal: true, isRequired: false, transformFunction: null }, emptyText: { classPropertyName: "emptyText", publicName: "emptyText", isSignal: true, isRequired: false, transformFunction: null }, agoFormat: { classPropertyName: "agoFormat", publicName: "agoFormat", isSignal: true, isRequired: false, transformFunction: null }, valueFormat: { classPropertyName: "valueFormat", publicName: "valueFormat", isSignal: true, isRequired: false, transformFunction: null } }, host: { properties: { "class.strct-chart--glow": "glow()", "style.--strct-chart-c": "color()" }, classAttribute: "strct-chart" }, viewQueries: [{ propertyName: "svgRef", first: true, predicate: ["svg"], descendants: true, isSignal: true }], ngImport: i0, template: `
|
|
9341
|
+
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.16", type: StrctChart, isStandalone: true, selector: "strct-chart", inputs: { data: { classPropertyName: "data", publicName: "data", isSignal: true, isRequired: false, transformFunction: null }, series: { classPropertyName: "series", publicName: "series", isSignal: true, isRequired: false, transformFunction: null }, type: { classPropertyName: "type", publicName: "type", isSignal: true, isRequired: false, transformFunction: null }, curve: { classPropertyName: "curve", publicName: "curve", isSignal: true, isRequired: false, transformFunction: null }, area: { classPropertyName: "area", publicName: "area", isSignal: true, isRequired: false, transformFunction: null }, glow: { classPropertyName: "glow", publicName: "glow", isSignal: true, isRequired: false, transformFunction: null }, live: { classPropertyName: "live", publicName: "live", isSignal: true, isRequired: false, transformFunction: null }, interval: { classPropertyName: "interval", publicName: "interval", isSignal: true, isRequired: false, transformFunction: null }, interactive: { classPropertyName: "interactive", publicName: "interactive", isSignal: true, isRequired: false, transformFunction: null }, strokeWidth: { classPropertyName: "strokeWidth", publicName: "strokeWidth", isSignal: true, isRequired: false, transformFunction: null }, grid: { classPropertyName: "grid", publicName: "grid", isSignal: true, isRequired: false, transformFunction: null }, dots: { classPropertyName: "dots", publicName: "dots", isSignal: true, isRequired: false, transformFunction: null }, legend: { classPropertyName: "legend", publicName: "legend", isSignal: true, isRequired: false, transformFunction: null }, labels: { classPropertyName: "labels", publicName: "labels", isSignal: true, isRequired: false, transformFunction: null }, xTicks: { classPropertyName: "xTicks", publicName: "xTicks", isSignal: true, isRequired: false, transformFunction: null }, xFormat: { classPropertyName: "xFormat", publicName: "xFormat", isSignal: true, isRequired: false, transformFunction: null }, status: { classPropertyName: "status", publicName: "status", isSignal: true, isRequired: false, transformFunction: null }, height: { classPropertyName: "height", publicName: "height", isSignal: true, isRequired: false, transformFunction: null }, max: { classPropertyName: "max", publicName: "max", isSignal: true, isRequired: false, transformFunction: null }, min: { classPropertyName: "min", publicName: "min", isSignal: true, isRequired: false, transformFunction: null }, yAxis: { classPropertyName: "yAxis", publicName: "yAxis", isSignal: true, isRequired: false, transformFunction: null }, yTicks: { classPropertyName: "yTicks", publicName: "yTicks", isSignal: true, isRequired: false, transformFunction: null }, axisFormat: { classPropertyName: "axisFormat", publicName: "axisFormat", isSignal: true, isRequired: false, transformFunction: null }, thresholds: { classPropertyName: "thresholds", publicName: "thresholds", isSignal: true, isRequired: false, transformFunction: null }, emptyText: { classPropertyName: "emptyText", publicName: "emptyText", isSignal: true, isRequired: false, transformFunction: null }, agoFormat: { classPropertyName: "agoFormat", publicName: "agoFormat", isSignal: true, isRequired: false, transformFunction: null }, valueFormat: { classPropertyName: "valueFormat", publicName: "valueFormat", isSignal: true, isRequired: false, transformFunction: null }, annotations: { classPropertyName: "annotations", publicName: "annotations", isSignal: true, isRequired: false, transformFunction: null }, activeIndex: { classPropertyName: "activeIndex", publicName: "activeIndex", isSignal: true, isRequired: false, transformFunction: null }, brush: { classPropertyName: "brush", publicName: "brush", isSignal: true, isRequired: false, transformFunction: null }, zoom: { classPropertyName: "zoom", publicName: "zoom", isSignal: true, isRequired: false, transformFunction: null }, gapText: { classPropertyName: "gapText", publicName: "gapText", isSignal: true, isRequired: false, transformFunction: null }, resetLabel: { classPropertyName: "resetLabel", publicName: "resetLabel", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { hoverIndex: "hoverIndex", brushChange: "brushChange" }, host: { properties: { "class.strct-chart--glow": "glow()", "class.strct-chart--brush": "brush() || zoom()", "style.--strct-chart-c": "color()" }, classAttribute: "strct-chart" }, viewQueries: [{ propertyName: "svgRef", first: true, predicate: ["svg"], descendants: true, isSignal: true }], ngImport: i0, template: `
|
|
8804
9342
|
@if (isEmpty()) {
|
|
8805
9343
|
<div class="strct-chart__empty" [style.height.px]="height()">{{ emptyText() }}</div>
|
|
8806
9344
|
} @else {
|
|
@@ -8835,10 +9373,14 @@ class StrctChart {
|
|
|
8835
9373
|
[attr.width]="width()"
|
|
8836
9374
|
[attr.height]="height()"
|
|
8837
9375
|
[style.height.px]="height()"
|
|
9376
|
+
(pointerdown)="onDown($event)"
|
|
8838
9377
|
(pointermove)="onMove($event)"
|
|
8839
|
-
(
|
|
9378
|
+
(pointerup)="onUp()"
|
|
9379
|
+
(lostpointercapture)="onUp()"
|
|
9380
|
+
(pointerleave)="onLeave()"
|
|
9381
|
+
(dblclick)="onDblClick()"
|
|
8840
9382
|
(keydown)="onKey($event)"
|
|
8841
|
-
(blur)="
|
|
9383
|
+
(blur)="onLeave()"
|
|
8842
9384
|
>
|
|
8843
9385
|
<defs>
|
|
8844
9386
|
<linearGradient [attr.id]="gradId" x1="0" y1="0" x2="0" y2="1">
|
|
@@ -8862,6 +9404,19 @@ class StrctChart {
|
|
|
8862
9404
|
}
|
|
8863
9405
|
}
|
|
8864
9406
|
|
|
9407
|
+
<!-- Event / annotation markers: behind the data, above the grid. -->
|
|
9408
|
+
@for (a of annotationLines(); track $index) {
|
|
9409
|
+
<line
|
|
9410
|
+
class="strct-chart__ann"
|
|
9411
|
+
[class.strct-chart__ann--dashed]="a.dashed"
|
|
9412
|
+
[attr.x1]="a.x"
|
|
9413
|
+
[attr.x2]="a.x"
|
|
9414
|
+
[attr.y1]="pad.t"
|
|
9415
|
+
[attr.y2]="height() - pad.b"
|
|
9416
|
+
[attr.stroke]="a.color"
|
|
9417
|
+
/>
|
|
9418
|
+
}
|
|
9419
|
+
|
|
8865
9420
|
@if (type() === 'bar' && !isMulti()) {
|
|
8866
9421
|
@for (b of bars(); track $index) {
|
|
8867
9422
|
<rect
|
|
@@ -8882,6 +9437,9 @@ class StrctChart {
|
|
|
8882
9437
|
>
|
|
8883
9438
|
@if (isMulti()) {
|
|
8884
9439
|
@for (s of multiSeries(); track $index) {
|
|
9440
|
+
@if (s.bandPath) {
|
|
9441
|
+
<path class="strct-chart__band" [attr.d]="s.bandPath" [attr.fill]="s.color" />
|
|
9442
|
+
}
|
|
8885
9443
|
@if (s.area && s.areaPath) {
|
|
8886
9444
|
<path
|
|
8887
9445
|
class="strct-chart__area strct-chart__area--flat"
|
|
@@ -8916,7 +9474,7 @@ class StrctChart {
|
|
|
8916
9474
|
[attr.stroke]="color()"
|
|
8917
9475
|
/>
|
|
8918
9476
|
@if (dots()) {
|
|
8919
|
-
@for (p of
|
|
9477
|
+
@for (p of dotPts(); track $index) {
|
|
8920
9478
|
<circle
|
|
8921
9479
|
class="strct-chart__dot"
|
|
8922
9480
|
[attr.cx]="p.x"
|
|
@@ -8942,6 +9500,16 @@ class StrctChart {
|
|
|
8942
9500
|
/>
|
|
8943
9501
|
}
|
|
8944
9502
|
|
|
9503
|
+
@if (brushRect(); as br) {
|
|
9504
|
+
<rect
|
|
9505
|
+
class="strct-chart__brush"
|
|
9506
|
+
[attr.x]="br.x"
|
|
9507
|
+
[attr.y]="pad.t"
|
|
9508
|
+
[attr.width]="br.w"
|
|
9509
|
+
[attr.height]="height() - pad.t - pad.b"
|
|
9510
|
+
/>
|
|
9511
|
+
}
|
|
9512
|
+
|
|
8945
9513
|
@if (interactive() && hoverX() !== null) {
|
|
8946
9514
|
<line
|
|
8947
9515
|
class="strct-chart__cross"
|
|
@@ -9002,12 +9570,29 @@ class StrctChart {
|
|
|
9002
9570
|
}
|
|
9003
9571
|
}
|
|
9004
9572
|
|
|
9573
|
+
@for (a of annotationLines(); track $index) {
|
|
9574
|
+
@if (a.label) {
|
|
9575
|
+
<div class="strct-chart__ann-label" [style.left.px]="a.x" [style.color]="a.color">
|
|
9576
|
+
{{ a.label }}
|
|
9577
|
+
</div>
|
|
9578
|
+
}
|
|
9579
|
+
}
|
|
9580
|
+
|
|
9581
|
+
@if (zoomed()) {
|
|
9582
|
+
<button type="button" class="strct-chart__reset" (click)="resetZoom()">
|
|
9583
|
+
⟲ {{ resetLabel() }}
|
|
9584
|
+
</button>
|
|
9585
|
+
}
|
|
9586
|
+
|
|
9005
9587
|
@if (interactive() && hoverX() !== null) {
|
|
9006
9588
|
@if (isMulti()) {
|
|
9007
9589
|
<div class="strct-chart__tip strct-chart__tip--multi" [style.left.px]="hoverX()">
|
|
9008
9590
|
@if (hoverMeta()) {
|
|
9009
9591
|
<span class="strct-chart__tip-l">{{ hoverMeta() }}</span>
|
|
9010
9592
|
}
|
|
9593
|
+
@if (annAt(); as ann) {
|
|
9594
|
+
<span class="strct-chart__tip-ann" [style.color]="ann.color">{{ ann.label }}</span>
|
|
9595
|
+
}
|
|
9011
9596
|
@for (r of hoverRows(); track r.label) {
|
|
9012
9597
|
<span class="strct-chart__tip-row">
|
|
9013
9598
|
<span class="strct-chart__tip-sw" [style.background]="r.color"></span>
|
|
@@ -9039,6 +9624,17 @@ class StrctChart {
|
|
|
9039
9624
|
}
|
|
9040
9625
|
</span>
|
|
9041
9626
|
}
|
|
9627
|
+
@if (annAt(); as ann) {
|
|
9628
|
+
<span class="strct-chart__tip-ann" [style.color]="ann.color">{{ ann.label }}</span>
|
|
9629
|
+
}
|
|
9630
|
+
</div>
|
|
9631
|
+
} @else if (hoverGap()) {
|
|
9632
|
+
<!-- A gap point: keep the time slot, say "no data" instead of a value. -->
|
|
9633
|
+
<div class="strct-chart__tip strct-chart__tip--gap" [style.left.px]="hoverX()">
|
|
9634
|
+
<span class="strct-chart__tip-v">{{ gapText() }}</span>
|
|
9635
|
+
@if (hoverMeta()) {
|
|
9636
|
+
<span class="strct-chart__tip-l">{{ hoverMeta() }}</span>
|
|
9637
|
+
}
|
|
9042
9638
|
</div>
|
|
9043
9639
|
}
|
|
9044
9640
|
}
|
|
@@ -9053,7 +9649,7 @@ class StrctChart {
|
|
|
9053
9649
|
<div class="strct-chart__labels">
|
|
9054
9650
|
@for (l of displayLabels(); track $index) {
|
|
9055
9651
|
<span
|
|
9056
|
-
[class.strct-chart__label--active]="interactive() &&
|
|
9652
|
+
[class.strct-chart__label--active]="interactive() && dispIdx() === l.i"
|
|
9057
9653
|
[style.left.px]="xOf(l.i)"
|
|
9058
9654
|
>{{ l.text }}</span
|
|
9059
9655
|
>
|
|
@@ -9061,7 +9657,7 @@ class StrctChart {
|
|
|
9061
9657
|
</div>
|
|
9062
9658
|
}
|
|
9063
9659
|
}
|
|
9064
|
-
`, isInline: true, styles: [".strct-chart{display:block;position:relative}.strct-chart__plot{position:relative}.strct-chart__svg{width:100%;display:block;touch-action:none}.strct-chart__svg:focus-visible{outline:2px solid var(--acc50);outline-offset:2px;border-radius:var(--radius-sm)}.strct-chart__sr{position:absolute;width:1px;height:1px;overflow:hidden;clip-path:inset(50%);white-space:nowrap}.strct-chart__empty{display:flex;align-items:center;justify-content:center;font-size:12px;color:var(--t3)}.strct-chart__grid{stroke:var(--b1);stroke-width:1;vector-effect:non-scaling-stroke}.strct-chart__line{vector-effect:non-scaling-stroke;stroke-linejoin:round;stroke-linecap:round}.strct-chart__area{stroke:none}.strct-chart__area--flat{opacity:.14}.strct-chart__dot,.strct-chart__hoverdot,.strct-chart__head-dot{stroke:var(--bg-1);stroke-width:1.5}.strct-chart__cross{stroke:var(--strct-chart-c);stroke-width:1;opacity:.4;stroke-dasharray:3 3;vector-effect:non-scaling-stroke}.strct-chart__threshold{stroke-width:1;opacity:.85;vector-effect:non-scaling-stroke}.strct-chart__threshold--dashed{stroke-dasharray:4 3}.strct-chart__bar{rx:1.5}.strct-chart--glow .strct-chart__line{filter:drop-shadow(0 0 1.5px var(--strct-chart-c)) drop-shadow(0 0 5px var(--strct-chart-c))}.strct-chart--glow .strct-chart__head-dot{filter:drop-shadow(0 0 2px var(--strct-chart-c)) drop-shadow(0 0 6px var(--strct-chart-c))}.strct-chart--glow .strct-chart__hoverdot{filter:drop-shadow(0 0 4px var(--strct-chart-c))}.strct-chart__ytick{position:absolute;left:0;width:34px;text-align:end;transform:translateY(-50%);pointer-events:none;font-family:var(--mono);font-size:12px;color:var(--t3);font-variant-numeric:tabular-nums}.strct-chart__thr{position:absolute;right:2px;transform:translateY(-50%);pointer-events:none;font-size:12px;font-weight:600;font-variant-numeric:tabular-nums;background:var(--bg-1);padding:0 3px;border-radius:3px}.strct-chart__axis-y{position:absolute;left:0;transform:translateY(-50%);pointer-events:none;padding:1px 5px;border-radius:var(--radius-sm);background:var(--bg-a);border:1px solid var(--b2);font-family:var(--mono);font-size:12px;font-weight:600;color:var(--t2);font-variant-numeric:tabular-nums;z-index:2}.strct-chart__label--active{color:var(--t1);font-weight:700}.strct-chart__legend{display:flex;flex-wrap:wrap;gap:6px 14px;margin-bottom:8px;font-size:12px;color:var(--t2)}.strct-chart__leg{display:inline-flex;align-items:center;gap:6px}.strct-chart__leg-sw{width:9px;height:3px;border-radius:2px;flex-shrink:0}.strct-chart__tip{position:absolute;transform:translate(-50%,calc(-100% - 10px));pointer-events:none;display:flex;flex-direction:column;align-items:center;gap:1px;padding:4px 8px;border-radius:var(--radius-sm);background:var(--bg-a);border:1px solid var(--b2);box-shadow:var(--shadow-elevated);white-space:nowrap;z-index:2}.strct-chart__tip--multi{top:6px;transform:translate(-50%);align-items:stretch;gap:3px}.strct-chart__tip-v{font-size:12px;font-weight:700;color:var(--t1);font-variant-numeric:tabular-nums}.strct-chart__tip-meta{display:inline-flex;align-items:center;gap:5px}.strct-chart__tip-delta{font-size:12px;font-weight:600;color:var(--t3);font-variant-numeric:tabular-nums}.strct-chart__tip-delta--up{color:var(--success)}.strct-chart__tip-delta--down{color:var(--critical)}.strct-chart__tip-l{font-size:12px;color:var(--t3)}.strct-chart__tip-row{display:inline-flex;align-items:center;gap:6px;font-size:12px}.strct-chart__tip-sw{width:8px;height:3px;border-radius:2px;flex-shrink:0}.strct-chart__tip-rl{color:var(--t3);margin-inline-end:auto}.strct-chart__tip-rv{color:var(--t1);font-weight:700;font-variant-numeric:tabular-nums}.strct-chart__labels{position:relative;height:15px;margin-top:6px;font-size:12px;color:var(--t3)}.strct-chart__labels span{position:absolute;transform:translate(-50%);white-space:nowrap}@media(prefers-reduced-motion:no-preference){.strct-chart__line--draw{stroke-dasharray:1;stroke-dashoffset:1;animation:strct-chart-draw .9s ease forwards}.strct-chart__pulse{transform-box:fill-box;transform-origin:center;animation:strct-chart-pulse 2.4s ease-out infinite}}@keyframes strct-chart-draw{to{stroke-dashoffset:0}}@keyframes strct-chart-pulse{0%{transform:scale(1);opacity:.45}70%{opacity:0}to{transform:scale(2.5);opacity:0}}\n"], changeDetection: i0.ChangeDetectionStrategy.OnPush, encapsulation: i0.ViewEncapsulation.None });
|
|
9660
|
+
`, isInline: true, styles: [".strct-chart{display:block;position:relative}.strct-chart__plot{position:relative}.strct-chart__svg{width:100%;display:block;touch-action:none}.strct-chart__svg:focus-visible{outline:2px solid var(--acc50);outline-offset:2px;border-radius:var(--radius-sm)}.strct-chart__sr{position:absolute;width:1px;height:1px;overflow:hidden;clip-path:inset(50%);white-space:nowrap}.strct-chart__empty{display:flex;align-items:center;justify-content:center;font-size:12px;color:var(--t3)}.strct-chart__grid{stroke:var(--b1);stroke-width:1;vector-effect:non-scaling-stroke}.strct-chart__line{vector-effect:non-scaling-stroke;stroke-linejoin:round;stroke-linecap:round}.strct-chart__area{stroke:none}.strct-chart__area--flat{opacity:.14}.strct-chart__dot,.strct-chart__hoverdot,.strct-chart__head-dot{stroke:var(--bg-1);stroke-width:1.5}.strct-chart__cross{stroke:var(--strct-chart-c);stroke-width:1;opacity:.4;stroke-dasharray:3 3;vector-effect:non-scaling-stroke}.strct-chart__threshold{stroke-width:1;opacity:.85;vector-effect:non-scaling-stroke}.strct-chart__threshold--dashed{stroke-dasharray:4 3}.strct-chart__bar{rx:1.5}.strct-chart__band{opacity:.13;stroke:none}.strct-chart__ann{stroke-width:1;opacity:.8;vector-effect:non-scaling-stroke}.strct-chart__ann--dashed{stroke-dasharray:4 3}.strct-chart__ann-label{position:absolute;top:0;transform:translate(-50%);pointer-events:none;font-size:12px;font-weight:600;background:var(--bg-1);padding:0 3px;border-radius:3px;white-space:nowrap}.strct-chart--brush .strct-chart__svg{cursor:crosshair}.strct-chart__brush{fill:var(--acc);opacity:.16;stroke:var(--acc50);stroke-width:1;vector-effect:non-scaling-stroke}.strct-chart__reset{position:absolute;top:6px;right:8px;z-index:3;display:inline-flex;align-items:center;gap:5px;padding:2px 9px;border:1px solid var(--b2);border-radius:99px;background:var(--bg-a);color:var(--t2);font-family:var(--font);font-size:12px;font-weight:600;cursor:pointer}.strct-chart__reset:hover{color:var(--t1);border-color:var(--acc50)}.strct-chart__reset:focus-visible{outline:2px solid var(--acc50);outline-offset:1px}.strct-chart__tip--gap{top:6px;transform:translate(-50%)}.strct-chart__tip-ann{font-size:12px;font-weight:600}.strct-chart--glow .strct-chart__line{filter:drop-shadow(0 0 1.5px var(--strct-chart-c)) drop-shadow(0 0 5px var(--strct-chart-c))}.strct-chart--glow .strct-chart__head-dot{filter:drop-shadow(0 0 2px var(--strct-chart-c)) drop-shadow(0 0 6px var(--strct-chart-c))}.strct-chart--glow .strct-chart__hoverdot{filter:drop-shadow(0 0 4px var(--strct-chart-c))}.strct-chart__ytick{position:absolute;left:0;width:34px;text-align:end;transform:translateY(-50%);pointer-events:none;font-family:var(--mono);font-size:12px;color:var(--t3);font-variant-numeric:tabular-nums}.strct-chart__thr{position:absolute;right:2px;transform:translateY(-50%);pointer-events:none;font-size:12px;font-weight:600;font-variant-numeric:tabular-nums;background:var(--bg-1);padding:0 3px;border-radius:3px}.strct-chart__axis-y{position:absolute;left:0;transform:translateY(-50%);pointer-events:none;padding:1px 5px;border-radius:var(--radius-sm);background:var(--bg-a);border:1px solid var(--b2);font-family:var(--mono);font-size:12px;font-weight:600;color:var(--t2);font-variant-numeric:tabular-nums;z-index:2}.strct-chart__label--active{color:var(--t1);font-weight:700}.strct-chart__legend{display:flex;flex-wrap:wrap;gap:6px 14px;margin-bottom:8px;font-size:12px;color:var(--t2)}.strct-chart__leg{display:inline-flex;align-items:center;gap:6px}.strct-chart__leg-sw{width:9px;height:3px;border-radius:2px;flex-shrink:0}.strct-chart__tip{position:absolute;transform:translate(-50%,calc(-100% - 10px));pointer-events:none;display:flex;flex-direction:column;align-items:center;gap:1px;padding:4px 8px;border-radius:var(--radius-sm);background:var(--bg-a);border:1px solid var(--b2);box-shadow:var(--shadow-elevated);white-space:nowrap;z-index:2}.strct-chart__tip--multi{top:6px;transform:translate(-50%);align-items:stretch;gap:3px}.strct-chart__tip-v{font-size:12px;font-weight:700;color:var(--t1);font-variant-numeric:tabular-nums}.strct-chart__tip-meta{display:inline-flex;align-items:center;gap:5px}.strct-chart__tip-delta{font-size:12px;font-weight:600;color:var(--t3);font-variant-numeric:tabular-nums}.strct-chart__tip-delta--up{color:var(--success)}.strct-chart__tip-delta--down{color:var(--critical)}.strct-chart__tip-l{font-size:12px;color:var(--t3)}.strct-chart__tip-row{display:inline-flex;align-items:center;gap:6px;font-size:12px}.strct-chart__tip-sw{width:8px;height:3px;border-radius:2px;flex-shrink:0}.strct-chart__tip-rl{color:var(--t3);margin-inline-end:auto}.strct-chart__tip-rv{color:var(--t1);font-weight:700;font-variant-numeric:tabular-nums}.strct-chart__labels{position:relative;height:15px;margin-top:6px;font-size:12px;color:var(--t3)}.strct-chart__labels span{position:absolute;transform:translate(-50%);white-space:nowrap}@media(prefers-reduced-motion:no-preference){.strct-chart__line--draw{stroke-dasharray:1;stroke-dashoffset:1;animation:strct-chart-draw .9s ease forwards}.strct-chart__pulse{transform-box:fill-box;transform-origin:center;animation:strct-chart-pulse 2.4s ease-out infinite}}@keyframes strct-chart-draw{to{stroke-dashoffset:0}}@keyframes strct-chart-pulse{0%{transform:scale(1);opacity:.45}70%{opacity:0}to{transform:scale(2.5);opacity:0}}\n"], changeDetection: i0.ChangeDetectionStrategy.OnPush, encapsulation: i0.ViewEncapsulation.None });
|
|
9065
9661
|
}
|
|
9066
9662
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.16", ngImport: i0, type: StrctChart, decorators: [{
|
|
9067
9663
|
type: Component,
|
|
@@ -9100,10 +9696,14 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.16", ngImpo
|
|
|
9100
9696
|
[attr.width]="width()"
|
|
9101
9697
|
[attr.height]="height()"
|
|
9102
9698
|
[style.height.px]="height()"
|
|
9699
|
+
(pointerdown)="onDown($event)"
|
|
9103
9700
|
(pointermove)="onMove($event)"
|
|
9104
|
-
(
|
|
9701
|
+
(pointerup)="onUp()"
|
|
9702
|
+
(lostpointercapture)="onUp()"
|
|
9703
|
+
(pointerleave)="onLeave()"
|
|
9704
|
+
(dblclick)="onDblClick()"
|
|
9105
9705
|
(keydown)="onKey($event)"
|
|
9106
|
-
(blur)="
|
|
9706
|
+
(blur)="onLeave()"
|
|
9107
9707
|
>
|
|
9108
9708
|
<defs>
|
|
9109
9709
|
<linearGradient [attr.id]="gradId" x1="0" y1="0" x2="0" y2="1">
|
|
@@ -9127,6 +9727,19 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.16", ngImpo
|
|
|
9127
9727
|
}
|
|
9128
9728
|
}
|
|
9129
9729
|
|
|
9730
|
+
<!-- Event / annotation markers: behind the data, above the grid. -->
|
|
9731
|
+
@for (a of annotationLines(); track $index) {
|
|
9732
|
+
<line
|
|
9733
|
+
class="strct-chart__ann"
|
|
9734
|
+
[class.strct-chart__ann--dashed]="a.dashed"
|
|
9735
|
+
[attr.x1]="a.x"
|
|
9736
|
+
[attr.x2]="a.x"
|
|
9737
|
+
[attr.y1]="pad.t"
|
|
9738
|
+
[attr.y2]="height() - pad.b"
|
|
9739
|
+
[attr.stroke]="a.color"
|
|
9740
|
+
/>
|
|
9741
|
+
}
|
|
9742
|
+
|
|
9130
9743
|
@if (type() === 'bar' && !isMulti()) {
|
|
9131
9744
|
@for (b of bars(); track $index) {
|
|
9132
9745
|
<rect
|
|
@@ -9147,6 +9760,9 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.16", ngImpo
|
|
|
9147
9760
|
>
|
|
9148
9761
|
@if (isMulti()) {
|
|
9149
9762
|
@for (s of multiSeries(); track $index) {
|
|
9763
|
+
@if (s.bandPath) {
|
|
9764
|
+
<path class="strct-chart__band" [attr.d]="s.bandPath" [attr.fill]="s.color" />
|
|
9765
|
+
}
|
|
9150
9766
|
@if (s.area && s.areaPath) {
|
|
9151
9767
|
<path
|
|
9152
9768
|
class="strct-chart__area strct-chart__area--flat"
|
|
@@ -9181,7 +9797,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.16", ngImpo
|
|
|
9181
9797
|
[attr.stroke]="color()"
|
|
9182
9798
|
/>
|
|
9183
9799
|
@if (dots()) {
|
|
9184
|
-
@for (p of
|
|
9800
|
+
@for (p of dotPts(); track $index) {
|
|
9185
9801
|
<circle
|
|
9186
9802
|
class="strct-chart__dot"
|
|
9187
9803
|
[attr.cx]="p.x"
|
|
@@ -9207,6 +9823,16 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.16", ngImpo
|
|
|
9207
9823
|
/>
|
|
9208
9824
|
}
|
|
9209
9825
|
|
|
9826
|
+
@if (brushRect(); as br) {
|
|
9827
|
+
<rect
|
|
9828
|
+
class="strct-chart__brush"
|
|
9829
|
+
[attr.x]="br.x"
|
|
9830
|
+
[attr.y]="pad.t"
|
|
9831
|
+
[attr.width]="br.w"
|
|
9832
|
+
[attr.height]="height() - pad.t - pad.b"
|
|
9833
|
+
/>
|
|
9834
|
+
}
|
|
9835
|
+
|
|
9210
9836
|
@if (interactive() && hoverX() !== null) {
|
|
9211
9837
|
<line
|
|
9212
9838
|
class="strct-chart__cross"
|
|
@@ -9267,12 +9893,29 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.16", ngImpo
|
|
|
9267
9893
|
}
|
|
9268
9894
|
}
|
|
9269
9895
|
|
|
9896
|
+
@for (a of annotationLines(); track $index) {
|
|
9897
|
+
@if (a.label) {
|
|
9898
|
+
<div class="strct-chart__ann-label" [style.left.px]="a.x" [style.color]="a.color">
|
|
9899
|
+
{{ a.label }}
|
|
9900
|
+
</div>
|
|
9901
|
+
}
|
|
9902
|
+
}
|
|
9903
|
+
|
|
9904
|
+
@if (zoomed()) {
|
|
9905
|
+
<button type="button" class="strct-chart__reset" (click)="resetZoom()">
|
|
9906
|
+
⟲ {{ resetLabel() }}
|
|
9907
|
+
</button>
|
|
9908
|
+
}
|
|
9909
|
+
|
|
9270
9910
|
@if (interactive() && hoverX() !== null) {
|
|
9271
9911
|
@if (isMulti()) {
|
|
9272
9912
|
<div class="strct-chart__tip strct-chart__tip--multi" [style.left.px]="hoverX()">
|
|
9273
9913
|
@if (hoverMeta()) {
|
|
9274
9914
|
<span class="strct-chart__tip-l">{{ hoverMeta() }}</span>
|
|
9275
9915
|
}
|
|
9916
|
+
@if (annAt(); as ann) {
|
|
9917
|
+
<span class="strct-chart__tip-ann" [style.color]="ann.color">{{ ann.label }}</span>
|
|
9918
|
+
}
|
|
9276
9919
|
@for (r of hoverRows(); track r.label) {
|
|
9277
9920
|
<span class="strct-chart__tip-row">
|
|
9278
9921
|
<span class="strct-chart__tip-sw" [style.background]="r.color"></span>
|
|
@@ -9304,6 +9947,17 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.16", ngImpo
|
|
|
9304
9947
|
}
|
|
9305
9948
|
</span>
|
|
9306
9949
|
}
|
|
9950
|
+
@if (annAt(); as ann) {
|
|
9951
|
+
<span class="strct-chart__tip-ann" [style.color]="ann.color">{{ ann.label }}</span>
|
|
9952
|
+
}
|
|
9953
|
+
</div>
|
|
9954
|
+
} @else if (hoverGap()) {
|
|
9955
|
+
<!-- A gap point: keep the time slot, say "no data" instead of a value. -->
|
|
9956
|
+
<div class="strct-chart__tip strct-chart__tip--gap" [style.left.px]="hoverX()">
|
|
9957
|
+
<span class="strct-chart__tip-v">{{ gapText() }}</span>
|
|
9958
|
+
@if (hoverMeta()) {
|
|
9959
|
+
<span class="strct-chart__tip-l">{{ hoverMeta() }}</span>
|
|
9960
|
+
}
|
|
9307
9961
|
</div>
|
|
9308
9962
|
}
|
|
9309
9963
|
}
|
|
@@ -9318,7 +9972,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.16", ngImpo
|
|
|
9318
9972
|
<div class="strct-chart__labels">
|
|
9319
9973
|
@for (l of displayLabels(); track $index) {
|
|
9320
9974
|
<span
|
|
9321
|
-
[class.strct-chart__label--active]="interactive() &&
|
|
9975
|
+
[class.strct-chart__label--active]="interactive() && dispIdx() === l.i"
|
|
9322
9976
|
[style.left.px]="xOf(l.i)"
|
|
9323
9977
|
>{{ l.text }}</span
|
|
9324
9978
|
>
|
|
@@ -9329,9 +9983,10 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.16", ngImpo
|
|
|
9329
9983
|
`, host: {
|
|
9330
9984
|
class: 'strct-chart',
|
|
9331
9985
|
'[class.strct-chart--glow]': 'glow()',
|
|
9986
|
+
'[class.strct-chart--brush]': 'brush() || zoom()',
|
|
9332
9987
|
'[style.--strct-chart-c]': 'color()',
|
|
9333
|
-
}, styles: [".strct-chart{display:block;position:relative}.strct-chart__plot{position:relative}.strct-chart__svg{width:100%;display:block;touch-action:none}.strct-chart__svg:focus-visible{outline:2px solid var(--acc50);outline-offset:2px;border-radius:var(--radius-sm)}.strct-chart__sr{position:absolute;width:1px;height:1px;overflow:hidden;clip-path:inset(50%);white-space:nowrap}.strct-chart__empty{display:flex;align-items:center;justify-content:center;font-size:12px;color:var(--t3)}.strct-chart__grid{stroke:var(--b1);stroke-width:1;vector-effect:non-scaling-stroke}.strct-chart__line{vector-effect:non-scaling-stroke;stroke-linejoin:round;stroke-linecap:round}.strct-chart__area{stroke:none}.strct-chart__area--flat{opacity:.14}.strct-chart__dot,.strct-chart__hoverdot,.strct-chart__head-dot{stroke:var(--bg-1);stroke-width:1.5}.strct-chart__cross{stroke:var(--strct-chart-c);stroke-width:1;opacity:.4;stroke-dasharray:3 3;vector-effect:non-scaling-stroke}.strct-chart__threshold{stroke-width:1;opacity:.85;vector-effect:non-scaling-stroke}.strct-chart__threshold--dashed{stroke-dasharray:4 3}.strct-chart__bar{rx:1.5}.strct-chart--glow .strct-chart__line{filter:drop-shadow(0 0 1.5px var(--strct-chart-c)) drop-shadow(0 0 5px var(--strct-chart-c))}.strct-chart--glow .strct-chart__head-dot{filter:drop-shadow(0 0 2px var(--strct-chart-c)) drop-shadow(0 0 6px var(--strct-chart-c))}.strct-chart--glow .strct-chart__hoverdot{filter:drop-shadow(0 0 4px var(--strct-chart-c))}.strct-chart__ytick{position:absolute;left:0;width:34px;text-align:end;transform:translateY(-50%);pointer-events:none;font-family:var(--mono);font-size:12px;color:var(--t3);font-variant-numeric:tabular-nums}.strct-chart__thr{position:absolute;right:2px;transform:translateY(-50%);pointer-events:none;font-size:12px;font-weight:600;font-variant-numeric:tabular-nums;background:var(--bg-1);padding:0 3px;border-radius:3px}.strct-chart__axis-y{position:absolute;left:0;transform:translateY(-50%);pointer-events:none;padding:1px 5px;border-radius:var(--radius-sm);background:var(--bg-a);border:1px solid var(--b2);font-family:var(--mono);font-size:12px;font-weight:600;color:var(--t2);font-variant-numeric:tabular-nums;z-index:2}.strct-chart__label--active{color:var(--t1);font-weight:700}.strct-chart__legend{display:flex;flex-wrap:wrap;gap:6px 14px;margin-bottom:8px;font-size:12px;color:var(--t2)}.strct-chart__leg{display:inline-flex;align-items:center;gap:6px}.strct-chart__leg-sw{width:9px;height:3px;border-radius:2px;flex-shrink:0}.strct-chart__tip{position:absolute;transform:translate(-50%,calc(-100% - 10px));pointer-events:none;display:flex;flex-direction:column;align-items:center;gap:1px;padding:4px 8px;border-radius:var(--radius-sm);background:var(--bg-a);border:1px solid var(--b2);box-shadow:var(--shadow-elevated);white-space:nowrap;z-index:2}.strct-chart__tip--multi{top:6px;transform:translate(-50%);align-items:stretch;gap:3px}.strct-chart__tip-v{font-size:12px;font-weight:700;color:var(--t1);font-variant-numeric:tabular-nums}.strct-chart__tip-meta{display:inline-flex;align-items:center;gap:5px}.strct-chart__tip-delta{font-size:12px;font-weight:600;color:var(--t3);font-variant-numeric:tabular-nums}.strct-chart__tip-delta--up{color:var(--success)}.strct-chart__tip-delta--down{color:var(--critical)}.strct-chart__tip-l{font-size:12px;color:var(--t3)}.strct-chart__tip-row{display:inline-flex;align-items:center;gap:6px;font-size:12px}.strct-chart__tip-sw{width:8px;height:3px;border-radius:2px;flex-shrink:0}.strct-chart__tip-rl{color:var(--t3);margin-inline-end:auto}.strct-chart__tip-rv{color:var(--t1);font-weight:700;font-variant-numeric:tabular-nums}.strct-chart__labels{position:relative;height:15px;margin-top:6px;font-size:12px;color:var(--t3)}.strct-chart__labels span{position:absolute;transform:translate(-50%);white-space:nowrap}@media(prefers-reduced-motion:no-preference){.strct-chart__line--draw{stroke-dasharray:1;stroke-dashoffset:1;animation:strct-chart-draw .9s ease forwards}.strct-chart__pulse{transform-box:fill-box;transform-origin:center;animation:strct-chart-pulse 2.4s ease-out infinite}}@keyframes strct-chart-draw{to{stroke-dashoffset:0}}@keyframes strct-chart-pulse{0%{transform:scale(1);opacity:.45}70%{opacity:0}to{transform:scale(2.5);opacity:0}}\n"] }]
|
|
9334
|
-
}], ctorParameters: () => [], propDecorators: { data: [{ type: i0.Input, args: [{ isSignal: true, alias: "data", required: false }] }], series: [{ type: i0.Input, args: [{ isSignal: true, alias: "series", required: false }] }], type: [{ type: i0.Input, args: [{ isSignal: true, alias: "type", required: false }] }], curve: [{ type: i0.Input, args: [{ isSignal: true, alias: "curve", required: false }] }], area: [{ type: i0.Input, args: [{ isSignal: true, alias: "area", required: false }] }], glow: [{ type: i0.Input, args: [{ isSignal: true, alias: "glow", required: false }] }], live: [{ type: i0.Input, args: [{ isSignal: true, alias: "live", required: false }] }], interval: [{ type: i0.Input, args: [{ isSignal: true, alias: "interval", required: false }] }], interactive: [{ type: i0.Input, args: [{ isSignal: true, alias: "interactive", required: false }] }], strokeWidth: [{ type: i0.Input, args: [{ isSignal: true, alias: "strokeWidth", required: false }] }], grid: [{ type: i0.Input, args: [{ isSignal: true, alias: "grid", required: false }] }], dots: [{ type: i0.Input, args: [{ isSignal: true, alias: "dots", required: false }] }], legend: [{ type: i0.Input, args: [{ isSignal: true, alias: "legend", required: false }] }], labels: [{ type: i0.Input, args: [{ isSignal: true, alias: "labels", required: false }] }], xTicks: [{ type: i0.Input, args: [{ isSignal: true, alias: "xTicks", required: false }] }], xFormat: [{ type: i0.Input, args: [{ isSignal: true, alias: "xFormat", required: false }] }], status: [{ type: i0.Input, args: [{ isSignal: true, alias: "status", required: false }] }], height: [{ type: i0.Input, args: [{ isSignal: true, alias: "height", required: false }] }], max: [{ type: i0.Input, args: [{ isSignal: true, alias: "max", required: false }] }], min: [{ type: i0.Input, args: [{ isSignal: true, alias: "min", required: false }] }], yAxis: [{ type: i0.Input, args: [{ isSignal: true, alias: "yAxis", required: false }] }], yTicks: [{ type: i0.Input, args: [{ isSignal: true, alias: "yTicks", required: false }] }], axisFormat: [{ type: i0.Input, args: [{ isSignal: true, alias: "axisFormat", required: false }] }], thresholds: [{ type: i0.Input, args: [{ isSignal: true, alias: "thresholds", required: false }] }], emptyText: [{ type: i0.Input, args: [{ isSignal: true, alias: "emptyText", required: false }] }], agoFormat: [{ type: i0.Input, args: [{ isSignal: true, alias: "agoFormat", required: false }] }], valueFormat: [{ type: i0.Input, args: [{ isSignal: true, alias: "valueFormat", required: false }] }], svgRef: [{ type: i0.ViewChild, args: ['svg', { isSignal: true }] }] } });
|
|
9988
|
+
}, styles: [".strct-chart{display:block;position:relative}.strct-chart__plot{position:relative}.strct-chart__svg{width:100%;display:block;touch-action:none}.strct-chart__svg:focus-visible{outline:2px solid var(--acc50);outline-offset:2px;border-radius:var(--radius-sm)}.strct-chart__sr{position:absolute;width:1px;height:1px;overflow:hidden;clip-path:inset(50%);white-space:nowrap}.strct-chart__empty{display:flex;align-items:center;justify-content:center;font-size:12px;color:var(--t3)}.strct-chart__grid{stroke:var(--b1);stroke-width:1;vector-effect:non-scaling-stroke}.strct-chart__line{vector-effect:non-scaling-stroke;stroke-linejoin:round;stroke-linecap:round}.strct-chart__area{stroke:none}.strct-chart__area--flat{opacity:.14}.strct-chart__dot,.strct-chart__hoverdot,.strct-chart__head-dot{stroke:var(--bg-1);stroke-width:1.5}.strct-chart__cross{stroke:var(--strct-chart-c);stroke-width:1;opacity:.4;stroke-dasharray:3 3;vector-effect:non-scaling-stroke}.strct-chart__threshold{stroke-width:1;opacity:.85;vector-effect:non-scaling-stroke}.strct-chart__threshold--dashed{stroke-dasharray:4 3}.strct-chart__bar{rx:1.5}.strct-chart__band{opacity:.13;stroke:none}.strct-chart__ann{stroke-width:1;opacity:.8;vector-effect:non-scaling-stroke}.strct-chart__ann--dashed{stroke-dasharray:4 3}.strct-chart__ann-label{position:absolute;top:0;transform:translate(-50%);pointer-events:none;font-size:12px;font-weight:600;background:var(--bg-1);padding:0 3px;border-radius:3px;white-space:nowrap}.strct-chart--brush .strct-chart__svg{cursor:crosshair}.strct-chart__brush{fill:var(--acc);opacity:.16;stroke:var(--acc50);stroke-width:1;vector-effect:non-scaling-stroke}.strct-chart__reset{position:absolute;top:6px;right:8px;z-index:3;display:inline-flex;align-items:center;gap:5px;padding:2px 9px;border:1px solid var(--b2);border-radius:99px;background:var(--bg-a);color:var(--t2);font-family:var(--font);font-size:12px;font-weight:600;cursor:pointer}.strct-chart__reset:hover{color:var(--t1);border-color:var(--acc50)}.strct-chart__reset:focus-visible{outline:2px solid var(--acc50);outline-offset:1px}.strct-chart__tip--gap{top:6px;transform:translate(-50%)}.strct-chart__tip-ann{font-size:12px;font-weight:600}.strct-chart--glow .strct-chart__line{filter:drop-shadow(0 0 1.5px var(--strct-chart-c)) drop-shadow(0 0 5px var(--strct-chart-c))}.strct-chart--glow .strct-chart__head-dot{filter:drop-shadow(0 0 2px var(--strct-chart-c)) drop-shadow(0 0 6px var(--strct-chart-c))}.strct-chart--glow .strct-chart__hoverdot{filter:drop-shadow(0 0 4px var(--strct-chart-c))}.strct-chart__ytick{position:absolute;left:0;width:34px;text-align:end;transform:translateY(-50%);pointer-events:none;font-family:var(--mono);font-size:12px;color:var(--t3);font-variant-numeric:tabular-nums}.strct-chart__thr{position:absolute;right:2px;transform:translateY(-50%);pointer-events:none;font-size:12px;font-weight:600;font-variant-numeric:tabular-nums;background:var(--bg-1);padding:0 3px;border-radius:3px}.strct-chart__axis-y{position:absolute;left:0;transform:translateY(-50%);pointer-events:none;padding:1px 5px;border-radius:var(--radius-sm);background:var(--bg-a);border:1px solid var(--b2);font-family:var(--mono);font-size:12px;font-weight:600;color:var(--t2);font-variant-numeric:tabular-nums;z-index:2}.strct-chart__label--active{color:var(--t1);font-weight:700}.strct-chart__legend{display:flex;flex-wrap:wrap;gap:6px 14px;margin-bottom:8px;font-size:12px;color:var(--t2)}.strct-chart__leg{display:inline-flex;align-items:center;gap:6px}.strct-chart__leg-sw{width:9px;height:3px;border-radius:2px;flex-shrink:0}.strct-chart__tip{position:absolute;transform:translate(-50%,calc(-100% - 10px));pointer-events:none;display:flex;flex-direction:column;align-items:center;gap:1px;padding:4px 8px;border-radius:var(--radius-sm);background:var(--bg-a);border:1px solid var(--b2);box-shadow:var(--shadow-elevated);white-space:nowrap;z-index:2}.strct-chart__tip--multi{top:6px;transform:translate(-50%);align-items:stretch;gap:3px}.strct-chart__tip-v{font-size:12px;font-weight:700;color:var(--t1);font-variant-numeric:tabular-nums}.strct-chart__tip-meta{display:inline-flex;align-items:center;gap:5px}.strct-chart__tip-delta{font-size:12px;font-weight:600;color:var(--t3);font-variant-numeric:tabular-nums}.strct-chart__tip-delta--up{color:var(--success)}.strct-chart__tip-delta--down{color:var(--critical)}.strct-chart__tip-l{font-size:12px;color:var(--t3)}.strct-chart__tip-row{display:inline-flex;align-items:center;gap:6px;font-size:12px}.strct-chart__tip-sw{width:8px;height:3px;border-radius:2px;flex-shrink:0}.strct-chart__tip-rl{color:var(--t3);margin-inline-end:auto}.strct-chart__tip-rv{color:var(--t1);font-weight:700;font-variant-numeric:tabular-nums}.strct-chart__labels{position:relative;height:15px;margin-top:6px;font-size:12px;color:var(--t3)}.strct-chart__labels span{position:absolute;transform:translate(-50%);white-space:nowrap}@media(prefers-reduced-motion:no-preference){.strct-chart__line--draw{stroke-dasharray:1;stroke-dashoffset:1;animation:strct-chart-draw .9s ease forwards}.strct-chart__pulse{transform-box:fill-box;transform-origin:center;animation:strct-chart-pulse 2.4s ease-out infinite}}@keyframes strct-chart-draw{to{stroke-dashoffset:0}}@keyframes strct-chart-pulse{0%{transform:scale(1);opacity:.45}70%{opacity:0}to{transform:scale(2.5);opacity:0}}\n"] }]
|
|
9989
|
+
}], ctorParameters: () => [], propDecorators: { data: [{ type: i0.Input, args: [{ isSignal: true, alias: "data", required: false }] }], series: [{ type: i0.Input, args: [{ isSignal: true, alias: "series", required: false }] }], type: [{ type: i0.Input, args: [{ isSignal: true, alias: "type", required: false }] }], curve: [{ type: i0.Input, args: [{ isSignal: true, alias: "curve", required: false }] }], area: [{ type: i0.Input, args: [{ isSignal: true, alias: "area", required: false }] }], glow: [{ type: i0.Input, args: [{ isSignal: true, alias: "glow", required: false }] }], live: [{ type: i0.Input, args: [{ isSignal: true, alias: "live", required: false }] }], interval: [{ type: i0.Input, args: [{ isSignal: true, alias: "interval", required: false }] }], interactive: [{ type: i0.Input, args: [{ isSignal: true, alias: "interactive", required: false }] }], strokeWidth: [{ type: i0.Input, args: [{ isSignal: true, alias: "strokeWidth", required: false }] }], grid: [{ type: i0.Input, args: [{ isSignal: true, alias: "grid", required: false }] }], dots: [{ type: i0.Input, args: [{ isSignal: true, alias: "dots", required: false }] }], legend: [{ type: i0.Input, args: [{ isSignal: true, alias: "legend", required: false }] }], labels: [{ type: i0.Input, args: [{ isSignal: true, alias: "labels", required: false }] }], xTicks: [{ type: i0.Input, args: [{ isSignal: true, alias: "xTicks", required: false }] }], xFormat: [{ type: i0.Input, args: [{ isSignal: true, alias: "xFormat", required: false }] }], status: [{ type: i0.Input, args: [{ isSignal: true, alias: "status", required: false }] }], height: [{ type: i0.Input, args: [{ isSignal: true, alias: "height", required: false }] }], max: [{ type: i0.Input, args: [{ isSignal: true, alias: "max", required: false }] }], min: [{ type: i0.Input, args: [{ isSignal: true, alias: "min", required: false }] }], yAxis: [{ type: i0.Input, args: [{ isSignal: true, alias: "yAxis", required: false }] }], yTicks: [{ type: i0.Input, args: [{ isSignal: true, alias: "yTicks", required: false }] }], axisFormat: [{ type: i0.Input, args: [{ isSignal: true, alias: "axisFormat", required: false }] }], thresholds: [{ type: i0.Input, args: [{ isSignal: true, alias: "thresholds", required: false }] }], emptyText: [{ type: i0.Input, args: [{ isSignal: true, alias: "emptyText", required: false }] }], agoFormat: [{ type: i0.Input, args: [{ isSignal: true, alias: "agoFormat", required: false }] }], valueFormat: [{ type: i0.Input, args: [{ isSignal: true, alias: "valueFormat", required: false }] }], annotations: [{ type: i0.Input, args: [{ isSignal: true, alias: "annotations", required: false }] }], activeIndex: [{ type: i0.Input, args: [{ isSignal: true, alias: "activeIndex", required: false }] }], brush: [{ type: i0.Input, args: [{ isSignal: true, alias: "brush", required: false }] }], zoom: [{ type: i0.Input, args: [{ isSignal: true, alias: "zoom", required: false }] }], gapText: [{ type: i0.Input, args: [{ isSignal: true, alias: "gapText", required: false }] }], resetLabel: [{ type: i0.Input, args: [{ isSignal: true, alias: "resetLabel", required: false }] }], hoverIndex: [{ type: i0.Output, args: ["hoverIndex"] }], brushChange: [{ type: i0.Output, args: ["brushChange"] }], svgRef: [{ type: i0.ViewChild, args: ['svg', { isSignal: true }] }] } });
|
|
9335
9990
|
|
|
9336
9991
|
const PALETTE = [
|
|
9337
9992
|
'var(--acc)',
|