TypeError during doMouseMove > moveParts > defaultFromPoint setter

My team has just started trying out GoJS and we’ve been thrilled with its capabilities so far!

However, we are getting the following error, very infrequently, while dragging elements around and I’m not sure if we’re doing something wrong, or there’s some kind of bug in GoJS. It seems to be related to setting a Link’s defaultFromPoint during the moveParts() logic – which I don’t fully understand. But I don’t think we’re doing anything particularly interesting wrt Links.

Do you think if we had a Link in the model with no matching Node that it could cause this?

Anyway, here’s the error:

TypeError: Cannot read property ‘copy’ of undefined

This error occurred in the setter for defaultFromPoint… (I assume on the Link prototype)

    defaultFromPoint: {
      configurable: !0,
      get: function () {
        return this.w;
      },
      set: function (a) {
>>>     this.w = a.copy();
                  ^
      }
    },

Called by…

  function Ff(a, b, c) {
    if (0 !== b || 0 !== c) {
      for (var d = a.qd, e = new H(), f = a.Gb.iterator; f.next();) {
        var g = f.value;
        e.add(new J(g.x + b, g.y + c).freeze());
      }

      e.freeze();
      f = a.Gb;
      a.Gb = e;
      g = a.diagram;
      isNaN(b) || isNaN(c) || null !== g && g.animationManager.yc ? a.v() : (a.rg.h(a.rg.x + b, a.rg.y + c), a.ra.h(a.ra.x + b, a.ra.y + c), Ul(a));
>>>   d ? Gp(a) : (a.defaultFromPoint && (a.defaultFromPoint = a.i(0)), a.defaultToPoint && (a.defaultToPoint = a.i(a.pointsCount - 1)));
                                                             ^
      null !== g && g.animationManager.yc && (a.Eg = e);
      a.g("points", f, e);
    }
  }

Called by…

  function Hf(a, b, c, d, e) {
    if (null !== b && (w(b, Db, R, "moveParts:parts"), 0 !== b.count)) {
      var f = J.alloc(),
          g = J.alloc();
      g.assign(c);
      isNaN(g.x) && (g.x = 0);
      isNaN(g.y) && (g.y = 0);
      (c = a.pq) || of(a, b);

      for (var h = Ma(), k = Ma(), l = b.iterator, m = J.alloc(); l.next();) {
        var n = l.key,
            p = l.value;

        if (n.Vc()) {
          var r = ek(a, n, b);
          if (null !== r) h.push(new fk(n, p, r));else if (!e || n.canMove()) r = p.point, f.assign(r), a.computeMove(n, f.add(g), d, m), n.location = m, void 0 === p.shifted && (p.shifted = new J()), p.shifted.assign(m.oe(r));
        } else l.key instanceof S && k.push(l.qa);
      }

      J.free(m);
      e = h.length;

      for (l = 0; l < e; l++) n = h[l], f.assign(n.info.point), void 0 === n.nw.shifted && (n.nw.shifted = new J()), n.node.location = f.add(n.nw.shifted);

      e = J.alloc();
      l = J.alloc();
      n = k.length;

      for (p = 0; p < n; p++) {
        var q = k[p];
        r = q.key;
        if (r instanceof S) if (r.suspendsRouting) {
          r.Eg = null;
          m = r.fromNode;
          var u = r.toNode;
          if (null !== a.draggedLink && d.dragsLink) {
            if (u = q.value.point, null === r.dragComputation) b.add(r, a.Jd(d, r, g)), Ff(r, g.x - u.x, g.y - u.y);else {
              q = J.allocAt(0, 0);
              (m = r.i(0)) && m.o() && q.assign(m);
>>>>>> Looks like r.i(0) is not undefined here ^              
              var x = m = J.alloc().assign(q).add(g);
              d.isGridSnapEnabled && (d.isGridSnapRealtime || a.lastInput.up) && (x = J.alloc(), Vg(a, r, m, x, d));
              m.assign(r.dragComputation(r, m, x)).oe(q);
              b.add(r, a.Jd(d, r, m));
>>>           Ff(r, m.x - u.x, m.y - u.y);
              ^
              J.free(q);
              J.free(m);
              x !== m && J.free(x);
            }
          } else null !== m && (e.assign(m.location), x = b.K(m), null !== x && e.oe(x.point)), null !== u && (l.assign(u.location), x = b.K(u), null !== x && l.oe(x.point)), null !== m && null !== u ? e.Ta(l) ? (m = q.value.point, u = f, u.assign(e), u.oe(m), b.add(r, a.Jd(d, r, e)), Ff(r, u.x, u.y)) : (r.suspendsRouting = !1, r.Za()) : (q = q.value.point, m = null !== m ? e : null !== u ? l : g, b.add(r, a.Jd(d, r, m)), Ff(r, m.x - q.x, m.y - q.y));
        } else if (null === r.fromNode || null === r.toNode) m = q.value.point, b.add(r, a.Jd(d, r, g)), Ff(r, g.x - m.x, g.y - m.y);
      }

      J.free(f);
      J.free(g);
      J.free(e);
      J.free(l);
      Oa(h);
      Oa(k);
      c || (jj(a), tf(a, b));
    }
  }

Called by… moveParts()

  jf.prototype.moveParts = function (a, b, c) {
    void 0 === c && (c = !1);
    var d = this.diagram;
>>> null !== d && Hf(d, a, b, this.dragOptions, c);
                  ^
  }

Called by…

  function Gf(a, b, c) {
    var d = a.diagram,
        e = a.startPoint,
        f = J.alloc();
    f.assign(d.lastInput.documentPoint);
    a.moveParts(b, f.oe(e), c);
    J.free(f);
    !0 === d.We("temporaryPixelRatio") && null === d.Ih && 30 < d.py && (nf(d), d.lr());
  }

Called by… doMouseMove() (on the currentTool)

  jf.prototype.doMouseMove = function () {
    if (this.isActive) {
      var a = this.diagram,
          b = a.lastInput;
      this.simulatedMouseMove(b.event, b.documentPoint, b.targetDiagram) || null === this.currentPart || null === this.draggedParts || (this.mayCopy() ? (Ef(this, !1), of(a, this.copiedParts), Gf(this, this.copiedParts, !1), tf(a, this.copiedParts)) : this.mayMove() ? (wf(this), Gf(this, this.draggedParts, !0)) : this.mayDragOut() ? (Ef(this, !1), Gf(this, this.copiedParts, !1)) : wf(this), If(this, a.lastInput.documentPoint));
    }
  };

Called by… a different doMouseMove()

R.prototype.doMouseMove = function () {
  this.currentTool.doMouseMove();
}

Called by…

  function Qi(a, b) {
    if (ih) {
      
      // ...
      
      a.Sk = function (b) {
        if (a.isEnabled) {
          a.mg = !0;
          var c = vj(a, b, !0);
          a.doMouseMove();
          a.currentTool.isBeyondDragSize() && (a.Dd = 0);
          Bj(a, c, b);
        }
      };

Oh, and here’s our link template, in case that helps:

import { GraphObject, Link, Binding, Panel } from "gojs";

import { Black } from "./colors";

const $ = GraphObject.make;

export const linkTemplate = $(
  Link,
  { layerName: "Links" },
  Panel.Link,
  {
    relinkableFrom: false,
    relinkableTo: false,
    toShortLength: 2,
    routing: Link.Orthogonal,
    corner: 20,
  },
  $("Shape", new Binding("stroke", "color"), {
    strokeWidth: 1,
    stroke: Black.L500 + "10", //adding an alpha value
  }),
  $("Shape", new Binding("fill", "color"), {
    fill: Black.L100,
    stroke: null,
    toArrow: "Standard",
  })
);

Yes, the user must be moving a Link, and for some reason that Link must not have any points in its route – Link.pointsCount is zero. But I don’t know how it got into that state. Please could you give more details about exactly what the user was doing just before and during the move? A small screenshot would also help. Do you have any customization of the DraggingTool or any event handlers/listeners that relate to moving or dragging?

Nevertheless, the code is clearly not handling the case where there are no points, so we’ll fix that, at least.

A link with no points? Interesting. So to make sure I understand, if we have links in our data that have a “from” or “to” node that doesn’t exist, that could cause this error?

I was the user, and I wasn’t moving links specifically as we disable selection in the layer we render links. I was (if I remember correctly) dragging a group around. That group had several nodes in it, and those nodes had a number of links both between each other and external to the group.

We don’t have any customization of the DraggingTool, and pretty much the only event listeners we have are related to mouse enter and mouse leave, and those change the styling of links. That is, on hover (mouse-enter), we display relevant links as darker, and stop doing so on mouse-leave.

Yes, no points in the link route must be the case for that exception to happen. I still don’t know how it got to that state during the dragging process, and you haven’t said anything that points to something unusual.

Anyway, although I don’t know the cause of the problem, I can at least fix that code to be more careful when for whatever reason there are no points in the route. So in 2.1.45 or later you shoudn’t run into that specific exception any more. That should be released sometime this week.

Thanks for pointing out the problem and giving detailed information about the exception.

1 Like