@gravity-ui/graph
Version:
Modern graph editor component
205 lines (204 loc) • 9.48 kB
TypeScript
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;
}