Data model classes for creating and managing graph elements with full property and attribute control. The model system provides the core data structures and operations for nodes, edges, and their container model, following an MVC architecture pattern.
Abstract base class for all graph elements providing common functionality for properties, attributes, and lifecycle management.
/**
* Abstract base class for all graph elements
* @param metadata - Initial cell metadata
*/
class Cell {
constructor(metadata?: Cell.Metadata);
// Core properties
readonly id: string;
readonly shape: string;
// Type checking methods
isNode(): this is Node;
isEdge(): this is Edge;
// Property management
prop(): Cell.Properties;
prop(key: string): any;
prop(key: string, value: any, options?: Cell.SetOptions): this;
prop(props: Partial<Cell.Properties>, options?: Cell.SetOptions): this;
setProp(key: string, value: any, options?: Cell.SetOptions): this;
setProp(props: Partial<Cell.Properties>, options?: Cell.SetOptions): this;
removeProp(path: string | string[], options?: Cell.SetOptions): this;
hasChanges(path?: string | string[]): boolean;
// Attribute management
attr(): CellAttrs;
attr(key: string): any;
attr(key: string, value: any, options?: Cell.SetOptions): this;
attr(attrs: CellAttrs, options?: Cell.SetOptions): this;
setAttrs(attrs: CellAttrs, options?: Cell.SetOptions): this;
removeAttr(path: string | string[], options?: Cell.SetOptions): this;
// Lifecycle methods
clone(options?: Cell.CloneOptions): Cell;
remove(options?: Cell.RemoveOptions): this;
// Serialization
toJSON(options?: Cell.ToJSONOptions): Cell.Properties;
// Hierarchy
getParent(): Cell | null;
getChildren(): Cell[];
getDescendants(options?: Cell.GetDescendantsOptions): Cell[];
getAncestors(): Cell[];
isDescendantOf(cell: Cell): boolean;
// Geometry
getBBox(options?: Cell.GetBBoxOptions): Rectangle;
// Animation
animate(attrs: CellAttrs, options?: Animation.Options): Animation;
stop(animation?: Animation, options?: Animation.StopOptions): this;
// Events
on<K extends keyof Cell.EventArgs>(name: K, callback: Cell.EventArgs[K], context?: any): this;
off<K extends keyof Cell.EventArgs>(name?: K, callback?: Cell.EventArgs[K], context?: any): this;
trigger<K extends keyof Cell.EventArgs>(name: K, args?: Cell.EventArgs[K]): this;
}
// Cell configuration interfaces
interface Cell.Metadata {
id?: string;
shape?: string;
markup?: Markup;
attrs?: CellAttrs;
data?: any;
parent?: string;
children?: (Cell | string)[];
zIndex?: number;
visible?: boolean;
[key: string]: any;
}
interface Cell.Properties extends Cell.Metadata {
id: string;
shape: string;
}
interface Cell.SetOptions {
silent?: boolean;
overwrite?: boolean;
isolate?: boolean;
deep?: boolean;
[key: string]: any;
}
interface Cell.CloneOptions {
deep?: boolean;
[key: string]: any;
}
interface Cell.RemoveOptions {
disconnectEdges?: boolean;
[key: string]: any;
}
interface CellAttrs {
[selector: string]: {
[attrName: string]: any;
};
}Usage Examples:
import { Cell } from "@antv/x6";
// Create a custom cell class
class CustomCell extends Cell {
constructor(metadata?: Cell.Metadata) {
super({
shape: 'custom-shape',
...metadata
});
}
}
// Working with properties
const cell = new CustomCell();
cell.prop('customData', { value: 42 });
cell.prop({ visible: true, zIndex: 10 });
const customData = cell.prop('customData');
const allProps = cell.prop();
// Working with attributes
cell.attr('body/fill', 'red');
cell.attr({
body: { fill: 'blue', stroke: 'black' },
label: { text: 'Hello World' }
});
// Animation
cell.animate({ 'body/fill': 'green' }, {
duration: 1000,
timing: 'ease-in-out'
});Represents graph nodes with position, size, rotation, and port management capabilities.
/**
* Node class representing graph nodes
* @param metadata - Initial node metadata
*/
class Node extends Cell {
constructor(metadata?: Node.Metadata);
// Position management
position(): Point.PointData;
position(x: number, y: number, options?: Node.PositionOptions): this;
position(pos: Point.PointLike, options?: Node.PositionOptions): this;
setPosition(x: number, y: number, options?: Node.PositionOptions): this;
setPosition(pos: Point.PointLike, options?: Node.PositionOptions): this;
getPosition(): Point.PointData;
translate(dx: number, dy: number, options?: Node.TranslateOptions): this;
// Size management
size(): Size;
size(width: number, height: number, options?: Node.ResizeOptions): this;
size(size: Size, options?: Node.ResizeOptions): this;
setSize(width: number, height: number, options?: Node.ResizeOptions): this;
setSize(size: Size, options?: Node.ResizeOptions): this;
getSize(): Size;
resize(width: number, height: number, options?: Node.ResizeOptions): this;
// Rotation
getAngle(): number;
setAngle(angle: number, options?: Node.RotateOptions): this;
rotate(angle: number, options?: Node.RotateOptions): this;
rotateAroundCenter(angle: number, options?: Node.RotateOptions): this;
// Scaling
scale(sx: number, sy: number, origin?: Point.PointLike, options?: Node.SetOptions): this;
// Geometric queries
getBBox(options?: Node.GetBBoxOptions): Rectangle;
getConnectionPoint(edge: Edge, type: Edge.TerminalType): Point;
// Port management
getPorts(): PortManager.Port[];
getPortsLayoutByGroup(groupName?: string, bbox?: Rectangle): PortLayoutResult[];
addPort(port: PortManager.PortMetadata, options?: Node.SetOptions): this;
addPorts(ports: PortManager.PortMetadata[], options?: Node.SetOptions): this;
insertPort(index: number, port: PortManager.PortMetadata, options?: Node.SetOptions): this;
removePort(portId: string, options?: Node.SetOptions): this;
removePortAt(index: number, options?: Node.SetOptions): this;
removePorts(portIds?: string[], options?: Node.SetOptions): this;
updatePort(portId: string, port: Partial<PortManager.PortMetadata>, options?: Node.SetOptions): this;
hasPort(portId: string): boolean;
getPort(portId: string): PortManager.Port | null;
getPortIndex(port: string | PortManager.Port): number;
getPortAt(index: number): PortManager.Port | null;
getPortProp(portId: string): PortManager.Port | null;
getPortProp(portId: string, path: string | string[]): any;
setPortProp(portId: string, path: string | string[], value: any, options?: Node.SetOptions): this;
setPortProp(portId: string, props: Partial<PortManager.PortMetadata>, options?: Node.SetOptions): this;
removePortProp(portId: string, path: string | string[], options?: Node.SetOptions): this;
}
// Node-specific interfaces
interface Node.Metadata extends Cell.Metadata {
x?: number;
y?: number;
width?: number;
height?: number;
angle?: number;
ports?: PortManager.PortMetadata[];
}
interface Node.Properties extends Node.Metadata, Cell.Properties {
position: Point.PointData;
size: Size;
angle: number;
ports: PortManager.Port[];
}
interface Node.PositionOptions extends Cell.SetOptions {
relative?: boolean;
restrict?: Rectangle.RectangleLike | null;
deep?: boolean;
}
interface Node.TranslateOptions extends Node.PositionOptions {
tx?: number;
ty?: number;
}
interface Node.ResizeOptions extends Cell.SetOptions {
direction?: 'left' | 'right' | 'top' | 'bottom' | 'top-left' | 'top-right' | 'bottom-left' | 'bottom-right';
}
interface Node.RotateOptions extends Cell.SetOptions {
center?: Point.PointLike;
}
interface Size {
width: number;
height: number;
}Usage Examples:
import { Node } from "@antv/x6";
// Create a node
const node = new Node({
x: 100,
y: 100,
width: 80,
height: 40,
attrs: {
body: {
fill: 'lightblue',
stroke: 'blue'
},
label: {
text: 'My Node',
fill: 'black'
}
}
});
// Position operations
node.position(200, 150);
node.translate(50, 25);
const pos = node.getPosition(); // { x: 250, y: 175 }
// Size operations
node.size(120, 60);
node.resize(100, 50);
const size = node.getSize(); // { width: 100, height: 50 }
// Rotation
node.rotate(45);
node.rotateAroundCenter(90);
// Port management
node.addPort({
id: 'port1',
group: 'top',
attrs: {
circle: { fill: 'red' }
}
});
node.addPorts([
{ id: 'in', group: 'left' },
{ id: 'out', group: 'right' }
]);
const ports = node.getPorts();
const port = node.getPort('port1');Represents connections between nodes with source/target terminals, path vertices, labels, and routing configuration.
/**
* Edge class representing connections between nodes
* @param metadata - Initial edge metadata
*/
class Edge extends Cell {
constructor(metadata?: Edge.Metadata);
// Terminal management
getSource(): Edge.TerminalData;
getTarget(): Edge.TerminalData;
setSource(source: Edge.TerminalData, options?: Edge.SetOptions): this;
setTarget(target: Edge.TerminalData, options?: Edge.SetOptions): this;
getSourceCell(): Cell | null;
getTargetCell(): Cell | null;
getSourceCellId(): string | null;
getTargetCellId(): string | null;
getSourceNode(): Node | null;
getTargetNode(): Node | null;
getSourcePoint(): Point;
getTargetPoint(): Point;
// Connection queries
isConnectedTo(cell: Cell): boolean;
getConnectedCells(): Cell[];
// Vertices management
getVertices(): Point.PointData[];
setVertices(vertices: Point.PointLike[], options?: Edge.SetOptions): this;
insertVertex(vertex: Point.PointLike, index?: number, options?: Edge.SetOptions): this;
appendVertex(vertex: Point.PointLike, options?: Edge.SetOptions): this;
prependVertex(vertex: Point.PointLike, options?: Edge.SetOptions): this;
removeVertex(index: number, options?: Edge.SetOptions): this;
removeVertexAt(index: number, options?: Edge.SetOptions): this;
updateVertex(index: number, vertex: Point.PointLike, options?: Edge.SetOptions): this;
getVertexAt(index: number): Point.PointData | null;
// Labels management
getLabels(): Edge.Label[];
setLabels(labels: Edge.Label[], options?: Edge.SetOptions): this;
insertLabel(label: Edge.Label, index?: number, options?: Edge.SetOptions): this;
appendLabel(label: Edge.Label, options?: Edge.SetOptions): this;
prependLabel(label: Edge.Label, options?: Edge.SetOptions): this;
removeLabel(index: number, options?: Edge.SetOptions): this;
removeLabelAt(index: number, options?: Edge.SetOptions): this;
updateLabel(index: number, label: Edge.Label, options?: Edge.SetOptions): this;
getLabelAt(index: number): Edge.Label | null;
setLabelAt(index: number, label: Edge.Label, options?: Edge.SetOptions): this;
// Routing and connection
getRouter(): RouterManualItem | RouterNativeItem | null;
setRouter(router: RouterManualItem | RouterNativeItem, options?: Edge.SetOptions): this;
getConnector(): ConnectorManualItem | ConnectorNativeItem | null;
setConnector(connector: ConnectorManualItem | ConnectorNativeItem, options?: Edge.SetOptions): this;
// Path utilities
getConnectionPoint(terminal: Edge.TerminalType): Point;
getConnection(): Path;
getConnectionLength(): number;
getPointAtLength(length: number): Point;
getPointAtRatio(ratio: number): Point;
getTangentAtLength(length: number): Line;
getTangentAtRatio(ratio: number): Line;
getClosestPoint(point: Point.PointLike): Point;
}
// Edge-specific interfaces
interface Edge.Metadata extends Cell.Metadata {
source?: Edge.TerminalData;
target?: Edge.TerminalData;
vertices?: Point.PointLike[];
labels?: Edge.Label[];
router?: any;
connector?: any;
defaultLabel?: Edge.Label;
}
interface Edge.Properties extends Edge.Metadata, Cell.Properties {
source: Edge.TerminalData;
target: Edge.TerminalData;
vertices: Point.PointData[];
labels: Edge.Label[];
}
// Terminal types
type Edge.TerminalData =
| string
| Cell
| { cell: string | Cell; port?: string; magnet?: string; selector?: string; }
| { x: number; y: number; };
type Edge.TerminalType = 'source' | 'target';
// Label interface
interface Edge.Label {
markup?: Markup;
attrs?: CellAttrs;
position?: number | Edge.LabelPosition;
size?: Size;
}
interface Edge.LabelPosition {
distance?: number;
offset?: number | Point.PointLike;
angle?: number;
options?: {
absoluteDistance?: boolean;
reverseDistance?: boolean;
absoluteOffset?: boolean;
keepGradient?: boolean;
ensureLegibility?: boolean;
};
}
// Router and connector types
type RouterManualItem = {
name: string;
args?: any;
};
type RouterNativeItem = (
vertices: Point.PointData[],
args: any,
view: EdgeView
) => Point.PointData[];
type ConnectorManualItem = {
name: string;
args?: any;
};
type ConnectorNativeItem = (
sourcePoint: Point,
targetPoint: Point,
vertices: Point.PointData[],
args: any,
view: EdgeView
) => Path;Usage Examples:
import { Edge, Node } from "@antv/x6";
// Create nodes
const source = new Node({ id: 'source', x: 100, y: 100, width: 80, height: 40 });
const target = new Node({ id: 'target', x: 300, y: 200, width: 80, height: 40 });
// Create edge connecting nodes
const edge = new Edge({
source: source.id,
target: target.id,
attrs: {
line: {
stroke: 'blue',
strokeWidth: 2
}
}
});
// Edge with specific ports
const edgeWithPorts = new Edge({
source: { cell: source, port: 'out' },
target: { cell: target, port: 'in' }
});
// Edge with vertices (path control points)
edge.setVertices([
{ x: 150, y: 120 },
{ x: 200, y: 150 },
{ x: 250, y: 180 }
]);
// Add labels
edge.setLabels([
{
attrs: { text: { text: 'Label 1' } },
position: 0.3
},
{
attrs: { text: { text: 'Label 2' } },
position: { distance: 0.7, offset: { x: 10, y: -10 } }
}
]);
// Set router and connector
edge.setRouter('manhattan');
edge.setConnector('rounded');
// Terminal management
edge.setSource({ x: 50, y: 50 }); // Point terminal
edge.setTarget(target); // Cell terminalContainer and manager for all graph cells providing batch operations, serialization, and collection management.
/**
* Model class managing collection of cells
* @param cells - Initial cells to add
*/
class Model {
constructor(cells?: Cell[]);
// Core collection operations
addCell(cell: Cell, options?: Model.AddOptions): this;
addCell(cells: Cell[], options?: Model.AddOptions): this;
addCells(cells: Cell[], options?: Model.AddOptions): this;
removeCell(cell: Cell, options?: Collection.RemoveOptions): Cell | null;
removeCell(id: string, options?: Collection.RemoveOptions): Cell | null;
removeCells(cells: (Cell | string)[], options?: Collection.RemoveOptions): Cell[];
// Cell retrieval
getCell(id: string): Cell | null;
getCells(): Cell[];
getCellCount(): number;
hasCell(cell: Cell | string): boolean;
indexOf(cell: Cell): number;
// Collection management
clear(options?: Cell.SetOptions): this;
resetCells(cells: Cell[], options?: Collection.SetOptions): this;
// Batch operations
startBatch(name: Model.BatchName, data?: KeyValue): this;
stopBatch(name: Model.BatchName, data?: KeyValue): this;
batchUpdate<T>(execute: () => T, data?: KeyValue): T;
// Serialization
toJSON(options?: Model.ToJSONOptions): Model.JSONData;
fromJSON(data: Model.FromJSONData, options?: Model.FromJSONOptions): this;
// Search and filtering
search(cell: Cell, iterator: Model.SearchIterator, options?: Model.SearchOptions): any;
getConnectedEdges(cell: Cell, options?: Model.GetConnectedEdgesOptions): Edge[];
getNeighbors(cell: Cell, options?: Model.GetNeighborsOptions): Cell[];
isSuccessor(cell: Cell, successor: Cell): boolean;
isPredecessor(cell: Cell, predecessor: Cell): boolean;
getCommonAncestor(...cells: Cell[]): Cell | null;
// Topological operations
getSuccessors(cell: Cell, options?: Model.GetSuccessorsOptions): Cell[];
getPredecessors(cell: Cell, options?: Model.GetPredecessorsOptions): Cell[];
getRootCells(): Cell[];
getLeafCells(): Cell[];
// Path finding
getShortestPath(source: Cell | string, target: Cell | string, options?: Model.GetShortestPathOptions): string[];
// Events
on<K extends keyof Model.EventArgs>(name: K, callback: Model.EventArgs[K], context?: any): this;
off<K extends keyof Model.EventArgs>(name?: K, callback?: Model.EventArgs[K], context?: any): this;
trigger<K extends keyof Model.EventArgs>(name: K, args?: Model.EventArgs[K]): this;
}
// Model interfaces
interface Model.AddOptions {
silent?: boolean;
sort?: boolean;
dryrun?: boolean;
[key: string]: any;
}
interface Collection.SetOptions {
silent?: boolean;
add?: boolean;
merge?: boolean;
remove?: boolean;
[key: string]: any;
}
interface Collection.RemoveOptions {
silent?: boolean;
[key: string]: any;
}
type Model.BatchName = string;
interface Model.ToJSONOptions {
diff?: any;
[key: string]: any;
}
interface Model.FromJSONOptions {
silent?: boolean;
[key: string]: any;
}
interface Model.JSONData {
cells: Cell.Properties[];
}
type Model.FromJSONData = Model.JSONData | Cell.Properties[];
type Model.SearchIterator = (cell: Cell, distance: number) => any;
interface Model.SearchOptions {
breadthFirst?: boolean;
deep?: boolean;
}
interface Model.GetConnectedEdgesOptions {
incoming?: boolean;
outgoing?: boolean;
deep?: boolean;
indirect?: boolean;
}
interface Model.GetNeighborsOptions {
incoming?: boolean;
outgoing?: boolean;
deep?: boolean;
indirect?: boolean;
}Usage Examples:
import { Model, Node, Edge } from "@antv/x6";
// Create model with initial cells
const model = new Model([
new Node({ id: 'node1', x: 100, y: 100 }),
new Node({ id: 'node2', x: 300, y: 200 })
]);
// Add cells
model.addCell(new Edge({ source: 'node1', target: 'node2' }));
// Batch operations for performance
model.startBatch('custom-operation');
model.addCell(new Node({ id: 'node3', x: 200, y: 150 }));
model.addCell(new Node({ id: 'node4', x: 400, y: 250 }));
model.stopBatch('custom-operation');
// Alternative batch syntax
model.batchUpdate(() => {
model.addCell(new Node({ id: 'node5', x: 500, y: 300 }));
model.addCell(new Edge({ source: 'node3', target: 'node5' }));
});
// Serialization
const jsonData = model.toJSON();
console.log(jsonData);
// Load from JSON
const newModel = new Model();
newModel.fromJSON(jsonData);
// Graph analysis
const node1 = model.getCell('node1');
const connectedEdges = model.getConnectedEdges(node1);
const neighbors = model.getNeighbors(node1);
const path = model.getShortestPath('node1', 'node4');// Port management types
namespace PortManager {
interface PortMetadata {
id?: string;
group?: string;
position?: Point.PointLike | string;
attrs?: CellAttrs;
args?: any;
label?: {
text?: string;
position?: any;
attrs?: CellAttrs;
};
zIndex?: number | 'auto';
markup?: Markup;
}
interface Port extends PortMetadata {
id: string;
position: Point.PointLike;
}
interface PortGroup {
position?: string | Point.PointLike | PortPosition;
attrs?: CellAttrs;
markup?: Markup;
label?: {
position?: string | PortLabelPosition;
attrs?: CellAttrs;
markup?: Markup;
};
}
type PortPosition = {
name: string;
args?: any;
};
type PortLabelPosition = {
name: string;
args?: any;
};
}
interface PortLayoutResult {
portId: string;
position: Point.PointData;
angle: number;
attrs: CellAttrs;
portAttrs: CellAttrs;
labelAttrs: CellAttrs;
portSize: Size;
labelSize: Size;
}
// Animation types
namespace Animation {
interface Options {
duration?: number;
delay?: number;
timing?: string | ((t: number) => number);
complete?: (this: Cell) => void;
[key: string]: any;
}
interface StopOptions {
jumpToEnd?: boolean;
[key: string]: any;
}
}
// Markup types
type Markup =
| string
| Markup.JSONMarkup
| (string | Markup.JSONMarkup)[];
namespace Markup {
interface JSONMarkup {
tagName: string;
selector?: string;
groupSelector?: string | string[];
namespaceURI?: string;
attributes?: { [key: string]: any };
style?: { [key: string]: any };
className?: string | string[];
children?: (string | JSONMarkup)[];
textContent?: string;
}
}
// Geometry types
interface Point.PointLike {
x: number;
y: number;
}
interface Point.PointData {
x: number;
y: number;
}
// Event argument types
interface Cell.EventArgs {
'change:*': { cell: Cell; options: any };
'changed': { cell: Cell; options: any };
'removed': { cell: Cell; collection: any; options: any };
'added': { cell: Cell; collection: any; options: any };
}
interface Model.EventArgs {
'cell:added': { cell: Cell; index: number; options: Model.AddOptions };
'cell:removed': { cell: Cell; index: number; options: Collection.RemoveOptions };
'cell:changed': { cell: Cell; options: Cell.SetOptions };
'reseted': { options: any };
'sorted': { options: any };
'batch:start': { name: string; data?: any };
'batch:stop': { name: string; data?: any };
}
// Utility types
interface KeyValue {
[key: string]: any;
}
interface Rectangle {
x: number;
y: number;
width: number;
height: number;
}
interface Size {
width: number;
height: number;
}