From 20b87abba1b5915cb27350c3d08271a8ab2f2cbb Mon Sep 17 00:00:00 2001 From: Daniel Ponte Date: Sat, 22 Feb 2025 17:36:09 -0500 Subject: [PATCH] Chart spinner --- .../src/app/charts/charts.component.html | 1 + .../src/app/charts/charts.component.ts | 157 +++++++++--------- .../stillbox/src/app/home/home.component.html | 14 +- .../stillbox/src/app/home/home.component.scss | 2 +- .../stillbox/src/app/home/home.component.ts | 35 +++- 5 files changed, 118 insertions(+), 91 deletions(-) diff --git a/client/stillbox/src/app/charts/charts.component.html b/client/stillbox/src/app/charts/charts.component.html index 439281b..db578cf 100644 --- a/client/stillbox/src/app/charts/charts.component.html +++ b/client/stillbox/src/app/charts/charts.component.html @@ -1 +1,2 @@
+
diff --git a/client/stillbox/src/app/charts/charts.component.ts b/client/stillbox/src/app/charts/charts.component.ts index b66045d..3573e5d 100644 --- a/client/stillbox/src/app/charts/charts.component.ts +++ b/client/stillbox/src/app/charts/charts.component.ts @@ -7,10 +7,7 @@ import { NgIf } from '@angular/common'; @Component({ selector: 'chart', - imports: [ - NgIf, - MatProgressSpinnerModule, - ], + imports: [NgIf, MatProgressSpinnerModule], templateUrl: './charts.component.html', styleUrl: './charts.component.scss', }) @@ -50,77 +47,87 @@ export class ChartsComponent { } ngOnInit() { - this.interval.pipe(switchMap((intv) => { - this.loading = true; - return this.callsSvc.getCallStats(intv); - })). - subscribe((stats) => { - let cMax = 0; - var cMin = 0; - let data = stats.stats.map((rec) => { - if (cMin == 0 && rec.count > cMin) { - cMin = rec.count; - } - if (rec.count < cMin) { - cMin = rec.count; - } - if (rec.count > cMax) { - cMax = rec.count; - } - return { count: rec.count, time: this.dateFormat(new Date(rec.time), stats.interval) }; - }); - // set the dimensions and margins of the graph - var margin = { top: 30, right: 30, bottom: 70, left: 60 }, - width = 460 - margin.left - margin.right, - height = 400 - margin.top - margin.bottom; - // clear the old one - d3.select(this.elementRef.nativeElement).select('.chart svg').remove(); - const svg = d3 - .select(this.elementRef.nativeElement) - .select('.chart') - .append('svg') - .attr('width', width + margin.left + margin.right) - .attr('height', height + margin.top + margin.bottom) - .append('g') - .attr('transform', 'translate(' + margin.left + ',' + margin.top + ')'); - // X axis - var x = d3 - .scaleBand() - .range([0, width]) - .domain( - data.map(function (d) { - return d.time; - }), - ) - .padding(0.2); - svg - .append('g') - .attr('transform', 'translate(0,' + height + ')') - .call(d3.axisBottom(x)) - .selectAll('text') - .attr('transform', 'translate(-10,0)rotate(-45)') - .style('text-anchor', 'end'); - - // Add Y axis - var y = d3.scaleLinear().domain([0, cMax]).range([height, 0]); - svg.append('g').call(d3.axisLeft(y)); - svg - .selectAll('mybar') - .data(data) - .enter() - .append('rect') - .attr('x', (d) => x(d.time)!) - .attr('y', function (d) { - return y(d.count); - }) - .attr('width', x.bandwidth()) - .attr('height', function (d) { - return height - y(d.count); - }) - .attr('fill', function (d) { - return d3.interpolateTurbo((d.count - cMin) / (cMax - cMin)); + this.interval + .pipe( + switchMap((intv) => { + d3.select(this.elementRef.nativeElement).select('.chart').html(''); + this.loading = true; + return this.callsSvc.getCallStats(intv); + }), + ) + .subscribe((stats) => { + let cMax = 0; + var cMin = 0; + let data = stats.stats.map((rec) => { + if (cMin == 0 && rec.count > cMin) { + cMin = rec.count; + } + if (rec.count < cMin) { + cMin = rec.count; + } + if (rec.count > cMax) { + cMax = rec.count; + } + return { + count: rec.count, + time: this.dateFormat(new Date(rec.time), stats.interval), + }; }); - this.loading = false; - }); + // set the dimensions and margins of the graph + var margin = { top: 30, right: 30, bottom: 70, left: 60 }, + width = 460 - margin.left - margin.right, + height = 400 - margin.top - margin.bottom; + // clear the old one + d3.select(this.elementRef.nativeElement).select('.chart').html(''); + const svg = d3 + .select(this.elementRef.nativeElement) + .select('.chart') + .append('svg') + .attr('width', width + margin.left + margin.right) + .attr('height', height + margin.top + margin.bottom) + .append('g') + .attr( + 'transform', + 'translate(' + margin.left + ',' + margin.top + ')', + ); + // X axis + var x = d3 + .scaleBand() + .range([0, width]) + .domain( + data.map(function (d) { + return d.time; + }), + ) + .padding(0.2); + svg + .append('g') + .attr('transform', 'translate(0,' + height + ')') + .call(d3.axisBottom(x)) + .selectAll('text') + .attr('transform', 'translate(-10,0)rotate(-45)') + .style('text-anchor', 'end'); + + // Add Y axis + var y = d3.scaleLinear().domain([0, cMax]).range([height, 0]); + svg.append('g').call(d3.axisLeft(y)); + svg + .selectAll('mybar') + .data(data) + .enter() + .append('rect') + .attr('x', (d) => x(d.time)!) + .attr('y', function (d) { + return y(d.count); + }) + .attr('width', x.bandwidth()) + .attr('height', function (d) { + return height - y(d.count); + }) + .attr('fill', function (d) { + return d3.interpolateTurbo((d.count - cMin) / (cMax - cMin)); + }); + this.loading = false; + }); } } diff --git a/client/stillbox/src/app/home/home.component.html b/client/stillbox/src/app/home/home.component.html index 4a9c6db..8d74aa4 100644 --- a/client/stillbox/src/app/home/home.component.html +++ b/client/stillbox/src/app/home/home.component.html @@ -1,14 +1,14 @@ -
Calls By
- - + + + Hour Day Week Month - - - - + +
+ +
diff --git a/client/stillbox/src/app/home/home.component.scss b/client/stillbox/src/app/home/home.component.scss index 06e84df..e78fb2f 100644 --- a/client/stillbox/src/app/home/home.component.scss +++ b/client/stillbox/src/app/home/home.component.scss @@ -1,6 +1,6 @@ mat-card.chart { width: 500px; - height: 400px; + height: 500px; margin: 30px 30px 40px 40px; } diff --git a/client/stillbox/src/app/home/home.component.ts b/client/stillbox/src/app/home/home.component.ts index 5de96e4..ad4b230 100644 --- a/client/stillbox/src/app/home/home.component.ts +++ b/client/stillbox/src/app/home/home.component.ts @@ -1,15 +1,35 @@ import { Component, computed, signal, ViewChild } from '@angular/core'; import { ChartsComponent } from '../charts/charts.component'; import { MatCardModule } from '@angular/material/card'; -import { FormControl, FormGroup, FormsModule, ReactiveFormsModule } from '@angular/forms'; -import { debounceTime, filter, Observable, startWith, switchAll, switchMap } from 'rxjs'; +import { + FormControl, + FormGroup, + FormsModule, + ReactiveFormsModule, +} from '@angular/forms'; +import { + debounceTime, + filter, + Observable, + startWith, + switchAll, + switchMap, +} from 'rxjs'; import { MatFormFieldModule } from '@angular/material/form-field'; import { MatSelectModule } from '@angular/material/select'; import { MatInputModule } from '@angular/material/input'; @Component({ selector: 'app-home', - imports: [ChartsComponent, MatCardModule, MatFormFieldModule, MatSelectModule, MatInputModule, FormsModule, ReactiveFormsModule ], + imports: [ + ChartsComponent, + MatCardModule, + MatFormFieldModule, + MatSelectModule, + MatInputModule, + FormsModule, + ReactiveFormsModule, + ], templateUrl: './home.component.html', styleUrl: './home.component.scss', }) @@ -20,12 +40,11 @@ export class HomeComponent { callsOb!: Observable; ngOnInit() { - this.form.controls["callsPer"].setValue("week"); - this.callsOb = this.form.controls['callsPer'].valueChanges - .pipe( - startWith("week"), + this.form.controls['callsPer'].setValue('week'); + this.callsOb = this.form.controls['callsPer'].valueChanges.pipe( + startWith('week'), debounceTime(300), - filter(val => val !== null) + filter((val) => val !== null), ); } }