Given path moving animation of ball

We have given links template in which ball should travel, start to end.

ballTravelingLink = [
{from: ‘START’, to: ‘create invoice’},
{from: ‘create invoice’, to: ‘approve invoice’},
{from: ‘approve invoice’, to: ‘create accounting for invoice’}
{from: ‘create accounting for invoice’, to: ‘END’}
]

this is my diagram where i need to travel ball from start to end, like above json.

This is what i wanted, i found it in your sample.

Do you mean something like: Concept Map with animation along paths ?

Thanks walter, my animation is working fine but the ball which i put on the links is going from start to any node randomly, but here we have path in json which is not followed by ball(animation).

That depends in how you choose the next path to follow.

Later I can create a sample for you.

Here’s three tokens going back up the path from Delta to Alpha:
image

Here’s the complete stand-alone sample:

<!DOCTYPE html>
<html>
<head>
  <title>MultiPath Animation</title>
  <!-- Copyright 1998-2024 by Northwoods Software Corporation. -->
</head>
<body>
  <div id="myDiagramDiv" style="border: solid 1px black; width:100%; height:400px"></div>
  <button id="myTestButton">Test 1</button><button id="myTestButton2">Test 2</button>
  <textarea id="mySavedModel" style="width:100%;height:250px"></textarea>

  <script src="go.js"></script>
  <script id="code">
const $ = go.GraphObject.make;

const myDiagram =
  new go.Diagram("myDiagramDiv",
    {
      layout: new go.LayeredDigraphLayout({ direction: 90 }),
      "undoManager.isEnabled": true,
      "ModelChanged": e => {     // just for demonstration purposes,
        if (e.isTransactionFinished) {  // show the model data in the page's TextArea
          document.getElementById("mySavedModel").textContent = e.model.toJson();
        }
      }
    });

myDiagram.nodeTemplate =
  $(go.Node, "Auto",
    $(go.Shape, "Capsule",
      { fill: "white", strokeWidth: 0, spot1: go.Spot.TopLeft, spot2: new go.Spot(1, 1, -10, 0) },
      new go.Binding("fill", "color")),
    $(go.Panel, "Horizontal",
      $(go.Panel, "Spot",
        $(go.Shape, "Circle", { width: 20, height: 20, fill: "white", strokeWidth: 0, margin: 4 }),
        $(go.TextBlock, { scale: 0.75 },
          new go.Binding("text", "value", v => v + "%"))
      ),
      $(go.TextBlock, { width: 100 },
        new go.Binding("text"))
    )
  );

myDiagram.linkTemplate =
  $(go.Link,
    { curve: go.Link.Bezier, fromEndSegmentLength: 30, toEndSegmentLength: 30 },
    $(go.Shape, { isPanelMain: true, stroke: "#666", strokeWidth: 5 }),
    $(go.Shape, { isPanelMain: true, stroke: "#999", strokeWidth: 3 }),
    $(go.Shape, { isPanelMain: true, stroke: "white", strokeWidth: 3, strokeDashArray: [6, 6] }),
    $(go.Shape, { toArrow: "Standard", fill: "#666", stroke: "#666" })
  );

myDiagram.model = new go.GraphLinksModel(
[
  { key: 1, text: "Alpha", color: "lightblue", value: 80 },
  { key: 2, text: "Beta", color: "orange", value: 40 },
  { key: 3, text: "Gamma", color: "lightgreen", value: 40 },
  { key: 4, text: "Delta", color: "pink", value: 10 }
],
[
  { from: 1, to: 2 },
  { from: 1, to: 3 },
  { from: 3, to: 4 },
  { from: 4, to: 1 }
]);

function animatePaths(fromtos, color) {
  const links = [];
  fromtos.forEach(fromto => {
    const from = myDiagram.findNodeForKey(fromto.from);
    if (!from) return;
    const to = myDiagram.findNodeForKey(fromto.to);
    if (!to) return;
    const link = from.findLinksTo(to).first();
    if (!link) return;
    links.push(link);
  });
  if (links.length === 0) return;

  const token =
    $(go.Part,
      { locationSpot: go.Spot.Center, layerName: "Adornment", _link: null, _frac: 0.0 },
      $(go.Shape, "Circle",
        { width: 12, height: 12, fill: color || "red", strokeWidth: 0 })
    );
  myDiagram.add(token);

  function animateToken() {
    if (!token._link) {
      token._link = links.shift();
      if (token._link) {
        token._length = token._link.path.geometry.flattenedTotalLength;
      } else {
        myDiagram.remove(token);
        return;
      }
    }
    if (token._frac >= 1.0 || !token._length) {  // next link
      token._link = null;
      token._frac = 0.0;
    } else {
      const link = token._link;
      token.location = link.path.getDocumentPoint(link.path.geometry.getPointAlongPath(token._frac));
      token._frac += 5/token._length;  // each tick moves a constant distance
    }
    requestAnimationFrame(animateToken);
  }

  requestAnimationFrame(animateToken);  // start right now
}

document.getElementById("myTestButton").addEventListener("click", e => {
  animatePaths([
    { from: 1, to: 2 }
  ], "blue");
});

document.getElementById("myTestButton2").addEventListener("click", e => {
  animatePaths([
    { from: 1, to: 3 },
    { from: 3, to: 4 },
    { from: 4, to: 1 }
  ], "red");
});
  </script>
</body>
</html>