VincentDM
VincentDM

Reputation: 489

D3v4 graph class, trouble adding nodes

I'm working on a javascript graph implementation that I could use as base for faster prototyping.

When I'm running the code, I'm constantly getting this error: Unexpected value translate(NaN,NaN) parsing transform attribute.

Here's the bit where I add a node, a complete CodePen example is available here.

var iNode = {'id':4, 'x':111, 'y':222};
wGraph.addNode(iNode);

// ...

function addNode (iNode)
{
  mNodesData.push(iNode);

  wNewNode = mSvg
    .select(".nodes")
    .selectAll(".node")
    .data(mNodesData).enter()
    .append("g")
      .attr("class", "node")
    .call(d3.drag()
      .on("start", graphDragstarted)
      .on("drag", graphDragged)
      .on("end", graphDragended))
    .append("g");

 // Merge new node
  mNodesRef = wNewNode.merge(mNodesRef);

  wNewNode.append("circle")
    .attr("r", mNodeRadius);
};

I'm just getting into Javascript (coming from C++) and the way types are defined still puzzles me. When I console.log(iNode) for var iNode = {'id':4, 'x':111, 'y':222}; I'm getting this kind of object :

{…}
    id: 4
    vx: NaN
    vy: NaN
    x: NaN
    y: NaN

...but If I'm removing the whole graph thing it prints out to :

{…}
    id: 4
    x: 111
    y: 222

...so my guess is that my Object is typed according to its use in the Graph() "class" but I can't figure out how to shape it correctly.

Upvotes: 0

Views: 52

Answers (1)

rioV8
rioV8

Reputation: 28663

After some inspection and logging it turns out that mCenterX and mCenterY are NaN.

This has the result that the d3.forceX and d3.forceY update the position of the node to NaN.

@VincentDM found that the px in the width and height attributes where a problem in the parsing of the attributes. The following would have solved the problem also

mSvgWidth  = iTargetElement.attr("width").replace("px","");
mSvgHeight = iTargetElement.attr("height").replace("px","");

This will result that the svg and rect both gets width and height without unit.


It is better to give the first rect a class, in case other rects are added to the svg

mSvg.append("rect")
  .attr("width", mSvgWidth)
  .attr("height", mSvgHeight)
  .attr("class", "background");

and adjust the CSS

rect.background {
  fill: none;
  stroke: #888;
  stroke-width: 2px;
  pointer-events: all;
}


When adding a node to the list the simulation was not started again. Adding a call to the function fixed that

function addNode (iNode)
{
    // ...
    updateSimulation();
    // ...
}


Because the initial lists are empty the construction of the link and node gs can be simplified

  // Create links structure
  mSvg.append("g")
    .attr("class", "links");

  mLinksRef = mSvg.select(".links").selectAll(".link");

  // Create nodes structure
  mSvg.append("g")
    .attr("class", "nodes")
    .selectAll(".node");

  mNodesRef = mSvg.select(".nodes").selectAll(".node");


If you remove the g added to the g.node the transformation will be set on the g.node and has a result that everything belonging to this node is transformed.


Setting an alphaTarget of 0.1 for the dragend results that the simulation takes a very long time till it finishes. There seems to be an alternative stop but it takes way to long.

  function graphDragended (d) 
  {
    if (!d3.event.active) mSimulation.alphaTarget(0);
    d.fx = null;
    d.fy = null;
  };

Upvotes: 1

Related Questions