UNPKG

@thi.ng/viz

Version:

Declarative, functional & multi-format data visualization toolkit based around @thi.ng/hiccup

59 lines (58 loc) 1.73 kB
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 };