CommandHandler while node is focused

I’m trying to follow the example at Drawing Commands with arrow mode ‘Select’.

In that example, it seems that it captures keyboard input even after a node is selected. However, in my case, it only captures the first keyboard input and no subsequent inputs. I think it’s because the diagram is not focused anymore since the node got selected, as described in GoJS Commands -- Northwoods Software

Please note that the handling of keyboard commands depends on the diagram getting focus and then getting keyboard events

But it wouldn’t make sense that the example works then. So I’m not sure what I’m doing differently. Here’s a snippet of my code, very similar to the example:

	goJsDiagram.commandHandler.doKeyDown = function() {
		var e = goJsDiagram.lastInput;
		// The meta (Command) key substitutes for "control" for Mac commands
		var control = e.control || e.meta;
		var key = e.key;
		var nextPart = null;
		if (e.key === "Up") {
		  nextPart = findNearestPartTowards(270, goJsDiagram);
		} else if (e.key === "Down") {
		  nextPart = findNearestPartTowards(90, goJsDiagram);
		} else if (e.key === "Left") {
		  nextPart = findNearestPartTowards(180, goJsDiagram);
		} else if (e.key === "Right") {
		  nextPart = findNearestPartTowards(0, goJsDiagram);
		}
		if (nextPart !== null) {
		  if (e.shift) {
			nextPart.isSelected = true;
		  } else if (e.control || e.meta) {
			nextPart.isSelected = !nextPart.isSelected;
		  } else {
			goJsDiagram.select(nextPart);
		  }
		}

		// call base method with no arguments (default functionality)
		go.CommandHandler.prototype.doKeyDown.call(this);
	};

When you actually handle the key (in this case changing the selection), you do not want to call the super method. Your code is always calling the super method.

Thanks for catching that! I put it in an else so that it only calls if nextPart was not found. However, even if I remove that line entirely, I still have the problem in this sequence:

  1. Click blank area in diagram to focus overall diagram
  2. Press any arrow key
  3. First node is selected and therefore focused (this is intentionally coded in findNearestPartTowards)
  4. Press any arrow key
  5. Nothing happens, doKeyDown is not fired

The code does not select a node if none is already selected.

I don’t have any problems when I try this code:

function _findNearestPartTowards(dir, diagram) {
  var originalPart = diagram.selection.first();
  if (originalPart === null) return null;
  var originalPoint = originalPart.actualBounds.center;
  var allParts = diagram.nodes;
  var closestDistance = Infinity;
  var closest = originalPart;  // if no parts meet the criteria, the same part remains selected

  for (var it = allParts; it.next(); ){
    var nextPart = it.value;
    if (nextPart === originalPart) continue;  // skips over currently selected part
    var nextPoint = nextPart.actualBounds.center;
    var angle = originalPoint.directionPoint(nextPoint);
    var anglediff = _angleCloseness(angle, dir);
    if (anglediff <= 45) {  // if this part's center is within the desired direction's sector,
      var distance = originalPoint.distanceSquaredPoint(nextPoint);
      distance *= 1+Math.sin(anglediff*Math.PI/180);  // the more different from the intended angle, the further it is
      if (distance < closestDistance) {  // and if it's closer than any other part,
        closestDistance = distance;      // remember it as a better choice
        closest = nextPart;
      }
    }
  }
  return closest;
}

function _angleCloseness(a, dir) {
  return Math.min(Math.abs(dir - a), Math.min(Math.abs(dir + 360 - a), Math.abs(dir - 360 - a)));
}

function init() {
  const $ = go.GraphObject.make;

  myDiagram =
    $(go.Diagram, "myDiagramDiv",
      {
        "commandHandler.doKeyDown": function() {
            var e = this.diagram.lastInput;
            // The meta (Command) key substitutes for "control" for Mac commands
            var control = e.control || e.meta;
            var key = e.key;
            var nextPart = null;
            if (e.key === "Up") {
              nextPart = _findNearestPartTowards(270, this.diagram);
            } else if (e.key === "Down") {
              nextPart = _findNearestPartTowards(90, this.diagram);
            } else if (e.key === "Left") {
              nextPart = _findNearestPartTowards(180, this.diagram);
            } else if (e.key === "Right") {
              nextPart = _findNearestPartTowards(0, this.diagram);
            }
            if (nextPart !== null) {
              if (e.shift) {
                nextPart.isSelected = true;
              } else if (e.control || e.meta) {
                nextPart.isSelected = !nextPart.isSelected;
              } else {
                this.diagram.select(nextPart);
              }
            } else {
              // call base method with no arguments (default functionality)
              go.CommandHandler.prototype.doKeyDown.call(this);
            }
          },
        . . .
      });