_update()

in src/visual/Visualizer.js [458:569]


  _update() {
    const step = this._step;
    if (!step) {
      return;
    }
    // validate call <-> step correspondence
    const children = this._children;

    const declarations = this._declarations;

    // handle the renames
    const pickBy = _.pickBy || _.pick; // be prepared for legacy lodash 3.10.1
    const renamed = pickBy(children, (vStep, name) => name !== generateChildName(vStep.step));

    _.forEach(renamed, (vStep, oldName) => {
      delete children[oldName];
      children[generateChildName(vStep.step)] = vStep;
    });

    const toRemove = [];
    const findChildInModel = (visChild, name, modelChild) => {
      const modelChildName = generateChildName(modelChild);
      if (modelChildName === name) {
        return true;
      }
      const modelChildren = modelChild.children;

      if (_.has(modelChildren, name)) {
        return true;
      }

      let res = false;
      _.forEach(modelChildren, (child) => {
        res = res || findChildInModel(visChild, name, child);
      });

      return res;
    };

    _.forEach(children, (visChild, name) => {
      if (!findChildInModel(visChild, name, step)) {
        // remove visual step from graph
        toRemove[toRemove.length] = visChild;
      }
    });

    this._graph.removeCells(toRemove);
    _.forEach(toRemove, (child) => {
      const idx = _.indexOf(this.selection, child);
      if (idx !== -1) {
        this.selection.splice(idx, 1);
      }
      delete children[generateChildName(child.step)];
    });

    const cellsToAdd = [];
    const updateOrCreateVisualSteps = (innerStep, parent = null) => {
      const name = generateChildName(innerStep);
      let visChild = children[name];
      if (!visChild) {
        const opts = this.zoom.fromWidgetToLocal({
          x: this.paper.el.offsetWidth / 2,
          y: this.paper.el.offsetHeight / 2,
        });
        opts.step = innerStep;
        visChild = createVisual(opts);
        children[name] = visChild;
        cellsToAdd[cellsToAdd.length] = visChild;
        if (_.size(opts.step.ownDeclarations)) {
          _.forEach(opts.step.ownDeclarations, (declaration) => {
            let visDeclaration = declarations[declaration.name];
            if (!visDeclaration) {
              visDeclaration = new VisualDeclaration({ declaration, x: opts.x, y: opts.y });
              cellsToAdd[cellsToAdd.length] = visDeclaration;
              declarations[declaration.name] = visDeclaration;
              visChild.embed(visDeclaration);
              visChild.fit();
              visChild.update();
            }
          });
        }
        if (parent) {
          parent.embed(visChild);
          parent.fit();
          parent.update();
        }
      } else {
        // it is essential to update links before the step!
        const links = this._graph.getConnectedLinks(visChild);
        _.forEach(links, (link) => {
          link.refresh();
        });
        visChild.update();
      }

      const innerChildren = innerStep.children;
      _.forEach(innerChildren, (child) => {
        updateOrCreateVisualSteps(child, visChild);
      });
    };

    updateOrCreateVisualSteps(step);

    _.forEach(children, (child) => {
      this._loopPorts(child.step.o, child, declarations, cellsToAdd, portName => child.isPortEnabled(false, portName));
      this._loopPorts(child.step.i, child, declarations, cellsToAdd, portName => child.isPortEnabled(true, portName));
    });

    this._loopDeclarations(declarations, cellsToAdd);

    this._graph.addCells(cellsToAdd);
  }