atmd
atmd

Reputation: 7490

D3 centre point of a line (not path)

are a few questions on here and on the D3 site about how you'd find the centre point (or any point) along a path, however I can't seem to find how to do it with a line.

I've done a simple jsfiddle here. Essentially I need to add a shape (using text in the jsfiddle to make it clearer) at a point along a line (lets say the middle for simplicity)

So I have a svg:

var canvas = d3.select('body').append('svg').attr('width', 500).attr('height', 500);

And add a line (the position is fixed and doesnt come from data)

var line = canvas.append('line').attr('x1', 50).attr('y1', 50).attr('x2', 250).attr('y2', 150);

The I add some text just to demo to the top and bottom of that line

canvas.append('text').attr('x', line.attr('x1')).attr('y', line.attr('y1')).text('top');
canvas.append('text').attr('x', line.attr('x2')).attr('y', line.attr('y2')).text('bottom');

path's have methods to get the centre point and width/BBox etc, but line doesnt seem to.

Anyone have any ideas how this can be achieved?

My initial though was to just get the difference between the x1/x2 values, like this:

canvas.append('text')
  .attr('x', parseInt(line.attr('x2') - line.attr('x1')))
  .attr('y', parseInt(line.attr('y2') - line.attr('y1')))
  .text('just looks a bit off');

But as you'll see from the jsfiddle, it's just off somehow.

Anyone want to point out my mistake?

Upvotes: 1

Views: 754

Answers (3)

Gilsha
Gilsha

Reputation: 14591

Line

Use simple mathematics, distance formula.

var canvas = d3.select('body').append('svg').attr('width', 500).attr('height', 500);

var line = canvas.append('line').attr('x1', 50).attr('y1', 50).attr('x2', 250).attr('y2', 150);
var x1 = parseInt(line.attr("x1"));
var y1 = parseInt(line.attr("y1"));
var x2 = parseInt(line.attr("x2"));
var y2 = parseInt(line.attr("y2"));

var midPoint = { x: (x1+x2)/2, y: (y1+y2)/2 };
canvas.append('text').attr('x', midPoint.x).attr('y', midPoint.y).text('X');
line{
    stroke:#444;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/3.4.11/d3.min.js"></script>

Path

var canvas = d3.select('body').append('svg').attr('width', 500).attr('height', 500);

var line = canvas.append('path').attr('d', "M 50 50 L 250 150");
var path = line.node();

var midPoint = path.getPointAtLength(path.getTotalLength()/2);
canvas.append('text').attr('x', midPoint.x).attr('y', midPoint.y).text('X');
path{
  stroke: red;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/3.4.11/d3.min.js"></script>

Upvotes: 1

Philipp Dahse
Philipp Dahse

Reputation: 748

I guess, this will work:

var lineData = {x1: 50, y1: 50, x2: 250, y2: 150};
var canvas = d3.select('body').append('svg').attr('width', 500).attr('height', 500);
var line = canvas.append('line').attr('x1', lineData.x1).attr('y1', lineData.y1).attr('x2', lineData.x2).attr('y2', lineData.y2);
console.log(line);

var x = lineData.x1 + Math.abs(lineData.x2 - lineData.x1) / 2;
var y = lineData.y1 + Math.abs(lineData.y2 - lineData.y1) / 2;
console.log([x,y]);

canvas.append('text').attr('x', x).attr('y', y).text('X');

Upvotes: 1

atmd
atmd

Reputation: 7490

Resolved the issue so thought I'd answer it incase anyone else found the question.

Used getBBox() of the node (using .node()). Used that to get the width, height and xy:

var canvas = d3.select('body').append('svg')
  .attr('width', 500)
  .attr('height', 500);

var line = canvas.append('line')
  .attr('x1', 50)
  .attr('y1', 150)
  .attr('x2', 50)
  .attr('y2', 250);

Then the middle x and y are:

var midX = line.node().getBBox().x + line.node().getBBox().width / 2;
var midY = line.node().getBBox().y + line.node().getBBox().height / 2;

Upvotes: 0

Related Questions