vega-util
Version:
JavaScript utilities for Vega.
52 lines (42 loc) • 1.48 kB
JavaScript
import {default as accessor, accessorFields} from './accessor.js';
import array from './array.js';
import field from './field.js';
import isFunction from './isFunction.js';
const DESCENDING = 'descending';
export default function(fields, orders, opt) {
opt = opt || {};
orders = array(orders) || [];
const ord = [], get = [], fmap = {},
gen = opt.comparator || comparator;
array(fields).forEach((f, i) => {
if (f == null) return;
ord.push(orders[i] === DESCENDING ? -1 : 1);
get.push(f = isFunction(f) ? f : field(f, null, opt));
(accessorFields(f) || []).forEach(_ => fmap[_] = 1);
});
return get.length === 0
? null
: accessor(gen(get, ord), Object.keys(fmap));
}
export const ascending = (u, v) => (u < v || u == null) && v != null ? -1
: (u > v || v == null) && u != null ? 1
: ((v = v instanceof Date ? +v : v), (u = u instanceof Date ? +u : u)) !== u && v === v ? -1
: v !== v && u === u ? 1
: 0;
const comparator = (fields, orders) => fields.length === 1
? compare1(fields[0], orders[0])
: compareN(fields, orders, fields.length);
const compare1 = (field, order) => function(a, b) {
return ascending(field(a), field(b)) * order;
};
const compareN = (fields, orders, n) => {
orders.push(0); // pad zero for convenient lookup
return function(a, b) {
let f, c = 0, i = -1;
while (c === 0 && ++i < n) {
f = fields[i];
c = ascending(f(a), f(b));
}
return c * orders[i];
};
};