Skip to content

Commit

Permalink
feat(Data Explorer): Sync table row sorting with connected graphs
Browse files Browse the repository at this point in the history
  • Loading branch information
breity authored Nov 15, 2022
1 parent ff7d1b3 commit f0f9517
Show file tree
Hide file tree
Showing 12 changed files with 186 additions and 48 deletions.
14 changes: 7 additions & 7 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -59,7 +59,7 @@
"sockjs-client": "^1.6.0",
"svg.draggable.js": "2.2.0",
"svg.js": "2.7.1",
"tabulator-tables": "^5.2.7",
"tabulator-tables": "^5.4.2",
"tinymce": "^5.10.3",
"tslib": "^2.3.1",
"webfontloader": "^1.6.28",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -449,6 +449,51 @@ function handleTableConnectedComponentStudentDataChanged() {
[20, 40]
]);
});
it('should handle table connected component student data changed with sorted rows', () => {
const connectedComponent = createTableConnectedComponent();
const dataRows: any[] = [
[0, 0],
[10, 20],
[20, 40],
[30, 80]
];
const tableDataRows: any[] = [['Time', 'Position']].concat(dataRows);
const componentState = {
studentData: {
tableData: createTable(tableDataRows),
sortOrder: [2, 1, 0, 3]
}
};
component.handleTableConnectedComponentStudentDataChanged(connectedComponent, componentState);
expect(component.activeTrial.series[0].data).toEqual([
[20, 40],
[10, 20],
[0, 0],
[30, 80]
]);
});
it('should handle table connected component student data changed with selected and sorted rows', () => {
const connectedComponent = createTableConnectedComponent();
const dataRows: any[] = [
[0, 0],
[10, 20],
[20, 40],
[30, 80]
];
const tableDataRows: any[] = [['Time', 'Position']].concat(dataRows);
const componentState = {
studentData: {
tableData: createTable(tableDataRows),
selectedRowIndices: [0, 2],
sortOrder: [2, 1, 0, 3]
}
};
component.handleTableConnectedComponentStudentDataChanged(connectedComponent, componentState);
expect(component.activeTrial.series[0].data).toEqual([
[20, 40],
[0, 0]
]);
});
it('should handle connected data explorer student data changed', () => {
const connectedComponent = createTableConnectedComponent();
const studentData = createDataExplorerStudentData();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -261,10 +261,12 @@ export class GraphStudent extends ComponentStudent {

handleTableConnectedComponentStudentDataChanged(connectedComponent, componentState) {
const studentData = this.UtilService.makeCopyOfJSONObject(componentState.studentData);
const selectedRowIndices = studentData.selectedRowIndices;
const tableData = studentData.tableData;
if (tableData.length > 0 && selectedRowIndices != null && selectedRowIndices.length > 0) {
studentData.tableData = this.getVisibleRows(studentData.tableData, selectedRowIndices);
if (studentData.tableData.length > 0) {
studentData.tableData = this.processTableData(
studentData.tableData,
studentData.sortOrder,
studentData.selectedRowIndices
);
}
if (studentData.isDataExplorerEnabled) {
this.handleDataExplorer(studentData);
Expand All @@ -275,14 +277,46 @@ export class GraphStudent extends ComponentStudent {
this.isDirty = true;
}

private getVisibleRows(tableData: any, selectedRowIndices: number[]): any[] {
const visibleRows = [];
visibleRows.push(tableData[0]);
tableData.forEach((row, index) => {
if (selectedRowIndices.includes(index - 1)) {
visibleRows.push(row);
private processTableData(
tableData: any[],
sortOrder: number[] = [],
selectedRowIndices: number[] = []
): any[] {
if (sortOrder && sortOrder.length > 0) {
return this.getSortedAndFilteredTableData(tableData, sortOrder, selectedRowIndices);
} else {
return this.getFilteredTableData(tableData, selectedRowIndices);
}
}

private getSortedAndFilteredTableData(
tableData: any[],
sortOrder: number[],
selectedRowIndices: number[]
): any[] {
const sortedTableData = [tableData[0]];
sortOrder.forEach((rowNumber, index) => {
if (this.isRowSelected(rowNumber, selectedRowIndices)) {
sortedTableData.push(tableData[rowNumber + 1]);
}
});
return sortedTableData;
}

private isRowSelected(rowNumber: number, selectedRowIndices: number[]): boolean {
return selectedRowIndices.length > 0 ? selectedRowIndices.includes(rowNumber) : true;
}

private getFilteredTableData(tableData: any[], selectedRowIndices: number[]): any[] {
let visibleRows = tableData;
if (selectedRowIndices && selectedRowIndices.length > 0) {
visibleRows = [tableData[0]];
tableData.forEach((row, index) => {
if (this.isRowSelected(index - 1, selectedRowIndices)) {
visibleRows.push(row);
}
});
}
return visibleRows;
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
[tabColumns]="tabulatorData.columns"
[tabData]="tabulatorData.data"
[tabOptions]="tabulatorData.options"
[tabSorters]="tabulatorSorters"
(ready)="tabulatorRendered()"></tabulator-table>
</div>
<ng-container *ngIf="componentContent.isDataExplorerEnabled">
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ export class TableShowWorkComponent extends ComponentShowWorkDirective {
columnNames: string[] = [];
noneText: string = $localize`(None)`;
tabulatorData: TabulatorData;
tabulatorSorters: any[];

constructor(
protected nodeService: NodeService,
Expand All @@ -36,6 +37,7 @@ export class TableShowWorkComponent extends ComponentShowWorkDirective {
const studentData = this.componentState.studentData;
this.tableData = studentData.tableData;
this.selectedRowIndices = studentData.selectedRowIndices ? studentData.selectedRowIndices : [];
this.tabulatorSorters = studentData.tabulatorSorters ? studentData.tabulatorSorters : [];
if (studentData.isDataExplorerEnabled) {
this.dataExplorerGraphType = studentData.dataExplorerGraphType;
this.dataExplorerSeries = studentData.dataExplorerSeries;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -37,8 +37,10 @@
[tabColumns]="tabulatorData.columns"
[tabData]="tabulatorData.data"
[tabOptions]="tabulatorData.options"
[tabSorters]="tabulatorSorters"
(cellChanged)="tabulatorCellChanged($event)"
(rowSelectionChanged)="tabulatorRowSelectionChanged($event)"
(rowSortChanged)="tabulatorRowSortChanged($event)"
(ready)="tabulatorRendered()"></tabulator-table>
<div *ngIf="isDataExplorerEnabled">
<br/>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -42,9 +42,11 @@ export class TableStudent extends ComponentStudent {
notebookConfig: any;
numDataExplorerSeries: number;
selectedRowIndices: number[] = [];
sortOrder: number[] = [];
tableData: any;
tableId: string;
tabulatorData: TabulatorData;
tabulatorSorters: any[] = [];

constructor(
protected AnnotationService: AnnotationService,
Expand Down Expand Up @@ -377,6 +379,10 @@ export class TableStudent extends ComponentStudent {
? studentData.selectedRowIndices
: [];

this.sortOrder = studentData.sortOrder ? studentData.sortOrder : [];

this.tabulatorSorters = studentData.tabulatorSorters ? studentData.tabulatorSorters : [];

this.processLatestStudentWork();
}
}
Expand All @@ -393,6 +399,8 @@ export class TableStudent extends ComponentStudent {
const studentData: any = {};
studentData.tableData = this.getCopyOfTableData(this.tableData);
studentData.selectedRowIndices = this.getSelectedRowIndices();
studentData.sortOrder = this.sortOrder;
studentData.tabulatorSorters = this.tabulatorSorters;
studentData.isDataExplorerEnabled = this.isDataExplorerEnabled;
studentData.dataExplorerGraphType = this.dataExplorerGraphType;
studentData.dataExplorerXAxisLabel = this.dataExplorerXAxisLabel;
Expand Down Expand Up @@ -1194,4 +1202,10 @@ export class TableStudent extends ComponentStudent {
private getSelectedRowIndices(): number[] {
return this.componentContent.enableRowSelection ? this.selectedRowIndices : [];
}

tabulatorRowSortChanged(sortData: any): void {
this.sortOrder = sortData.sortOrder;
this.tabulatorSorters = sortData.tabSorters;
this.studentDataChanged();
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,10 @@
background-color: #ffffff;
min-height: 44px; // temporary hack to fix height for some rows with empty cell values; TODO: investigate and fix
border-bottom: 1px solid #dddddd;

&.tabulator-frozen {
background-color: #ffffff;
}

&.tabulator-cell-editable {
&:before {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,8 +1,9 @@
import { SimpleChange } from '@angular/core';
import { NO_ERRORS_SCHEMA, SimpleChange } from '@angular/core';
import { ComponentFixture, TestBed } from '@angular/core/testing';
import { TabulatorTableComponent } from './tabulator-table.component';
import { Tabulator } from 'tabulator-tables';
import { TabulatorColumn } from '../TabulatorData';
import { StudentTeacherCommonServicesModule } from '../../../../../app/student-teacher-common-services.module';

let component: TabulatorTableComponent;
let fixture: ComponentFixture<TabulatorTableComponent>;
Expand All @@ -23,13 +24,18 @@ const tabData = [
{ 0: '12', 1: '', 2: '' }
];
const tabOptions = {
layout: "fitDataTable",
maxHeight: "500px",
reactiveData: true,
}
layout: 'fitDataTable',
maxHeight: '500px',
reactiveData: true
};

describe('TabulatorTableComponent', () => {
beforeEach(() => {
TestBed.configureTestingModule({
imports: [StudentTeacherCommonServicesModule],
declarations: [TabulatorTableComponent],
schemas: [NO_ERRORS_SCHEMA]
});
fixture = TestBed.createComponent(TabulatorTableComponent);
component = fixture.componentInstance;
component.tabColumns = tabColumns;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ import {
SelectRowModule,
SortModule
} from 'tabulator-tables';
import { UtilService } from '../../../services/utilService';
import { TabulatorColumn } from '../TabulatorData';

@Component({
Expand All @@ -38,17 +39,19 @@ export class TabulatorTableComponent implements OnChanges, AfterViewInit {
@Input() tabColumns: TabulatorColumn[]; // see http://tabulator.info/docs/5.3/columns
@Input() tabData: any[]; // see http://tabulator.info/docs/5.3/data
@Input() tabOptions: any; // see http://tabulator.info/docs/5.3/options
@Input() tabSorters: any; // see https://tabulator.info/docs/5.4/sort#intial
@Output() cellChanged = new EventEmitter<Tabulator.CellComponent>();
@Output() ready = new EventEmitter<void>();
@Output() rowSelectionChanged = new EventEmitter<Tabulator.RowComponent>();
@Output() rowSortChanged = new EventEmitter<{ sortOrder: number[]; tabSorters: [] }>();
@ViewChild('table', { static: false }) tableContainer: ElementRef;

table: Tabulator;
tableEl = document.createElement('div');
subscriptions: Subscription = new Subscription();
viewInit$ = new ReplaySubject();

constructor() {
constructor(protected UtilService: UtilService) {
Tabulator.registerModule([
EditModule,
FormatModule,
Expand All @@ -65,6 +68,7 @@ export class TabulatorTableComponent implements OnChanges, AfterViewInit {
this.tabOptions.columns = this.setupColumns(this.tabColumns);
this.initializeRowSelection();
this.tabOptions.data = this.tabData;
this.tabOptions.initialSort = this.UtilService.makeCopyOfJSONObject(this.tabSorters);
this.table = new Tabulator(this.tableEl, this.tabOptions);
this.table.on('cellEdited', (cell) => {
this.cellChanged.emit(cell);
Expand All @@ -73,6 +77,7 @@ export class TabulatorTableComponent implements OnChanges, AfterViewInit {
if (this.enableRowSelection) {
this.setupRowSelection();
}
this.setupSorting();
this.ready.emit();
});
this.tableContainer.nativeElement.appendChild(this.tableEl);
Expand Down Expand Up @@ -154,4 +159,29 @@ export class TabulatorTableComponent implements OnChanges, AfterViewInit {
this.rowSelectionChanged.emit(rows);
});
}

private setupSorting(): void {
this.table.on('dataSorted', (sorters, rows) => {
const prevRowIndices: number[] = [];
for (const row of rows) {
prevRowIndices.push(row.getIndex());
}
this.rowSortChanged.emit({
sortOrder: prevRowIndices,
tabSorters: this.sortersToJson(sorters)
});
});
}

private sortersToJson(sorters: any[]): any {
const sortersJson = [];
for (const sorter of sorters) {
sortersJson.push({
column: sorter.field,
dir: sorter.dir,
params: sorter.params
});
}
return sortersJson;
}
}
Loading

0 comments on commit f0f9517

Please sign in to comment.