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.
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;
}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;
}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;
}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[];
}// 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;
}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 } }
}
]);The view system follows a structured lifecycle:
init() method called for custom setuprender() creates DOM structure and calls renderMarkup()update() and confirmUpdate() handle attribute changesonRemove() and dispose() handle cleanup before removalThe view system integrates seamlessly with X6's plugin architecture and provides the foundation for creating rich, interactive diagram applications.