@tetacom/svg-charts 1.2.2 → 1.2.5
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 +2 -1
- package/chart/chart-container/chart-container.component.d.ts +3 -5
- package/chart/chart-container/series/linear-series-base.d.ts +1 -1
- package/chart/chart-container/series/scatter-series/scatter-series.component.d.ts +0 -1
- package/chart/chart-container/x-axis/x-axis.component.d.ts +2 -4
- package/chart/core/axis/axis.d.ts +3 -0
- package/chart/model/i-broadcast-message.d.ts +2 -2
- package/chart/model/i-scales-map.d.ts +5 -0
- package/chart/model/public-api.d.ts +1 -0
- package/chart/service/chart.service.d.ts +4 -0
- package/chart/service/scale.service.d.ts +2 -5
- package/esm2020/chart/chart/chart.component.mjs +14 -6
- package/esm2020/chart/chart-container/annotation/annotation.component.mjs +3 -3
- package/esm2020/chart/chart-container/chart-container.component.mjs +16 -25
- package/esm2020/chart/chart-container/gridlines/gridlines.component.mjs +11 -5
- package/esm2020/chart/chart-container/series/area-series/area-series.component.mjs +6 -9
- package/esm2020/chart/chart-container/series/bar/bar-series.component.mjs +5 -5
- package/esm2020/chart/chart-container/series/block-area-series/block-area-series.component.mjs +3 -3
- package/esm2020/chart/chart-container/series/block-series/block-series.component.mjs +3 -3
- package/esm2020/chart/chart-container/series/linear-series-base.mjs +21 -26
- package/esm2020/chart/chart-container/series/scatter-series/scatter-series.component.mjs +3 -3
- package/esm2020/chart/chart-container/x-axis/x-axis.component.mjs +3 -27
- package/esm2020/chart/chart-container/y-axis/y-axis.component.mjs +3 -3
- package/esm2020/chart/core/axis/axis.mjs +7 -1
- package/esm2020/chart/default/default-axis-config.mjs +2 -2
- package/esm2020/chart/directives/brushable.directive.mjs +1 -1
- package/esm2020/chart/directives/zoomable.directive.mjs +27 -7
- package/esm2020/chart/model/i-broadcast-message.mjs +2 -2
- package/esm2020/chart/model/i-scales-map.mjs +2 -0
- package/esm2020/chart/model/public-api.mjs +2 -1
- package/esm2020/chart/service/brush.service.mjs +20 -17
- package/esm2020/chart/service/chart.service.mjs +6 -1
- package/esm2020/chart/service/scale.service.mjs +37 -65
- package/esm2020/chart/service/zoom.service.mjs +2 -2
- package/fesm2015/tetacom-svg-charts.mjs +177 -197
- package/fesm2015/tetacom-svg-charts.mjs.map +1 -1
- package/fesm2020/tetacom-svg-charts.mjs +168 -190
- package/fesm2020/tetacom-svg-charts.mjs.map +1 -1
- package/package.json +1 -1
|
@@ -7,9 +7,9 @@ import * as d3 from 'd3';
|
|
|
7
7
|
import { zoomIdentity } from 'd3';
|
|
8
8
|
import objectHash from 'object-hash';
|
|
9
9
|
import { maxIndex } from 'd3-array';
|
|
10
|
+
import { debounceTime, tap as tap$1 } from 'rxjs/operators';
|
|
10
11
|
import { tetaZoneFull } from '@tetacom/ng-components';
|
|
11
12
|
import * as i3 from '@angular/platform-browser';
|
|
12
|
-
import { tap as tap$1, debounceTime } from 'rxjs/operators';
|
|
13
13
|
|
|
14
14
|
var ZoomType;
|
|
15
15
|
(function (ZoomType) {
|
|
@@ -94,7 +94,7 @@ const defaultAxisConfig = {
|
|
|
94
94
|
scaleType: {
|
|
95
95
|
type: ScaleType.linear,
|
|
96
96
|
},
|
|
97
|
-
niceTicks:
|
|
97
|
+
niceTicks: false,
|
|
98
98
|
};
|
|
99
99
|
|
|
100
100
|
var SeriesType;
|
|
@@ -148,6 +148,7 @@ class ChartService {
|
|
|
148
148
|
this.chartContextMenu$ = new Subject();
|
|
149
149
|
this.annotationEvent$ = new Subject();
|
|
150
150
|
this.annotationMove$ = new Subject();
|
|
151
|
+
this.zoomInstance$ = new Subject();
|
|
151
152
|
this.id = of((Date.now() + Math.random()).toString(36));
|
|
152
153
|
this.config = this.config$.asObservable().pipe(withLatestFrom(this.id), map(this.setDefaults), map(this.setPreparationData), map(this.restoreLocalStorage), shareReplay({
|
|
153
154
|
bufferSize: 1,
|
|
@@ -174,6 +175,7 @@ class ChartService {
|
|
|
174
175
|
this.plotBandContextMenu = this.plotBandEvent$
|
|
175
176
|
.asObservable()
|
|
176
177
|
.pipe(filter((_) => _?.event?.type === 'contextmenu'));
|
|
178
|
+
this.zoomInstance = this.zoomInstance$.asObservable();
|
|
177
179
|
}
|
|
178
180
|
setConfig(config) {
|
|
179
181
|
this.clearTooltips();
|
|
@@ -240,6 +242,9 @@ class ChartService {
|
|
|
240
242
|
emitChartContextMenu(event) {
|
|
241
243
|
this.chartContextMenu$.next(event);
|
|
242
244
|
}
|
|
245
|
+
emitZoomInstance(event) {
|
|
246
|
+
this.zoomInstance$.next(event);
|
|
247
|
+
}
|
|
243
248
|
saveCookie(config) {
|
|
244
249
|
if (!config.name)
|
|
245
250
|
return;
|
|
@@ -361,7 +366,7 @@ class ZoomService {
|
|
|
361
366
|
this.scaleHashMap = new Map();
|
|
362
367
|
this.elementHashMap = new Map();
|
|
363
368
|
this.zoomHashMap = new Map();
|
|
364
|
-
this.zoomed$ = new BehaviorSubject(
|
|
369
|
+
this.zoomed$ = new BehaviorSubject({});
|
|
365
370
|
this.zoomed = this.zoomed$.asObservable().pipe(shareReplay({
|
|
366
371
|
bufferSize: 1,
|
|
367
372
|
refCount: true
|
|
@@ -567,6 +572,9 @@ class Axis {
|
|
|
567
572
|
setOriginDomain(domain) {
|
|
568
573
|
this._originDomain = domain;
|
|
569
574
|
}
|
|
575
|
+
setScale(scale) {
|
|
576
|
+
this._scale = scale;
|
|
577
|
+
}
|
|
570
578
|
setSelfSize() {
|
|
571
579
|
this._selfSize = new AxisSizeBuilder().build(this);
|
|
572
580
|
}
|
|
@@ -579,6 +587,9 @@ class Axis {
|
|
|
579
587
|
: this.chartConfig.yAxis[this.index];
|
|
580
588
|
this._options = options;
|
|
581
589
|
}
|
|
590
|
+
get scale() {
|
|
591
|
+
return this._scale;
|
|
592
|
+
}
|
|
582
593
|
get extremes() {
|
|
583
594
|
return this._extremes;
|
|
584
595
|
}
|
|
@@ -622,49 +633,29 @@ class ScaleService {
|
|
|
622
633
|
.set(ScaleType.symlog, d3.scaleSymlog)
|
|
623
634
|
.set(ScaleType.pow, d3.scalePow)
|
|
624
635
|
.set(ScaleType.sqrt, d3.scaleSqrt);
|
|
625
|
-
this.
|
|
626
|
-
this.chartService.size,
|
|
627
|
-
this.chartService.config,
|
|
628
|
-
]).pipe(map((data) => {
|
|
629
|
-
const [, config] = data;
|
|
630
|
-
const map = new Map();
|
|
631
|
-
config.xAxis.map((_, index) => {
|
|
632
|
-
map.set(index, Axis.createAxis(AxisOrientation.x, config, index));
|
|
633
|
-
});
|
|
634
|
-
return map;
|
|
635
|
-
}), shareReplay({
|
|
636
|
-
bufferSize: 1,
|
|
637
|
-
refCount: true,
|
|
638
|
-
}));
|
|
639
|
-
this.yAxisMap = combineLatest([
|
|
636
|
+
this.scales = combineLatest([
|
|
640
637
|
this.chartService.size,
|
|
641
638
|
this.chartService.config,
|
|
639
|
+
this.zoomService.zoomed,
|
|
642
640
|
]).pipe(map((data) => {
|
|
643
|
-
const [, config] = data;
|
|
644
|
-
const
|
|
641
|
+
const [size, config, zoom] = data;
|
|
642
|
+
const xAxisMap = new Map();
|
|
643
|
+
const yAxisMap = new Map();
|
|
645
644
|
config.yAxis.map((_, index) => {
|
|
646
|
-
|
|
645
|
+
yAxisMap.set(index, Axis.createAxis(AxisOrientation.y, config, index));
|
|
647
646
|
});
|
|
648
|
-
|
|
649
|
-
|
|
650
|
-
|
|
651
|
-
|
|
652
|
-
|
|
653
|
-
this.xScaleMap = combineLatest([
|
|
654
|
-
this.chartService.size,
|
|
655
|
-
this.chartService.config,
|
|
656
|
-
this.zoomService.zoomed,
|
|
657
|
-
]).pipe(withLatestFrom(this.yAxisMap, this.xAxisMap), map((data) => {
|
|
658
|
-
const [[size, config, zoom], yAxes, xAxes] = data;
|
|
659
|
-
const map = new Map();
|
|
660
|
-
const left = [...yAxes.values()]
|
|
647
|
+
config.xAxis.map((_, index) => {
|
|
648
|
+
xAxisMap.set(index, Axis.createAxis(AxisOrientation.x, config, index));
|
|
649
|
+
});
|
|
650
|
+
// Generate x scales
|
|
651
|
+
const left = Array.from(yAxisMap.values())
|
|
661
652
|
.filter((_) => _.options?.visible && _.options?.opposite)
|
|
662
653
|
.reduce((acc, cur) => acc + cur.selfSize, 0);
|
|
663
|
-
const right =
|
|
654
|
+
const right = Array.from(yAxisMap.values())
|
|
664
655
|
.filter((_) => _.options?.visible && _.options?.opposite !== true)
|
|
665
656
|
.reduce((acc, cur) => acc + cur.selfSize, 0);
|
|
666
657
|
const finalWidth = (size.width || 0) - left - right;
|
|
667
|
-
|
|
658
|
+
xAxisMap.forEach((axis) => {
|
|
668
659
|
let domain = axis.extremes;
|
|
669
660
|
if (axis?.options.inverted) {
|
|
670
661
|
domain = [...axis.extremes].reverse();
|
|
@@ -679,44 +670,33 @@ class ScaleService {
|
|
|
679
670
|
if (axis.options.scaleType.type === ScaleType.log) {
|
|
680
671
|
scale.base(axis.options.scaleType.base);
|
|
681
672
|
}
|
|
682
|
-
|
|
673
|
+
axis.setScale(scale);
|
|
683
674
|
axis.setOriginDomain(scale.domain());
|
|
684
675
|
const hasCache = this.transformCacheX.has(axis.index);
|
|
685
676
|
const shouldRestore = zoom?.target?.orientation !== AxisOrientation.x ||
|
|
686
677
|
zoom.target?.index !== axis.index;
|
|
687
678
|
if (hasCache && shouldRestore) {
|
|
688
679
|
const restoredTransform = this.transformCacheX.get(axis.index);
|
|
689
|
-
|
|
680
|
+
axis.setScale(restoredTransform.rescaleX(scale));
|
|
690
681
|
}
|
|
691
682
|
});
|
|
692
683
|
if (zoom) {
|
|
693
684
|
const event = zoom.event;
|
|
694
685
|
if (zoom.target?.orientation === AxisOrientation.x) {
|
|
695
|
-
if (
|
|
696
|
-
const
|
|
697
|
-
const rescaled = event.transform.rescaleX(
|
|
698
|
-
|
|
699
|
-
const axis =
|
|
686
|
+
if (xAxisMap.has(zoom.target.index)) {
|
|
687
|
+
const x = xAxisMap.get(zoom.target.index);
|
|
688
|
+
const rescaled = event.transform.rescaleX(x.scale);
|
|
689
|
+
x.setScale(rescaled);
|
|
690
|
+
const axis = xAxisMap.get(zoom.target.index);
|
|
700
691
|
this.transformCacheX.set(axis.index, event.transform);
|
|
701
692
|
}
|
|
702
693
|
}
|
|
703
694
|
}
|
|
704
|
-
|
|
705
|
-
|
|
706
|
-
bufferSize: 1,
|
|
707
|
-
refCount: true,
|
|
708
|
-
}));
|
|
709
|
-
this.yScaleMap = combineLatest([
|
|
710
|
-
this.chartService.size,
|
|
711
|
-
this.chartService.config,
|
|
712
|
-
this.zoomService.zoomed,
|
|
713
|
-
]).pipe(withLatestFrom(this.yAxisMap, this.xAxisMap), map((data) => {
|
|
714
|
-
const [[size, config, zoom], yAxes, xAxes] = data;
|
|
715
|
-
const map = new Map();
|
|
716
|
-
const top = [...xAxes.values()]
|
|
695
|
+
// Generate y axis
|
|
696
|
+
const top = Array.from(xAxisMap.values())
|
|
717
697
|
.filter((_) => _.options?.visible && _.options?.opposite)
|
|
718
698
|
.reduce((acc, cur) => acc + cur.selfSize, 0);
|
|
719
|
-
const bottom =
|
|
699
|
+
const bottom = Array.from(xAxisMap.values())
|
|
720
700
|
.filter((_) => _.options?.visible && _.options?.opposite !== true)
|
|
721
701
|
.reduce((acc, cur) => acc + cur.selfSize, 0);
|
|
722
702
|
const finalHeight = (size.height || 0) -
|
|
@@ -724,7 +704,7 @@ class ScaleService {
|
|
|
724
704
|
bottom -
|
|
725
705
|
config?.bounds?.top -
|
|
726
706
|
config.bounds?.bottom;
|
|
727
|
-
|
|
707
|
+
yAxisMap.forEach((axis) => {
|
|
728
708
|
let domain = axis.extremes;
|
|
729
709
|
if (axis.orientation === AxisOrientation.y) {
|
|
730
710
|
domain = [...axis.extremes].reverse();
|
|
@@ -742,29 +722,32 @@ class ScaleService {
|
|
|
742
722
|
if (axis.options.scaleType.type === ScaleType.log) {
|
|
743
723
|
scale.base(axis.options.scaleType.base);
|
|
744
724
|
}
|
|
745
|
-
|
|
725
|
+
axis.setScale(scale);
|
|
746
726
|
axis.setOriginDomain(scale.domain());
|
|
747
727
|
const hasCache = this.transformCacheY.has(axis.index);
|
|
748
728
|
const shouldRestore = zoom?.target?.orientation !== AxisOrientation.y ||
|
|
749
729
|
zoom.target?.index !== axis.index;
|
|
750
730
|
if (hasCache && shouldRestore) {
|
|
751
731
|
const restoredTransform = this.transformCacheY.get(axis.index);
|
|
752
|
-
|
|
732
|
+
axis.setScale(restoredTransform.rescaleY(scale));
|
|
753
733
|
}
|
|
754
734
|
});
|
|
755
735
|
if (zoom) {
|
|
756
736
|
const event = zoom.event;
|
|
757
737
|
if (zoom.target?.orientation === AxisOrientation.y) {
|
|
758
|
-
if (
|
|
759
|
-
const
|
|
760
|
-
const rescaled = event.transform.rescaleY(
|
|
761
|
-
|
|
762
|
-
const axis =
|
|
738
|
+
if (yAxisMap.has(zoom.target.index)) {
|
|
739
|
+
const y = yAxisMap.get(zoom.target.index);
|
|
740
|
+
const rescaled = event.transform.rescaleY(y.scale);
|
|
741
|
+
y.setScale(rescaled);
|
|
742
|
+
const axis = yAxisMap.get(zoom.target.index);
|
|
763
743
|
this.transformCacheY.set(axis.index, event.transform);
|
|
764
744
|
}
|
|
765
745
|
}
|
|
766
746
|
}
|
|
767
|
-
return
|
|
747
|
+
return {
|
|
748
|
+
x: xAxisMap,
|
|
749
|
+
y: yAxisMap
|
|
750
|
+
};
|
|
768
751
|
}), shareReplay({
|
|
769
752
|
bufferSize: 1,
|
|
770
753
|
refCount: true,
|
|
@@ -791,7 +774,7 @@ class ZoomMessage {
|
|
|
791
774
|
constructor(options) {
|
|
792
775
|
this.event = options?.event;
|
|
793
776
|
this.axis = options?.axis;
|
|
794
|
-
this.
|
|
777
|
+
this.domain = options.domain;
|
|
795
778
|
this.chartId = options?.chartId;
|
|
796
779
|
this.style = options?.style;
|
|
797
780
|
}
|
|
@@ -946,29 +929,31 @@ class BrushService {
|
|
|
946
929
|
(window.TouchEvent &&
|
|
947
930
|
m.message.event.sourceEvent instanceof TouchEvent));
|
|
948
931
|
}), tap((m) => {
|
|
949
|
-
const { message: {
|
|
932
|
+
const { message: { domain }, } = m;
|
|
950
933
|
if ((m.message?.axis.index === 0 &&
|
|
951
934
|
m.message?.axis.orientation === AxisOrientation.y &&
|
|
952
935
|
config.brush?.type === BrushType.y) ||
|
|
953
936
|
(m.message?.axis.orientation === AxisOrientation.x &&
|
|
954
937
|
config.brush?.type === BrushType.x)) {
|
|
955
938
|
container.call(this.brush.move, [
|
|
956
|
-
brushScale(
|
|
957
|
-
brushScale(
|
|
939
|
+
brushScale(domain[0]),
|
|
940
|
+
brushScale(domain[1]),
|
|
958
941
|
]);
|
|
959
|
-
|
|
960
|
-
|
|
961
|
-
|
|
962
|
-
|
|
963
|
-
|
|
964
|
-
|
|
965
|
-
|
|
966
|
-
|
|
967
|
-
|
|
968
|
-
|
|
969
|
-
|
|
970
|
-
|
|
971
|
-
|
|
942
|
+
this.selection = domain;
|
|
943
|
+
}
|
|
944
|
+
}), debounceTime(30), tap((m) => {
|
|
945
|
+
const { message: { domain }, } = m;
|
|
946
|
+
if (m.message.event.type === 'zoom') {
|
|
947
|
+
const brushMessage = new BrushMessage({
|
|
948
|
+
event: null,
|
|
949
|
+
selection: domain,
|
|
950
|
+
brushType: config?.brush?.type ?? BrushType.x,
|
|
951
|
+
brushScale,
|
|
952
|
+
});
|
|
953
|
+
this.broadcastService.broadcastBrush({
|
|
954
|
+
channel: config?.zoom?.syncChannel,
|
|
955
|
+
message: brushMessage,
|
|
956
|
+
});
|
|
972
957
|
}
|
|
973
958
|
}))
|
|
974
959
|
.subscribe();
|
|
@@ -1067,17 +1052,14 @@ class LinearSeriesBase extends SeriesBaseComponent {
|
|
|
1067
1052
|
};
|
|
1068
1053
|
this.defaultClipPointsMapping.set(ClipPointsDirection.x, filterX);
|
|
1069
1054
|
this.defaultClipPointsMapping.set(ClipPointsDirection.y, filterY);
|
|
1070
|
-
this.transform = this.svc.pointerMove.pipe(withLatestFrom(this.scaleService.
|
|
1071
|
-
const [event, x, y] = data;
|
|
1072
|
-
return this.getTransform(event, x, y);
|
|
1055
|
+
this.transform = this.svc.pointerMove.pipe(withLatestFrom(this.scaleService.scales), map((data) => {
|
|
1056
|
+
const [event, { x, y }] = data;
|
|
1057
|
+
return this.getTransform(event, x.get(this.series.xAxisIndex).scale, y.get(this.series.yAxisIndex).scale);
|
|
1073
1058
|
}), tap(() => setTimeout(() => this.cdr.detectChanges())));
|
|
1074
|
-
this.path =
|
|
1075
|
-
|
|
1076
|
-
this.
|
|
1077
|
-
|
|
1078
|
-
const [x, y] = data;
|
|
1079
|
-
this.x = x.get(this.series.xAxisIndex);
|
|
1080
|
-
this.y = y.get(this.series.yAxisIndex);
|
|
1059
|
+
this.path = this.scaleService.scales.pipe(map((data) => {
|
|
1060
|
+
const { x, y } = data;
|
|
1061
|
+
this.x = x.get(this.series.xAxisIndex).scale;
|
|
1062
|
+
this.y = y.get(this.series.yAxisIndex).scale;
|
|
1081
1063
|
const filter = this.defaultClipPointsMapping.get(this.series.clipPointsDirection);
|
|
1082
1064
|
const line = d3
|
|
1083
1065
|
.line()
|
|
@@ -1160,8 +1142,6 @@ class LinearSeriesBase extends SeriesBaseComponent {
|
|
|
1160
1142
|
return null;
|
|
1161
1143
|
}
|
|
1162
1144
|
const mouse = [event?.offsetX, event?.offsetY];
|
|
1163
|
-
const foundX = scaleX.get(this.series.xAxisIndex);
|
|
1164
|
-
const foundY = scaleY.get(this.series.yAxisIndex);
|
|
1165
1145
|
const tooltipTracking = this.config?.tooltip?.tracking;
|
|
1166
1146
|
const lineIntersection = (p0_x, p0_y, p1_x, p1_y, p2_x, p2_y, p3_x, p3_y) => {
|
|
1167
1147
|
const rV = {};
|
|
@@ -1187,18 +1167,18 @@ class LinearSeriesBase extends SeriesBaseComponent {
|
|
|
1187
1167
|
if (tooltipTracking === TooltipTracking.x) {
|
|
1188
1168
|
const bisect = d3.bisector((_) => _.x).right;
|
|
1189
1169
|
const pointer = mouse[0];
|
|
1190
|
-
let x0 =
|
|
1170
|
+
let x0 = scaleX.invert(pointer);
|
|
1191
1171
|
if (x0 instanceof Date) {
|
|
1192
1172
|
x0 = x0.getTime();
|
|
1193
1173
|
}
|
|
1194
1174
|
const rightId = bisect(this.series.data, x0);
|
|
1195
|
-
const range =
|
|
1196
|
-
const intersect = lineIntersection(pointer, range[0], pointer, range[1],
|
|
1197
|
-
const x =
|
|
1198
|
-
const y =
|
|
1175
|
+
const range = scaleY.range();
|
|
1176
|
+
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));
|
|
1177
|
+
const x = scaleX.invert(intersect.x);
|
|
1178
|
+
const y = scaleY.invert(intersect.y);
|
|
1199
1179
|
if (x !== null && x !== undefined && !isNaN(x) && y !== null && y !== undefined && !isNaN(y)) {
|
|
1200
1180
|
this.svc.setTooltip({
|
|
1201
|
-
point: { x:
|
|
1181
|
+
point: { x: scaleX.invert(intersect.x), y: scaleY.invert(intersect.y) },
|
|
1202
1182
|
series: this.series,
|
|
1203
1183
|
});
|
|
1204
1184
|
}
|
|
@@ -1215,18 +1195,18 @@ class LinearSeriesBase extends SeriesBaseComponent {
|
|
|
1215
1195
|
}
|
|
1216
1196
|
if (tooltipTracking === TooltipTracking.y) {
|
|
1217
1197
|
const bisect = d3.bisector((_) => _.y).right;
|
|
1218
|
-
let y0 =
|
|
1198
|
+
let y0 = scaleY.invert(mouse[1]);
|
|
1219
1199
|
if (y0 instanceof Date) {
|
|
1220
1200
|
y0 = y0.getTime();
|
|
1221
1201
|
}
|
|
1222
1202
|
const rightId = bisect(this.series.data, y0);
|
|
1223
|
-
const range =
|
|
1224
|
-
const intersect = lineIntersection(range[0], mouse[1], range[1], mouse[1],
|
|
1225
|
-
const x =
|
|
1226
|
-
const y =
|
|
1203
|
+
const range = scaleX.range();
|
|
1204
|
+
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));
|
|
1205
|
+
const x = scaleX.invert(intersect.x);
|
|
1206
|
+
const y = scaleY.invert(intersect.y);
|
|
1227
1207
|
if (x !== null && x !== undefined && !isNaN(x) && y !== null && y !== undefined && !isNaN(y)) {
|
|
1228
1208
|
this.svc.setTooltip({
|
|
1229
|
-
point: { x:
|
|
1209
|
+
point: { x: scaleX.invert(intersect.x), y: scaleY.invert(intersect.y) },
|
|
1230
1210
|
series: this.series,
|
|
1231
1211
|
});
|
|
1232
1212
|
}
|
|
@@ -1284,8 +1264,8 @@ class BarSeriesComponent extends SeriesBaseComponent {
|
|
|
1284
1264
|
const count = _.series.filter((_) => _.type === SeriesType.bar && _.xAxisIndex === this.series.xAxisIndex);
|
|
1285
1265
|
return count.length;
|
|
1286
1266
|
}));
|
|
1287
|
-
this.x1 = this.scaleService.
|
|
1288
|
-
const x = _.get(this.series.xAxisIndex);
|
|
1267
|
+
this.x1 = this.scaleService.scales.pipe(map((_) => {
|
|
1268
|
+
const x = _.x.get(this.series.xAxisIndex).scale;
|
|
1289
1269
|
const range = x.range();
|
|
1290
1270
|
const domain = this.series.data.map((_) => _.x);
|
|
1291
1271
|
return d3
|
|
@@ -1294,8 +1274,8 @@ class BarSeriesComponent extends SeriesBaseComponent {
|
|
|
1294
1274
|
.domain(domain)
|
|
1295
1275
|
.padding(0.1);
|
|
1296
1276
|
}));
|
|
1297
|
-
this.x = this.scaleService.
|
|
1298
|
-
this.y = this.scaleService.
|
|
1277
|
+
this.x = this.scaleService.scales.pipe(map((_) => _.x.get(this.series.xAxisIndex).scale));
|
|
1278
|
+
this.y = this.scaleService.scales.pipe(map((_) => _.y.get(this.series.yAxisIndex).scale));
|
|
1299
1279
|
}
|
|
1300
1280
|
mouseenter(point) {
|
|
1301
1281
|
this.svc.setTooltip({
|
|
@@ -1328,8 +1308,8 @@ class ScatterSeriesComponent extends SeriesBaseComponent {
|
|
|
1328
1308
|
this.element = element;
|
|
1329
1309
|
}
|
|
1330
1310
|
ngOnInit() {
|
|
1331
|
-
this.x = this.scaleService.
|
|
1332
|
-
this.y = this.scaleService.
|
|
1311
|
+
this.x = this.scaleService.scales.pipe(map(_ => _.x.get(this.series.xAxisIndex).scale));
|
|
1312
|
+
this.y = this.scaleService.scales.pipe(map(_ => _.y.get(this.series.yAxisIndex).scale));
|
|
1333
1313
|
}
|
|
1334
1314
|
ngAfterViewInit() {
|
|
1335
1315
|
}
|
|
@@ -1367,8 +1347,8 @@ class BlockSeriesComponent extends SeriesBaseComponent {
|
|
|
1367
1347
|
}
|
|
1368
1348
|
ngOnInit() {
|
|
1369
1349
|
const defaultVisiblePixels = 0;
|
|
1370
|
-
this.x = this.scaleService.
|
|
1371
|
-
this.y = this.scaleService.
|
|
1350
|
+
this.x = this.scaleService.scales.pipe(map((_) => _.x.get(this.series.xAxisIndex).scale));
|
|
1351
|
+
this.y = this.scaleService.scales.pipe(map((_) => _.y.get(this.series.yAxisIndex).scale));
|
|
1372
1352
|
this.displayPoints = this.y.pipe(map((y) => {
|
|
1373
1353
|
return this.series.data.filter((point, index, arr) => {
|
|
1374
1354
|
const [min, max] = y.domain();
|
|
@@ -1419,8 +1399,8 @@ class BlockAreaSeriesComponent extends SeriesBaseComponent {
|
|
|
1419
1399
|
}
|
|
1420
1400
|
ngOnInit() {
|
|
1421
1401
|
const defaultVisiblePixels = 0;
|
|
1422
|
-
this.x = this.scaleService.
|
|
1423
|
-
this.y = this.scaleService.
|
|
1402
|
+
this.x = this.scaleService.scales.pipe(map((_) => _.x.get(this.series.xAxisIndex).scale));
|
|
1403
|
+
this.y = this.scaleService.scales.pipe(map((_) => _.y.get(this.series.yAxisIndex).scale));
|
|
1424
1404
|
this.displayPoints = this.y.pipe(map((y) => {
|
|
1425
1405
|
return this.series.data.filter((point, index, arr) => {
|
|
1426
1406
|
const [min, max] = y.domain();
|
|
@@ -1471,13 +1451,10 @@ class AreaSeriesComponent extends LinearSeriesBase {
|
|
|
1471
1451
|
}
|
|
1472
1452
|
ngOnInit() {
|
|
1473
1453
|
super.ngOnInit();
|
|
1474
|
-
this.areaPath =
|
|
1475
|
-
|
|
1476
|
-
this.
|
|
1477
|
-
|
|
1478
|
-
const [x, y] = data;
|
|
1479
|
-
this.x = x.get(this.series.xAxisIndex);
|
|
1480
|
-
this.y = y.get(this.series.yAxisIndex);
|
|
1454
|
+
this.areaPath = this.scaleService.scales.pipe(map((data) => {
|
|
1455
|
+
const { x, y } = data;
|
|
1456
|
+
this.x = x.get(this.series.xAxisIndex).scale;
|
|
1457
|
+
this.y = y.get(this.series.yAxisIndex).scale;
|
|
1481
1458
|
const area = d3
|
|
1482
1459
|
.area()
|
|
1483
1460
|
.defined((point) => point.x !== null &&
|
|
@@ -1567,10 +1544,16 @@ class GridlinesComponent {
|
|
|
1567
1544
|
this.svc = svc;
|
|
1568
1545
|
this.chartService = chartService;
|
|
1569
1546
|
this.config = this.chartService.config;
|
|
1570
|
-
this.tickYValues = this.svc.
|
|
1571
|
-
|
|
1572
|
-
|
|
1573
|
-
|
|
1547
|
+
this.tickYValues = this.svc.scales.pipe(map((_) => {
|
|
1548
|
+
const ratio = this.size.height / 40;
|
|
1549
|
+
return _.y.get(0).scale.ticks(ratio);
|
|
1550
|
+
}));
|
|
1551
|
+
this.tickXValues = this.svc.scales.pipe(map((_) => {
|
|
1552
|
+
const ratio = this.size.width / 40;
|
|
1553
|
+
return _.x.get(0).scale.ticks(ratio);
|
|
1554
|
+
}));
|
|
1555
|
+
this.y = this.svc.scales.pipe(map((_) => _.y.get(0).scale));
|
|
1556
|
+
this.x = this.svc.scales.pipe(map((_) => _.x.get(0).scale));
|
|
1574
1557
|
}
|
|
1575
1558
|
ngAfterViewInit() {
|
|
1576
1559
|
}
|
|
@@ -1588,8 +1571,8 @@ class XAxisComponent {
|
|
|
1588
1571
|
constructor(scaleService) {
|
|
1589
1572
|
this.scaleService = scaleService;
|
|
1590
1573
|
this._alive = true;
|
|
1591
|
-
this.x = this.scaleService.
|
|
1592
|
-
return _.get(this.axis.index);
|
|
1574
|
+
this.x = this.scaleService.scales.pipe(map((_) => {
|
|
1575
|
+
return _.x.get(this.axis.index)?.scale;
|
|
1593
1576
|
}));
|
|
1594
1577
|
}
|
|
1595
1578
|
getLabelTransform() {
|
|
@@ -1599,30 +1582,6 @@ class XAxisComponent {
|
|
|
1599
1582
|
ngOnDestroy() {
|
|
1600
1583
|
this._alive = false;
|
|
1601
1584
|
}
|
|
1602
|
-
ngAfterViewInit() {
|
|
1603
|
-
// this.draw();
|
|
1604
|
-
}
|
|
1605
|
-
draw() {
|
|
1606
|
-
// if (!this.node || !this.axis) {
|
|
1607
|
-
// return;
|
|
1608
|
-
// }
|
|
1609
|
-
//
|
|
1610
|
-
// const axis = this.axis.options.opposite
|
|
1611
|
-
// ? d3
|
|
1612
|
-
// .axisTop(this.scale)
|
|
1613
|
-
// .tickFormat(
|
|
1614
|
-
// this.axis.options.tickFormat ?? this.axis.defaultFormatter()
|
|
1615
|
-
// )
|
|
1616
|
-
// : d3
|
|
1617
|
-
// .axisBottom(this.scale)
|
|
1618
|
-
// .tickFormat(
|
|
1619
|
-
// this.axis.options.tickFormat ?? this.axis.defaultFormatter()
|
|
1620
|
-
// );
|
|
1621
|
-
//
|
|
1622
|
-
// d3.select(this.node.nativeElement)
|
|
1623
|
-
// .call(axis)
|
|
1624
|
-
// .call((_) => _.select('.domain').remove());
|
|
1625
|
-
}
|
|
1626
1585
|
}
|
|
1627
1586
|
XAxisComponent.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "14.0.2", ngImport: i0, type: XAxisComponent, deps: [{ token: ScaleService }], target: i0.ɵɵFactoryTarget.Component });
|
|
1628
1587
|
XAxisComponent.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "14.0.2", type: XAxisComponent, selector: "[teta-x-axis]", inputs: { axis: "axis", size: "size" }, ngImport: i0, template: "<ng-container *ngIf=\"x | async as scale\">\n <svg:g text-anchor=\"middle\" *ngFor=\"let tick of scale.ticks()\" [attr.transform]=\"'translate('+ scale(tick) +', 0)'\">\n <text fill=\"var(--color-text-70)\" [attr.dy]=\"axis.options.opposite ? '-0.71em' : '0.71em'\" [attr.y]=\"axis.options.opposite ? 0 : 9\">{{ this.axis.options.tickFormat ? this.axis.options.tickFormat(tick) : this.axis.defaultFormatter()(tick) }}</text>\n <line stroke=\"var(--color-text-30)\" [attr.y2]=\"axis.options.opposite ? -6 : 6\"></line>\n </svg:g>\n\n <svg:g class=\"label-axis font-caption\" [attr.transform]=\"getLabelTransform()\">\n <text fill=\"var(--color-text-70)\" text-anchor=\"middle\" dominant-baseline=\"middle\">{{ axis.options.title }}</text>\n </svg:g>\n</ng-container>\n\n", styles: [":host .tick{stroke:var(--color-text-20)}\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: "pipe", type: i4.AsyncPipe, name: "async" }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
|
|
@@ -1639,8 +1598,8 @@ class YAxisComponent {
|
|
|
1639
1598
|
constructor(scaleService) {
|
|
1640
1599
|
this.scaleService = scaleService;
|
|
1641
1600
|
this._alive = true;
|
|
1642
|
-
this.y = this.scaleService.
|
|
1643
|
-
return _.get(this.axis.index);
|
|
1601
|
+
this.y = this.scaleService.scales.pipe(map((_) => {
|
|
1602
|
+
return _.y.get(this.axis.index)?.scale;
|
|
1644
1603
|
}));
|
|
1645
1604
|
}
|
|
1646
1605
|
ngOnInit() { }
|
|
@@ -1996,7 +1955,7 @@ class ZoomableDirective {
|
|
|
1996
1955
|
const message = new ZoomMessage({
|
|
1997
1956
|
event,
|
|
1998
1957
|
axis: this.axis,
|
|
1999
|
-
|
|
1958
|
+
domain,
|
|
2000
1959
|
chartId: this.config.id,
|
|
2001
1960
|
});
|
|
2002
1961
|
this.broadcastService.broadcastZoom({
|
|
@@ -2063,6 +2022,7 @@ class ZoomableDirective {
|
|
|
2063
2022
|
this.zoom.scaleExtent([maxZoom, minZoom]);
|
|
2064
2023
|
this.zoom.on('zoom end', this.zoomed);
|
|
2065
2024
|
this._element.call(this.zoom).on('dblclick.zoom', null); // Disable dbclick zoom
|
|
2025
|
+
this.chartService.emitZoomInstance(this.zoomService);
|
|
2066
2026
|
if (this.config?.zoom?.zoomBehavior === ZoomBehaviorType.wheel) {
|
|
2067
2027
|
this.runWheelZoom();
|
|
2068
2028
|
}
|
|
@@ -2083,7 +2043,26 @@ class ZoomableDirective {
|
|
|
2083
2043
|
this.axis.orientation === m.message?.axis?.orientation);
|
|
2084
2044
|
}), tap$1((m) => {
|
|
2085
2045
|
if (this.config.id !== m.message?.chartId) {
|
|
2086
|
-
this.
|
|
2046
|
+
this.brushScale.domain(this.axis.originDomain);
|
|
2047
|
+
const scale = Math.abs(this.axis.originDomain[1] - this.axis.originDomain[0]) / Math.abs(m.message.domain[1] - m.message.domain[0]);
|
|
2048
|
+
let transform = zoomIdentity.scale(scale);
|
|
2049
|
+
if (this.config?.zoom?.type === ZoomType.x) {
|
|
2050
|
+
if (this.config.xAxis[0]?.inverted) {
|
|
2051
|
+
transform = transform.translate(-this.brushScale(m.message.domain[0]), 0);
|
|
2052
|
+
}
|
|
2053
|
+
else {
|
|
2054
|
+
transform = transform.translate(this.brushScale(-m.message.domain[1]), 0);
|
|
2055
|
+
}
|
|
2056
|
+
}
|
|
2057
|
+
if (this.config?.zoom?.type === ZoomType.y) {
|
|
2058
|
+
if (this.config.yAxis[0]?.inverted) {
|
|
2059
|
+
transform = transform.translate(0, -this.brushScale(m.message.domain[0]));
|
|
2060
|
+
}
|
|
2061
|
+
else {
|
|
2062
|
+
transform = transform.translate(0, -this.brushScale(m.message.domain[1]));
|
|
2063
|
+
}
|
|
2064
|
+
}
|
|
2065
|
+
this._element.call(this.zoom.transform, transform, null, {});
|
|
2087
2066
|
}
|
|
2088
2067
|
}))
|
|
2089
2068
|
.subscribe();
|
|
@@ -2096,7 +2075,7 @@ class ZoomableDirective {
|
|
|
2096
2075
|
.pipe(combineLatestWith(this.chartService.size), takeWhile((_) => this.alive), filter((data) => {
|
|
2097
2076
|
const [m] = data;
|
|
2098
2077
|
return Boolean(m.message.selection);
|
|
2099
|
-
}),
|
|
2078
|
+
}), tap$1((data) => {
|
|
2100
2079
|
const [m] = data;
|
|
2101
2080
|
const currentTransform = d3.zoomTransform(this._element.node());
|
|
2102
2081
|
if (!m.message.event &&
|
|
@@ -2180,7 +2159,7 @@ class ZoomableDirective {
|
|
|
2180
2159
|
type,
|
|
2181
2160
|
},
|
|
2182
2161
|
axis: this.axis,
|
|
2183
|
-
|
|
2162
|
+
domain,
|
|
2184
2163
|
chartId: this.config.id,
|
|
2185
2164
|
});
|
|
2186
2165
|
this.zoomService.fireZoom({
|
|
@@ -2275,8 +2254,8 @@ class AnnotationComponent {
|
|
|
2275
2254
|
this.scaleService = scaleService;
|
|
2276
2255
|
this.cdr = cdr;
|
|
2277
2256
|
this.chartService = chartService;
|
|
2278
|
-
this.x = this.scaleService.
|
|
2279
|
-
this.y = this.scaleService.
|
|
2257
|
+
this.x = this.scaleService.scales.pipe(map((_) => _.x.get(this.annotation.xAxisIndex ?? 0).scale));
|
|
2258
|
+
this.y = this.scaleService.scales.pipe(map((_) => _.y.get(this.annotation.yAxisIndex ?? 0).scale));
|
|
2280
2259
|
this.drag = d3.drag();
|
|
2281
2260
|
}
|
|
2282
2261
|
set annotation(annotation) {
|
|
@@ -2390,30 +2369,21 @@ class ChartContainerComponent {
|
|
|
2390
2369
|
this.sumSize = (acc, curr) => acc + curr.selfSize;
|
|
2391
2370
|
this.config = this._svc.config;
|
|
2392
2371
|
this.size = this._svc.size;
|
|
2393
|
-
this.
|
|
2394
|
-
this.xAxisMap = this._scaleService.xAxisMap;
|
|
2395
|
-
this.yScaleMap = this._scaleService.yScaleMap.pipe(observeOn(animationFrameScheduler, 10), tetaZoneFull(this._zone), shareReplay({
|
|
2396
|
-
bufferSize: 1,
|
|
2397
|
-
refCount: true,
|
|
2398
|
-
}));
|
|
2399
|
-
this.xScaleMap = this._scaleService.xScaleMap.pipe(observeOn(animationFrameScheduler, 10), tetaZoneFull(this._zone), shareReplay({
|
|
2372
|
+
this.scales = this._scaleService.scales.pipe(observeOn(animationFrameScheduler), tetaZoneFull(this._zone), shareReplay({
|
|
2400
2373
|
bufferSize: 1,
|
|
2401
2374
|
refCount: true,
|
|
2402
2375
|
}));
|
|
2403
|
-
this.brushScale =
|
|
2404
|
-
|
|
2405
|
-
|
|
2406
|
-
]).pipe(withLatestFrom(this.config), map((data) => {
|
|
2407
|
-
const [[x, y], config] = data;
|
|
2408
|
-
return config.brush?.type === BrushType.x || config?.zoom?.type === ZoomType.x ? x.get(0) : y.get(0);
|
|
2376
|
+
this.brushScale = this._scaleService.scales.pipe(withLatestFrom(this.config), map((data) => {
|
|
2377
|
+
const [{ x, y }, config] = data;
|
|
2378
|
+
return config.brush?.type === BrushType.x || config?.zoom?.type === ZoomType.x ? x.get(0).scale : y.get(0).scale;
|
|
2409
2379
|
}), shareReplay({
|
|
2410
2380
|
bufferSize: 1,
|
|
2411
2381
|
refCount: true,
|
|
2412
2382
|
}));
|
|
2413
|
-
this.visibleRect = this.size.pipe(combineLatestWith(this.
|
|
2414
|
-
const [[size, x, y], config] = data;
|
|
2415
|
-
const yAxesArray =
|
|
2416
|
-
const xAxesArray =
|
|
2383
|
+
this.visibleRect = this.size.pipe(combineLatestWith(this.scales)).pipe(withLatestFrom(this.config), map((data) => {
|
|
2384
|
+
const [[size, { x, y }], config] = data;
|
|
2385
|
+
const yAxesArray = Array.from(y.values());
|
|
2386
|
+
const xAxesArray = Array.from(x.values());
|
|
2417
2387
|
const left = yAxesArray
|
|
2418
2388
|
.filter((_) => _.options.opposite !== true && _.options.visible)
|
|
2419
2389
|
.reduce(this.sumSize, 0);
|
|
@@ -2465,10 +2435,10 @@ class ChartContainerComponent {
|
|
|
2465
2435
|
this._observer.disconnect();
|
|
2466
2436
|
}
|
|
2467
2437
|
getTranslate(axis, size) {
|
|
2468
|
-
return
|
|
2469
|
-
const [
|
|
2470
|
-
const xAxesArray =
|
|
2471
|
-
const yAxesArray =
|
|
2438
|
+
return this.scales.pipe(withLatestFrom(this.config), map((data) => {
|
|
2439
|
+
const [{ x, y }, config] = data;
|
|
2440
|
+
const xAxesArray = Array.from(x.values());
|
|
2441
|
+
const yAxesArray = Array.from(y.values());
|
|
2472
2442
|
const oppositeFilter = this.filterPositionMap.get(true);
|
|
2473
2443
|
const nonOppositeFilter = this.filterPositionMap.get(false);
|
|
2474
2444
|
const oppositeOffsetY = yAxesArray.filter(oppositeFilter(axis));
|
|
@@ -2531,10 +2501,10 @@ class ChartContainerComponent {
|
|
|
2531
2501
|
}
|
|
2532
2502
|
}
|
|
2533
2503
|
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 });
|
|
2534
|
-
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
|
|
2504
|
+
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.visibleRect?.width > 0 && data.visibleRect?.height > 0 && data.scales.x && data.scales.y\">\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 && data.scales.y\">\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.visibleRect?.width > 0 && data.visibleRect?.height > 0 && data.scales.x && data.scales.y\">\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.size\"\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.size\"\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.x.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 });
|
|
2535
2505
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "14.0.2", ngImport: i0, type: ChartContainerComponent, decorators: [{
|
|
2536
2506
|
type: Component,
|
|
2537
|
-
args: [{ selector: 'teta-chart-container', changeDetection: ChangeDetectionStrategy.OnPush, template: "<ng-container *ngIf=\"{\n size: size | async,\n config: config | async,\n
|
|
2507
|
+
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.visibleRect?.width > 0 && data.visibleRect?.height > 0 && data.scales.x && data.scales.y\">\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 && data.scales.y\">\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.visibleRect?.width > 0 && data.visibleRect?.height > 0 && data.scales.x && data.scales.y\">\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.size\"\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.size\"\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.x.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"] }]
|
|
2538
2508
|
}], ctorParameters: function () { return [{ type: ChartService }, { type: i0.ChangeDetectorRef }, { type: ScaleService }, { type: ZoomService }, { type: i0.ElementRef }, { type: i0.NgZone }]; } });
|
|
2539
2509
|
|
|
2540
2510
|
class LegendComponent {
|
|
@@ -2584,6 +2554,7 @@ class ChartComponent {
|
|
|
2584
2554
|
this.annotationContextMenu = new EventEmitter();
|
|
2585
2555
|
this.annotationClick = new EventEmitter();
|
|
2586
2556
|
this.annotationMove = new EventEmitter();
|
|
2557
|
+
this.zoomServiceInstance = new EventEmitter();
|
|
2587
2558
|
this._alive = true;
|
|
2588
2559
|
this.svcConfig = this.chartService.config;
|
|
2589
2560
|
this.hasSeriesData = this.svcConfig.pipe(map((_) => _.series?.length > 0 && _.series?.some((_) => _.data?.length > 0)));
|
|
@@ -2595,14 +2566,14 @@ class ChartComponent {
|
|
|
2595
2566
|
}
|
|
2596
2567
|
ngOnInit() {
|
|
2597
2568
|
this.chartService.pointerMove
|
|
2598
|
-
.pipe(takeWhile(() => this._alive), withLatestFrom(this.scaleService.
|
|
2569
|
+
.pipe(takeWhile(() => this._alive), withLatestFrom(this.scaleService.scales, this.chartService.config))
|
|
2599
2570
|
.subscribe((data) => {
|
|
2600
|
-
const [event, x, y, config] = data;
|
|
2571
|
+
const [event, { x, y }, config] = data;
|
|
2601
2572
|
const tooltipTracking = config?.tooltip?.tracking;
|
|
2602
2573
|
if (tooltipTracking === TooltipTracking.y) {
|
|
2603
2574
|
const result = new Map();
|
|
2604
2575
|
y.forEach((value, key) => {
|
|
2605
|
-
result.set(key, value.invert(event.offsetY));
|
|
2576
|
+
result.set(key, value.scale.invert(event.offsetY));
|
|
2606
2577
|
});
|
|
2607
2578
|
this.pointerMove.emit({
|
|
2608
2579
|
event: event,
|
|
@@ -2612,7 +2583,7 @@ class ChartComponent {
|
|
|
2612
2583
|
else {
|
|
2613
2584
|
const result = new Map();
|
|
2614
2585
|
x.forEach((value, key) => {
|
|
2615
|
-
result.set(key, value.invert(event.offsetX));
|
|
2586
|
+
result.set(key, value.scale.invert(event.offsetX));
|
|
2616
2587
|
});
|
|
2617
2588
|
this.pointerMove.emit({
|
|
2618
2589
|
event: event,
|
|
@@ -2664,6 +2635,11 @@ class ChartComponent {
|
|
|
2664
2635
|
.subscribe((_) => {
|
|
2665
2636
|
this.annotationMove.emit(_);
|
|
2666
2637
|
});
|
|
2638
|
+
this.chartService.zoomInstance
|
|
2639
|
+
.pipe(takeWhile(() => this._alive))
|
|
2640
|
+
.subscribe((_) => {
|
|
2641
|
+
this.zoomServiceInstance.emit(_);
|
|
2642
|
+
});
|
|
2667
2643
|
}
|
|
2668
2644
|
ngAfterViewInit() {
|
|
2669
2645
|
}
|
|
@@ -2675,7 +2651,7 @@ class ChartComponent {
|
|
|
2675
2651
|
}
|
|
2676
2652
|
}
|
|
2677
2653
|
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 });
|
|
2678
|
-
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" }, 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 align-center justify-content-center\">\n <span class=\"font-body-3 color-text-40\">\u0414\u0430\u043D\u043D\u044B\u0435 \u043E\u0442\u0441\u0443\u0442\u0441\u0442\u0432\u0443\u044E\u0442</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 });
|
|
2654
|
+
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 align-center justify-content-center\">\n <span class=\"font-body-3 color-text-40\">\u0414\u0430\u043D\u043D\u044B\u0435 \u043E\u0442\u0441\u0443\u0442\u0441\u0442\u0432\u0443\u044E\u0442</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 });
|
|
2679
2655
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "14.0.2", ngImport: i0, type: ChartComponent, decorators: [{
|
|
2680
2656
|
type: Component,
|
|
2681
2657
|
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 align-center justify-content-center\">\n <span class=\"font-body-3 color-text-40\">\u0414\u0430\u043D\u043D\u044B\u0435 \u043E\u0442\u0441\u0443\u0442\u0441\u0442\u0432\u0443\u044E\u0442</span>\n </div>\n</ng-template>\n", styles: [":host{position:relative;display:flex;flex-direction:column;height:100%;width:100%}\n"] }]
|
|
@@ -2701,6 +2677,8 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "14.0.2", ngImpor
|
|
|
2701
2677
|
type: Output
|
|
2702
2678
|
}], annotationMove: [{
|
|
2703
2679
|
type: Output
|
|
2680
|
+
}], zoomServiceInstance: [{
|
|
2681
|
+
type: Output
|
|
2704
2682
|
}], config: [{
|
|
2705
2683
|
type: Input
|
|
2706
2684
|
}] } });
|