@tetacom/svg-charts 1.7.37 → 1.7.39

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.
@@ -1,11 +1,11 @@
1
1
  import * as i0 from '@angular/core';
2
2
  import { Injectable, input, inject, ChangeDetectorRef, ElementRef, computed, Component, ViewChild, Input, ChangeDetectionStrategy, HostListener, HostBinding, Directive, signal, effect, EventEmitter, Output, ViewContainerRef } from '@angular/core';
3
- import { ReplaySubject, filter, BehaviorSubject, Subject, of, shareReplay, withLatestFrom, map, merge, lastValueFrom, take, combineLatest, tap, takeWhile, observeOn, animationFrameScheduler } from 'rxjs';
3
+ import { ReplaySubject, filter, BehaviorSubject, Subject, of, shareReplay, withLatestFrom, map, merge, lastValueFrom, take, combineLatest, takeWhile, tap, observeOn, animationFrameScheduler, distinctUntilChanged } from 'rxjs';
4
4
  import * as d3 from 'd3';
5
5
  import { zoomIdentity } from 'd3';
6
6
  import { maxIndex } from 'd3-array';
7
7
  import { toSignal } from '@angular/core/rxjs-interop';
8
- import * as i3 from '@angular/platform-browser';
8
+ import { DomSanitizer } from '@angular/platform-browser';
9
9
  import { NgTemplateOutlet, AsyncPipe, KeyValuePipe, NgStyle } from '@angular/common';
10
10
  import { DialogService, Align as Align$1, TetaSize, ButtonComponent, DropdownComponent, DropdownContentDirective, DropdownHeadDirective, IconComponent, AccordionComponent, AccordionHeadComponent, AccordionItemComponent, AccordionContentDirective, ColorInputComponent, SelectComponent, SelectOptionDirective, SelectValueDirective, ScrollableComponent, InputComponent } from '@tetacom/ng-components';
11
11
  import * as i1 from '@angular/forms';
@@ -193,8 +193,9 @@ class ChartService {
193
193
  this.plotBandEvent$ = new Subject();
194
194
  this.plotLineMove$ = new Subject();
195
195
  this.pointMove$ = new Subject();
196
- this.seriesOffsetMove$ = new Subject();
196
+ this.seriesMove$ = new Subject();
197
197
  this.seriesPathOffsets$ = new BehaviorSubject(new Map());
198
+ this.selectedSeriesIds$ = new BehaviorSubject([]);
198
199
  this.chartClick$ = new Subject();
199
200
  this.chartContextMenu$ = new Subject();
200
201
  this.annotationEvent$ = new Subject();
@@ -218,8 +219,9 @@ class ChartService {
218
219
  this.plotBandEvent = this.plotBandEvent$.asObservable();
219
220
  this.plotLineMove = this.plotLineMove$.asObservable();
220
221
  this.pointMove = this.pointMove$.asObservable();
221
- this.seriesOffsetMove = this.seriesOffsetMove$.asObservable();
222
+ this.seriesMove = this.seriesMove$.asObservable();
222
223
  this.seriesPathOffsets = this.seriesPathOffsets$.asObservable();
224
+ this.selectedSeriesIds = this.selectedSeriesIds$.asObservable();
223
225
  this.chartClick = this.chartClick$.asObservable();
224
226
  this.chartContextMenu = this.chartContextMenu$.asObservable();
225
227
  this.annotationClick = this.annotationEvent$.asObservable().pipe(filter((_) => _?.event?.type === 'click'));
@@ -235,6 +237,7 @@ class ChartService {
235
237
  }
236
238
  setConfig(config) {
237
239
  this.clearTooltips();
240
+ this.clearSeriesPathOffsets();
238
241
  this.config$.next(config);
239
242
  }
240
243
  setSize(size) {
@@ -297,8 +300,8 @@ class ChartService {
297
300
  emitPoint(event) {
298
301
  this.pointMove$.next(event);
299
302
  }
300
- emitSeriesOffset(event) {
301
- this.seriesOffsetMove$.next(event);
303
+ emitSeriesMove(event) {
304
+ this.seriesMove$.next(event);
302
305
  }
303
306
  getSeriesPathOffsets() {
304
307
  return this.seriesPathOffsets$.value;
@@ -306,6 +309,30 @@ class ChartService {
306
309
  setSeriesPathOffsets(offsets) {
307
310
  this.seriesPathOffsets$.next(new Map(offsets));
308
311
  }
312
+ clearSeriesPathOffsets() {
313
+ this.seriesPathOffsets$.next(new Map());
314
+ }
315
+ getSelectedSeriesIds() {
316
+ return this.selectedSeriesIds$.value;
317
+ }
318
+ setSelectedSeriesIds(seriesIds) {
319
+ const nextSeriesIds = [...(seriesIds ?? [])];
320
+ if (this.areSeriesIdsEqual(this.selectedSeriesIds$.value, nextSeriesIds)) {
321
+ return;
322
+ }
323
+ this.selectedSeriesIds$.next(nextSeriesIds);
324
+ }
325
+ toggleSelectedSeriesId(seriesId) {
326
+ const selectedIds = this.selectedSeriesIds$.value;
327
+ if (selectedIds.includes(seriesId)) {
328
+ this.setSelectedSeriesIds(selectedIds.filter((id) => id !== seriesId));
329
+ return;
330
+ }
331
+ this.setSelectedSeriesIds([...selectedIds, seriesId]);
332
+ }
333
+ areSeriesIdsEqual(first, second) {
334
+ return first.length === second.length && first.every((id, index) => id === second[index]);
335
+ }
309
336
  emitChartClick(event) {
310
337
  this.chartClick$.next(event);
311
338
  }
@@ -1169,29 +1196,24 @@ class PositionUtil {
1169
1196
  }
1170
1197
 
1171
1198
  class TooltipComponent {
1172
- constructor(svc, cdr, zoomService, sanitizer, _zone, _elementRef) {
1173
- this.svc = svc;
1174
- this.cdr = cdr;
1175
- this.zoomService = zoomService;
1176
- this.sanitizer = sanitizer;
1177
- this._zone = _zone;
1178
- this._elementRef = _elementRef;
1199
+ constructor() {
1200
+ this.svc = inject(ChartService);
1201
+ this.sanitizer = inject(DomSanitizer);
1202
+ this.pointerMove = toSignal(this.svc.pointerMove);
1203
+ this.display = computed(() => (this.pointerMove()?.type === 'mousemove' ? 1 : 0), ...(ngDevMode ? [{ debugName: "display" }] : /* istanbul ignore next */ []));
1204
+ this.position = computed(() => {
1205
+ const event = this.pointerMove();
1206
+ if (!this.display() || !event) {
1207
+ return null;
1208
+ }
1209
+ return this.getPosition(event);
1210
+ }, ...(ngDevMode ? [{ debugName: "position" }] : /* istanbul ignore next */ []));
1179
1211
  this.tooltips = this.svc.tooltips.pipe(map((_) => [..._.values()]));
1180
1212
  }
1181
1213
  getImplicit(t) {
1182
1214
  return { $implicit: t };
1183
1215
  }
1184
1216
  ngOnInit() {
1185
- this.display = this.svc.pointerMove.pipe(map((event) => {
1186
- return event.type === 'mousemove' ? 1 : 0;
1187
- }), tap(() => {
1188
- setTimeout(() => {
1189
- this.cdr.detectChanges();
1190
- });
1191
- }));
1192
- this.position = this.svc.pointerMove.pipe(filter((event) => !!event), map((_) => {
1193
- return this.getPosition(_);
1194
- }), tap(() => this.cdr.detectChanges()));
1195
1217
  const transformHtml = (html) => {
1196
1218
  return this.sanitizer.bypassSecurityTrustHtml(html);
1197
1219
  };
@@ -1216,8 +1238,7 @@ class TooltipComponent {
1216
1238
  if (tooltipList?.length < 1) {
1217
1239
  return '';
1218
1240
  }
1219
- const formatted = formatter ? transformHtml(formatter(tooltipList)) : defaultFormatter(tooltipList);
1220
- return formatted;
1241
+ return formatter ? transformHtml(formatter(tooltipList)) : defaultFormatter(tooltipList);
1221
1242
  }));
1222
1243
  }
1223
1244
  getPosition(event) {
@@ -1239,13 +1260,13 @@ class TooltipComponent {
1239
1260
  const format = d3.format(',.5~r');
1240
1261
  return format(input);
1241
1262
  }
1242
- static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.9", ngImport: i0, type: TooltipComponent, deps: [{ token: ChartService }, { token: i0.ChangeDetectorRef }, { token: ZoomService }, { token: i3.DomSanitizer }, { token: i0.NgZone }, { token: i0.ElementRef }], target: i0.ɵɵFactoryTarget.Component }); }
1243
- static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.9", type: TooltipComponent, isStandalone: true, selector: "teta-tooltip", inputs: { size: "size", config: "config" }, viewQueries: [{ propertyName: "tooltip", first: true, predicate: ["tooltip"], descendants: true, read: ElementRef }], ngImport: i0, template: "@if ({ p: position | async }; as data) {\n @if (tooltips | async; as t) {\n @if (t.length > 0) {\n <div\n class=\"chart-tooltip color-text-90 bg-global-bgcard shadow-2\"\n #tooltip\n [style.position]=\"'fixed'\"\n [style.opacity]=\"display | async\"\n [hidden]=\"!data.p\"\n style=\"pointer-events: none; min-width: 200px\"\n [style.left.px]=\"data.p?.left\"\n [style.top.px]=\"data.p?.top\"\n [style.bottom.px]=\"data.p?.bottom\"\n [style.right.px]=\"data.p?.right\"\n >\n @if (config.tooltip?.template) {\n <ng-container *ngTemplateOutlet=\"config.tooltip.template; context: getImplicit(t)\"></ng-container>\n }\n @if (config.tooltip?.format) {\n <div [innerHTML]=\"displayTooltips | async\"></div>\n } @else {\n @if (!config.tooltip?.template) {\n <div class=\"padding-2 border-radius-1\">\n @for (tooltip of t; track $index) {\n <div class=\"display-flex align-center\">\n <span\n class=\"display-block margin-right-1\"\n [style.width.px]=\"10\"\n [style.height.px]=\"2\"\n [style.background-color]=\"tooltip.series?.color\"\n >\n </span>\n <span class=\"font-title-3\">\n {{ tooltip.series?.name }}\n <span class=\"font-body-3\">\n x: {{ format(tooltip.point?.x) }} y: {{ format(tooltip.point?.y) }}\n </span>\n </span>\n </div>\n }\n </div>\n }\n }\n </div>\n }\n }\n}\n", styles: [":host{position:absolute;z-index:2}\n"], dependencies: [{ kind: "directive", type: NgTemplateOutlet, selector: "[ngTemplateOutlet]", inputs: ["ngTemplateOutletContext", "ngTemplateOutlet", "ngTemplateOutletInjector"] }, { kind: "pipe", type: AsyncPipe, name: "async" }], changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
1263
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.9", ngImport: i0, type: TooltipComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
1264
+ static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.9", type: TooltipComponent, isStandalone: true, selector: "teta-tooltip", inputs: { size: "size", config: "config" }, viewQueries: [{ propertyName: "tooltip", first: true, predicate: ["tooltip"], descendants: true, read: ElementRef }], ngImport: i0, template: "@if ({ p: position() }; as data) {\n @if (tooltips | async; as t) {\n @if (t.length > 0) {\n <div\n class=\"chart-tooltip color-text-90 bg-global-bgcard shadow-2\"\n #tooltip\n [style.position]=\"'fixed'\"\n [style.opacity]=\"display()\"\n [hidden]=\"!data.p\"\n style=\"pointer-events: none; min-width: 200px\"\n [style.left.px]=\"data.p?.left\"\n [style.top.px]=\"data.p?.top\"\n [style.bottom.px]=\"data.p?.bottom\"\n [style.right.px]=\"data.p?.right\"\n >\n @if (config.tooltip?.template) {\n <ng-container *ngTemplateOutlet=\"config.tooltip.template; context: getImplicit(t)\"></ng-container>\n }\n @if (config.tooltip?.format) {\n <div [innerHTML]=\"displayTooltips | async\"></div>\n } @else {\n @if (!config.tooltip?.template) {\n <div class=\"padding-2 border-radius-1\">\n @for (tooltip of t; track $index) {\n <div class=\"display-flex align-center\">\n <span\n class=\"display-block margin-right-1\"\n [style.width.px]=\"10\"\n [style.height.px]=\"2\"\n [style.background-color]=\"tooltip.series?.color\"\n >\n </span>\n <span class=\"font-title-3\">\n {{ tooltip.series?.name }}\n <span class=\"font-body-3\">\n x: {{ format(tooltip.point?.x) }} y: {{ format(tooltip.point?.y) }}\n </span>\n </span>\n </div>\n }\n </div>\n }\n }\n </div>\n }\n }\n}\n", styles: [":host{position:absolute;z-index:2}\n"], dependencies: [{ kind: "directive", type: NgTemplateOutlet, selector: "[ngTemplateOutlet]", inputs: ["ngTemplateOutletContext", "ngTemplateOutlet", "ngTemplateOutletInjector"] }, { kind: "pipe", type: AsyncPipe, name: "async" }], changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
1244
1265
  }
1245
1266
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.9", ngImport: i0, type: TooltipComponent, decorators: [{
1246
1267
  type: Component,
1247
- args: [{ selector: 'teta-tooltip', changeDetection: ChangeDetectionStrategy.OnPush, imports: [AsyncPipe, NgTemplateOutlet], template: "@if ({ p: position | async }; as data) {\n @if (tooltips | async; as t) {\n @if (t.length > 0) {\n <div\n class=\"chart-tooltip color-text-90 bg-global-bgcard shadow-2\"\n #tooltip\n [style.position]=\"'fixed'\"\n [style.opacity]=\"display | async\"\n [hidden]=\"!data.p\"\n style=\"pointer-events: none; min-width: 200px\"\n [style.left.px]=\"data.p?.left\"\n [style.top.px]=\"data.p?.top\"\n [style.bottom.px]=\"data.p?.bottom\"\n [style.right.px]=\"data.p?.right\"\n >\n @if (config.tooltip?.template) {\n <ng-container *ngTemplateOutlet=\"config.tooltip.template; context: getImplicit(t)\"></ng-container>\n }\n @if (config.tooltip?.format) {\n <div [innerHTML]=\"displayTooltips | async\"></div>\n } @else {\n @if (!config.tooltip?.template) {\n <div class=\"padding-2 border-radius-1\">\n @for (tooltip of t; track $index) {\n <div class=\"display-flex align-center\">\n <span\n class=\"display-block margin-right-1\"\n [style.width.px]=\"10\"\n [style.height.px]=\"2\"\n [style.background-color]=\"tooltip.series?.color\"\n >\n </span>\n <span class=\"font-title-3\">\n {{ tooltip.series?.name }}\n <span class=\"font-body-3\">\n x: {{ format(tooltip.point?.x) }} y: {{ format(tooltip.point?.y) }}\n </span>\n </span>\n </div>\n }\n </div>\n }\n }\n </div>\n }\n }\n}\n", styles: [":host{position:absolute;z-index:2}\n"] }]
1248
- }], ctorParameters: () => [{ type: ChartService }, { type: i0.ChangeDetectorRef }, { type: ZoomService }, { type: i3.DomSanitizer }, { type: i0.NgZone }, { type: i0.ElementRef }], propDecorators: { size: [{
1268
+ args: [{ selector: 'teta-tooltip', changeDetection: ChangeDetectionStrategy.OnPush, imports: [AsyncPipe, NgTemplateOutlet], template: "@if ({ p: position() }; as data) {\n @if (tooltips | async; as t) {\n @if (t.length > 0) {\n <div\n class=\"chart-tooltip color-text-90 bg-global-bgcard shadow-2\"\n #tooltip\n [style.position]=\"'fixed'\"\n [style.opacity]=\"display()\"\n [hidden]=\"!data.p\"\n style=\"pointer-events: none; min-width: 200px\"\n [style.left.px]=\"data.p?.left\"\n [style.top.px]=\"data.p?.top\"\n [style.bottom.px]=\"data.p?.bottom\"\n [style.right.px]=\"data.p?.right\"\n >\n @if (config.tooltip?.template) {\n <ng-container *ngTemplateOutlet=\"config.tooltip.template; context: getImplicit(t)\"></ng-container>\n }\n @if (config.tooltip?.format) {\n <div [innerHTML]=\"displayTooltips | async\"></div>\n } @else {\n @if (!config.tooltip?.template) {\n <div class=\"padding-2 border-radius-1\">\n @for (tooltip of t; track $index) {\n <div class=\"display-flex align-center\">\n <span\n class=\"display-block margin-right-1\"\n [style.width.px]=\"10\"\n [style.height.px]=\"2\"\n [style.background-color]=\"tooltip.series?.color\"\n >\n </span>\n <span class=\"font-title-3\">\n {{ tooltip.series?.name }}\n <span class=\"font-body-3\">\n x: {{ format(tooltip.point?.x) }} y: {{ format(tooltip.point?.y) }}\n </span>\n </span>\n </div>\n }\n </div>\n }\n }\n </div>\n }\n }\n}\n", styles: [":host{position:absolute;z-index:2}\n"] }]
1269
+ }], ctorParameters: () => [], propDecorators: { size: [{
1249
1270
  type: Input
1250
1271
  }], config: [{
1251
1272
  type: Input
@@ -1767,9 +1788,17 @@ class LinearSeriesBaseComponent extends SeriesBaseComponent {
1767
1788
  this.markers = computed(() => {
1768
1789
  return this.series().data?.filter((_) => _?.marker && _?.x !== undefined && _?.y !== undefined && _?.x !== null && _?.y !== null);
1769
1790
  }, ...(ngDevMode ? [{ debugName: "markers" }] : /* istanbul ignore next */ []));
1791
+ this.sortedTooltipData = computed(() => {
1792
+ this.update();
1793
+ const data = [...this.series().data];
1794
+ const tooltipTracking = this.config()?.tooltip?.tracking;
1795
+ return data.sort(tooltipTracking === TooltipTracking.y ? (a, b) => a.y - b.y : (a, b) => a.x - b.x);
1796
+ }, ...(ngDevMode ? [{ debugName: "sortedTooltipData" }] : /* istanbul ignore next */ []));
1770
1797
  this.path = computed(() => {
1771
1798
  this.update();
1772
- if (!this.x() || !this.y()) {
1799
+ const x = this.x();
1800
+ const y = this.y();
1801
+ if (!x || !y) {
1773
1802
  return '';
1774
1803
  }
1775
1804
  const filter = this.defaultClipPointsMapping.get(this.series().clipPointsDirection);
@@ -1781,18 +1810,18 @@ class LinearSeriesBaseComponent extends SeriesBaseComponent {
1781
1810
  point.y !== undefined &&
1782
1811
  !isNaN(point.x) &&
1783
1812
  !isNaN(point.y))
1784
- .x((point) => this.x()(point.x))
1785
- .y((point) => this.y()(point.y));
1813
+ .x((point) => x(point.x))
1814
+ .y((point) => y(point.y));
1786
1815
  let filteredData = this.series().data;
1787
1816
  const clipOffset = this.getClipOffset();
1788
1817
  if (this.series().clipPointsDirection === ClipPointsDirection.x) {
1789
- let [min, max] = this.x().domain();
1818
+ let [min, max] = x.domain();
1790
1819
  min = min instanceof Date ? min.getTime() : min;
1791
1820
  max = max instanceof Date ? max.getTime() : max;
1792
1821
  filteredData = filteredData?.filter(filter(min - clipOffset.x, max - clipOffset.x));
1793
1822
  }
1794
1823
  if (this.series().clipPointsDirection === ClipPointsDirection.y) {
1795
- let [min, max] = this.y().domain();
1824
+ let [min, max] = y.domain();
1796
1825
  min = min instanceof Date ? min.getTime() : min;
1797
1826
  max = max instanceof Date ? max.getTime() : max;
1798
1827
  filteredData = filteredData?.filter(filter(min - clipOffset.y, max - clipOffset.y));
@@ -1842,6 +1871,13 @@ class LinearSeriesBaseComponent extends SeriesBaseComponent {
1842
1871
  }
1843
1872
  const mouse = [event?.offsetX, event?.offsetY];
1844
1873
  const tooltipTracking = this.config()?.tooltip?.tracking;
1874
+ const clipOffset = this.getClipOffset();
1875
+ const addOffset = (value, offset) => {
1876
+ return value instanceof Date ? new Date(value.getTime() + offset) : value + offset;
1877
+ };
1878
+ const subtractOffset = (value, offset) => {
1879
+ return value instanceof Date ? value.getTime() - offset : value - offset;
1880
+ };
1845
1881
  const lineIntersection = (p0_x, p0_y, p1_x, p1_y, p2_x, p2_y, p3_x, p3_y) => {
1846
1882
  const rV = {};
1847
1883
  const s1_x = p1_x - p0_x;
@@ -1857,16 +1893,17 @@ class LinearSeriesBaseComponent extends SeriesBaseComponent {
1857
1893
  return rV;
1858
1894
  };
1859
1895
  if (tooltipTracking === TooltipTracking.x) {
1860
- const sortedData = [...this.series().data].sort((a, b) => a.x - b.x);
1896
+ const sortedData = this.sortedTooltipData();
1861
1897
  const bisect = d3.bisector((_) => _.x).right;
1862
1898
  const pointer = mouse[0];
1863
1899
  let x0 = scaleX.invert(pointer);
1864
1900
  if (x0 instanceof Date) {
1865
1901
  x0 = x0.getTime();
1866
1902
  }
1867
- const rightId = bisect([...this.series().data].sort((a, b) => a.x - b.x), x0);
1903
+ x0 = subtractOffset(x0, clipOffset.x);
1904
+ const rightId = bisect(sortedData, x0);
1868
1905
  const range = scaleY.range();
1869
- const intersect = lineIntersection(pointer, range[0], pointer, Number.MAX_SAFE_INTEGER, scaleX(sortedData[rightId - 1]?.x), scaleY(sortedData[rightId - 1]?.y), scaleX(sortedData[rightId]?.x), scaleY(sortedData[rightId]?.y));
1906
+ const intersect = lineIntersection(pointer, range[0], pointer, Number.MAX_SAFE_INTEGER, scaleX(addOffset(sortedData[rightId - 1]?.x, clipOffset.x)), scaleY(addOffset(sortedData[rightId - 1]?.y, clipOffset.y)), scaleX(addOffset(sortedData[rightId]?.x, clipOffset.x)), scaleY(addOffset(sortedData[rightId]?.y, clipOffset.y)));
1870
1907
  const x = scaleX.invert(intersect.x);
1871
1908
  const y = scaleY.invert(intersect.y);
1872
1909
  if (x !== null && x !== undefined && !isNaN(x) && y !== null && y !== undefined && !isNaN(y)) {
@@ -1890,15 +1927,16 @@ class LinearSeriesBaseComponent extends SeriesBaseComponent {
1890
1927
  };
1891
1928
  }
1892
1929
  if (tooltipTracking === TooltipTracking.y) {
1893
- const sortedData = [...this.series().data].sort((a, b) => a.y - b.y);
1930
+ const sortedData = this.sortedTooltipData();
1894
1931
  const bisect = d3.bisector((_) => _.y).right;
1895
1932
  let y0 = scaleY.invert(mouse[1]);
1896
1933
  if (y0 instanceof Date) {
1897
1934
  y0 = y0.getTime();
1898
1935
  }
1936
+ y0 = subtractOffset(y0, clipOffset.y);
1899
1937
  const rightId = bisect(sortedData, y0);
1900
1938
  const range = scaleX.range();
1901
- const intersect = lineIntersection(range[0], mouse[1], Number.MAX_SAFE_INTEGER, mouse[1], scaleX(sortedData[rightId - 1]?.x), scaleY(sortedData[rightId - 1]?.y), scaleX(sortedData[rightId]?.x), scaleY(sortedData[rightId]?.y));
1939
+ const intersect = lineIntersection(range[0], mouse[1], Number.MAX_SAFE_INTEGER, mouse[1], scaleX(addOffset(sortedData[rightId - 1]?.x, clipOffset.x)), scaleY(addOffset(sortedData[rightId - 1]?.y, clipOffset.y)), scaleX(addOffset(sortedData[rightId]?.x, clipOffset.x)), scaleY(addOffset(sortedData[rightId]?.y, clipOffset.y)));
1902
1940
  const x = scaleX.invert(intersect.x);
1903
1941
  const y = scaleY.invert(intersect.y);
1904
1942
  if (x !== null && x !== undefined && !isNaN(x) && y !== null && y !== undefined && !isNaN(y)) {
@@ -2191,12 +2229,16 @@ class LineSeriesComponent extends LinearSeriesBaseComponent {
2191
2229
  constructor() {
2192
2230
  super(...arguments);
2193
2231
  this.seriesPathOffsets = toSignal(this.svc.seriesPathOffsets, { initialValue: new Map() });
2232
+ this.selectedSeriesIds = toSignal(this.svc.selectedSeriesIds, { initialValue: [] });
2194
2233
  this.seriesDragStartOffsets = new Map();
2195
2234
  this.seriesDragGroup = [];
2196
2235
  this.seriesDragMoved = false;
2197
2236
  this.seriesOffsetValue = computed(() => {
2198
2237
  return this.seriesPathOffsets().get(this.series().id) ?? { x: 0, y: 0 };
2199
2238
  }, ...(ngDevMode ? [{ debugName: "seriesOffsetValue" }] : /* istanbul ignore next */ []));
2239
+ this.seriesSelectedForPathDrag = computed(() => {
2240
+ return this.isSeriesSelectedForPathDrag(this.series());
2241
+ }, ...(ngDevMode ? [{ debugName: "seriesSelectedForPathDrag" }] : /* istanbul ignore next */ []));
2200
2242
  this.seriesPathTransform = computed(() => {
2201
2243
  const offset = this.seriesOffsetValue();
2202
2244
  const offsetX = this.getOffsetPixels(this.x(), offset.x);
@@ -2238,16 +2280,16 @@ class LineSeriesComponent extends LinearSeriesBaseComponent {
2238
2280
  this.seriesDragStartOffsets = new Map(this.seriesDragGroup.map((series) => {
2239
2281
  return [series.id, this.svc.getSeriesPathOffsets().get(series.id) ?? { x: 0, y: 0 }];
2240
2282
  }));
2241
- this.emitSeriesOffset('start', event);
2283
+ this.emitSeriesMove('start', event);
2242
2284
  }
2243
2285
  seriesMoveProcess(event) {
2244
2286
  this.seriesDragMoved = this.seriesDragMoved || Math.abs(event.deltaX) > 3 || Math.abs(event.deltaY) > 3;
2245
2287
  this.updateSeriesOffset(event);
2246
- this.emitSeriesOffset('drag', event);
2288
+ this.emitSeriesMove('drag', event);
2247
2289
  }
2248
2290
  seriesMoveEnd(event) {
2249
2291
  this.updateSeriesOffset(event);
2250
- this.emitSeriesOffset('end', event);
2292
+ this.emitSeriesMove('end', event);
2251
2293
  }
2252
2294
  seriesPathClick(event) {
2253
2295
  if (this.seriesDragMoved) {
@@ -2264,8 +2306,7 @@ class LineSeriesComponent extends LinearSeriesBaseComponent {
2264
2306
  }
2265
2307
  event.stopPropagation();
2266
2308
  event.preventDefault();
2267
- this.series().selectedForPathDrag = !this.series().selectedForPathDrag;
2268
- this.cdr.markForCheck();
2309
+ this.svc.toggleSelectedSeriesId(this.series().id);
2269
2310
  }
2270
2311
  moveStart(event, point) {
2271
2312
  this.start = { x: point.x, y: point.y };
@@ -2309,10 +2350,10 @@ class LineSeriesComponent extends LinearSeriesBaseComponent {
2309
2350
  label.dx = this.labelStart.dx + event.deltaX;
2310
2351
  label.dy = this.labelStart.dy + event.deltaY;
2311
2352
  }
2312
- emitSeriesOffset(type, event) {
2353
+ emitSeriesMove(type, event) {
2313
2354
  const offsetValue = this.seriesOffsetValue();
2314
2355
  const seriesList = this.seriesDragGroup.length ? this.seriesDragGroup : [this.series()];
2315
- this.svc.emitSeriesOffset({
2356
+ this.svc.emitSeriesMove({
2316
2357
  event: {
2317
2358
  type,
2318
2359
  sourceEvent: event,
@@ -2375,19 +2416,24 @@ class LineSeriesComponent extends LinearSeriesBaseComponent {
2375
2416
  }
2376
2417
  getPathDragSeriesGroup() {
2377
2418
  const currentSeries = this.series();
2378
- if (!currentSeries.selectedForPathDrag) {
2419
+ if (!this.isSeriesSelectedForPathDrag(currentSeries)) {
2379
2420
  return [currentSeries];
2380
2421
  }
2422
+ const selectedIds = this.svc.getSelectedSeriesIds();
2381
2423
  const selectedSeries = this.config()?.series?.filter((series) => {
2382
- return (series.selectedForPathDrag &&
2424
+ return (selectedIds.includes(series.id) &&
2383
2425
  series.draggablePath &&
2384
2426
  series.visible !== false &&
2385
2427
  series.enabled !== false &&
2386
- series.xAxisIndex === currentSeries.xAxisIndex &&
2387
- series.yAxisIndex === currentSeries.yAxisIndex);
2428
+ series.pathDragType === currentSeries.pathDragType &&
2429
+ ((currentSeries.pathDragType === DragPointType.x && series.xAxisIndex === currentSeries.xAxisIndex) ||
2430
+ (currentSeries.pathDragType === DragPointType.y && series.yAxisIndex === currentSeries.yAxisIndex)));
2388
2431
  });
2389
2432
  return selectedSeries?.length ? selectedSeries : [currentSeries];
2390
2433
  }
2434
+ isSeriesSelectedForPathDrag(series) {
2435
+ return this.selectedSeriesIds().includes(series.id);
2436
+ }
2391
2437
  getOffsetPixels(scale, offsetValue) {
2392
2438
  if (!scale || !scale?.domain || offsetValue === null || offsetValue === undefined) {
2393
2439
  return 0;
@@ -2398,24 +2444,27 @@ class LineSeriesComponent extends LinearSeriesBaseComponent {
2398
2444
  return scale(nextValue) - scale(domainStart);
2399
2445
  }
2400
2446
  static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.9", ngImport: i0, type: LineSeriesComponent, deps: null, target: i0.ɵɵFactoryTarget.Component }); }
2401
- static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.9", type: LineSeriesComponent, isStandalone: true, selector: "svg:svg[teta-line-series]", usesInheritance: true, ngImport: i0, template: "@if (series(); as series) {\n <svg:g\n [tetaDraggableSeries]=\"series.draggablePath\"\n [dragDirection]=\"series.pathDragType\"\n [attr.transform]=\"seriesPathTransform()\"\n [class.draggable-path]=\"series.draggablePath\"\n [class.selected-path]=\"series.selectedForPathDrag\"\n (click)=\"seriesPathClick($event)\"\n (moveStart)=\"seriesMoveStart($event)\"\n (moveProcess)=\"seriesMoveProcess($event)\"\n (moveEnd)=\"seriesMoveEnd($event)\"\n >\n <svg:path\n class=\"line\"\n [class.line-selected]=\"series.selectedForPathDrag\"\n [attr.d]=\"path()\"\n [attr.stroke]=\"series.color\"\n [attr.stroke-dasharray]=\"series.style?.strokeDasharray\"\n [attr.stroke-width]=\"series.style?.strokeWidth\"\n [style.--series-color]=\"series.color\"\n fill=\"none\"\n ></svg:path>\n @if (series.draggablePath) {\n <svg:path\n class=\"line-hitbox\"\n [attr.d]=\"path()\"\n fill=\"none\"\n stroke=\"transparent\"\n stroke-width=\"14\"\n pointer-events=\"stroke\"\n ></svg:path>\n }\n </svg:g>\n @if (transform(); as t) {\n @if (t?.x !== null && t?.x !== undefined && t?.y !== null && t?.y !== undefined) {\n <svg:circle\n r=\"3\"\n [attr.fill]=\"series.color\"\n [attr.transform]=\"'translate(' + t.x + ', ' + t.y + ')'\"\n ></svg:circle>\n }\n }\n @if (markers(); as draggablePoints) {\n @if (x() && y()) {\n @for (point of draggablePoints; track point) {\n <svg:g [attr.transform]=\"'translate(' + x()(point.x) + ',' + y()(point.y) + ')'\">\n <svg:g\n [tetaDraggablePoint]=\"point.marker.draggable\"\n [dragDirection]=\"point.marker.dragType\"\n [allowDrag]=\"allowDrag(point)\"\n #dragPoint=\"tetaDraggablePoint\"\n (moveStart)=\"moveStart($event, point)\"\n (moveEnd)=\"moveEnd($event, point); dragPoint.resetTransform()\"\n (moveProcess)=\"moveProcess($event, point); dragPoint.resetTransform()\"\n [class.draggable-marker]=\"point?.marker?.draggable\"\n >\n <svg:circle\n class=\"marker\"\n [attr.r]=\"point.marker.style?.radius ?? 5\"\n [attr.fill]=\"point.marker.style?.fill ?? 'transparent'\"\n [attr.stroke]=\"point.marker.style?.stroke ?? 'none'\"\n [attr.stroke-width]=\"point.marker.style?.strokeWidth\"\n [attr.stroke-dasharray]=\"point.marker.style?.strokeDasharray\"\n [attr.cx]=\"0\"\n [attr.cy]=\"0\"\n ></svg:circle>\n @if (point.marker.label?.text) {\n <svg:line\n [attr.x1]=\"0\"\n [attr.y1]=\"0\"\n [attr.x2]=\"point.marker.label?.dx\"\n [attr.y2]=\"point.marker.label?.dy\"\n [attr.stroke]=\"point.marker.label?.style?.stroke ?? 'var(--color-text-90)'\"\n [attr.stroke-width]=\"point.marker.label?.style?.strokeWidth ?? 1\"\n [attr.stroke-dasharray]=\"point.marker.label?.style?.strokeDasharray ?? null\"\n ></svg:line>\n <svg:foreignObject\n [tetaDraggablePoint]=\"point.marker.label?.draggable\"\n [dragDirection]=\"point.marker.label.dragType\"\n #labelPoint=\"tetaDraggablePoint\"\n (moveStart)=\"startLabel($event, point.marker.label)\"\n (moveProcess)=\"moveLabel($event, point.marker.label); labelPoint.resetTransform()\"\n (moveEnd)=\"labelPoint.resetTransform()\"\n [attr.width]=\"annotationNode?.offsetWidth ?? 0\"\n [attr.height]=\"annotationNode?.offsetHeight ?? 0\"\n [attr.x]=\"point.marker.label?.dx\"\n [attr.y]=\"point.marker.label?.dy\"\n class=\"position-absolute\"\n >\n <div\n #annotationNode\n class=\"shadow-2 padding-2\"\n [style.color]=\"'var(--color-text-90)'\"\n [style.background-color]=\"'var(--color-global-bgcard)'\"\n [style.cursor]=\"'move'\"\n style=\"border-radius: 2px; display: inline-block\"\n >\n {{ point.marker.label?.text }}\n </div>\n </svg:foreignObject>\n }\n </svg:g>\n </svg:g>\n }\n }\n }\n}\n", styles: [".draggable-marker{cursor:move}.draggable-path,.selected-path,.selected-path:active{cursor:ew-resize}.line-selected{filter:drop-shadow(0 0 3px var(--series-color))}.active{stroke-opacity:.5}.marker-grab{opacity:0}\n"], dependencies: [{ kind: "directive", type: DraggablePointDirective, selector: "[tetaDraggablePoint]", inputs: ["tetaDraggablePoint", "dragDirection", "allowDrag"], outputs: ["moveStart", "moveProcess", "moveEnd"], exportAs: ["tetaDraggablePoint"] }, { kind: "directive", type: DraggableSeriesDirective, selector: "[tetaDraggableSeries]", inputs: ["tetaDraggableSeries", "dragDirection"], outputs: ["moveStart", "moveProcess", "moveEnd"], exportAs: ["tetaDraggableSeries"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
2447
+ static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.9", type: LineSeriesComponent, isStandalone: true, selector: "svg:svg[teta-line-series]", usesInheritance: true, ngImport: i0, template: "@if (series(); as series) {\n <svg:g\n [tetaDraggableSeries]=\"series.draggablePath\"\n [dragDirection]=\"series.pathDragType\"\n [attr.transform]=\"seriesPathTransform()\"\n [class.draggable-path]=\"series.draggablePath\"\n [class.selected-path]=\"seriesSelectedForPathDrag()\"\n (click)=\"seriesPathClick($event)\"\n (moveStart)=\"seriesMoveStart($event)\"\n (moveProcess)=\"seriesMoveProcess($event)\"\n (moveEnd)=\"seriesMoveEnd($event)\"\n >\n <svg:path\n class=\"line\"\n [class.line-selected]=\"seriesSelectedForPathDrag()\"\n [attr.d]=\"path()\"\n [attr.stroke]=\"series.color\"\n [attr.stroke-dasharray]=\"series.style?.strokeDasharray\"\n [attr.stroke-width]=\"series.style?.strokeWidth\"\n [style.--series-color]=\"series.color\"\n fill=\"none\"\n ></svg:path>\n @if (series.draggablePath) {\n <svg:path\n class=\"line-hitbox\"\n [attr.d]=\"path()\"\n fill=\"none\"\n stroke=\"transparent\"\n stroke-width=\"14\"\n pointer-events=\"stroke\"\n ></svg:path>\n }\n </svg:g>\n @if (transform(); as t) {\n @if (t?.x !== null && t?.x !== undefined && t?.y !== null && t?.y !== undefined) {\n <svg:circle\n r=\"3\"\n [attr.fill]=\"series.color\"\n [attr.transform]=\"'translate(' + t.x + ', ' + t.y + ')'\"\n ></svg:circle>\n }\n }\n @if (markers(); as draggablePoints) {\n @if ({ x: x(), y: y() }; as scales) {\n @if (scales.x && scales.y) {\n @for (point of draggablePoints; track point) {\n <svg:g [attr.transform]=\"'translate(' + scales.x(point.x) + ',' + scales.y(point.y) + ')'\">\n <svg:g\n [tetaDraggablePoint]=\"point.marker.draggable\"\n [dragDirection]=\"point.marker.dragType\"\n [allowDrag]=\"allowDrag(point)\"\n #dragPoint=\"tetaDraggablePoint\"\n (moveStart)=\"moveStart($event, point)\"\n (moveEnd)=\"moveEnd($event, point); dragPoint.resetTransform()\"\n (moveProcess)=\"moveProcess($event, point); dragPoint.resetTransform()\"\n [class.draggable-marker]=\"point?.marker?.draggable\"\n >\n <svg:circle\n class=\"marker\"\n [attr.r]=\"point.marker.style?.radius ?? 5\"\n [attr.fill]=\"point.marker.style?.fill ?? 'transparent'\"\n [attr.stroke]=\"point.marker.style?.stroke ?? 'none'\"\n [attr.stroke-width]=\"point.marker.style?.strokeWidth\"\n [attr.stroke-dasharray]=\"point.marker.style?.strokeDasharray\"\n [attr.cx]=\"0\"\n [attr.cy]=\"0\"\n ></svg:circle>\n @if (point.marker.label?.text) {\n <svg:line\n [attr.x1]=\"0\"\n [attr.y1]=\"0\"\n [attr.x2]=\"point.marker.label?.dx\"\n [attr.y2]=\"point.marker.label?.dy\"\n [attr.stroke]=\"point.marker.label?.style?.stroke ?? 'var(--color-text-90)'\"\n [attr.stroke-width]=\"point.marker.label?.style?.strokeWidth ?? 1\"\n [attr.stroke-dasharray]=\"point.marker.label?.style?.strokeDasharray ?? null\"\n ></svg:line>\n <svg:foreignObject\n [tetaDraggablePoint]=\"point.marker.label?.draggable\"\n [dragDirection]=\"point.marker.label.dragType\"\n #labelPoint=\"tetaDraggablePoint\"\n (moveStart)=\"startLabel($event, point.marker.label)\"\n (moveProcess)=\"moveLabel($event, point.marker.label); labelPoint.resetTransform()\"\n (moveEnd)=\"labelPoint.resetTransform()\"\n [attr.width]=\"annotationNode?.offsetWidth ?? 0\"\n [attr.height]=\"annotationNode?.offsetHeight ?? 0\"\n [attr.x]=\"point.marker.label?.dx\"\n [attr.y]=\"point.marker.label?.dy\"\n class=\"position-absolute\"\n >\n <div\n #annotationNode\n class=\"shadow-2 padding-2\"\n [style.color]=\"'var(--color-text-90)'\"\n [style.background-color]=\"'var(--color-global-bgcard)'\"\n [style.cursor]=\"'move'\"\n style=\"border-radius: 2px; display: inline-block\"\n >\n {{ point.marker.label?.text }}\n </div>\n </svg:foreignObject>\n }\n </svg:g>\n </svg:g>\n }\n }\n }\n }\n}\n", styles: [".draggable-marker{cursor:move}.draggable-path,.selected-path,.selected-path:active{cursor:ew-resize}.line-selected{filter:drop-shadow(0 0 3px var(--series-color))}.active{stroke-opacity:.5}.marker-grab{opacity:0}\n"], dependencies: [{ kind: "directive", type: DraggablePointDirective, selector: "[tetaDraggablePoint]", inputs: ["tetaDraggablePoint", "dragDirection", "allowDrag"], outputs: ["moveStart", "moveProcess", "moveEnd"], exportAs: ["tetaDraggablePoint"] }, { kind: "directive", type: DraggableSeriesDirective, selector: "[tetaDraggableSeries]", inputs: ["tetaDraggableSeries", "dragDirection"], outputs: ["moveStart", "moveProcess", "moveEnd"], exportAs: ["tetaDraggableSeries"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
2402
2448
  }
2403
2449
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.9", ngImport: i0, type: LineSeriesComponent, decorators: [{
2404
2450
  type: Component,
2405
- args: [{ selector: 'svg:svg[teta-line-series]', changeDetection: ChangeDetectionStrategy.OnPush, imports: [AsyncPipe, DraggablePointDirective, DraggableSeriesDirective], template: "@if (series(); as series) {\n <svg:g\n [tetaDraggableSeries]=\"series.draggablePath\"\n [dragDirection]=\"series.pathDragType\"\n [attr.transform]=\"seriesPathTransform()\"\n [class.draggable-path]=\"series.draggablePath\"\n [class.selected-path]=\"series.selectedForPathDrag\"\n (click)=\"seriesPathClick($event)\"\n (moveStart)=\"seriesMoveStart($event)\"\n (moveProcess)=\"seriesMoveProcess($event)\"\n (moveEnd)=\"seriesMoveEnd($event)\"\n >\n <svg:path\n class=\"line\"\n [class.line-selected]=\"series.selectedForPathDrag\"\n [attr.d]=\"path()\"\n [attr.stroke]=\"series.color\"\n [attr.stroke-dasharray]=\"series.style?.strokeDasharray\"\n [attr.stroke-width]=\"series.style?.strokeWidth\"\n [style.--series-color]=\"series.color\"\n fill=\"none\"\n ></svg:path>\n @if (series.draggablePath) {\n <svg:path\n class=\"line-hitbox\"\n [attr.d]=\"path()\"\n fill=\"none\"\n stroke=\"transparent\"\n stroke-width=\"14\"\n pointer-events=\"stroke\"\n ></svg:path>\n }\n </svg:g>\n @if (transform(); as t) {\n @if (t?.x !== null && t?.x !== undefined && t?.y !== null && t?.y !== undefined) {\n <svg:circle\n r=\"3\"\n [attr.fill]=\"series.color\"\n [attr.transform]=\"'translate(' + t.x + ', ' + t.y + ')'\"\n ></svg:circle>\n }\n }\n @if (markers(); as draggablePoints) {\n @if (x() && y()) {\n @for (point of draggablePoints; track point) {\n <svg:g [attr.transform]=\"'translate(' + x()(point.x) + ',' + y()(point.y) + ')'\">\n <svg:g\n [tetaDraggablePoint]=\"point.marker.draggable\"\n [dragDirection]=\"point.marker.dragType\"\n [allowDrag]=\"allowDrag(point)\"\n #dragPoint=\"tetaDraggablePoint\"\n (moveStart)=\"moveStart($event, point)\"\n (moveEnd)=\"moveEnd($event, point); dragPoint.resetTransform()\"\n (moveProcess)=\"moveProcess($event, point); dragPoint.resetTransform()\"\n [class.draggable-marker]=\"point?.marker?.draggable\"\n >\n <svg:circle\n class=\"marker\"\n [attr.r]=\"point.marker.style?.radius ?? 5\"\n [attr.fill]=\"point.marker.style?.fill ?? 'transparent'\"\n [attr.stroke]=\"point.marker.style?.stroke ?? 'none'\"\n [attr.stroke-width]=\"point.marker.style?.strokeWidth\"\n [attr.stroke-dasharray]=\"point.marker.style?.strokeDasharray\"\n [attr.cx]=\"0\"\n [attr.cy]=\"0\"\n ></svg:circle>\n @if (point.marker.label?.text) {\n <svg:line\n [attr.x1]=\"0\"\n [attr.y1]=\"0\"\n [attr.x2]=\"point.marker.label?.dx\"\n [attr.y2]=\"point.marker.label?.dy\"\n [attr.stroke]=\"point.marker.label?.style?.stroke ?? 'var(--color-text-90)'\"\n [attr.stroke-width]=\"point.marker.label?.style?.strokeWidth ?? 1\"\n [attr.stroke-dasharray]=\"point.marker.label?.style?.strokeDasharray ?? null\"\n ></svg:line>\n <svg:foreignObject\n [tetaDraggablePoint]=\"point.marker.label?.draggable\"\n [dragDirection]=\"point.marker.label.dragType\"\n #labelPoint=\"tetaDraggablePoint\"\n (moveStart)=\"startLabel($event, point.marker.label)\"\n (moveProcess)=\"moveLabel($event, point.marker.label); labelPoint.resetTransform()\"\n (moveEnd)=\"labelPoint.resetTransform()\"\n [attr.width]=\"annotationNode?.offsetWidth ?? 0\"\n [attr.height]=\"annotationNode?.offsetHeight ?? 0\"\n [attr.x]=\"point.marker.label?.dx\"\n [attr.y]=\"point.marker.label?.dy\"\n class=\"position-absolute\"\n >\n <div\n #annotationNode\n class=\"shadow-2 padding-2\"\n [style.color]=\"'var(--color-text-90)'\"\n [style.background-color]=\"'var(--color-global-bgcard)'\"\n [style.cursor]=\"'move'\"\n style=\"border-radius: 2px; display: inline-block\"\n >\n {{ point.marker.label?.text }}\n </div>\n </svg:foreignObject>\n }\n </svg:g>\n </svg:g>\n }\n }\n }\n}\n", styles: [".draggable-marker{cursor:move}.draggable-path,.selected-path,.selected-path:active{cursor:ew-resize}.line-selected{filter:drop-shadow(0 0 3px var(--series-color))}.active{stroke-opacity:.5}.marker-grab{opacity:0}\n"] }]
2451
+ args: [{ selector: 'svg:svg[teta-line-series]', changeDetection: ChangeDetectionStrategy.OnPush, imports: [AsyncPipe, DraggablePointDirective, DraggableSeriesDirective], template: "@if (series(); as series) {\n <svg:g\n [tetaDraggableSeries]=\"series.draggablePath\"\n [dragDirection]=\"series.pathDragType\"\n [attr.transform]=\"seriesPathTransform()\"\n [class.draggable-path]=\"series.draggablePath\"\n [class.selected-path]=\"seriesSelectedForPathDrag()\"\n (click)=\"seriesPathClick($event)\"\n (moveStart)=\"seriesMoveStart($event)\"\n (moveProcess)=\"seriesMoveProcess($event)\"\n (moveEnd)=\"seriesMoveEnd($event)\"\n >\n <svg:path\n class=\"line\"\n [class.line-selected]=\"seriesSelectedForPathDrag()\"\n [attr.d]=\"path()\"\n [attr.stroke]=\"series.color\"\n [attr.stroke-dasharray]=\"series.style?.strokeDasharray\"\n [attr.stroke-width]=\"series.style?.strokeWidth\"\n [style.--series-color]=\"series.color\"\n fill=\"none\"\n ></svg:path>\n @if (series.draggablePath) {\n <svg:path\n class=\"line-hitbox\"\n [attr.d]=\"path()\"\n fill=\"none\"\n stroke=\"transparent\"\n stroke-width=\"14\"\n pointer-events=\"stroke\"\n ></svg:path>\n }\n </svg:g>\n @if (transform(); as t) {\n @if (t?.x !== null && t?.x !== undefined && t?.y !== null && t?.y !== undefined) {\n <svg:circle\n r=\"3\"\n [attr.fill]=\"series.color\"\n [attr.transform]=\"'translate(' + t.x + ', ' + t.y + ')'\"\n ></svg:circle>\n }\n }\n @if (markers(); as draggablePoints) {\n @if ({ x: x(), y: y() }; as scales) {\n @if (scales.x && scales.y) {\n @for (point of draggablePoints; track point) {\n <svg:g [attr.transform]=\"'translate(' + scales.x(point.x) + ',' + scales.y(point.y) + ')'\">\n <svg:g\n [tetaDraggablePoint]=\"point.marker.draggable\"\n [dragDirection]=\"point.marker.dragType\"\n [allowDrag]=\"allowDrag(point)\"\n #dragPoint=\"tetaDraggablePoint\"\n (moveStart)=\"moveStart($event, point)\"\n (moveEnd)=\"moveEnd($event, point); dragPoint.resetTransform()\"\n (moveProcess)=\"moveProcess($event, point); dragPoint.resetTransform()\"\n [class.draggable-marker]=\"point?.marker?.draggable\"\n >\n <svg:circle\n class=\"marker\"\n [attr.r]=\"point.marker.style?.radius ?? 5\"\n [attr.fill]=\"point.marker.style?.fill ?? 'transparent'\"\n [attr.stroke]=\"point.marker.style?.stroke ?? 'none'\"\n [attr.stroke-width]=\"point.marker.style?.strokeWidth\"\n [attr.stroke-dasharray]=\"point.marker.style?.strokeDasharray\"\n [attr.cx]=\"0\"\n [attr.cy]=\"0\"\n ></svg:circle>\n @if (point.marker.label?.text) {\n <svg:line\n [attr.x1]=\"0\"\n [attr.y1]=\"0\"\n [attr.x2]=\"point.marker.label?.dx\"\n [attr.y2]=\"point.marker.label?.dy\"\n [attr.stroke]=\"point.marker.label?.style?.stroke ?? 'var(--color-text-90)'\"\n [attr.stroke-width]=\"point.marker.label?.style?.strokeWidth ?? 1\"\n [attr.stroke-dasharray]=\"point.marker.label?.style?.strokeDasharray ?? null\"\n ></svg:line>\n <svg:foreignObject\n [tetaDraggablePoint]=\"point.marker.label?.draggable\"\n [dragDirection]=\"point.marker.label.dragType\"\n #labelPoint=\"tetaDraggablePoint\"\n (moveStart)=\"startLabel($event, point.marker.label)\"\n (moveProcess)=\"moveLabel($event, point.marker.label); labelPoint.resetTransform()\"\n (moveEnd)=\"labelPoint.resetTransform()\"\n [attr.width]=\"annotationNode?.offsetWidth ?? 0\"\n [attr.height]=\"annotationNode?.offsetHeight ?? 0\"\n [attr.x]=\"point.marker.label?.dx\"\n [attr.y]=\"point.marker.label?.dy\"\n class=\"position-absolute\"\n >\n <div\n #annotationNode\n class=\"shadow-2 padding-2\"\n [style.color]=\"'var(--color-text-90)'\"\n [style.background-color]=\"'var(--color-global-bgcard)'\"\n [style.cursor]=\"'move'\"\n style=\"border-radius: 2px; display: inline-block\"\n >\n {{ point.marker.label?.text }}\n </div>\n </svg:foreignObject>\n }\n </svg:g>\n </svg:g>\n }\n }\n }\n }\n}\n", styles: [".draggable-marker{cursor:move}.draggable-path,.selected-path,.selected-path:active{cursor:ew-resize}.line-selected{filter:drop-shadow(0 0 3px var(--series-color))}.active{stroke-opacity:.5}.marker-grab{opacity:0}\n"] }]
2406
2452
  }] });
2407
2453
 
2408
2454
  class BarSeriesComponent extends SeriesBaseComponent {
2409
2455
  constructor() {
2410
2456
  super(...arguments);
2411
2457
  this.x1 = computed(() => {
2412
- const x = this.xScales().get(this.series().xAxisIndex)?.scale;
2458
+ const series = this.series();
2459
+ const x = this.xScales().get(series.xAxisIndex)?.scale;
2413
2460
  const range = x.range();
2414
- const domain = this.series().data.map((_) => _.x);
2461
+ const domain = series.data.map((_) => _.x);
2415
2462
  return d3.scaleBand().range([0, range[1]]).domain(domain).padding(0.1);
2416
2463
  }, ...(ngDevMode ? [{ debugName: "x1" }] : /* istanbul ignore next */ []));
2417
2464
  this.barSeriesCount = computed(() => {
2418
- const count = this.config().series.filter((_) => _.type === SeriesType.bar && _.xAxisIndex === this.series().xAxisIndex);
2465
+ const config = this.config();
2466
+ const series = this.series();
2467
+ const count = config.series.filter((_) => _.type === SeriesType.bar && _.xAxisIndex === series.xAxisIndex);
2419
2468
  return count.length;
2420
2469
  }, ...(ngDevMode ? [{ debugName: "barSeriesCount" }] : /* istanbul ignore next */ []));
2421
2470
  this.Math = Math;
@@ -2445,12 +2494,14 @@ class BlockSeriesComponent extends SeriesBaseComponent {
2445
2494
  constructor() {
2446
2495
  super(...arguments);
2447
2496
  this.displayPoints = computed(() => {
2448
- const domain = this.config().inverted ? this.y().domain() : this.x().domain();
2497
+ const config = this.config();
2498
+ const series = this.series();
2499
+ const domain = config.inverted ? this.y().domain() : this.x().domain();
2449
2500
  const [min, max] = domain;
2450
- return this.series().data.filter((point, index, arr) => {
2501
+ return series.data.filter((point, index, arr) => {
2451
2502
  const next = arr[index + 1];
2452
2503
  const secondNext = arr[index + 2];
2453
- if (this.config().inverted) {
2504
+ if (config.inverted) {
2454
2505
  if (point.y1 === null || point.y1 === undefined) {
2455
2506
  point.y1 = next?.y ?? point.y;
2456
2507
  }
@@ -2487,12 +2538,14 @@ class BlockAreaSeriesComponent extends SeriesBaseComponent {
2487
2538
  constructor() {
2488
2539
  super(...arguments);
2489
2540
  this.displayPoints = computed(() => {
2490
- const domain = this.config().inverted ? this.y().domain() : this.x().domain();
2541
+ const config = this.config();
2542
+ const series = this.series();
2543
+ const domain = config.inverted ? this.y().domain() : this.x().domain();
2491
2544
  const [min, max] = domain;
2492
- return this.series().data.filter((point, index, arr) => {
2545
+ return series.data.filter((point, index, arr) => {
2493
2546
  const next = arr[index + 1];
2494
2547
  const secondNext = arr[index + 2];
2495
- if (this.config().inverted) {
2548
+ if (config.inverted) {
2496
2549
  if (point.y1 === null || point.y1 === undefined) {
2497
2550
  point.y1 = next?.y ?? point.y;
2498
2551
  }
@@ -2529,34 +2582,38 @@ class AreaSeriesComponent extends LinearSeriesBaseComponent {
2529
2582
  constructor() {
2530
2583
  super(...arguments);
2531
2584
  this.areaPath = computed(() => {
2532
- if (!this.x() || !this.y()) {
2585
+ const x = this.x();
2586
+ const y = this.y();
2587
+ const config = this.config();
2588
+ const series = this.series();
2589
+ if (!x || !y) {
2533
2590
  return '';
2534
2591
  }
2535
2592
  const area = d3
2536
2593
  .area()
2537
2594
  .defined((point) => point.x !== null && point.y !== null && !isNaN(point.x) && !isNaN(point.y));
2538
- if (this.config().inverted) {
2595
+ if (config.inverted) {
2539
2596
  area
2540
- .x1((_) => (_.x1 !== null && _.x1 !== undefined ? this.x()(_.x1) : this.x()(0)))
2541
- .x0((_) => this.x()(_.x))
2542
- .y((_) => this.y()(_.y));
2597
+ .x1((_) => (_.x1 !== null && _.x1 !== undefined ? x(_.x1) : x(0)))
2598
+ .x0((_) => x(_.x))
2599
+ .y((_) => y(_.y));
2543
2600
  }
2544
2601
  else {
2545
2602
  area
2546
- .y1((_) => (_.y1 !== null && _.y1 !== undefined ? this.y()(_.y1) : this.y()(0)))
2547
- .y0((_) => this.y()(_.y))
2548
- .x((_) => this.x()(_.x));
2549
- }
2550
- const filter = this.defaultClipPointsMapping.get(this.series().clipPointsDirection);
2551
- let filteredData = this.series().data;
2552
- if (this.series().clipPointsDirection === ClipPointsDirection.x) {
2553
- let [min, max] = this.x().domain();
2603
+ .y1((_) => (_.y1 !== null && _.y1 !== undefined ? y(_.y1) : y(0)))
2604
+ .y0((_) => y(_.y))
2605
+ .x((_) => x(_.x));
2606
+ }
2607
+ const filter = this.defaultClipPointsMapping.get(series.clipPointsDirection);
2608
+ let filteredData = series.data;
2609
+ if (series.clipPointsDirection === ClipPointsDirection.x) {
2610
+ let [min, max] = x.domain();
2554
2611
  min = min instanceof Date ? min.getTime() : min;
2555
2612
  max = max instanceof Date ? max.getTime() : max;
2556
2613
  filteredData = filteredData?.filter(filter(min, max));
2557
2614
  }
2558
- if (this.series().clipPointsDirection === ClipPointsDirection.y) {
2559
- let [min, max] = this.y().domain();
2615
+ if (series.clipPointsDirection === ClipPointsDirection.y) {
2616
+ let [min, max] = y.domain();
2560
2617
  min = min instanceof Date ? min.getTime() : min;
2561
2618
  max = max instanceof Date ? max.getTime() : max;
2562
2619
  filteredData = filteredData?.filter(filter(min, max));
@@ -2567,11 +2624,11 @@ class AreaSeriesComponent extends LinearSeriesBaseComponent {
2567
2624
  this.FillDirection = FillDirection;
2568
2625
  }
2569
2626
  static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.9", ngImport: i0, type: AreaSeriesComponent, deps: null, target: i0.ɵɵFactoryTarget.Component }); }
2570
- static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.9", type: AreaSeriesComponent, isStandalone: true, selector: "svg:svg[teta-area-series]", usesInheritance: true, ngImport: i0, template: "@if (series()?.fillType === FillType.gradient) {\n <svg:defs>\n <svg:linearGradient [id]=\"'gradient-fill-' + id\"\n gradientUnits=\"userSpaceOnUse\"\n x1=\"0%\"\n [attr.y1]=\"config()?.inverted || series()?.fillDirection === FillDirection.y ? '0%' : '100%'\"\n [attr.x2]=\"config()?.inverted || series()?.fillDirection === FillDirection.y ? '100%' : '0%'\"\n y2=\"0%\">\n <svg:stop offset=\"0%\" [attr.stop-color]=\"series().color\" stop-opacity=\"0\"></svg:stop>\n <svg:stop offset=\"5%\" [attr.stop-color]=\"series().color\" stop-opacity=\"0.1\"></svg:stop>\n <svg:stop offset=\"20%\" [attr.stop-color]=\"series().color\" stop-opacity=\"0.2\"></svg:stop>\n <svg:stop offset=\"60%\" [attr.stop-color]=\"series().color\" stop-opacity=\"0.5\"></svg:stop>\n <svg:stop offset=\"100%\" [attr.stop-color]=\"series().color\" stop-opacity=\"0.8\"></svg:stop>\n </svg:linearGradient>\n </svg:defs>\n}\n<svg:path class=\"area\"\n [attr.d]=\"areaPath()\"\n [attr.stroke-width]=\"0\"\n [attr.fill-opacity]=\"series().style?.fillOpacity\"\n [attr.fill]=\"series().fillType === FillType.gradient ? 'url(#gradient-fill-' + id + ')' : (series().style?.fill ?? series().color)\"></svg:path>\n<svg:path class=\"area\"\n fill=\"none\"\n [attr.d]=\"path()\"\n [attr.stroke]=\"series().color\"\n [attr.stroke-dasharray]=\"series().style?.strokeDasharray\"\n [attr.stroke-width]=\"series().style?.strokeWidth\"></svg:path>\n@if (transform(); as t) {\n @if (t?.x !== null && t?.x !== undefined && t?.y !== null && t?.y !== undefined) {\n <svg:circle r=\"3\"\n [attr.fill]=\"series().color\"\n [attr.transform]=\"'translate(' + t.x + ', ' + t.y + ')'\"></svg:circle>\n }\n}\n@if (markers(); as draggablePoints) {\n @for (point of draggablePoints; track point) {\n <svg:circle class=\"marker\"\n [class.draggable-marker]=\"point?.marker?.draggable\"\n [attr.r]=\"point.marker.style?.radius ?? 5\"\n [attr.fill]=\"point.marker.style?.fill ?? 'transparent'\"\n [attr.stroke]=\"point.marker.style?.stroke ?? 'none'\"\n [attr.stroke-width]=\"point.marker.style?.strokeWidth\"\n [attr.stroke-dasharray]=\"point.marker.style?.strokeDasharray\"\n [attr.cx]=\"x()(point.x)\"\n [attr.cy]=\"y()(point.y)\"\n ></svg:circle>\n }\n}\n", styles: [""], changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
2627
+ static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.9", type: AreaSeriesComponent, isStandalone: true, selector: "svg:svg[teta-area-series]", usesInheritance: true, ngImport: i0, template: "@if (series()?.fillType === FillType.gradient) {\n <svg:defs>\n <svg:linearGradient [id]=\"'gradient-fill-' + id\"\n gradientUnits=\"userSpaceOnUse\"\n x1=\"0%\"\n [attr.y1]=\"config()?.inverted || series()?.fillDirection === FillDirection.y ? '0%' : '100%'\"\n [attr.x2]=\"config()?.inverted || series()?.fillDirection === FillDirection.y ? '100%' : '0%'\"\n y2=\"0%\">\n <svg:stop offset=\"0%\" [attr.stop-color]=\"series().color\" stop-opacity=\"0\"></svg:stop>\n <svg:stop offset=\"5%\" [attr.stop-color]=\"series().color\" stop-opacity=\"0.1\"></svg:stop>\n <svg:stop offset=\"20%\" [attr.stop-color]=\"series().color\" stop-opacity=\"0.2\"></svg:stop>\n <svg:stop offset=\"60%\" [attr.stop-color]=\"series().color\" stop-opacity=\"0.5\"></svg:stop>\n <svg:stop offset=\"100%\" [attr.stop-color]=\"series().color\" stop-opacity=\"0.8\"></svg:stop>\n </svg:linearGradient>\n </svg:defs>\n}\n<svg:path class=\"area\"\n [attr.d]=\"areaPath()\"\n [attr.stroke-width]=\"0\"\n [attr.fill-opacity]=\"series().style?.fillOpacity\"\n [attr.fill]=\"series().fillType === FillType.gradient ? 'url(#gradient-fill-' + id + ')' : (series().style?.fill ?? series().color)\"></svg:path>\n<svg:path class=\"area\"\n fill=\"none\"\n [attr.d]=\"path()\"\n [attr.stroke]=\"series().color\"\n [attr.stroke-dasharray]=\"series().style?.strokeDasharray\"\n [attr.stroke-width]=\"series().style?.strokeWidth\"></svg:path>\n@if (transform(); as t) {\n @if (t?.x !== null && t?.x !== undefined && t?.y !== null && t?.y !== undefined) {\n <svg:circle r=\"3\"\n [attr.fill]=\"series().color\"\n [attr.transform]=\"'translate(' + t.x + ', ' + t.y + ')'\"></svg:circle>\n }\n}\n@if ({ points: markers(), x: x(), y: y() }; as data) {\n @if (data.x && data.y) {\n @for (point of data.points; track point) {\n <svg:circle class=\"marker\"\n [class.draggable-marker]=\"point?.marker?.draggable\"\n [attr.r]=\"point.marker.style?.radius ?? 5\"\n [attr.fill]=\"point.marker.style?.fill ?? 'transparent'\"\n [attr.stroke]=\"point.marker.style?.stroke ?? 'none'\"\n [attr.stroke-width]=\"point.marker.style?.strokeWidth\"\n [attr.stroke-dasharray]=\"point.marker.style?.strokeDasharray\"\n [attr.cx]=\"data.x(point.x)\"\n [attr.cy]=\"data.y(point.y)\"\n ></svg:circle>\n }\n }\n}\n", styles: [""], changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
2571
2628
  }
2572
2629
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.9", ngImport: i0, type: AreaSeriesComponent, decorators: [{
2573
2630
  type: Component,
2574
- args: [{ selector: 'svg:svg[teta-area-series]', changeDetection: ChangeDetectionStrategy.OnPush, template: "@if (series()?.fillType === FillType.gradient) {\n <svg:defs>\n <svg:linearGradient [id]=\"'gradient-fill-' + id\"\n gradientUnits=\"userSpaceOnUse\"\n x1=\"0%\"\n [attr.y1]=\"config()?.inverted || series()?.fillDirection === FillDirection.y ? '0%' : '100%'\"\n [attr.x2]=\"config()?.inverted || series()?.fillDirection === FillDirection.y ? '100%' : '0%'\"\n y2=\"0%\">\n <svg:stop offset=\"0%\" [attr.stop-color]=\"series().color\" stop-opacity=\"0\"></svg:stop>\n <svg:stop offset=\"5%\" [attr.stop-color]=\"series().color\" stop-opacity=\"0.1\"></svg:stop>\n <svg:stop offset=\"20%\" [attr.stop-color]=\"series().color\" stop-opacity=\"0.2\"></svg:stop>\n <svg:stop offset=\"60%\" [attr.stop-color]=\"series().color\" stop-opacity=\"0.5\"></svg:stop>\n <svg:stop offset=\"100%\" [attr.stop-color]=\"series().color\" stop-opacity=\"0.8\"></svg:stop>\n </svg:linearGradient>\n </svg:defs>\n}\n<svg:path class=\"area\"\n [attr.d]=\"areaPath()\"\n [attr.stroke-width]=\"0\"\n [attr.fill-opacity]=\"series().style?.fillOpacity\"\n [attr.fill]=\"series().fillType === FillType.gradient ? 'url(#gradient-fill-' + id + ')' : (series().style?.fill ?? series().color)\"></svg:path>\n<svg:path class=\"area\"\n fill=\"none\"\n [attr.d]=\"path()\"\n [attr.stroke]=\"series().color\"\n [attr.stroke-dasharray]=\"series().style?.strokeDasharray\"\n [attr.stroke-width]=\"series().style?.strokeWidth\"></svg:path>\n@if (transform(); as t) {\n @if (t?.x !== null && t?.x !== undefined && t?.y !== null && t?.y !== undefined) {\n <svg:circle r=\"3\"\n [attr.fill]=\"series().color\"\n [attr.transform]=\"'translate(' + t.x + ', ' + t.y + ')'\"></svg:circle>\n }\n}\n@if (markers(); as draggablePoints) {\n @for (point of draggablePoints; track point) {\n <svg:circle class=\"marker\"\n [class.draggable-marker]=\"point?.marker?.draggable\"\n [attr.r]=\"point.marker.style?.radius ?? 5\"\n [attr.fill]=\"point.marker.style?.fill ?? 'transparent'\"\n [attr.stroke]=\"point.marker.style?.stroke ?? 'none'\"\n [attr.stroke-width]=\"point.marker.style?.strokeWidth\"\n [attr.stroke-dasharray]=\"point.marker.style?.strokeDasharray\"\n [attr.cx]=\"x()(point.x)\"\n [attr.cy]=\"y()(point.y)\"\n ></svg:circle>\n }\n}\n" }]
2631
+ args: [{ selector: 'svg:svg[teta-area-series]', changeDetection: ChangeDetectionStrategy.OnPush, template: "@if (series()?.fillType === FillType.gradient) {\n <svg:defs>\n <svg:linearGradient [id]=\"'gradient-fill-' + id\"\n gradientUnits=\"userSpaceOnUse\"\n x1=\"0%\"\n [attr.y1]=\"config()?.inverted || series()?.fillDirection === FillDirection.y ? '0%' : '100%'\"\n [attr.x2]=\"config()?.inverted || series()?.fillDirection === FillDirection.y ? '100%' : '0%'\"\n y2=\"0%\">\n <svg:stop offset=\"0%\" [attr.stop-color]=\"series().color\" stop-opacity=\"0\"></svg:stop>\n <svg:stop offset=\"5%\" [attr.stop-color]=\"series().color\" stop-opacity=\"0.1\"></svg:stop>\n <svg:stop offset=\"20%\" [attr.stop-color]=\"series().color\" stop-opacity=\"0.2\"></svg:stop>\n <svg:stop offset=\"60%\" [attr.stop-color]=\"series().color\" stop-opacity=\"0.5\"></svg:stop>\n <svg:stop offset=\"100%\" [attr.stop-color]=\"series().color\" stop-opacity=\"0.8\"></svg:stop>\n </svg:linearGradient>\n </svg:defs>\n}\n<svg:path class=\"area\"\n [attr.d]=\"areaPath()\"\n [attr.stroke-width]=\"0\"\n [attr.fill-opacity]=\"series().style?.fillOpacity\"\n [attr.fill]=\"series().fillType === FillType.gradient ? 'url(#gradient-fill-' + id + ')' : (series().style?.fill ?? series().color)\"></svg:path>\n<svg:path class=\"area\"\n fill=\"none\"\n [attr.d]=\"path()\"\n [attr.stroke]=\"series().color\"\n [attr.stroke-dasharray]=\"series().style?.strokeDasharray\"\n [attr.stroke-width]=\"series().style?.strokeWidth\"></svg:path>\n@if (transform(); as t) {\n @if (t?.x !== null && t?.x !== undefined && t?.y !== null && t?.y !== undefined) {\n <svg:circle r=\"3\"\n [attr.fill]=\"series().color\"\n [attr.transform]=\"'translate(' + t.x + ', ' + t.y + ')'\"></svg:circle>\n }\n}\n@if ({ points: markers(), x: x(), y: y() }; as data) {\n @if (data.x && data.y) {\n @for (point of data.points; track point) {\n <svg:circle class=\"marker\"\n [class.draggable-marker]=\"point?.marker?.draggable\"\n [attr.r]=\"point.marker.style?.radius ?? 5\"\n [attr.fill]=\"point.marker.style?.fill ?? 'transparent'\"\n [attr.stroke]=\"point.marker.style?.stroke ?? 'none'\"\n [attr.stroke-width]=\"point.marker.style?.strokeWidth\"\n [attr.stroke-dasharray]=\"point.marker.style?.strokeDasharray\"\n [attr.cx]=\"data.x(point.x)\"\n [attr.cy]=\"data.y(point.y)\"\n ></svg:circle>\n }\n }\n}\n" }]
2575
2632
  }] });
2576
2633
 
2577
2634
  const defaultSeriesTypeMapping = new Map()
@@ -3263,6 +3320,9 @@ class ChartComponent {
3263
3320
  this.chartService.setConfig(config);
3264
3321
  this.zoomService.setBroadcastChannel(config?.zoom?.syncChannel);
3265
3322
  }
3323
+ set selectedSeriesIds(seriesIds) {
3324
+ this.chartService.setSelectedSeriesIds(seriesIds ?? []);
3325
+ }
3266
3326
  constructor(chartService, zoomService, brushService, scaleService) {
3267
3327
  this.chartService = chartService;
3268
3328
  this.zoomService = zoomService;
@@ -3274,7 +3334,8 @@ class ChartComponent {
3274
3334
  this.plotBandContextMenu = new EventEmitter();
3275
3335
  this.plotLinesMove = new EventEmitter();
3276
3336
  this.pointMove = new EventEmitter();
3277
- this.seriesOffsetMove = new EventEmitter();
3337
+ this.seriesMove = new EventEmitter();
3338
+ this.selectedSeriesIdsChange = new EventEmitter();
3278
3339
  this.chartClick = new EventEmitter();
3279
3340
  this.chartContextMenu = new EventEmitter();
3280
3341
  this.annotationContextMenu = new EventEmitter();
@@ -3334,8 +3395,13 @@ class ChartComponent {
3334
3395
  this.chartService.pointMove.pipe(takeWhile(() => this._alive)).subscribe((_) => {
3335
3396
  this.pointMove.emit(_);
3336
3397
  });
3337
- this.chartService.seriesOffsetMove.pipe(takeWhile(() => this._alive)).subscribe((_) => {
3338
- this.seriesOffsetMove.emit(_);
3398
+ this.chartService.seriesMove.pipe(takeWhile(() => this._alive)).subscribe((_) => {
3399
+ this.seriesMove.emit(_);
3400
+ });
3401
+ this.chartService.selectedSeriesIds
3402
+ .pipe(takeWhile(() => this._alive), distinctUntilChanged((prev, next) => this.areSeriesIdsEqual(prev, next)))
3403
+ .subscribe((_) => {
3404
+ this.selectedSeriesIdsChange.emit(_);
3339
3405
  });
3340
3406
  this.chartService.chartClick.pipe(takeWhile(() => this._alive)).subscribe((_) => {
3341
3407
  this.chartClick.emit(_);
@@ -3365,8 +3431,11 @@ class ChartComponent {
3365
3431
  ngOnDestroy() {
3366
3432
  this._alive = false;
3367
3433
  }
3434
+ areSeriesIdsEqual(first, second) {
3435
+ return first.length === second.length && first.every((id, index) => id === second[index]);
3436
+ }
3368
3437
  static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.9", ngImport: i0, type: ChartComponent, deps: [{ token: ChartService }, { token: ZoomService }, { token: BrushService }, { token: ScaleService }], target: i0.ɵɵFactoryTarget.Component }); }
3369
- static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.9", type: ChartComponent, isStandalone: true, selector: "teta-svg-chart", inputs: { config: "config" }, outputs: { pointerMove: "pointerMove", plotBandsMove: "plotBandsMove", plotBandClick: "plotBandClick", plotBandContextMenu: "plotBandContextMenu", plotLinesMove: "plotLinesMove", pointMove: "pointMove", seriesOffsetMove: "seriesOffsetMove", chartClick: "chartClick", chartContextMenu: "chartContextMenu", annotationContextMenu: "annotationContextMenu", annotationClick: "annotationClick", annotationMove: "annotationMove", zoomServiceInstance: "zoomServiceInstance", brushServiceInstance: "brushServiceInstance", configUpdated: "configUpdated" }, providers: [ChartService, ZoomService, ScaleService, BrushService], ngImport: i0, template: "@if ({ hasSeriesData: hasSeriesData | async, svcConfig: svcConfig | async }; as data) {\n @if (data.hasSeriesData === true) {\n <div class=\"column column_auto\">\n <teta-chart-container class=\"chart-container position-relative\"></teta-chart-container>\n </div>\n @if (data.svcConfig.legend?.enable === true) {\n <teta-legend [series]=\"data.svcConfig.series\"></teta-legend>\n }\n } @else {\n <div class=\"column column_auto justify-content-center\">\n <span class=\"font-body-3 color-text-40 overflow-hidden text-overflow-ellipsis nowrap text-align-center\">\n <div #ref><ng-content></ng-content></div>\n @if (!ref.hasChildNodes()) {\n <span> No data </span>\n }\n </span>\n </div>\n }\n}\n", styles: [":host{position:relative;display:flex;flex-direction:column;height:100%;width:100%}\n"], dependencies: [{ kind: "component", type: ChartContainerComponent, selector: "teta-chart-container" }, { kind: "component", type: LegendComponent, selector: "teta-legend", inputs: ["series"] }, { kind: "pipe", type: AsyncPipe, name: "async" }], changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
3438
+ static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.9", type: ChartComponent, isStandalone: true, selector: "teta-svg-chart", inputs: { config: "config", selectedSeriesIds: "selectedSeriesIds" }, outputs: { pointerMove: "pointerMove", plotBandsMove: "plotBandsMove", plotBandClick: "plotBandClick", plotBandContextMenu: "plotBandContextMenu", plotLinesMove: "plotLinesMove", pointMove: "pointMove", seriesMove: "seriesMove", selectedSeriesIdsChange: "selectedSeriesIdsChange", chartClick: "chartClick", chartContextMenu: "chartContextMenu", annotationContextMenu: "annotationContextMenu", annotationClick: "annotationClick", annotationMove: "annotationMove", zoomServiceInstance: "zoomServiceInstance", brushServiceInstance: "brushServiceInstance", configUpdated: "configUpdated" }, providers: [ChartService, ZoomService, ScaleService, BrushService], ngImport: i0, template: "@if ({ hasSeriesData: hasSeriesData | async, svcConfig: svcConfig | async }; as data) {\n @if (data.hasSeriesData === true) {\n <div class=\"column column_auto\">\n <teta-chart-container class=\"chart-container position-relative\"></teta-chart-container>\n </div>\n @if (data.svcConfig.legend?.enable === true) {\n <teta-legend [series]=\"data.svcConfig.series\"></teta-legend>\n }\n } @else {\n <div class=\"column column_auto justify-content-center\">\n <span class=\"font-body-3 color-text-40 overflow-hidden text-overflow-ellipsis nowrap text-align-center\">\n <div #ref><ng-content></ng-content></div>\n @if (!ref.hasChildNodes()) {\n <span> No data </span>\n }\n </span>\n </div>\n }\n}\n", styles: [":host{position:relative;display:flex;flex-direction:column;height:100%;width:100%}\n"], dependencies: [{ kind: "component", type: ChartContainerComponent, selector: "teta-chart-container" }, { kind: "component", type: LegendComponent, selector: "teta-legend", inputs: ["series"] }, { kind: "pipe", type: AsyncPipe, name: "async" }], changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
3370
3439
  }
3371
3440
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.9", ngImport: i0, type: ChartComponent, decorators: [{
3372
3441
  type: Component,
@@ -3383,7 +3452,9 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.9", ngImpor
3383
3452
  type: Output
3384
3453
  }], pointMove: [{
3385
3454
  type: Output
3386
- }], seriesOffsetMove: [{
3455
+ }], seriesMove: [{
3456
+ type: Output
3457
+ }], selectedSeriesIdsChange: [{
3387
3458
  type: Output
3388
3459
  }], chartClick: [{
3389
3460
  type: Output
@@ -3403,6 +3474,8 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.9", ngImpor
3403
3474
  type: Output
3404
3475
  }], config: [{
3405
3476
  type: Input
3477
+ }], selectedSeriesIds: [{
3478
+ type: Input
3406
3479
  }] } });
3407
3480
 
3408
3481
  class PlotBand {
@@ -3427,8 +3500,9 @@ class BlockHorizontalSeriesComponent extends SeriesBaseComponent {
3427
3500
  constructor() {
3428
3501
  super(...arguments);
3429
3502
  this.displayPoints = computed(() => {
3503
+ const x = this.x();
3504
+ const [min, max] = x.domain();
3430
3505
  return this.series().data.filter((point, index, arr) => {
3431
- const [min, max] = this.x().domain();
3432
3506
  return ((point.x >= min || point.x1 >= min || arr[index + 1]?.x >= min || arr[index + 1]?.x1 >= min) &&
3433
3507
  (point.x <= max || point.x1 <= max || arr[index - 1]?.x <= max || arr[index - 1]?.x1 <= max));
3434
3508
  });