documentationfor yFiles for HTML 3.0.0.1

Commands

yFiles for HTML features a commanding infrastructure similar to that in other modern UI frameworks. This infrastructure provides a flexible mechanism for input handling. A command decouples an input event (resulting from an user interaction) from the actual logic that performs the corresponding action.

Commands effectively separate the invocation, interaction, and implementation from each other. A command is just an abstract concept of an interaction to perform, e.g. increase the zoom level, or copy to clipboard. The actual implementation for that command lies with the component it is invoked on as target. Commands are connected to their actual implementation via a command binding.

This also means that commands can become available or unavailable depending on how the GraphComponent is configured. For example, editing commands cannot be executed unless GraphEditorInputMode is set as the GraphComponent's input mode, because the implementation for those commands is part of the GraphEditorInputMode.

Commands in yFiles for HTML are of type Command and the command are managed by KeyboardInputMode.

The Executing commands on a target example shows how commands can be executed on a GraphComponent to increase the zoom level. The command is the Command.INCREASE_ZOOM, and it is matched by a command binding provided by default by the GraphComponent class.

Executing commands on a target
// Executes the INCREASE_ZOOM command on the GraphComponent.
// The parameter value given is optional and not provided, here, which means that a default value is
// chosen as the factor.
myGraphComponent.executeCommand(Command.INCREASE_ZOOM)

// Executes the INCREASE_ZOOM command on the GraphControl using the factor 2.
myGraphComponent.executeCommand(Command.INCREASE_ZOOM, 2)

The Predefined commands table shows the predefined commands from the command library classes and GraphComponent view implementation classes:

Predefined commands
Class Commands
CommandCommands for general application-related functionality such as clipboard support (CUT, COPY, and PASTE operations) and Undo/Redo support (UNDO and REDO operations), etc. Also commands for IGraph-related editing and navigation commands.
CanvasComponentThe view related commands FIT_CONTENT and UPDATE_CONTENT_BOUNDS.
GraphComponentCommands related to the current item in the canvas: FIT_GRAPH_BOUNDS, ZOOM_TO_SELECTION, SET_CURRENT_ITEM, and ZOOM_TO_CURRENT_ITEM operations.

Default command bindings are commonly provided by the GraphComponent (some of them by inheritance), but further bindings are added by several input modes like GraphEditorInputMode, GraphViewerInputMode, etc.

The following table lists some of the predefined command bindings.

Predefined command bindings
Class Provided Command Bindings
CanvasComponentCommand bindings for:
GraphComponent
GraphEditorInputModeCommand bindings for:
GraphViewerInputModeCommand bindings for selection: SELECT_ITEM, DESELECT_ITEM etc.
NavigationInputModeCommand bindings for keyboard actions to move/extend the selection and to move the focus indicator.
CreateEdgeInputModeCommand binding for BEGIN_EDGE_CREATION; only available if the input mode is installed in a CanvasComponent and enabled.

The other aspect of input handling, namely determining whether a command can be executed, is handled by the combination of command and command binding.

The following example shows how to test whether a command can be executed on a GraphComponent. You can use the result of this test to enable or disable a button in the UI, for example.

Determining availability of a command on a target
// Test whether the INCREASE_ZOOM command on the GraphComponent is available,
// respectively, whether it can be executed with the given parameter value.
const enableButton = myGraphComponent.canExecuteCommand(
  Command.INCREASE_ZOOM,
  2
)

Custom Command Bindings

Command bindings can be created programmatically and associated with the GraphComponent using the KeyboardInputMode class.

Adding a command binding to a GraphComponent can be done with the help of the KeyboardInputMode class:

Adding a command binding to a GraphComponent using KeyboardInputMode
// first create a handler function.
const logCommand = (command) => {
  console.log(command)
}
// Then, we create key bindings to connect the handler function with key gestures
keyboardInputMode.addKeyBinding('K', ModifierKeys.CONTROL, () =>
  logCommand('Go!')
)
keyboardInputMode.addKeyBinding(
  'K',
  ModifierKeys.CONTROL | ModifierKeys.SHIFT,
  () => logCommand('Go Back!')
)
// first create a handler function.
const logCommand = (command: string): void => {
  console.log(command)
}
// Then, we create key bindings to connect the handler function with key gestures
keyboardInputMode.addKeyBinding('K', ModifierKeys.CONTROL, () =>
  logCommand('Go!')
)
keyboardInputMode.addKeyBinding(
  'K',
  ModifierKeys.CONTROL | ModifierKeys.SHIFT,
  () => logCommand('Go Back!')
)

Commands and HTML Widgets

To enable easy usage of Commands in web apps, a simple pattern can be applied

Using Commands with Buttons
// create a new CommandAction using the zoom command
const button = document.getElementById('zoomOneToOneButton')
const command = Command.ZOOM
const parameter = 1
const target = myGraphComponent

// use our helper function to bind the button to the command
bindCommand(button, command, parameter, target)

// noinspection JSAnnotator
function bindCommand(button, command, parameter, targetCanvas) {
  // listen for possible changes
  targetCanvas.addEventListener('can-execute-changed', () => {
    if (targetCanvas.canExecuteCommand(command, parameter)) {
      button.removeAttribute('disabled')
    } else {
      button.setAttribute('disabled', 'disabled')
    }
  })

  // execute the command on click
  button.addEventListener('click', () => {
    if (targetCanvas.canExecuteCommand(command, parameter)) {
      targetCanvas.executeCommand(command, parameter)
    }
  })

  // set the initial state
  if (!targetCanvas.canExecuteCommand(parameter, target)) {
    button.setAttribute('disabled', 'disabled')
  }
}

// create a new CommandAction using the zoom command
const button = document.getElementById(
  'zoomOneToOneButton'
) as HTMLButtonElement
const command = Command.ZOOM
const parameter = 1
const target = myGraphComponent

// use our helper function to bind the button to the command
bindCommand(button, command, parameter, target)

// noinspection JSAnnotator
function bindCommand(
  button: HTMLButtonElement,
  command: Command,
  parameter: any,
  targetCanvas: CanvasComponent
): void {
  // listen for possible changes
  targetCanvas.addEventListener('can-execute-changed', () => {
    if (targetCanvas.canExecuteCommand(command, parameter)) {
      button.removeAttribute('disabled')
    } else {
      button.setAttribute('disabled', 'disabled')
    }
  })

  // execute the command on click
  button.addEventListener('click', () => {
    if (targetCanvas.canExecuteCommand(command, parameter)) {
      targetCanvas.executeCommand(command, parameter)
    }
  })

  // set the initial state
  if (!targetCanvas.canExecuteCommand(parameter, target)) {
    button.setAttribute('disabled', 'disabled')
  }
}

With this setup in place, clicking the widget finds the corresponding logic to execute the command on the target and invokes it as described above. Furthermore, the button will automatically be enabled or disabled depending on whether the command can currently be executed or not.

Command bindings can also be added using KeyboardInputMode's method addCommandBinding. Using the KeyboardInputMode has the advantage that commands are automatically disabled when the input mode is disabled, e.g. during a layout animation.