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:
Click blank area in diagram to focus overall diagram
Press any arrow key
First node is selected and therefore focused (this is intentionally coded in findNearestPartTowards)
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);
}
},
. . .
});