saving progress, lots of charting decisions made

This commit is contained in:
2024-06-06 13:53:51 -04:00
parent bf74aeeba3
commit e88499cbaf
24 changed files with 612 additions and 87 deletions

View File

@@ -1,10 +1,24 @@
<div> <!-- <div>
<fbi-select label="Class" key="cohort" [data]="data.Cohorts"></fbi-select> <fbi-select label="Class" key="cohort" [data]="data.Cohorts"></fbi-select>
<fbi-select label="Year" key="year" [data]="data.Years"></fbi-select> <fbi-select label="Year" key="year" [data]="data.Years"></fbi-select>
<fbi-select label="Grade" key="grade" [data]="data.Grades"></fbi-select> <fbi-select label="Grade" key="grade" [data]="data.Grades"></fbi-select>
<fbi-select label="County" key="county" [data]="data.Counties"></fbi-select> <fbi-select label="County" key="county" [data]="data.Counties"></fbi-select>
<fbi-select label="School" key="school" [data]="data.Schools"></fbi-select> <fbi-select label="School" key="school" [data]="data.Schools"></fbi-select>
</div> <button (click)="onReset($event)">Reset</button>
<div> </div> -->
<!-- <div>
<fbi-table [header]="header" [rows]="rows"></fbi-table> <fbi-table [header]="header" [rows]="rows"></fbi-table>
</div> </div> -->
<!-- <fbi-scores
*ngFor="let grade of grades"
[grade]="grade"
[county]="county"
[school]="school"
></fbi-scores> -->
<fbi-cohort-section
*ngFor="let cohort of cohorts"
[cohort]="cohort"
[county]="county"
[school]="school"
></fbi-cohort-section>

View File

@@ -6,24 +6,49 @@ import { DataService } from '../services/data.service';
import { TableComponent } from '../components/table/table.component'; import { TableComponent } from '../components/table/table.component';
import { Header } from '../components/table/header'; import { Header } from '../components/table/header';
import { FilterService } from '../services/filters.service'; import { FilterService } from '../services/filters.service';
import { Observable } from 'rxjs';
import { Milestone } from '../enums/milestone';
import { ScoresComponent } from './scores/scores.component';
import { CommonModule } from '@angular/common';
import { CohortSectionComponent } from './cohort-section/cohort-section.component';
import { KeyValue } from '../models/key-value';
@Component({ @Component({
selector: 'app-root', selector: 'app-root',
standalone: true, standalone: true,
imports: [RouterOutlet, ChartComponent, SelectComponent, TableComponent], imports: [
CommonModule,
RouterOutlet,
ChartComponent,
SelectComponent,
TableComponent,
ScoresComponent,
CohortSectionComponent,
],
templateUrl: './app.component.html', templateUrl: './app.component.html',
styleUrl: './app.component.scss', styleUrl: './app.component.scss',
}) })
export class AppComponent implements OnInit { export class AppComponent implements OnInit {
title = 'Georgia Milestones'; title = 'Georgia Milestones';
county = '644';
school = ['3067', '0605'];
grades = [3, 4, 5];
cohorts: string[] = [];
data = inject(DataService); data = inject(DataService);
filter = inject(FilterService); filter = inject(FilterService);
header = [new Header({ label: 'School', source: 'school' })]; header = [
rows: Record<string, any>[] = []; { label: 'School', source: Milestone.School },
{ label: 'Grade', source: Milestone.Grade },
].map((data) => new Header(data));
rows: Observable<Record<string, any>[]> = this.data.Data;
ngOnInit(): void { ngOnInit(): void {
this.data.Cohorts.subscribe((kv: KeyValue[]) => {
this.cohorts = kv.map((i: KeyValue) => i.key);
});
// this.filter.filters$.subscribe((filters: KeyValue[]) => { // this.filter.filters$.subscribe((filters: KeyValue[]) => {
// this.data.Data.pipe(take(1)).subscribe((data: Milestone[]) => { // this.data.Data.pipe(take(1)).subscribe((data: Milestone[]) => {
// const result = data.filter((d: Milestone) => { // const result = data.filter((d: Milestone) => {
@@ -46,4 +71,8 @@ export class AppComponent implements OnInit {
// }); // });
// }); // });
} }
onReset(event: any): void {
this.filter.reset();
}
} }

View File

@@ -0,0 +1 @@
<fbi-chart [config]="chart" [data]="data"></fbi-chart>

View File

@@ -0,0 +1,23 @@
import { ComponentFixture, TestBed } from '@angular/core/testing';
import { CohortSectionComponent } from './cohort-section.component';
describe('CohortSectionComponent', () => {
let component: CohortSectionComponent;
let fixture: ComponentFixture<CohortSectionComponent>;
beforeEach(async () => {
await TestBed.configureTestingModule({
imports: [CohortSectionComponent]
})
.compileComponents();
fixture = TestBed.createComponent(CohortSectionComponent);
component = fixture.componentInstance;
fixture.detectChanges();
});
it('should create', () => {
expect(component).toBeTruthy();
});
});

View File

@@ -0,0 +1,80 @@
import { Component, Input, inject } from '@angular/core';
import { ChartComponent } from '../../components/chart/chart.component';
import { CommonModule } from '@angular/common';
import { Milestone } from '../../enums/milestone';
import {
ChartAxisPosition,
ChartType,
} from '../../components/chart/chart-type';
import { ChartConfig } from '../../components/chart/chart-config';
import { DataService } from '../../services/data.service';
@Component({
selector: 'fbi-cohort-section',
standalone: true,
imports: [CommonModule, ChartComponent],
templateUrl: './cohort-section.component.html',
styleUrl: './cohort-section.component.scss',
})
export class CohortSectionComponent {
@Input() county: string | string[] = '644';
@Input() school: string | string[] = '3067';
@Input() cohort!: string | string[];
chart: ChartConfig = {
type: ChartType.Line,
axis: [
{
label: 'Grade',
source: Milestone.Grade,
position: ChartAxisPosition.Bottom,
stacked: true,
},
{
label: [
'Beginning Learner',
'Developing Learner',
'Proficient Learner',
'Distinguished Learner',
],
source: [
Milestone.ELA0,
Milestone.ELA1,
Milestone.ELA2,
Milestone.ELA3,
],
position: ChartAxisPosition.Left,
fill: true,
stacked: true,
stack: 'ELA',
min: 0,
max: 100,
},
],
};
data: Record<string, any>[] = [];
private dataService = inject(DataService);
ngOnInit(): void {
const county = Array.isArray(this.county) ? this.county : [this.county];
const school = Array.isArray(this.school) ? this.school : [this.school];
const cohort = (
Array.isArray(this.cohort) ? this.cohort : [this.cohort]
).map((v: string) => parseInt(v));
this.dataService.Data.subscribe((data: Record<string, any>[]) => {
this.data = data
.filter(
(d: Record<string, any>) =>
county.includes(d[Milestone.County]) &&
school.includes(d[Milestone.School]) &&
cohort.includes(d[Milestone.Cohort])
)
.sort(
(a: Record<string, any>, b: Record<string, any>) =>
a['grade'] - b['grade']
);
});
}
}

View File

@@ -0,0 +1 @@
<fbi-chart [config]="chart" [data]="data"></fbi-chart>

View File

View File

@@ -0,0 +1,23 @@
import { ComponentFixture, TestBed } from '@angular/core/testing';
import { ScoresComponent } from './scores.component';
describe('ScoresComponent', () => {
let component: ScoresComponent;
let fixture: ComponentFixture<ScoresComponent>;
beforeEach(async () => {
await TestBed.configureTestingModule({
imports: [ScoresComponent]
})
.compileComponents();
fixture = TestBed.createComponent(ScoresComponent);
component = fixture.componentInstance;
fixture.detectChanges();
});
it('should create', () => {
expect(component).toBeTruthy();
});
});

View File

@@ -0,0 +1,92 @@
import { CommonModule } from '@angular/common';
import { Component, Input, OnInit, inject } from '@angular/core';
import { ChartComponent } from '../../components/chart/chart.component';
import {
ChartAxisPosition,
ChartType,
} from '../../components/chart/chart-type';
import { ChartConfig } from '../../components/chart/chart-config';
import { DataService } from '../../services/data.service';
import { Milestone } from '../../enums/milestone';
@Component({
selector: 'fbi-scores',
standalone: true,
imports: [CommonModule, ChartComponent],
templateUrl: './scores.component.html',
styleUrl: './scores.component.scss',
})
export class ScoresComponent implements OnInit {
@Input() county: string = '644';
@Input() school: string = '3067';
@Input() grade!: number;
chart: ChartConfig = {
type: ChartType.Bar,
axis: [
{
label: 'Year',
source: Milestone.Year,
position: ChartAxisPosition.Bottom,
stacked: true,
},
{
label: [
'Beginning Learner',
'Developing Learner',
'Proficient Learner',
'Distinguished Learner',
],
source: [
Milestone.ELA0,
Milestone.ELA1,
Milestone.ELA2,
Milestone.ELA3,
],
position: ChartAxisPosition.Left,
stacked: true,
stack: 'ELA',
min: 0,
max: 100,
},
{
label: [
'Beginning Learner',
'Developing Learner',
'Proficient Learner',
'Distinguished Learner',
],
source: [
Milestone.Math0,
Milestone.Math1,
Milestone.Math2,
Milestone.Math3,
],
position: ChartAxisPosition.Right,
stacked: true,
stack: 'Math',
min: 0,
max: 100,
},
],
};
data: Record<string, any>[] = [];
private dataService = inject(DataService);
ngOnInit(): void {
const county = this.county;
const school = this.school;
const grade = this.grade;
this.dataService.Data.subscribe((data: Record<string, any>[]) => {
this.data = data.filter(
(d: Record<string, any>) =>
d[Milestone.County] === county &&
d[Milestone.School] === school &&
d[Milestone.Grade] === grade
);
});
}
}

View File

@@ -0,0 +1,7 @@
import { ChartType } from 'chart.js';
import { ChartAxis } from './chart-type';
export interface ChartConfig {
type: ChartType;
axis: ChartAxis[];
}

View File

@@ -9,14 +9,30 @@ export enum ChartType {
Radar = 'radar', Radar = 'radar',
} }
export enum ChartAxisPosition {
Top = 'top',
Right = 'right',
Bottom = 'bottom',
Left = 'left',
Center = 'center',
}
export interface IDataset { export interface IDataset {
type?: ChartType; type?: ChartType;
borderColor?: string; borderColor?: string;
label?: string; label?: string;
data: string[]; order?: number;
data: (string | Record<string, any>)[];
beginAtZero?: boolean;
fill?: string | number | boolean;
backgroundColor?: string | string[]; backgroundColor?: string | string[];
pointBackgroundColor?: string; pointBackgroundColor?: string;
pointBorderColor?: string; pointBorderColor?: string;
parsing?: {
xAxisKey?: string;
yAxisKey?: string;
};
stack?: string;
} }
export interface IData { export interface IData {
@@ -24,3 +40,15 @@ export interface IData {
labelsSource?: string[]; labelsSource?: string[];
datasets: IDataset[]; datasets: IDataset[];
} }
export interface ChartAxis {
label: string | string[];
source: string | string[];
type?: ChartType;
fill?: boolean;
stacked?: boolean;
stack?: string;
position: ChartAxisPosition;
min?: number;
max?: number;
}

View File

@@ -2,13 +2,21 @@ import {
AfterViewInit, AfterViewInit,
Component, Component,
ElementRef, ElementRef,
Input,
OnChanges,
OnDestroy, OnDestroy,
SimpleChanges,
ViewChild, ViewChild,
} from '@angular/core'; } from '@angular/core';
import { Chart, ChartOptions } from 'chart.js/auto'; import { Chart } from 'chart.js/auto';
import { PluginNodata } from './plugin-nodata'; import { PluginNodata } from './plugin-nodata';
import { PluginMoreColors } from './plugin-more-colors'; import { PluginMoreColors } from './plugin-more-colors';
import { ChartType, IData } from './chart-type'; import { ChartConfig } from './chart-config';
import { ChartConfigService } from './services/chart-config.service';
import { DatasetService } from './services/dataset.service';
import { LabelService } from './services/label.service';
import { OptionsService } from './services/options.service';
import { ScaleService } from './services/scale.service';
@Component({ @Component({
selector: 'fbi-chart', selector: 'fbi-chart',
@@ -16,50 +24,43 @@ import { ChartType, IData } from './chart-type';
imports: [], imports: [],
templateUrl: './chart.component.html', templateUrl: './chart.component.html',
styleUrl: './chart.component.scss', styleUrl: './chart.component.scss',
providers: [
ChartConfigService,
DatasetService,
LabelService,
OptionsService,
ScaleService,
],
}) })
export class ChartComponent implements AfterViewInit, OnDestroy { export class ChartComponent implements OnChanges, AfterViewInit, OnDestroy {
@ViewChild('chart') canvas!: ElementRef; @ViewChild('chart') canvas!: ElementRef;
@Input() config!: ChartConfig;
@Input() data!: Record<string, any>[];
private chart: any = undefined; private chart: any = undefined;
private data: IData = {
labels: Array.from(
{ length: 10 },
() => `${Math.floor(Math.random() * 100)}`
),
// labelsSource: [],
datasets: [
{
label: 'test',
data: Array.from(
{ length: 10 },
() => `${Math.floor(Math.random() * 100)}`
),
},
],
};
constructor() {} constructor(private chartConfigService: ChartConfigService) {}
ngAfterViewInit(): void { ngAfterViewInit(): void {
this.initChart(); this.initChart();
} }
ngOnChanges(changes: SimpleChanges): void {
this.initChart();
}
ngOnDestroy(): void { ngOnDestroy(): void {
this.chart?.destroy?.(); this.chart?.destroy?.();
} }
initChart() { private initChart() {
if (!this.canvas?.nativeElement) return;
this.chart?.destroy?.(); this.chart?.destroy?.();
const config = this.chartConfigService.chart(this.config, this.data);
console.log(config);
const opts: ChartOptions = {}; config.plugins = [PluginNodata.config(), PluginMoreColors.config()];
opts.responsive = true; this.chart = new Chart(this.canvas.nativeElement, config);
opts.maintainAspectRatio = false;
this.chart = new Chart(this.canvas.nativeElement, {
type: ChartType.Bar,
data: this.data,
options: opts,
plugins: [PluginNodata.config(), PluginMoreColors.config()] as any[],
});
} }
} }

View File

@@ -0,0 +1,30 @@
import { Injectable } from '@angular/core';
import { ChartConfig } from '../chart-config';
import { IData } from '../chart-type';
import { DatasetService } from './dataset.service';
import { LabelService } from './label.service';
import { OptionsService } from './options.service';
@Injectable()
export class ChartConfigService {
constructor(
private datasetService: DatasetService,
private labelService: LabelService,
private optionsService: OptionsService
) {}
chart(chart: ChartConfig, data: Record<string, any>[]): any {
return {
type: chart?.type,
data: this.data(chart, data),
options: this.optionsService.options(chart, data),
} as any;
}
private data(chart: ChartConfig, data: Record<string, any>[]): IData {
return {
labels: this.labelService.labels(chart, data),
datasets: this.datasetService.datasets(chart, data),
} as IData;
}
}

View File

@@ -0,0 +1,54 @@
import { Injectable } from '@angular/core';
import { ChartConfig } from '../chart-config';
import { ChartAxis, ChartAxisPosition, IDataset } from '../chart-type';
@Injectable()
export class DatasetService {
constructor() {}
datasets(chart: ChartConfig, data: Record<string, any>[]): IDataset[] {
const result: IDataset[] = [];
(chart?.axis ?? []).forEach((axis: ChartAxis) => {
switch (axis.position) {
case ChartAxisPosition.Left:
case ChartAxisPosition.Right:
const ds = this.dataset(axis, data);
result.push(...ds);
break;
}
});
return result;
}
private dataset(axis: ChartAxis, data: Record<string, any>[]): IDataset[] {
let result: IDataset[] = [];
const labels = Array.isArray(axis.label) ? axis.label : [axis.label];
const sources = Array.isArray(axis.source) ? axis.source : [axis.source];
if (labels.length !== sources.length) return result;
labels.forEach((label: string, idx: number) => {
const source = sources[idx];
const entry: IDataset = {
label: label,
// order: idx,
data: (data ?? []).map((d: Record<string, any>) => d[source]),
};
if (axis.type) {
entry.type = axis.type;
}
if (axis.stack) {
entry.stack = axis.stack;
}
if (axis.fill) {
entry.fill = axis.fill;
}
result.push(entry);
});
return result;
}
}

View File

@@ -0,0 +1,33 @@
import { Injectable } from '@angular/core';
import { ChartConfig } from '../chart-config';
import { ChartAxis, ChartAxisPosition } from '../chart-type';
@Injectable()
export class LabelService {
constructor() {}
labels(chart: ChartConfig, data: Record<string, any>[]): string[] {
const result: string[] = [];
(chart?.axis ?? [])
.filter((axis: ChartAxis) =>
[ChartAxisPosition.Top, ChartAxisPosition.Bottom].includes(
axis.position
)
)
.map((axis: ChartAxis, index: number) => {
if (index > 0) return;
const sources = Array.isArray(axis.source)
? axis.source
: [axis.source];
const source = sources[0];
(data ?? []).map((record: Record<string, any>) =>
result.push(record[sources[0]])
);
});
return result;
}
}

View File

@@ -0,0 +1,27 @@
import { ChartOptions } from 'chart.js';
import { ChartConfig } from '../chart-config';
import { ScaleService } from './scale.service';
import { Injectable } from '@angular/core';
import { ChartAxis } from '../chart-type';
@Injectable()
export class OptionsService {
constructor(private scaleService: ScaleService) {}
options(chart: ChartConfig, data: Record<string, any>[]): ChartOptions {
const result: ChartOptions = {};
result.responsive = true;
result.maintainAspectRatio = false;
result.scales = this.scaleService.scales(chart, data);
const fill =
(chart?.axis ?? []).filter((axis: ChartAxis) => axis.fill).length > 0;
if (fill) {
result.plugins = result.plugins ?? {};
result.plugins.filler = { propagate: true };
}
return result;
}
}

View File

@@ -0,0 +1,59 @@
import { Injectable } from '@angular/core';
import { ChartConfig } from '../chart-config';
import { ChartAxis, ChartAxisPosition } from '../chart-type';
@Injectable()
export class ScaleService {
constructor() {}
scales(chart: ChartConfig, data: Record<string, any>[]): any {
const result: any = {};
let x = 0;
let y = 0;
(chart?.axis ?? []).forEach((axis: ChartAxis, index: number) => {
let scale = '';
let count = 0;
axis.position = axis.position ?? ChartAxisPosition.Bottom;
switch (axis.position) {
case ChartAxisPosition.Left:
case ChartAxisPosition.Right:
scale = 'y';
count = y;
++y;
break;
case ChartAxisPosition.Bottom:
case ChartAxisPosition.Top:
scale = 'x';
count = x;
++x;
break;
}
result[`${scale}${count === 0 ? '' : count}`] = this.getScale(axis);
});
return result;
}
private getScale(item: ChartAxis): Record<string, any> {
const opts: Record<string, any> = {};
if (item.stacked) {
opts['stacked'] = true;
}
if (item.position) {
opts['position'] = item.position;
}
if (item.stack) {
opts['stack'] = item.stack;
}
if (item.min) {
opts['min'] = item.min;
}
if (item.max) {
opts['max'] = item.max;
}
return opts;
}
}

View File

@@ -1,6 +1,8 @@
<select name="select" (change)="onChange($event)"> <select name="select" [(ngModel)]="selected" (change)="onChange($event)">
<option selected disabled hidden value="">{{ label }}</option> <option [ngValue]="undefined" selected disabled hidden>
<option *ngFor="let kv of data | async" [value]="kv.key"> {{ label }}
</option>
<option *ngFor="let kv of data | async" [ngValue]="kv.key">
{{ kv.value }} {{ kv.value }}
</option> </option>
</select> </select>

View File

@@ -1,23 +1,39 @@
import { Component, Input, inject } from '@angular/core'; import { Component, Input, OnInit, inject } from '@angular/core';
import { CommonModule } from '@angular/common'; import { CommonModule } from '@angular/common';
import { Observable } from 'rxjs'; import { Observable } from 'rxjs';
import { KeyValue } from '../../models/key-value'; import { KeyValue } from '../../models/key-value';
import { FilterService } from '../../services/filters.service'; import { FilterService } from '../../services/filters.service';
import { FormsModule } from '@angular/forms';
@Component({ @Component({
selector: 'fbi-select', selector: 'fbi-select',
standalone: true, standalone: true,
imports: [CommonModule], imports: [CommonModule, FormsModule],
templateUrl: './select.component.html', templateUrl: './select.component.html',
styleUrl: './select.component.scss', styleUrl: './select.component.scss',
}) })
export class SelectComponent { export class SelectComponent implements OnInit {
@Input() label!: string; @Input() label!: string;
@Input() key!: string; @Input() key!: string;
@Input() data!: Observable<KeyValue[]>; @Input() data!: Observable<KeyValue[]>;
selected: any = undefined;
private filterService = inject(FilterService); private filterService = inject(FilterService);
ngOnInit(): void {
this.filterService.filters$.subscribe((f: KeyValue[]) => {
let me = (f ?? [])
.filter((i: KeyValue) => i.key === this.key)
.find((_) => true);
if (me) {
this.selected = me.value;
} else {
this.selected = undefined;
}
});
}
onChange(event: any): void { onChange(event: any): void {
this.filterService.set(this.key, event?.target?.value); this.filterService.set(this.key, event?.target?.value);
} }

View File

@@ -4,7 +4,8 @@
{{ h.label }} {{ h.label }}
</th> </th>
</tr> </tr>
<tr *ngFor="let row of rows; let index"> <tr *ngFor="let row of rows | async; let index">
<td>{{ index }}</td>
<td *ngFor="let h of header"> <td *ngFor="let h of header">
{{ row[h.source] }} {{ row[h.source] }}
</td> </td>

View File

@@ -1,6 +1,7 @@
import { CommonModule } from '@angular/common'; import { CommonModule } from '@angular/common';
import { Component, Input } from '@angular/core'; import { Component, Input } from '@angular/core';
import { Header } from './header'; import { Header } from './header';
import { Observable } from 'rxjs';
@Component({ @Component({
selector: 'fbi-table', selector: 'fbi-table',
@@ -11,5 +12,5 @@ import { Header } from './header';
}) })
export class TableComponent { export class TableComponent {
@Input() header!: Header[]; @Input() header!: Header[];
@Input() rows!: Record<string, any>[]; @Input() rows!: Observable<Record<string, any>[]>;
} }

View File

@@ -48,10 +48,14 @@ export class DataService {
download: true, download: true,
header: false, header: false,
complete: (results: ParseResult<Record<string, any>>) => { complete: (results: ParseResult<Record<string, any>>) => {
const headers = this.getHeaders((results?.data ?? []).slice(1, 3)); const h = this.getHeaders((results?.data ?? []).slice(1, 3));
const lookup = (x: string, record: Record<string, any>): any => { const fs = (x: string, r: Record<string, any>): string => {
const idx = headers.findIndex((h: string) => x === h); const idx = h.findIndex((h: string) => x === h);
return (idx > -1 ? record[idx] : '') as any; return (idx > -1 ? r[idx] : '') as string;
};
const fn = (x: string, r: Record<string, any>): number => {
const idx = h.findIndex((h: string) => x === h);
return +(idx > -1 ? r[idx] : '');
}; };
const cohort = year + 12 - grade; const cohort = year + 12 - grade;
this._cohorts.set(`${cohort}`, `Class of ${cohort}`); this._cohorts.set(`${cohort}`, `Class of ${cohort}`);
@@ -59,7 +63,7 @@ export class DataService {
const data: Record<string, any>[] = []; const data: Record<string, any>[] = [];
(results?.data ?? []).forEach((record: Record<string, any>) => { (results?.data ?? []).forEach((record: Record<string, any>) => {
let code = parseInt(lookup(Csv.County_Code, record)); let code = fn(Csv.County_Code, record);
// skip non-data rows on the csv // skip non-data rows on the csv
if (isNaN(code)) return; if (isNaN(code)) return;
@@ -68,44 +72,39 @@ export class DataService {
ms[Milestone.Year] = year; ms[Milestone.Year] = year;
ms[Milestone.Grade] = grade; ms[Milestone.Grade] = grade;
ms[Milestone.Cohort] = cohort; ms[Milestone.Cohort] = cohort;
ms[Milestone.County] = lookup(Csv.County_Code, record); ms[Milestone.County] = fs(Csv.County_Code, record);
ms[Milestone.School] = lookup(Csv.School_Code, record); ms[Milestone.School] = fs(Csv.School_Code, record);
ms[Milestone.ELACount] = lookup(Csv.ELA_Count, record); ms[Milestone.ELACount] = fn(Csv.ELA_Count, record);
ms[Milestone.ELAMean] = lookup(Csv.ELA_Mean, record); ms[Milestone.ELAMean] = fn(Csv.ELA_Mean, record);
ms[Milestone.ELA0] = lookup(Csv.ELA_L0, record); ms[Milestone.ELA0] = fn(Csv.ELA_L0, record);
ms[Milestone.ELA1] = lookup(Csv.ELA_L1, record); ms[Milestone.ELA1] = fn(Csv.ELA_L1, record);
ms[Milestone.ELA2] = lookup(Csv.ELA_L2, record); ms[Milestone.ELA2] = fn(Csv.ELA_L2, record);
ms[Milestone.ELA3] = lookup(Csv.ELA_L3, record); ms[Milestone.ELA3] = fn(Csv.ELA_L3, record);
ms[Milestone.MathCount] = lookup(Csv.Math_Count, record); ms[Milestone.MathCount] = fn(Csv.Math_Count, record);
ms[Milestone.MathMean] = lookup(Csv.Math_Mean, record); ms[Milestone.MathMean] = fn(Csv.Math_Mean, record);
ms[Milestone.Math0] = lookup(Csv.Math_L0, record); ms[Milestone.Math0] = fn(Csv.Math_L0, record);
ms[Milestone.Math1] = lookup(Csv.Math_L1, record); ms[Milestone.Math1] = fn(Csv.Math_L1, record);
ms[Milestone.Math2] = lookup(Csv.Math_L2, record); ms[Milestone.Math2] = fn(Csv.Math_L2, record);
ms[Milestone.Math3] = lookup(Csv.Math_L3, record); ms[Milestone.Math3] = fn(Csv.Math_L3, record);
ms[Milestone.SciCount] = lookup(Csv.Science_Count, record); ms[Milestone.SciCount] = fn(Csv.Science_Count, record);
ms[Milestone.SciMean] = lookup(Csv.Science_Mean, record); ms[Milestone.SciMean] = fn(Csv.Science_Mean, record);
ms[Milestone.Sci0] = lookup(Csv.Science_L0, record); ms[Milestone.Sci0] = fn(Csv.Science_L0, record);
ms[Milestone.Sci1] = lookup(Csv.Science_L1, record); ms[Milestone.Sci1] = fn(Csv.Science_L1, record);
ms[Milestone.Sci2] = lookup(Csv.Science_L2, record); ms[Milestone.Sci2] = fn(Csv.Science_L2, record);
ms[Milestone.Sci3] = lookup(Csv.Science_L3, record); ms[Milestone.Sci3] = fn(Csv.Science_L3, record);
ms[Milestone.SocCount] = lookup(Csv.Social_Count, record); ms[Milestone.SocCount] = fn(Csv.Social_Count, record);
ms[Milestone.SocMean] = lookup(Csv.Social_Mean, record); ms[Milestone.SocMean] = fn(Csv.Social_Mean, record);
ms[Milestone.Soc0] = lookup(Csv.Social_L0, record); ms[Milestone.Soc0] = fn(Csv.Social_L0, record);
ms[Milestone.Soc1] = lookup(Csv.Social_L1, record); ms[Milestone.Soc1] = fn(Csv.Social_L1, record);
ms[Milestone.Soc2] = lookup(Csv.Social_L2, record); ms[Milestone.Soc2] = fn(Csv.Social_L2, record);
ms[Milestone.Soc3] = lookup(Csv.Social_L3, record); ms[Milestone.Soc3] = fn(Csv.Social_L3, record);
data.push(ms); data.push(ms);
this._counties.set( const county = fs(Csv.County_Code, record);
lookup(Csv.County_Code, record), this._counties.set(county, fs(Csv.County_Label, record));
lookup(Csv.County_Label, record)
);
this._schools.set( this._schools.set(
`${lookup(Csv.County_Code, record)}-${lookup( `${county}-${fs(Csv.School_Code, record)}`,
Csv.School_Code, fs(Csv.School_Label, record)
record
)}`,
lookup(Csv.School_Label, record)
); );
}); });

View File

@@ -22,4 +22,8 @@ export class FilterService {
if (!!value) update.push(new KeyValue({ key: key, value: value })); if (!!value) update.push(new KeyValue({ key: key, value: value }));
this.filters = update; this.filters = update;
} }
reset(): void {
this.filters = [];
}
} }