fix center calculation of simple Bezier edges

This commit is contained in:
Ze-Zheng Wu
2022-03-21 18:18:07 +08:00
parent 3b804d82ce
commit 6328b6fbe3
2 changed files with 56 additions and 30 deletions
-2
View File
@@ -10,8 +10,6 @@ export interface GetBezierPathParams {
targetY: number; targetY: number;
targetPosition?: Position; targetPosition?: Position;
curvature?: number; curvature?: number;
centerX?: number;
centerY?: number;
} }
interface GetControlWithCurvatureParams { interface GetControlWithCurvatureParams {
+56 -28
View File
@@ -1,7 +1,6 @@
import React, { memo } from 'react'; import React, { memo } from 'react';
import { EdgeProps, Position } from '../../types'; import { EdgeProps, Position } from '../../types';
import BaseEdge from './BaseEdge'; import BaseEdge from './BaseEdge';
import { getCenter } from './utils';
export interface GetSimpleBezierPathParams { export interface GetSimpleBezierPathParams {
sourceX: number; sourceX: number;
@@ -10,33 +9,31 @@ export interface GetSimpleBezierPathParams {
targetX: number; targetX: number;
targetY: number; targetY: number;
targetPosition?: Position; targetPosition?: Position;
centerX?: number;
centerY?: number;
} }
interface GetControlParams { interface GetControlParams {
pos: Position; pos: Position;
x: number; x1: number;
y: number; y1: number;
cX: number; x2: number;
cY: number; y2: number;
} }
function getControl({ pos, x, y, cX, cY }: GetControlParams): [number, number] { function getControl({ pos, x1, y1, x2, y2 }: GetControlParams): [number, number] {
let ctX: number, ctY: number; let ctX: number, ctY: number;
switch (pos) { switch (pos) {
case Position.Left: case Position.Left:
case Position.Right: case Position.Right:
{ {
ctX = cX; ctX = 0.5 * (x1 + x2);
ctY = y; ctY = y1;
} }
break; break;
case Position.Top: case Position.Top:
case Position.Bottom: case Position.Bottom:
{ {
ctX = x; ctX = x1;
ctY = cY; ctY = 0.5 * (y1 + y2);
} }
break; break;
} }
@@ -50,29 +47,59 @@ export function getSimpleBezierPath({
targetX, targetX,
targetY, targetY,
targetPosition = Position.Top, targetPosition = Position.Top,
centerX,
centerY,
}: GetSimpleBezierPathParams): string { }: GetSimpleBezierPathParams): string {
const [_centerX, _centerY] = getCenter({ sourceX, sourceY, targetX, targetY });
centerX = centerX ?? _centerX;
centerY = centerY ?? _centerY;
const [sourceControlX, sourceControlY] = getControl({ const [sourceControlX, sourceControlY] = getControl({
pos: sourcePosition, pos: sourcePosition,
x: sourceX, x1: sourceX,
y: sourceY, y1: sourceY,
cX: centerX, x2: targetX,
cY: centerY, y2: targetY,
}); });
const [targetControlX, targetControlY] = getControl({ const [targetControlX, targetControlY] = getControl({
pos: targetPosition, pos: targetPosition,
x: targetX, x1: targetX,
y: targetY, y1: targetY,
cX: centerX, x2: sourceX,
cY: centerY, y2: sourceY,
}); });
return `M${sourceX},${sourceY} C${sourceControlX},${sourceControlY} ${targetControlX},${targetControlY} ${targetX},${targetY}`; return `M${sourceX},${sourceY} C${sourceControlX},${sourceControlY} ${targetControlX},${targetControlY} ${targetX},${targetY}`;
} }
// @TODO: this function will recalculate the control points
// one option is to let getXXXPath() return center points
// but will introduce breaking changes
// the getCenter() of other types of edges might need to change, too
export function getSimpleBezierCenter({
sourceX,
sourceY,
sourcePosition = Position.Bottom,
targetX,
targetY,
targetPosition = Position.Top,
}: GetSimpleBezierPathParams): [number, number, number, number] {
const [sourceControlX, sourceControlY] = getControl({
pos: sourcePosition,
x1: sourceX,
y1: sourceY,
x2: targetX,
y2: targetY,
});
const [targetControlX, targetControlY] = getControl({
pos: targetPosition,
x1: targetX,
y1: targetY,
x2: sourceX,
y2: sourceY,
});
// quadratic bezier t=0.5 mid point, not the actual mid point, but easy to calculate
// https://stackoverflow.com/questions/67516101/how-to-find-distance-mid-point-of-bezier-curve
const centerX = sourceX * 0.125 + sourceControlX * 0.375 + targetControlX * 0.375 + targetX * 0.125;
const centerY = sourceY * 0.125 + sourceControlY * 0.375 + targetControlY * 0.375 + targetY * 0.125;
const xOffset = Math.abs(centerX - sourceX);
const yOffset = Math.abs(centerY - sourceY);
return [centerX, centerY, xOffset, yOffset];
}
export default memo( export default memo(
({ ({
sourceX, sourceX,
@@ -91,15 +118,16 @@ export default memo(
markerEnd, markerEnd,
markerStart, markerStart,
}: EdgeProps) => { }: EdgeProps) => {
const [centerX, centerY] = getCenter({ sourceX, sourceY, targetX, targetY, sourcePosition, targetPosition }); const params = {
const path = getSimpleBezierPath({
sourceX, sourceX,
sourceY, sourceY,
sourcePosition, sourcePosition,
targetX, targetX,
targetY, targetY,
targetPosition, targetPosition,
}); };
const path = getSimpleBezierPath(params);
const [centerX, centerY] = getSimpleBezierCenter(params);
return ( return (
<BaseEdge <BaseEdge