adding in path geometry for the add point +
This commit is contained in:
@@ -1,5 +1,5 @@
|
|||||||
import { describe, it, expect } from 'vitest'
|
import { describe, it, expect } from 'vitest'
|
||||||
import { buildWaypointPath, distToSegment, findInsertIndex, getWaypointLabelPosition, snap45, snap45both } from '../waypointUtils'
|
import { buildWaypointPath, distToSegment, findInsertIndex, getAddWaypointHandlePosition, getWaypointLabelPosition, snap45, snap45both } from '../waypointUtils'
|
||||||
|
|
||||||
describe('buildWaypointPath — bezier (default)', () => {
|
describe('buildWaypointPath — bezier (default)', () => {
|
||||||
it('builds a catmull-rom curve with no waypoints (start = end clamp)', () => {
|
it('builds a catmull-rom curve with no waypoints (start = end clamp)', () => {
|
||||||
@@ -192,3 +192,16 @@ describe('getWaypointLabelPosition', () => {
|
|||||||
expect(point).toEqual({ x: 10, y: 20 })
|
expect(point).toEqual({ x: 10, y: 20 })
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|
||||||
|
describe('getAddWaypointHandlePosition', () => {
|
||||||
|
it('places bezier add handle on the rendered curved segment', () => {
|
||||||
|
const point = getAddWaypointHandlePosition(0, 0, [{ x: 50, y: 100 }], 100, 0, 0, 'bezier')
|
||||||
|
expect(point.x).toBeCloseTo(21.875, 3)
|
||||||
|
expect(point.y).toBeCloseTo(56.25, 3)
|
||||||
|
})
|
||||||
|
|
||||||
|
it('keeps smooth add handle at straight segment midpoint', () => {
|
||||||
|
const point = getAddWaypointHandlePosition(0, 0, [{ x: 50, y: 0 }, { x: 50, y: 100 }], 100, 100, 1, 'smooth')
|
||||||
|
expect(point).toEqual({ x: 50, y: 50 })
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|||||||
@@ -13,7 +13,7 @@ import type { EdgeData, EdgeType, Waypoint } from '@/types'
|
|||||||
import { useThemeStore } from '@/stores/themeStore'
|
import { useThemeStore } from '@/stores/themeStore'
|
||||||
import { useCanvasStore } from '@/stores/canvasStore'
|
import { useCanvasStore } from '@/stores/canvasStore'
|
||||||
import { THEMES } from '@/utils/themes'
|
import { THEMES } from '@/utils/themes'
|
||||||
import { buildWaypointPath, getWaypointLabelPosition, snap45, snap45both } from './waypointUtils'
|
import { buildWaypointPath, getAddWaypointHandlePosition, getWaypointLabelPosition, snap45, snap45both } from './waypointUtils'
|
||||||
|
|
||||||
const VLAN_COLORS = ['#00d4ff', '#a855f7', '#39d353', '#ff6e00', '#e3b341', '#f85149']
|
const VLAN_COLORS = ['#00d4ff', '#a855f7', '#39d353', '#ff6e00', '#e3b341', '#f85149']
|
||||||
|
|
||||||
@@ -161,9 +161,9 @@ function segmentMidpoints(
|
|||||||
const isSmooth = pathStyle === 'smooth'
|
const isSmooth = pathStyle === 'smooth'
|
||||||
|
|
||||||
return pts.slice(0, -1).map((a, i) => {
|
return pts.slice(0, -1).map((a, i) => {
|
||||||
const b = pts[i + 1]
|
const base = getAddWaypointHandlePosition(sourceX, sourceY, waypoints, targetX, targetY, i, pathStyle)
|
||||||
let mx = (a.x + b.x) / 2
|
let mx = base.x
|
||||||
const my = (a.y + b.y) / 2
|
const my = base.y
|
||||||
|
|
||||||
// For smooth style with no existing waypoints, bias the single + handle onto
|
// For smooth style with no existing waypoints, bias the single + handle onto
|
||||||
// the source handle axis so clicking it creates a perpendicular exit.
|
// the source handle axis so clicking it creates a perpendicular exit.
|
||||||
|
|||||||
@@ -238,6 +238,50 @@ export function getWaypointLabelPosition(
|
|||||||
return lastSegment.pointAt(1)
|
return lastSegment.pointAt(1)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function getBezierSegmentPoint(
|
||||||
|
pts: Waypoint[],
|
||||||
|
insertIndex: number,
|
||||||
|
t: number,
|
||||||
|
): Waypoint {
|
||||||
|
const i = Math.max(0, Math.min(insertIndex, pts.length - 2))
|
||||||
|
const p0 = pts[Math.max(i - 1, 0)]
|
||||||
|
const p1 = pts[i]
|
||||||
|
const p2 = pts[i + 1]
|
||||||
|
const p3 = pts[Math.min(i + 2, pts.length - 1)]
|
||||||
|
const cp1 = {
|
||||||
|
x: p1.x + (p2.x - p0.x) / 6,
|
||||||
|
y: p1.y + (p2.y - p0.y) / 6,
|
||||||
|
}
|
||||||
|
const cp2 = {
|
||||||
|
x: p2.x - (p3.x - p1.x) / 6,
|
||||||
|
y: p2.y - (p3.y - p1.y) / 6,
|
||||||
|
}
|
||||||
|
|
||||||
|
return interpolateCubic(p1, cp1, cp2, p2, t)
|
||||||
|
}
|
||||||
|
|
||||||
|
export function getAddWaypointHandlePosition(
|
||||||
|
sourceX: number, sourceY: number,
|
||||||
|
waypoints: Waypoint[],
|
||||||
|
targetX: number, targetY: number,
|
||||||
|
insertIndex: number,
|
||||||
|
pathStyle: string = 'bezier',
|
||||||
|
): Waypoint {
|
||||||
|
const pts = [{ x: sourceX, y: sourceY }, ...waypoints, { x: targetX, y: targetY }]
|
||||||
|
|
||||||
|
if (pts.length < 2) return { x: sourceX, y: sourceY }
|
||||||
|
|
||||||
|
if (pathStyle !== 'smooth') {
|
||||||
|
return getBezierSegmentPoint(pts, insertIndex, 0.5)
|
||||||
|
}
|
||||||
|
|
||||||
|
const i = Math.max(0, Math.min(insertIndex, pts.length - 2))
|
||||||
|
return {
|
||||||
|
x: (pts[i].x + pts[i + 1].x) / 2,
|
||||||
|
y: (pts[i].y + pts[i + 1].y) / 2,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// ── 45° snapping ──────────────────────────────────────────────────────────────
|
// ── 45° snapping ──────────────────────────────────────────────────────────────
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
Reference in New Issue
Block a user