Как сохранить равную ширину перпендикуляра между двумя кривыми Безье? - PullRequest
0 голосов
/ 03 апреля 2020

Я создаю связь между точками с кривой Безье для диаграммы Санки.

Вот код, который я пробовал:

let 
  margin = 10,
  x0 = 20,
  y0 = 20,
  x1 = 150,
  y1 = 100,
  width = 30,
  path = d3.path(),
  path2 = d3.path(),
  controlPointX = (x0 + x1) / 2;

/* with filled path */
path.moveTo(x0, y0);
path.bezierCurveTo(controlPointX, y0, controlPointX, y1, x1, y1);
path.lineTo(x1, y1 + width);
path.bezierCurveTo(controlPointX, y1 + width, controlPointX, y0 + width, x0, y0 + width);
path.closePath();

let svg = d3.select('svg');
let g = svg.append('g').attr('transform', `translate(${margin}, ${margin})`);
g.append('path')
  .attr('d', path)
  .attr('fill', 'red');

// curve 2 offset
y0 += 120;
y1 += 120;

// with stroke
path2.moveTo(x0, y0);
path2.bezierCurveTo(controlPointX, y0, controlPointX, y1, x1, y1);
g.append('path')
  .attr('d', path2)
  .attr('stroke-width', width)
  .attr('stroke', 'blue')
  .attr('fill', 'none');

enter image description here

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

Fiddle Link: https://jsfiddle.net/3cxt40Lz/

1 Ответ

3 голосов
/ 03 апреля 2020

Вот приблизительное решение.

Я открыл сгенерированный SVG в программном обеспечении для векторного редактирования, чтобы проверить контрольные точки кривой Безье.

enter image description here

Немного поиграв, оказалось, что смещение нижних контрольных точек по горизонтали влево адаптировало кривую по желанию:

enter image description here

Итак, вернемся к коду, создал новую контрольную точку, смещенную влево на width / 2:

controlPointX2 = (x0 + x1 - width) / 2;

/* with filled path */
path.moveTo(x0, y0);
path.bezierCurveTo(controlPointX, y0, controlPointX, y1, x1, y1);
path.lineTo(x1, y1 + width);
path.bezierCurveTo(controlPointX2, y1 + width, controlPointX2, y0 + width, x0, y0 + width);

Результат не совсем такой, как синяя кривая, но очень близко, как показано ниже, где красная кривая показана над синей (с некоторой прозрачностью).

result

Обновлено jsFiddle:

https://jsfiddle.net/zbe90rjq/1/

...