@tetacom/svg-charts 1.0.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (216) hide show
  1. package/.browserslistrc +16 -0
  2. package/README.md +24 -0
  3. package/dist/README.md +24 -0
  4. package/dist/chart/base/series-base.component.d.ts +22 -0
  5. package/dist/chart/chart/chart.component.d.ts +29 -0
  6. package/dist/chart/chart-container/chart-container.component.d.ts +42 -0
  7. package/dist/chart/chart-container/gridlines/gridlines.component.d.ts +23 -0
  8. package/dist/chart/chart-container/plotband/plotband.component.d.ts +33 -0
  9. package/dist/chart/chart-container/plotline/plotline.component.d.ts +30 -0
  10. package/dist/chart/chart-container/series/bar/bar-series.component.d.ts +25 -0
  11. package/dist/chart/chart-container/series/line/line-series.component.d.ts +28 -0
  12. package/dist/chart/chart-container/series-host/series-host.component.d.ts +20 -0
  13. package/dist/chart/chart-container/tooltip/tooltip.component.d.ts +29 -0
  14. package/dist/chart/chart-container/x-axis/x-axis.component.d.ts +23 -0
  15. package/dist/chart/chart-container/y-axis/y-axis.component.d.ts +24 -0
  16. package/dist/chart/chart.module.d.ts +22 -0
  17. package/dist/chart/core/axis/axis.d.ts +54 -0
  18. package/dist/chart/core/axis/builders/axis-size-builder.d.ts +8 -0
  19. package/dist/chart/core/axis/builders/extremes-builder.d.ts +7 -0
  20. package/dist/chart/core/axis/builders/public-api.d.ts +2 -0
  21. package/dist/chart/core/utils/generate-ticks.d.ts +1 -0
  22. package/dist/chart/core/utils/get-text-width.d.ts +1 -0
  23. package/dist/chart/core/utils/public-api.d.ts +2 -0
  24. package/dist/chart/directives/brushable.directive.d.ts +17 -0
  25. package/dist/chart/directives/zoomable.directive.d.ts +20 -0
  26. package/dist/chart/legend/legend.component.d.ts +14 -0
  27. package/dist/chart/model/axis-options.d.ts +17 -0
  28. package/dist/chart/model/base-point.d.ts +9 -0
  29. package/dist/chart/model/chart-bounds.d.ts +12 -0
  30. package/dist/chart/model/enum/axis-orientation.d.ts +4 -0
  31. package/dist/chart/model/enum/axis-type.d.ts +7 -0
  32. package/dist/chart/model/enum/brush-type.d.ts +5 -0
  33. package/dist/chart/model/enum/drag-point-type.d.ts +5 -0
  34. package/dist/chart/model/enum/series-type.d.ts +4 -0
  35. package/dist/chart/model/enum/tooltip-tracking.d.ts +4 -0
  36. package/dist/chart/model/enum/zoom-type.d.ts +5 -0
  37. package/dist/chart/model/i-broadcast-message.d.ts +5 -0
  38. package/dist/chart/model/i-builder.d.ts +3 -0
  39. package/dist/chart/model/i-chart-config.d.ts +32 -0
  40. package/dist/chart/model/i-chart-event.d.ts +4 -0
  41. package/dist/chart/model/i-display-tooltip.d.ts +6 -0
  42. package/dist/chart/model/i-point-move.d.ts +6 -0
  43. package/dist/chart/model/marker-options.d.ts +7 -0
  44. package/dist/chart/model/plotband.d.ts +31 -0
  45. package/dist/chart/model/plotline.d.ts +19 -0
  46. package/dist/chart/model/series.d.ts +17 -0
  47. package/dist/chart/model/svg-attributes.d.ts +14 -0
  48. package/dist/chart/model/tooltip-options.d.ts +8 -0
  49. package/dist/chart/service/axes.service.d.ts +11 -0
  50. package/dist/chart/service/broadcast.service.d.ts +11 -0
  51. package/dist/chart/service/brush.service.d.ts +17 -0
  52. package/dist/chart/service/chart.service.d.ts +38 -0
  53. package/dist/chart/service/scale.service.d.ts +14 -0
  54. package/dist/chart/service/zoom.service.d.ts +25 -0
  55. package/dist/esm2020/chart/base/series-base.component.mjs +34 -0
  56. package/dist/esm2020/chart/chart/chart.component.mjs +73 -0
  57. package/dist/esm2020/chart/chart-container/chart-container.component.mjs +151 -0
  58. package/dist/esm2020/chart/chart-container/gridlines/gridlines.component.mjs +41 -0
  59. package/dist/esm2020/chart/chart-container/plotband/plotband.component.mjs +139 -0
  60. package/dist/esm2020/chart/chart-container/plotline/plotline.component.mjs +79 -0
  61. package/dist/esm2020/chart/chart-container/series/bar/bar-series.component.mjs +48 -0
  62. package/dist/esm2020/chart/chart-container/series/line/line-series.component.mjs +148 -0
  63. package/dist/esm2020/chart/chart-container/series-host/series-host.component.mjs +59 -0
  64. package/dist/esm2020/chart/chart-container/tooltip/tooltip.component.mjs +81 -0
  65. package/dist/esm2020/chart/chart-container/x-axis/x-axis.component.mjs +56 -0
  66. package/dist/esm2020/chart/chart-container/y-axis/y-axis.component.mjs +63 -0
  67. package/dist/esm2020/chart/chart.module.mjs +62 -0
  68. package/dist/esm2020/chart/core/axis/axis.mjs +96 -0
  69. package/dist/esm2020/chart/core/axis/builders/axis-size-builder.mjs +24 -0
  70. package/dist/esm2020/chart/core/axis/builders/extremes-builder.mjs +32 -0
  71. package/dist/esm2020/chart/core/axis/builders/public-api.mjs +3 -0
  72. package/dist/esm2020/chart/core/utils/generate-ticks.mjs +11 -0
  73. package/dist/esm2020/chart/core/utils/get-text-width.mjs +6 -0
  74. package/dist/esm2020/chart/core/utils/public-api.mjs +3 -0
  75. package/dist/esm2020/chart/directives/brushable.directive.mjs +28 -0
  76. package/dist/esm2020/chart/directives/zoomable.directive.mjs +37 -0
  77. package/dist/esm2020/chart/legend/legend.component.mjs +30 -0
  78. package/dist/esm2020/chart/model/axis-options.mjs +2 -0
  79. package/dist/esm2020/chart/model/base-point.mjs +2 -0
  80. package/dist/esm2020/chart/model/chart-bounds.mjs +13 -0
  81. package/dist/esm2020/chart/model/enum/axis-orientation.mjs +6 -0
  82. package/dist/esm2020/chart/model/enum/axis-type.mjs +9 -0
  83. package/dist/esm2020/chart/model/enum/brush-type.mjs +7 -0
  84. package/dist/esm2020/chart/model/enum/drag-point-type.mjs +7 -0
  85. package/dist/esm2020/chart/model/enum/series-type.mjs +6 -0
  86. package/dist/esm2020/chart/model/enum/tooltip-tracking.mjs +6 -0
  87. package/dist/esm2020/chart/model/enum/zoom-type.mjs +7 -0
  88. package/dist/esm2020/chart/model/i-broadcast-message.mjs +2 -0
  89. package/dist/esm2020/chart/model/i-builder.mjs +2 -0
  90. package/dist/esm2020/chart/model/i-chart-config.mjs +2 -0
  91. package/dist/esm2020/chart/model/i-chart-event.mjs +2 -0
  92. package/dist/esm2020/chart/model/i-display-tooltip.mjs +2 -0
  93. package/dist/esm2020/chart/model/i-point-move.mjs +2 -0
  94. package/dist/esm2020/chart/model/marker-options.mjs +2 -0
  95. package/dist/esm2020/chart/model/plotband.mjs +16 -0
  96. package/dist/esm2020/chart/model/plotline.mjs +12 -0
  97. package/dist/esm2020/chart/model/series.mjs +2 -0
  98. package/dist/esm2020/chart/model/svg-attributes.mjs +2 -0
  99. package/dist/esm2020/chart/model/tooltip-options.mjs +2 -0
  100. package/dist/esm2020/chart/service/axes.service.mjs +29 -0
  101. package/dist/esm2020/chart/service/broadcast.service.mjs +25 -0
  102. package/dist/esm2020/chart/service/brush.service.mjs +67 -0
  103. package/dist/esm2020/chart/service/chart.service.mjs +76 -0
  104. package/dist/esm2020/chart/service/scale.service.mjs +64 -0
  105. package/dist/esm2020/chart/service/zoom.service.mjs +117 -0
  106. package/dist/esm2020/public-api.mjs +7 -0
  107. package/dist/esm2020/tetacom-svg-charts.mjs +5 -0
  108. package/dist/fesm2015/tetacom-svg-charts.mjs +1589 -0
  109. package/dist/fesm2015/tetacom-svg-charts.mjs.map +1 -0
  110. package/dist/fesm2020/tetacom-svg-charts.mjs +1575 -0
  111. package/dist/fesm2020/tetacom-svg-charts.mjs.map +1 -0
  112. package/dist/package.json +35 -0
  113. package/dist/public-api.d.ts +3 -0
  114. package/dist/tetacom-svg-charts.d.ts +5 -0
  115. package/karma.conf.js +44 -0
  116. package/ng-package.json +7 -0
  117. package/package.json +15 -0
  118. package/src/chart/Chart.stories.ts +397 -0
  119. package/src/chart/base/series-base.component.ts +41 -0
  120. package/src/chart/chart/chart.component.html +5 -0
  121. package/src/chart/chart/chart.component.scss +6 -0
  122. package/src/chart/chart/chart.component.spec.ts +25 -0
  123. package/src/chart/chart/chart.component.ts +97 -0
  124. package/src/chart/chart-container/chart-container.component.html +78 -0
  125. package/src/chart/chart-container/chart-container.component.scss +15 -0
  126. package/src/chart/chart-container/chart-container.component.spec.ts +25 -0
  127. package/src/chart/chart-container/chart-container.component.ts +242 -0
  128. package/src/chart/chart-container/gridlines/gridlines.component.html +7 -0
  129. package/src/chart/chart-container/gridlines/gridlines.component.scss +8 -0
  130. package/src/chart/chart-container/gridlines/gridlines.component.spec.ts +25 -0
  131. package/src/chart/chart-container/gridlines/gridlines.component.ts +55 -0
  132. package/src/chart/chart-container/plotband/plotband.component.html +58 -0
  133. package/src/chart/chart-container/plotband/plotband.component.scss +13 -0
  134. package/src/chart/chart-container/plotband/plotband.component.spec.ts +25 -0
  135. package/src/chart/chart-container/plotband/plotband.component.ts +206 -0
  136. package/src/chart/chart-container/plotline/plotline.component.html +22 -0
  137. package/src/chart/chart-container/plotline/plotline.component.scss +6 -0
  138. package/src/chart/chart-container/plotline/plotline.component.spec.ts +25 -0
  139. package/src/chart/chart-container/plotline/plotline.component.ts +113 -0
  140. package/src/chart/chart-container/series/bar/bar-series.component.html +3 -0
  141. package/src/chart/chart-container/series/bar/bar-series.component.scss +0 -0
  142. package/src/chart/chart-container/series/bar/bar-series.component.ts +71 -0
  143. package/src/chart/chart-container/series/line/line-series.component.html +38 -0
  144. package/src/chart/chart-container/series/line/line-series.component.scss +9 -0
  145. package/src/chart/chart-container/series/line/line-series.component.spec.ts +25 -0
  146. package/src/chart/chart-container/series/line/line-series.component.ts +245 -0
  147. package/src/chart/chart-container/series-host/series-host.component.ts +80 -0
  148. package/src/chart/chart-container/tooltip/tooltip.component.html +14 -0
  149. package/src/chart/chart-container/tooltip/tooltip.component.scss +7 -0
  150. package/src/chart/chart-container/tooltip/tooltip.component.spec.ts +25 -0
  151. package/src/chart/chart-container/tooltip/tooltip.component.ts +134 -0
  152. package/src/chart/chart-container/x-axis/x-axis.component.html +1 -0
  153. package/src/chart/chart-container/x-axis/x-axis.component.scss +3 -0
  154. package/src/chart/chart-container/x-axis/x-axis.component.spec.ts +25 -0
  155. package/src/chart/chart-container/x-axis/x-axis.component.ts +80 -0
  156. package/src/chart/chart-container/y-axis/y-axis.component.html +4 -0
  157. package/src/chart/chart-container/y-axis/y-axis.component.scss +13 -0
  158. package/src/chart/chart-container/y-axis/y-axis.component.spec.ts +25 -0
  159. package/src/chart/chart-container/y-axis/y-axis.component.ts +90 -0
  160. package/src/chart/chart.module.ts +40 -0
  161. package/src/chart/core/axis/axis.ts +132 -0
  162. package/src/chart/core/axis/builders/axis-size-builder.ts +37 -0
  163. package/src/chart/core/axis/builders/extremes-builder.ts +45 -0
  164. package/src/chart/core/axis/builders/public-api.ts +2 -0
  165. package/src/chart/core/utils/generate-ticks.ts +14 -0
  166. package/src/chart/core/utils/get-text-width.ts +10 -0
  167. package/src/chart/core/utils/public-api.ts +2 -0
  168. package/src/chart/default/default-chart-config.ts +12 -0
  169. package/src/chart/directives/brushable.directive.ts +30 -0
  170. package/src/chart/directives/zoomable.directive.ts +31 -0
  171. package/src/chart/legend/legend.component.html +6 -0
  172. package/src/chart/legend/legend.component.scss +20 -0
  173. package/src/chart/legend/legend.component.spec.ts +25 -0
  174. package/src/chart/legend/legend.component.ts +35 -0
  175. package/src/chart/model/axis-options.ts +18 -0
  176. package/src/chart/model/base-point.ts +10 -0
  177. package/src/chart/model/chart-bounds.ts +18 -0
  178. package/src/chart/model/enum/axis-orientation.ts +4 -0
  179. package/src/chart/model/enum/axis-type.ts +7 -0
  180. package/src/chart/model/enum/brush-type.ts +5 -0
  181. package/src/chart/model/enum/drag-point-type.ts +5 -0
  182. package/src/chart/model/enum/public-api.ts +7 -0
  183. package/src/chart/model/enum/series-type.ts +4 -0
  184. package/src/chart/model/enum/tooltip-tracking.ts +4 -0
  185. package/src/chart/model/enum/zoom-type.ts +5 -0
  186. package/src/chart/model/i-broadcast-message.ts +5 -0
  187. package/src/chart/model/i-builder.ts +3 -0
  188. package/src/chart/model/i-chart-config.ts +33 -0
  189. package/src/chart/model/i-chart-event.ts +4 -0
  190. package/src/chart/model/i-display-tooltip.ts +7 -0
  191. package/src/chart/model/i-drag-event.ts +5 -0
  192. package/src/chart/model/i-point-move.ts +7 -0
  193. package/src/chart/model/marker-options.ts +8 -0
  194. package/src/chart/model/plotband.ts +45 -0
  195. package/src/chart/model/plotline.ts +29 -0
  196. package/src/chart/model/public-api.ts +0 -0
  197. package/src/chart/model/series.ts +18 -0
  198. package/src/chart/model/svg-attributes.ts +14 -0
  199. package/src/chart/model/tooltip-options.ts +37 -0
  200. package/src/chart/service/axes.service.spec.ts +16 -0
  201. package/src/chart/service/axes.service.ts +27 -0
  202. package/src/chart/service/broadcast.service.spec.ts +16 -0
  203. package/src/chart/service/broadcast.service.ts +24 -0
  204. package/src/chart/service/brush.service.spec.ts +16 -0
  205. package/src/chart/service/brush.service.ts +87 -0
  206. package/src/chart/service/chart.service.spec.ts +16 -0
  207. package/src/chart/service/chart.service.ts +100 -0
  208. package/src/chart/service/scale.service.spec.ts +16 -0
  209. package/src/chart/service/scale.service.ts +74 -0
  210. package/src/chart/service/zoom.service.spec.ts +16 -0
  211. package/src/chart/service/zoom.service.ts +153 -0
  212. package/src/public-api.ts +7 -0
  213. package/src/test.ts +27 -0
  214. package/tsconfig.lib.json +15 -0
  215. package/tsconfig.lib.prod.json +10 -0
  216. package/tsconfig.spec.json +17 -0
@@ -0,0 +1,134 @@
1
+ import {
2
+ ChangeDetectorRef,
3
+ Component,
4
+ Input,
5
+ OnDestroy,
6
+ OnInit,
7
+ } from '@angular/core';
8
+ import { filter, map, merge, Observable, takeWhile, tap } from 'rxjs';
9
+ import { ChartService } from '../../service/chart.service';
10
+ import { ZoomService } from '../../service/zoom.service';
11
+ import { IChartEvent } from '../../model/i-chart-event';
12
+ import { IDisplayTooltip } from '../../model/i-display-tooltip';
13
+ import { DomSanitizer } from '@angular/platform-browser';
14
+
15
+ @Component({
16
+ selector: 'teta-tooltip',
17
+ templateUrl: './tooltip.component.html',
18
+ styleUrls: ['./tooltip.component.scss'],
19
+ })
20
+ export class TooltipComponent implements OnInit, OnDestroy {
21
+ @Input() size: DOMRect;
22
+
23
+ position: Observable<{
24
+ left: string;
25
+ top: string;
26
+ bottom: string;
27
+ right: string;
28
+ }>;
29
+
30
+ displayTooltips: Observable<string>;
31
+
32
+ tooltips = [];
33
+
34
+ private alive = true;
35
+
36
+ display: Observable<number>;
37
+
38
+ constructor(
39
+ private svc: ChartService,
40
+ private cdr: ChangeDetectorRef,
41
+ private zoomService: ZoomService,
42
+ private sanitizer: DomSanitizer
43
+ ) {}
44
+
45
+ ngOnInit(): void {
46
+ this.display = merge(this.svc.pointerMove, this.zoomService.zoomed).pipe(
47
+ map(({ event }) => {
48
+ const opacity = event?.type === 'mousemove' ? 1 : 0;
49
+
50
+ return opacity;
51
+ }),
52
+ tap(() => {
53
+ requestAnimationFrame(() => {
54
+ this.cdr.detectChanges();
55
+ });
56
+ })
57
+ );
58
+
59
+ this.position = this.svc.pointerMove.pipe(
60
+ filter(({ event }) => event),
61
+ map((_) => {
62
+ return this.getPoisition(_);
63
+ }),
64
+ tap((_) => this.cdr.detectChanges())
65
+ );
66
+
67
+ const transformHtml = (html) => {
68
+ return this.sanitizer.bypassSecurityTrustHtml(html);
69
+ };
70
+
71
+ const defaultFormatter = (tooltips: IDisplayTooltip[]) => {
72
+ let html = '';
73
+
74
+ tooltips.forEach((_) => {
75
+ const indicatorStyle = `display:block; width: 10px; height: 2px; background-color: ${_?.series?.color}`;
76
+
77
+ html += `<div class="display-flex align-center"><span class="margin-right-1" style="${indicatorStyle}"></span>
78
+ <span class="font-title-3">${_.series.name}
79
+ <span class="font-body-3">x: ${_.point.x?.toFixed(
80
+ 2
81
+ )} y: ${_.point.y?.toFixed(2)}</span></span></div>`;
82
+ });
83
+
84
+ return transformHtml(html);
85
+ };
86
+
87
+ const formatter = this.svc.config?.tooltip?.format;
88
+
89
+ this.displayTooltips = merge(
90
+ this.svc.pointerMove.pipe(tap((_) => (this.tooltips = []))),
91
+ this.svc.tooltips
92
+ ).pipe(
93
+ takeWhile((_) => this.alive),
94
+ filter((_) => !_['event']),
95
+ map((tooltip: any) => {
96
+ if (tooltip) {
97
+ this.tooltips.push(tooltip);
98
+ }
99
+
100
+ const formatted = formatter
101
+ ? formatter(this.tooltips)
102
+ : defaultFormatter(this.tooltips);
103
+
104
+ return formatted;
105
+ })
106
+ );
107
+ }
108
+
109
+ private getPoisition({ event }: any) {
110
+ const centerX = this.size.width / 2;
111
+ const centerY = this.size.height / 2;
112
+
113
+ const padding = { x: 10, y: 10 };
114
+
115
+ const scene = {
116
+ left: event.pageX > centerX ? 'initial' : `${event.pageX + padding.x}px`,
117
+ top: event.pageY > centerY ? 'initial' : `${event.pageY + padding.y}px`,
118
+ bottom:
119
+ event.pageY > centerY
120
+ ? `${window.innerHeight - event.pageY}px`
121
+ : 'initial',
122
+ right:
123
+ event.pageX > centerX
124
+ ? `${window.innerWidth - event.pageX + padding.x}px`
125
+ : 'initial',
126
+ };
127
+
128
+ return scene;
129
+ }
130
+
131
+ ngOnDestroy() {
132
+ this.alive = false;
133
+ }
134
+ }
@@ -0,0 +1 @@
1
+ <svg:g #svg></svg:g>
@@ -0,0 +1,3 @@
1
+ :host .tick {
2
+ stroke: var(--color-text-20);
3
+ }
@@ -0,0 +1,25 @@
1
+ import { ComponentFixture, TestBed } from '@angular/core/testing';
2
+
3
+ import { XAxisComponent } from './x-axis.component';
4
+
5
+ describe('XAxisComponent', () => {
6
+ let component: XAxisComponent;
7
+ let fixture: ComponentFixture<XAxisComponent>;
8
+
9
+ beforeEach(async () => {
10
+ await TestBed.configureTestingModule({
11
+ declarations: [ XAxisComponent ]
12
+ })
13
+ .compileComponents();
14
+ });
15
+
16
+ beforeEach(() => {
17
+ fixture = TestBed.createComponent(XAxisComponent);
18
+ component = fixture.componentInstance;
19
+ fixture.detectChanges();
20
+ });
21
+
22
+ it('should create', () => {
23
+ expect(component).toBeTruthy();
24
+ });
25
+ });
@@ -0,0 +1,80 @@
1
+ import {
2
+ AfterViewInit,
3
+ ChangeDetectionStrategy,
4
+ ChangeDetectorRef,
5
+ Component,
6
+ ElementRef,
7
+ Input,
8
+ OnChanges,
9
+ OnDestroy,
10
+ OnInit,
11
+ SimpleChanges,
12
+ ViewChild,
13
+ } from '@angular/core';
14
+ import { Axis } from '../../core/axis/axis';
15
+ import { ScaleService } from '../../service/scale.service';
16
+ import { ChartService } from '../../service/chart.service';
17
+ import * as d3 from 'd3';
18
+ import { ZoomService } from '../../service/zoom.service';
19
+ import { concat, map, merge, takeWhile, tap } from 'rxjs';
20
+
21
+ @Component({
22
+ selector: '[teta-x-axis]',
23
+ templateUrl: './x-axis.component.html',
24
+ styleUrls: ['./x-axis.component.scss'],
25
+ changeDetection: ChangeDetectionStrategy.OnPush,
26
+ })
27
+ export class XAxisComponent implements OnInit, OnDestroy, AfterViewInit {
28
+ @Input() axis: Axis;
29
+ @Input() size: DOMRect;
30
+ @ViewChild('svg') node: ElementRef;
31
+
32
+ private _alive = true;
33
+
34
+ constructor(
35
+ private scaleService: ScaleService,
36
+ private chartService: ChartService,
37
+ private cdr: ChangeDetectorRef,
38
+ private zoomService: ZoomService
39
+ ) {
40
+ merge(this.zoomService.zoomed, this.chartService.size)
41
+ .pipe(
42
+ takeWhile(() => this._alive),
43
+ tap((_) => {
44
+ this.draw();
45
+ this.cdr.detectChanges();
46
+ })
47
+ )
48
+ .subscribe();
49
+ }
50
+
51
+ ngOnInit(): void {}
52
+
53
+ ngOnDestroy(): void {
54
+ this._alive = false;
55
+ }
56
+
57
+ ngAfterViewInit() {
58
+ this.draw();
59
+ }
60
+
61
+ private draw() {
62
+ const scale = this.scaleService.xScales.get(this.axis.index);
63
+
64
+ const axis = this.axis.options.opposite
65
+ ? d3
66
+ .axisTop(scale)
67
+ .tickFormat(
68
+ this.axis.options.tickFormat ?? this.axis.defaultFormatter()
69
+ )
70
+ : d3
71
+ .axisBottom(scale)
72
+ .tickFormat(
73
+ this.axis.options.tickFormat ?? this.axis.defaultFormatter()
74
+ );
75
+
76
+ d3.select(this.node.nativeElement)
77
+ .call(axis)
78
+ .call((_) => _.select('.domain').remove());
79
+ }
80
+ }
@@ -0,0 +1,4 @@
1
+ <svg:g #svg></svg:g>
2
+ <svg:g class="label-axis font-caption" [attr.transform]="getLabelTransform()">
3
+ <text dy="-8px" text-anchor="middle" dominant-baseline="middle">{{ axis.options.title }}</text>
4
+ </svg:g>
@@ -0,0 +1,13 @@
1
+ :host {
2
+ shape-rendering: crispEdges;
3
+ }
4
+
5
+ ::ng-deep .tick text {
6
+ fill: var(--color-text-70);
7
+ }
8
+ ::ng-deep .tick line {
9
+ stroke: var(--color-text-20);
10
+ }
11
+ :host .label-axis {
12
+ fill: var(--color-text-70);
13
+ }
@@ -0,0 +1,25 @@
1
+ import { ComponentFixture, TestBed } from '@angular/core/testing';
2
+
3
+ import { YAxisComponent } from './y-axis.component';
4
+
5
+ describe('YAxisComponent', () => {
6
+ let component: YAxisComponent;
7
+ let fixture: ComponentFixture<YAxisComponent>;
8
+
9
+ beforeEach(async () => {
10
+ await TestBed.configureTestingModule({
11
+ declarations: [ YAxisComponent ]
12
+ })
13
+ .compileComponents();
14
+ });
15
+
16
+ beforeEach(() => {
17
+ fixture = TestBed.createComponent(YAxisComponent);
18
+ component = fixture.componentInstance;
19
+ fixture.detectChanges();
20
+ });
21
+
22
+ it('should create', () => {
23
+ expect(component).toBeTruthy();
24
+ });
25
+ });
@@ -0,0 +1,90 @@
1
+ import {
2
+ AfterViewInit,
3
+ ChangeDetectionStrategy,
4
+ ChangeDetectorRef,
5
+ Component,
6
+ ElementRef,
7
+ Input,
8
+ OnDestroy,
9
+ OnInit,
10
+ ViewChild,
11
+ } from '@angular/core';
12
+ import { Axis } from '../../core/axis/axis';
13
+ import * as d3 from 'd3';
14
+ import { ScaleService } from '../../service/scale.service';
15
+ import { ChartService } from '../../service/chart.service';
16
+ import { ZoomService } from '../../service/zoom.service';
17
+ import { merge, takeWhile, tap } from 'rxjs';
18
+
19
+ @Component({
20
+ selector: '[teta-y-axis]',
21
+ templateUrl: './y-axis.component.html',
22
+ styleUrls: ['./y-axis.component.scss'],
23
+ changeDetection: ChangeDetectionStrategy.OnPush,
24
+ })
25
+ export class YAxisComponent implements OnInit, OnDestroy, AfterViewInit {
26
+ @Input() axis: Axis;
27
+ @Input() size: DOMRect;
28
+ @ViewChild('svg') node: ElementRef;
29
+
30
+ private _alive = true;
31
+
32
+ constructor(
33
+ private scaleService: ScaleService,
34
+ private chartService: ChartService,
35
+ private cdr: ChangeDetectorRef,
36
+ private zoomService: ZoomService
37
+ ) {
38
+ merge(this.zoomService.zoomed, this.chartService.size)
39
+ .pipe(
40
+ takeWhile(() => this._alive),
41
+ tap((_) => {
42
+ this.draw();
43
+ this.cdr.markForCheck();
44
+ })
45
+ )
46
+ .subscribe();
47
+ }
48
+
49
+ ngOnInit(): void {}
50
+
51
+ ngOnDestroy(): void {
52
+ this._alive = false;
53
+ }
54
+
55
+ ngAfterViewInit() {
56
+ this.draw();
57
+ }
58
+
59
+ getLabelTransform() {
60
+ return `translate(${
61
+ this.axis.options.opposite
62
+ ? this.axis.selfSize - 24
63
+ : -this.axis.selfSize + 24
64
+ }, ${this.size.height / 2}) rotate(${
65
+ this.axis.options.opposite ? '90' : '-90'
66
+ })`;
67
+ }
68
+
69
+ private draw() {
70
+ const scale = this.scaleService.yScales.get(this.axis.index);
71
+
72
+ const axis = this.axis.options.opposite
73
+ ? d3
74
+ .axisRight(scale)
75
+ // .tickValues(this.axis.tickValues)
76
+ .tickFormat(
77
+ this.axis.options.tickFormat ?? this.axis.defaultFormatter()
78
+ )
79
+ : d3
80
+ .axisLeft(scale)
81
+ // .tickValues(this.axis.tickValues)
82
+ .tickFormat(
83
+ this.axis.options.tickFormat ?? this.axis.defaultFormatter()
84
+ );
85
+
86
+ d3.select(this.node.nativeElement)
87
+ .call(axis)
88
+ .call((_) => _.select('.domain').remove());
89
+ }
90
+ }
@@ -0,0 +1,40 @@
1
+ import { NgModule } from '@angular/core';
2
+ import { CommonModule } from '@angular/common';
3
+ import { ChartComponent } from './chart/chart.component';
4
+ import { SeriesHostComponent } from './chart-container/series-host/series-host.component';
5
+ import { ChartContainerComponent } from './chart-container/chart-container.component';
6
+ import { LegendComponent } from './legend/legend.component';
7
+ import { SeriesBaseComponent } from './base/series-base.component';
8
+ import { LineSeriesComponent } from './chart-container/series/line/line-series.component';
9
+ import { GridlinesComponent } from './chart-container/gridlines/gridlines.component';
10
+ import { XAxisComponent } from './chart-container/x-axis/x-axis.component';
11
+ import { YAxisComponent } from './chart-container/y-axis/y-axis.component';
12
+ import { PlotlineComponent } from './chart-container/plotline/plotline.component';
13
+ import { PlotbandComponent } from './chart-container/plotband/plotband.component';
14
+ import { BarSeriesComponent } from './chart-container/series/bar/bar-series.component';
15
+ import { TooltipComponent } from './chart-container/tooltip/tooltip.component';
16
+ import { ZoomableDirective } from './directives/zoomable.directive';
17
+ import { BrushableDirective } from './directives/brushable.directive';
18
+
19
+ @NgModule({
20
+ declarations: [
21
+ ChartComponent,
22
+ SeriesHostComponent,
23
+ ChartContainerComponent,
24
+ LegendComponent,
25
+ SeriesBaseComponent,
26
+ LineSeriesComponent,
27
+ GridlinesComponent,
28
+ XAxisComponent,
29
+ YAxisComponent,
30
+ PlotlineComponent,
31
+ PlotbandComponent,
32
+ BarSeriesComponent,
33
+ TooltipComponent,
34
+ ZoomableDirective,
35
+ BrushableDirective,
36
+ ],
37
+ exports: [ChartComponent],
38
+ imports: [CommonModule],
39
+ })
40
+ export class ChartModule {}
@@ -0,0 +1,132 @@
1
+ import { IChartConfig } from '../../model/i-chart-config';
2
+ import { AxisOrientation } from '../../model/enum/axis-orientation';
3
+ import { Series } from '../../model/series';
4
+ import { BasePoint } from '../../model/base-point';
5
+ import * as d3 from 'd3';
6
+ import { AxisOptions } from '../../model/axis-options';
7
+ import { AxisSizeBuilder, ExtremesBuilder } from './builders/public-api';
8
+ import { AxisType } from '../../model/enum/axis-type';
9
+
10
+ import { generateTicks } from '../utils/public-api';
11
+
12
+ export class Axis {
13
+ private chartConfig: IChartConfig;
14
+ private _orientation: AxisOrientation;
15
+ private _index: number | string;
16
+ private _extremes: [number, number] = [0, 0];
17
+ private _selfSize: number;
18
+ private _ticksValues: number[];
19
+
20
+ private defaultFormatters = new Map<AxisType, any>()
21
+ .set(AxisType.number, d3.format(',.2f'))
22
+ .set(AxisType.time, d3.timeFormat('%B %d, %Y'))
23
+ .set(AxisType.log, d3.format(',.2f'));
24
+
25
+ constructor(config: IChartConfig) {
26
+ this.chartConfig = config;
27
+ }
28
+
29
+ /**
30
+ * Factory for creating x,y axes
31
+ * @param {AxisOrientation} orientation
32
+ * Axis type
33
+ * @param {IChartConfig} config
34
+ * Chart config
35
+ * @param {number} index
36
+ * Index axis
37
+ * @return {Axis}
38
+ * New generated axis
39
+ */
40
+ public static createAxis(
41
+ orientation: AxisOrientation,
42
+ config: IChartConfig,
43
+ index: number
44
+ ): Axis {
45
+ const axis = new Axis(config);
46
+ axis.setLocate(orientation);
47
+ axis.setIndex(index);
48
+ axis.setExtremes();
49
+ axis.setTicksValues();
50
+ axis.setSelfSize();
51
+
52
+ return axis;
53
+ }
54
+
55
+ /**
56
+ *
57
+ * @param {orientation} orientation
58
+ * Set locate axis x or y
59
+ */
60
+ private setLocate(orientation: AxisOrientation): void {
61
+ this._orientation = orientation;
62
+ }
63
+
64
+ /**
65
+ *
66
+ * @param {number | string} index
67
+ * Index axis
68
+ */
69
+ private setIndex(index: number | string): void {
70
+ this._index = index;
71
+ }
72
+
73
+ /**
74
+ * @return {Array<Series<BasePoint>>}
75
+ * Linked series
76
+ */
77
+ public linkedSeries(): Array<Series<BasePoint>> {
78
+ const linkedFilter = (serie: Series<BasePoint>) =>
79
+ serie[
80
+ this._orientation === AxisOrientation.y ? 'yAxisIndex' : 'xAxisIndex'
81
+ ] === this._index;
82
+
83
+ return this.chartConfig?.series.filter(linkedFilter);
84
+ }
85
+
86
+ private setExtremes(): void {
87
+ const builder = new ExtremesBuilder();
88
+ this._extremes = builder.build(this);
89
+
90
+ this._extremes = d3.nice(this._extremes[0], this._extremes[1], 10);
91
+ }
92
+
93
+ private setSelfSize(): void {
94
+ const builder = new AxisSizeBuilder();
95
+ this._selfSize = builder.build(this);
96
+ }
97
+
98
+ private setTicksValues(): void {
99
+ const ticks = generateTicks(this._extremes);
100
+ this._ticksValues = ticks;
101
+ }
102
+
103
+ get extremes(): Array<number> {
104
+ return this._extremes;
105
+ }
106
+
107
+ get orientation(): AxisOrientation {
108
+ return this._orientation;
109
+ }
110
+
111
+ get selfSize(): number {
112
+ return this._selfSize;
113
+ }
114
+
115
+ get tickValues(): number[] {
116
+ return this._ticksValues;
117
+ }
118
+
119
+ get index() {
120
+ return this._index;
121
+ }
122
+
123
+ get options(): AxisOptions {
124
+ return this.orientation === AxisOrientation.x
125
+ ? this.chartConfig.xAxis[this.index]
126
+ : this.chartConfig.yAxis[this.index];
127
+ }
128
+
129
+ public defaultFormatter() {
130
+ return this.defaultFormatters.get(this.options.type);
131
+ }
132
+ }
@@ -0,0 +1,37 @@
1
+ import { Axis } from '../axis';
2
+ import { AxisOrientation } from '../../../model/enum/axis-orientation';
3
+ import { maxIndex } from 'd3-array';
4
+ import { getTextWidth } from '../../utils/public-api';
5
+ import { IBuilder } from '../../../model/i-builder';
6
+
7
+ export class AxisSizeBuilder implements IBuilder<Axis, number> {
8
+ private titlePadding = 8;
9
+ private basePadding = 16;
10
+ private backupRatio = 0.58;
11
+
12
+ build(settings: Axis): number {
13
+ let finalPadding = this.basePadding;
14
+
15
+ if (settings.orientation === AxisOrientation.y) {
16
+ const formatter = settings.defaultFormatter();
17
+
18
+ finalPadding += settings.options.title ? this.titlePadding : 0;
19
+
20
+ const maxElementLengthIndex = maxIndex(
21
+ settings.tickValues,
22
+ (_) => formatter(_).length
23
+ );
24
+
25
+ finalPadding += getTextWidth(
26
+ formatter(settings.tickValues[maxElementLengthIndex]),
27
+ this.backupRatio
28
+ );
29
+ }
30
+
31
+ if (settings.orientation === AxisOrientation.x) {
32
+ finalPadding += finalPadding + 20;
33
+ }
34
+
35
+ return finalPadding;
36
+ }
37
+ }
@@ -0,0 +1,45 @@
1
+ import { IBuilder } from '../../../model/i-builder';
2
+ import { Axis } from '../axis';
3
+ import { BasePoint } from '../../../model/base-point';
4
+ import { AxisOrientation } from '../../../model/enum/axis-orientation';
5
+
6
+ import * as d3 from 'd3';
7
+
8
+ export class ExtremesBuilder implements IBuilder<Axis, [number, number]> {
9
+ private extentAccessorMap = new Map<
10
+ AxisOrientation,
11
+ (point: BasePoint) => number
12
+ >()
13
+ .set(AxisOrientation.x, (_) => _.x)
14
+ .set(AxisOrientation.y, (_) => _.y);
15
+
16
+ private extremes: [number, number] = [0, 0];
17
+
18
+ build(settings: Axis): [number, number] {
19
+ const options = settings.options;
20
+
21
+ const hasMin = options?.min != null;
22
+ const hasMax = options?.max != null;
23
+
24
+ if (!hasMin || !hasMax) {
25
+ const linkedSeries = settings.linkedSeries();
26
+ const data = linkedSeries.reduce((acc: BasePoint[], current) => {
27
+ return acc.concat(current.data);
28
+ }, []);
29
+
30
+ const accessor = this.extentAccessorMap.get(settings.orientation);
31
+ // add negative axis!
32
+
33
+ this.extremes = d3.extent(data, accessor);
34
+ }
35
+
36
+ if (hasMin) {
37
+ this.extremes[0] = options?.min;
38
+ }
39
+
40
+ if (hasMax) {
41
+ this.extremes[1] = options?.max;
42
+ }
43
+ return this.extremes;
44
+ }
45
+ }
@@ -0,0 +1,2 @@
1
+ export * from './axis-size-builder';
2
+ export * from './extremes-builder';
@@ -0,0 +1,14 @@
1
+ import * as d3 from 'd3';
2
+
3
+ export function generateTicks(extremes: number[]) {
4
+ const [min, max] = extremes;
5
+
6
+ const tickCount = 10;
7
+ const tickStep = (max - min) / tickCount;
8
+
9
+ const ticks = d3
10
+ .range(min, max + tickStep, tickStep)
11
+ .filter((step) => step <= max);
12
+
13
+ return ticks;
14
+ }
@@ -0,0 +1,10 @@
1
+ export const getTextWidth = (
2
+ inputText?: string | number | null,
3
+ backupRatio = 0.5,
4
+ fontSize = 11
5
+ ): number => {
6
+ let text = inputText ?? '';
7
+ text = text.toString();
8
+
9
+ return fontSize * backupRatio * text.length;
10
+ };
@@ -0,0 +1,2 @@
1
+ export * from './get-text-width';
2
+ export * from './generate-ticks';
@@ -0,0 +1,12 @@
1
+ import {IChartConfig} from '../model/i-chart-config';
2
+
3
+ export const defaultChartConfig: IChartConfig = {
4
+ series: [],
5
+ xAxis: [{
6
+ visible: true
7
+ }],
8
+ yAxis: [{
9
+ visible: true
10
+ }],
11
+ gridLines: true
12
+ };