private addNewNodes()

in src/Explorer/Graph/GraphExplorerComponent/D3ForceGraph.ts [679:790]


  private addNewNodes(): d3.Selection<Element, any, any, any> {
    var self = this;

    const newNodes = this.nodeSelection
      .enter()
      .append("g")
      .attr("class", (d: D3Node) => {
        return d._isRoot ? "node root" : "node";
      })
      .call(
        drag()
          .on("start", ((e: D3DragEvent<SVGGElement, D3Node, unknown>, d: D3Node) => {
            return this.dragstarted(d, e);
          }) as any)
          .on("drag", ((e: D3DragEvent<SVGGElement, D3Node, unknown>, d: D3Node) => {
            return this.dragged(d, e);
          }) as any)
          .on("end", ((e: D3DragEvent<SVGGElement, D3Node, unknown>, d: D3Node) => {
            return this.dragended(d, e);
          }) as any),
      )
      .on("mouseover", (_: MouseEvent, d: D3Node) => {
        if (this.isHighlightDisabled || this.selectedNode || this.isDragging) {
          return;
        }

        this.highlightNode(this, d);
        this.simulation.stop();
      })
      .on("mouseout", (_: MouseEvent, d: D3Node) => {
        if (this.isHighlightDisabled || this.selectedNode || this.isDragging) {
          return;
        }

        this.unhighlightNode();

        this.simulation.restart();
      })
      .each((d: D3Node) => {
        // Initial position for nodes. This prevents blinking as following the tween transition doesn't always start right away
        d.x = self.viewCenter.x;
        d.y = self.viewCenter.y;
      });

    newNodes
      .append("circle")
      .attr("fill", this.getNodeColor.bind(this))
      .attr("class", "main")
      .attr("r", this.igraphConfig.nodeSize);

    var iconGroup = newNodes
      .append("g")
      .attr("class", "iconContainer")
      .attr("role", "group")
      .attr("tabindex", 0)
      .attr("aria-label", (d: D3Node) => {
        return this.retrieveNodeCaption(d);
      })
      .on("dblclick", function (this: Element, _: MouseEvent, d: D3Node) {
        // https://stackoverflow.com/a/41945742 ('this' implicitly has type 'any' because it does not have a type annotation)
        // this is the <g> element
        self.onNodeClicked(this.parentNode as BaseType, d);
      })
      .on("click", function (this: Element, _: MouseEvent, d: D3Node) {
        // this is the <g> element
        self.onNodeClicked(this.parentNode as BaseType, d);
      })
      .on("keypress", function (this: Element, event: KeyboardEvent, d: D3Node) {
        if (event.charCode === Constants.KeyCodes.Space || event.charCode === Constants.KeyCodes.Enter) {
          event.stopPropagation();
          // this is the <g> element
          self.onNodeClicked(this.parentNode as BaseType, d);
        }
      });
    var nodeSize = this.igraphConfig.nodeSize;
    var bgsize = nodeSize + 1;

    iconGroup
      .append("rect")
      .attr("x", -bgsize)
      .attr("y", -bgsize)
      .attr("width", bgsize * 2)
      .attr("height", bgsize * 2)
      .attr("fill-opacity", (d: D3Node) => {
        return this.igraphConfig.nodeIconKey ? 1 : 0;
      })
      .attr("class", "icon-background");

    // Possible icon: if xlink:href is undefined, the image won't show
    iconGroup
      .append("svg:image")
      .attr("xlink:href", (d: D3Node) => {
        return D3ForceGraph.computeImageData(d, this.igraphConfig);
      })
      .attr("x", -nodeSize)
      .attr("y", -nodeSize)
      .attr("height", nodeSize * 2)
      .attr("width", nodeSize * 2)
      .attr("class", "icon");
    newNodes
      .append("text")
      .attr("class", "caption")
      .attr("dx", D3ForceGraph.TEXT_DX)
      .attr("dy", ".35em")
      .text((d: D3Node) => {
        return this.retrieveNodeCaption(d);
      });

    this.nodeSelection = newNodes.merge(this.nodeSelection);

    return newNodes;
  }