ngx-deebodata 0.0.1 → 0.0.2

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 (78) hide show
  1. package/LICENSE +1 -1
  2. package/README.md +2 -1
  3. package/ng-package.json +7 -0
  4. package/package.json +16 -33
  5. package/src/lib/data-table/charts/bar-graph-component/bar-graph-component.css +156 -0
  6. package/src/lib/data-table/charts/bar-graph-component/bar-graph-component.html +29 -0
  7. package/src/lib/data-table/charts/bar-graph-component/bar-graph-component.spec.ts +23 -0
  8. package/src/lib/data-table/charts/bar-graph-component/bar-graph-component.ts +286 -0
  9. package/src/lib/data-table/charts/charts-and-graphs/charts-and-graphs.css +27 -0
  10. package/src/lib/data-table/charts/charts-and-graphs/charts-and-graphs.html +53 -0
  11. package/src/lib/data-table/charts/charts-and-graphs/charts-and-graphs.spec.ts +23 -0
  12. package/src/lib/data-table/charts/charts-and-graphs/charts-and-graphs.ts +214 -0
  13. package/src/lib/data-table/charts/column-chart/column-chart.css +19 -0
  14. package/src/lib/data-table/charts/column-chart/column-chart.html +47 -0
  15. package/src/lib/data-table/charts/column-chart/column-chart.spec.ts +23 -0
  16. package/src/lib/data-table/charts/column-chart/column-chart.ts +178 -0
  17. package/src/lib/data-table/charts/line-graph-component/line-graph-component.css +33 -0
  18. package/src/lib/data-table/charts/line-graph-component/line-graph-component.html +59 -0
  19. package/src/lib/data-table/charts/line-graph-component/line-graph-component.spec.ts +23 -0
  20. package/src/lib/data-table/charts/line-graph-component/line-graph-component.ts +661 -0
  21. package/src/lib/data-table/charts/num-value-distro-component/num-value-distro-component.css +61 -0
  22. package/src/lib/data-table/charts/num-value-distro-component/num-value-distro-component.html +27 -0
  23. package/src/lib/data-table/charts/num-value-distro-component/num-value-distro-component.spec.ts +23 -0
  24. package/src/lib/data-table/charts/num-value-distro-component/num-value-distro-component.ts +210 -0
  25. package/src/lib/data-table/charts/pie-graph-component/pie-graph-component.css +0 -0
  26. package/src/lib/data-table/charts/pie-graph-component/pie-graph-component.html +15 -0
  27. package/src/lib/data-table/charts/pie-graph-component/pie-graph-component.spec.ts +23 -0
  28. package/src/lib/data-table/charts/pie-graph-component/pie-graph-component.ts +197 -0
  29. package/src/lib/data-table/data-table-module/data-cell/data-cell.css +0 -0
  30. package/src/lib/data-table/data-table-module/data-cell/data-cell.html +6 -0
  31. package/src/lib/data-table/data-table-module/data-cell/data-cell.spec.ts +23 -0
  32. package/src/lib/data-table/data-table-module/data-cell/data-cell.ts +271 -0
  33. package/src/lib/data-table/data-table-module/data-table-header/data-table-header.css +25 -0
  34. package/src/lib/data-table/data-table-module/data-table-header/data-table-header.html +55 -0
  35. package/src/lib/data-table/data-table-module/data-table-header/data-table-header.spec.ts +23 -0
  36. package/src/lib/data-table/data-table-module/data-table-header/data-table-header.ts +261 -0
  37. package/src/lib/data-table/data-table-module/data-table-paginator/data-table-paginator.css +69 -0
  38. package/src/lib/data-table/data-table-module/data-table-paginator/data-table-paginator.html +24 -0
  39. package/src/lib/data-table/data-table-module/data-table-paginator/data-table-paginator.spec.ts +23 -0
  40. package/src/lib/data-table/data-table-module/data-table-paginator/data-table-paginator.ts +125 -0
  41. package/src/lib/data-table/data-table-module/export-component/export-component.css +91 -0
  42. package/src/lib/data-table/data-table-module/export-component/export-component.html +16 -0
  43. package/src/lib/data-table/data-table-module/export-component/export-component.spec.ts +23 -0
  44. package/src/lib/data-table/data-table-module/export-component/export-component.ts +206 -0
  45. package/src/lib/data-table/data-table-module/ngx-deebodata/ngx-deebodata.css +91 -0
  46. package/src/lib/data-table/data-table-module/ngx-deebodata/ngx-deebodata.html +193 -0
  47. package/src/lib/data-table/data-table-module/ngx-deebodata/ngx-deebodata.spec.ts +23 -0
  48. package/src/lib/data-table/data-table-module/ngx-deebodata/ngx-deebodata.ts +2226 -0
  49. package/src/lib/data-table/data-table-module/row-group-menu/row-group-menu.css +14 -0
  50. package/src/lib/data-table/data-table-module/row-group-menu/row-group-menu.html +27 -0
  51. package/src/lib/data-table/data-table-module/row-group-menu/row-group-menu.spec.ts +23 -0
  52. package/src/lib/data-table/data-table-module/row-group-menu/row-group-menu.ts +58 -0
  53. package/src/lib/data-table/data-table-module/row-group-panel/row-group-panel.css +23 -0
  54. package/src/lib/data-table/data-table-module/row-group-panel/row-group-panel.html +48 -0
  55. package/src/lib/data-table/data-table-module/row-group-panel/row-group-panel.spec.ts +23 -0
  56. package/src/lib/data-table/data-table-module/row-group-panel/row-group-panel.ts +599 -0
  57. package/src/lib/data-table/data-table-module/worker.worker.ts +44 -0
  58. package/src/lib/interfaces/cell-edit.ts +5 -0
  59. package/src/lib/interfaces/column-header.ts +10 -0
  60. package/src/lib/interfaces/column-styles.ts +14 -0
  61. package/src/lib/interfaces/column-symbol.ts +4 -0
  62. package/src/lib/interfaces/data-cell.ts +14 -0
  63. package/src/lib/interfaces/data-row.ts +11 -0
  64. package/src/lib/interfaces/row-number.ts +4 -0
  65. package/src/lib/services/common-service.spec.ts +16 -0
  66. package/src/lib/services/common-service.ts +336 -0
  67. package/src/lib/services/data-table-service.spec.ts +16 -0
  68. package/src/lib/services/data-table-service.ts +597 -0
  69. package/src/lib/services/table-drag-service.spec.ts +16 -0
  70. package/src/lib/services/table-drag-service.ts +347 -0
  71. package/src/lib/styles.css +1065 -0
  72. package/src/public-api.ts +8 -0
  73. package/tsconfig.lib.json +17 -0
  74. package/tsconfig.lib.prod.json +11 -0
  75. package/tsconfig.spec.json +15 -0
  76. package/fesm2022/ngx-deebodata.mjs +0 -6863
  77. package/fesm2022/ngx-deebodata.mjs.map +0 -1
  78. package/types/ngx-deebodata.d.ts +0 -439
@@ -0,0 +1,214 @@
1
+ import { Component, ElementRef, EventEmitter, Input, Output, signal, ViewChild } from '@angular/core';
2
+ import { CommonService } from '../../../services/common-service';
3
+ import { DataTableService } from '../../../services/data-table-service';
4
+ import { ColumnChart } from '../column-chart/column-chart';
5
+ import { LineGraphComponent } from '../line-graph-component/line-graph-component';
6
+ import { CommonModule } from '@angular/common';
7
+
8
+ @Component({
9
+ selector: 'app-charts-and-graphs',
10
+ imports: [ CommonModule, ColumnChart, LineGraphComponent, ],
11
+ templateUrl: './charts-and-graphs.html',
12
+ styleUrls: ['./charts-and-graphs.css', '../../../styles.css']
13
+ })
14
+ export class ChartsAndGraphs {
15
+
16
+ chartsReady = signal<boolean>(false);
17
+ rowIsAboveFold = signal<number[]>([0]);
18
+ useData: any[] = []
19
+ iRows: any[][] = []
20
+ dtCols: string[] = [];
21
+ numCols: string[] = [];
22
+ filterInfo: string = ""
23
+ currNumColData: any = {}//[] = []
24
+ currNumColNm: any = {}//string = ""
25
+ okBarGraphs: string[] = []
26
+ okLineGraphs: string[] = []
27
+ hasNoData: string[] = []
28
+ @Input() height: string = "";
29
+ @Input() state: string = "all";
30
+ @Input() chartColumns: string[] = [];
31
+ @Output("close") close: EventEmitter<boolean> = new EventEmitter();
32
+ @ViewChild("xChartsBtn", { static: true }) xChartsBtn!: ElementRef<HTMLButtonElement>;
33
+ @ViewChild("chartsTitle", { static: true }) chartsTitle!: ElementRef<HTMLHeadElement>;
34
+ @ViewChild("chartContain", { static: true }) chartContain!: ElementRef<HTMLElement>;
35
+ h2Text: string = ""
36
+
37
+ constructor(public common: CommonService,
38
+ public dataTableService: DataTableService,){ }
39
+
40
+ ngOnInit() {
41
+ if(this.state === "selected")
42
+ this.useData = this.dataTableService.mainData.filter( (d, ind) => this.dataTableService.currSelRows.indexOf(ind) > -1 )
43
+ else
44
+ this.useData = this.dataTableService.currFilData//.filter( d => true )
45
+ this.gatherRelationalPairs()
46
+ const dLen = this.useData.length
47
+ let filinfo = this.dataTableService.getAllFilSrtInfo()?.replace(/Filtered By:/g, "filtered by").
48
+ replace(/ \&bull; Sorted By/g, ", Sorted By").replace(/ \&bull; /g, " ")
49
+ this.h2Text = "Data Insights for <b>"+ dLen.toLocaleString(undefined, {maximumFractionDigits: 0}) + "</b>" +
50
+ (this.state !== 'all' ? (' ' + this.common.titleCase(this.state)) : '') +" Rows ";
51
+ if(filinfo){
52
+ this.h2Text = ("Data Insights " + ("for <b>" + (dLen).toLocaleString(undefined, {maximumFractionDigits:0}) +
53
+ "</b> row" + (dLen === 1 ? " " : "s ")) + filinfo?.split(", Sorted By")[0].trim())
54
+ }
55
+ }
56
+
57
+ ngAfterViewInit() {
58
+ setTimeout( () => {
59
+ let r = 0; let c = 0; let u = 0; let o = 0
60
+ let useChartCols: string[] = [];
61
+ const usableCharts = this.chartColumns.filter( c => !this.hasNoData.includes(c))
62
+ const uclen = usableCharts.length
63
+ const nlen = this.numCols.length
64
+ for(u; u < uclen; u++){
65
+ const ucol = usableCharts[u]
66
+ useChartCols.push(ucol)
67
+ if(this.okBarGraphs.indexOf(ucol) > -1){
68
+ for(o; o < nlen; o++)
69
+ useChartCols.push(ucol + this.dataTableService.bgSep + this.numCols[o])
70
+ o = 0;
71
+ }
72
+ if(this.okLineGraphs.indexOf(ucol) > -1){
73
+ o = 0; let d = 0;
74
+ const dtlen = this.dtCols.length
75
+ for(o; o < nlen; o++){
76
+ for(d; d < dtlen; d++)
77
+ useChartCols.push(ucol + this.dataTableService.bgSep + this.numCols[o] + this.dataTableService.bgSep + this.dtCols[d])
78
+ d = 0;
79
+ }
80
+ o = 0;
81
+ }
82
+ }
83
+ const clen = useChartCols.length
84
+ const cWid = this.chartContain.nativeElement.getBoundingClientRect().width
85
+ const insightColsPerRow = cWid < 640 ? 1 : (cWid < 960 ? 2 : 3);
86
+ const rlen = Math.ceil(clen/insightColsPerRow)
87
+ for(r; r < rlen; r++){
88
+ let i = 0
89
+ this.iRows[r] = []
90
+ for(i; i < insightColsPerRow; i++){
91
+ const col = useChartCols[c]
92
+ if(col){
93
+ let title = this.common.titleCase(col)
94
+ let mappedData: any[] = []
95
+ const reg = new RegExp(this.dataTableService.bgSep, "g")
96
+ if(reg.test(col)){
97
+ const bgCols = col.split(this.dataTableService.bgSep)
98
+ const strCol = bgCols[0]
99
+ const numCol = bgCols[1]
100
+ let dtCol
101
+ if(bgCols.length === 3)//line graph
102
+ dtCol = bgCols[2]
103
+ if(!dtCol){//bar graph
104
+ const valsLen = this.dataTableService.dataFilSrtTracker[strCol]?.selDDVals?.filter( (g: any) => g.value !== "(Select All)").length || 0;
105
+ const doAvg = this.useData.length <= valsLen ? "" : "Avg ";
106
+ title = doAvg + this.common.titleCase(numCol) + " by " + this.common.titleCase(strCol);
107
+ mappedData = this.useData.filter( d => d[numCol] === 0 || !!d[numCol]).map( d => ({strColumn: (d[strCol] || "N/A"), numColumn: d[numCol]}))
108
+ } else {//line graph
109
+ title = "Avg " + this.common.titleCase(numCol) + " by " + this.common.titleCase(dtCol);
110
+ mappedData = this.useData.filter( d => d[numCol] === 0 || !!d[numCol]).map( d => ({strColumn: (d[strCol] || "N/A"), numColumn: d[numCol], dtColumn: d[dtCol]}))
111
+ }
112
+ } else {
113
+ if(this.dtCols.indexOf(col) > -1){
114
+ const n0 = this.numCols[0]
115
+ title = "Avg " + this.common.titleCase(n0) + " by " + this.common.titleCase(col);
116
+ mappedData = this.useData.filter( d => d[n0] === 0 || !!d[n0]).map( d => ({numColumn: d[n0], dtColumn: d[col]}))
117
+ } else {
118
+ mappedData = this.useData.map( d => d[col] )
119
+ }
120
+ }
121
+ this.iRows[r].push({ column: col, data: mappedData, title: title })
122
+ c += 1
123
+ }
124
+ }
125
+ }
126
+ setTimeout( () => { this.chartsReady.set(true) })
127
+ })
128
+ }
129
+
130
+ handleChartScroll(event: any) {
131
+ let abv: number[] = []
132
+ const xBtn= this.xChartsBtn.nativeElement
133
+ const top = event.target.scrollTop
134
+ const rows = document.getElementsByClassName("insight-field-row")
135
+ const rlen = rows.length
136
+ if(xBtn)
137
+ xBtn.style.top = (7 + top) + "px"
138
+ for(var i = (rlen-1); i >= 0; i--){
139
+ const row: HTMLElement = <HTMLElement>rows[i]
140
+ if(this.dataTableService.elIsAboveFold(row, this.dataTableService.tblBot) && !abv.includes(i) && !this.rowIsAboveFold().includes(i))
141
+ abv.push(i)
142
+ }
143
+ this.rowIsAboveFold.set([...this.rowIsAboveFold(), ...abv])
144
+ }
145
+
146
+
147
+
148
+ gatherRelationalPairs() {//dot plots and bar graphs
149
+ let i = 0;
150
+ const len = this.chartColumns.length
151
+ for(i; i < len; i++){
152
+ const col = this.chartColumns[i]
153
+ const colData = this.useData.map( (d) => d[col] )
154
+ if(colData.every( (d: any) => !d )){
155
+ this.hasNoData.push(col)
156
+ continue;
157
+ }
158
+ const yearCol = /(year|yr|fy)/g.test(col?.toLocaleLowerCase())
159
+ const allNumData = colData.every( (d: any) => !d || (d && typeof d === "number") )
160
+ let bitData;
161
+ if(allNumData)
162
+ bitData = colData.every( (d: any) => !d || d === 1 || d === 0 )
163
+ if(allNumData && !yearCol && !bitData){//num data
164
+ this.numCols.push(col);
165
+ } else {
166
+ const dSet =new Set(colData)
167
+ let arrFrmSet: any = []
168
+ dSet.forEach( (v) => arrFrmSet.push(v) )
169
+ const dateData = (colData.every( (d: any) => !d || this.common.isADateObject(d)) && !colData.every( (d: any) => !d ))
170
+ if(dateData || yearCol)
171
+ this.dtCols.push(col)
172
+ }
173
+ }
174
+
175
+ if(this.numCols.length){
176
+ for(const prop in this.dataTableService.dataFilSrtTracker){
177
+ const trkr = this.dataTableService.dataFilSrtTracker[prop]
178
+ if(trkr && trkr.selDDVals){
179
+ this.okBarGraphs.push(prop)
180
+ if(this.dtCols.length)
181
+ this.okLineGraphs.push(prop)
182
+ }
183
+ }
184
+ }
185
+
186
+ const dtlen = this.dtCols.length
187
+ if(dtlen && this.numCols.length && typeof document.querySelectorAll === "function"){
188
+ let c = 0
189
+ for(c; c < dtlen; c++){
190
+ const dcol = this.dtCols[c]
191
+ this.currNumColNm[dcol] = this.numCols[0]
192
+ this.currNumColData[dcol] = [1]//this.useData.filter( d => !!d).map( (d) => d[this.numCols[0]] )* this was for dot plot, but now we use line graph
193
+ }
194
+ }
195
+ }
196
+
197
+ setLineGraphNumCol(rowI: number, dtCol: string, col: string) {
198
+ this.currNumColData[dtCol] = []
199
+ setTimeout( () => {
200
+ this.currNumColNm[dtCol] = col
201
+ const irow = this.iRows[rowI].find( i => i.column === dtCol)
202
+ if(irow){
203
+ this.iRows[rowI].find( i => i.column === dtCol).data = this.useData.filter( d => d[col] === 0 || !!d[col]).map( d => ({numColumn: d[col], dtColumn: d[dtCol]}))
204
+ this.iRows[rowI].find( i => i.column === dtCol).title = "Avg " + this.common.titleCase(col) + " by " + this.common.titleCase(dtCol);
205
+ }
206
+ this.currNumColData[dtCol] = [1]//this.useData.filter( d => !!d).map( (d) => d[col] )* this was for dot plot, but now we use line graph
207
+ })
208
+ }
209
+
210
+ closeCharts() {
211
+ this.close.emit(false)
212
+ }
213
+
214
+ }
@@ -0,0 +1,19 @@
1
+ div{
2
+ box-sizing: border-box;
3
+ padding:7px 7px 0 2px
4
+ }
5
+
6
+ .half-wid{
7
+ padding: 0 !important;
8
+ margin: 11px 0 7px 0;
9
+ }
10
+
11
+ .half-wid span{
12
+ vertical-align: middle;
13
+ }
14
+
15
+ .vdh-loading{
16
+ text-align: center;
17
+ text-decoration: underline;
18
+ padding: 33px 0px 17px 0px;
19
+ }
@@ -0,0 +1,47 @@
1
+ @if(isNumData){
2
+ <div class="half-wid" [id]="'sum' + common.elifyCol(column)">
3
+ <span class="v-mid">Total: </span><span class="lg-text v-mid{{symCls}}" [attr.data-symbol]="symAttr">{{sum}}</span>
4
+ </div><div class="half-wid" [id]="'avg' + common.elifyCol(column)">
5
+ <span class="v-mid">Avg: </span><span class="lg-text v-mid{{symCls}}" [attr.data-symbol]="symAttr">{{avg}}</span>
6
+ </div><div class="half-wid" [id]="'min' + common.elifyCol(column)">
7
+ <span class="v-mid">Min: </span><span class="lg-text v-mid{{symCls}}" [attr.data-symbol]="symAttr">{{min}}</span>
8
+ </div><div class="half-wid" [id]="'max' + common.elifyCol(column)">
9
+ <span class="v-mid">Max: </span><span class="lg-text v-mid{{symCls}}" [attr.data-symbol]="symAttr">{{max}}</span>
10
+ </div>@if(modeHtml){ <div [innerHTML]="modeHtml"></div>}<div>{{tdivHtml}}</div>
11
+ @if(numValDistMsg){ <div class="vdh-loading">{{numValDistMsg}}</div> }
12
+ @if(numLen < numArrMax){
13
+ <app-num-value-distro-component
14
+ [column]="column"
15
+ [average]="numAvg"
16
+ [originalArr]="colData"
17
+ (done)="numValDistMsg = $event"
18
+ [title]="'Building ' + common.sanitizeUi(common.titleCase(column)) + ' value distribution...'"
19
+ ></app-num-value-distro-component>
20
+ }
21
+ } @else {
22
+ @if(nonNumUVal){ <div>{{nonNumUVal}}</div> }
23
+ @if(nonNumEVal){ <div>{{nonNumEVal}}</div> }
24
+ @if(modeHtml){ <div [innerHTML]="modeHtml"></div> }
25
+ }
26
+
27
+ @if(pieData){
28
+ <app-pie-graph-component
29
+ [uncoverPie]="dataTableService.removePieCovers"
30
+ [data]="pieData"
31
+ [column]="column"
32
+ ></app-pie-graph-component>
33
+ }
34
+ @if(isBarGraph){
35
+ <app-bar-graph-component
36
+ [column]="column"
37
+ [data]="colData"
38
+ (title)="handleBgTitle($event)"
39
+ ></app-bar-graph-component>
40
+ }
41
+ @if(isLineGraph){
42
+ <app-line-graph-component
43
+ [column]="column"
44
+ [data]="colData"
45
+ (title)="handleBgTitle($event)"
46
+ ></app-line-graph-component>
47
+ }
@@ -0,0 +1,23 @@
1
+ import { ComponentFixture, TestBed } from '@angular/core/testing';
2
+
3
+ import { ColumnChart } from './column-chart';
4
+
5
+ describe('ColumnChart', () => {
6
+ let component: ColumnChart;
7
+ let fixture: ComponentFixture<ColumnChart>;
8
+
9
+ beforeEach(async () => {
10
+ await TestBed.configureTestingModule({
11
+ imports: [ColumnChart]
12
+ })
13
+ .compileComponents();
14
+
15
+ fixture = TestBed.createComponent(ColumnChart);
16
+ component = fixture.componentInstance;
17
+ fixture.detectChanges();
18
+ });
19
+
20
+ it('should create', () => {
21
+ expect(component).toBeTruthy();
22
+ });
23
+ });
@@ -0,0 +1,178 @@
1
+ import { Component, EventEmitter, Input, Output } from '@angular/core';
2
+ import { CommonService } from '../../../services/common-service';
3
+ import { DataTableService } from '../../../services/data-table-service';
4
+ import { CommonModule } from '@angular/common';
5
+ import { NumValueDistroComponent } from '../num-value-distro-component/num-value-distro-component';
6
+ import { PieGraphComponent } from '../pie-graph-component/pie-graph-component';
7
+ import { BarGraphComponent } from '../bar-graph-component/bar-graph-component';
8
+ import { LineGraphComponent } from '../line-graph-component/line-graph-component';
9
+
10
+ @Component({
11
+ selector: 'app-column-chart',
12
+ imports: [ CommonModule, NumValueDistroComponent, PieGraphComponent, BarGraphComponent, LineGraphComponent, ],
13
+ templateUrl: './column-chart.html',
14
+ styleUrls: ['./column-chart.css', '../../../styles.css']
15
+ })
16
+ export class ColumnChart {
17
+
18
+ isNumData = false
19
+ isBoolData = false
20
+ isBarGraph = false
21
+ isLineGraph = false
22
+ counts: any = null
23
+ sum: string = ""
24
+ avg: string = ""
25
+ min: string = ""
26
+ max: string = ""
27
+ numArrMax: number = 5000
28
+ numAvg: number = 0
29
+ modeHtml: string = ""
30
+ tdivHtml: string = ""
31
+ numValDistMsg = ""
32
+ numLen: number = 0
33
+ symCls: string = ""
34
+ symAttr: string = ""
35
+ pieData: any = null
36
+ nonNumUVal: string = ""
37
+ nonNumEVal: string = ""
38
+ @Input() column: string = ""
39
+ @Input() colData: any[] = []
40
+ @Output("bgTitle") bgTitle: EventEmitter<string> = new EventEmitter();
41
+
42
+ constructor(public common: CommonService,
43
+ public dataTableService: DataTableService,){ }
44
+
45
+ ngOnInit() {
46
+ const reg = new RegExp(this.dataTableService.bgSep, "g")
47
+ if(reg.test(this.column)){
48
+ if(this.column.split(this.dataTableService.bgSep).length > 2){
49
+ this.isLineGraph = true
50
+ } else {
51
+ this.isBarGraph = true
52
+ }
53
+ } else {
54
+ this.buildDataInsights()
55
+ }
56
+ }
57
+
58
+ setDistMsg(event: string) {
59
+ this.numValDistMsg = event
60
+ }
61
+
62
+ buildDataInsights() {
63
+ const yearCol = /(year|yr|fy)/g.test(this.column?.toLocaleLowerCase())
64
+ const allNumData = this.colData.every( d => !d || (d && typeof d === "number") )
65
+ const boolData = this.colData.every( d => !d || (d && typeof d === "boolean") )
66
+ this.counts = this.getColumnValueCounts(this.colData)//build pie graphs with this
67
+ let mode = this.getColumnMode(this.counts)
68
+ const disr = (this.counts["n_a"] && this.counts["n_a"] >= mode?.amount) ? " (non-empty value)" : "";
69
+ if(mode && mode.amount != 1){
70
+ try{
71
+ let maxChars = 75
72
+ let pMdTxt = this.common.sanitizeUi(mode.text)
73
+ if(mode.text && typeof mode.text === "string"){
74
+ pMdTxt = mode.text.substring(0, maxChars)
75
+ if(pMdTxt.length === maxChars){
76
+ try{
77
+ pMdTxt = (pMdTxt.trim() + "...")
78
+ if(pMdTxt.startsWith("\""))
79
+ pMdTxt += "\""
80
+ if(pMdTxt.startsWith("'"))
81
+ pMdTxt += "'"
82
+ }catch(e){}
83
+ }
84
+ }
85
+ if(pMdTxt && allNumData && !yearCol)
86
+ pMdTxt = parseInt(pMdTxt).toLocaleString(undefined, { maximumFractionDigits: 3 })
87
+ const modeVal = mode.amount.toLocaleString(undefined, { maximumFractionDigits: 0 })
88
+ this.modeHtml = "Most frequent"+disr+": <i>" + pMdTxt + "</i> appears " + modeVal + " time" + (mode.amount === 1 ? "" : "s");
89
+ }catch(e){}
90
+ }
91
+ let bitData;
92
+ if(allNumData)
93
+ bitData = this.colData.every( d => !d || d === 1 || d === 0 )
94
+ if(allNumData && !yearCol && !bitData){//num data
95
+ let isCurr = false
96
+ this.isNumData = true
97
+ const numsOnly = this.colData.filter( d => !!d || (d === 0) )
98
+ this.numLen = numsOnly.length
99
+ let usum = numsOnly.reduce( (acc, curr) => (acc + curr), 0)
100
+ const lastNum = numsOnly[numsOnly.length-1]
101
+ const sym = this.dataTableService.dataFilSrtTracker[this.column]?.colCellSymbol;
102
+ if(sym){
103
+ isCurr = ["$","€","£","¥","₣","₹"].indexOf(sym) > -1
104
+ this.symCls = isCurr ? ' has-symbol-b' : ' has-symbol';
105
+ this.symAttr = sym;
106
+ }
107
+ if(typeof lastNum === "number" && ((usum - lastNum === lastNum) || (Math.abs(usum - lastNum*2) < 0.02))){//check that a total column is already there
108
+ usum -= lastNum
109
+ this.numLen -= 1
110
+ this.tdivHtml = "We omitted the last value from the total because it may be a total row itself.";
111
+ }
112
+ this.numAvg = (usum/this.numLen)
113
+ this.sum = usum.toLocaleString(undefined, { maximumFractionDigits: 2, minimumFractionDigits: (isCurr ? 2 : 0) });
114
+ this.avg = this.numAvg.toLocaleString(undefined, { maximumFractionDigits: 2, minimumFractionDigits: (isCurr ? 2 : 0) });
115
+ this.min = Math.min(...numsOnly).toLocaleString(undefined, { maximumFractionDigits: 2, minimumFractionDigits: (isCurr ? 2 : 0) });
116
+ this.max = Math.max(...(this.tdivHtml ? numsOnly.filter( (n, ind) => ind < (numsOnly.length-1) ) : numsOnly)).
117
+ toLocaleString(undefined, { maximumFractionDigits: 2, minimumFractionDigits: (isCurr ? 2 : 0) });
118
+ if(this.numLen && this.numLen < this.numArrMax)
119
+ this.numValDistMsg = "Building " + this.common.sanitizeUi(this.common.titleCase(this.column)) + " value distribution..."
120
+ } else {
121
+ const dSet =new Set(this.colData)
122
+ let arrFrmSet: any[] = []
123
+ dSet.forEach( (v) => { arrFrmSet.push(v) })
124
+ this.nonNumUVal = arrFrmSet.length.toLocaleString(undefined, { maximumFractionDigits: 0 }) + " unique value" + (dSet.size === 1 ? "" : "s")
125
+ const empVals = this.colData.filter( (d) => !d).length
126
+ this.nonNumEVal = empVals.toLocaleString(undefined, { maximumFractionDigits: 0 }) + " empty value" + (empVals === 1 ? "" : "s");
127
+ const cantDoDD = arrFrmSet.some( a => a && a.length > 40 )
128
+ if(!cantDoDD && ((boolData || bitData) || (arrFrmSet.filter( (a) => !!a ).length > 0 && this.colData.every( (d) => !d || typeof d === "string")))){
129
+ if(arrFrmSet.length <= 18)
130
+ this.pieData = { counts: this.counts, type: ((boolData || bitData) ? "boolean" : "string") }
131
+ }
132
+ }
133
+ }
134
+
135
+ getColumnValueCounts(data: any[]) {
136
+ let i = 0
137
+ let count: any = {}
138
+ const na = "n_a"
139
+ const len = data.length
140
+ for(i; i < len; i++){
141
+ const d = data[i]
142
+ const val = (d && typeof d) === "string" ? d :
143
+ (this.common.isADateObject(d) ? d.toLocaleDateString() : d)
144
+ if(!val || typeof val === "undefined" || this.dataTableService.badStrings.indexOf(val) > -1){
145
+ if(!count[na] || typeof count[na] === "undefined")
146
+ count[na] = 1
147
+ else
148
+ count[na] += 1
149
+ continue
150
+ }
151
+ if(!count[val] || typeof count[val] === "undefined")
152
+ count[val] = 1
153
+ else
154
+ count[val] += 1
155
+ }
156
+ count[this.dataTableService.deboTotal] = len
157
+ return count;
158
+ }
159
+
160
+ getColumnMode(count: any) {
161
+ let most = null
162
+ const na = "n_a"
163
+ for(const prop in count){
164
+ if(prop === this.dataTableService.deboTotal || prop === na)
165
+ continue
166
+ if(!most)
167
+ most = {text: prop, amount: count[prop]}
168
+ if(count[prop] > most.amount)
169
+ most = {text: prop, amount: count[prop]}
170
+ }
171
+ return most
172
+ }
173
+
174
+ handleBgTitle(event: string) {
175
+ this.bgTitle.emit(event)
176
+ }
177
+
178
+ }
@@ -0,0 +1,33 @@
1
+ :host{
2
+ --accent-color:rgb(50, 50, 50);
3
+ --grid-color:rgb(199, 199, 199);
4
+ --pad-left-base: 33px;
5
+ --row-num-width: 75px;
6
+ --reg-font-size: 17px
7
+ }
8
+
9
+ .lg-plot-opq{
10
+ opacity: 0;
11
+ background: white;
12
+ }
13
+
14
+ .lg-plot-opq:hover{
15
+ opacity: 1 !important;
16
+ background: var(--grid-color);
17
+ transition: opacity 0.2s ease;
18
+ }
19
+
20
+ .lg-canvas{
21
+ top: 0;
22
+ left: 0;
23
+ bottom: 0;
24
+ position: absolute;
25
+ }
26
+
27
+ .lg-msg{
28
+ top: 0;
29
+ left: 0;
30
+ right: 0;
31
+ position: absolute;
32
+ color: var(--accent-color);
33
+ }
@@ -0,0 +1,59 @@
1
+ <div #statOptsCont class="center stat-opt-contain">
2
+ @for(stat of statOpts; track stat){
3
+ <div [style.width]="statBtnWid" class="inline-b center">
4
+ <button class="no-btn stat-opt-btn" (click)="handleStatChange(stat)"
5
+ [class.stat-opt-btn-active]="selStat === stat">{{common.titleCase(stat)}}</button>
6
+ </div>
7
+ }
8
+ </div>
9
+ <div #auxOptsCont style="padding-bottom: 17px;">
10
+ <div class="qtr-wid center v-mid">
11
+ @if(valOpts().length){
12
+ <select [name]="'valSel' + common.elifyCol(column)" [id]="'valSel' + common.elifyCol(column)" [(ngModel)]="selDdVal"
13
+ (change)="handleValSelChange($any($event).target.value)" style="max-width: 80%">
14
+ @for(o of valOpts(); track o){
15
+ <option [value]="o" [selected]="o === selDdVal">{{o}}</option>
16
+ }
17
+ </select>
18
+ }
19
+ </div><div class="qtr-wid center v-mid">
20
+ <select [name]="'timeDiff' + common.elifyCol(column)" [id]="'timeDiff' + common.elifyCol(column)"
21
+ (change)="handleTimeDiffChange($any($event).target.value)" style="max-width: 88%" [(ngModel)]="selTDOpt">
22
+ <option value="-1" [selected]="selTDOpt === -1">All time</option>
23
+ @for(t of timeDiffOpts; track t.val){
24
+ <option [value]="t.val" [selected]="t.val === selTDOpt">{{t.text}}</option>
25
+ }
26
+ </select>
27
+ </div><div class="half-wid v-mid center dontwrap {{currentDeltaCls}}" [innerHTML]="currentDelta"></div>
28
+ </div>
29
+ <div #lgContain [id]="'lineGraph' + common.elifyCol(column)" class="inner-bg-contain" style="margin-bottom: 33px;">
30
+ <div #yAxis class="lg-n-marker-cont" [style.height]="totalHgt + 'px'">
31
+ @for(n of naddedtks(); track n.value; let i = $index){
32
+ <div class="bg-dep-var" [class.invisible]="n.value && n.value === maxYVal" [attr.data-number]="n.value"
33
+ [style.padding-bottom]="i < 4 ? (((i*4)+1) + 'px') : '0px'">
34
+ {{(n.value === '0') ? '' : n.value}}
35
+ </div>
36
+ }
37
+ @for(n of nmrks; track n){
38
+ <div class="lg-n-marker-h">{{n.value}}</div>
39
+ }
40
+ </div><div #lineGraph class="line-graph" [style.height]="totalHgt + 'px'">
41
+ @for(n of dtmrks; track n){
42
+ <div class="lg-dt-marker" [class.visible-marker]="n.visible" [style.left]="n.left">{{n.value}}</div>
43
+ }
44
+ @for(n of dtmrksH; track n){
45
+ <div class="lg-dt-marker-h" [class.visible-marker]="n.visible" [style.left]="n.left">{{n.value}}</div>
46
+ }
47
+ @if(lblTxt){
48
+ <div class="lg-lbl-x">{{lblTxt}}</div>
49
+ }
50
+ <canvas #lgCanvas class="lg-canvas" [height]="totalHgt"></canvas>
51
+ @for(p of plots(); track $index){
52
+ <div class="lg-plot lg-plot-opq" [attr.data-number]="p.number" (mouseenter)="showDotPlotInfo(p.date, p.number)"
53
+ (mouseleave)="hideDotPlotInfo()" [ngStyle]="{'bottom': (p.bottom-4) + 'px', 'left': (p.left-4) + 'px' }">{{p.value}}</div>
54
+ }
55
+ @if(!plots().length){
56
+ <div class="flex-center lg-msg" [style.height]="totalHgt + 'px'"><div>{{graphMsg}}</div></div>
57
+ }
58
+ </div>
59
+ </div>
@@ -0,0 +1,23 @@
1
+ import { ComponentFixture, TestBed } from '@angular/core/testing';
2
+
3
+ import { LineGraphComponent } from './line-graph-component';
4
+
5
+ describe('LineGraphComponent', () => {
6
+ let component: LineGraphComponent;
7
+ let fixture: ComponentFixture<LineGraphComponent>;
8
+
9
+ beforeEach(async () => {
10
+ await TestBed.configureTestingModule({
11
+ imports: [LineGraphComponent]
12
+ })
13
+ .compileComponents();
14
+
15
+ fixture = TestBed.createComponent(LineGraphComponent);
16
+ component = fixture.componentInstance;
17
+ fixture.detectChanges();
18
+ });
19
+
20
+ it('should create', () => {
21
+ expect(component).toBeTruthy();
22
+ });
23
+ });