How to manage the animation of each node individually

Hello, each of my nodes starts or closes the animation according to the number of line segments connected to itself. For example, if there are three nodes a, b, and c, and a is connected to b, then the animation of a and b will stop, and the animation of c will continue. Do you have any ideas? do you

You will need to set up separate animations:
GoJS Animation -- Northwoods Software

Hello, at present, I turn on or off the animation of some nodes through some events, such as the connection of nodes a and b. I turn off animation 1, but it does not take effect. Can you help me to see where there is a problem with the code?

Below is the main code snippet

const animation1 = new go.Animation()
const animation2 = new go.Animation()
animation1.duration = animation2.duration = 1000
animation1.reversible = animation2.reversible = true
animation1.runCount = animation2.runCount = Infinity

// Call this function through the corresponding event and pass in the parameters
function setArrowTipAnimate(status) {
      const nodes = myDiagram.model.nodeDataArray.map(m => myDiagram.findNodeForKey(m.key))
      const linkConnectedNode = nodes.filter(v => v.findLinksConnected().count)
      const notLinkConectedNode = nodes.filter(v => !v.findLinksConnected().count)
      notLinkConectedNode.forEach(node => {
        animation1.add(node.elt(6), 'opacity', node.elt(6).opacity, 1)
        animation1.add(node.elt(7), 'opacity', node.elt(7).opacity, 1)
        animation1.add(node.elt(8), 'opacity', node.elt(8).opacity, 1)
        animation1.add(node.elt(9), 'opacity', node.elt(9).opacity, 1)
      })
      linkConnectedNode.forEach(node => {
        animation2.add(node.elt(6), 'opacity', node.elt(6).opacity, 1)
        animation2.add(node.elt(7), 'opacity', node.elt(7).opacity, 1)
        animation2.add(node.elt(8), 'opacity', node.elt(8).opacity, 1)
        animation2.add(node.elt(9), 'opacity', node.elt(9).opacity, 1)
      })
      if (status === 'stop') {
        animation2.stop()
        animation1.start()
      } else if (status === 'start') {
        animation1.start()
        animation2.stop()
      }
    },

When do you set the opacity of those elements to a value other than 1? If they are always fully opaque, there’s nothing to animate.

Are you saying that you only start either of the Animations when the element opacity is not 1?

What exactly is the problem? Is it that you cannot turn off a running Animation? That calling Animation.stop doesn’t work?

Are you calling setArrowTipAnimate repeatedly? That will cause a problem, because you cannot modify a running Animation.

Thanks Reply!

The page initialization will call the setArrowTipAnimate function once to check the nodes with no connected line segments on the canvas and add a startup animation. The subsequent drawing also starts or stops the animation according to the connection of the nodes.
All in all, when the node has no connection line, the animation of the node is started, and vice versa, the animation is closed.

How do you think the design is reasonable?

function makeArrowTip(spot, angle, fig) {
      return $(go.Shape,
        {
          name: 'ARROWTIP',
          figure: fig,
          alignment: spot,
          alignmentFocus: spot.opposite(),
          width: 22,
          height: 18,
          fill: '#87CEFA',
          angle: angle,
          strokeWidth: 0,
          opacity: 0.001
        })
    },

ytor1-kuzix

I don’t understand what animations you want and when. So I made up some answers and implemented them:

<!DOCTYPE html>
<html>
<head>
  <title>Minimal GoJS Sample</title>
  <!-- Copyright 1998-2022 by Northwoods Software Corporation. -->
</head>
<body>
  <div id="myDiagramDiv" style="border: solid 1px black; width:100%; height:600px"></div>

  <script src="https://unpkg.com/gojs"></script>
  <script id="code">
const $ = go.GraphObject.make;

myDiagram =
  $(go.Diagram, "myDiagramDiv",
    {
      initialScale: 2.0,
      "undoManager.isEnabled": true
    });

function animatePort(port, before, after) {
  if (before !== port.fill) {
    const anim = new go.Animation();
    anim.duration = 2000;
    anim.add(port, "fill", before, after);
    anim.start();
  }
}

myDiagram.nodeTemplate =
  $(go.Node, "Auto",
    {
      linkConnected: (node, link, port) => {
        const before = port.fill;
        port.fill = "white";
        animatePort(port, before, port.fill);
      },
      linkDisconnected: (node, link, port) => {
        const before = port.fill;
        port.fill = node.findLinksConnected(port.portId).count === 0 ? "red" : "white";
        animatePort(port, before, port.fill);
      }
    },
    $(go.Shape,
      // use the stroke outline to show whether it needs a link connected
      { fill: "red", strokeWidth: 2 },  // assume initially there are no links connected
      { portId: "", fromLinkable: true, toLinkable: true, cursor: "pointer" }),
    $(go.TextBlock,
      { margin: 8, editable: true },
      new go.Binding("text").makeTwoWay())
  );

myDiagram.linkTemplate =
  $(go.Link,
    $(go.Shape),
    $(go.Shape, { toArrow: "OpenTriangle" })
  );

myDiagram.model = new go.GraphLinksModel(
[
  { key: 1, text: "Alpha" },
  { key: 2, text: "Beta" },
  { key: 3, text: "Gamma" },
  { key: 4, text: "Delta" }
],
[
  { from: 1, to: 2 }
]);
  </script>
</body>
</html>

Drawing a new link to either “Gamma” or “Delta” will cause that node to turn from red to white. Deleting that new link will cause the node to turn back to red.

Thanks for the example of the reply.
The approximate logic is as in the example, the node starts or closes the animation according to the number of its own connections.

But missing an important point, the animation is repetitive and loops between show and hide states. So add the following code to your example and the effect is messed up.
anim.reversible = true
anim.runCount = Infinity

So I think I still need to call anim.stop to stop the animation. The key point of the problem is that I don’t know how to manage the connected node animation and unconnected node animation.

Oh, now I think I see what you want. How about something like this?

<!DOCTYPE html>
<html>
<head>
  <title>Minimal GoJS Sample</title>
  <!-- Copyright 1998-2022 by Northwoods Software Corporation. -->
</head>
<body>
  <div id="myDiagramDiv" style="border: solid 1px black; width:100%; height:600px"></div>

  <script src="https://unpkg.com/gojs"></script>
  <script id="code">
const $ = go.GraphObject.make;

const myDiagram =
  $(go.Diagram, "myDiagramDiv",
    {
      initialScale: 2.0,
      "InitialLayoutCompleted": startAnimation,
      "undoManager.isEnabled": true
    });

var myAnimation = null;

function startAnimation() {
  if (myAnimation) myAnimation.stop();
  const anim = new go.Animation({ duration: 1000, reversible: true, runCount: Infinity });
  myDiagram.nodes.each(n => {
    n.ports.each(p => {
      if (n.findLinksConnected(p.portId).count === 0) {
        anim.add(p, "fill", "white", "red");
      }
    });
  });
  anim.start();
  myAnimation = anim;
}

function maybeAnimate(node, link, port) {
  // don't setup any animation until after "InitialLayoutCompleted"
  if (myAnimation) startAnimation();
}

myDiagram.nodeTemplate =
  $(go.Node, "Auto",
    {
      linkConnected: maybeAnimate,
      linkDisconnected: maybeAnimate
    },
    $(go.Shape,
      { fill: "white", portId: "", fromLinkable: true, toLinkable: true, cursor: "pointer" }),
    $(go.TextBlock,
      { margin: 8, editable: true },
      new go.Binding("text").makeTwoWay())
  );

myDiagram.linkTemplate =
  $(go.Link,
    $(go.Shape),
    $(go.Shape, { toArrow: "OpenTriangle" })
  );

myDiagram.model = new go.GraphLinksModel(
  [
    { key: 1, text: "Alpha" },
    { key: 2, text: "Beta" },
    { key: 3, text: "Gamma" },
    { key: 4, text: "Delta" }
  ],
  [
    { from: 1, to: 2 }
  ]);
  </script>
</body>
</html>

I solved the problem based on the example from your reply
thank you very much !