Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

d3js force node xy start position

I have a node with fx/fy parameter on simulation starting. This node is fixed on the correct position. But now I want to define x and y coordinates for one or multiple other nodes (in this example: number 10 in jsfiddle), the purpose is to start the simulation of this "unfixed" nodes on a given position and not 0/0. Why is the node fixed on 0/0?

jsfiddle example: https://jsfiddle.net/6g9howo7/2/

                var nodes = [
                {
                    "id" : "1",
                    "fx" : "225",
                    "fy" : "225"
                },
                {
                    "id" : "2"
                },
                {
                    "id" : "3"
                },
                {
                    "id" : "4"
                },
                {
                    "id" : "5"
                },
                {
                    "id" : "6"
                },
                {
                    "id" : "7"
                },
                {
                    "id" : "8"
                },
                {
                    "id" : "9"
                },
                {
                    "id" : "10",
                    "x" : "125",
                    "y" : "125" 
                },
                {
                    "id" : "11"
                },
                {
                    "id" : "12"
                },
                {
                    "id" : "13"
                },
                {
                    "id" : "14"
                },
                {
                    "id" : "15"
                }
            ]

            var links = 
            [
                {
                    "source" : 1,
                    "target" : 2
                },
                {
                    "source" : 1,
                    "target" : 3
                },
                {
                    "source" : 1,
                    "target" : 4
                },
                {
                    "source" : 1,
                    "target" : 5
                },
                {
                    "source" : 1,
                    "target" : 6
                },
                {
                    "source" : 1,
                    "target" : 7
                },
                {
                    "source" : 1,
                    "target" : 8
                },
                {
                    "source" : 1,
                    "target" : 9
                },
                {
                    "source" : 1,
                    "target" : 10
                },
                {
                    "source" : 10,
                    "target" : 11
                },
                {
                    "source" : 10,
                    "target" : 12
                },
                {
                    "source" : 10,
                    "target" : 13
                },
                {
                    "source" : 10,
                    "target" : 14
                },
                {
                    "source" : 10,
                    "target" : 15
                }
            ]


            var svg = d3.select("svg")

                var zoom = d3.zoom()
                    .on("zoom", zoomed);
                    //.scaleExtent([1 / 8, 4])

                    svg
                        .call(zoom).on("dblclick.zoom", null)


            var g = svg.append("g");

            function zoomed() {
            g.attr("transform", d3.event.transform);
            }

            var color = d3.scaleOrdinal(d3.schemeCategory20);



            var simulation = d3.forceSimulation()
                //.force("link", d3.forceLink().id(function(d) { return d.id; }).distance(function(d) {return d.distance/2;}).strength(1))
            .force("link", d3.forceLink().id(function(d) { return d.id; }).distance(10).strength(1))
            .force("charge", d3.forceManyBody().strength(-10).distanceMax(100));
            //.force("center", d3.forceCenter(1000, 1000));
            //.force("y", d3.forceY(500))
            //.force("x", d3.forceX(500));
            //.force("collide",d3.forceCollide(.5));
            //.force("collide",d3.forceCollide( function(d){return d.r + 8 }).iterations(4) );


            var link = g.append("g")
                .attr("class", "links")
                .selectAll("line")
                .data(links)
                .enter().append("line")
                    .attr("stroke-width", 1 /*function(d) { return Math.sqrt(2); }*/)
                .style("stroke", 'red');

            var node = g.append("g")
                .attr("class", "nodes")
                .selectAll("circle")
                .data(nodes)
                .enter().append("circle")
            .attr("r",3)
            //  .attr("cx", function(d) { return d.x; })
            //  .attr("cy", function(d) { return d.y; })
                .on("dblclick", dblclick)
                .call(d3.drag()
                    .on("start", dragstarted)
                    .on("drag", dragged)
                    .on("end", dragended));


                node.append("title")
                    .text(function(d) { return d.id; });


            simulation.nodes(nodes)
                //  .alphaDecay(0.5)
                .velocityDecay(0.1)
                .on("tick", ticked);

            simulation.force("link")
                .links(links);


            function ticked() {
            link
                .attr("x1", function(d) { return d.source.x; })
                .attr("y1", function(d) { return d.source.y; })
                .attr("x2", function(d) { return d.target.x; })
                .attr("y2", function(d) { return d.target.y; });

            node
                .attr("cx", function(d) { return d.x; })
                .attr("cy", function(d) { return d.y; });

            }

            function dblclick(d) {
            d.fx = null;
            d.fy = null;
            }

            function dragstarted(d) {
            //if (!d3.event.active) simulation.alphaTarget(0.3).restart();
            simulation.restart();
            // simulation.alpha -> redémarre la période de simulation
            simulation.alpha(1.0);
            d.fx = d.x;
            d.fy = d.y;
            }

            //Grid
            var grid = 50;

            function dragged(d,i) {
            //force.stop();
            //var grid = 50;

            var gx = Math.round(d3.event.x/grid)*grid;
            var gy = Math.round(d3.event.y/grid)*grid;

            d.fx = gx;
            d.fy = gy;
            }


            function dragended(d) {
            if (!d3.event.active) simulation.alphaTarget(0);
            //    console.log(d);
            //  d.fx = null;
            //  d.fy = null;
            //  d.fixed = true;
            }

            //Grid
            var width = 7000;
            var height = 7000;


                var lineGraph = g.append("g")
                    .attr("width", width)
                    .attr("height", height);

            // Using for loop to draw multiple horizontal lines
            for (var j=grid; j <= width-grid; j=j+grid) {
                lineGraph.append("svg:line")
                    .attr("x1", grid)
                    .attr("y1", j)
                    .attr("x2", width-grid)
                    .attr("y2", j)
                    .style("stroke", "rgb(119,119,119)")
                    .style("stroke-width", 1);
            };

            // Using for loop to draw multiple vertical lines
            for (var j=grid; j <= height-grid; j=j+grid) {
                lineGraph.append("svg:line")
                    .attr("x1", j)
                    .attr("y1", grid)
                    .attr("x2", j)
                    .attr("y2", height-grid)
                    .style("stroke", "rgb(119,119,119)")
                    .style("stroke-width", 1);
            };
like image 748
vogis Avatar asked Jul 21 '17 12:07

vogis


1 Answers

Your approach is correct, setting x and y defines the start position. However, they have to be numbers, not strings.

Therefore, instead of:

{
    "id": "10",
    "x": "125",
    "y": "125"
}

It should be:

{
    "id": "10",
    "x": 125,
    "y": 125
}

Here is your code with that change:

var nodes = [{
  "id": "1",
  "fx": "225",
  "fy": "225"
}, {
  "id": "2"
}, {
  "id": "3"
}, {
  "id": "4"
}, {
  "id": "5"
}, {
  "id": "6"
}, {
  "id": "7"
}, {
  "id": "8"
}, {
  "id": "9"
}, {
  "id": "10",
  "x": 125,
  "y": 125
}, {
  "id": "11"
}, {
  "id": "12"
}, {
  "id": "13"
}, {
  "id": "14"
}, {
  "id": "15"
}]

var links = [{
  "source": 1,
  "target": 2
}, {
  "source": 1,
  "target": 3
}, {
  "source": 1,
  "target": 4
}, {
  "source": 1,
  "target": 5
}, {
  "source": 1,
  "target": 6
}, {
  "source": 1,
  "target": 7
}, {
  "source": 1,
  "target": 8
}, {
  "source": 1,
  "target": 9
}, {
  "source": 1,
  "target": 10
}, {
  "source": 10,
  "target": 11
}, {
  "source": 10,
  "target": 12
}, {
  "source": 10,
  "target": 13
}, {
  "source": 10,
  "target": 14
}, {
  "source": 10,
  "target": 15
}]


var svg = d3.select("svg")

var zoom = d3.zoom()
  .on("zoom", zoomed);
//.scaleExtent([1 / 8, 4])

svg
  .call(zoom).on("dblclick.zoom", null)


var g = svg.append("g");

function zoomed() {
  g.attr("transform", d3.event.transform);
}

var color = d3.scaleOrdinal(d3.schemeCategory20);



var simulation = d3.forceSimulation()
  //.force("link", d3.forceLink().id(function(d) { return d.id; }).distance(function(d) {return d.distance/2;}).strength(1))
  .force("link", d3.forceLink().id(function(d) {
    return d.id;
  }).distance(10).strength(1))
  .force("charge", d3.forceManyBody().strength(-10).distanceMax(100));
//.force("center", d3.forceCenter(1000, 1000));
//.force("y", d3.forceY(500))
//.force("x", d3.forceX(500));
//.force("collide",d3.forceCollide(.5));
//.force("collide",d3.forceCollide( function(d){return d.r + 8 }).iterations(4) );


var link = g.append("g")
  .attr("class", "links")
  .selectAll("line")
  .data(links)
  .enter().append("line")
  .attr("stroke-width", 1 /*function(d) { return Math.sqrt(2); }*/ )
  .style("stroke", 'red');

var node = g.append("g")
  .attr("class", "nodes")
  .selectAll("circle")
  .data(nodes)
  .enter().append("circle")
  .attr("r", 3)
  //	.attr("cx", function(d) { return d.x; })
  //  .attr("cy", function(d) { return d.y; })
  .on("dblclick", dblclick)
  .call(d3.drag()
    .on("start", dragstarted)
    .on("drag", dragged)
    .on("end", dragended));


node.append("title")
  .text(function(d) {
    return d.id;
  });


simulation.nodes(nodes)
  //  .alphaDecay(0.5)
  .velocityDecay(0.1)
  .on("tick", ticked);

simulation.force("link")
  .links(links);


function ticked() {
  link
    .attr("x1", function(d) {
      return d.source.x;
    })
    .attr("y1", function(d) {
      return d.source.y;
    })
    .attr("x2", function(d) {
      return d.target.x;
    })
    .attr("y2", function(d) {
      return d.target.y;
    });

  node
    .attr("cx", function(d) {
      return d.x;
    })
    .attr("cy", function(d) {
      return d.y;
    });

}

function dblclick(d) {
  d.fx = null;
  d.fy = null;
}

function dragstarted(d) {
  //if (!d3.event.active) simulation.alphaTarget(0.3).restart();
  simulation.restart();
  // simulation.alpha -> redémarre la période de simulation
  simulation.alpha(1.0);
  d.fx = d.x;
  d.fy = d.y;
}

//Grid
var grid = 50;

function dragged(d, i) {
  //force.stop();
  //var grid = 50;

  var gx = Math.round(d3.event.x / grid) * grid;
  var gy = Math.round(d3.event.y / grid) * grid;

  d.fx = gx;
  d.fy = gy;
}


function dragended(d) {
  if (!d3.event.active) simulation.alphaTarget(0);
  //    console.log(d);
  //  d.fx = null;
  //  d.fy = null;
  //  d.fixed = true;
}

//Grid
var width = 7000;
var height = 7000;


var lineGraph = g.append("g")
  .attr("width", width)
  .attr("height", height);

// Using for loop to draw multiple horizontal lines
for (var j = grid; j <= width - grid; j = j + grid) {
  lineGraph.append("svg:line")
    .attr("x1", grid)
    .attr("y1", j)
    .attr("x2", width - grid)
    .attr("y2", j)
    .style("stroke", "rgb(119,119,119)")
    .style("stroke-width", 1);
};

// Using for loop to draw multiple vertical lines
for (var j = grid; j <= height - grid; j = j + grid) {
  lineGraph.append("svg:line")
    .attr("x1", j)
    .attr("y1", grid)
    .attr("x2", j)
    .attr("y2", height - grid)
    .style("stroke", "rgb(119,119,119)")
    .style("stroke-width", 1);
};
html {
  width: 100%;
  height: 100%;
}

body {
  width: 100%;
  height: 100%;
  margin: 0;
  padding: 0;
  display: flex;
  font-family: sans-serif;
  font-size: 75%;
}


/* SVG styles */

svg {
  flex-basis: 100%;
}

.links line {
  stroke: #999;
  stroke-opacity: 0.6;
}

.nodes circle {
  stroke: #fff;
  stroke-width: 1.5px;
}
<script src="https://d3js.org/d3.v4.min.js"></script>
<svg></svg>
like image 108
Gerardo Furtado Avatar answered Sep 30 '22 14:09

Gerardo Furtado