Change not within a transaction

Hi,

I’m having two problems:

—PROBLEM 1—

I recently started using go-debug and came across an unexplainable message.

When loading a model i get this message:

Change not within a transaction: !d points: Link#1650(55e97ba1c9942a0a287cebf5) old: List(Point)#1697 new: List(Point)#1737

I am setting points on the links, and have a binding to them, so i thought i might have made an error somewhere. I spent the day trying to solve the message but with no result. I deleted the bindings and points properties (in data) of the links but still get the message. Could this be a bug in gojs?

—PROBLEM 2—

I wanted to have my nodes act as a group, so i changed my nodetemplate to a group template. all is working well, only the links started acting differently after the change.The links are connected to the node (group) with ports.

Here is what my grouptemplate looks like:

$(go.Group, 'Table', {
  locationObjectName: 'BODY',
  selectionObjectName: 'BODY',
  resizable: true, 
  resizeObjectName: 'BODY', 
  dragComputation: _this.get('objectDragged'),
  mouseDrop: //logic that binds or unbinds an object to the group
  containingGroupChanged: //logic to change the appearance and location of the object
  mouseOver: //logic to set some variables on the object
  mouseDragEnter:  //logic to change the appearance of the object
  mouseDragLeave: //logic to change the appearance of the object
  memberValidation: //logic to validate member
  memberAdded: //logic to change the appearance of the object, and appearance and location of the memberparts
  memberRemoved: //logic to change the appearance of the object, and appearance and location of the   memberparts
},
new go.Binding('location', 'loc', go.Point.parse).makeTwoWay(go.Point.stringify),
new go.Binding('cursor'),
new go.Binding('groupable', 'group', function(v) { return !v; }),

$(go.Panel, 'Table', {
  row: 1, column: 1, name: 'BODY', stretch: go.GraphObject.Fill, minSize: new go.Size(10,10), width: 206 },
  new go.Binding('desiredSize', 'size', function(v) { if (v && v !== '0 0') { return go.Size.parse(v); } }).makeTwoWay(go.Size.stringify),
new go.Binding('background', 'color'), 

  $(go.Panel, 'Auto', { row: 1, column: 1, stretch: go.GraphObject.Fill, },
    $(go.TextBlock,  {  margin: 10, wrap: go.TextBlock.WrapFit }, 
      new go.Binding('text', 'object_title'), 
      new go.Binding('stroke', 'font'))
    ), //end of the main panel

    $(go.Panel, 'Vertical', { row: 1, column: 2, stretch: go.GraphObject.Fill, width: 18, margin: 2 },
       $(go.Picture, new go.Binding('source', 'source'))
    )  // end of right panel
  ), //end of body, consists of a main panel containing a shape and a textblock and a small panel located right for the image
  this.getPortTemplate($, 'top'),
  this.getPortTemplate($, 'bottom'),
  this.getPortTemplate($, 'left'),
  this.getPortTemplate($, 'right')
); // end of nodeTemplate

The problem i’m having is when i resize a node, the links will change their location, and are not connected anymore to the ports…

also i’m getting a lot of these errors when loading:
Uncaught Error: Link.setPointAt:x must be a real number type, and not NaN or Infinity: NaN

and also these:
Uncaught Error: Non-real measuredBounds has been set. Object Shape(None)#37423, measuredBounds: Rect(-6,-6,NaN,NaN)

I cannot tell what your app is doing, so I cannot tell where the bug lies. Samples that save link routes by having a TwoWay Binding on Link.points don’t seem to have this problem. See for example the Draggable Link sample.

The second error you encounter is also quite unusual and unexpected to us. Certainly if there is an error occurring, that might prevent the default routing behavior from happening. Could you provide a minimal app by which we could reproduce the problem? Or modify an existing sample to produce the error?

Okay, i’ll try and find out why this is happening. in the meantime (since it’s almost releasetime again) is it possible to end and clear all transactions? then i can at least start with a clean slate, since it only happens at the initial loading.

yes, here you go.

Before instead of creating a go.Group i had a go.Node. There we no problems there but since i made it into a Group i started to have problems with nodes that have a link from and to itself.

If you resize the group the link will stay in place, only if you change the left side it moves (but not as it should though). If you relink the link afterwards it’ll be placed as it should

Yes, I see the difference in link route invalidation behavior between a Node and a Group with basically the same template.

I’m not sure I will have time to investigate this tomorrow, but I will pursue the issue.

OK, I think we have fixed this for version 1.5.11, which should be coming out next week. You can try it now at GoJS - Build Interactive Diagrams for the Web.

Hi Walter,

Thanks for your reply. The beta version does fix the link invalidation when resizing, but it doesn’t work when i set the size externally. The nodes in my program can be dropped onto other nodes, and change their size accordingly. When i drop it, and the size changes, the link will still not be drawn correctly. This also is the case when i set the location and the size of multiple nodes that have a link between them.

Tim

This is a modification of your codepen, I’ve made a few changes:

I marked the JS code with // !!! where I changed:

  • the node has a “lime” background so I can more easily see the transparent parts of it
  • I added a button and an event handler to resize the node programatically since I think that’s what you meant by “Set the size externally”
  • I changed the <script> tag to point to the beta branch of GoJS, where the provisional 1.5.11 is built right now

Everything seems to be working as I’d expect. Can you show me the issue you were encountering?

Version 1.5.11 is now “latest”. The library has changed since the beta version that I posted about a few days ago.

ok, so i found out where it went wrong…

Like i said, i change the appearance of the node when i drop it onto a group. I do this in the ‘containingGroupChanged’ event. When i drop it i change the location and the size of the node. (only) if it has a link to itself or another node that is being dropped onto the group, then the links will still be drawn incorrect. If i postpone these changes to the next run loop, then the links will be drawn correctly. I don’t know if this is a bug, or a defect in my code, but this solves it for me.

I still have the next error though, sometimes even in an endless loop.

‘Change not within a transaction: !d points: Link#28866(560bc482c9942a06a09ad0f0) old: List(Point)#266029 new: List(Point)#266138

Is there absolutely no way to find out where this message is coming from using go-debug? I’ve searched heaven and earth to find the problem but i still can’t find it.

That’s not an error message – just a warning that maybe things aren’t happening when you want them to. Usually it’s because you forget to perform some change within a transaction. So, if you are modifying things when you “postpone these changes to the next run loop”, are you performing those changes in a transaction?

I’m more concerned about “sometimes even in an endless loop”. Can you characterize the situation so that we can reproduce the problem?

Hi Walter,

Yes i know it’s not an error, but i have the feeling the origin of this message is causing bugs in my application. I tried to ignore it at first (leave it for another time) but then i got the endless loop… I checked all my code and everything happens in a transaction. I’m quite sure the message is thrown when the graphlinksmodel is being set

For now i’ll explain whats happening as detailed as possible:

I have a simple diagram with a node that has a link to itself. The link goes from port_0 on the right side to port_0 on the bottom. All the sides of the node are filled with ports.
The link routing is go.Link.Normal and i have a binding with the points property, which is saved as an array of doubles, though in this case, the points array is empty.
I added debug logs to try and show the flow of my code, this is wat is logged when i load my diagram

Next i create a new node and make a link between the two nodes, as you can see, all seems to be well

When i reload the diagram after saving the changes again the ‘transaction’ messages are shown (this was a test to see if it only happens to links that fo from and to the same node)

— INFINITE LOOP —

So the problem with the infinite loop is quite specific. I’m working on the next functionality which is that nodes can be dropped onto other nodes. The node that it is dropped on now functions as a group (although now all the nodes are groups, so nothing changes in the node, only the memberparts and the containinggroup).

When the node is dropped on to an other node, the size will be set according to the size of the node that it is dropped on, als the location will be set (this was the problem i was talking about earlier). This all works fine now, only there is this one specific case. When a node has a link with the group AND with a node that is a member of the group, the points property will be endlessly updated, as you can see in the console

and it goes on and on…

— OTHER STUFF —

What i find really strange is that only sometimes this warning is thrown, when i do a mousedown after loading a diagram, which also disappears at some point

WARNING: In ToolManager.doMouseDown: UndoManager.transactionLevel is not zero

Another thing that i can’t figure out is what type of object this is, this is how the points are stored in the link.data

{
  __gohashid:3210,
    Ja:true,
    p:[{L:-46,M:-337.5,Ja:true},
       {L:-36,M:-337.5,Ja:true},
       {L:-36,M:-182,Ja:true},
       {L:-251,M:-182,Ja:true},
       {L:-251,M:-300,Ja:true},
       {L:-251,M:-310,Ja:true}],
    Y:6,
    Kd:null,
    eo:null
}

Thanks for the detailed information.

I just tried reproducing the basic situation by modifying the Regrouping Demo sample, so that one can draw reflexive links and duplicate links, and so that the links are routed Orthogonally and their “points” are TwoWay bound to the model link data. This involved reflexive links and links from member nodes to the containing Group, too.

Everything worked without any “transactionLevel is not zero” messages. And no infinite loops either.

How are your event handlers defined?

Walter, i found out why i get the messages about the link points. I hope it will also solve the infinite loop, i’m guessing it will.

I made a codepen: http://codepen.io/timdegore/pen/gadROE?editors=001

What’s happening is (and it seems that it is a bug, but maybe its a configuration issue in my nodetemplate) is that the picture that is part of my node causes the link points to recalculate (or something like that).

If you open the codepen and press the ‘add node and link’ button, you see the message in the console. If you set the undomanager.isEnabled to false, or remove the picture from the node, the message won’t show.

Tim

—EDIT—

Unfortunately this didn’t fix the endless loop problem… If i set the undomanager.isEnabled to false it doesn’t loop anymore, but i want to keep the undomanager enabled.

This is my event handler for the containingGroupChanged event:

function(part) {
  var group = part.diagram.findNodeForKey(part.data.group);
  var groupWidth, loc, nodeHeight, groupTitleHeight, groupMembersHeight, nodeWidth;

  if (group) {
    groupWidth = group.measuredBounds.width;
     loc = go.Point.parse(group.data.loc);
    nodeWidth = (groupWidth - _this.get('padding') * 2);
    nodeHeight = parseInt(part.data.size.split(' ')[1]);
    groupTitleHeight = _this.get('padding') + _this.getTitleHeight(group.data.object_title);
    groupMembersHeight = _this.getMemberHeight(group, part);	
  }

  Ember.run.next(function() {
    if (_this.get('hasRendered')) {
      part.diagram.startTransaction('setColor');
      part.groupable = !part.data.group;
      if (group) {
        _this._resizePartOnDataChange(nodeWidth, nodeHeight, part);
        part.resizeObject.desiredSize = new go.Size(nodeWidth, nodeHeight);
        part.diagram.model.setDataProperty(part.data, 'loc', (loc.x + _this.get('padding')) + ' ' + (loc.y + groupMembersHeight + groupTitleHeight));
        part.diagram.model.setDataProperty(part.data, 'group', group.data.key);
      }
      part.resizable = !part.data.group;
      part.diagram.model.setDataProperty(part.data, 'color', !part.data.group ? part.data.primaryColor : part.data.secondaryColor);
      part.diagram.model.setDataProperty(part.data, 'font', !part.data.group ? part.data.primaryFont : part.data.secondaryFont);
      part.diagram.commitTransaction('setColor');
     _this.get('partialUpdateModel').update(part.data);
     _this.hideTooltips();
    }
 });

The asynchronous loading of Picture images would explain the not-in-transaction messages, but not the infinite loop.

We recommend that you specify Picture.desiredSize or otherwise constrain its size so that the size is not dependent on the image size.

I suspect that the infinite loop is caused by trying to modify the size of the node, which causes the containing group to be resized. It would be more natural to have the Group.layout be a custom Layout that does what you want.

I’ll do that, i’m guessing that should work without problems

Sounds logical. I already tried to set a layout, but since i already had this functionality working as it is now (at least i thought) i kept it as an improvement possibility.

I hope the problems are now solved, if anything changes i’ll let you know. Thanks for all the help!

Sorry for digging out this old thread, I had the same problem with the asynchronous loading of Picture images (warning in the console).

Is there any other way to solve this? I generate the node template from an XML with the image being provided as a base64 encoded string. Currently I don’t know the size of the images upfront. I could add height and width properties to the XML or use some way to determine the size of the image (jquery - Get image width and height from the Base64 code in JavaScript - Stack Overflow) but I’d rather just ignore the warnings as they don’t have any negative side effect?

If the Picture is inside a Panel with a fixed width and height, that should be OK. We should review this situation and see if we can handle it better.

@Dominic.Lerbs can you state exactly what your problem is? Is it only the console messages, or is this breaking something else for you too?

Well I thought my problem were only the console warnings which make it more difficult to spot the “important” warnings.
However, it also seems to have an effect on the bounds calculation:
I need to get the bounds of all nodes in the diagram (diagram.computePartsBounds(diagram.nodes)).
If I calculate the bounds directly after creating the diagram, the size of the images seem not to be considered, therefore the calculated bounds are smaller than they should be. If I recalculate the bounds a while after the diagram has been created, they are being calculated correctly.

Unfortunately, I don’t know the image sizes at compile time. So I guess I need to use one of the two options mentioned above to determine the actual image size, or set a fixed width/height at compile time?

Yes, we have to re-measure after the image asset is loaded because of the new sizing information. There’s no way around that, unless you are using some library that loads the image assets first, and then creates the Diagram. If its important for your app, I’d suggest doing something like that.

If all images are the same size, you could load only one, to get its width/height, then set the desiredSize in the template and load.