Imports name this capability’s declared dependencies, which fune builds next to it in your project; each one links to its page.
import { roundFloat } from "./math_round_float.ts"; ← from math.round-float ^1.0.0 · built alongside by fune
import type { StackedValue, StackOffset } from "./charts_stack_types.ts";
/**
* Stack series position by position, as d3.stack does with the series in the
* given order: stackOffsetNone (zero), stackOffsetExpand and
* stackOffsetDiverging. Running totals are kept unrounded; only the returned
* edges are rounded, so rounding never accumulates up the stack.
*/
export function stack(series: readonly (readonly number[])[], offset: StackOffset): readonly (readonly StackedValue[])[] {
if (offset !== "zero" && offset !== "expand" && offset !== "diverging") {
throw new RangeError(`stack offset must be zero, expand or diverging, received ${offset}`);
}
const n = series.length;
if (n === 0) return [];
const m = series[0].length;
for (const s of series) {
if (s.length !== m) throw new RangeError("every series must have the same number of values");
for (const v of s) {
if (typeof v !== "number" || !Number.isFinite(v)) throw new TypeError(`stack values must be finite numbers, received ${v}`);
if (offset === "expand" && v < 0) throw new RangeError(`expand needs values of zero or more, received ${v}`);
}
}
const lower: number[][] = series.map(() => new Array<number>(m));
const upper: number[][] = series.map(() => new Array<number>(m));
for (let j = 0; j < m; j++) {
if (offset === "diverging") {
let up = 0;
let down = 0;
for (let i = 0; i < n; i++) {
const v = series[i][j];
if (v > 0) {
lower[i][j] = up;
up += v;
upper[i][j] = up;
} else if (v < 0) {
upper[i][j] = down;
down += v;
lower[i][j] = down;
} else {
lower[i][j] = 0;
upper[i][j] = 0;
}
}
} else {
let total = 0;
if (offset === "expand") for (let i = 0; i < n; i++) total += series[i][j];
let top = 0;
for (let i = 0; i < n; i++) {
// Each share is divided by the total first, then summed, as d3 does.
const v = offset === "expand" ? (total > 0 ? series[i][j] / total : 0) : series[i][j];
lower[i][j] = top;
top += v;
upper[i][j] = top;
}
}
}
return series.map((_, i) => lower[i].map((y0, j) => ({ y0: roundFloat(y0, 6), y1: roundFloat(upper[i][j], 6) })));
}