@thi.ng/viz
Version:
Declarative, functional & multi-format data visualization toolkit based around @thi.ng/hiccup
59 lines (58 loc) • 1.73 kB
JavaScript
import { comp } from "@thi.ng/transducers/comp";
import { filter } from "@thi.ng/transducers/filter";
import { iterator } from "@thi.ng/transducers/iterator";
import { map } from "@thi.ng/transducers/map";
import { mapcatIndexed } from "@thi.ng/transducers/mapcat-indexed";
import { push } from "@thi.ng/transducers/push";
import { some } from "@thi.ng/transducers/some";
import { transduce } from "@thi.ng/transducers/transduce";
import { __valueMapper } from "./utils.js";
const __overlap = ([a, b], [c, d], pad = 0) => a <= d + pad && b + pad >= c;
const __laneStacking = (data, pad = 0) => data.reduce((acc, item) => {
const rx = item[0];
for (let i = 0; true; i++) {
const row = acc[i];
if (!row || !some((y) => __overlap(rx, y[0], pad), row)) {
row ? row.push(item) : acc[i] = [item];
return acc;
}
}
}, []);
const __processLane = (mapper, [d1, d2]) => (i, row) => map(
([[a, b], item]) => [
mapper([Math.max(d1, a), i]),
mapper([Math.min(d2, b), i]),
item,
i
],
row
);
const stackedIntervals = (data, opts) => (spec) => {
const mapper = __valueMapper(spec.xaxis, spec.yaxis, spec.project);
const domain = spec.xaxis.domain;
const lanes = __laneStacking(
transduce(
comp(
map((x) => [opts.interval(x), x]),
filter(([x]) => __overlap(domain, x, opts.overlap))
),
push(),
data
).sort(opts.sort || ((a, b) => a[0][0] - b[0][0])),
opts.overlap
);
return [
"g",
{ ...opts.attribs, "data-num-lanes": lanes.length },
...iterator(
comp(
mapcatIndexed(__processLane(mapper, domain)),
map((x) => opts.shape(x, mapper))
),
lanes
)
];
};
export {
stackedIntervals
};