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

view-system.mddocs/

View System

The View System provides the presentation layer of X6's MVC architecture, responsible for rendering graph elements to the DOM and handling user interactions. Views bridge the gap between the data model (Cell, Node, Edge) and the visual representation, managing SVG/HTML rendering, event handling, and tool integration.

Capabilities

CellView Base Class

Abstract base class for all graph element views providing common rendering and interaction functionality.

/**
 * Base view class for all graph elements
 * @param cell - The model entity this view represents
 * @param options - View configuration options
 */
class CellView<Entity extends Cell = Cell> extends View<CellViewEventArgs> {
  constructor(cell: Entity, options: Partial<CellViewOptions> = {});
  
  // Core properties
  readonly cell: Entity;
  readonly graph: Graph;
  readonly container: Element;
  readonly priority: number;
  
  // Rendering lifecycle
  render(): this;
  update(partialAttrs?: CellAttrs): this;
  resize(): this;
  translate(): this;
  rotate(): this;
  confirmUpdate(flag: number, options: any): number;
  
  // Measurements and geometry
  getBBox(options?: { useModelGeometry?: boolean }): Rectangle;
  
  // Highlighting system
  highlight(elem?: Element, options?: CellViewHighlightOptions): this;
  unhighlight(elem?: Element, options?: CellViewHighlightOptions): this;
  
  // Interaction control
  can(feature: string): boolean;
  
  // Tool management
  addTools(config: any): this;
  removeTools(): this;
  updateTools(options?: any): this;
  
  // Event notification
  notify<K extends keyof CellViewEventArgs>(name: K, args: CellViewEventArgs[K]): this;
}

interface CellViewOptions {
  graph: Graph;
  priority: number;
  isSvgElement: boolean;
  rootSelector: string;
  bootstrap: FlagManagerActions;
  actions: KeyValue<FlagManagerActions>;
  events?: View.Events | null;
  documentEvents?: View.Events | null;
}

interface CellViewHighlightOptions {
  highlighter?: string | { name: string; args: KeyValue };
  type?: 'embedding' | 'nodeAvailable' | 'magnetAvailable' | 'magnetAdsorbed';
  partial?: boolean;
}

NodeView Class

Specialized view for rendering and managing node elements with port and embedding support.

/**
 * View class for node elements extending CellView
 */
class NodeView<Entity extends Node = Node> extends CellView<Entity> {
  // Port management
  findPortElem(portId?: string, selector?: string): Element | null;
  renderPorts(): this;
  updatePorts(): this;
  createPortElement(port: PortManager.Port): Element;
  
  // Embedding and delegation
  getDelegatedView(): NodeView | null;
  processEmbedding(e: any, data: any): void;
  autoOffsetNode(): this;
  
  // Rendering
  renderMarkup(): this;
  renderJSONMarkup(markup: any): this;
  updateTransform(): this;
  
  // Port system internals
  portsCache: { [portId: string]: { elem: Element; selector: string } };
  cleanPortsCache(): this;
  removePorts(): this;
  appendPorts(ports: PortManager.Port[], zIndex?: number, refs?: any): this;
}

EdgeView Class

Specialized view for rendering and managing edge elements with path calculation and label positioning.

/**
 * View class for edge elements extending CellView
 */
class EdgeView<Entity extends Edge = Edge> extends CellView<Entity> {
  // Connection and path management
  getConnection(): Path;
  updateConnection(options?: any): this;
  getConnectionLength(): number;
  getPointAtLength(length: number): Point;
  getPointAtRatio(ratio: number): Point;
  getClosestPoint(point: Point): Point;
  
  // Label management
  getLabelPosition(x: number, y: number, angle?: number, options?: any): Edge.LabelPosition;
  updateLabelPositions(): this;
  renderLabels(): this;
  normalizeLabelPosition(pos: any): Edge.LabelPosition;
  
  // Path calculation
  findPath(routePoints: Point[], sourcePoint: Point, targetPoint: Point): Path;
  findAnchors(vertices: Point[]): [Point, Point];
  findRoutePoints(vertices: Point[]): Point[];
  findConnectionPoints(
    routePoints: Point[],
    sourceAnchor: Point, 
    targetAnchor: Point
  ): [Point, Point];
  
  // Connection validation
  validateConnection(
    sourceView: CellView,
    sourceMagnet: Element,
    targetView: CellView,
    targetMagnet: Element
  ): boolean;
  
  // Arrowhead interaction
  prepareArrowheadDragging(type: 'source' | 'target', options?: any): void;
  dragArrowhead(e: MouseEvent, x: number, y: number): void;
  stopArrowheadDragging(e: MouseEvent, x: number, y: number): void;
}

ToolsView System

Tool management system for adding interactive tools to graph elements.

/**
 * Container view for managing element tools
 */
class ToolsView extends View<ToolsViewEventArgs> {
  constructor(options: ToolsViewOptions = {});
  
  // Configuration and lifecycle
  config(options: ToolsViewConfigOptions): this;
  update(options: ToolsViewUpdateOptions): this;
  
  // Focus management
  focus(focusedTool: ToolItem | null): this;
  blur(blurredTool: ToolItem | null): this;
  
  // Visibility control
  show(): this;
  hide(): this;
  mount(): this;
  
  // Tool management
  addTool(tool: ToolItem): this;
  removeTool(tool: ToolItem): this;
  findTool(toolName: string): ToolItem | null;
}

/**
 * Base class for interactive tools
 */
class ToolItem extends View<ToolItemEventArgs> {
  constructor(options: Partial<ToolItemOptions> = {});
  
  // Configuration
  config(view: CellView, toolsView: ToolsView): this;
  
  // Lifecycle
  render(): this;
  update(): this;
  
  // Visibility and focus
  show(): this;
  hide(): this;
  isVisible(): boolean;
  focus(): this;
  blur(): this;
}

interface ToolsViewOptions {
  tools?: (ToolItem | ToolItem.Config)[];
  className?: string;
  layer?: string;
}

interface ToolItemOptions {
  name?: string;
  className?: string;
  tagName?: string;
  children?: ToolItem[];
}

Event System

// View event arguments
interface CellViewEventArgs {
  'view:render': { view: CellView };
  'view:update': { view: CellView; flag: number };
  'view:resize': { view: CellView };
  'view:translate': { view: CellView };
  'view:rotate': { view: CellView };
}

interface NodeViewEventArgs extends CellViewEventArgs {
  'node:click': NodeViewPositionEventArgs<Dom.ClickEvent>;
  'node:dblclick': NodeViewPositionEventArgs<Dom.DoubleClickEvent>;
  'node:mouseenter': NodeViewPositionEventArgs<Dom.MouseEnterEvent>;
  'node:mouseleave': NodeViewPositionEventArgs<Dom.MouseLeaveEvent>;
  'node:mousedown': NodeViewPositionEventArgs<Dom.MouseDownEvent>;
  'node:mousemove': NodeViewPositionEventArgs<Dom.MouseMoveEvent>;
  'node:mouseup': NodeViewPositionEventArgs<Dom.MouseUpEvent>;
  'node:move': NodeViewPositionEventArgs<Dom.MouseMoveEvent>;
  'node:moved': NodeViewPositionEventArgs<Dom.MouseUpEvent>;
  'node:port:click': NodeViewPortEventArgs<Dom.ClickEvent>;
  'node:port:mouseenter': NodeViewPortEventArgs<Dom.MouseEnterEvent>;
  'node:port:mouseleave': NodeViewPortEventArgs<Dom.MouseLeaveEvent>;
}

interface EdgeViewEventArgs extends CellViewEventArgs {
  'edge:click': EdgeViewPositionEventArgs<Dom.ClickEvent>;
  'edge:dblclick': EdgeViewPositionEventArgs<Dom.DoubleClickEvent>;
  'edge:mouseenter': EdgeViewPositionEventArgs<Dom.MouseEnterEvent>;
  'edge:mouseleave': EdgeViewPositionEventArgs<Dom.MouseLeaveEvent>;
  'edge:mousedown': EdgeViewPositionEventArgs<Dom.MouseDownEvent>;
  'edge:mousemove': EdgeViewPositionEventArgs<Dom.MouseMoveEvent>;
  'edge:mouseup': EdgeViewPositionEventArgs<Dom.MouseUpEvent>;
  'edge:label:click': EdgeViewLabelEventArgs<Dom.ClickEvent>;
  'edge:label:mouseenter': EdgeViewLabelEventArgs<Dom.MouseEnterEvent>;
  'edge:label:mouseleave': EdgeViewLabelEventArgs<Dom.MouseLeaveEvent>;
}

// Base event argument interfaces
interface CellViewMouseEventArgs<E> {
  e: E;
  view: CellView;
  cell: Cell;
}

interface CellViewPositionEventArgs<E> extends CellViewMouseEventArgs<E> {
  x: number;
  y: number;
}

interface NodeViewPositionEventArgs<E> extends CellViewPositionEventArgs<E> {
  view: NodeView;
  node: Node;
}

interface EdgeViewPositionEventArgs<E> extends CellViewPositionEventArgs<E> {
  view: EdgeView;
  edge: Edge;
}

interface NodeViewPortEventArgs<E> extends NodeViewPositionEventArgs<E> {
  port: PortManager.Port;
  portId: string;
}

interface EdgeViewLabelEventArgs<E> extends EdgeViewPositionEventArgs<E> {
  label: Edge.Label;
  labelIndex: number;
}

Custom View Creation

Usage Examples:

Creating a custom node view with special rendering:

import { NodeView, Rectangle } from "@antv/x6";

class CustomNodeView extends NodeView {
  protected renderMarkup() {
    // Custom rendering logic
    return this;
  }
  
  protected onRender() {
    // Custom initialization after rendering
    this.updateCustomElements();
  }
  
  private updateCustomElements() {
    // Update custom visual elements
    const rect = this.findOne('rect');
    if (rect) {
      rect.setAttribute('rx', '10');
      rect.setAttribute('ry', '10');
    }
  }
}

// Register the custom view
NodeView.registry.register('custom-node-view', CustomNodeView);

Creating a custom tool for nodes:

import { ToolItem } from "@antv/x6";

class CustomTool extends ToolItem {
  render() {
    this.container.innerHTML = `
      <g class="custom-tool">
        <circle r="8" fill="blue" stroke="white" stroke-width="2"/>
        <text text-anchor="middle" dy="0.3em" fill="white">×</text>
      </g>
    `;
    return this;
  }
  
  protected onRender() {
    this.container.addEventListener('click', this.onToolClick.bind(this));
  }
  
  private onToolClick(e: MouseEvent) {
    // Handle tool interaction
    const { view } = this.options;
    view.cell.remove();
  }
}

// Use the custom tool
node.addTools([
  {
    name: 'custom-delete',
    args: { x: '100%', y: 0, offset: { x: -10, y: 10 } }
  }
]);

View Lifecycle

The view system follows a structured lifecycle:

  1. Construction: View is created with cell reference and options
  2. Initialization: init() method called for custom setup
  3. Rendering: render() creates DOM structure and calls renderMarkup()
  4. Updates: update() and confirmUpdate() handle attribute changes
  5. Interaction: Event handlers manage user interactions and tool integration
  6. Cleanup: onRemove() and dispose() handle cleanup before removal

The view system integrates seamlessly with X6's plugin architecture and provides the foundation for creating rich, interactive diagram applications.