The element from pallete is jumping when initially is dropped on diagram

Hello Support,

We used your sample: Logic Circuit in our MVC application, but when we try to pick up and drop some element from palette for the first time, it’s initially jumping to the right side and then return back to point where mouse cursor is. How can I attach the small video that represents the issue?

That is probably due to the Diagram not having been completely initialized. Before you allow users to drag from the Palette to the main Diagram, have you set the main Diagram’s Diagram.model, as most samples do? Or if not that, have you called Diagram.requestUpdate, in case the HTML DIV has changed size?

How can I set diagram’s model if I want to draw my diagram (schema) from scratch? The main diagram is empty at the beginning.

Here’s the code:

var red = "orangered";  // 0 or false
var green = "forestgreen";  // 1 or true
var blue = "blue";
var aqua = "aqua";
var white = "white";
var dollarbill = "#85BB65";
var myDiagram;

function initElectricalShema() {
    //if (window.goSamples) goSamples();  // init for these samples -- you don't need to call this
    var $ = go.GraphObject.make;  // for conciseness in defining templates

    myDiagram =
      $(go.Diagram, "myDiagramDiv",  // create a new Diagram in the HTML DIV element "myDiagramDiv"
        {
            initialContentAlignment: go.Spot.Center,
            allowDrop: true,  // Nodes from the Palette can be dropped into the Diagram
            //"draggingTool.isGridSnapEnabled": true,  // dragged nodes will snap to a grid of 10x10 cells
            "undoManager.isEnabled": true
        });

    // when the document is modified, add a "*" to the title and enable the "Save" button
    myDiagram.addDiagramListener("Modified", function (e) {
        var button = document.getElementById("saveModel");
        if (button) button.disabled = !myDiagram.isModified;
        var idx = document.title.indexOf("*");
        if (myDiagram.isModified) {
            if (idx < 0) document.title += "*";
        } else {
            if (idx >= 0) document.title = document.title.substr(0, idx);
        }
    });

    var palette = new go.Palette("palette");  // create a new Palette in the HTML DIV element "palette"

    // creates relinkable Links that will avoid crossing Nodes when possible and will jump over other Links in their paths
    myDiagram.linkTemplate =
      $(go.Link,
        {
            //routing: go.Link.AvoidsNodes,
            //curve: go.Link.JumpOver,
            //corner: 3,
            relinkableFrom: true, relinkableTo: true,
            selectionAdorned: false, // Links are not adorned when selected so that their color remains visible.
            shadowOffset: new go.Point(0, 0), shadowBlur: 5, shadowColor: "blue"
        },
        new go.Binding("isShadowed", "isSelected").ofObject(),
        $(go.Shape,
          { name: "SHAPE", strokeWidth: 2, stroke: red }));

    // node template helpers
    var sharedToolTip =
      $(go.Adornment, "Auto",
        $(go.Shape, "RoundedRectangle", { fill: "lightyellow" }),
        $(go.TextBlock, { margin: 2 },
          new go.Binding("text", "", function (d) { return d.category; })));

    // define some common property settings
    function nodeStyle() {
        return [new go.Binding("location", "loc", go.Point.parse).makeTwoWay(go.Point.stringify),
                new go.Binding("isShadowed", "isSelected").ofObject(),
                {
                    selectionAdorned: false,
                    shadowOffset: new go.Point(0, 0),
                    shadowBlur: 15,
                    shadowColor: "blue",
                    toolTip: sharedToolTip
                }];
    }

    function shapeStyle1() {
        return {
            name: "NODESHAPE",
            fill: "lightgray",
            stroke: "darkslategray",
            desiredSize: new go.Size(40, 40),
            strokeWidth: 2
        };
    }

    function shapeStyle2() {
        return {
            name: "NODESHAPE1",
            fill: "aqua",
            stroke: "yellow",
            desiredSize: new go.Size(40, 40),
            strokeWidth: 2
        };
    }

    function shapeStyle3() {
        return {
            name: "NODESHAPE2",
            fill: "dollarbill",
            stroke: "darkgreen",
            desiredSize: new go.Size(10, 40),
            strokeWidth: 2
        };
    }

    function shapeStyle4() {
        return {
            name: "NODESHAPE3",
            fill: "green",
            stroke: "green",
            desiredSize: new go.Size(1, 4),
            strokeWidth: 2
        };
    }

    function shapeStyle5() {
        return {
            name: "NODESHAPE4",
            fill: "green",
            stroke: "green",
            desiredSize: new go.Size(1, 10),
            strokeWidth: 2
        };
    }

    function portStyle(input) {
        return {
            desiredSize: new go.Size(6, 6),
            fill: "black",
            fromSpot: go.Spot.Right,
            fromLinkable: !input,
            toSpot: go.Spot.Left,
            toLinkable: input,
            toMaxLinks: 2,
            cursor: "pointer"
        };
    }

    function portStyle1(input) {
        return {
            desiredSize: new go.Size(2, 2),
            fill: "green",
            //fromSpot: go.Spot.Center,
            fromLinkable: input,
            //toSpot: go.Spot.Center,
            toLinkable: !input,
            toMaxLinks: 2,
            cursor: "pointer"
        };
    }

    function portStyle2(input) {
        return {
            desiredSize: new go.Size(2, 2),
            fill: "green",
            //fromSpot: go.Spot.Center,
            fromLinkable: !input,
            //toSpot: go.Spot.Center,
            toLinkable: input,
            toMaxLinks: 2,
            cursor: "pointer"
        };
    }

    // define templates for each type of node
    var inputTemplate =
      $(go.Node, "Spot", nodeStyle(),
        $(go.Shape, "Circle", shapeStyle1(),
          { fill: red }),  // override the default fill (from shapeStyle1()) to be red
        $(go.Shape, "Rectangle", portStyle(false),  // the only port
          { portId: "", alignment: new go.Spot(1, 0.5) }),
        { // if double-clicked, an input node will change its value, represented by the color.
            doubleClick: function (e, obj) {
                e.diagram.startTransaction("Toggle Input");
                var shp = obj.findObject("NODESHAPE");
                shp.fill = (shp.fill === green) ? red : green;
                updateStates();
                e.diagram.commitTransaction("Toggle Input");
            }
        }
      );

    var outputTemplate =
      $(go.Node, "Spot", nodeStyle(),
        $(go.Shape, "Rectangle", shapeStyle1(),
          { fill: green }),  // override the default fill (from shapeStyle1()) to be green
        $(go.Shape, "Rectangle", portStyle(true),  // the only port
          { portId: "", alignment: new go.Spot(0, 0.5) })
      );

    var andTemplate =
      $(go.Node, "Spot", nodeStyle(),
        $(go.Shape, "AndGate", shapeStyle1()),
        $(go.Shape, "Rectangle", portStyle(true),
          { portId: "in1", alignment: new go.Spot(0, 0.3) }),
        $(go.Shape, "Rectangle", portStyle(true),
          { portId: "in2", alignment: new go.Spot(0, 0.7) }),
        $(go.Shape, "Rectangle", portStyle(false),
          { portId: "out", alignment: new go.Spot(1, 0.5) })
      );

    var orTemplate =
      $(go.Node, "Spot", nodeStyle(),
        $(go.Shape, "OrGate", shapeStyle1()),
        $(go.Shape, "Rectangle", portStyle(true),
          { portId: "in1", alignment: new go.Spot(0.16, 0.3) }),
        $(go.Shape, "Rectangle", portStyle(true),
          { portId: "in2", alignment: new go.Spot(0.16, 0.7) }),
        $(go.Shape, "Rectangle", portStyle(false),
          { portId: "out", alignment: new go.Spot(1, 0.5) })
      );

    var xorTemplate =
      $(go.Node, "Spot", nodeStyle(),
        $(go.Shape, "XorGate", shapeStyle1()),
        $(go.Shape, "Rectangle", portStyle(true),
          { portId: "in1", alignment: new go.Spot(0.26, 0.3) }),
        $(go.Shape, "Rectangle", portStyle(true),
          { portId: "in2", alignment: new go.Spot(0.26, 0.7) }),
        $(go.Shape, "Rectangle", portStyle(false),
          { portId: "out", alignment: new go.Spot(1, 0.5) })
      );

    var norTemplate =
      $(go.Node, "Spot", nodeStyle(),
        $(go.Shape, "NorGate", shapeStyle1()),
        $(go.Shape, "Rectangle", portStyle(true),
          { portId: "in1", alignment: new go.Spot(0.16, 0.3) }),
        $(go.Shape, "Rectangle", portStyle(true),
          { portId: "in2", alignment: new go.Spot(0.16, 0.7) }),
        $(go.Shape, "Rectangle", portStyle(false),
          { portId: "out", alignment: new go.Spot(1, 0.5) })
      );

    var xnorTemplate =
      $(go.Node, "Spot", nodeStyle(),
        $(go.Shape, "XnorGate", shapeStyle1()),
        $(go.Shape, "Rectangle", portStyle(true),
          { portId: "in1", alignment: new go.Spot(0.26, 0.3) }),
        $(go.Shape, "Rectangle", portStyle(true),
          { portId: "in2", alignment: new go.Spot(0.26, 0.7) }),
        $(go.Shape, "Rectangle", portStyle(false),
          { portId: "out", alignment: new go.Spot(1, 0.5) })
      );

    var nandTemplate =
      $(go.Node, "Spot", nodeStyle(),
        $(go.Shape, "NandGate", shapeStyle1()),
        $(go.Shape, "Rectangle", portStyle(true),
          { portId: "in1", alignment: new go.Spot(0, 0.3) }),
        $(go.Shape, "Rectangle", portStyle(true),
          { portId: "in2", alignment: new go.Spot(0, 0.7) }),
        $(go.Shape, "Rectangle", portStyle(false),
          { portId: "out", alignment: new go.Spot(1, 0.5) })
      );

    var notTemplate =
      $(go.Node, "Spot", nodeStyle(),
        $(go.Shape, "Inverter", shapeStyle1()),
        $(go.Shape, "Rectangle", portStyle(true),
          { portId: "in", alignment: new go.Spot(0, 0.5) }),
        $(go.Shape, "Rectangle", portStyle(false),
          { portId: "out", alignment: new go.Spot(1, 0.5) })
      );

    var custom1Template =
      $(go.Node, "Spot", nodeStyle(),
        $(go.Shape, "Rectangle", shapeStyle2(),
          { fill: blue }),  // override the default fill (from shapeStyle1()) to be green
        $(go.Shape, "Rectangle", portStyle(true),  // the only port
          { portId: "", alignment: new go.Spot(0, 0.5) })
      );

    var custom2Template =
      $(go.Node, "Vertical",
        $(go.Shape, "Circle", shapeStyle1(),
          { fill: white }),  // override the default fill (from shapeStyle1()) to be green
        $(go.Shape, "Rectangle", shapeStyle4(),
          { fill: green }),  // override the default fill (from shapeStyle1()) to be green
        $(go.Shape, "Rectangle", shapeStyle3(),
          { fill: dollarbill }),  // override the default fill (from shapeStyle1()) to be green
        $(go.Shape, "Rectangle", shapeStyle5(),
          { fill: green }),  // override the default fill (from shapeStyle1()) to be green
        $(go.Shape, "Rectangle", portStyle1(true),  // the only port
          { portId: "" }),
        $(go.Shape, "Rectangle", portStyle2(true),  // the only port
          { portId: "" })
      );

    // add the templates created above to myDiagram and palette
    myDiagram.nodeTemplateMap.add("input", inputTemplate);
    myDiagram.nodeTemplateMap.add("output", outputTemplate);
    myDiagram.nodeTemplateMap.add("and", andTemplate);
    myDiagram.nodeTemplateMap.add("or", orTemplate);
    myDiagram.nodeTemplateMap.add("xor", xorTemplate);
    myDiagram.nodeTemplateMap.add("not", notTemplate);
    myDiagram.nodeTemplateMap.add("nand", nandTemplate);
    myDiagram.nodeTemplateMap.add("nor", norTemplate);
    myDiagram.nodeTemplateMap.add("xnor", xnorTemplate);
    myDiagram.nodeTemplateMap.add("custom1", custom1Template);
    myDiagram.nodeTemplateMap.add("custom2", custom2Template);

    // share the template map with the Palette
    palette.nodeTemplateMap = myDiagram.nodeTemplateMap;

    palette.model.nodeDataArray = [
      { category: "input" },
      { category: "output" },
      { category: "and" },
      { category: "or" },
      { category: "xor" },
      { category: "not" },
      { category: "nand" },
      { category: "nor" },
      { category: "xnor" },
      { category: "custom1" },
      { category: "custom2" }
];

    // load the initial diagram
    load();

    // continually update the diagram
    loop();
}

// update the diagram every 250 milliseconds
function loop() {
    setTimeout(function () { updateStates(); loop(); }, 250);
}

// update the value and appearance of each node according to its type and input values
function updateStates() {
    var oldskip = myDiagram.skipsUndoManager;
    myDiagram.skipsUndoManager = true;
    // do all "input" nodes first
    myDiagram.nodes.each(function (node) {
        if (node.category === "input") {
            doInput(node);
        }
    });
    // now we can do all other kinds of nodes
    myDiagram.nodes.each(function (node) {
        switch (node.category) {
            case "and": doAnd(node); break;
            case "or": doOr(node); break;
            case "xor": doXor(node); break;
            case "not": doNot(node); break;
            case "nand": doNand(node); break;
            case "nor": doNor(node); break;
            case "xnor": doXnor(node); break;
            case "output": doOutput(node); break;
            case "custom1": doCustom1(node); break;
            case "custom2": doCustom2(node); break;
            case "input": break;  // doInput already called, above
        }
    });
    myDiagram.skipsUndoManager = oldskip;
}

// helper predicate
function linkIsTrue(link) {  // assume the given Link has a Shape named "SHAPE"
    return link.findObject("SHAPE").stroke === green;
}

// helper function for propagating results
function setOutputLinks(node, color) {
    node.findLinksOutOf().each(function (link) { link.findObject("SHAPE").stroke = color; });
}

// update nodes by the specific function for its type
// determine the color of links coming out of this node based on those coming in and node type

function doInput(node) {
    // the output is just the node's Shape.fill
    setOutputLinks(node, node.findObject("NODESHAPE").fill);
}

function doAnd(node) {
    var color = node.findLinksInto().all(linkIsTrue) ? green : red;
    setOutputLinks(node, color);
}
function doNand(node) {
    var color = !node.findLinksInto().all(linkIsTrue) ? green : red;
    setOutputLinks(node, color);
}
function doNot(node) {
    var color = !node.findLinksInto().all(linkIsTrue) ? green : red;
    setOutputLinks(node, color);
}

function doOr(node) {
    var color = node.findLinksInto().any(linkIsTrue) ? green : red;
    setOutputLinks(node, color);
}
function doNor(node) {
    var color = !node.findLinksInto().any(linkIsTrue) ? green : red;
    setOutputLinks(node, color);
}

function doXor(node) {
    var truecount = 0;
    node.findLinksInto().each(function (link) { if (linkIsTrue(link)) truecount++; });
    var color = truecount % 2 === 0 ? green : red;
    setOutputLinks(node, color);
}
function doXnor(node) {
    var truecount = 0;
    node.findLinksInto().each(function (link) { if (linkIsTrue(link)) truecount++; });
    var color = truecount % 2 !== 0 ? green : red;
    setOutputLinks(node, color);
}

function doOutput(node) {
    // assume there is just one input link
    // we just need to update the node's Shape.fill
    node.linksConnected.each(function (link) { node.findObject("NODESHAPE").fill = link.findObject("SHAPE").stroke; });
}

function doCustom1(node) {
    // assume there is just one input link
    // we just need to update the node's Shape.fill
    node.linksConnected.each(function (link) { node.findObject("NODESHAPE1").fill = link.findObject("SHAPE").stroke; });
}

function doCustom2(node) {
    // assume there is just one input link
    // we just need to update the node's Shape.fill
    node.linksConnected.each(function (link) { node.findObject("NODESHAPE1").fill = link.findObject("SHAPE").stroke; });
}

// save a model to and load a model from JSON text, displayed below the Diagram
function save() {
    document.getElementById("mySavedModel").value = myDiagram.model.toJson();
    //alert(myDiagram.model.toJson());
    myDiagram.isModified = false;
}
function load() {
    myDiagram.model = go.Model.fromJson(document.getElementById("mySavedModel").value);
}

The element is jumping only when I drop it on main diagram for the first time. There’s no jumping after that. Could you tell me, please, what should I change in my code to avoid jumping at the beginning?

Is it working OK now? Someone marked my reply as a solution. What did you do that worked?

Diagram.requestUpdate.

Thank you very much.