import type { TransformLineage, TransformValue, TransformValueOutput } from './transform.js'; import type { ChartKey } from './types.js'; import type { Force, SimulationLinkDatum, SimulationNodeDatum } from 'd3-force'; export type ForceNumericValue = number | TransformValue; export interface ForceLinkDescriptor { readonly type: 'link'; readonly distance?: ForceNumericValue; readonly strength?: ForceNumericValue; } export interface ForceManyBodyDescriptor { readonly type: 'manyBody'; readonly strength?: ForceNumericValue; } export interface ForceCenterDescriptor { readonly type: 'center'; readonly x?: number; readonly y?: number; } export interface ForceCollideDescriptor { readonly type: 'collide'; readonly radius?: ForceNumericValue; readonly strength?: number; } export interface ForceXDescriptor { readonly type: 'x'; readonly x?: ForceNumericValue; readonly strength?: ForceNumericValue; } export interface ForceYDescriptor { readonly type: 'y'; readonly y?: ForceNumericValue; readonly strength?: ForceNumericValue; } /** A private node clone initialized and mutated only by the D3 simulation. */ export type ForceLayoutWorkingNode = Omit & SimulationNodeDatum; /** A private link clone whose endpoints may be resolved by a D3 link force. */ export type ForceLayoutWorkingLink = Omit>> & SimulationLinkDatum>; export interface ForceFactoryContext { readonly nodes: ForceLayoutWorkingNode[]; readonly links: ForceLayoutWorkingLink[]; readonly nodeKeys: readonly TNodeKey[]; readonly sourceKeys: readonly ChartKey[]; readonly targetKeys: readonly ChartKey[]; readonly nodeKey: (node: ForceLayoutWorkingNode, index: number) => TNodeKey; } export type ForceFactory = (context: ForceFactoryContext) => Force, ForceLayoutWorkingLink>; export interface ForceFactoryDescriptor { readonly type: 'custom'; readonly name: string; readonly create: ForceFactory; } export type ForceDescriptor = ForceLinkDescriptor | ForceManyBodyDescriptor | ForceCenterDescriptor | ForceCollideDescriptor | ForceXDescriptor | ForceYDescriptor | ForceFactoryDescriptor; export interface ForceLayoutOptions = TransformValue, TSource extends TransformValue = TransformValue, TTarget extends TransformValue = TransformValue> { readonly nodeKey: TNodeKey; readonly source: TSource; readonly target: TTarget; /** Number of synchronous simulation ticks. Defaults to D3's natural 300. */ readonly iterations?: number; /** Fraction of each positional span added to both domain ends. Defaults to 0.2. */ readonly domainPadding?: number; /** Forces are initialized and applied in authored order. */ readonly forces: readonly ForceDescriptor, ChartKey>>[]; } export type ForceLayoutNode = Omit | 'x' | 'y' | 'vx' | 'vy'> & TransformLineage & { readonly x: number; readonly y: number; readonly vx: number; readonly vy: number; }; /** * Link lineage uses `sourceRows` because `source` remains the raw graph endpoint. * This is the deliberate exception to the ordinary `TransformLineage` field name. */ export interface ForceLinkLineage { readonly sourceRows: readonly TLink[]; readonly sourceIndexes: readonly number[]; } type ForceLinkDerivedFields = keyof ForceLinkLineage | 'source' | 'target' | 'sourceNode' | 'targetNode' | 'sourceIndex' | 'targetIndex' | 'sourceKey' | 'targetKey' | 'x1' | 'y1' | 'x2' | 'y2'; export type ForceLayoutLink = Omit & ForceLinkLineage & { /** Raw source identifier, preserved after D3 resolves its private clone. */ readonly source: TSourceKey; /** Raw target identifier, preserved after D3 resolves its private clone. */ readonly target: TTargetKey; readonly sourceKey: TSourceKey; readonly targetKey: TTargetKey; readonly sourceIndex: number; readonly targetIndex: number; readonly sourceNode: ForceLayoutNode; readonly targetNode: ForceLayoutNode; readonly x1: number; readonly y1: number; readonly x2: number; readonly y2: number; }; export interface ForceLayoutResult { readonly nodes: readonly ForceLayoutNode[]; readonly links: readonly ForceLayoutLink[]; readonly xDomain: readonly [number, number]; readonly yDomain: readonly [number, number]; } type EndpointKey = Extract, ChartKey>; /** Settles a deterministic, synchronous D3 force simulation over private clones. */ export declare function forceLayout, const TSource extends TransformValue, const TTarget extends TransformValue>(nodes: Iterable, links: Iterable, options: ForceLayoutOptions, NoInfer, TNodeKey, TSource, TTarget>): ForceLayoutResult, EndpointKey>; export {};