Таблица шагов SVG с закругленными углами - PullRequest
1 голос
/ 02 марта 2020

Как создать пошаговую диаграмму с плавными закругленными углами, как в примере ниже?

Пример графика

Радиус углов зависит от разностей координат между шагами.

Я использовал ссылки d3. js и пытался создавать собственные SVG-кривые, но не могу правильно их реализовать.

Буду признателен за любые идеи. Может быть, для этого есть какая-то библиотека?

UPD: полилинейный код для @ exaneta

<polyline points="10,40 15,45 30,70 35,75" fill="none" stroke="black" stroke-width="1"></polyline>

1 Ответ

1 голос
/ 03 марта 2020

Как я уже говорил, вы можете использовать javascript для вычисления координат для квадратичной c кривой Безье для закругленных углов. Контрольной точкой Безье является точка полилинии. Затем вам нужно получить начальную и конечную точки Безье в виде точки на расстоянии r от контрольной точки на полилинии. Когда у вас есть все точки для нового пути, вы можете использовать их для построения значения атрибута d thePath.

. Убедитесь, что переменная r имеет разумный размер.

let polypoints = poly.getAttribute("points");
let r = 5; // distance for the curvature

function getPoints(poly) {
  // poly is the polygon's element d attribute
  let polyPoints = poly
    .replace(/(\r?\n|\r|\t)+/g, "")
    .replace(/\-/g, " -")
    .split(/[\s,]+/);
  polyPoints = removeEmptyElements(polyPoints);
  let points = [];
  for (let i = 0; i < polyPoints.length; i += 2) {
    let temp = [Number(polyPoints[i]), Number(polyPoints[i + 1])];
    points.push(temp);
  }
  return points;////[[10, 40],[15, 45],[30, 70],[35, 75]]
}

function getAngle(c, l) {
  let delta_x = l.x - c.x;
  let delta_y = l.y - c.y;
  let a = Math.atan2(delta_y, delta_x);
  return a; //in radians;
}

function removeEmptyElements(array) {
  for (let i = 0; i < array.length; i++) {
    if (array[i] == "") {
      array.splice(i, 1);
    }
  }
  return array;
}

function polygonWithRoundedCorners(poly, r) {
  let points = getPoints(poly);
  //move to the first point
  let d = `M${points[0][0]},${points[0][1]}`;
  
  for (let i = 1; i < points.length - 1; i++) {
    let previous = i - 1;
    let next = i + 1;
    let c = {};//the control point
    c.x = points[i][0];
    c.y = points[i][1];
    let l1 = {};
    l1.x = points[previous][0];
    l1.y = points[previous][1];
    let l2 = {};
    l2.x = points[next][0];
    l2.y = points[next][1];
    let a1 = getAngle(c, l1);
    let a2 = getAngle(c, l2);

    //if great precision is needed remove .toFixed(3)
    //x1 and y1 are defining the start point of the Bézier
    let x1 = (c.x + r * Math.cos(a1)).toFixed(3);
    let y1 = (c.y + r * Math.sin(a1)).toFixed(3);
    //x2 and y2 are defining the end point of the Bézier
    let x2 = (c.x + r * Math.cos(a2)).toFixed(3);
    let y2 = (c.y + r * Math.sin(a2)).toFixed(3);
    //build the d attribute
    d += "L" + x1 + "," + y1 + " Q" + c.x + "," + c.y + " " + x2 + "," + y2;
  }
  //move to the last point and return the d attribute
  return (d += `L${points[points.length - 1][0]},${
    points[points.length - 1][1]
  }`);
}

thePath.setAttributeNS(null, "d", polygonWithRoundedCorners(polypoints, r));
svg{border:solid;width:90vh}
<svg viewBox="-5 30 55 55">
<polyline id="poly" points="10,40 15,45 30,70 35,75" fill="none" stroke="black" ></polyline>  
<path id="thePath" fill="none" stroke="red"  /> 
</svg>
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...