Использование d3js для вычисления средних точек и траектории кривой для квадратичных SVG-коннекторов - PullRequest
1 голос
/ 08 июля 2019

Я пытаюсь показать соединения от прямоугольников слева до прямоугольников справа.Прямоугольники с обеих сторон построены динамически на основе значений в JSON.В настоящее время я поместил пустые элементы div на левый и правый конец прямоугольников и использовал их как ссылку для получения координат x, y и использовал их для построения квадратичной SVG-кривой.В то время как это делает работу, я хотел знать, смогу ли я улучшить способ вычисления пути кривой.

Расчет кривой SVG основан на ответе, найденном здесь https://stackoverflow.com/a/49286885/9924482. Это работает, но я хотелчтобы узнать, может ли d3js автоматически построить соединитель с учетом двух точек. Если бы он мог рассчитать среднюю точку, я уверен, что соединения будут более плавными, чем мои вычисления.

function x() {
    var p1x = parseFloat(document.getElementById("au").getAttribute("cx"));
    var p1y = parseFloat(document.getElementById("au").getAttribute("cy"));
    var p2x = parseFloat(document.getElementById("sl").getAttribute("cx"));
    var p2y = parseFloat(document.getElementById("sl").getAttribute("cy"));

    // mid-point of line:
    var mpx = (p2x + p1x) * 0.5;
    var mpy = (p2y + p1y) * 0.5;

    // angle of perpendicular to line:
    var theta = Math.atan2(p2y - p1y, p2x - p1x) - Math.PI / 2;

    // distance of control point from mid-point of line:
    var offset = 30;

    // location of control point:
    var c1x = mpx + offset * Math.cos(theta);
    var c1y = mpy + offset * Math.sin(theta);

    // show where the control point is:
    var c1 = document.getElementById("cp");
    c1.setAttribute("cx", c1x);
    c1.setAttribute("cy", c1y);

    // construct the command to draw a quadratic curve
    var curve = "M" + p1x + " " + p1y + " Q " + c1x + " " + c1y + " " + p2x + " " + p2y;
    var curveElement = document.getElementById("curve");
    curveElement.setAttribute("d", curve);
}

1 Ответ

1 голос
/ 08 июля 2019

Не ясно в вашем вопросе, сколько контрольных точек вы хотите.Если вы хотите создать ссылки с точкой перегиба, наиболее удобное решение - использовать D3 генераторы ссылок .

Например, предположим, у вас есть эти данные:

const data = [{x: 20, y: 20}, {x: 280, y: 130}];

Вы можете использовать генератор ссылок следующим образом:

const linkGenerator = d3.linkHorizontal()
  .x(d => d.x)
  .y(d => d.y)
  .source(d => d[0])
  .target(d => d[1]);

Вот демонстрационная версия:

const data = [{
  x: 20,
  y: 20
}, {
  x: 280,
  y: 130
}];
const svg = d3.select("svg");
const linkGenerator = d3.linkHorizontal()
  .x(d => d.x)
  .y(d => d.y)
  .source(d => d[0])
  .target(d => d[1]);
const circles = svg.selectAll(null)
  .data(data)
  .enter()
  .append("circle")
  .attr("r", 10)
  .attr("cx", d => d.x)
  .attr("cy", d => d.y);
const link = svg.append("path")
  .style("fill", "none")
  .style("stroke", "black")
  .attr("d", linkGenerator(data))
<script src="https://d3js.org/d3.v5.min.js"></script>
<svg></svg>

А вот еще одна демка со случайными данными:

const svg = d3.select("svg");
const linkGenerator = d3.linkHorizontal()
  .x(d => d.x)
  .y(d => d.y)
  .source(d => d[0])
  .target(d => d[1]);
draw();
d3.select("button").on("click", draw);

function draw() {
  const data = [{
    x: 20,
    y: 20 + Math.random() * 110
  }, {
    x: 280,
    y: 20 + Math.random() * 110
  }];
  const circles = svg.selectAll("circle")
    .data(data);
  circles.enter()
    .append("circle")
    .merge(circles)
    .attr("r", 10)
    .attr("cx", d => d.x)
    .attr("cy", d => d.y);
  const link = svg.selectAll("path")
    .data([data]);
  link.enter()
    .append("path")
    .style("fill", "none")
    .style("stroke", "black")
    .merge(link)
    .attr("d", linkGenerator(data))
};
<script src="https://d3js.org/d3.v5.min.js"></script>
<button>Change data</button>
<br>
<svg></svg>
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...