Skip to content

Commit

Permalink
start with rank filter
Browse files Browse the repository at this point in the history
  • Loading branch information
sgratzl committed Nov 20, 2018
1 parent 683891a commit b8c55ab
Show file tree
Hide file tree
Showing 4 changed files with 121 additions and 8 deletions.
17 changes: 17 additions & 0 deletions src/model/Column.ts
Original file line number Diff line number Diff line change
Expand Up @@ -570,6 +570,23 @@ export default class Column extends AEventDispatcher {
return row != null;
}

/**
* flag whether any filter is applied after sorting
* @return {boolean}
*/
isFilteredRank() {
return false;
}

/**
* predicate whether the current row should be included
* @param row
* @return {boolean}
*/
filterRank(row: IDataRow, _relativeRank: number, _rank: number, _group: IGroup) {
return row != null;
}

/**
* determines the renderer type that should be used to render this column. By default the same type as the column itself
* @return {string}
Expand Down
76 changes: 73 additions & 3 deletions src/model/RankColumn.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
import {IDataRow} from './interfaces';
import {Category, SupportType} from './annotations';
import Column, {IColumnDesc} from './Column';
import {Category, SupportType, toolbar} from './annotations';
import Column, {widthChanged, labelChanged, metaDataChanged, dirty, dirtyHeader, dirtyValues, rendererTypeChanged, groupRendererChanged, summaryRendererChanged, visibilityChanged} from './Column';
import {IEventListener} from '../internal/AEventDispatcher';
import {IDataRow, IColumnDesc} from './interfaces';


/**
* factory for creating a description creating a rank column
Expand All @@ -11,12 +13,23 @@ export function createRankDesc(label: string = 'Rank') {
return {type: 'rank', label};
}

/**
* emitted when the filter property changes
* @asMemberOf StringColumn
* @event
*/
export declare function filterChanged(previous: string | RegExp | null, current: string | RegExp | null): void;
/**
* a rank column
*/
@SupportType()
@toolbar('filterRank')
@Category('support')
export default class RankColumn extends Column {
static readonly EVENT_FILTER_CHANGED = 'filterChanged';


private currentFilter = -1;

constructor(id: string, desc: IColumnDesc) {
super(id, desc);
Expand Down Expand Up @@ -52,4 +65,61 @@ export default class RankColumn extends Column {
get frozen() {
return this.desc.frozen !== false;
}

dump(toDescRef: (desc: any) => any): any {
const r = super.dump(toDescRef);
if (this.currentFilter > 0) {
r.filter = this.currentFilter;
}
return r;
}

restore(dump: any, factory: (dump: any) => Column | null) {
super.restore(dump, factory);
if (dump.filter) {
this.currentFilter = dump.filter;
}
}

filterRank(_row: IDataRow, relativeRank: number) {
if (this.currentFilter === -1) {
return true;
}
return relativeRank < this.currentFilter;
}

getFilter() {
return this.currentFilter;
}

setFilter(filter: number | null) {
if (filter === null) {
filter = -1;
}
if (this.currentFilter === filter) {
return;
}
this.fire([RankColumn.EVENT_FILTER_CHANGED, Column.EVENT_DIRTY_VALUES, Column.EVENT_DIRTY], this.currentFilter, this.currentFilter = filter);
}

protected createEventList() {
return super.createEventList().concat([RankColumn.EVENT_FILTER_CHANGED]);
}

on(type: typeof RankColumn.EVENT_FILTER_CHANGED, listener: typeof filterChanged | null): this;
on(type: typeof Column.EVENT_WIDTH_CHANGED, listener: typeof widthChanged | null): this;
on(type: typeof Column.EVENT_LABEL_CHANGED, listener: typeof labelChanged | null): this;
on(type: typeof Column.EVENT_METADATA_CHANGED, listener: typeof metaDataChanged | null): this;
on(type: typeof Column.EVENT_DIRTY, listener: typeof dirty | null): this;
on(type: typeof Column.EVENT_DIRTY_HEADER, listener: typeof dirtyHeader | null): this;
on(type: typeof Column.EVENT_DIRTY_VALUES, listener: typeof dirtyValues | null): this;
on(type: typeof Column.EVENT_RENDERER_TYPE_CHANGED, listener: typeof rendererTypeChanged | null): this;
on(type: typeof Column.EVENT_GROUP_RENDERER_TYPE_CHANGED, listener: typeof groupRendererChanged | null): this;
on(type: typeof Column.EVENT_SUMMARY_RENDERER_TYPE_CHANGED, listener: typeof summaryRendererChanged | null): this;
on(type: typeof Column.EVENT_VISIBILITY_CHANGED, listener: typeof visibilityChanged | null): this;
on(type: string | string[], listener: IEventListener | null): this {
return super.on(<any>type, listener);
}


}
8 changes: 8 additions & 0 deletions src/model/Ranking.ts
Original file line number Diff line number Diff line change
Expand Up @@ -691,6 +691,14 @@ export default class Ranking extends AEventDispatcher implements IColumnParent {
return this.columns.every((d) => d.filter(row));
}

isFilteredRank() {
return this.columns.some((d) => d.isFilteredRank());
}

filterRank(row: IDataRow, rank: number, relativeRank: number, group: IGroup) {
return this.columns.every((d) => d.filterRank(row, rank, relativeRank, group));
}

findMyRanker() {
return this;
}
Expand Down
28 changes: 23 additions & 5 deletions src/provider/LocalDataProvider.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ import Column, {
import Ranking from '../model/Ranking';
import ACommonDataProvider from './ACommonDataProvider';
import {IDataProviderOptions, IStatsBuilder} from './interfaces';
import {ISortWorker, sortComplex, chooseByLength, WorkerSortWorker, normalizeCompareValues} from './sort';
import {ISortWorker, sortComplex, chooseByLength, local, normalizeCompareValues} from './sort';
import {range} from 'd3-array';
import ADataProvider from './ADataProvider';

Expand Down Expand Up @@ -49,7 +49,7 @@ export default class LocalDataProvider extends ACommonDataProvider {

private _dataRows: IDataRow[];
private filter: ((row: IDataRow) => boolean) | null = null;
private sortWorker: ISortWorker = new WorkerSortWorker();
private sortWorker: ISortWorker = local; // new WorkerSortWorker();

constructor(private _data: any[], columns: IColumnDesc[] = [], options: Partial<ILocalDataProviderOptions & IDataProviderOptions> = {}) {
super(columns, options);
Expand Down Expand Up @@ -146,13 +146,28 @@ export default class LocalDataProvider extends ACommonDataProvider {
}
//do the optional filtering step
let filter: ((d: IDataRow) => boolean) | null = null;
let rankFilter: ((d: IDataRow, rank: number, relativeRank: number, group: IGroup) => boolean) | null = null;

if (this.options.filterGlobally) {
const filtered = this.getRankings().filter((d) => d.isFiltered());
if (filtered.length > 0) {
if (filtered.length === 1) {
rankFilter = filtered[0].filter.bind(filtered[0]);
} else if (filtered.length > 1) {
filter = (d: IDataRow) => filtered.every((f) => f.filter(d));
}
} else if (ranking.isFiltered()) {
filter = (d) => ranking.filter(d);
const filteredRank = this.getRankings().filter((d) => d.isFilteredRank());
if (filteredRank.length === 1) {
rankFilter = filteredRank[0].filterRank.bind(filteredRank[0]);
} else if (filteredRank.length > 1) {
rankFilter = (d: IDataRow, rank: number, relativeRank: number, group: IGroup) => filteredRank.every((f) => f.filterRank(d, rank, relativeRank, group));
}
} else {
if (ranking.isFiltered()) {
filter = ranking.filter.bind(ranking);
}
if (ranking.isFilteredRank()) {
rankFilter = ranking.filterRank.bind(ranking);
}
}

if (this.filter) {
Expand All @@ -170,6 +185,7 @@ export default class LocalDataProvider extends ACommonDataProvider {
const order = chooseByLength(this._data.length);
order.set(range(this._data.length));
const index2pos = order.slice();
// TODO rank filter
return [Object.assign({order, index2pos}, defaultGroup)];
}

Expand Down Expand Up @@ -220,6 +236,8 @@ export default class LocalDataProvider extends ACommonDataProvider {
groupHelper.sort((a, b) => a.o.name.toLowerCase().localeCompare(b.o.name.toLowerCase()));
}

// TODO rank fiter

return groupHelper.map((d) => d.o);
});
}
Expand Down

0 comments on commit b8c55ab

Please sign in to comment.