Skip to content

Commit

Permalink
Externalizing Crossfilter specific behavior
Browse files Browse the repository at this point in the history
  • Loading branch information
kum-deepak committed Mar 31, 2024
1 parent ee9dd26 commit 618dc0a
Show file tree
Hide file tree
Showing 7 changed files with 81 additions and 45 deletions.
11 changes: 9 additions & 2 deletions spec/pie-chart-spec.js
Original file line number Diff line number Diff line change
Expand Up @@ -384,6 +384,13 @@ describe('dc.pieChart', () => {
});
describe('comparing crossfilter and chart ordering', () => {
let crossfilterOrder, crossfilterTop2;
const prepData = raw => {
return raw.map(g => {
delete g._value;
return g
});
};

beforeEach(() => {
countryChart = buildCountryChart('country-chart');
countryChart.innerRadius(innerRadius);
Expand All @@ -398,15 +405,15 @@ describe('dc.pieChart', () => {
});
describe('with ordering and capping not set', () => {
it('should match the crossfilter top 2', () => {
expect(countryChart.data()).toEqual(crossfilterTop2);
expect(prepData(countryChart.data())).toEqual(crossfilterTop2);
});
});
describe('with ordering by key', () => {
beforeEach(() => {
countryChart.ordering(kv => kv.key).redraw();
});
it('should should match crossfilter top(2)', () => {
expect(countryChart.data()).toEqual(crossfilterOrder);
expect(prepData(countryChart.data())).toEqual(crossfilterOrder);
});
describe('with cap(1)', () => {
beforeEach(() => {
Expand Down
37 changes: 5 additions & 32 deletions src/data/c-f-filter-handler.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
import { MinimalCFDimension } from '../core/types.js';
import { FilterStorageHelper, IFilterStorageConf } from './filter-storage-helper.js';
import { cfHelper } from './cf-helper.js';
import { ICFHelper } from './i-c-f-helper.js';

export interface ICFFilterHandlerConf extends IFilterStorageConf {
dimension?: MinimalCFDimension;
Expand All @@ -8,6 +10,7 @@ export interface ICFFilterHandlerConf extends IFilterStorageConf {

export class CFFilterHandler extends FilterStorageHelper {
protected _conf: ICFFilterHandlerConf;
protected helper: ICFHelper = cfHelper;

constructor(conf: ICFFilterHandlerConf = {}) {
super({
Expand All @@ -24,40 +27,10 @@ export class CFFilterHandler extends FilterStorageHelper {
}

protected _storageKey(): any {
if (this._conf.shareFilters) {
return this._conf.dimension;
} else {
return this;
}
return this.helper.storageKey(this);
}

public applyFilters() {
if (!(this._conf.dimension && this._conf.dimension.filter)) {
return;
}

if (this.filters.length === 0) {
this._conf.dimension.filter(null);
} else if (this.filters.length === 1 && !this.filters[0].isFiltered) {
// single value and not a function-based filter
this._conf.dimension.filterExact(this.filters[0]);
} else if (this.filters.length === 1 && this.filters[0].filterType === 'RangedFilter') {
// single range-based filter
this._conf.dimension.filterRange(this.filters[0]);
} else {
this._conf.dimension.filterFunction(d => {
for (let i = 0; i < this.filters.length; i++) {
const filter = this.filters[i];
if (filter.isFiltered) {
if (filter.isFiltered(d)) {
return true;
}
} else if (filter <= d && filter >= d) {
return true;
}
}
return false;
});
}
this.helper.applyFilters(this._conf.dimension, this.filters);
}
}
3 changes: 1 addition & 2 deletions src/data/c-f-multi-adapter.ts
Original file line number Diff line number Diff line change
Expand Up @@ -35,8 +35,7 @@ export class CFMultiAdapter extends CFSimpleAdapter {
// Two level defensive copy
return this.layers().map(layer => {
const valueAccessor = layer.valueAccessor || this._conf.valueAccessor;
// Two level defensive copy
const rawData = layer.group.all().map(val => ({ ...val, _value: valueAccessor(val) }));
const rawData = this._getData(this._conf.dimension, layer.group, valueAccessor);

return { name: layer.name, rawData };
});
Expand Down
20 changes: 11 additions & 9 deletions src/data/c-f-simple-adapter.ts
Original file line number Diff line number Diff line change
Expand Up @@ -29,15 +29,17 @@ export class CFSimpleAdapter extends CFFilterHandler {

// TODO: better typing
public data(): any {
const entities = this._conf.group.all();

// create a two level deep copy defensively
entities.map(val => ({ ...val }));

entities.forEach(e => {
e._value = this._conf.valueAccessor(e);
});
return this._getData(this._conf.dimension, this._conf.group, this._conf.valueAccessor);
}

return entities;
protected _getData(
dimension: any,
group: MinimalCFGroup,
valueAccessor: (d: any, i?: number) => any
) {
// create a two-level deep copy defensively
return this.helper
.getGroupings(dimension, group)
.map(grp => ({ ...grp, _value: valueAccessor(grp) }));
}
}
46 changes: 46 additions & 0 deletions src/data/cf-helper.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
import { MinimalCFDimension, MinimalCFGroup } from '../core/index.js';
import { ICFHelper } from './i-c-f-helper.js';

export const cfHelper: ICFHelper = {
applyFilters: (dimension: MinimalCFDimension, filters: any[]) => {
if (!(dimension && dimension.filter)) {
return;
}
if (filters.length === 0) {
dimension.filter(null);
} else if (filters.length === 1 && !filters[0].isFiltered) {
// single value and not a function-based filter
dimension.filterExact(filters[0]);
} else if (filters.length === 1 && filters[0].filterType === 'RangedFilter') {
// single range-based filter
dimension.filterRange(filters[0]);
} else {
dimension.filterFunction(d => {
for (let i = 0; i < filters.length; i++) {
const filter = filters[i];
if (filter.isFiltered) {
if (filter.isFiltered(d)) {
return true;
}
} else if (filter <= d && filter >= d) {
return true;
}
}
return false;
});
}
},

storageKey: (provider: any) => {
const { shareFilters, dimension } = provider.conf();
if (shareFilters) {
return dimension;
} else {
return provider;
}
},

getGroupings: (dimension: any, group: MinimalCFGroup) => {
return group.all();
},
};
7 changes: 7 additions & 0 deletions src/data/i-c-f-helper.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
import { CFGrouping, MinimalCFDimension, MinimalCFGroup } from '../core/index.js';

export interface ICFHelper {
applyFilters(dimension: MinimalCFDimension, filters: any[]): void;
storageKey(provider: any): any;
getGroupings(dimension: any, group: MinimalCFGroup): ReadonlyArray<CFGrouping>;
}
2 changes: 2 additions & 0 deletions src/data/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,3 +4,5 @@ export * from './c-f-multi-adapter.js';
export * from './c-f-simple-adapter.js';
export * from './filter-handler.js';
export * from './filter-storage-helper.js';
export * from './i-c-f-helper.js';
export * from './cf-helper.js';

0 comments on commit 618dc0a

Please sign in to comment.