Accepted answer

Set d.fixed on the desired nodes to true, and initialize d.x and d.y to the desired position. These nodes will then still be part of the simulation, and you can use the normal display code (e.g., setting a transform attribute); however, because they are marked as fixed, they can only be moved by dragging and not by the simulation.

See the force layout documentation for more details (v3 docs, current docs), and also see how the root node is positioned in this example.


Fixed nodes in force layout for d3v4 and d4v5

In d3v3 d.fixed will fix nodes at d.x and d.y; however, in d3v4/5 this method no longer is supported. The d3 documentation states:

To fix a node in a given position, you may specify two additional properties:

fx - the node’s fixed x-position

fy - the node’s fixed y-position

At the end of each tick, after the application of any forces, a node with a defined node.fx has node.x reset to this value and node.vx set to zero; likewise, a node with a defined node.fy has node.y reset to this value and node.vy set to zero. To unfix a node that was previously fixed, set node.fx and node.fy to null, or delete these properties.

You can set fx and fy attributes for the force nodes in your data source, or you can add and remove fx and fy values dynamically. The snippet below sets these properties at the end of drag events, just drag a node to fix its position:

var data ={ 
  [{"id": "A"},{"id": "B"},{"id": "C"},{"id":"D"}], 
  [{"source": "A", "target": "B"}, 
   {"source": "B", "target": "C"},
   {"source": "C", "target": "A"},
   {"source": "D", "target": "A"}]
var height = 250;
var width = 400;

var svg ="body").append("svg")
var simulation = d3.forceSimulation()
    .force("link", d3.forceLink().id(function(d) { return; }).distance(50))
    .force("charge", d3.forceManyBody())
    .force("center", d3.forceCenter(width / 2, height / 2));
var link = svg.append("g")

var node = svg.append("g")
 .attr("r", 5)
   .on("drag", dragged)
   .on("end", dragended));
 .on("tick", ticked)

function ticked() {
   .attr("x1", function(d) { return d.source.x; })
   .attr("y1", function(d) { return d.source.y; })
   .attr("x2", function(d) { return; })
   .attr("y2", function(d) { return; });
   .attr("cx", function(d) { return d.x; })
   .attr("cy", function(d) { return d.y; });
function dragged(d) {
  d.fx = d3.event.x;
  d.fy = d3.event.y;

function dragended(d) {
  d.fx = d3.event.x;
  d.fy = d3.event.y;
<script src=""></script>

d3v6 changes to event listners

In the above snippet, the drag events use the form

function dragged(d) {
  d.fx = d3.event.x;
  d.fy = d3.event.y;

Where d is the datum of the node being dragged. In d3v6, the form is now:

function dragged(event) {
  event.subject.fx = event.x;
  event.subject.fy = event.y;


function dragged(event,d) {
  d.fx = event.x;
  d.fy = event.y;

The event is now passed directly to the listener, the second parameter passed to the event listener is the datum. Here's the canonical example on Observable.

Related Query