or run

npx @tessl/cli init
Log in

Version

Tile

Overview

Evals

Files

docs

binding-animation.mdcore-diagram.mddata-models.mdgeometry-collections.mdgraphobject-hierarchy.mdindex.mdinteractive-tools.mdlayout-system.mdtheme-management.mdvisual-elements.md
tile.json

interactive-tools.mddocs/

Interactive Tools

GoJS provides a comprehensive tool system for handling user interactions like selection, dragging, linking, and editing. The tool system is managed by the ToolManager and provides both built-in tools and extensibility for custom interactions.

Capabilities

ToolManager extends Tool

Central coordinator for all diagram tools, managing tool activation and user input routing.

class ToolManager extends Tool {
  // Selection Tools
  clickSelectingTool: ClickSelectingTool;
  dragSelectingTool: DragSelectingTool;
  
  // Movement and Manipulation Tools
  draggingTool: DraggingTool;
  resizingTool: ResizingTool;
  rotatingTool: RotatingTool;
  
  // Link Tools
  linkingTool: LinkingTool;
  relinkingTool: RelinkingTool;
  linkReshapingTool: LinkReshapingTool;
  
  // Editing Tools
  textEditingTool: TextEditingTool;
  contextMenuTool: ContextMenuTool;
  
  // Navigation Tools
  panningTool: PanningTool;
  
  // Custom Tools
  mouseDownTools: List<Tool>;
  mouseMoveTools: List<Tool>;
  mouseUpTools: List<Tool>;
  
  // Timing and Behavior
  hoverDelay: number;
  toolTipDuration: number;
  standardMouseOver: (() => void) | null;
  standardMouseOut: (() => void) | null;
  
  // Input State
  currentTool: Tool;
  defaultTool: Tool;
  mouseDownPoint: Point;
  lastInput: InputEvent;
}

DraggingTool extends Tool

Handles moving parts by dragging with support for copying, grouping, and grid snapping.

class DraggingTool extends Tool {
  // Drag Behavior
  copiesEffectively: boolean;
  copiesTree: boolean;
  dragsTree: boolean;
  dragsLink: boolean;
  
  // Grid and Snapping
  isGridSnapEnabled: boolean;
  gridSnapCellSize: Size;
  gridSnapCellSpot: Spot;
  gridSnapOrigin: Point;
  
  // Drag State
  draggedParts: Map<Part, DraggingInfo>;
  copiedParts: Map<Part, Part>;
  
  // Validation
  mayMove(): boolean;
  mayCopy(): boolean;
  computeEffectiveCollection(parts: Iterable<Part>): Map<Part, DraggingInfo>;
  
  // Methods
  doActivate(): void;
  doMouseMove(): void;
  doMouseUp(): void;
  doDragOver(pt: Point, obj: GraphObject): void;
  doDropOnto(pt: Point, obj: GraphObject): void;
}

interface DraggingInfo {
  point: Point;
  part: Part;
}

LinkingTool extends Tool

Creates new links by dragging from one node to another with validation and visual feedback.

class LinkingTool extends Tool {
  // Link Creation
  temporaryLink: Link;
  temporaryFromNode: Node;
  temporaryFromPort: GraphObject;
  temporaryToNode: Node;
  temporaryToPort: GraphObject;
  
  // Behavior
  direction: LinkingDirection;
  portGravity: number;
  delay: number;
  
  // Validation
  isLinkValid(fromnode: Node, fromport: GraphObject, tonode: Node, toport: GraphObject): boolean;
  isUnconnectedLinkValid(link: Link): boolean;
  
  // Visual Feedback
  temporaryTool: Tool;
  archetypeLinkData: ObjectData;
  
  // Methods
  findLinkablePort(): GraphObject | null;
  insertLink(fromnode: Node, fromport: GraphObject, tonode: Node, toport: GraphObject): Link | null;
}

enum LinkingDirection {
  Either = 'Either',
  ForwardsOnly = 'ForwardsOnly',
  BackwardsOnly = 'BackwardsOnly'
}

ResizingTool extends Tool

Provides resize handles for changing part dimensions with aspect ratio and size constraints.

class ResizingTool extends Tool {
  // Handle Configuration
  handleArchetype: GraphObject;
  minSize: Size;
  maxSize: Size;
  
  // Resize Behavior
  cellSize: Size;
  isGridSnapEnabled: boolean;
  oppositePoint: Point;
  
  // State
  handle: GraphObject;
  adornedObject: GraphObject;
  originalBounds: Rect;
  
  // Methods
  updateAdornments(part: Part): void;
  resize(newr: Rect): void;
  computeResize(p: Point): Size;
  computeMinPoolSize(group: Group): Size;
}

TextEditingTool extends Tool

Handles in-place text editing with validation and custom editor support.

class TextEditingTool extends Tool {
  // Editor Configuration
  textBlock: TextBlock;
  defaultTextEditor: HTMLElement;
  starting: TextEditingStarting;
  state: TextEditingState;
  
  // Validation
  textValidation: ((tb: TextBlock, oldstr: string, newstr: string) => boolean) | null;
  
  // Events
  selectsTextOnActivate: boolean;
  
  // Methods
  doActivate(): void;
  acceptText(reason: TextEditingAccept): boolean;
  doMouseUp(): void;
  
  // State Management
  isActive: boolean;
  currentTextEditor: HTMLElement;
}

enum TextEditingStarting {
  SingleClick = 'SingleClick',
  SingleClickSelected = 'SingleClickSelected',  
  DoubleClick = 'DoubleClick'
}

enum TextEditingState {
  None = 'None',
  Active = 'Active',
  Editing = 'Editing'
}

enum TextEditingAccept {
  Enter = 'Enter',
  Tab = 'Tab',
  LostFocus = 'LostFocus',
  MouseDown = 'MouseDown',
  NotCancelled = 'NotCancelled'
}

Usage Examples:

// Configure text editing behavior
diagram.toolManager.textEditingTool.starting = go.TextEditingStarting.SingleClick;
diagram.toolManager.textEditingTool.selectsTextOnActivate = true;

// Custom text validation
diagram.toolManager.textEditingTool.textValidation = (tb, oldstr, newstr) => {
  // Limit text length and disallow empty strings
  return newstr.length > 0 && newstr.length <= 50;
};

Selection Tools

Tools for selecting parts using click or drag operations.

class ClickSelectingTool extends Tool {
  standardMouseSelect(): void;
  selectPart(part: Part, extend: boolean): void;
}

class DragSelectingTool extends Tool {  
  box: Part;
  delay: number;
  isPartialInclusion: boolean;
  
  computeBoxBounds(): Rect;
  selectInBox(r: Rect): void;
}

Usage Examples:

// Configure selection behavior
diagram.toolManager.clickSelectingTool.standardMouseSelect = function() {
  // Custom selection logic
  const part = this.findSelectableObject();
  if (part) {
    if (this.diagram.lastInput.control) {
      // Toggle selection with Ctrl
      part.isSelected = !part.isSelected;
    } else {
      // Normal selection
      this.diagram.select(part);
    }
  }
};

// Customize drag selection box
diagram.toolManager.dragSelectingTool.box = 
  new go.Part()
    .add(new go.Shape({
      name: 'SHAPE',
      fill: 'rgba(0,128,255,0.3)',
      stroke: 'blue'
    }));

Common Patterns

Custom Tool Implementation

class CustomClickTool extends go.Tool {
  constructor() {
    super();
    this.name = 'CustomClick';
  }
  
  canStart(): boolean {
    if (!super.canStart()) return false;
    
    const diagram = this.diagram;
    const e = diagram.lastInput;
    
    // Only start on double-click
    return e.clickCount >= 2;
  }
  
  doMouseUp(): void {
    const obj = this.diagram.findObjectAt(this.diagram.lastInput.documentPoint);
    if (obj && obj.part) {
      console.log('Double-clicked on:', obj.part.data);
      // Custom double-click logic here
    }
    
    this.stopTool();
  }
}

// Add custom tool to diagram
diagram.toolManager.mouseDownTools.insertAt(0, new CustomClickTool());

Tool State Management

// Check tool states
if (diagram.toolManager.draggingTool.isActive) {
  console.log('Currently dragging');
}

if (diagram.toolManager.textEditingTool.state === go.TextEditingState.Editing) {
  console.log('Currently editing text');
}

// Programmatically activate tools
if (diagram.toolManager.linkingTool.canStart()) {
  diagram.toolManager.linkingTool.doStart();
}

Tool Customization

// Customize dragging behavior
diagram.toolManager.draggingTool.isGridSnapEnabled = true;
diagram.toolManager.draggingTool.gridSnapCellSize = new go.Size(20, 20);
diagram.toolManager.draggingTool.copiesEffectively = true;

// Custom linking validation
diagram.toolManager.linkingTool.isLinkValid = function(fromnode, fromport, tonode, toport) {
  // Prevent linking to same node
  if (fromnode === tonode) return false;
  
  // Only allow certain node types to connect
  const fromType = fromnode.data.type;
  const toType = tonode.data.type;
  
  return (fromType === 'source' && toType === 'process') ||
         (fromType === 'process' && toType === 'sink');
};

// Custom resize constraints
diagram.toolManager.resizingTool.minSize = new go.Size(20, 20);
diagram.toolManager.resizingTool.maxSize = new go.Size(200, 200);