Question About Tools

I have a question about tools. Can more than one mousemove/dragging tool operating simultaneously?

Consider the GuidedDraggingTool used in conjunction with the NodeLableDraggingTool

Does only the first tool that satisfies the canStart predicate win or do all tools that satisfy canStart execute in order?

Is there an example you can point me to?

Thanks!

No, there can be only one Diagram.currentTool. Yes, only the first Tool whose Tool.canStart predicate returns true will be started as the Diagram.currentTool by the ToolManager.

When that tool stops, the Diagram.currentTool is normally replaced by the Diagram.defaultTool, which is normally the ToolManager, allowing another tool to be chosen to start running.

I suppose you could customize the NodeLabelDraggingTool to call the methods of the GuidedDraggingTool to show and hide guide-lines. The main problem is that the NodeLabelDraggingTool is dragging a simple GraphObject that is a label of a Node, not a whole Node, so some of the methods of GuidedDraggingTool won’t be effective.

OK, now that I understand that. I would like to automatically switch dragging tools based on the entity being dragged.

Consider the pipes example and the planogram example in the same diagram. When a pipe is selected the pipe SnappingTool should be active. When a planogram shape item is dragged the normal grid snapping behaviour should be active.

Is there an appropriate way to implement this?
I have tried setting the canStart() methods on the tools but find the adornedObject to be unreliable as a means by which to obtain the dragged object.

Is there a dragging tool switching example?
Thanks again.

Yes, you could have both instances of tools in the ToolManager.mouseMoveTools list, where their Tool.canStart predicates have been overridden so that one is only chosen when the user has selected parts appropriate for that tool. Actually, in your case you could override findDraggablePart to return either what it would normally return, or null if it’s not the kind of Node that you want that tool to handle.

var snaptool = new SnappingTool();
snaptool.findDraggablePart = function() {
    var part = go.DraggingTool.prototype.findDraggablePart.call(snaptool);
    if (part is a pipe ...) return part;
    return null;
};
myDiagram.toolManager.mouseMoveTools.insertAt(1, snaptool);

var dragtool = myDiagram.toolManager.draggingTool;  // the standard one
dragtool.findDraggablePart = function() {
    var part = go.DraggingTool.prototype.findDraggablePart.call(dragtool);
    if (part is a planogram item ...) return part;
    return null;
};

OK that works quite nicely for the dragging tools. How about the resizing tools. I can’t seem to find a way to distinguish the item being resized. The adornedObject is always null as is the lastInput.targetObject.

Thanks again!

Are you asking about ResizingTool.adornedObject? Are you looking at that value during your override of canStart?

Tool.canStart is just supposed to return true or false – it does not have the responsiblity of modifying any state such as the ResizingTool.adornedObject. That should only happen when the ResizingTool is activated – in ResizingTool.doActivate.

So if you have two separate ResizingTools you’ll need to override ResizingTool.canStart to return true only in the appropriate conditions. Here’s the definition of that method, which you can adapt for your own needs:

ResizingTool.prototype.canStart = function() {
  if (!this.isEnabled) return false;
  var diagram = this.diagram;
  if (diagram === null || diagram.isReadOnly) return false;
  if (!diagram.allowResize) return false;
  if (!diagram.lastInput.left) return false;

  var h = this.findToolHandleAt(diagram.firstInput.documentPoint, this.name);
  return (h !== null);
};

Understood but how does one differentiate the resizing object in order to determine the appropriateness of the tool?

.prototype.canStart = function() {
  if (!this.isEnabled) return false;
  var diagram = this.diagram;
  if (diagram === null || diagram.isReadOnly) return false;
  if (!diagram.allowResize) return false;
  if (!diagram.lastInput.left) return false;

  var h = this.findToolHandleAt(diagram.firstInput.documentPoint, this.name);
//Apply some differentiation here to determine if this resizing tool is appropriate for the 
//selected/resizing object.
//this.adornedObject is always null. I was hoping I could just check the category of the 
//adornedObject but no joy.
  return toolIsAppropriateForSelectedObject;
};

I think I got it figured out. This is how I did it:

        MyTool.prototype.canStart = function() {
            if (!this.isEnabled) return false;
            var diagram = this.diagram;
            if (diagram === null || diagram.isReadOnly) return false;
            if (!diagram.allowResize) return false;
            if (!diagram.lastInput.left) return false;

            var h = this.findToolHandleAt(diagram.firstInput.documentPoint, this.name);
            if (h === null) return false;
            var part = diagram.findPartAt(diagram.firstInput.documentPoint, true);
            if (part === null) return false;
            return (part.category == "SomeThing" );
        };`

Is there a better way?
How come we cannot count on adornedObject here?

Tool.canStart is just supposed to return true or false – it does not have the responsiblity of modifying any state such as the ResizingTool.adornedObject. That should only happen when the ResizingTool is activated – in ResizingTool.doActivate.

return h.part.adornedPart.category === ...