@tetacom/svg-charts 1.2.28 → 1.3.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.
Files changed (35) hide show
  1. package/chart/chart/chart.component.d.ts +5 -2
  2. package/chart/chart-container/chart-container.component.d.ts +1 -1
  3. package/chart/chart-container/series/linear-series-base.d.ts +0 -3
  4. package/chart/core/axis/axis.d.ts +2 -2
  5. package/chart/directives/brushable.directive.d.ts +15 -5
  6. package/chart/directives/zoomable.directive.d.ts +6 -11
  7. package/chart/model/i-broadcast-message.d.ts +18 -19
  8. package/chart/model/marker-options.d.ts +1 -1
  9. package/chart/service/broadcast.service.d.ts +1 -4
  10. package/chart/service/brush.service.d.ts +6 -13
  11. package/chart/service/chart.service.d.ts +0 -4
  12. package/chart/service/scale.service.d.ts +1 -1
  13. package/chart/service/zoom.service.d.ts +15 -15
  14. package/esm2020/chart/chart/chart.component.mjs +17 -17
  15. package/esm2020/chart/chart-container/chart-container.component.mjs +3 -3
  16. package/esm2020/chart/chart-container/crosshair/crosshair.component.mjs +1 -2
  17. package/esm2020/chart/chart-container/plotband/plot-band.component.mjs +4 -2
  18. package/esm2020/chart/chart-container/series/line/line-series.component.mjs +4 -4
  19. package/esm2020/chart/chart-container/series/linear-series-base.mjs +4 -72
  20. package/esm2020/chart/core/axis/axis.mjs +2 -2
  21. package/esm2020/chart/directives/brushable.directive.mjs +120 -10
  22. package/esm2020/chart/directives/draggable-point.directive.mjs +2 -1
  23. package/esm2020/chart/directives/zoomable.directive.mjs +90 -197
  24. package/esm2020/chart/model/i-broadcast-message.mjs +4 -6
  25. package/esm2020/chart/model/marker-options.mjs +1 -1
  26. package/esm2020/chart/service/broadcast.service.mjs +4 -17
  27. package/esm2020/chart/service/brush.service.mjs +11 -147
  28. package/esm2020/chart/service/chart.service.mjs +17 -9
  29. package/esm2020/chart/service/scale.service.mjs +19 -21
  30. package/esm2020/chart/service/zoom.service.mjs +48 -53
  31. package/fesm2015/tetacom-svg-charts.mjs +373 -586
  32. package/fesm2015/tetacom-svg-charts.mjs.map +1 -1
  33. package/fesm2020/tetacom-svg-charts.mjs +356 -566
  34. package/fesm2020/tetacom-svg-charts.mjs.map +1 -1
  35. package/package.json +1 -1
@@ -2,12 +2,10 @@ import * as i0 from '@angular/core';
2
2
  import { Injectable, Component, Input, EventEmitter, Directive, Output, HostListener, ChangeDetectionStrategy, ChangeDetectorRef, ElementRef, ViewChild, HostBinding, NgModule } from '@angular/core';
3
3
  import * as i4 from '@angular/common';
4
4
  import { CommonModule } from '@angular/common';
5
- import { BehaviorSubject, Subject, of, withLatestFrom, map, shareReplay, filter, lastValueFrom, take, combineLatest, ReplaySubject, tap, takeWhile, combineLatestWith, observeOn, animationFrameScheduler } from 'rxjs';
5
+ import { BehaviorSubject, Subject, of, withLatestFrom, map, shareReplay, filter, lastValueFrom, take, ReplaySubject, combineLatest, tap, takeWhile, observeOn, animationFrameScheduler } from 'rxjs';
6
6
  import * as d3 from 'd3';
7
7
  import { zoomIdentity } from 'd3';
8
- import objectHash from 'object-hash';
9
8
  import { maxIndex } from 'd3-array';
10
- import { debounceTime, tap as tap$1 } from 'rxjs/operators';
11
9
  import * as i5 from '@tetacom/ng-components';
12
10
  import { PositionUtil, Align, VerticalAlign, tetaZoneFull, LetModule } from '@tetacom/ng-components';
13
11
  import * as i3 from '@angular/platform-browser';
@@ -138,8 +136,10 @@ const defaultSeriesConfig = () => ({
138
136
 
139
137
  class ChartService {
140
138
  constructor() {
139
+ // public zoomInstance: Observable<ZoomService>;
140
+ // public brushInstance: Observable<BrushService>;
141
141
  this.config$ = new BehaviorSubject(defaultChartConfig());
142
- this.size$ = new BehaviorSubject(new DOMRectReadOnly());
142
+ this.size$ = new BehaviorSubject(null);
143
143
  this.pointerMove$ = new Subject();
144
144
  this.tooltips$ = new BehaviorSubject(new Map());
145
145
  this.plotBandEvent$ = new Subject();
@@ -149,13 +149,12 @@ class ChartService {
149
149
  this.chartContextMenu$ = new Subject();
150
150
  this.annotationEvent$ = new Subject();
151
151
  this.annotationMove$ = new Subject();
152
- this.zoomInstance$ = new Subject();
153
152
  this.id = of((Date.now() + Math.random()).toString(36));
154
153
  this.config = this.config$.asObservable().pipe(withLatestFrom(this.id), map(this.setDefaults), map(this.setPreparationData), map(this.restoreLocalStorage), shareReplay({
155
154
  bufferSize: 1,
156
155
  refCount: true,
157
156
  }));
158
- this.size = this.size$.asObservable();
157
+ this.size = this.size$.asObservable().pipe(filter((size) => size != null));
159
158
  this.pointerMove = this.pointerMove$.asObservable();
160
159
  this.tooltips = this.tooltips$.asObservable();
161
160
  this.plotBandEvent = this.plotBandEvent$.asObservable();
@@ -176,7 +175,8 @@ class ChartService {
176
175
  this.plotBandContextMenu = this.plotBandEvent$
177
176
  .asObservable()
178
177
  .pipe(filter((_) => _?.event?.type === 'contextmenu'));
179
- this.zoomInstance = this.zoomInstance$.asObservable();
178
+ // this.zoomInstance = this.zoomInstance$.asObservable();
179
+ // this.brushInstance = this.brushInstance$.asObservable();
180
180
  }
181
181
  setConfig(config) {
182
182
  this.clearTooltips();
@@ -243,9 +243,13 @@ class ChartService {
243
243
  emitChartContextMenu(event) {
244
244
  this.chartContextMenu$.next(event);
245
245
  }
246
- emitZoomInstance(event) {
247
- this.zoomInstance$.next(event);
248
- }
246
+ // public emitZoomInstance(event: ZoomService) {
247
+ // this.zoomInstance$.next(event);
248
+ // }
249
+ //
250
+ // public emitZoomInstance(event: ZoomService) {
251
+ // this.zoomInstance$.next(event);
252
+ // }
249
253
  saveCookie(config) {
250
254
  if (!config.name)
251
255
  return;
@@ -279,7 +283,7 @@ class ChartService {
279
283
  };
280
284
  };
281
285
  config = Object.assign({}, defaultChartConfig(), config);
282
- config.id = id;
286
+ config.id = config.id ?? id;
283
287
  config.xAxis = config.xAxis.map(defaultConfig(defaultAxisConfig));
284
288
  config.yAxis = config.yAxis.map(defaultConfig(defaultAxisConfig));
285
289
  config.series = config.series.map(defaultConfig(defaultSeriesConfig()));
@@ -344,6 +348,8 @@ class ChartService {
344
348
  return config;
345
349
  }
346
350
  }
351
+ // private zoomInstance$ = new Subject<ZoomService>();
352
+ // private brushInstance$ = new Subject<BrushService>();
347
353
  ChartService._hiddenSeriesPostfix = 'hidden_series';
348
354
  ChartService.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "14.0.2", ngImport: i0, type: ChartService, deps: [], target: i0.ɵɵFactoryTarget.Injectable });
349
355
  ChartService.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "14.0.2", ngImport: i0, type: ChartService, providedIn: 'root' });
@@ -360,14 +366,31 @@ var AxisOrientation;
360
366
  AxisOrientation[AxisOrientation["y"] = 1] = "y";
361
367
  })(AxisOrientation || (AxisOrientation = {}));
362
368
 
363
- class ZoomService {
369
+ class BroadcastService {
364
370
  constructor() {
365
- this.broadcastSubscription = [];
366
- this.axisHashMap = new Map();
367
- this.scaleHashMap = new Map();
368
- this.elementHashMap = new Map();
369
- this.zoomHashMap = new Map();
370
- this.zoomed$ = new BehaviorSubject({});
371
+ this.zoomEmitter = new ReplaySubject(1);
372
+ }
373
+ broadcastZoom(value) {
374
+ this.zoomEmitter.next(value);
375
+ }
376
+ subscribeToZoom(channel) {
377
+ return this.zoomEmitter.asObservable().pipe(filter((msg) => channel && msg.channel === channel));
378
+ }
379
+ }
380
+ BroadcastService.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "14.0.2", ngImport: i0, type: BroadcastService, deps: [], target: i0.ɵɵFactoryTarget.Injectable });
381
+ BroadcastService.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "14.0.2", ngImport: i0, type: BroadcastService, providedIn: 'root' });
382
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "14.0.2", ngImport: i0, type: BroadcastService, decorators: [{
383
+ type: Injectable,
384
+ args: [{
385
+ providedIn: 'root',
386
+ }]
387
+ }], ctorParameters: function () { return []; } });
388
+
389
+ class ZoomService {
390
+ constructor(_broadcast, _chart) {
391
+ this._broadcast = _broadcast;
392
+ this._chart = _chart;
393
+ this.zoomed$ = new BehaviorSubject(null);
371
394
  this.zoomed = this.zoomed$.asObservable().pipe(shareReplay({
372
395
  bufferSize: 1,
373
396
  refCount: true
@@ -376,64 +399,62 @@ class ZoomService {
376
399
  fireZoom(zoom) {
377
400
  this.zoomed$.next(zoom);
378
401
  }
402
+ broadcastZoom(zoom) {
403
+ if (this.broadcastChannel?.length) {
404
+ this._broadcast.broadcastZoom({
405
+ channel: this.broadcastChannel,
406
+ message: zoom
407
+ });
408
+ }
409
+ }
379
410
  setBroadcastChannel(channel) {
411
+ if (this.broadcastSub) {
412
+ this.broadcastSub?.unsubscribe();
413
+ }
380
414
  this.broadcastChannel = channel;
381
- }
382
- setZoom(from, to, axisIndex = 0, axisOrientation = AxisOrientation.x) {
383
- const hash = objectHash.sha1({ index: axisIndex, orientation: axisOrientation });
384
- if (!this.zoomHashMap.has(hash)) {
385
- return;
415
+ if (this.broadcastChannel?.length) {
416
+ this.broadcastSub = combineLatest([this._broadcast.subscribeToZoom(this.broadcastChannel), this._chart.config])
417
+ .pipe(filter(([zoom, config]) => {
418
+ return zoom.message?.chartId !== config.id;
419
+ }))
420
+ .subscribe(([zoom, config]) => {
421
+ this.fireZoom(zoom.message);
422
+ });
386
423
  }
387
- const currentAxis = this.axisHashMap.get(hash);
388
- const currentScale = this.scaleHashMap.get(hash);
389
- const currentElement = this.elementHashMap.get(hash);
390
- const currentZoom = this.zoomHashMap.get(hash);
391
- currentScale.domain(currentAxis.originDomain);
392
- if (axisOrientation === AxisOrientation.x) {
393
- if (currentAxis.options.scaleType.type === ScaleType.log) {
394
- currentScale.domain(currentAxis.options.inverted ? [...currentAxis.originDomain].reverse() : currentAxis.originDomain);
424
+ }
425
+ getD3Transform(targetDomain, originalDomain, scale, orientation, inverted) {
426
+ const zoomScale = Math.abs(originalDomain[1] - originalDomain[0]) / Math.abs(targetDomain[1] - targetDomain[0]);
427
+ let transform = zoomIdentity.scale(zoomScale);
428
+ if (orientation === AxisOrientation.x) {
429
+ if (!!inverted) {
430
+ transform = transform.translate(-scale(Math.max(...targetDomain)), 0);
395
431
  }
396
- }
397
- if (axisOrientation === AxisOrientation.y) {
398
- if (currentAxis.options.scaleType.type === ScaleType.log) {
399
- currentScale.domain(currentAxis.options.inverted ? currentAxis.originDomain : [...currentAxis.originDomain].reverse());
432
+ else {
433
+ transform = transform.translate(-scale(Math.min(...targetDomain)), 0);
400
434
  }
401
435
  }
402
- const delta = Math.abs(currentScale(to) - currentScale(from));
403
- const scale = currentScale.range()[1] / delta;
404
- let transform = zoomIdentity.scale(scale);
405
- if (currentAxis.orientation === AxisOrientation.x) {
406
- if (currentAxis.options.scaleType.type === ScaleType.log) {
407
- currentScale.domain(currentAxis.options.inverted ? [...currentScale.domain()].reverse() : currentScale.domain());
436
+ if (orientation === AxisOrientation.y) {
437
+ if (!!inverted) {
438
+ transform = transform.translate(0, -scale(Math.min(...targetDomain)));
408
439
  }
409
- transform = transform.translate(-currentScale(from), 0);
410
- }
411
- if (currentAxis.orientation === AxisOrientation.y) {
412
- if (currentAxis.options.scaleType.type === ScaleType.log) {
413
- currentScale.domain(currentAxis.options.inverted ? currentScale.domain() : [...currentScale.domain()].reverse());
440
+ else {
441
+ transform = transform.translate(0, -scale(Math.max(...targetDomain)));
414
442
  }
415
- transform = transform.translate(0, -currentScale(from));
416
443
  }
417
- currentElement.transition().call(currentZoom.transform, transform, null, new MouseEvent('setZoom'));
444
+ return transform;
418
445
  }
419
- resetZoom(axisIndex = 0, axisOrientation = AxisOrientation.x) {
420
- const hash = objectHash.sha1({ index: axisIndex, orientation: axisOrientation });
421
- if (!this.zoomHashMap.has(hash)) {
422
- return;
423
- }
424
- const currentElement = this.elementHashMap.get(hash);
425
- const currentZoom = this.zoomHashMap.get(hash);
426
- currentElement.transition().call(currentZoom.transform, zoomIdentity, null, new MouseEvent('resetZoom'));
446
+ ngOnDestroy() {
447
+ this.broadcastSub?.unsubscribe();
427
448
  }
428
449
  }
429
- ZoomService.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "14.0.2", ngImport: i0, type: ZoomService, deps: [], target: i0.ɵɵFactoryTarget.Injectable });
450
+ ZoomService.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "14.0.2", ngImport: i0, type: ZoomService, deps: [{ token: BroadcastService }, { token: ChartService }], target: i0.ɵɵFactoryTarget.Injectable });
430
451
  ZoomService.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "14.0.2", ngImport: i0, type: ZoomService, providedIn: 'root' });
431
452
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "14.0.2", ngImport: i0, type: ZoomService, decorators: [{
432
453
  type: Injectable,
433
454
  args: [{
434
455
  providedIn: 'root',
435
456
  }]
436
- }], ctorParameters: function () { return []; } });
457
+ }], ctorParameters: function () { return [{ type: BroadcastService }, { type: ChartService }]; } });
437
458
 
438
459
  const getTextWidth = (inputText, backupRatio = 0.5, fontSize = 10) => {
439
460
  let text = inputText ?? '';
@@ -506,7 +527,7 @@ class ExtremesBuilder {
506
527
  class Axis {
507
528
  constructor(config) {
508
529
  this._extremes = [0, 0];
509
- this._originDomain = [];
530
+ this._originDomain = [0, 0];
510
531
  this.defaultFormatters = new Map()
511
532
  .set(ScaleType.linear, d3.format(',.5~r'))
512
533
  .set(ScaleType.time, d3.timeFormat('%d.%m.%Y'))
@@ -674,22 +695,21 @@ class ScaleService {
674
695
  axis.setScale(scale);
675
696
  axis.setOriginDomain(scale.domain());
676
697
  const hasCache = this.transformCacheX.has(axis.index);
677
- const shouldRestore = zoom?.target?.orientation !== AxisOrientation.x ||
678
- zoom.target?.index !== axis.index;
698
+ const shouldRestore = zoom?.axis?.orientation !== AxisOrientation.x ||
699
+ zoom.axis?.index !== axis.index;
679
700
  if (hasCache && shouldRestore) {
680
701
  const restoredTransform = this.transformCacheX.get(axis.index);
681
702
  axis.setScale(restoredTransform.rescaleX(scale));
682
703
  }
683
704
  });
684
- if (zoom) {
685
- const event = zoom.event;
686
- if (zoom.target?.orientation === AxisOrientation.x) {
687
- if (xAxisMap.has(zoom.target.index)) {
688
- const x = xAxisMap.get(zoom.target.index);
689
- const rescaled = event.transform.rescaleX(x.scale);
705
+ if (zoom && zoom.domain) {
706
+ if (zoom.axis?.orientation === AxisOrientation.x) {
707
+ if (xAxisMap.has(zoom.axis.index)) {
708
+ const x = xAxisMap.get(zoom.axis.index);
709
+ const transform = this.zoomService.getD3Transform(zoom.domain, x.originDomain, x.scale, AxisOrientation.x, x.options.inverted);
710
+ const rescaled = transform.rescaleX(x.scale.copy());
690
711
  x.setScale(rescaled);
691
- const axis = xAxisMap.get(zoom.target.index);
692
- this.transformCacheX.set(axis.index, event.transform);
712
+ this.transformCacheX.set(x.index, transform);
693
713
  }
694
714
  }
695
715
  }
@@ -726,22 +746,21 @@ class ScaleService {
726
746
  axis.setScale(scale);
727
747
  axis.setOriginDomain(scale.domain());
728
748
  const hasCache = this.transformCacheY.has(axis.index);
729
- const shouldRestore = zoom?.target?.orientation !== AxisOrientation.y ||
730
- zoom.target?.index !== axis.index;
749
+ const shouldRestore = zoom?.axis?.orientation !== AxisOrientation.y ||
750
+ zoom.axis?.index !== axis.index;
731
751
  if (hasCache && shouldRestore) {
732
752
  const restoredTransform = this.transformCacheY.get(axis.index);
733
753
  axis.setScale(restoredTransform.rescaleY(scale));
734
754
  }
735
755
  });
736
- if (zoom) {
737
- const event = zoom.event;
738
- if (zoom.target?.orientation === AxisOrientation.y) {
739
- if (yAxisMap.has(zoom.target.index)) {
740
- const y = yAxisMap.get(zoom.target.index);
741
- const rescaled = event.transform.rescaleY(y.scale);
756
+ if (zoom && zoom.domain) {
757
+ if (zoom.axis?.orientation === AxisOrientation.y) {
758
+ if (yAxisMap.has(zoom.axis.index)) {
759
+ const y = yAxisMap.get(zoom.axis.index);
760
+ const transform = this.zoomService.getD3Transform(zoom.domain, y.originDomain, y.scale, AxisOrientation.y, y.options.inverted);
761
+ const rescaled = transform.rescaleY(y.scale.copy());
742
762
  y.setScale(rescaled);
743
- const axis = yAxisMap.get(zoom.target.index);
744
- this.transformCacheY.set(axis.index, event.transform);
763
+ this.transformCacheY.set(y.index, transform);
745
764
  }
746
765
  }
747
766
  }
@@ -764,214 +783,32 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "14.0.2", ngImpor
764
783
  }]
765
784
  }], ctorParameters: function () { return [{ type: ChartService }, { type: ZoomService }]; } });
766
785
 
767
- var BrushType;
768
- (function (BrushType) {
769
- BrushType[BrushType["x"] = 0] = "x";
770
- BrushType[BrushType["y"] = 1] = "y";
771
- BrushType[BrushType["xy"] = 2] = "xy";
772
- })(BrushType || (BrushType = {}));
773
-
774
- class ZoomMessage {
775
- constructor(options) {
776
- this.event = options?.event;
777
- this.axis = options?.axis;
778
- this.domain = options.domain;
779
- this.chartId = options?.chartId;
780
- this.style = options?.style;
781
- }
782
- }
783
- class BrushMessage {
784
- constructor(options) {
785
- this.event = options?.event;
786
- this.brushType = options?.brushType;
787
- this.selection = options?.selection;
788
- this.brushScale = options?.brushScale;
789
- this.style = options?.style;
790
- }
791
- }
792
-
793
- class BroadcastService {
794
- constructor() {
795
- this.zoomEmitter = new Subject();
796
- this.brushEmitter = new ReplaySubject(1);
797
- }
798
- broadcastZoom(value) {
799
- this.zoomEmitter.next(value);
800
- }
801
- broadcastBrush(value) {
802
- this.brushEmitter.next(value);
803
- }
804
- subscribeToZoom(channel) {
805
- return this.zoomEmitter.asObservable().pipe(filter((msg) => channel && msg.channel === channel), shareReplay({
806
- bufferSize: 1,
807
- refCount: true
808
- }));
809
- }
810
- subscribeToBrush(channel) {
811
- return this.brushEmitter.asObservable().pipe(filter((msg) => channel && msg.channel === channel), shareReplay({
812
- bufferSize: 1,
813
- refCount: true
814
- }));
815
- }
816
- }
817
- BroadcastService.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "14.0.2", ngImport: i0, type: BroadcastService, deps: [], target: i0.ɵɵFactoryTarget.Injectable });
818
- BroadcastService.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "14.0.2", ngImport: i0, type: BroadcastService, providedIn: 'root' });
819
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "14.0.2", ngImport: i0, type: BroadcastService, decorators: [{
820
- type: Injectable,
821
- args: [{
822
- providedIn: 'root',
823
- }]
824
- }], ctorParameters: function () { return []; } });
825
-
826
786
  class BrushService {
827
- constructor(broadcastService, zone) {
828
- this.broadcastService = broadcastService;
829
- this.zone = zone;
830
- this.brushMap = new Map()
831
- .set(BrushType.x, d3.brushX())
832
- .set(BrushType.y, d3.brushY());
833
- }
834
- applyBrush(svgElement, config, brushScale) {
835
- this.broadcastSubscribtion?.unsubscribe();
836
- this.brush?.on('start brush end', null);
837
- if (config.brush?.enable) {
838
- this.brush = this.brushMap.get(config?.brush?.type ?? BrushType.x);
839
- const container = d3.select(svgElement.nativeElement);
840
- this.brush.on('start brush end', (_) => {
841
- if (_.sourceEvent) {
842
- if (!_.selection)
843
- return;
844
- const [from, to] = _.selection;
845
- if (to - from === 0) {
846
- const selection = this.selection?.map(brushScale) ??
847
- [config.brush?.from, config.brush?.to].map(brushScale);
848
- const halfBrushHeight = (selection[1] - selection[0]) / 2;
849
- const invertedSelection = [
850
- from - halfBrushHeight,
851
- to + halfBrushHeight,
852
- ].map(brushScale.invert);
853
- if (invertedSelection[1] - invertedSelection[0] >
854
- config.brush?.max) {
855
- container.call(this.brush.move, [
856
- Math.floor(invertedSelection[0]),
857
- Math.floor(invertedSelection[0] + config.brush?.max),
858
- ].map(brushScale));
859
- return;
860
- }
861
- if (invertedSelection[1] - invertedSelection[0] <
862
- config.brush?.min) {
863
- container.call(this.brush.move, [
864
- Math.floor(invertedSelection[0]),
865
- Math.ceil(invertedSelection[0] + config.brush?.min),
866
- ].map(brushScale));
867
- return;
868
- }
869
- container.call(this.brush.move, [
870
- from - halfBrushHeight,
871
- to + halfBrushHeight,
872
- ]);
873
- return;
874
- }
875
- if (brushScale.invert(to) - brushScale.invert(from) >
876
- config.brush?.max) {
877
- container.call(this.brush.move, this.selection
878
- ? [
879
- this.selection[0],
880
- this.selection[0] + config.brush?.max,
881
- ].map(brushScale)
882
- : [config.brush?.from, config.brush?.to].map(brushScale));
883
- return;
884
- }
885
- if (brushScale.invert(to) - brushScale.invert(from) <
886
- config.brush?.min) {
887
- container.call(this.brush.move, this.selection
888
- ? [
889
- this.selection[0],
890
- this.selection[0] + config.brush?.min,
891
- ].map(brushScale)
892
- : [config.brush?.from, config.brush?.to].map(brushScale));
893
- return;
894
- }
895
- if (_.sourceEvent instanceof MouseEvent) {
896
- this.selection = _.selection.map(brushScale.invert);
897
- }
898
- const brushMessage = new BrushMessage({
899
- event: _,
900
- selection: [brushScale.invert(from), brushScale.invert(to)],
901
- brushType: config?.brush?.type ?? BrushType.x,
902
- brushScale,
903
- });
904
- this.broadcastService.broadcastBrush({
905
- channel: config?.zoom?.syncChannel,
906
- message: brushMessage,
907
- });
908
- }
909
- });
910
- this.zone.runOutsideAngular(() => {
911
- setTimeout(() => {
912
- container.call(this.brush);
913
- let domain = brushScale.domain();
914
- if (config?.brush?.from) {
915
- domain[0] = config.brush.from;
916
- }
917
- if (config?.brush?.to) {
918
- domain[1] = config.brush.to;
919
- }
920
- container.call(this.brush.move, this.selection
921
- ? this.selection.map(brushScale)
922
- : domain.map(brushScale), {});
923
- }, 0);
924
- });
925
- this.broadcastSubscribtion = this.broadcastService
926
- .subscribeToZoom(config?.zoom?.syncChannel)
927
- .pipe(filter((m) => {
928
- return (m.message.event.sourceEvent instanceof MouseEvent ||
929
- m.message.event.sourceEvent instanceof WheelEvent ||
930
- (window.TouchEvent &&
931
- m.message.event.sourceEvent instanceof TouchEvent));
932
- }), tap((m) => {
933
- const { message: { domain }, } = m;
934
- if ((m.message?.axis.index === 0 &&
935
- m.message?.axis.orientation === AxisOrientation.y &&
936
- config.brush?.type === BrushType.y) ||
937
- (m.message?.axis.orientation === AxisOrientation.x &&
938
- config.brush?.type === BrushType.x)) {
939
- container.call(this.brush.move, [
940
- brushScale(domain[0]),
941
- brushScale(domain[1]),
942
- ]);
943
- this.selection = domain;
944
- }
945
- }), debounceTime(30), tap((m) => {
946
- const { message: { domain }, } = m;
947
- if (m.message.event.type === 'zoom') {
948
- const brushMessage = new BrushMessage({
949
- event: null,
950
- selection: domain,
951
- brushType: config?.brush?.type ?? BrushType.x,
952
- brushScale,
953
- });
954
- this.broadcastService.broadcastBrush({
955
- channel: config?.zoom?.syncChannel,
956
- message: brushMessage,
957
- });
958
- }
959
- }))
960
- .subscribe();
961
- }
787
+ // private _outBrushDomain = new ReplaySubject<[number, number]>(1);
788
+ constructor() {
789
+ // outBrushDomain: Observable<[number, number]>;
790
+ this._brushDomain = new ReplaySubject(1);
791
+ this.brushDomain = this._brushDomain.asObservable();
962
792
  }
963
- clearPreviousSelection() {
964
- this.selection = null;
793
+ setBrush(brush) {
794
+ this._brushDomain.next(brush);
965
795
  }
966
796
  }
967
- BrushService.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "14.0.2", ngImport: i0, type: BrushService, deps: [{ token: BroadcastService }, { token: i0.NgZone }], target: i0.ɵɵFactoryTarget.Injectable });
797
+ BrushService.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "14.0.2", ngImport: i0, type: BrushService, deps: [], target: i0.ɵɵFactoryTarget.Injectable });
968
798
  BrushService.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "14.0.2", ngImport: i0, type: BrushService, providedIn: 'root' });
969
799
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "14.0.2", ngImport: i0, type: BrushService, decorators: [{
970
800
  type: Injectable,
971
801
  args: [{
972
802
  providedIn: 'root',
973
803
  }]
974
- }], ctorParameters: function () { return [{ type: BroadcastService }, { type: i0.NgZone }]; } });
804
+ }], ctorParameters: function () { return []; } });
805
+
806
+ var BrushType;
807
+ (function (BrushType) {
808
+ BrushType[BrushType["x"] = 0] = "x";
809
+ BrushType[BrushType["y"] = 1] = "y";
810
+ BrushType[BrushType["xy"] = 2] = "xy";
811
+ })(BrushType || (BrushType = {}));
975
812
 
976
813
  class SeriesBaseComponent {
977
814
  constructor(svc, cdr, scaleService, zoomService, element, zone) {
@@ -1023,7 +860,7 @@ class LinearSeriesBase extends SeriesBaseComponent {
1023
860
  }
1024
861
  set series(series) {
1025
862
  this.__series = series;
1026
- this.markers = this.__series.data?.filter((_) => _?.marker);
863
+ this.markers = this.__series.data?.filter((_) => _?.marker && _?.x !== undefined && _?.y !== undefined);
1027
864
  }
1028
865
  get series() {
1029
866
  return this.__series;
@@ -1060,7 +897,6 @@ class LinearSeriesBase extends SeriesBaseComponent {
1060
897
  return this.getTransform(event, x.get(this.series.xAxisIndex).scale, y.get(this.series.yAxisIndex).scale);
1061
898
  }), tap(() => setTimeout(() => this.cdr.detectChanges())));
1062
899
  this.path = combineLatest([this.scaleService.scales, this._update]).pipe(map(([data]) => {
1063
- // console.log(data);
1064
900
  const { x, y } = data;
1065
901
  this.x = x.get(this.series.xAxisIndex)?.scale;
1066
902
  this.y = y.get(this.series.yAxisIndex)?.scale;
@@ -1092,17 +928,9 @@ class LinearSeriesBase extends SeriesBaseComponent {
1092
928
  filteredData = filteredData?.filter(filter(min, max));
1093
929
  }
1094
930
  return line(filteredData);
1095
- }), tap((_) => {
1096
- // console.log(_)
1097
- setTimeout(() => {
1098
- if (this.markers?.length > 0) {
1099
- // this.addDragEvents();
1100
- }
1101
- });
1102
931
  }));
1103
932
  }
1104
933
  ngOnDestroy() {
1105
- // this.markerListeners?.on('start drag end', null);
1106
934
  this.svc.setTooltip({
1107
935
  point: null,
1108
936
  series: this.series,
@@ -1110,65 +938,6 @@ class LinearSeriesBase extends SeriesBaseComponent {
1110
938
  }
1111
939
  ngAfterViewInit() {
1112
940
  }
1113
- addDragEvents() {
1114
- // this.markerListeners?.on('start drag end', null);
1115
- // const drag = (node, event: d3.D3DragEvent<any, any, any>, d: BasePoint) => {
1116
- // if (
1117
- // d.marker?.dragType === DragPointType.x ||
1118
- // d.marker?.dragType === DragPointType.xy
1119
- // ) {
1120
- // d.x = this.x.invert(event.x);
1121
- // }
1122
- //
1123
- // if (
1124
- // d.marker?.dragType === DragPointType.y ||
1125
- // d.marker?.dragType === DragPointType.xy
1126
- // ) {
1127
- // d.y = this.y.invert(event.y);
1128
- // }
1129
- //
1130
- // this.svc.emitPoint({
1131
- // target: {
1132
- // series: this.series,
1133
- // point: d,
1134
- // },
1135
- // event,
1136
- // });
1137
- //
1138
- // this.cdr.detectChanges();
1139
- // };
1140
- // this.markerListeners = d3
1141
- // .drag()
1142
- // .subject(function (event, d: BasePoint) {
1143
- // const node = d3.select(this);
1144
- // return {x: node.attr('cx'), y: node.attr('cy')};
1145
- // });
1146
- // const dragMarkers =
1147
- // this.markerListeners.on(
1148
- // 'start drag end',
1149
- // function (event: d3.D3DragEvent<any, any, any>, d: BasePoint) {
1150
- // const node = d3.select(this);
1151
- //
1152
- // drag(node, event, d);
1153
- // }
1154
- // );
1155
- //
1156
- // const draggableMarkers = this.series.data?.filter(
1157
- // (_) => _?.marker && _?.marker?.draggable
1158
- // );
1159
- //
1160
- // const element = d3
1161
- // .select(this.element.nativeElement)
1162
- // .selectAll('.draggable-marker')
1163
- // .data(draggableMarkers);
1164
- //
1165
- // element.call(dragMarkers as any);
1166
- //
1167
- // this.svgElement = d3
1168
- // .select(this.element.nativeElement)
1169
- // .select('.line')
1170
- // .node() as SVGGeometryElement;
1171
- }
1172
941
  getTransform(event, scaleX, scaleY) {
1173
942
  if (event.type === 'mouseleave') {
1174
943
  return null;
@@ -1205,7 +974,7 @@ class LinearSeriesBase extends SeriesBaseComponent {
1205
974
  }
1206
975
  const rightId = bisect(this.series.data, x0);
1207
976
  const range = scaleY.range();
1208
- const intersect = lineIntersection(pointer, range[0], pointer, range[1], scaleX(this.series.data[rightId - 1]?.x), scaleY(this.series.data[rightId - 1]?.y), scaleX(this.series.data[rightId]?.x), scaleY(this.series.data[rightId]?.y));
977
+ const intersect = lineIntersection(pointer, range[0], pointer, Number.MAX_SAFE_INTEGER, scaleX(this.series.data[rightId - 1]?.x), scaleY(this.series.data[rightId - 1]?.y), scaleX(this.series.data[rightId]?.x), scaleY(this.series.data[rightId]?.y));
1209
978
  const x = scaleX.invert(intersect.x);
1210
979
  const y = scaleY.invert(intersect.y);
1211
980
  if (x !== null && x !== undefined && !isNaN(x) && y !== null && y !== undefined && !isNaN(y)) {
@@ -1233,7 +1002,7 @@ class LinearSeriesBase extends SeriesBaseComponent {
1233
1002
  }
1234
1003
  const rightId = bisect(this.series.data, y0);
1235
1004
  const range = scaleX.range();
1236
- const intersect = lineIntersection(range[0], mouse[1], range[1], mouse[1], scaleX(this.series.data[rightId - 1]?.x), scaleY(this.series.data[rightId - 1]?.y), scaleX(this.series.data[rightId]?.x), scaleY(this.series.data[rightId]?.y));
1005
+ const intersect = lineIntersection(range[0], mouse[1], Number.MAX_SAFE_INTEGER, mouse[1], scaleX(this.series.data[rightId - 1]?.x), scaleY(this.series.data[rightId - 1]?.y), scaleX(this.series.data[rightId]?.x), scaleY(this.series.data[rightId]?.y));
1237
1006
  const x = scaleX.invert(intersect.x);
1238
1007
  const y = scaleY.invert(intersect.y);
1239
1008
  if (x !== null && x !== undefined && !isNaN(x) && y !== null && y !== undefined && !isNaN(y)) {
@@ -1308,6 +1077,7 @@ class DraggablePointDirective {
1308
1077
  deltaX,
1309
1078
  deltaY
1310
1079
  })) {
1080
+ this.startPosition = null;
1311
1081
  return;
1312
1082
  }
1313
1083
  if (this.transformCache) {
@@ -1426,7 +1196,7 @@ class LineSeriesComponent extends LinearSeriesBase {
1426
1196
  }
1427
1197
  }
1428
1198
  if (point.marker.maxX !== null && point.marker.maxX !== undefined) {
1429
- if (this.x.invert(this.x(this.start.x) + newPoint.deltaX) > point.marker.minX) {
1199
+ if (this.x.invert(this.x(this.start.x) + newPoint.deltaX) > point.marker.maxX) {
1430
1200
  return false;
1431
1201
  }
1432
1202
  }
@@ -1488,10 +1258,10 @@ class LineSeriesComponent extends LinearSeriesBase {
1488
1258
  }
1489
1259
  }
1490
1260
  LineSeriesComponent.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "14.0.2", ngImport: i0, type: LineSeriesComponent, deps: [{ token: ChartService }, { token: i0.ChangeDetectorRef }, { token: ScaleService }, { token: ZoomService }, { token: i0.ElementRef }], target: i0.ɵɵFactoryTarget.Component });
1491
- LineSeriesComponent.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "14.0.2", type: LineSeriesComponent, selector: "svg:svg[teta-line-series]", usesInheritance: true, ngImport: i0, template: "<svg:path\n class=\"line\"\n [attr.d]=\"path | async\"\n [attr.stroke]=\"series.color\"\n [attr.stroke-dasharray]=\"series.style?.strokeDasharray\"\n [attr.stroke-width]=\"series.style?.strokeWidth\"\n fill=\"none\">\n</svg:path>\n<ng-container *ngIf=\"transform | async as t\">\n <svg:circle\n *ngIf=\"t?.x !=null && t?.y!=null\"\n r=\"3\"\n [attr.fill]=\"series.color\"\n [attr.transform]=\"'translate('+ t.x +', '+ t.y +')'\"\n >\n </svg:circle>\n</ng-container>\n<ng-container *ngIf=\"markers as draggablePoints\">\n <svg:g\n *ngFor=\"let point of draggablePoints\"\n [attr.transform]=\"'translate(' + x(point.x)+ ',' +y(point.y) + ')'\">\n <svg:g [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 <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 <ng-container *ngIf=\"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 <div\n #annotationNode\n class=\"shadow-2 padding-2\"\n [style.color]=\"'var(--color-text-90)'\"\n [style.background-color]=\"'var(--color-background-50)'\"\n [style.cursor]=\"'move'\"\n style=\"border-radius: 2px; display: inline-block;\">\n {{point.marker.label?.text}}\n </div>\n </svg:foreignObject>\n </ng-container>\n </svg:g>\n </svg:g>\n</ng-container>\n\n\n\n", styles: [".draggable-marker{cursor:move}.active{stroke-opacity:.5}.marker-grab{opacity:0}\n"], dependencies: [{ kind: "directive", type: i4.NgForOf, selector: "[ngFor][ngForOf]", inputs: ["ngForOf", "ngForTrackBy", "ngForTemplate"] }, { kind: "directive", type: i4.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { kind: "directive", type: DraggablePointDirective, selector: "[tetaDraggablePoint]", inputs: ["tetaDraggablePoint", "dragDirection", "allowDrag"], outputs: ["moveStart", "moveProcess", "moveEnd"], exportAs: ["tetaDraggablePoint"] }, { kind: "pipe", type: i4.AsyncPipe, name: "async" }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
1261
+ LineSeriesComponent.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "14.0.2", type: LineSeriesComponent, selector: "svg:svg[teta-line-series]", usesInheritance: true, ngImport: i0, template: "<svg:path\n class=\"line\"\n [attr.d]=\"path | async\"\n [attr.stroke]=\"series.color\"\n [attr.stroke-dasharray]=\"series.style?.strokeDasharray\"\n [attr.stroke-width]=\"series.style?.strokeWidth\"\n fill=\"none\">\n</svg:path>\n<ng-container *ngIf=\"transform | async as t\">\n <svg:circle\n *ngIf=\"t?.x !=null && t?.y!=null\"\n r=\"3\"\n [attr.fill]=\"series.color\"\n [attr.transform]=\"'translate('+ t.x +', '+ t.y +')'\"\n >\n </svg:circle>\n</ng-container>\n<ng-container *ngIf=\"markers as draggablePoints\">\n <ng-container *ngIf=\"x && y\">\n <svg:g\n *ngFor=\"let point of draggablePoints\"\n [attr.transform]=\"'translate(' + x(point.x) + ',' + y(point.y) + ')'\">\n <svg:g [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 <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 <ng-container *ngIf=\"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 <div\n #annotationNode\n class=\"shadow-2 padding-2\"\n [style.color]=\"'var(--color-text-90)'\"\n [style.background-color]=\"'var(--color-background-50)'\"\n [style.cursor]=\"'move'\"\n style=\"border-radius: 2px; display: inline-block;\">\n {{point.marker.label?.text}}\n </div>\n </svg:foreignObject>\n </ng-container>\n </svg:g>\n </svg:g>\n </ng-container>\n\n</ng-container>\n\n\n\n", styles: [".draggable-marker{cursor:move}.active{stroke-opacity:.5}.marker-grab{opacity:0}\n"], dependencies: [{ kind: "directive", type: i4.NgForOf, selector: "[ngFor][ngForOf]", inputs: ["ngForOf", "ngForTrackBy", "ngForTemplate"] }, { kind: "directive", type: i4.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { kind: "directive", type: DraggablePointDirective, selector: "[tetaDraggablePoint]", inputs: ["tetaDraggablePoint", "dragDirection", "allowDrag"], outputs: ["moveStart", "moveProcess", "moveEnd"], exportAs: ["tetaDraggablePoint"] }, { kind: "pipe", type: i4.AsyncPipe, name: "async" }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
1492
1262
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "14.0.2", ngImport: i0, type: LineSeriesComponent, decorators: [{
1493
1263
  type: Component,
1494
- args: [{ selector: 'svg:svg[teta-line-series]', changeDetection: ChangeDetectionStrategy.OnPush, template: "<svg:path\n class=\"line\"\n [attr.d]=\"path | async\"\n [attr.stroke]=\"series.color\"\n [attr.stroke-dasharray]=\"series.style?.strokeDasharray\"\n [attr.stroke-width]=\"series.style?.strokeWidth\"\n fill=\"none\">\n</svg:path>\n<ng-container *ngIf=\"transform | async as t\">\n <svg:circle\n *ngIf=\"t?.x !=null && t?.y!=null\"\n r=\"3\"\n [attr.fill]=\"series.color\"\n [attr.transform]=\"'translate('+ t.x +', '+ t.y +')'\"\n >\n </svg:circle>\n</ng-container>\n<ng-container *ngIf=\"markers as draggablePoints\">\n <svg:g\n *ngFor=\"let point of draggablePoints\"\n [attr.transform]=\"'translate(' + x(point.x)+ ',' +y(point.y) + ')'\">\n <svg:g [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 <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 <ng-container *ngIf=\"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 <div\n #annotationNode\n class=\"shadow-2 padding-2\"\n [style.color]=\"'var(--color-text-90)'\"\n [style.background-color]=\"'var(--color-background-50)'\"\n [style.cursor]=\"'move'\"\n style=\"border-radius: 2px; display: inline-block;\">\n {{point.marker.label?.text}}\n </div>\n </svg:foreignObject>\n </ng-container>\n </svg:g>\n </svg:g>\n</ng-container>\n\n\n\n", styles: [".draggable-marker{cursor:move}.active{stroke-opacity:.5}.marker-grab{opacity:0}\n"] }]
1264
+ args: [{ selector: 'svg:svg[teta-line-series]', changeDetection: ChangeDetectionStrategy.OnPush, template: "<svg:path\n class=\"line\"\n [attr.d]=\"path | async\"\n [attr.stroke]=\"series.color\"\n [attr.stroke-dasharray]=\"series.style?.strokeDasharray\"\n [attr.stroke-width]=\"series.style?.strokeWidth\"\n fill=\"none\">\n</svg:path>\n<ng-container *ngIf=\"transform | async as t\">\n <svg:circle\n *ngIf=\"t?.x !=null && t?.y!=null\"\n r=\"3\"\n [attr.fill]=\"series.color\"\n [attr.transform]=\"'translate('+ t.x +', '+ t.y +')'\"\n >\n </svg:circle>\n</ng-container>\n<ng-container *ngIf=\"markers as draggablePoints\">\n <ng-container *ngIf=\"x && y\">\n <svg:g\n *ngFor=\"let point of draggablePoints\"\n [attr.transform]=\"'translate(' + x(point.x) + ',' + y(point.y) + ')'\">\n <svg:g [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 <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 <ng-container *ngIf=\"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 <div\n #annotationNode\n class=\"shadow-2 padding-2\"\n [style.color]=\"'var(--color-text-90)'\"\n [style.background-color]=\"'var(--color-background-50)'\"\n [style.cursor]=\"'move'\"\n style=\"border-radius: 2px; display: inline-block;\">\n {{point.marker.label?.text}}\n </div>\n </svg:foreignObject>\n </ng-container>\n </svg:g>\n </svg:g>\n </ng-container>\n\n</ng-container>\n\n\n\n", styles: [".draggable-marker{cursor:move}.active{stroke-opacity:.5}.marker-grab{opacity:0}\n"] }]
1495
1265
  }], ctorParameters: function () { return [{ type: ChartService }, { type: i0.ChangeDetectorRef }, { type: ScaleService }, { type: ZoomService }, { type: i0.ElementRef }]; } });
1496
1266
 
1497
1267
  class BarSeriesComponent extends SeriesBaseComponent {
@@ -1960,7 +1730,9 @@ class PlotBandComponent {
1960
1730
  this.element = element;
1961
1731
  this.orientation = AxisOrientation;
1962
1732
  this.getTextPosition = () => {
1963
- const [min, max] = this.scale.domain();
1733
+ let [min, max] = this.scale.domain();
1734
+ min = min instanceof Date ? min.getTime() : min;
1735
+ max = max instanceof Date ? max.getTime() : max;
1964
1736
  const position = ((this.plotBand.from <= min ? min : this.plotBand.from) + (this.plotBand.to >= max ? max : this.plotBand.to)) / 2;
1965
1737
  return this.scale(position);
1966
1738
  };
@@ -2187,11 +1959,27 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "14.0.2", ngImpor
2187
1959
  args: ['tooltip', { static: false, read: ElementRef }]
2188
1960
  }] } });
2189
1961
 
1962
+ class ZoomMessage {
1963
+ constructor(options) {
1964
+ this.eventType = options?.eventType;
1965
+ this.element = options?.element;
1966
+ this.axis = options?.axis;
1967
+ this.domain = options.domain;
1968
+ this.chartId = options?.chartId;
1969
+ this.style = options?.style;
1970
+ }
1971
+ }
1972
+ class BrushMessage {
1973
+ constructor(options) {
1974
+ this.chartId = options?.chartId;
1975
+ this.selection = options?.selection;
1976
+ }
1977
+ }
1978
+
2190
1979
  class ZoomableDirective {
2191
- constructor(elementRef, zoomService, broadcastService, chartService, zone) {
1980
+ constructor(elementRef, zoomService, chartService, zone) {
2192
1981
  this.elementRef = elementRef;
2193
1982
  this.zoomService = zoomService;
2194
- this.broadcastService = broadcastService;
2195
1983
  this.chartService = chartService;
2196
1984
  this.zone = zone;
2197
1985
  this.zoomable = false;
@@ -2201,28 +1989,23 @@ class ZoomableDirective {
2201
1989
  this.zoomed = (event) => {
2202
1990
  if (event.sourceEvent) {
2203
1991
  if (Object.keys(event.sourceEvent).length !== 0) {
2204
- if (this.currentTransform === event.transform) {
2205
- return;
2206
- }
2207
- const origin = this.brushScale.copy().domain(this.axis.extremes);
2208
- let domain = this.config.zoom?.type === ZoomType.y
1992
+ const origin = this.axis.scale.copy().domain(this.axis.originDomain);
1993
+ let domain = this.axis.orientation === AxisOrientation.y
2209
1994
  ? event.transform.rescaleY(origin).domain()
2210
1995
  : event.transform.rescaleX(origin).domain();
2211
1996
  const message = new ZoomMessage({
2212
- event,
2213
- axis: this.axis,
2214
- domain,
2215
- chartId: this.config.id,
2216
- });
2217
- this.broadcastService.broadcastZoom({
2218
- channel: this.config?.zoom?.syncChannel,
2219
- message,
1997
+ eventType: event.type,
1998
+ axis: {
1999
+ index: this.axis.index,
2000
+ orientation: this.axis.orientation,
2001
+ },
2002
+ element: this.elementRef,
2003
+ domain: domain,
2004
+ chartId: this.config.id
2220
2005
  });
2006
+ this.zoomService.fireZoom(message);
2007
+ this.zoomService.broadcastZoom(message);
2221
2008
  }
2222
- this.zoomService.fireZoom({
2223
- event,
2224
- target: this.axis,
2225
- });
2226
2009
  this.currentTransform = event.transform;
2227
2010
  }
2228
2011
  };
@@ -2233,160 +2016,77 @@ class ZoomableDirective {
2233
2016
  this.crosshair = this.config?.tooltip?.showCrosshair;
2234
2017
  }
2235
2018
  }
2236
- ngOnChanges(changes) {
2237
- if (changes.hasOwnProperty('brushScale') || changes.hasOwnProperty('scale') || changes.hasOwnProperty('axis')) {
2238
- if (this.hash) {
2239
- this.zoomService.scaleHashMap.set(this.hash, this.scale);
2240
- this.zoomService.axisHashMap.set(this.hash, this.axis);
2019
+ ngAfterViewInit() {
2020
+ this.initZoomListeners();
2021
+ this.initZoomSync();
2022
+ }
2023
+ ngOnDestroy() {
2024
+ this.zoom?.on('start zoom end', null);
2025
+ this._element?.on('wheel', null);
2026
+ this.alive = false;
2027
+ }
2028
+ initZoomSync() {
2029
+ this.zoomService.zoomed.pipe(takeWhile(() => this.alive)).subscribe((zoomed) => {
2030
+ if (this._element && this.elementRef !== zoomed?.element
2031
+ && zoomed?.axis?.index === this.axis.index
2032
+ && zoomed?.axis?.orientation === this.axis.orientation) {
2033
+ const scale = this.axis.scale.copy().domain(this.axis.originDomain);
2034
+ let transform;
2035
+ if (zoomed.domain === null) {
2036
+ transform = zoomIdentity;
2037
+ }
2038
+ else {
2039
+ transform =
2040
+ this.zoomService.getD3Transform(zoomed.domain, this.axis.originDomain, scale, this.axis.orientation, this.axis.options.inverted);
2041
+ }
2042
+ if (zoomed.style?.transition) {
2043
+ this._element.transition().call(this.zoom.transform, transform);
2044
+ }
2045
+ else {
2046
+ this._element.call(this.zoom.transform, transform);
2047
+ }
2048
+ this.currentTransform = transform;
2241
2049
  }
2242
- }
2050
+ });
2243
2051
  }
2244
- ngAfterViewInit() {
2052
+ initZoomListeners() {
2245
2053
  const enable = (this.axis?.options?.zoom && this.axis?.options.visible !== false) ||
2246
2054
  this.config?.zoom?.enable;
2247
2055
  if (!enable) {
2248
2056
  return;
2249
2057
  }
2250
- if (enable) {
2251
- this._element = d3.select(this.elementRef.nativeElement);
2252
- this.hash = objectHash.sha1({ index: this.axis.index, orientation: this.axis.orientation });
2253
- this.zoom = d3.zoom().extent([
2058
+ this._element = d3.select(this.elementRef.nativeElement);
2059
+ this.zoom = d3.zoom().extent([
2060
+ [0, 0],
2061
+ [this.size.width, this.size.height],
2062
+ ]);
2063
+ if (this.config.zoom?.limitTranslateByData) {
2064
+ this.zoom.translateExtent([
2254
2065
  [0, 0],
2255
2066
  [this.size.width, this.size.height],
2256
2067
  ]);
2257
- if (this.config.zoom?.limitTranslateByData) {
2258
- this.zoom.translateExtent([
2259
- [0, 0],
2260
- [this.size.width, this.size.height],
2261
- ]);
2262
- }
2263
- if (this.config.zoom?.wheelDelta) {
2264
- this.zoom.wheelDelta(this.config.zoom?.wheelDelta);
2265
- }
2266
- this.zoomService.axisHashMap.set(this.hash, this.axis);
2267
- this.zoomService.elementHashMap.set(this.hash, this._element);
2268
- this.zoomService.scaleHashMap.set(this.hash, this.scale);
2269
- this.zoomService.zoomHashMap.set(this.hash, this.zoom);
2270
- this.zoomService.setBroadcastChannel(this.config?.zoom.syncChannel);
2271
- const maxZoom = this.config.zoom?.max
2272
- ? (this.axis.extremes[1] - this.axis.extremes[0]) /
2273
- this.config.zoom?.max
2274
- : this.config.zoom?.limitZoomByData
2275
- ? 1
2276
- : 0;
2277
- const minZoom = this.config.zoom?.min
2278
- ? (this.axis.extremes[1] - this.axis.extremes[0]) /
2279
- this.config.zoom?.min
2280
- : Infinity;
2281
- this.zoom.scaleExtent([maxZoom, minZoom]);
2282
- this.zoom.on('zoom end', this.zoomed);
2283
- this._element.call(this.zoom).on('dblclick.zoom', null); // Disable dbclick zoom
2284
- this.zone.runOutsideAngular(() => {
2285
- setTimeout(() => {
2286
- this.chartService.emitZoomInstance(this.zoomService);
2287
- });
2288
- });
2289
- if (this.config?.zoom?.zoomBehavior === ZoomBehaviorType.wheel) {
2290
- this.runWheelZoom();
2291
- }
2292
2068
  }
2293
- // Subscribe to zoom events
2294
- this.broadcastService.subscribeToZoom(this.config?.zoom.syncChannel).pipe(takeWhile((_) => this.alive), tap$1((m) => {
2295
- if (this.axis.index === m.message?.axis?.index && this.axis.orientation === m.message?.axis?.orientation) {
2296
- const currentZoom = d3.zoomTransform(this._element.node());
2297
- if (currentZoom !== m.message.event.transform && this.config.id === m.message?.chartId) {
2298
- this._element.call(this.zoom.transform, m.message.event.transform);
2299
- }
2300
- }
2301
- }), filter((m) => m.message.event.sourceEvent instanceof MouseEvent ||
2302
- m.message.event.sourceEvent instanceof WheelEvent ||
2303
- (window.TouchEvent &&
2304
- m.message.event.sourceEvent instanceof TouchEvent)), filter((m) => {
2305
- return (this.axis.index === m.message?.axis?.index &&
2306
- this.axis.orientation === m.message?.axis?.orientation);
2307
- }), tap$1((m) => {
2308
- if (this.config.id !== m.message?.chartId) {
2309
- this.brushScale.domain(this.axis.originDomain);
2310
- const scale = Math.abs(this.axis.originDomain[1] - this.axis.originDomain[0]) / Math.abs(m.message.domain[1] - m.message.domain[0]);
2311
- let transform = zoomIdentity.scale(scale);
2312
- if (this.config?.zoom?.type === ZoomType.x) {
2313
- if (this.config.xAxis[0]?.inverted) {
2314
- transform = transform.translate(this.brushScale(-m.message.domain[1]), 0);
2315
- }
2316
- else {
2317
- transform = transform.translate(-this.brushScale(m.message.domain[0]), 0);
2318
- }
2319
- }
2320
- if (this.config?.zoom?.type === ZoomType.y) {
2321
- if (this.config.yAxis[0]?.inverted) {
2322
- transform = transform.translate(0, -this.brushScale(m.message.domain[0]));
2323
- }
2324
- else {
2325
- transform = transform.translate(0, -this.brushScale(m.message.domain[1]));
2326
- }
2327
- }
2328
- this._element.call(this.zoom.transform, transform, null, {});
2329
- }
2330
- }))
2331
- .subscribe();
2332
- // Subscribe to brush events x or y
2333
- if ((this.config.brush?.type === BrushType.x &&
2334
- this.axis.orientation === AxisOrientation.x) ||
2335
- (this.config.brush?.type === BrushType.y &&
2336
- this.axis.orientation === AxisOrientation.y)) {
2337
- this.broadcastService.subscribeToBrush(this.config?.zoom.syncChannel)
2338
- .pipe(combineLatestWith(this.chartService.size), takeWhile((_) => this.alive), filter((data) => {
2339
- const [m] = data;
2340
- return Boolean(m.message.selection);
2341
- }), tap$1((data) => {
2342
- const [m] = data;
2343
- const currentTransform = d3.zoomTransform(this._element.node());
2344
- if (!m.message.event &&
2345
- this.currentSelection &&
2346
- currentTransform.k !== 1) {
2347
- return;
2348
- }
2349
- const s = m.message.selection;
2350
- this.brushScale.domain(this.axis.originDomain);
2351
- const domain = this.brushScale.domain();
2352
- const range = this.brushScale.range();
2353
- const scale = Math.abs(domain[1] - domain[0]) / Math.abs(s[1] - s[0]);
2354
- let transform = zoomIdentity.scale(scale);
2355
- if (m.message?.brushType === BrushType.x) {
2356
- this.brushScale.range([range[0], this.size.width]);
2357
- if (this.config.xAxis[0]?.inverted) {
2358
- transform = transform.translate(-this.brushScale(s[0]), 0);
2359
- }
2360
- else {
2361
- transform = transform.translate(-this.brushScale(s[1]), 0);
2362
- }
2363
- }
2364
- if (m.message?.brushType === BrushType.y) {
2365
- this.brushScale.range([range[0], this.size.height]);
2366
- if (this.config.yAxis[0]?.inverted) {
2367
- transform = transform.translate(0, -this.brushScale(s[0]));
2368
- }
2369
- else {
2370
- transform = transform.translate(0, -this.brushScale(s[1]));
2371
- }
2372
- }
2373
- if (m.message?.style?.transition) {
2374
- this._element.transition().call(this.zoom.transform, transform, null, {});
2375
- }
2376
- else {
2377
- this._element.call(this.zoom.transform, transform, null, {});
2378
- }
2379
- this.currentSelection = m.message.selection;
2380
- }))
2381
- .subscribe();
2069
+ if (this.config.zoom?.wheelDelta) {
2070
+ this.zoom.wheelDelta(this.config.zoom?.wheelDelta);
2071
+ }
2072
+ const maxZoom = this.config.zoom?.max
2073
+ ? (this.axis.extremes[1] - this.axis.extremes[0]) /
2074
+ this.config.zoom?.max
2075
+ : this.config.zoom?.limitZoomByData
2076
+ ? 1
2077
+ : 0;
2078
+ const minZoom = this.config.zoom?.min
2079
+ ? (this.axis.extremes[1] - this.axis.extremes[0]) /
2080
+ this.config.zoom?.min
2081
+ : Infinity;
2082
+ this.zoom.scaleExtent([maxZoom, minZoom]);
2083
+ this.zoom.on('zoom end', this.zoomed);
2084
+ this._element.call(this.zoom).on('dblclick.zoom', null); // Disable dbclick zoom
2085
+ if (this.config?.zoom?.zoomBehavior === ZoomBehaviorType.wheel) {
2086
+ this.runWheelTranslate();
2382
2087
  }
2383
2088
  }
2384
- ngOnDestroy() {
2385
- this.zoom?.on('start zoom end', null);
2386
- this._element?.on('wheel', null);
2387
- this.alive = false;
2388
- }
2389
- runWheelZoom() {
2089
+ runWheelTranslate() {
2390
2090
  let type = 'start';
2391
2091
  let wheeling;
2392
2092
  this.zoom
@@ -2401,47 +2101,37 @@ class ZoomableDirective {
2401
2101
  return delta * 0.002;
2402
2102
  });
2403
2103
  const emit = (type, event) => {
2404
- const origin = this.brushScale.copy().domain(this.axis.extremes);
2104
+ const origin = this.axis.scale.copy().domain(this.axis.originDomain);
2405
2105
  let transform = zoomIdentity;
2406
2106
  const delta = type === 'end'
2407
2107
  ? 0
2408
- : this.config.zoom?.type === ZoomType.y
2108
+ : this.axis.orientation === AxisOrientation.y
2409
2109
  ? event.deltaY
2410
2110
  : event.deltaX;
2411
- if (this.config.zoom?.type === ZoomType.y) {
2111
+ if (this.axis.orientation === AxisOrientation.y) {
2412
2112
  transform = transform.translate(0, this.currentTransform.y - delta / 2);
2413
2113
  }
2414
- if (this.config.zoom?.type === ZoomType.x) {
2114
+ if (this.axis.orientation === AxisOrientation.x) {
2415
2115
  transform = transform.translate(this.currentTransform.x - delta / 2, 0);
2416
2116
  }
2417
2117
  transform = transform.scale(this.currentTransform.k);
2418
- let domain = this.config.zoom?.type === ZoomType.y
2118
+ let domain = this.axis.orientation === AxisOrientation.y
2419
2119
  ? transform.rescaleY(origin).domain()
2420
2120
  : transform.rescaleX(origin).domain();
2421
2121
  const message = new ZoomMessage({
2422
- event: {
2423
- sourceEvent: event,
2424
- transform,
2425
- type,
2122
+ eventType: type,
2123
+ element: this.elementRef,
2124
+ axis: {
2125
+ index: this.axis.index,
2126
+ orientation: this.axis.orientation
2426
2127
  },
2427
- axis: this.axis,
2428
2128
  domain,
2429
2129
  chartId: this.config.id,
2430
2130
  });
2431
- this.zoomService.fireZoom({
2432
- event: {
2433
- sourceEvent: event,
2434
- transform,
2435
- type,
2436
- },
2437
- target: this.axis,
2438
- });
2439
- this._element.call(this.zoom.transform, transform);
2131
+ this._element?.call(this.zoom.transform, transform);
2132
+ this.zoomService.fireZoom(message);
2133
+ this.zoomService.broadcastZoom(message);
2440
2134
  this.currentTransform = transform;
2441
- this.broadcastService.broadcastZoom({
2442
- channel: this.config?.zoom?.syncChannel,
2443
- message,
2444
- });
2445
2135
  };
2446
2136
  this._element.on('wheel', (event) => {
2447
2137
  event.preventDefault();
@@ -2460,23 +2150,19 @@ class ZoomableDirective {
2460
2150
  });
2461
2151
  }
2462
2152
  }
2463
- ZoomableDirective.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "14.0.2", ngImport: i0, type: ZoomableDirective, deps: [{ token: i0.ElementRef }, { token: ZoomService }, { token: BroadcastService }, { token: ChartService }, { token: i0.NgZone }], target: i0.ɵɵFactoryTarget.Directive });
2464
- ZoomableDirective.ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "14.0.2", type: ZoomableDirective, selector: "[tetaZoomable]", inputs: { config: "config", axis: "axis", size: "size", brushScale: "brushScale", scale: "scale" }, host: { properties: { "class.zoomable": "this.zoomable", "class.crosshair": "this.crosshair" } }, usesOnChanges: true, ngImport: i0 });
2153
+ ZoomableDirective.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "14.0.2", ngImport: i0, type: ZoomableDirective, deps: [{ token: i0.ElementRef }, { token: ZoomService }, { token: ChartService }, { token: i0.NgZone }], target: i0.ɵɵFactoryTarget.Directive });
2154
+ ZoomableDirective.ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "14.0.2", type: ZoomableDirective, selector: "[tetaZoomable]", inputs: { config: "config", axis: "axis", size: "size" }, host: { properties: { "class.zoomable": "this.zoomable", "class.crosshair": "this.crosshair" } }, ngImport: i0 });
2465
2155
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "14.0.2", ngImport: i0, type: ZoomableDirective, decorators: [{
2466
2156
  type: Directive,
2467
2157
  args: [{
2468
2158
  selector: '[tetaZoomable]',
2469
2159
  }]
2470
- }], ctorParameters: function () { return [{ type: i0.ElementRef }, { type: ZoomService }, { type: BroadcastService }, { type: ChartService }, { type: i0.NgZone }]; }, propDecorators: { config: [{
2160
+ }], ctorParameters: function () { return [{ type: i0.ElementRef }, { type: ZoomService }, { type: ChartService }, { type: i0.NgZone }]; }, propDecorators: { config: [{
2471
2161
  type: Input
2472
2162
  }], axis: [{
2473
2163
  type: Input
2474
2164
  }], size: [{
2475
2165
  type: Input
2476
- }], brushScale: [{
2477
- type: Input
2478
- }], scale: [{
2479
- type: Input
2480
2166
  }], zoomable: [{
2481
2167
  type: HostBinding,
2482
2168
  args: ['class.zoomable']
@@ -2486,32 +2172,138 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "14.0.2", ngImpor
2486
2172
  }] } });
2487
2173
 
2488
2174
  class BrushableDirective {
2489
- constructor(brushService, chartService, element) {
2175
+ constructor(brushService, chartService, element, zone) {
2490
2176
  this.brushService = brushService;
2491
2177
  this.chartService = chartService;
2492
2178
  this.element = element;
2179
+ this.zone = zone;
2180
+ this.brushMap = new Map()
2181
+ .set(BrushType.x, d3.brushX())
2182
+ .set(BrushType.y, d3.brushY());
2183
+ this._alive = true;
2184
+ this._container = d3.select(this.element.nativeElement);
2185
+ }
2186
+ ngOnInit() {
2187
+ this.brushService.brushDomain.pipe(takeWhile(() => this._alive), filter((brush) => brush.chartId !== this.config.id)).subscribe((brush) => {
2188
+ this._container.call(this.brush.move, [
2189
+ Math.floor(brush.selection[0]),
2190
+ Math.floor(brush.selection[1]),
2191
+ ].map(this.axis.scale));
2192
+ });
2193
+ }
2194
+ ngOnDestroy() {
2195
+ this._alive = false;
2196
+ }
2197
+ ngAfterViewInit() {
2493
2198
  }
2494
- ngOnInit() { }
2495
- ngAfterViewInit() { }
2496
2199
  ngOnChanges(changes) {
2497
2200
  if (changes.hasOwnProperty('config')) {
2498
- this.brushService.clearPreviousSelection();
2201
+ this.clearPreviousSelection();
2499
2202
  }
2500
2203
  if (this.config?.brush?.enable) {
2501
- this.brushService.applyBrush(this.element, this.config, this.brushScale);
2204
+ this.applyBrush(this.config, this.axis.scale);
2205
+ }
2206
+ }
2207
+ applyBrush(config, brushScale) {
2208
+ this.brush?.on('start brush end', null);
2209
+ if (config.brush?.enable) {
2210
+ this.brush = this.brushMap.get(config?.brush?.type ?? BrushType.x);
2211
+ this.brush.on('start brush end', (_) => {
2212
+ if (_.sourceEvent) {
2213
+ if (!_.selection)
2214
+ return;
2215
+ const [from, to] = _.selection;
2216
+ if (to - from === 0) {
2217
+ const selection = this.selection?.map(brushScale) ??
2218
+ [config.brush?.from, config.brush?.to].map(brushScale);
2219
+ const halfBrushHeight = (selection[1] - selection[0]) / 2;
2220
+ const invertedSelection = [
2221
+ from - halfBrushHeight,
2222
+ to + halfBrushHeight,
2223
+ ].map(brushScale.invert);
2224
+ if (invertedSelection[1] - invertedSelection[0] >
2225
+ config.brush?.max) {
2226
+ this._container.call(this.brush.move, [
2227
+ Math.floor(invertedSelection[0]),
2228
+ Math.floor(invertedSelection[0] + config.brush?.max),
2229
+ ].map(brushScale));
2230
+ return;
2231
+ }
2232
+ if (invertedSelection[1] - invertedSelection[0] <
2233
+ config.brush?.min) {
2234
+ this._container.call(this.brush.move, [
2235
+ Math.floor(invertedSelection[0]),
2236
+ Math.ceil(invertedSelection[0] + config.brush?.min),
2237
+ ].map(brushScale));
2238
+ return;
2239
+ }
2240
+ this._container.call(this.brush.move, [
2241
+ from - halfBrushHeight,
2242
+ to + halfBrushHeight,
2243
+ ]);
2244
+ return;
2245
+ }
2246
+ if (brushScale.invert(to) - brushScale.invert(from) >
2247
+ config.brush?.max) {
2248
+ this._container.call(this.brush.move, this.selection
2249
+ ? [
2250
+ this.selection[0],
2251
+ this.selection[0] + config.brush?.max,
2252
+ ].map(brushScale)
2253
+ : [config.brush?.from, config.brush?.to].map(brushScale));
2254
+ return;
2255
+ }
2256
+ if (brushScale.invert(to) - brushScale.invert(from) <
2257
+ config.brush?.min) {
2258
+ this._container.call(this.brush.move, this.selection
2259
+ ? [
2260
+ this.selection[0],
2261
+ this.selection[0] + config.brush?.min,
2262
+ ].map(brushScale)
2263
+ : [config.brush?.from, config.brush?.to].map(brushScale));
2264
+ return;
2265
+ }
2266
+ if (_.sourceEvent instanceof MouseEvent) {
2267
+ this.selection = _.selection.map(brushScale.invert);
2268
+ }
2269
+ const brushMessage = new BrushMessage({
2270
+ chartId: this.config.id,
2271
+ selection: [brushScale.invert(from), brushScale.invert(to)],
2272
+ });
2273
+ this.brushService.setBrush(brushMessage);
2274
+ }
2275
+ });
2276
+ this.zone.runOutsideAngular(() => {
2277
+ setTimeout(() => {
2278
+ this._container.call(this.brush);
2279
+ let domain = brushScale.domain();
2280
+ if (config?.brush?.from) {
2281
+ domain[0] = config.brush.from;
2282
+ }
2283
+ if (config?.brush?.to) {
2284
+ domain[1] = config.brush.to;
2285
+ }
2286
+ this._container.call(this.brush.move, this.selection
2287
+ ? this.selection.map(brushScale)
2288
+ : domain.map(brushScale), {});
2289
+ }, 0);
2290
+ });
2502
2291
  }
2503
2292
  }
2293
+ clearPreviousSelection() {
2294
+ this.selection = null;
2295
+ }
2504
2296
  }
2505
- BrushableDirective.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "14.0.2", ngImport: i0, type: BrushableDirective, deps: [{ token: BrushService }, { token: ChartService }, { token: i0.ElementRef }], target: i0.ɵɵFactoryTarget.Directive });
2506
- BrushableDirective.ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "14.0.2", type: BrushableDirective, selector: "[tetaBrushable]", inputs: { config: "config", brushScale: "brushScale" }, usesOnChanges: true, ngImport: i0 });
2297
+ BrushableDirective.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "14.0.2", ngImport: i0, type: BrushableDirective, deps: [{ token: BrushService }, { token: ChartService }, { token: i0.ElementRef }, { token: i0.NgZone }], target: i0.ɵɵFactoryTarget.Directive });
2298
+ BrushableDirective.ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "14.0.2", type: BrushableDirective, selector: "[tetaBrushable]", inputs: { config: "config", axis: "axis" }, usesOnChanges: true, ngImport: i0 });
2507
2299
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "14.0.2", ngImport: i0, type: BrushableDirective, decorators: [{
2508
2300
  type: Directive,
2509
2301
  args: [{
2510
2302
  selector: '[tetaBrushable]',
2511
2303
  }]
2512
- }], ctorParameters: function () { return [{ type: BrushService }, { type: ChartService }, { type: i0.ElementRef }]; }, propDecorators: { config: [{
2304
+ }], ctorParameters: function () { return [{ type: BrushService }, { type: ChartService }, { type: i0.ElementRef }, { type: i0.NgZone }]; }, propDecorators: { config: [{
2513
2305
  type: Input
2514
- }], brushScale: [{
2306
+ }], axis: [{
2515
2307
  type: Input
2516
2308
  }] } });
2517
2309
 
@@ -2597,7 +2389,6 @@ class CrosshairComponent {
2597
2389
  this.transform = this.chartService.pointerMove.pipe(map((event) => {
2598
2390
  const composedPath = event.composedPath();
2599
2391
  const classes = composedPath.map((_) => _.classList?.contains('crosshair')).filter((_) => _);
2600
- console.log(classes);
2601
2392
  return {
2602
2393
  x: event.type === 'mouseleave' ? -9999 : event.offsetX,
2603
2394
  y: event.type === 'mouseleave' ? -9999 : event.offsetY
@@ -2771,10 +2562,10 @@ class ChartContainerComponent {
2771
2562
  }
2772
2563
  }
2773
2564
  ChartContainerComponent.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "14.0.2", ngImport: i0, type: ChartContainerComponent, deps: [{ token: ChartService }, { token: i0.ChangeDetectorRef }, { token: ScaleService }, { token: ZoomService }, { token: i0.ElementRef }, { token: i0.NgZone }], target: i0.ɵɵFactoryTarget.Component });
2774
- ChartContainerComponent.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "14.0.2", type: ChartContainerComponent, selector: "teta-chart-container", ngImport: i0, template: "<ng-container *ngIf=\"{\n size: size | async,\n config: config | async,\n scales: scales | async,\n visibleRect: visibleRect | async,\n brushScale: brushScale | async\n} as data\" xmlns:svg=\"http://www.w3.org/1999/html\">\n <teta-tooltip *ngIf=\"data.config?.tooltip?.enable\"\n [size]=\"data.size\"\n [config]=\"data.config\"></teta-tooltip>\n <ng-container *ngIf=\"data.size?.height > 0 && data.size?.width > 0 && data.scales?.x.size === data.config.xAxis.length && data.scales?.y.size === data.config.yAxis.length\">\n <svg height=\"100%\" width=\"100%\" class=\"position-absolute\">\n <g class=\"y-axis-container\">\n <ng-container *ngFor=\"let item of data.scales.y | keyvalue; trackBy: identify\">\n <ng-container *ngIf=\"item.value.options.visible\">\n <g\n teta-y-axis\n [axis]=\"item.value\"\n [size]=\"data.visibleRect\"\n [attr.transform]=\"getTranslate(item.value, data.size) | async\"></g>\n <rect\n tetaZoomable\n fill-opacity=\"0\"\n [brushScale]=\"data.brushScale\"\n [scale]=\"data.scales.y.get(item.key).scale\"\n [axis]=\"item.value\"\n [config]=\"data.config\"\n [size]=\"data.visibleRect\"\n [attr.x]=\"item.value.options.opposite ? 0 : -item.value.selfSize\"\n [attr.y]=\"0\"\n [attr.height]=\"data.visibleRect.height\"\n [attr.width]=\"item.value.selfSize\"\n [attr.transform]=\"getTranslate(item.value, data.size) | async\"></rect>\n </ng-container>\n\n </ng-container>\n </g>\n <g class=\"x-axis-container\">\n <ng-container *ngFor=\"let item of data.scales.x | keyvalue; trackBy: identify\">\n <ng-container *ngIf=\"item.value.options.visible && data.scales.x.size > 0 && data.scales.y.size > 0\">\n <g\n teta-x-axis\n [axis]=\"item.value\"\n [size]=\"data.visibleRect\"\n [attr.transform]=\"getTranslate(item.value, data.size) | async\"></g>\n <rect\n tetaZoomable\n fill-opacity=\"0\"\n [brushScale]=\"data.brushScale\"\n [scale]=\"data.scales.x.get(item.key).scale\"\n [axis]=\"item.value\"\n [config]=\"data.config\"\n [size]=\"data.visibleRect\"\n [attr.x]=\"0\"\n [attr.y]=\"item.value.options.opposite ? -item.value.selfSize : 0\"\n [attr.width]=\"data.visibleRect.width\"\n [attr.height]=\"item.value.selfSize\"\n [attr.transform]=\"getTranslate(item.value, data.size) | async\"></rect>\n </ng-container>\n </ng-container>\n </g>\n </svg>\n </ng-container>\n <ng-container *ngIf=\"data.size?.height > 0 && data.size?.width > 0 && data.scales?.x.size === data.config.xAxis.length && data.scales?.y.size === data.config.yAxis.length\">\n <svg\n tetaBrushable\n tetaZoomable\n class=\"position-absolute\"\n [size]=\"data.visibleRect\"\n [brushScale]=\"data.brushScale\"\n [scale]=\"data.brushScale\"\n [config]=\"data.config\"\n [axis]=\"data.config?.zoom?.type === zoomType.x ? data.scales.x.get(0) : data.scales.y.get(0)\"\n [attr.width]=\"data.visibleRect.width\"\n [attr.height]=\"data.visibleRect.height\"\n [attr.viewBox]=\"'0 0 ' + data.visibleRect.width + ' ' + data.visibleRect.height\"\n [style.transform]=\"'translate('+ data.visibleRect.x +'px, '+ data.visibleRect.y +'px)'\"\n (contextmenu)=\"contextMenu($event, data.scales.x, data.scales.y)\"\n (click)=\"click($event, data.scales.x, data.scales.y)\"\n (mouseleave)=\"mouseLeave($event)\"\n (mousemove)=\"mouseMove($event)\">\n\n <g class=\"gridlines\"\n teta-gridlines\n *ngIf=\"data.config.gridLines?.enable !== false\"\n [size]=\"data.size\"></g>\n\n <g class=\"x-axis-plotband-container\">\n <ng-container *ngFor=\"let axis of data.config.xAxis; let i = index\">\n <g teta-plot-band *ngFor=\"let plotBand of axis.plotBands\"\n [plotBand]=\"plotBand\"\n [scale]=\"data.scales.x.get(i).scale\"\n [size]=\"data.visibleRect\"\n [axis]=\"data.scales.x.get(i)\"></g>\n </ng-container>\n </g>\n <g class=\"y-axis-plotband-container\">\n <ng-container *ngFor=\"let axis of data.config.yAxis; let i = index\">\n <g teta-plot-band *ngFor=\"let plotBand of axis.plotBands\"\n [plotBand]=\"plotBand\"\n [scale]=\"data.scales.y.get(i).scale\"\n [size]=\"data.visibleRect\"\n [axis]=\"data.scales.y.get(i)\"></g>\n </ng-container>\n </g>\n <g class=\"x-axis-plotline-container\">\n <ng-container *ngFor=\"let axis of data.config.xAxis; let i = index\">\n <g teta-plot-line *ngFor=\"let plotLine of axis.plotLines\"\n [plotLine]=\"plotLine\"\n [scale]=\"data.scales.x.get(i).scale\"\n [size]=\"data.size\"\n [axis]=\"data.scales.x.get(i)\"></g>\n </ng-container>\n </g>\n <g class=\"y-axis-plotline-container\">\n <ng-container *ngFor=\"let axis of data.config.yAxis; let i = index\">\n <g teta-plot-line *ngFor=\"let plotLine of axis.plotLines\"\n [plotLine]=\"plotLine\"\n [scale]=\"data.scales.y.get(i).scale\"\n [size]=\"data.size\"\n [axis]=\"data.scales.y.get(i)\"></g>\n </ng-container>\n </g>\n <g class=\"series-container\">\n <ng-container *ngFor=\"let series of data.config.series;\">\n <g teta-series-host\n *ngIf=\"series.visible\"\n [config]=\"data.config\"\n [series]=\"series\"></g>\n </ng-container>\n </g>\n <g class=\"annotations\">\n <g teta-annotation\n *ngFor=\"let annotation of data.config.annotations\"\n [annotation]=\"annotation\"></g>\n </g>\n <g class=\"crosshair\" *ngIf=\"data.config.tooltip?.showCrosshair\">\n <g teta-crosshair [size]=\"data.visibleRect\"></g>\n </g>\n </svg>\n\n </ng-container>\n</ng-container>\n", styles: [":host{display:flex;flex-direction:column;flex-grow:1;min-width:0;min-height:0}:host .zoomable:hover{cursor:grab}:host .zoomable:active{cursor:grabbing}:host .crosshair{cursor:crosshair}\n"], dependencies: [{ kind: "directive", type: i4.NgForOf, selector: "[ngFor][ngForOf]", inputs: ["ngForOf", "ngForTrackBy", "ngForTemplate"] }, { kind: "directive", type: i4.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { kind: "component", type: SeriesHostComponent, selector: "[teta-series-host]", inputs: ["config", "series"] }, { kind: "component", type: GridlinesComponent, selector: "[teta-gridlines]", inputs: ["size"] }, { kind: "component", type: XAxisComponent, selector: "[teta-x-axis]", inputs: ["axis", "size"] }, { kind: "component", type: YAxisComponent, selector: "[teta-y-axis]", inputs: ["axis", "size"] }, { kind: "component", type: PlotlineComponent, selector: "[teta-plot-line]", inputs: ["plotLine", "size", "axis", "scale"] }, { kind: "component", type: PlotBandComponent, selector: "[teta-plot-band]", inputs: ["plotBand", "axis", "scale", "size"] }, { kind: "component", type: TooltipComponent, selector: "teta-tooltip", inputs: ["size", "config"] }, { kind: "directive", type: ZoomableDirective, selector: "[tetaZoomable]", inputs: ["config", "axis", "size", "brushScale", "scale"] }, { kind: "directive", type: BrushableDirective, selector: "[tetaBrushable]", inputs: ["config", "brushScale"] }, { kind: "component", type: AnnotationComponent, selector: "[teta-annotation]", inputs: ["annotation"] }, { kind: "component", type: CrosshairComponent, selector: "[teta-crosshair]", inputs: ["size"] }, { kind: "pipe", type: i4.AsyncPipe, name: "async" }, { kind: "pipe", type: i4.KeyValuePipe, name: "keyvalue" }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
2565
+ ChartContainerComponent.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "14.0.2", type: ChartContainerComponent, selector: "teta-chart-container", ngImport: i0, template: "<ng-container *ngIf=\"{\n size: size | async,\n config: config | async,\n scales: scales | async,\n visibleRect: visibleRect | async\n} as data\" xmlns:svg=\"http://www.w3.org/1999/html\">\n <teta-tooltip *ngIf=\"data.config?.tooltip?.enable\"\n [size]=\"data.size\"\n [config]=\"data.config\"></teta-tooltip>\n <ng-container *ngIf=\"data.size?.height > 0 && data.size?.width > 0 && data.scales?.x.size === data.config.xAxis.length && data.scales?.y.size === data.config.yAxis.length\">\n <svg height=\"100%\" width=\"100%\" class=\"position-absolute\">\n <g class=\"y-axis-container\">\n <ng-container *ngFor=\"let item of data.scales.y | keyvalue; trackBy: identify\">\n <ng-container *ngIf=\"item.value.options.visible && data.scales.x.size > 0 && data.scales.y.size > 0\">\n <g\n teta-y-axis\n [axis]=\"item.value\"\n [size]=\"data.visibleRect\"\n [attr.transform]=\"getTranslate(item.value, data.size) | async\"></g>\n <rect\n tetaZoomable\n fill-opacity=\"0\"\n [axis]=\"item.value\"\n [config]=\"data.config\"\n [size]=\"data.visibleRect\"\n [attr.x]=\"item.value.options.opposite ? 0 : -item.value.selfSize\"\n [attr.y]=\"0\"\n [attr.height]=\"data.visibleRect.height\"\n [attr.width]=\"item.value.selfSize\"\n [attr.transform]=\"getTranslate(item.value, data.size) | async\"></rect>\n </ng-container>\n\n </ng-container>\n </g>\n <g class=\"x-axis-container\">\n <ng-container *ngFor=\"let item of data.scales.x | keyvalue; trackBy: identify\">\n <ng-container *ngIf=\"item.value.options.visible && data.scales.x.size > 0 && data.scales.y.size > 0\">\n <g\n teta-x-axis\n [axis]=\"item.value\"\n [size]=\"data.visibleRect\"\n [attr.transform]=\"getTranslate(item.value, data.size) | async\"></g>\n <rect\n tetaZoomable\n fill-opacity=\"0\"\n [axis]=\"item.value\"\n [config]=\"data.config\"\n [size]=\"data.visibleRect\"\n [attr.x]=\"0\"\n [attr.y]=\"item.value.options.opposite ? -item.value.selfSize : 0\"\n [attr.width]=\"data.visibleRect.width\"\n [attr.height]=\"item.value.selfSize\"\n [attr.transform]=\"getTranslate(item.value, data.size) | async\"></rect>\n </ng-container>\n </ng-container>\n </g>\n </svg>\n </ng-container>\n <ng-container *ngIf=\"data.size?.height > 0 && data.size?.width > 0 && data.scales?.x.size === data.config.xAxis.length && data.scales?.y.size === data.config.yAxis.length\">\n <svg\n tetaZoomable\n tetaBrushable\n class=\"position-absolute\"\n [size]=\"data.visibleRect\"\n [config]=\"data.config\"\n [axis]=\"data.config?.zoom?.type === zoomType.x ? data.scales.x.get(0) : data.scales.y.get(0)\"\n [attr.width]=\"data.visibleRect.width\"\n [attr.height]=\"data.visibleRect.height\"\n [attr.viewBox]=\"'0 0 ' + data.visibleRect.width + ' ' + data.visibleRect.height\"\n [style.transform]=\"'translate('+ data.visibleRect.x +'px, '+ data.visibleRect.y +'px)'\"\n (contextmenu)=\"contextMenu($event, data.scales.x, data.scales.y)\"\n (click)=\"click($event, data.scales.x, data.scales.y)\"\n (mouseleave)=\"mouseLeave($event)\"\n (mousemove)=\"mouseMove($event)\">\n\n <g class=\"gridlines\"\n teta-gridlines\n *ngIf=\"data.config.gridLines?.enable !== false\"\n [size]=\"data.size\"></g>\n\n <g class=\"x-axis-plotband-container\">\n <ng-container *ngFor=\"let axis of data.config.xAxis; let i = index\">\n <g teta-plot-band *ngFor=\"let plotBand of axis.plotBands\"\n [plotBand]=\"plotBand\"\n [scale]=\"data.scales.x.get(i).scale\"\n [size]=\"data.visibleRect\"\n [axis]=\"data.scales.x.get(i)\"></g>\n </ng-container>\n </g>\n <g class=\"y-axis-plotband-container\">\n <ng-container *ngFor=\"let axis of data.config.yAxis; let i = index\">\n <g teta-plot-band *ngFor=\"let plotBand of axis.plotBands\"\n [plotBand]=\"plotBand\"\n [scale]=\"data.scales.y.get(i).scale\"\n [size]=\"data.visibleRect\"\n [axis]=\"data.scales.y.get(i)\"></g>\n </ng-container>\n </g>\n <g class=\"x-axis-plotline-container\">\n <ng-container *ngFor=\"let axis of data.config.xAxis; let i = index\">\n <g teta-plot-line *ngFor=\"let plotLine of axis.plotLines\"\n [plotLine]=\"plotLine\"\n [scale]=\"data.scales.x.get(i).scale\"\n [size]=\"data.size\"\n [axis]=\"data.scales.x.get(i)\"></g>\n </ng-container>\n </g>\n <g class=\"y-axis-plotline-container\">\n <ng-container *ngFor=\"let axis of data.config.yAxis; let i = index\">\n <g teta-plot-line *ngFor=\"let plotLine of axis.plotLines\"\n [plotLine]=\"plotLine\"\n [scale]=\"data.scales.y.get(i).scale\"\n [size]=\"data.size\"\n [axis]=\"data.scales.y.get(i)\"></g>\n </ng-container>\n </g>\n <g class=\"series-container\">\n <ng-container *ngFor=\"let series of data.config.series;\">\n <g teta-series-host\n *ngIf=\"series.visible\"\n [config]=\"data.config\"\n [series]=\"series\"></g>\n </ng-container>\n </g>\n <g class=\"annotations\">\n <g teta-annotation\n *ngFor=\"let annotation of data.config.annotations\"\n [annotation]=\"annotation\"></g>\n </g>\n <g class=\"crosshair\" *ngIf=\"data.config.tooltip?.showCrosshair\">\n <g teta-crosshair [size]=\"data.visibleRect\"></g>\n </g>\n </svg>\n\n </ng-container>\n</ng-container>\n", styles: [":host{display:flex;flex-direction:column;flex-grow:1;min-width:0;min-height:0}:host .zoomable:hover{cursor:grab}:host .zoomable:active{cursor:grabbing}:host .crosshair{cursor:crosshair}\n"], dependencies: [{ kind: "directive", type: i4.NgForOf, selector: "[ngFor][ngForOf]", inputs: ["ngForOf", "ngForTrackBy", "ngForTemplate"] }, { kind: "directive", type: i4.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { kind: "component", type: SeriesHostComponent, selector: "[teta-series-host]", inputs: ["config", "series"] }, { kind: "component", type: GridlinesComponent, selector: "[teta-gridlines]", inputs: ["size"] }, { kind: "component", type: XAxisComponent, selector: "[teta-x-axis]", inputs: ["axis", "size"] }, { kind: "component", type: YAxisComponent, selector: "[teta-y-axis]", inputs: ["axis", "size"] }, { kind: "component", type: PlotlineComponent, selector: "[teta-plot-line]", inputs: ["plotLine", "size", "axis", "scale"] }, { kind: "component", type: PlotBandComponent, selector: "[teta-plot-band]", inputs: ["plotBand", "axis", "scale", "size"] }, { kind: "component", type: TooltipComponent, selector: "teta-tooltip", inputs: ["size", "config"] }, { kind: "directive", type: ZoomableDirective, selector: "[tetaZoomable]", inputs: ["config", "axis", "size"] }, { kind: "directive", type: BrushableDirective, selector: "[tetaBrushable]", inputs: ["config", "axis"] }, { kind: "component", type: AnnotationComponent, selector: "[teta-annotation]", inputs: ["annotation"] }, { kind: "component", type: CrosshairComponent, selector: "[teta-crosshair]", inputs: ["size"] }, { kind: "pipe", type: i4.AsyncPipe, name: "async" }, { kind: "pipe", type: i4.KeyValuePipe, name: "keyvalue" }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
2775
2566
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "14.0.2", ngImport: i0, type: ChartContainerComponent, decorators: [{
2776
2567
  type: Component,
2777
- args: [{ selector: 'teta-chart-container', changeDetection: ChangeDetectionStrategy.OnPush, template: "<ng-container *ngIf=\"{\n size: size | async,\n config: config | async,\n scales: scales | async,\n visibleRect: visibleRect | async,\n brushScale: brushScale | async\n} as data\" xmlns:svg=\"http://www.w3.org/1999/html\">\n <teta-tooltip *ngIf=\"data.config?.tooltip?.enable\"\n [size]=\"data.size\"\n [config]=\"data.config\"></teta-tooltip>\n <ng-container *ngIf=\"data.size?.height > 0 && data.size?.width > 0 && data.scales?.x.size === data.config.xAxis.length && data.scales?.y.size === data.config.yAxis.length\">\n <svg height=\"100%\" width=\"100%\" class=\"position-absolute\">\n <g class=\"y-axis-container\">\n <ng-container *ngFor=\"let item of data.scales.y | keyvalue; trackBy: identify\">\n <ng-container *ngIf=\"item.value.options.visible\">\n <g\n teta-y-axis\n [axis]=\"item.value\"\n [size]=\"data.visibleRect\"\n [attr.transform]=\"getTranslate(item.value, data.size) | async\"></g>\n <rect\n tetaZoomable\n fill-opacity=\"0\"\n [brushScale]=\"data.brushScale\"\n [scale]=\"data.scales.y.get(item.key).scale\"\n [axis]=\"item.value\"\n [config]=\"data.config\"\n [size]=\"data.visibleRect\"\n [attr.x]=\"item.value.options.opposite ? 0 : -item.value.selfSize\"\n [attr.y]=\"0\"\n [attr.height]=\"data.visibleRect.height\"\n [attr.width]=\"item.value.selfSize\"\n [attr.transform]=\"getTranslate(item.value, data.size) | async\"></rect>\n </ng-container>\n\n </ng-container>\n </g>\n <g class=\"x-axis-container\">\n <ng-container *ngFor=\"let item of data.scales.x | keyvalue; trackBy: identify\">\n <ng-container *ngIf=\"item.value.options.visible && data.scales.x.size > 0 && data.scales.y.size > 0\">\n <g\n teta-x-axis\n [axis]=\"item.value\"\n [size]=\"data.visibleRect\"\n [attr.transform]=\"getTranslate(item.value, data.size) | async\"></g>\n <rect\n tetaZoomable\n fill-opacity=\"0\"\n [brushScale]=\"data.brushScale\"\n [scale]=\"data.scales.x.get(item.key).scale\"\n [axis]=\"item.value\"\n [config]=\"data.config\"\n [size]=\"data.visibleRect\"\n [attr.x]=\"0\"\n [attr.y]=\"item.value.options.opposite ? -item.value.selfSize : 0\"\n [attr.width]=\"data.visibleRect.width\"\n [attr.height]=\"item.value.selfSize\"\n [attr.transform]=\"getTranslate(item.value, data.size) | async\"></rect>\n </ng-container>\n </ng-container>\n </g>\n </svg>\n </ng-container>\n <ng-container *ngIf=\"data.size?.height > 0 && data.size?.width > 0 && data.scales?.x.size === data.config.xAxis.length && data.scales?.y.size === data.config.yAxis.length\">\n <svg\n tetaBrushable\n tetaZoomable\n class=\"position-absolute\"\n [size]=\"data.visibleRect\"\n [brushScale]=\"data.brushScale\"\n [scale]=\"data.brushScale\"\n [config]=\"data.config\"\n [axis]=\"data.config?.zoom?.type === zoomType.x ? data.scales.x.get(0) : data.scales.y.get(0)\"\n [attr.width]=\"data.visibleRect.width\"\n [attr.height]=\"data.visibleRect.height\"\n [attr.viewBox]=\"'0 0 ' + data.visibleRect.width + ' ' + data.visibleRect.height\"\n [style.transform]=\"'translate('+ data.visibleRect.x +'px, '+ data.visibleRect.y +'px)'\"\n (contextmenu)=\"contextMenu($event, data.scales.x, data.scales.y)\"\n (click)=\"click($event, data.scales.x, data.scales.y)\"\n (mouseleave)=\"mouseLeave($event)\"\n (mousemove)=\"mouseMove($event)\">\n\n <g class=\"gridlines\"\n teta-gridlines\n *ngIf=\"data.config.gridLines?.enable !== false\"\n [size]=\"data.size\"></g>\n\n <g class=\"x-axis-plotband-container\">\n <ng-container *ngFor=\"let axis of data.config.xAxis; let i = index\">\n <g teta-plot-band *ngFor=\"let plotBand of axis.plotBands\"\n [plotBand]=\"plotBand\"\n [scale]=\"data.scales.x.get(i).scale\"\n [size]=\"data.visibleRect\"\n [axis]=\"data.scales.x.get(i)\"></g>\n </ng-container>\n </g>\n <g class=\"y-axis-plotband-container\">\n <ng-container *ngFor=\"let axis of data.config.yAxis; let i = index\">\n <g teta-plot-band *ngFor=\"let plotBand of axis.plotBands\"\n [plotBand]=\"plotBand\"\n [scale]=\"data.scales.y.get(i).scale\"\n [size]=\"data.visibleRect\"\n [axis]=\"data.scales.y.get(i)\"></g>\n </ng-container>\n </g>\n <g class=\"x-axis-plotline-container\">\n <ng-container *ngFor=\"let axis of data.config.xAxis; let i = index\">\n <g teta-plot-line *ngFor=\"let plotLine of axis.plotLines\"\n [plotLine]=\"plotLine\"\n [scale]=\"data.scales.x.get(i).scale\"\n [size]=\"data.size\"\n [axis]=\"data.scales.x.get(i)\"></g>\n </ng-container>\n </g>\n <g class=\"y-axis-plotline-container\">\n <ng-container *ngFor=\"let axis of data.config.yAxis; let i = index\">\n <g teta-plot-line *ngFor=\"let plotLine of axis.plotLines\"\n [plotLine]=\"plotLine\"\n [scale]=\"data.scales.y.get(i).scale\"\n [size]=\"data.size\"\n [axis]=\"data.scales.y.get(i)\"></g>\n </ng-container>\n </g>\n <g class=\"series-container\">\n <ng-container *ngFor=\"let series of data.config.series;\">\n <g teta-series-host\n *ngIf=\"series.visible\"\n [config]=\"data.config\"\n [series]=\"series\"></g>\n </ng-container>\n </g>\n <g class=\"annotations\">\n <g teta-annotation\n *ngFor=\"let annotation of data.config.annotations\"\n [annotation]=\"annotation\"></g>\n </g>\n <g class=\"crosshair\" *ngIf=\"data.config.tooltip?.showCrosshair\">\n <g teta-crosshair [size]=\"data.visibleRect\"></g>\n </g>\n </svg>\n\n </ng-container>\n</ng-container>\n", styles: [":host{display:flex;flex-direction:column;flex-grow:1;min-width:0;min-height:0}:host .zoomable:hover{cursor:grab}:host .zoomable:active{cursor:grabbing}:host .crosshair{cursor:crosshair}\n"] }]
2568
+ args: [{ selector: 'teta-chart-container', changeDetection: ChangeDetectionStrategy.OnPush, template: "<ng-container *ngIf=\"{\n size: size | async,\n config: config | async,\n scales: scales | async,\n visibleRect: visibleRect | async\n} as data\" xmlns:svg=\"http://www.w3.org/1999/html\">\n <teta-tooltip *ngIf=\"data.config?.tooltip?.enable\"\n [size]=\"data.size\"\n [config]=\"data.config\"></teta-tooltip>\n <ng-container *ngIf=\"data.size?.height > 0 && data.size?.width > 0 && data.scales?.x.size === data.config.xAxis.length && data.scales?.y.size === data.config.yAxis.length\">\n <svg height=\"100%\" width=\"100%\" class=\"position-absolute\">\n <g class=\"y-axis-container\">\n <ng-container *ngFor=\"let item of data.scales.y | keyvalue; trackBy: identify\">\n <ng-container *ngIf=\"item.value.options.visible && data.scales.x.size > 0 && data.scales.y.size > 0\">\n <g\n teta-y-axis\n [axis]=\"item.value\"\n [size]=\"data.visibleRect\"\n [attr.transform]=\"getTranslate(item.value, data.size) | async\"></g>\n <rect\n tetaZoomable\n fill-opacity=\"0\"\n [axis]=\"item.value\"\n [config]=\"data.config\"\n [size]=\"data.visibleRect\"\n [attr.x]=\"item.value.options.opposite ? 0 : -item.value.selfSize\"\n [attr.y]=\"0\"\n [attr.height]=\"data.visibleRect.height\"\n [attr.width]=\"item.value.selfSize\"\n [attr.transform]=\"getTranslate(item.value, data.size) | async\"></rect>\n </ng-container>\n\n </ng-container>\n </g>\n <g class=\"x-axis-container\">\n <ng-container *ngFor=\"let item of data.scales.x | keyvalue; trackBy: identify\">\n <ng-container *ngIf=\"item.value.options.visible && data.scales.x.size > 0 && data.scales.y.size > 0\">\n <g\n teta-x-axis\n [axis]=\"item.value\"\n [size]=\"data.visibleRect\"\n [attr.transform]=\"getTranslate(item.value, data.size) | async\"></g>\n <rect\n tetaZoomable\n fill-opacity=\"0\"\n [axis]=\"item.value\"\n [config]=\"data.config\"\n [size]=\"data.visibleRect\"\n [attr.x]=\"0\"\n [attr.y]=\"item.value.options.opposite ? -item.value.selfSize : 0\"\n [attr.width]=\"data.visibleRect.width\"\n [attr.height]=\"item.value.selfSize\"\n [attr.transform]=\"getTranslate(item.value, data.size) | async\"></rect>\n </ng-container>\n </ng-container>\n </g>\n </svg>\n </ng-container>\n <ng-container *ngIf=\"data.size?.height > 0 && data.size?.width > 0 && data.scales?.x.size === data.config.xAxis.length && data.scales?.y.size === data.config.yAxis.length\">\n <svg\n tetaZoomable\n tetaBrushable\n class=\"position-absolute\"\n [size]=\"data.visibleRect\"\n [config]=\"data.config\"\n [axis]=\"data.config?.zoom?.type === zoomType.x ? data.scales.x.get(0) : data.scales.y.get(0)\"\n [attr.width]=\"data.visibleRect.width\"\n [attr.height]=\"data.visibleRect.height\"\n [attr.viewBox]=\"'0 0 ' + data.visibleRect.width + ' ' + data.visibleRect.height\"\n [style.transform]=\"'translate('+ data.visibleRect.x +'px, '+ data.visibleRect.y +'px)'\"\n (contextmenu)=\"contextMenu($event, data.scales.x, data.scales.y)\"\n (click)=\"click($event, data.scales.x, data.scales.y)\"\n (mouseleave)=\"mouseLeave($event)\"\n (mousemove)=\"mouseMove($event)\">\n\n <g class=\"gridlines\"\n teta-gridlines\n *ngIf=\"data.config.gridLines?.enable !== false\"\n [size]=\"data.size\"></g>\n\n <g class=\"x-axis-plotband-container\">\n <ng-container *ngFor=\"let axis of data.config.xAxis; let i = index\">\n <g teta-plot-band *ngFor=\"let plotBand of axis.plotBands\"\n [plotBand]=\"plotBand\"\n [scale]=\"data.scales.x.get(i).scale\"\n [size]=\"data.visibleRect\"\n [axis]=\"data.scales.x.get(i)\"></g>\n </ng-container>\n </g>\n <g class=\"y-axis-plotband-container\">\n <ng-container *ngFor=\"let axis of data.config.yAxis; let i = index\">\n <g teta-plot-band *ngFor=\"let plotBand of axis.plotBands\"\n [plotBand]=\"plotBand\"\n [scale]=\"data.scales.y.get(i).scale\"\n [size]=\"data.visibleRect\"\n [axis]=\"data.scales.y.get(i)\"></g>\n </ng-container>\n </g>\n <g class=\"x-axis-plotline-container\">\n <ng-container *ngFor=\"let axis of data.config.xAxis; let i = index\">\n <g teta-plot-line *ngFor=\"let plotLine of axis.plotLines\"\n [plotLine]=\"plotLine\"\n [scale]=\"data.scales.x.get(i).scale\"\n [size]=\"data.size\"\n [axis]=\"data.scales.x.get(i)\"></g>\n </ng-container>\n </g>\n <g class=\"y-axis-plotline-container\">\n <ng-container *ngFor=\"let axis of data.config.yAxis; let i = index\">\n <g teta-plot-line *ngFor=\"let plotLine of axis.plotLines\"\n [plotLine]=\"plotLine\"\n [scale]=\"data.scales.y.get(i).scale\"\n [size]=\"data.size\"\n [axis]=\"data.scales.y.get(i)\"></g>\n </ng-container>\n </g>\n <g class=\"series-container\">\n <ng-container *ngFor=\"let series of data.config.series;\">\n <g teta-series-host\n *ngIf=\"series.visible\"\n [config]=\"data.config\"\n [series]=\"series\"></g>\n </ng-container>\n </g>\n <g class=\"annotations\">\n <g teta-annotation\n *ngFor=\"let annotation of data.config.annotations\"\n [annotation]=\"annotation\"></g>\n </g>\n <g class=\"crosshair\" *ngIf=\"data.config.tooltip?.showCrosshair\">\n <g teta-crosshair [size]=\"data.visibleRect\"></g>\n </g>\n </svg>\n\n </ng-container>\n</ng-container>\n", styles: [":host{display:flex;flex-direction:column;flex-grow:1;min-width:0;min-height:0}:host .zoomable:hover{cursor:grab}:host .zoomable:active{cursor:grabbing}:host .crosshair{cursor:crosshair}\n"] }]
2778
2569
  }], ctorParameters: function () { return [{ type: ChartService }, { type: i0.ChangeDetectorRef }, { type: ScaleService }, { type: ZoomService }, { type: i0.ElementRef }, { type: i0.NgZone }]; } });
2779
2570
 
2780
2571
  class LegendComponent {
@@ -2809,9 +2600,10 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "14.0.2", ngImpor
2809
2600
  }] } });
2810
2601
 
2811
2602
  class ChartComponent {
2812
- constructor(chartService, zoomService, scaleService) {
2603
+ constructor(chartService, zoomService, brushService, scaleService) {
2813
2604
  this.chartService = chartService;
2814
2605
  this.zoomService = zoomService;
2606
+ this.brushService = brushService;
2815
2607
  this.scaleService = scaleService;
2816
2608
  this.pointerMove = new EventEmitter();
2817
2609
  this.plotBandsMove = new EventEmitter();
@@ -2825,16 +2617,20 @@ class ChartComponent {
2825
2617
  this.annotationClick = new EventEmitter();
2826
2618
  this.annotationMove = new EventEmitter();
2827
2619
  this.zoomServiceInstance = new EventEmitter();
2620
+ this.brushServiceInstance = new EventEmitter();
2828
2621
  this._alive = true;
2829
2622
  this.svcConfig = this.chartService.config;
2830
2623
  this.hasSeriesData = this.svcConfig.pipe(map((_) => _.series?.length > 0 && _.series?.some((_) => _.data?.length > 0)));
2831
2624
  }
2832
2625
  set config(config) {
2833
2626
  this.chartService.setConfig(config);
2627
+ this.zoomService.setBroadcastChannel(config?.zoom?.syncChannel);
2834
2628
  }
2835
2629
  ngOnChanges(changes) {
2836
2630
  }
2837
2631
  ngOnInit() {
2632
+ this.zoomServiceInstance.emit(this.zoomService);
2633
+ this.brushServiceInstance.emit(this.brushService);
2838
2634
  this.chartService.pointerMove
2839
2635
  .pipe(takeWhile(() => this._alive), withLatestFrom(this.scaleService.scales, this.chartService.config))
2840
2636
  .subscribe((data) => {
@@ -2905,27 +2701,19 @@ class ChartComponent {
2905
2701
  .subscribe((_) => {
2906
2702
  this.annotationMove.emit(_);
2907
2703
  });
2908
- this.chartService.zoomInstance
2909
- .pipe(takeWhile(() => this._alive))
2910
- .subscribe((_) => {
2911
- this.zoomServiceInstance.emit(_);
2912
- });
2913
2704
  }
2914
2705
  ngAfterViewInit() {
2915
2706
  }
2916
2707
  ngOnDestroy() {
2917
2708
  this._alive = false;
2918
- this.zoomService.broadcastSubscription?.forEach((sub) => {
2919
- sub.unsubscribe();
2920
- });
2921
2709
  }
2922
2710
  }
2923
- ChartComponent.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "14.0.2", ngImport: i0, type: ChartComponent, deps: [{ token: ChartService }, { token: ZoomService }, { token: ScaleService }], target: i0.ɵɵFactoryTarget.Component });
2924
- ChartComponent.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "14.0.2", type: ChartComponent, selector: "teta-svg-chart", inputs: { config: "config" }, outputs: { pointerMove: "pointerMove", plotBandsMove: "plotBandsMove", plotBandClick: "plotBandClick", plotBandContextMenu: "plotBandContextMenu", plotLinesMove: "plotLinesMove", pointMove: "pointMove", chartClick: "chartClick", chartContextMenu: "chartContextMenu", annotationContextMenu: "annotationContextMenu", annotationClick: "annotationClick", annotationMove: "annotationMove", zoomServiceInstance: "zoomServiceInstance" }, providers: [ChartService, ZoomService, ScaleService, BrushService], usesOnChanges: true, ngImport: i0, template: "<ng-container *ngIf=\"{\n hasSeriesData: hasSeriesData | async,\n svcConfig: svcConfig | async\n} as data\">\n <ng-container *ngIf=\"data.hasSeriesData === true else noData\">\n <div class=\"column column_auto\">\n <teta-chart-container class=\"chart-container position-relative\"></teta-chart-container>\n </div>\n <teta-legend *ngIf=\"data.svcConfig.legend?.enable === true\" [series]=\"data.svcConfig.series\"></teta-legend>\n </ng-container>\n</ng-container>\n<ng-template #noData>\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 <span *ngIf=\"!ref.hasChildNodes()\">\n No data\n </span>\n </span>\n </div>\n</ng-template>\n", styles: [":host{position:relative;display:flex;flex-direction:column;height:100%;width:100%}\n"], dependencies: [{ kind: "directive", type: i4.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { kind: "component", type: ChartContainerComponent, selector: "teta-chart-container" }, { kind: "component", type: LegendComponent, selector: "teta-legend", inputs: ["series"] }, { kind: "pipe", type: i4.AsyncPipe, name: "async" }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
2711
+ ChartComponent.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "14.0.2", ngImport: i0, type: ChartComponent, deps: [{ token: ChartService }, { token: ZoomService }, { token: BrushService }, { token: ScaleService }], target: i0.ɵɵFactoryTarget.Component });
2712
+ ChartComponent.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "14.0.2", type: ChartComponent, selector: "teta-svg-chart", inputs: { config: "config" }, outputs: { pointerMove: "pointerMove", plotBandsMove: "plotBandsMove", plotBandClick: "plotBandClick", plotBandContextMenu: "plotBandContextMenu", plotLinesMove: "plotLinesMove", pointMove: "pointMove", chartClick: "chartClick", chartContextMenu: "chartContextMenu", annotationContextMenu: "annotationContextMenu", annotationClick: "annotationClick", annotationMove: "annotationMove", zoomServiceInstance: "zoomServiceInstance", brushServiceInstance: "brushServiceInstance" }, providers: [ChartService, ZoomService, ScaleService, BrushService], usesOnChanges: true, ngImport: i0, template: "<ng-container *ngIf=\"{\n hasSeriesData: hasSeriesData | async,\n svcConfig: svcConfig | async\n} as data\">\n <ng-container *ngIf=\"data.hasSeriesData === true else noData\">\n <div class=\"column column_auto\">\n <teta-chart-container class=\"chart-container position-relative\"></teta-chart-container>\n </div>\n <teta-legend *ngIf=\"data.svcConfig.legend?.enable === true\" [series]=\"data.svcConfig.series\"></teta-legend>\n </ng-container>\n</ng-container>\n<ng-template #noData>\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 <span *ngIf=\"!ref.hasChildNodes()\">\n No data\n </span>\n </span>\n </div>\n</ng-template>\n", styles: [":host{position:relative;display:flex;flex-direction:column;height:100%;width:100%}\n"], dependencies: [{ kind: "directive", type: i4.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { kind: "component", type: ChartContainerComponent, selector: "teta-chart-container" }, { kind: "component", type: LegendComponent, selector: "teta-legend", inputs: ["series"] }, { kind: "pipe", type: i4.AsyncPipe, name: "async" }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
2925
2713
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "14.0.2", ngImport: i0, type: ChartComponent, decorators: [{
2926
2714
  type: Component,
2927
2715
  args: [{ selector: 'teta-svg-chart', providers: [ChartService, ZoomService, ScaleService, BrushService], changeDetection: ChangeDetectionStrategy.OnPush, template: "<ng-container *ngIf=\"{\n hasSeriesData: hasSeriesData | async,\n svcConfig: svcConfig | async\n} as data\">\n <ng-container *ngIf=\"data.hasSeriesData === true else noData\">\n <div class=\"column column_auto\">\n <teta-chart-container class=\"chart-container position-relative\"></teta-chart-container>\n </div>\n <teta-legend *ngIf=\"data.svcConfig.legend?.enable === true\" [series]=\"data.svcConfig.series\"></teta-legend>\n </ng-container>\n</ng-container>\n<ng-template #noData>\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 <span *ngIf=\"!ref.hasChildNodes()\">\n No data\n </span>\n </span>\n </div>\n</ng-template>\n", styles: [":host{position:relative;display:flex;flex-direction:column;height:100%;width:100%}\n"] }]
2928
- }], ctorParameters: function () { return [{ type: ChartService }, { type: ZoomService }, { type: ScaleService }]; }, propDecorators: { pointerMove: [{
2716
+ }], ctorParameters: function () { return [{ type: ChartService }, { type: ZoomService }, { type: BrushService }, { type: ScaleService }]; }, propDecorators: { pointerMove: [{
2929
2717
  type: Output
2930
2718
  }], plotBandsMove: [{
2931
2719
  type: Output
@@ -2949,6 +2737,8 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "14.0.2", ngImpor
2949
2737
  type: Output
2950
2738
  }], zoomServiceInstance: [{
2951
2739
  type: Output
2740
+ }], brushServiceInstance: [{
2741
+ type: Output
2952
2742
  }], config: [{
2953
2743
  type: Input
2954
2744
  }] } });