Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Positioning nodes with x and y #274

Closed
z-sanjivini opened this issue Dec 4, 2019 · 13 comments
Closed

Positioning nodes with x and y #274

z-sanjivini opened this issue Dec 4, 2019 · 13 comments
Labels
enhancement improving existent functionality or performance related feature request question

Comments

@z-sanjivini
Copy link

I have been using the default example given and was simply playing around with the config.

import React from "react";
import { Graph } from "react-d3-graph";

// graph payload (with minimalist structure)
const data = {
    // nodes: [{ id: "Harry" }, { id: "Sally" }, { id: "Alice" }],
    // links: [{ source: "Harry", target: "Sally" }, { source: "Harry", target: "Alice" }],
    nodes : [
      {
          id: 1,
          name: "A",
          x: 50,
          y: 300,
      },
      {
          id: 2,
          name: "B",
          x: 40,
          y: 310,
      },
      {
          id: 3,
          name: "C",
          x: 40,
          y: 310,
      },
      {
          id: 4,
          name: "D",
          x: 400,
          y: 200,
      },
  ],
    links: [
      {
          source: 1,
          target: 2,
          //label: "A-B",
      },
      {
          source: 1,
          target: 3,
          //label: "A-C",
      },
      {
          source: 2,
          target: 4,
          //label: "A-D",
      },
  ],
};

// the graph configuration, you only need to pass down properties
// that you want to override, otherwise default ones will be used
const myConfig = {
    // nodeHighlightBehavior: true,
    // node: {
    //     color: "lightgreen",
    //     size: 120,
    //     highlightStrokeColor: "blue",
    // },
    // link: {
    //     highlightColor: "lightblue",
    // },
    height: 1200,
    width: 1200,
    nodeHighlightBehavior: true,
    linkHighlightBehavior: true,
    staticGraphWithDragAndDrop: true,
    node: {
        fontSize: 12,
        highlightFontSize: 12,
        highlightFontWeight: "bold",
        highlightStrokeColor: "blue",
        labelProperty: "name",
        size: 500,
        strokeWidth: 2,
    },
    link: {
        highlightColor: "blue",
        renderLabel: true,
        highlightFontWeight: "bold",
        semanticStrokeWidth: true,
        fontSize: 12,
    },
    d3: {
        gravity: -400,
        linkLength: 180,
    },
};

// graph event callbacks
const onClickGraph = function() {
    window.alert(`Clicked the graph background`);
};

const onClickNode = function(nodeId) {
    window.alert(`Clicked node ${nodeId}`);
};

// const onDoubleClickNode = function(nodeId) {
//     window.alert(`Double clicked node ${nodeId}`);
// };

const onRightClickNode = function(event, nodeId) {
    window.alert(`Right clicked node ${nodeId}`);
};

const onMouseOverNode = function(nodeId) {
    // window.alert(`Mouse over node ${nodeId}`);
};

const onMouseOutNode = function(nodeId) {
    // window.alert(`Mouse out node ${nodeId}`);
};

const onClickLink = function(source, target) {
    window.alert(`Clicked link between ${source} and ${target}`);
};

const onRightClickLink = function(event, source, target) {
    window.alert(`Right clicked link between ${source} and ${target}`);
};

const onMouseOverLink = function(source, target) {
    // window.alert(`Mouse over in link between ${source} and ${target}`);
};

const onMouseOutLink = function(source, target) {
    // window.alert(`Mouse out link between ${source} and ${target}`);
};

const onNodePositionChange = function(nodeId, x, y) {
    window.alert(`Node ${nodeId} is moved to new position. New position is x= ${x} y= ${y}`);
};

function App() {
  return (<Graph
    id="graph-id" // id is mandatory, if no id is defined rd3g will throw an error
    data={data}
    config={myConfig}
    onClickNode={onClickNode}
    onRightClickNode={onRightClickNode}
    onClickGraph={onClickGraph}
    onClickLink={onClickLink}
    onRightClickLink={onRightClickLink}
    onMouseOverNode={onMouseOverNode}
    onMouseOutNode={onMouseOutNode}
    onMouseOverLink={onMouseOverLink}
    onMouseOutLink={onMouseOutLink}
    onNodePositionChange={onNodePositionChange}
/>)
}

export default App;

Each time I run this code, even when the coordinates have been hardcoded, I get new positions. Why is that so since they should now be fixed. I would like to simply create a tree structure with siblings getting equally spaced, how do I calculate these coordinates. Could you please explain?

@danielcaldas
Copy link
Owner

@StevenHeven maybe you could share a bit no your experience of displaying tree-like structure with react-d3-graph 🙂 (sorry to tag you here directly 🙈 )

@z-sanjivini
Copy link
Author

Also, even after fixing the coordinates why do the node's position change everytime on re-rendering? I believed that they would remain in constant positions.

@StevenHeven
Copy link

StevenHeven commented Dec 11, 2019

Hi @z-sanjivini ,

I launched your code and, except that you have nodes with the same x values, it works.

Afterwards, to create a kind of tree with child-parent relationships, you must first walk your tree like roads.
Let me explain:
You have to go through your graph from the beginning, and go up via the links to know who the children of the node being looked at are, and then create a table of your nodes that will be in the right order or then simply a map with a key a node and worth its children for example. Then with this table, you can then define positions according to the children of the nodes.

That is basically how to proceed in a logical way. That's what it can do:

TreeGraph

I'm not going to put my code to get to that because there's no point but it's to make the principle understandable;)

If you need more explanations, I'm here ;)
And no problem @danielcaldas , if i can help ;)

@antoninklopp
Copy link
Collaborator

@StevenHeven I also had problem with node positioning, even with gravity at 0 and different positions they get rearranged by d3. How do you get around this problem?

@StevenHeven
Copy link

I don't understand how you get this trouble because i run your code and it's work :
your_graph_work

With your code upper ....

@StevenHeven
Copy link

If you want to see how i made my tree graph, you can check the Issue#270 to see the code ;)

@antoninklopp
Copy link
Collaborator

@StevenHeven, I can reproduce the problem here (link to sandbox)
The real problem is that the d3.linkLength rearranges the nodes alone.

In my example, 3 nodes should be at the same level at the bottom, and one above the second one, like this :
without-links

But when I add the links I get this :
with-links

Do you have any fix for this?

@antoninklopp
Copy link
Collaborator

After looking a bit at the code, I found exactly the behavior I'd like to have :
Changing the function here

From :

   _graphBindD3ToReactComponent() {
        this.state.simulation.nodes(this.state.d3Nodes).on("tick", this._tick);
        this._graphLinkForceConfig();
        this._graphNodeDragConfig();
    }

To :

   _graphBindD3ToReactComponent() {
        this._graphNodeDragConfig();
    }

It lets my config as I described it in the doc.
@danielcaldas Is it possible to override this behavior, or at least to override it if the user specified an x, y position for each entry?

@danielcaldas danielcaldas added the needs more info not enough proof to specify issue label Dec 13, 2019
@danielcaldas
Copy link
Owner

danielcaldas commented Dec 13, 2019

I currently don't have time to look into it in more detail, but my approach would be something like:

First look into the comments from @StevenHeven, maybe you're missing something? If that's not the case we could try to go for the following implementation:

  1. Create a new config to disable link force and simulation
config = {
   nodeHighlightBehaviour: true,
   // ... other configs
   disableLinkForceConfig: false, // --> new API config
  1. Implement changes according to the config
_graphBindD3ToReactComponent() {
    if (disableLinkForceConfig) {
        this.state.simulation.nodes(this.state.d3Nodes).on("tick", this._tick);
        this._graphLinkForceConfig();
    }
    this._graphNodeDragConfig();
}

Let me know if you're willing to give this a try, cheers!

@antoninklopp
Copy link
Collaborator

Sure I will do a PR for this one !

@danielcaldas
Copy link
Owner

Thanks @antoninklopp, closing this with #278

@danielcaldas danielcaldas added enhancement improving existent functionality or performance related feature request question and removed needs more info not enough proof to specify issue question labels Jan 11, 2020
@ASchwad
Copy link

ASchwad commented Nov 18, 2020

Sorry for bringing this old issue up again, but this seems like the most fitting place for my question:

I would like to statically position nodes on 3 levels based on the x coordinate. If there are multiple nodes on one level, they should automatically take distance from each other by adjusting their y-coordinate.
Is it still possible to use gravity for the y-coordinate, if I set the following config? I cannot get it to work so far.

d3: { disableLinkForce: true, gravity: -500 },

@danielcaldas
Copy link
Owner

danielcaldas commented Nov 18, 2020

Hi @ASchwad, you would have to compute yourself the x,y coordinates to fulfill your distancing requirements.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
enhancement improving existent functionality or performance related feature request question
Projects
None yet
Development

No branches or pull requests

5 participants