export function logSpace(xMin: number, xMax: number, steps: number): number[] { const logMin = Math.log10(xMin); const logMax = Math.log10(xMax); const out: number[] = []; for (let s = 0; s <= steps; s++) { out.push(Math.pow(10, logMin + ((logMax - logMin) * s) / steps)); } return out; } export type CurvePoint = { x: number; y: number }; export type CurveColors = { strokeColor: string; fillAbove: string; fillAboveFade: string; fillBelowFade: string; fillBelow: string; }; export const DEFAULT_CURVE_COLORS: CurveColors = { strokeColor: '#e5e7eb', fillAbove: 'rgba(74, 222, 128, 0.35)', fillAboveFade: 'rgba(74, 222, 128, 0.08)', fillBelowFade: 'rgba(248, 113, 113, 0.08)', fillBelow: 'rgba(248, 113, 113, 0.35)', }; export type CurveStyle = { strokeColor?: string; fillColors?: CurveColors; /** Draw the area fill under/around the curve. Defaults to true. */ fill?: boolean; lineWidth?: number; dimmed?: boolean; }; /** A single polyline ready to be handed to `drawCurves`. */ export type Curve = { points: CurvePoint[]; style?: CurveStyle; }; export function sumCurvePoints(pointArrays: CurvePoint[][]): CurvePoint[] { if (pointArrays.length === 0) return []; const length = pointArrays[0].length; const result: CurvePoint[] = new Array(length); for (let i = 0; i < length; i++) { let y = 0; for (const points of pointArrays) { y += points[i]?.y ?? 0; } result[i] = { x: pointArrays[0][i].x, y }; } return result; } export function sumPhaseCurvePoints(pointArrays: CurvePoint[][]): CurvePoint[] { if (pointArrays.length === 0) return []; const length = pointArrays[0].length; const result: CurvePoint[] = new Array(length); let previousPhase = 0; for (let i = 0; i < length; i++) { let phase = 0; for (const points of pointArrays) { phase += points[i]?.y ?? 0; } // Keep phase continuous while summing. while (phase - previousPhase > 180) { phase -= 360; } while (phase - previousPhase < -180) { phase += 360; } // Wrap to [-180, 180]. const wrapped = ((((phase + 180) % 360) + 360) % 360) - 180; result[i] = { x: pointArrays[0][i].x, y: wrapped, }; previousPhase = phase; } return result; }