[1.8] Updating model from server data has inconsistent events

I’ve found a way to detect if it’s from the initial form loading. This was not a fun one to track down - I hate issues that happen randomly!

So @Walter we’ve figured out a sure-fire way to make our problem happen. As soon as clicking the button that makes the REST call, if you move you mouse (or trackpad) quickly over the diagram, the problem happens. If you click the button and do nothing it doesn’t happen.

I need to do more investigating but any idea on what could be going on with the diagram with the mouse moving fast vs slow? I know it’s strange but something with moving a mouse fast when getting new model data causes our diagram problem.

Moving the mouse over the diagram causes it to look for any Parts that should get mouseEnter and mouseLeave events. And maybe other things like that.

Are you saying that the problem occurs only the first time that the page (or HTML panel, holding the Div for the Diagram) is loaded? And not when just replacing the Diagram.model or modifying the model?

It happens on initial model load and also any updates after that. Our node template does have mouse events.


                    make(go.Shape, 'Circle', {
                            name: 'LINKHANDLE',
                            portId: '',
                            height: me.circleSize,
                            width: me.circleSize,
                            fromLinkable: true,
                            toLinkable: true,
                            strokeWidth: 0,
                            fill: 'transparent',
                            fromLinkableSelfNode: true,
                            toLinkableSelfNode: true,
                            fromLinkableDuplicates: true,
                            toLinkableDuplicates: true,
                            cursor: 'pointer',
                            mouseOver: me.mouseOverNode,
                            mouseLeave: me.mouseLeaveNode
                        },
                        new go.Binding('fill', 'stateColor')
                    ),

...
    mouseOverNode: function(e, obj) {
        obj.fillSave = obj.fillSave || obj.fill;
        obj.fill = '#999';
    },

    mouseLeaveNode: function(e, obj) {
        obj.fill = obj.fillSave;
    }

Now the previous problem of “Initial Layout” ModelChanged event randomly not getting called appears to be fixed as it fires when the fast mouse problem happens. I still wonder if these warnings when updating the model might be the problem? Thing is if I put a transaction around the model update it says don’t change model in a transaction.

[Log] Change not within a transaction: !d isTreeLeaf: 540:TEST  old: false  new: true (go-debug.js, line 35)
[Log] Change not within a transaction: !d isTreeLeaf: 538:TEST  old: false  new: true (go-debug.js, line 35)
[Log] Change not within a transaction: !d isTreeLeaf: 539:TEST  old: false  new: true (go-debug.js, line 35)
[Log] Change not within a transaction: !d isTreeLeaf: 537:TEST  old: false  new: true (go-debug.js, line 35)
[Log] Change not within a transaction: !d isTreeLeaf: 535:TEST  old: false  new: true (go-debug.js, line 35)
[Log] Change not within a transaction: !d isTreeLeaf: 536:TEST  old: false  new: true (go-debug.js, line 35)

Is there something I should do to the Diagram before updating the model?

I would love to be able to make a reproducible example but our application is 700 JavaScript files and I never have luck making an example.

Walter here’s a simple question. Since we’re on 1.8 how much work should it be to try 2.1? Don’t know if that will fix our problem but this one is so weird I’m willing to try!

Try it. Chances are the only problem you’ll encounter are undefined Shape figures. Read the https://gojs.net/latest/changelog.html.

Some simple tests and it dropped in just fine. It does give more details that I’m going to look into. First it doesn’t like our Auto Panel with multiple children - could that be the problem? Also it gives more details on what is causing the change not within a transaction. We do modify the points after a server read since our data doesn’t store start and end points. I do create a transaction for this but maybe there’s somewhere else we’re modifying points and not creating a transaction. My guess the List/Map/Set warning isn’t causing a problem but I’ll fix that.

[Log] Auto, Spot, or Graduated Panel should not have zero or one elements: Panel([object Object])#534 in Node#537 (go-debug.js, line 14)
[Log] InitialLayoutCompleted (AbstractModelerController.js, line 130)
[Log] updatingModel – "Initial Layout" (AbstractModelerController.js, line 193)
[Log] Warning: List/Map/Set constructors no longer take an argument that enforces type.Instead they take an optional collection of Values to add to the collection. See 2.0 changelog for details. (go-debug.js, line 15, x8)
[Log] Change not within a transaction: !d position: 377:TEST  old: Point(362.0728165276795,138.9416034424153)  new: Point(362.8684722395101,138.20264500312663) (go-debug.js, line 14)
[Log] Change not within a transaction: !d position: 372:TEST  old: Point(258.7942407357911,147.8457184292247)  new: Point(260.4037856592116,148.10427500435998) (go-debug.js, line 14)
[Log] Change not within a transaction: !d position: 373:TEST  old: Point(261.4958300223222,147.8457184292247)  new: Point(275.7785805171748,106) (go-debug.js, line 14)
[Log] Change not within a transaction: !d position: 374:TEST  old: Point(353.438633445903,146.57435090054173)  new: Point(346.72036474213047,148.3023302951565) (go-debug.js, line 14)
[Log] Change not within a transaction: !d position: 375:TEST  old: Point(352.86712942310254,145.41936865533262)  new: Point(373.34991803896384,97) (go-debug.js, line 14)
[Log] Change not within a transaction: !d position: 370:TEST  old: Point(161.730098890795,144.50795440063587)  new: Point(158.20468442624153,142.36474510664578) (go-debug.js, line 14)
[Log] Change not within a transaction: !d position: 371:TEST  old: Point(164.79063843848886,143.49859253887178)  new: Point(170.8397738507141,113) (go-debug.js, line 14)
[Log] Change not within a transaction: !d position: 376:TEST  old: Point(364.1273997190738,141.2460733737131)  new: Point(361.884408696545,143.08626009937916) (go-debug.js, line 14)

No, the empty Panel warning and the collection constructor warning shouldn’t be a problem – just an indication of a template design and some code that you could clean up.

Can’t you modify the points before assigning the data to the model?

This would take a fair amount of code reworking but something I might eventually try.

The change not in transaction is what I’m currently trying to track down. Since our data model is 20+ years old and way before we started using GoJS we only store midpoints and not start and end points. In the “Initial Layout” ModelChanged event I add them. As you can see below the array originally had 1 point and the start and end points were added so now 3. The data all looks good then after the transaction is committed the change not within a transaction log happens. This model has only 1 link with key 390:TEST but those points values in the log don’t match anything that I just added. Could GoJS be changing the points here? I can’t find anywhere in our code that we’re doing that.

What would be really helpful is a way have GoJS print a stack trace on logs. Is that possible?

[Log] startTransation updatePoints (AbstractModelerController.js, line 265)
[Log] adding start/end points (2) (AbstractModelerController.js, line 286)
Array (1)
0 "Point(196,174)"

Array Prototype
Array (3)
0 "Point(140.5272165851675,233.12230863949253)"
1 "Point(196,174)"
2 "Point(285.5921229253661,155.93100041841356)"

Array Prototype
[Log] commitTransation updatePoints (AbstractModelerController.js, line 289)
[Log] Change not within a transaction: !d position: 390:TEST  old: Point(145.41413299766526,160.26087474140076)  new: Point(139.5272165851675,150.72508132786822) (go-debug.js, line 14)

Here’s the code where I’m adding the points. If there are no midpoints then I don’t add the start/end since it appears GoJS handles a link with no points just fine.

        if (e.oldValue === 'Initial Layout') {
            var oldPoints = [];
            var newPoints = [];
            goDiagram.startTransaction('updatePoints');
            console.log('startTransation updatePoints')
            Ext.each(changes, function(change) {
                midpoints = change.midpoints;
                if (midpoints.length > 0) {
                    points = new go.List();
                    link = diagram.goDiagram.findLinkForData(e.model.findLinkDataForKey(change.key));
                    node = diagram.goDiagram.findNodeForKey(change.from);
                    point = link.getLinkPointFromPoint(node, node.port, node.port.getDocumentPoint(go.Spot.Center), midpoints[0], true);
                    points.add(point);
                    newPoints.push(point.toString());
                    Ext.each(midpoints, function(midpoint)  {
                        point = new go.Point(midpoint.x, midpoint.y);
                        points.add(point);
                        oldPoints.push(point.toString());
                        newPoints.push(point.toString());
                    }, me);
                    node = diagram.goDiagram.findNodeForKey(change.to);
                    point = link.getLinkPointFromPoint(node, node.port, node.port.getDocumentPoint(go.Spot.Center), midpoints[midpoints.length - 1], false);
                    points.add(point);
                    newPoints.push(point.toString())
                    link.points = points;
                    console.log('adding start/end points', oldPoints, newPoints)
                }
            }, me);
            console.log('commitTransation updatePoints')
            goDiagram.commitTransaction('updatePoints');
        }

Are those warnings actually causing any problems for you?

What is the value of ChangedEvent.change? Of ChangedEvent.modelChange? I’m wondering when you are actually executing that code.

Looking at this code might be why I didn’t add the start/end points before creating the model. Can this functionality be done without using the Diagram and existing nodes?

link = diagram.goDiagram.findLinkForData(e.model.findLinkDataForKey(change.key));
node = diagram.goDiagram.findNodeForKey(change.from);
point = link.getLinkPointFromPoint(node, node.port, node.port.getDocumentPoint(go.Spot.Center), midpoints[0], true);

Probably not. The additional problem is that at the time of the ChangedEvent (and I still don’t know when you are seeing one that has “Initial Layout” as the oldValue – there should be at least two of them!), depending on conditions, the nodes might not have their final size and position yet.

Putting more logging in there are 4 “Initial Layout” as the oldValue.

There are several checks in the code before we add the start/end points. Here is the first of them and the 2nd line of checks are transaction names that we’ve started. If any of these conditions are true we don’t add the points.

        if (!e.isTransactionFinished || e.propertyName === 'CommittingTransaction' || e.modelChange === 'SourceChanged' ||
            e.oldValue === 'updateLink' || e.oldValue === 'updateNode' || e.oldValue === 'updateGrid' || e.oldValue === 'highlight') {
            return;
        }

Later on we do more checks and if this passes then we enter the function that might add points.

        if (e.propertyName === 'CommittedTransaction' || e.propertyName === 'FinishedUndo' || e.propertyName === 'FinishedRedo') {

Then once in that function a final check and if it passes we add the start/end points

        if (e.oldValue === 'Initial Layout') {

When we finally make it to where the start/end points are added, here are some ChangedEvent values including the 2 you asked about:

{
  "change": "EnumValue.Transaction",
  "propertyName": "CommittedTransaction",
  "modelChange": "",
  "newParam": null,
  "newValue": null,
  "oldParam": null,
  "oldValue": "Initial Layout"
}

Four of them? I was expecting two of them, plus two for each use of Diagram.delayInitialization.

I haven’t tried this, but if I were you, I would do it when:

e.change === go.ChangedEvent.Transaction &&
e.propertyName === "CommittingTransaction" &&
e.oldValue === "Initial Layout"

In other words, I am guessing that at “CommittedTransaction” it might be too late.

I have my code to add the points only when those conditions are met and there’s no incremental JSON at that point.

[Log] toIncrementalJson – "{ \"incremental\": 0 }" (AbstractModelerController.js, line 200)

So you changed your code to meet those conditions and you are still getting warnings.

But the warnings are independent of any actual problems that you are having, yes?

Walter let’s start from scratch, ignore the transaction warnings for now, and hopefully this helps simplify things as I think this is the problem. When the model is first loaded with server data AND the mouse isn’t moving here is what happens in the ModelChanged handler.

{
  "modelProperties": {
    "change": "EnumValue.Transaction",
    "propertyName": "CommittedTransaction",
    "modelChange": "",
    "newParam": null,
    "newValue": null,
    "oldParam": null,
    "oldValue": "Initial Layout"
  },
  "toIncrementalJson": {
    "class": "GraphLinksModel",
    "incremental": 1,
    "linkKeyProperty": "key",
    "modifiedLinkData": [
      {
        "parent": "ext-comp-1247",
        "key": "390:TEST",
        "midpoints": [
          {
            "class": "go.Point",
            "x": 178,
            "y": 148
          }
        ],
        "category": "namedlink",
        "labelVisible": false,
        "text": "",
        "from": "529:TEST",
        "to": "530:TEST",
        "linkColor": "#999",
        "tranVisible": true,
        "strokeDashArray": null,
        "badgeVisible": false,
        "points": [
          146.41413299766526,
          240.77700530894947,
          288.58586700233474,
          164.22299469105053
        ]
      }
    ]
  }
}

Do the same thing AND move the mouse over the diagram and this is what happens.

{
  "modelProperties": {
    "change": "EnumValue.Transaction",
    "propertyName": "CommittedTransaction",
    "modelChange": "",
    "newParam": null,
    "newValue": null,
    "oldParam": null,
    "oldValue": "Initial Layout"
  },
  "toIncrementalJson": {
    "class": "GraphLinksModel",
    "incremental": 1,
    "linkKeyProperty": "key"
  }
}

What could be causing the incremental JSON to be empty because the mouse is moving? Because there is no modifiedLinkData my code to add the start/end points doesn’t get called.

In both cases you are getting those events before you get any of those warnings about changes outside of a transaction?

Is there anything showing in the viewport at the time the mouse is moving? Oh, and that is moving within the viewport, not outside of the viewport?

Yes this is during initial model load and the changes outside of a transaction only happen on new server data and model update. I added a 2s delay before setting the model to make the problem easier to reproduce.

        Ext.defer(function() {
            me.goDiagram.model = new go.GraphLinksModel(me.nodes, me.links);
            me.goDiagram.model.linkKeyProperty = 'key';
        }, 2000, me);

Mouse is moving over the viewport and there is nothing in it yet as the model hasn’t been set.

I have a video that shows what is happening but the forum doesn’t allow. Have an email I can send it to?

sure, send it to GoJS at our domain, nwoods.com.