UNPKG

@gravity-ui/graph

Version:

Modern graph editor component

205 lines (204 loc) 9.48 kB
import { PublicGraphApi, ZoomConfig } from "./api/PublicGraphApi"; import { GraphComponent } from "./components/canvas/GraphComponent"; import { TBlock } from "./components/canvas/blocks/Block"; import { BelowLayer } from "./components/canvas/layers/belowLayer/BelowLayer"; import { CursorLayer, CursorLayerCursorTypes } from "./components/canvas/layers/cursorLayer"; import { GraphLayer } from "./components/canvas/layers/graphLayer/GraphLayer"; import { SelectionLayer } from "./components/canvas/layers/selectionLayer/SelectionLayer"; import { TGraphColors, TGraphConstants } from "./graphConfig"; import { GraphEventParams, GraphEventsDefinitions } from "./graphEvents"; import { HitTest } from "./services/HitTest"; import { Layer, LayerPublicProps } from "./services/Layer"; import { Layers } from "./services/LayersService"; import { CameraService } from "./services/camera/CameraService"; import { RootStore } from "./store"; import { TBlockId } from "./store/block/Block"; import { TConnection } from "./store/connection/ConnectionState"; import { TGraphSettingsConfig } from "./store/settings"; import { RecursivePartial } from "./utils/types/helpers"; import { IPoint, IRect, Point, TPoint, TRect } from "./utils/types/shapes"; export type LayerConfig<T extends Constructor<Layer> = Constructor<Layer>> = [T, LayerPublicProps<T>]; export type TGraphConfig<Block extends TBlock = TBlock, Connection extends TConnection = TConnection> = { configurationName?: string; blocks?: Block[]; connections?: TConnection[]; /** * @deprecated use Graph.zoom api */ rect?: TRect; /** * @deprecated use Graph.zoom api * */ cameraXY?: TPoint; /** * @deprecated use Graph.zoom api * */ cameraScale?: number; settings?: Partial<TGraphSettingsConfig<Block, Connection>>; layers?: LayerConfig[]; }; export type TGraphZoomTarget = "center" | TRect | TBlockId[]; export declare enum GraphState { INIT = 0, ATTACHED = 1, READY = 2 } export declare class Graph { private scheduler; cameraService: CameraService; layers: Layers; api: PublicGraphApi; eventEmitter: EventTarget; rootStore: RootStore; hitTest: HitTest; protected graphLayer: GraphLayer; protected belowLayer: BelowLayer; protected selectionLayer: SelectionLayer; protected cursorLayer: CursorLayer; getGraphCanvas(): HTMLCanvasElement; get graphColors(): TGraphColors; $graphColors: import("@preact/signals-core").Signal<TGraphColors>; get graphConstants(): TGraphConstants; $graphConstants: import("@preact/signals-core").Signal<TGraphConstants>; state: GraphState; protected config: TGraphConfig; protected startRequested: boolean; get blocks(): import("./store/block/BlocksList").BlockListStore; get connections(): import("./store/connection").ConnectionsStore; get selectionService(): import("./services/selection").SelectionService; constructor(config: TGraphConfig, rootEl?: HTMLDivElement, graphColors?: TGraphColors, graphConstants?: TGraphConstants); protected onUpdateSize: (event: IRect) => void; getGraphLayer(): GraphLayer; setColors(colors: RecursivePartial<TGraphColors>): void; setConstants(constants: RecursivePartial<TGraphConstants>): void; /** * Zoom to center of camera * @param zoomConfig - zoom config * @param zoomConfig.x if set - zoom to x coordinate, else - zoom to center * @param zoomConfig.y if set - zoom to y coordinate, else - zoom to center * @param zoomConfig.scale camera scale * * @returns {undefined} * */ zoom(zoomConfig: { x?: number; y?: number; scale: number; }): void; zoomTo(target: TGraphZoomTarget, config?: ZoomConfig): void; getElementsOverPoint<T extends Constructor<GraphComponent>>(point: IPoint, filter?: T[]): InstanceType<T>[]; getElementOverPoint<T extends Constructor<GraphComponent>>(point: IPoint, filter?: T[]): InstanceType<T> | undefined; /** * Returns the current viewport rectangle in camera space, expanded by threshold. * @returns {TRect} Viewport rect in camera-relative coordinates */ getViewportRect(): TRect; getElementsInViewport<T extends Constructor<GraphComponent>>(filter?: T[]): InstanceType<T>[]; getElementsOverRect<T extends Constructor<GraphComponent>>(rect: TRect, filter?: T[]): InstanceType<T>[]; getPointInCameraSpace(event: MouseEvent): Point; updateEntities({ blocks, connections, }: Partial<{ blocks?: TBlock[]; connections?: TConnection[]; }>): void; setEntities({ blocks, connections, }: Partial<{ blocks?: TBlock[]; connections?: TConnection[]; }>): void; on<EventName extends keyof GraphEventsDefinitions = keyof GraphEventsDefinitions, Cb extends GraphEventsDefinitions[EventName] = GraphEventsDefinitions[EventName]>(type: EventName, cb: Cb, options?: AddEventListenerOptions | boolean): () => void; off<EventName extends keyof GraphEventsDefinitions = keyof GraphEventsDefinitions, Cb extends GraphEventsDefinitions[EventName] = GraphEventsDefinitions[EventName]>(type: EventName, cb: Cb): void; emit<EventName extends keyof GraphEventsDefinitions = keyof GraphEventsDefinitions, Cb extends GraphEventsDefinitions[EventName] = GraphEventsDefinitions[EventName], P extends Parameters<Cb>[0] = Parameters<Cb>[0]>(eventName: EventName, detail: GraphEventParams<P>): CustomEvent<GraphEventParams<P>>; executеDefaultEventAction<EventName extends keyof GraphEventsDefinitions = keyof GraphEventsDefinitions, Cb extends GraphEventsDefinitions[EventName] = GraphEventsDefinitions[EventName], P extends Parameters<Cb>[0] = Parameters<Cb>[0]>(eventName: EventName, detail: GraphEventParams<P>, defaultCb: () => void): void; addLayer<T extends Constructor<Layer> = Constructor<Layer>>(layerCtor: T, props: LayerPublicProps<T>): InstanceType<T>; detachLayer(layer: Layer): void; setupGraph(config?: TGraphConfig): void; updateSettings(settings: Partial<TGraphSettingsConfig>): void; updateSize(): void; attach(rootEl: HTMLDivElement): void; start(rootEl?: HTMLDivElement): void; /** * Graph is ready when the hitboxes are stable. * In order to initialize hitboxes we need to start scheduler and wait untils every component registered in hitTest service * Immediatelly after registering startign a rendering process. * @param cb - Callback to run after graph is ready */ runAfterGraphReady(cb: () => void): void; stop(full?: boolean): void; protected setGraphState(state: GraphState): void; protected clear(): void; detach(): void; unmount(): void; /** * Locks the cursor to a specific type, disabling automatic cursor changes. * * When the cursor is locked, it will remain fixed to the specified type * and will not change automatically based on component interactions until * unlockCursor() is called. This is useful during drag operations, loading * states, or other situations where you want to override the default * interactive cursor behavior. * * @param cursor - The cursor type to lock to * * @example * ```typescript * // Lock to loading cursor during async operation * graph.lockCursor("wait"); * * // Lock to grabbing cursor during drag operation * graph.lockCursor("grabbing"); * * // Lock to copy cursor for duplication operations * graph.lockCursor("copy"); * ``` * * @see {@link CursorLayer.lockCursor} for more details * @see {@link unlockCursor} to return to automatic behavior */ lockCursor(cursor: CursorLayerCursorTypes): void; /** * Unlocks the cursor and returns to automatic cursor management. * * The cursor will immediately update to reflect the current state * based on the component under the mouse (if any). This provides * smooth transitions when ending drag operations or async tasks. * * @example * ```typescript * // After completing a drag operation * graph.unlockCursor(); // Will show appropriate cursor for current hover state * * // After finishing an async operation * await someAsyncTask(); * graph.unlockCursor(); // Returns to interactive cursor behavior * ``` * * @see {@link CursorLayer.unlockCursor} for more details * @see {@link lockCursor} to override automatic behavior */ unlockCursor(): void; /** * Returns the CursorLayer instance for advanced cursor management. * * Use this method when you need direct access to cursor layer functionality * beyond the basic setCursor/unsetCursor API, such as checking the current * mode or getting the component under the cursor. * * @returns The CursorLayer instance * * @example * ```typescript * const cursorLayer = graph.getCursorLayer(); * * // Check current mode * if (cursorLayer.isManual()) { * console.log("Manual cursor:", cursorLayer.getManualCursor()); * } * * // Get component under cursor for debugging * const target = cursorLayer.getCurrentTarget(); * console.log("Hovering over:", target?.constructor.name); * ``` * * @see {@link CursorLayer} for available methods and properties */ getCursorLayer(): CursorLayer; }