Как нарисовать дугу с массивом точек в d3 v4

1

Я хотел нарисовать дугу из массива таких точек:

var points = [
    [
        51.93326250000001,
        21.4375
    ],
    [
        36.72733749999999,
        40.603550000000002
    ],
    [
        21.527537500000008,
        21.4144
    ]
];

Я попытался использовать d3.line(), d3.curveBasis() и d3.curveBundle.beta(1).

var arcPath = d3.line()
    .x(function (d) {
         return d[0];
    })
    .y(function (d) {
         return d[1];
    })
    .curve(d3.curveBasis);
    var arc = node.append('path').attr("d", arcPath(points));

Но он рисует изогнутую линию:

Изображение 174551

который не является тем, что я ищу. Вместо этого мне нужна дуга:

Изображение 174551

Я не понимаю, как это использовать:

var arc = d3.arc()
    .innerRadius(180)
    .outerRadius(240)
    .startAngle(0);

с моими очками.

  • 2
    Команда SVG arc описывает эллиптические дуги. Трех точек недостаточно, чтобы найти единственное решение; вам нужно установить дополнительные ограничения (такие как большая и малая ось одинаковой длины, то есть круг)
Теги:
d3.js
svg

1 ответ

3

Чтобы нарисовать дугу, вам нужно знать координаты центра связанного круга и его радиуса.

В этом случае, когда ваша дуга (часть круга) определяется координатами 3 точек, вам нужно вычислить центр круга, определяемый этими тремя точками:

var points = [
  [
    51.93326250000001,
    21.4375
  ],
  [
    36.72733749999999,
    40.603550000000002
  ],
  [
    21.527537500000008,
    21.4144
  ]
];

function calculateCircleCenter(A, B, C) {

  var yDelta_a = B[1] - A[1];
  var xDelta_a = B[0] - A[0];
  var yDelta_b = C[1] - B[1];
  var xDelta_b = C[0] - B[0];

  var center = [];

  var aSlope = yDelta_a / xDelta_a;
  var bSlope = yDelta_b / xDelta_b;

  center[0] = (aSlope*bSlope*(A[1] - C[1]) + bSlope*(A[0] + B[0]) - aSlope*(B[0]+C[0]) )/(2* (bSlope-aSlope) );
  center[1] = -1*(center[0] - (A[0]+B[0])/2)/aSlope +  (A[1]+B[1])/2;

  return center;
}

function distance(A, B) {
  var a = A[0] - B[0];
  var b = A[1] - B[1];
  return Math.sqrt(a*a + b*b);
}

var center = calculateCircleCenter(points[0], points[1], points[2]);

var radius = distance(points[0], center);

var svg = d3.select("svg").attr("width", 200).attr("height", 200);

// The circle
svg.append("circle")
  .attr("cx", center[0])
  .attr("cy", center[1])
  .attr("r", radius)
  .attr("fill", "white")
  .attr("stroke", "black");

var startAngle = Math.atan2(points[0][1] - center[1], points[0][0] - center[0]) + 0.5 * Math.PI;
var endAngle = Math.atan2(center[1] - points[2][1], center[0] - points[2][0]) + 1.5 * Math.PI;

var arc = d3.arc().innerRadius(radius).outerRadius(radius);

var sector = svg.append("path")
  .attr("fill", "none")
  .attr("stroke-width", 2)
  .attr("stroke", "blue")
  .attr("d", arc({ "startAngle": startAngle, "endAngle": endAngle }))
  .attr("transform", "translate(" + center[0] + "," + center[1] + ")");

// The 3 points:
svg.selectAll("small_circle")
  .data(points)
  .enter().append("circle")
  .attr("cx", function (d) { return d[0]; })
  .attr("cy", function (d) { return d[1]; })
  .attr("r", 2)
  .attr("fill", "red");
<svg></svg>
<script src="/d3.v4.min.js"></script>

Что касается математики:

Вы можете использовать любой метод для вычисления центра круга, определенного тремя точками. Здесь используется этот один.

Затем вы можете вычислить радиус этого круга, вычислив расстояние между этим центром и одной из трех точек.

И вам также нужно знать начальный и конечный углы дуги, основанные на угле между первой точкой и центром окружности и углом между последней точкой и центром окружности. Этого можно достичь с помощью этой формулы.


Что касается чертежа:

Вот как вы можете нарисовать дугу с d3.js:

var arc = d3.arc().innerRadius(radius).outerRadius(radius);

var sector = svg.append("path")
 .attr("fill", "none")
 .attr("stroke-width", 2)
 .attr("stroke", "blue")
 .attr("d", arc({ startAngle: 0.5 * Math.PI, endAngle: 1.5 * Math.PI }))
 .attr("transform", "translate(" + center[0] + "," + center[1] + ")");

Дуга определяется ее радиусом. Более конкретно, его innerRadius и outerRadius. В нашем случае это то же самое.

Затем мы определяем центр дуги, переводя дугу:

.attr("transform", "translate(" + center[0] + "," + center[1] + ")");

И таким образом мы определяем начальный и конечный углы дуги:

.attr("d", arc({ "startAngle": startAngle, "endAngle": endAngle }))

где startAngle и endAngle вычисляются на основе первых/последних точек и центра:

var startAngle = Math.atan2(points[0][1] - center[1], points[0][0] - center[0]) + 0.5 * Math.PI;
var endAngle = Math.atan2(center[1] - points[2][1], center[0] - points[2][0]) + 1.5 * Math.PI;
  • 0
    Я думаю, что OP хочет нарисовать путь с сегментом дуги, а не кругом.
  • 0
    Да, именно об этом я и думал, читая пост обратно. Обновил ответ.

Ещё вопросы

Сообщество Overcoder
Наверх
Меню