Skip to content

Commit 618dc0a

Browse files
committed
Externalizing Crossfilter specific behavior
1 parent ee9dd26 commit 618dc0a

7 files changed

+81
-45
lines changed

spec/pie-chart-spec.js

+9-2
Original file line numberDiff line numberDiff line change
@@ -384,6 +384,13 @@ describe('dc.pieChart', () => {
384384
});
385385
describe('comparing crossfilter and chart ordering', () => {
386386
let crossfilterOrder, crossfilterTop2;
387+
const prepData = raw => {
388+
return raw.map(g => {
389+
delete g._value;
390+
return g
391+
});
392+
};
393+
387394
beforeEach(() => {
388395
countryChart = buildCountryChart('country-chart');
389396
countryChart.innerRadius(innerRadius);
@@ -398,15 +405,15 @@ describe('dc.pieChart', () => {
398405
});
399406
describe('with ordering and capping not set', () => {
400407
it('should match the crossfilter top 2', () => {
401-
expect(countryChart.data()).toEqual(crossfilterTop2);
408+
expect(prepData(countryChart.data())).toEqual(crossfilterTop2);
402409
});
403410
});
404411
describe('with ordering by key', () => {
405412
beforeEach(() => {
406413
countryChart.ordering(kv => kv.key).redraw();
407414
});
408415
it('should should match crossfilter top(2)', () => {
409-
expect(countryChart.data()).toEqual(crossfilterOrder);
416+
expect(prepData(countryChart.data())).toEqual(crossfilterOrder);
410417
});
411418
describe('with cap(1)', () => {
412419
beforeEach(() => {

src/data/c-f-filter-handler.ts

+5-32
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,7 @@
11
import { MinimalCFDimension } from '../core/types.js';
22
import { FilterStorageHelper, IFilterStorageConf } from './filter-storage-helper.js';
3+
import { cfHelper } from './cf-helper.js';
4+
import { ICFHelper } from './i-c-f-helper.js';
35

46
export interface ICFFilterHandlerConf extends IFilterStorageConf {
57
dimension?: MinimalCFDimension;
@@ -8,6 +10,7 @@ export interface ICFFilterHandlerConf extends IFilterStorageConf {
810

911
export class CFFilterHandler extends FilterStorageHelper {
1012
protected _conf: ICFFilterHandlerConf;
13+
protected helper: ICFHelper = cfHelper;
1114

1215
constructor(conf: ICFFilterHandlerConf = {}) {
1316
super({
@@ -24,40 +27,10 @@ export class CFFilterHandler extends FilterStorageHelper {
2427
}
2528

2629
protected _storageKey(): any {
27-
if (this._conf.shareFilters) {
28-
return this._conf.dimension;
29-
} else {
30-
return this;
31-
}
30+
return this.helper.storageKey(this);
3231
}
3332

3433
public applyFilters() {
35-
if (!(this._conf.dimension && this._conf.dimension.filter)) {
36-
return;
37-
}
38-
39-
if (this.filters.length === 0) {
40-
this._conf.dimension.filter(null);
41-
} else if (this.filters.length === 1 && !this.filters[0].isFiltered) {
42-
// single value and not a function-based filter
43-
this._conf.dimension.filterExact(this.filters[0]);
44-
} else if (this.filters.length === 1 && this.filters[0].filterType === 'RangedFilter') {
45-
// single range-based filter
46-
this._conf.dimension.filterRange(this.filters[0]);
47-
} else {
48-
this._conf.dimension.filterFunction(d => {
49-
for (let i = 0; i < this.filters.length; i++) {
50-
const filter = this.filters[i];
51-
if (filter.isFiltered) {
52-
if (filter.isFiltered(d)) {
53-
return true;
54-
}
55-
} else if (filter <= d && filter >= d) {
56-
return true;
57-
}
58-
}
59-
return false;
60-
});
61-
}
34+
this.helper.applyFilters(this._conf.dimension, this.filters);
6235
}
6336
}

src/data/c-f-multi-adapter.ts

+1-2
Original file line numberDiff line numberDiff line change
@@ -35,8 +35,7 @@ export class CFMultiAdapter extends CFSimpleAdapter {
3535
// Two level defensive copy
3636
return this.layers().map(layer => {
3737
const valueAccessor = layer.valueAccessor || this._conf.valueAccessor;
38-
// Two level defensive copy
39-
const rawData = layer.group.all().map(val => ({ ...val, _value: valueAccessor(val) }));
38+
const rawData = this._getData(this._conf.dimension, layer.group, valueAccessor);
4039

4140
return { name: layer.name, rawData };
4241
});

src/data/c-f-simple-adapter.ts

+11-9
Original file line numberDiff line numberDiff line change
@@ -29,15 +29,17 @@ export class CFSimpleAdapter extends CFFilterHandler {
2929

3030
// TODO: better typing
3131
public data(): any {
32-
const entities = this._conf.group.all();
33-
34-
// create a two level deep copy defensively
35-
entities.map(val => ({ ...val }));
36-
37-
entities.forEach(e => {
38-
e._value = this._conf.valueAccessor(e);
39-
});
32+
return this._getData(this._conf.dimension, this._conf.group, this._conf.valueAccessor);
33+
}
4034

41-
return entities;
35+
protected _getData(
36+
dimension: any,
37+
group: MinimalCFGroup,
38+
valueAccessor: (d: any, i?: number) => any
39+
) {
40+
// create a two-level deep copy defensively
41+
return this.helper
42+
.getGroupings(dimension, group)
43+
.map(grp => ({ ...grp, _value: valueAccessor(grp) }));
4244
}
4345
}

src/data/cf-helper.ts

+46
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,46 @@
1+
import { MinimalCFDimension, MinimalCFGroup } from '../core/index.js';
2+
import { ICFHelper } from './i-c-f-helper.js';
3+
4+
export const cfHelper: ICFHelper = {
5+
applyFilters: (dimension: MinimalCFDimension, filters: any[]) => {
6+
if (!(dimension && dimension.filter)) {
7+
return;
8+
}
9+
if (filters.length === 0) {
10+
dimension.filter(null);
11+
} else if (filters.length === 1 && !filters[0].isFiltered) {
12+
// single value and not a function-based filter
13+
dimension.filterExact(filters[0]);
14+
} else if (filters.length === 1 && filters[0].filterType === 'RangedFilter') {
15+
// single range-based filter
16+
dimension.filterRange(filters[0]);
17+
} else {
18+
dimension.filterFunction(d => {
19+
for (let i = 0; i < filters.length; i++) {
20+
const filter = filters[i];
21+
if (filter.isFiltered) {
22+
if (filter.isFiltered(d)) {
23+
return true;
24+
}
25+
} else if (filter <= d && filter >= d) {
26+
return true;
27+
}
28+
}
29+
return false;
30+
});
31+
}
32+
},
33+
34+
storageKey: (provider: any) => {
35+
const { shareFilters, dimension } = provider.conf();
36+
if (shareFilters) {
37+
return dimension;
38+
} else {
39+
return provider;
40+
}
41+
},
42+
43+
getGroupings: (dimension: any, group: MinimalCFGroup) => {
44+
return group.all();
45+
},
46+
};

src/data/i-c-f-helper.ts

+7
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
import { CFGrouping, MinimalCFDimension, MinimalCFGroup } from '../core/index.js';
2+
3+
export interface ICFHelper {
4+
applyFilters(dimension: MinimalCFDimension, filters: any[]): void;
5+
storageKey(provider: any): any;
6+
getGroupings(dimension: any, group: MinimalCFGroup): ReadonlyArray<CFGrouping>;
7+
}

src/data/index.ts

+2
Original file line numberDiff line numberDiff line change
@@ -4,3 +4,5 @@ export * from './c-f-multi-adapter.js';
44
export * from './c-f-simple-adapter.js';
55
export * from './filter-handler.js';
66
export * from './filter-storage-helper.js';
7+
export * from './i-c-f-helper.js';
8+
export * from './cf-helper.js';

0 commit comments

Comments
 (0)