@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.
- package/chart/chart/chart.component.d.ts +5 -2
- package/chart/chart-container/chart-container.component.d.ts +1 -1
- package/chart/chart-container/series/linear-series-base.d.ts +0 -3
- package/chart/core/axis/axis.d.ts +2 -2
- package/chart/directives/brushable.directive.d.ts +15 -5
- package/chart/directives/zoomable.directive.d.ts +6 -11
- package/chart/model/i-broadcast-message.d.ts +18 -19
- package/chart/model/marker-options.d.ts +1 -1
- package/chart/service/broadcast.service.d.ts +1 -4
- package/chart/service/brush.service.d.ts +6 -13
- package/chart/service/chart.service.d.ts +0 -4
- package/chart/service/scale.service.d.ts +1 -1
- package/chart/service/zoom.service.d.ts +15 -15
- package/esm2020/chart/chart/chart.component.mjs +17 -17
- package/esm2020/chart/chart-container/chart-container.component.mjs +3 -3
- package/esm2020/chart/chart-container/crosshair/crosshair.component.mjs +1 -2
- package/esm2020/chart/chart-container/plotband/plot-band.component.mjs +4 -2
- package/esm2020/chart/chart-container/series/line/line-series.component.mjs +4 -4
- package/esm2020/chart/chart-container/series/linear-series-base.mjs +4 -72
- package/esm2020/chart/core/axis/axis.mjs +2 -2
- package/esm2020/chart/directives/brushable.directive.mjs +120 -10
- package/esm2020/chart/directives/draggable-point.directive.mjs +2 -1
- package/esm2020/chart/directives/zoomable.directive.mjs +90 -197
- package/esm2020/chart/model/i-broadcast-message.mjs +4 -6
- package/esm2020/chart/model/marker-options.mjs +1 -1
- package/esm2020/chart/service/broadcast.service.mjs +4 -17
- package/esm2020/chart/service/brush.service.mjs +11 -147
- package/esm2020/chart/service/chart.service.mjs +17 -9
- package/esm2020/chart/service/scale.service.mjs +19 -21
- package/esm2020/chart/service/zoom.service.mjs +48 -53
- package/fesm2015/tetacom-svg-charts.mjs +373 -586
- package/fesm2015/tetacom-svg-charts.mjs.map +1 -1
- package/fesm2020/tetacom-svg-charts.mjs +356 -566
- package/fesm2020/tetacom-svg-charts.mjs.map +1 -1
- 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,
|
|
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(
|
|
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
|
-
|
|
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
|
|
369
|
+
class BroadcastService {
|
|
364
370
|
constructor() {
|
|
365
|
-
this.
|
|
366
|
-
|
|
367
|
-
|
|
368
|
-
this.
|
|
369
|
-
|
|
370
|
-
|
|
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
|
-
|
|
383
|
-
|
|
384
|
-
|
|
385
|
-
|
|
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
|
-
|
|
388
|
-
|
|
389
|
-
const
|
|
390
|
-
|
|
391
|
-
|
|
392
|
-
|
|
393
|
-
|
|
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
|
-
|
|
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
|
-
|
|
403
|
-
|
|
404
|
-
|
|
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
|
-
|
|
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
|
-
|
|
444
|
+
return transform;
|
|
418
445
|
}
|
|
419
|
-
|
|
420
|
-
|
|
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?.
|
|
678
|
-
zoom.
|
|
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
|
-
|
|
686
|
-
|
|
687
|
-
|
|
688
|
-
const
|
|
689
|
-
const rescaled =
|
|
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
|
-
|
|
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?.
|
|
730
|
-
zoom.
|
|
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
|
-
|
|
738
|
-
|
|
739
|
-
|
|
740
|
-
const
|
|
741
|
-
const rescaled =
|
|
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
|
-
|
|
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
|
-
|
|
828
|
-
|
|
829
|
-
|
|
830
|
-
this.
|
|
831
|
-
|
|
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
|
-
|
|
964
|
-
this.
|
|
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: [
|
|
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 [
|
|
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,
|
|
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],
|
|
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.
|
|
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
|
|
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
|
|
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
|
-
|
|
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,
|
|
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
|
-
|
|
2205
|
-
|
|
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:
|
|
2214
|
-
|
|
2215
|
-
|
|
2216
|
-
|
|
2217
|
-
|
|
2218
|
-
|
|
2219
|
-
|
|
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
|
-
|
|
2237
|
-
|
|
2238
|
-
|
|
2239
|
-
|
|
2240
|
-
|
|
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
|
-
|
|
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
|
-
|
|
2251
|
-
|
|
2252
|
-
|
|
2253
|
-
this.
|
|
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
|
-
|
|
2294
|
-
|
|
2295
|
-
|
|
2296
|
-
|
|
2297
|
-
|
|
2298
|
-
|
|
2299
|
-
|
|
2300
|
-
|
|
2301
|
-
|
|
2302
|
-
|
|
2303
|
-
(
|
|
2304
|
-
|
|
2305
|
-
|
|
2306
|
-
|
|
2307
|
-
|
|
2308
|
-
|
|
2309
|
-
|
|
2310
|
-
|
|
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
|
-
|
|
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.
|
|
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.
|
|
2108
|
+
: this.axis.orientation === AxisOrientation.y
|
|
2409
2109
|
? event.deltaY
|
|
2410
2110
|
: event.deltaX;
|
|
2411
|
-
if (this.
|
|
2111
|
+
if (this.axis.orientation === AxisOrientation.y) {
|
|
2412
2112
|
transform = transform.translate(0, this.currentTransform.y - delta / 2);
|
|
2413
2113
|
}
|
|
2414
|
-
if (this.
|
|
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.
|
|
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
|
-
|
|
2423
|
-
|
|
2424
|
-
|
|
2425
|
-
|
|
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.
|
|
2432
|
-
|
|
2433
|
-
|
|
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:
|
|
2464
|
-
ZoomableDirective.ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "14.0.2", type: ZoomableDirective, selector: "[tetaZoomable]", inputs: { config: "config", axis: "axis", size: "size"
|
|
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:
|
|
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.
|
|
2201
|
+
this.clearPreviousSelection();
|
|
2499
2202
|
}
|
|
2500
2203
|
if (this.config?.brush?.enable) {
|
|
2501
|
-
this.
|
|
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",
|
|
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
|
-
}],
|
|
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
|
|
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
|
|
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
|
}] } });
|