Finding where occurs 'Change not within a transaction' warning

Hello, walter.

I have so many these warning message.

I do nothing special, I just move the canvas position with click and drag on background.
I think I know how I fix this.
Maybe I should add ‘d.startTransaction(“scale Nodes”);’ and ‘d.commitTransaction(“scale Nodes”);’ pairs on the right place.

But I cannot find where makes this error.
Please give me some comments.

So you say that you are getting these warning messages when the user pans the diagram.

Do you have a “ViewportBoundsChanged” DiagramEvent listener that is modifying the location of some Part or Node in order to keep it positioned at a particular place in the viewport? If so, please wrap that code with something like this in that listener:

var oldskips = myDiagram.skipsUndoManager;
myDiagram.skipsUndoManager = true;
. . . do your code . . .
myDiagram.skipsUndoManager = oldskips;

I think I already do that as needed.
Would you please see my implemented codes?

function onViewportChanged(e) {
    if (!_d1Initialized) return;

    _isD1PositionChanged = true;

    var diagram = e.diagram;
    if (diagram.scale != __scale_old) {
        console.log(Math.floor(1. / diagram.scale * 100) + "%");
        __scale_old = diagram.scale;
    }

    var viewb = diagram.viewportBounds;
    var model = diagram.model;

    var oldskips = diagram.skipsUndoManager;
    diagram.skipsUndoManager = true;

    var b = new go.Rect();
    var ndata = model.nodeDataArray;

    for (var i = 0; i < ndata.length; i++) {
        var n = ndata[i];
        if (!n.bounds) continue;

        if (n.bounds.intersectsRect(viewb)) {
            showNodeAndGroups(diagram, n);
        }
    }

    if (model instanceof go.GraphLinksModel) {
        var ldata = model.linkDataArray;
        for (var i = 0; i < ldata.length; i++) {
            var l = ldata[i];

            var fromkey = model.getFromKeyForLinkData(l);
            if (fromkey === undefined) continue;
            var from = model.findNodeDataForKey(fromkey);
            if (from === null || !from.bounds) continue;

            var tokey = model.getToKeyForLinkData(l);
            if (tokey === undefined) continue;
            var to = model.findNodeDataForKey(tokey);
            if (to === null || !to.bounds) continue;

            b.set(from.bounds);
            b.unionRect(to.bounds);
            if (b.intersectsRect(viewb)) {
                showNodeAndGroups(diagram, from);
                showNodeAndGroups(diagram, to);
                model.addLinkData(l);
                var link = diagram.findLinkForData(l);
                if (link !== null) {
                    link.updateRoute();
                }
            }
        }
    }

    diagram.skipsUndoManager = oldskips;

    if (removeTimer === null) {
        removeTimer = setTimeout(function() {
            removeOffscreen(diagram);
        }, 3000);

    }

    var newscale = _d.scale;
    if (e.subject.scale !== newscale) {
        updateEachNodeScale(newscale);
    }

    call('viewportChanged');
}// end of function onViewportChanged(e)

function showNode(data) {
    var node = _d.findNodeForKey(data.key);
    if (node) {
        node.visible = true;
    }
    else {
        _d.model.setDataProperty(data, 'visible', true);
    }
}

function showNodeAndGroups(diagram, data) {
    var model = diagram.model;
    showNode(data);
    var n = diagram.findNodeForData(data);
    if (n !== null) n.ensureBounds();
    var groupkey = model.getGroupKeyForNodeData(data);
    while (groupkey !== undefined) {
        var gd = model.findNodeDataForKey(groupkey);
        if (gd !== null) { // is there a containing group data?
            showNode(gd);
            var g = diagram.findNodeForData(gd);
            if (g !== null) g.ensureBounds();
        }
        // walk up chain of containing group data
        groupkey = model.getGroupKeyForNodeData(gd);
    }
}

// fixes actually represented size of node by modifying 'node.scale' value
function updateEachNodeScale(newscale) {
    _d.skipsUndoManager = true;
    _d.startTransaction("scale Nodes");
    _d.nodes.each(function(node) {
        if (newscale >  _DEFAULT_SCALE)
            return;

        if (new Set(["Comment", "Icon", "Number", "Dict"]).has(node.category)) {
            node.scale = _DEFAULT_SCALE / newscale;
        }
        else if (node.category == "Gain" && node.findNodesConnected().count == 0) {
            node.scale = _DEFAULT_SCALE / newscale;
        }
        else {
            return;
        }
    });

    _d.commitTransaction("scale Nodes");
    _d.skipsUndoManager = false;
}

Walter,

I’ve resolved this issue by your help. (in ViewportBoundsChanged listener)

I added these 2 lines on begin and end of the code lines I shared.

_d.startTransaction('updateDiagramVisiblityByViewportChanged');

_d.commitTransaction('updateDiagramVisiblityByViewportChanged');

Thank you!

That’s good.

By the way, in your “ViewportBoundsChanged” DiagramEvent listener, the DiagramEvent.subject has properties that are the old values of various Diagram properties. DiagramEvent | GoJS API

So you don’t need any __scale_old global variable – just use e.subject.scale.

what a truly nice comment!
thank you!