or run

npx @tessl/cli init
Log in

Version

Tile

Overview

Evals

Files

docs

geometry.mdgraph.mdindex.mdmodel.mdplugins.mdregistry.mdshapes.mdutilities.mdview-system.md
tile.json

model.mddocs/

Model System

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.

Capabilities

Cell Base Class

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'
});

Node Class

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');

Edge Class

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 terminal

Model Class

Container 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');

Types

// 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;
}