Skip to content

Commit

Permalink
inplace last sorting backup criteria
Browse files Browse the repository at this point in the history
  • Loading branch information
sgratzl committed Dec 1, 2018
1 parent c6e3aa7 commit 53f8891
Show file tree
Hide file tree
Showing 4 changed files with 119 additions and 85 deletions.
115 changes: 72 additions & 43 deletions demo/big.html
Original file line number Diff line number Diff line change
@@ -1,59 +1,88 @@
<!DOCTYPE html>
<html>

<head lang="en">
<meta charset="UTF-8">
<title>LineUp Taggle Test</title>

<link href="./LineUpJS.css" rel="stylesheet">
<link href="./demo.css" rel="stylesheet">
</head>

<body>
<script src="https://d3js.org/d3.v4.min.js"></script>
<script src="./LineUpJS.js"></script>

<script>
window.onload = function () {
const arr = [];
const cats = ['c1', 'c2', 'c3'];
for (let i = 0; i < 500000; ++i) {
arr.push({
a: Math.random() *10,
d: 'Row ' + i,
cat: cats[Math.floor(Math.random() * 3)],
cat2: cats[Math.floor(Math.random() * 3)]
})
}
const desc = [
{label: 'D', type: 'string', column: 'd'},
{label: 'A', type: 'number', column: 'a', 'domain': [0, 10]},
{
label: 'Cat',
type: 'categorical',
column: 'cat',
categories: ['c1', 'c2', 'c3']
},
{
label: 'Cat Label',
type: 'categorical',
column: 'cat2',
categories: [{name: 'c1', label: 'C1', color: 'green'}, {name: 'c2', label: 'C2', color: 'blue'}, {
name: 'c3',
label: 'C3',
color: 'red'
}]
<script src="https://d3js.org/d3.v4.min.js"></script>
<script src="./LineUpJS.js"></script>

<script>
window.onload = function () {
const arr = [];
const cats = ['c1', 'c2', 'c3'];
for (let i = 0; i < 500000; ++i) {
arr.push({
a: Math.random() * 10,
d: 'Row ' + i,
cat: cats[Math.floor(Math.random() * 3)],
cat2: cats[Math.floor(Math.random() * 3)]
})
}
];
console.log('generated');
const desc = [{
label: 'D',
type: 'string',
column: 'd'
},
{
label: 'A',
type: 'number',
column: 'a',
'domain': [0, 10]
},
{
label: 'Cat',
type: 'categorical',
column: 'cat',
categories: ['c1', 'c2', 'c3']
},
{
label: 'Cat Label',
type: 'categorical',
column: 'cat2',
categories: [{
name: 'c1',
label: 'C1',
color: 'green'
}, {
name: 'c2',
label: 'C2',
color: 'blue'
}, {
name: 'c3',
label: 'C3',
color: 'red'
}]
}
];

const p = new LineUpJS.LocalDataProvider(arr, desc, { grouping: true});
p.deriveDefault();
p.getLastRanking().insert(p.create({ type: 'selection', label: 'S'}), 0);
p.getLastRanking().insert(p.create({ type: 'aggregate', label: 'A'}), 0);
p.getLastRanking().push(p.create(desc[1]));
const p = new LineUpJS.LocalDataProvider(arr, desc, {
grouping: true
});
p.deriveDefault();
p.getLastRanking().insert(p.create({
type: 'selection',
label: 'S'
}), 0);
p.getLastRanking().insert(p.create({
type: 'aggregate',
label: 'A'
}), 0);
p.getLastRanking().push(p.create(desc[1]));

const instance = new LineUpJS.Taggle(document.body, p);
instance.update();
};
</script>
const instance = new LineUpJS.Taggle(document.body, p);
instance.update();
};

</script>

</body>

</html>
28 changes: 13 additions & 15 deletions src/model/Ranking.ts
Original file line number Diff line number Diff line change
Expand Up @@ -245,7 +245,7 @@ export default class Ranking extends AEventDispatcher implements IColumnParent {
}

const restoreSortCriteria = (dumped: any) => {
return dumped.map((s: { asc: boolean, sortBy: string }) => {
return dumped.map((s: {asc: boolean, sortBy: string}) => {
return {
asc: s.asc,
col: this.columns.find((d) => d.id === s.sortBy) || null
Expand All @@ -265,9 +265,9 @@ export default class Ranking extends AEventDispatcher implements IColumnParent {

toCompareValue(row: IDataRow) {
if (this.sortCriteria.length === 0) {
return [row.i];
return [];
}
const vs : ICompareValue[] = [];
const vs: ICompareValue[] = [];
for (const s of this.sortCriteria) {
const r = s.col.toCompareValue(row);
if (Array.isArray(r)) {
Expand All @@ -276,12 +276,11 @@ export default class Ranking extends AEventDispatcher implements IColumnParent {
vs.push(r);
}
}
vs.push(row.i);
return vs;
}

toCompareValueType() {
const vs : {asc: boolean, v: ECompareValueType}[] = [];
const vs: {asc: boolean, v: ECompareValueType}[] = [];
for (const s of this.sortCriteria) {
const types = s.col.toCompareValueType();
if (!Array.isArray(types)) {
Expand All @@ -292,15 +291,14 @@ export default class Ranking extends AEventDispatcher implements IColumnParent {
vs.push({asc: s.asc, v});
}
}
vs.push({asc: true, v: ECompareValueType.UINT});
return vs;
}

toGroupCompareValue(group: IGroupData) {
if (this.groupSortCriteria.length === 0) {
return [group.name.toLowerCase()];
}
const vs : ICompareValue[] = [];
const vs: ICompareValue[] = [];
for (const s of this.groupSortCriteria) {
const r = s.col.toCompareGroupValue(group);
if (Array.isArray(r)) {
Expand All @@ -314,7 +312,7 @@ export default class Ranking extends AEventDispatcher implements IColumnParent {
}

toGroupCompareValueType() {
const vs : {asc: boolean, v: ECompareValueType}[] = [];
const vs: {asc: boolean, v: ECompareValueType}[] = [];
for (const s of this.groupSortCriteria) {
const types = s.col.toCompareGroupValueType();
if (!Array.isArray(types)) {
Expand Down Expand Up @@ -463,7 +461,7 @@ export default class Ranking extends AEventDispatcher implements IColumnParent {
return true;
}

setGroupCriteria(column: Column[]|Column) {
setGroupCriteria(column: Column[] | Column) {
const cols = Array.isArray(column) ? column : [column];

if (equalArrays(this.groupColumns, cols)) {
Expand All @@ -481,7 +479,7 @@ export default class Ranking extends AEventDispatcher implements IColumnParent {
});

this.fire([Ranking.EVENT_GROUP_CRITERIA_CHANGED, Ranking.EVENT_DIRTY_ORDER, Ranking.EVENT_DIRTY_HEADER,
Ranking.EVENT_DIRTY_VALUES, Ranking.EVENT_DIRTY_CACHES, Ranking.EVENT_DIRTY], bak, this.getGroupCriteria());
Ranking.EVENT_DIRTY_VALUES, Ranking.EVENT_DIRTY_CACHES, Ranking.EVENT_DIRTY], bak, this.getGroupCriteria());
return true;
}

Expand Down Expand Up @@ -513,14 +511,14 @@ export default class Ranking extends AEventDispatcher implements IColumnParent {
const sortCriterias = this.getGroupSortCriteria();
const bakMulti = Array.isArray(bak) ? bak : sortCriterias;
this.fire([Ranking.EVENT_GROUP_SORT_CRITERIA_CHANGED, Ranking.EVENT_DIRTY_ORDER, Ranking.EVENT_DIRTY_HEADER,
Ranking.EVENT_DIRTY_VALUES, Ranking.EVENT_DIRTY], bakMulti, sortCriterias);
Ranking.EVENT_DIRTY_VALUES, Ranking.EVENT_DIRTY], bakMulti, sortCriterias);
}

private triggerResort(bak: ISortCriteria | ISortCriteria[] | null) {
const sortCriterias = this.getSortCriteria();
const bakMulti = Array.isArray(bak) ? bak : sortCriterias;
this.fire([Ranking.EVENT_SORT_CRITERIA_CHANGED, Ranking.EVENT_DIRTY_ORDER, Ranking.EVENT_DIRTY_HEADER,
Ranking.EVENT_DIRTY_VALUES, Ranking.EVENT_DIRTY], bakMulti, sortCriterias);
Ranking.EVENT_DIRTY_VALUES, Ranking.EVENT_DIRTY], bakMulti, sortCriterias);
}

get children() {
Expand Down Expand Up @@ -624,7 +622,7 @@ export default class Ranking extends AEventDispatcher implements IColumnParent {
this.groupSortCriteria.splice(isGroupSortCriteria, 1);
}

let newGrouping: Column[]|null = null;
let newGrouping: Column[] | null = null;
const isGroupColumn = this.groupColumns.indexOf(col);
if (isGroupColumn >= 0) { // was my grouping criteria
newGrouping = this.groupColumns.slice();
Expand Down Expand Up @@ -680,7 +678,7 @@ export default class Ranking extends AEventDispatcher implements IColumnParent {
}

find(idOrFilter: string | ((col: Column) => boolean)) {
const filter = typeof(idOrFilter) === 'string' ? (col: Column) => col.id === idOrFilter : idOrFilter;
const filter = typeof (idOrFilter) === 'string' ? (col: Column) => col.id === idOrFilter : idOrFilter;
const r = this.flatColumns;
for (const v of r) {
if (filter(v)) {
Expand Down Expand Up @@ -747,5 +745,5 @@ function toOrder(groups: IOrderedGroup[]) {
shift += g.order.length;
}
return r;
}
}
}
26 changes: 13 additions & 13 deletions src/provider/LocalDataProvider.ts
Original file line number Diff line number Diff line change
Expand Up @@ -202,26 +202,26 @@ export default class LocalDataProvider extends ACommonDataProvider {
}


return Promise.all(Array.from(groups.values()).map((g) => {
return Promise.all(Array.from(groups.values()).map((g, i) => {
const group = g.group;
return this.sortWorker.sort(this._data.length, g.rows, types)
// to group info
.then(({order, index2pos}) => {
const o: IOrderedGroup = Object.assign({order, index2pos}, group);

// compute sort group value
let sort: ICompareValue[] | null = null;
if (isGroupedSortedBy) {
const groupData = Object.assign({rows: lazySeq(order).map((d) => this._dataRows[d]), meta: <IGroupMeta>'first last'}, group);
sort = ranking.toGroupCompareValue(groupData);
}
return {o, sort};
});
const o: IOrderedGroup = Object.assign({order, index2pos}, group);

// compute sort group value
let sort: ICompareValue[] | null = null;
if (isGroupedSortedBy) {
const groupData = Object.assign({rows: lazySeq(order).map((d) => this._dataRows[d]), meta: <IGroupMeta>'first last'}, group);
sort = ranking.toGroupCompareValue(groupData);
}
return {o, sort, i};
});
})).then((groupHelper) => {

// sort groups
if (isGroupedSortedBy) {
sortComplex(<{sort: ICompareValue[]}[]>groupHelper, ranking.toGroupCompareValueType());
sortComplex(<{sort: ICompareValue[], i: number}[]>groupHelper, ranking.toGroupCompareValueType());
} else {
groupHelper.sort((a, b) => a.o.name.toLowerCase().localeCompare(b.o.name.toLowerCase()));
}
Expand All @@ -242,7 +242,7 @@ export default class LocalDataProvider extends ACommonDataProvider {

private seqRawRows(indices: IndicesArray) {
if (indices.length < 10000) { // small copy
return mapIndices(indices, (i) => this._dataRows[i]);
return mapIndices(indices, (i) => this._dataRows[i]);
}
// what about filter invalid indices
return lazySeq(indices).map((i) => this._dataRows[i]);
Expand Down
35 changes: 21 additions & 14 deletions src/provider/sort.ts
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@ const missingString = FIRST_IS_MISSING > 0 ? '\uffff' : '\u0000'; // first or la
export function normalizeCompareValues(vs: ICompareValue[], comparators: {asc: boolean, v: ECompareValueType}[]) {
return comparators.map((d, i) => {
const v = vs[i];
switch(d.v) {
switch (d.v) {
case ECompareValueType.BINARY:
case ECompareValueType.UINT:
return v == null || isNaN(<number>v) ? missingInt : v;
Expand All @@ -43,37 +43,44 @@ export function normalizeCompareValues(vs: ICompareValue[], comparators: {asc: b
});
}

export function sortComplex<T extends {sort: ICompareValue[]}>(arr: T[], comparators: {asc: boolean, v: ECompareValueType}[]) {
export function sortComplex<T extends {sort: ICompareValue[], i: number}>(arr: T[], comparators: {asc: boolean, v: ECompareValueType}[]) {
if (arr.length < 2 || comparators.length === 0) {
return arr;
}

const comp = (asc: boolean, a: any, b: any) => {
const smaller = asc ? 1 : -1;
return a < b ? smaller : ((a > b) ? -smaller : 0);
const asc = (a: any, b: any) => {
return a < b ? 1 : ((a > b) ? -1 : 0);
};
const desc = (a: any, b: any) => {
return a < b ? -1 : ((a > b) ? 1 : 0);
};

switch(comparators.length) {
switch (comparators.length) {
case 1:
const f = comparators[0]!.asc;
return arr.sort((a, b) => comp(f, a.sort[0], b.sort[0]));
const f = comparators[0]!.asc ? asc : desc;
return arr.sort((a, b) => {
const r = f(a.sort[0], b.sort[0]);
return r !== 0 ? r : a.i - b.i;
});
case 2:
const f1 = comparators[0]!.asc;
const f2 = comparators[0]!.asc;
const f1 = comparators[0]!.asc ? asc : desc;
const f2 = comparators[0]!.asc ? asc : desc;
return arr.sort((a, b) => {
const r = comp(f1, a.sort[0], b.sort[0]);
return r !== 0 ? r : comp(f2, a.sort[1], b.sort[1]);
let r = f1(a.sort[0], b.sort[0]);
r = r !== 0 ? r : f2(a.sort[1], b.sort[1]);
return r !== 0 ? r : a.i - b.i;
});
default:
const l = comparators.length;
const fs = comparators.map((d) => d.asc ? asc : desc);
return arr.sort((a, b) => {
for (let i = 0; i < l; ++i) {
const r = comp(comparators[i].asc, a.sort[i], b.sort[i]);
const r = fs[i](a.sort[i], b.sort[i]);
if (r !== 0) {
return r;
}
}
return 0;
return a.i - b.i;
});
}
}
Expand Down

0 comments on commit 53f8891

Please sign in to comment.