Getting a node from draggingTool.draggedParts()

Hi

I may be being dim today, and I can’t intuit my way from a dragged part to the node data. Should be an easy one to answer I hope.

Scenario: A diagram with a node on it. I put the mousedown on the node, drag it a bit, then let the mouse up. I have subclassed the dragTool.doDeactivate() function. In that function I want to get the key for the dragged node, so I iterate on the draggedParts, as:

            var it = this.draggedParts.iterator;
            var obj = null
            while (it.next()) {
                obj = it.value;

                if ( obj instanceof go.Node   ) {
                        console.log('I am getting here ok!')

                    if (obj.data) {
                        console.log('I am NOT getting here')

                        console.log('node key=' + obj.data.key) // never happens
                    }

                }

            }  
            go.DraggingTool.prototype.doDeactivate.call(dragTool); // pass on to main tool

[Update] I have an alternative solution using the diagram ‘SelectionMoved’ listerner, however I am now even more curious how to make the above work since the diagram.selection is 'read-only collection of selected objects.’ via which one can get a handle to the first of the selected nodes via:

var obj = myDiagram.selection.iterator.first();

I guess I am struggling to understand the difference between the diagram.selection (evidently a collection of node references) and the draggedParts (defined in the docs as ‘a Map mapping Parts to DraggingInfo Objects’). By the way, this Google search of the docs site shows no hits for DraggingInfo outside the draggingTool page. - maybe worth documenting and throwing in a sample ?

Diagram.selection is a Set of the Parts that are currently selected.

DraggingTool.draggedParts is a Map that holds the Parts that are being dragged along with their original locations.

Given a Part, aPart.data will get you the node data object in the model to which the Part is data bound.

Thanks - so assuming the code below is inside the dragTool.doDeactivate() function, the value of theKey would be set to the value of the data.key of the node that the aPart is on ?

       var aPart= null, theKey = '';
       var it = this.draggedParts.iterator;
       while (it.next()) {
            aPart = it.value;
            theKey = aPart.data.key
       }

That is each dragged Part’s data.key, yes. Try it!

I thought I had - guess I had another self-induced bug. I have a workaround now but will try when I can and let you know.

ok - back on this as needed to subclass each step of the drag via dragTool.computeMove. Found a solution in this post from Punkie to do with dragging links.

Answer is to use draggedparts.iteratorKeys and not draggedParts.iterator

   var aPart= null, theKey = '';
   var it = this.draggedParts.iteratorKeys ;
   while (it.next()) {
        aPart = it.value;
        theKey = aPart.data.key
   }

Walter - there is no reference to iteratorKeys in the docs except on the Map page. Looking at the description of iterator, iteratorKeys and iteratorValues the latter two would appear to be shortcuts to values or keys of the iterator. I may be misunderstanding a core concept here, but it feels to me like there is a bug in how iterator instances are returned when dealing with the draggedParts map.

See minimal case in codepen for an example. At each computeMove call it tries to log the key of the dragged item via using iterator then iteratorKeys. It illustrates that iterator fails but iteratorKeys works as expected. As you can see from the codepen, the gojs version being used is http://gojs.net/latest/release/go-debug.js,

Finally, I used draggedParts,iterator having followed the pattern shown in the learn.collections docs here, where examples of how to use iterators are provided.

DraggingTool.draggedParts, DraggingTool | GoJS API, is documented to be of type Map, with the key type to be Part and the value type to be an Object with a “point” property. Of course JavaScript does not really have type declarations or generic types.

A better declaration is available in the TypeScript definition file, Page Not Found -- Northwoods Software, where the type is declared to be Map<Part,DraggingInfo>.

In either case Map.iterator will iterate over the key-value pairs in the map. So if you want to look at the Parts in the Map, you need to use Iterator.key, not Iterator.value.

But if you use Map.iteratorKeys, the Parts will be available as Iterator.value.

The way you wrote your code using Map.iterator you are looking at the DraggingInfo objects, which of course will not have the properties that Part has.

Thanks for replying on a weekend Walter.

I modified the codepen and the code below now works, full source for the computeMove included so it can be found by others.

// subclass the node drag process. Used to compute allowed drags.
var dragTool = myDiagram.toolManager.draggingTool;
dragTool.computeMove = function(n, newloc, draggedparts, result) {
  console.log('In drag to new location: ' + newloc)

  // Try iteratorKeys
  var aPart= null, theKey = '';
  var it = draggedparts.iteratorKeys;
  while (it.next()) {
    try { 
      aPart = it.value;
      theKey = aPart.data.key
      console.log('Ok using iteratorKeys: dragged key=' + theKey)
    }
    catch(err) {
      console.log('Error using iteratorKeys')     
    }
    
  }

  // Try iterator
  var aPart= null, theKey = '';
  var it = draggedparts.iterator;
  while (it.next()) {
    try { 
      aPart = it.key;
      theKey = aPart.data.key
      console.log('Ok using iterator: dragged key=' + theKey)
    }
    catch(err) {
      console.log('Error using iterator')     
    }
    
  }
  
  // pass control on to standard function
  var pt = go.DraggingTool.prototype.computeMove.call(dragTool, n, newloc, draggedparts, result);
  return pt;  
}

It felt like you made me work really hard for that little gem. I find the disparity of the key / value relationship in this case is confusing.

Sorry about that. The design was derived from Java and .NET.

Here’s some Java code for iterating over a Map:

Iterator entries = map.entrySet().iterator();
while (entries.hasNext()) {
  Entry thisEntry = (Entry) entries.next();
  Object key = thisEntry.getKey();
  Object value = thisEntry.getValue();
  // ...
}

or with generic types:

Iterator<Map.Entry<KeyType, ValueType>> entries = map.entrySet().iterator();
while (entries.hasNext()) {
  Map.Entry<KeyType, ValueType> entry = entries.next();
  KeyType key = entry.getKey();
  ValueType value = entry.getValue();
  // ...
}

If you want to iterate over only the keys, use Map.keySet(); if you want to iterate over only the values, use Map.values().

Here’s some .NET code:

Dictionary<KeyType, ValueType> dict = ...
foreach (var entry in dict) {
    var key = entry.Key;
    var val = entry.Value;
    // ...
}

If you want to iterate over only the keys, use IDictionary.Keys; if you want to iterate over only the values, use IDictionary.Values;

Of course GoJS, since it had to implement its own collection classes for JavaScript/EcmaScript 5, took the opportunity to use short names and to use properties. But we have added synonyms for the names used in ES6, as documented in each collection class description, even though the semantics are not exactly the same.

var it = map.iterator;
while (it.next()) {
    var key = it.key;
    var val = it.value;
}

Again, you can iterate over only the keys or only the values by using Map.iteratorKeys or Map.iteratorValues, but that’s infrequently necessary – they’re normally only used when passing an Iterator on to other methods.

Thanks.

May I suggest that the documentation in the docs intro section covering collections is updated to show that collections do not always return the same class of items in their keys & values ?

An example of how to iterate and get the nodes in a draggedParts collection, and any other edge-cases, should be included in the More Iteration Examples section on that page too if you can.

Also an example in the extensions area, perhaps using computeMove with part.minLocation and part.maxLocation - working code is always very welcome and great to learn from - part of what makes your docs so useful.

It would have been great in this case - would have saved us both the time taken in this post.

OK, thanks for the feedback.

I have updated my previous post to mention how in both Java and .NET there are ways of easily iterating over only the keys or only the values of a Map/Dictionary. And I’ve included an example of iterating over a Map in GoJS.

OK - appreciated. Lets call this thread over !

A post was split to a new topic: Drag and drop with TableLayout