diff --git a/editor-packages/editor-canvas/flow-connections/arrow.tsx b/editor-packages/editor-canvas/flow-connections/arrow.tsx new file mode 100644 index 00000000..617b2f8f --- /dev/null +++ b/editor-packages/editor-canvas/flow-connections/arrow.tsx @@ -0,0 +1,64 @@ +import React from "react"; +import type { XY } from "../types"; + +export function Arrow({ + b, + color, + size, + width, + direction, +}: { + b: XY; + color: React.CSSProperties["color"]; + size: number; + width: number; + direction: "n" | "s" | "e" | "w"; +}) { + return ( + + ); +} + +/** + * + * the result will have 3 modifiers, + * if the arrow is facing right, the modifiers will be: + * - M - starting point [edge_x - height, edge_y + width / 2] + * - L - edge [edge_x, edge_y] + * - L - ending point [edge_x - height, edge_y - width / 2] + * + * @param edge the edge of a arrow (triangle) + * @param width + */ +function make_arrow_svg_path_data( + edge: XY, + direction: "n" | "s" | "e" | "w", + { width, height }: { width: number; height: number } +) { + const [x, y] = edge; + const w = width / 2; + switch (direction) { + case "e": { + return `M${x - height},${y + w} L${x},${y} L${x - height},${y - w}`; + } + case "w": { + return `M${x + height},${y + w} L${x},${y} L${x + height},${y - w}`; + } + case "n": { + return `M${x - w},${y + height} L${x},${y} L${x + w},${y + height}`; + } + case "s": { + return `M${x - w},${y - height} L${x},${y} L${x + w},${y - height}`; + } + default: { + throw new Error(`invalid direction: ${direction}`); + } + } +} diff --git a/editor-packages/editor-canvas/flow-connections/connection-line-bezier-curved.tsx b/editor-packages/editor-canvas/flow-connections/connection-line-bezier-curved.tsx new file mode 100644 index 00000000..c3392199 --- /dev/null +++ b/editor-packages/editor-canvas/flow-connections/connection-line-bezier-curved.tsx @@ -0,0 +1,84 @@ +import { color_connection_line } from "../theme"; +import type { XY } from "../types"; +import { Arrow } from "./arrow"; +import { get_direction } from "./math"; +import type { ConnectionLineStyleProps } from "./props"; + +export function BezierCurvedLine({ + a, + b, + width = 2, + color = color_connection_line, +}: { a: XY; b: XY } & ConnectionLineStyleProps) { + const direction = get_direction(a, b); + + return ( + + + + + ); +} + +const direction_to_axis_map = { + n: "v", + s: "v", + e: "h", + w: "h", +} as const; + +/** + * make a svg path data to connect point a to point b + * + * the output will contain 2 commands + * - M - starting point + * - C - curve + * + * e.g. for a a[0, 0], b[1000, 500], (1000x500 box) + * - `"M 0 0 C 500 0 500 500 1000 500"` + * - M a[0], a[1] (start point) + * - C0 a[0] + w / 2, a[1] + * - C1 a[0] + w / 2, b[1] + * - C2 b[0], b[1] (end point) + * + * @param a - starting point + * @param b - ending point + */ +function make_bazier_curved_svg_path_data(a: XY, b: XY, axis: "h" | "v" = "h") { + const [x0, y0] = a; + const [x1, y1] = b; + const w = axis === "h" ? x1 - x0 : y1 - y0; + + if (axis === "h") { + return `M ${x0},${y0} C ${x0 + w / 2},${y0} ${ + x0 + w / 2 + },${y1} ${x1},${y1}`; + } else if (axis === "v") { + return `M ${x0},${y0} C ${x0},${y0 + w / 2} ${x1},${ + y0 + w / 2 + } ${x1},${y1}`; + } +} diff --git a/editor-packages/editor-canvas/flow-connections/connection-line-edge-curved.tsx b/editor-packages/editor-canvas/flow-connections/connection-line-edge-curved.tsx new file mode 100644 index 00000000..85cab50a --- /dev/null +++ b/editor-packages/editor-canvas/flow-connections/connection-line-edge-curved.tsx @@ -0,0 +1,91 @@ +import React from "react"; +import type { XY } from "../types"; +import { Arrow } from "./arrow"; +import { get_direction } from "./math"; + +/** + * @deprecated - not implemented + * @param param0 + * @returns + */ +export function EdgeCurvedConnectionLine({ + a, + b, + width = 2, + color = "blue", +}: { a: XY; b: XY } & { + width?: number; + color?: React.CSSProperties["color"]; +}) { + const direction = get_direction(a, b); + return ( + + + + + ); +} + +function Line({ a, b }: { a: XY; b: XY }) { + return ; +} + +/** + * + * makes the svg path data that connects point a to point b, with extra parameters, curve delta and edge inset + * + * the shape looks line + * ``` + * (a) --- + * | + * | + * | + * | + * | + * --- (b) + * ``` + * + * the line components are.. + * 0. M | starting point + * 1. L L | the line from `a - edge` to `a` - [a - edge, a] + * 2. C | the curve to before 3 + * 3. L | the line from `a` to `b` - [a, b] + * 4. C | the curve to after 3 + * 5. L L | the line from `b` to `b + edge` - [b, b + edge] + * + * the output command is: + * - M - the start point (a) + * - L - line start + * - L - draw line to the curving point + * - C - curve + * - L - line between two curves + * - C - curve + * - L - line start + * - L - line end point + * + * e.g. the output of this function is: + * - `"M 0 0 L 0 0 L 8 0 L 8 0 C 17.1638 0 25.4139 5.5525 28.8641 14.042 L 165.907 351.249 C 169.358 359.739 177.608 365.291 186.772 365.291 L 186.772 365.291 L 194.772 365.291"` + * + * @param a the starting point a + * @param b the ending point b + * @param curve the curve delta + * @param edge the edge (margin) value + */ +function make_svg_path_data(a: XY, b: XY, edge) {} diff --git a/editor-packages/editor-canvas/flow-connections/index.ts b/editor-packages/editor-canvas/flow-connections/index.ts new file mode 100644 index 00000000..6ea59047 --- /dev/null +++ b/editor-packages/editor-canvas/flow-connections/index.ts @@ -0,0 +1,2 @@ +export { EdgeCurvedConnectionLine } from "./connection-line-edge-curved"; +export { BezierCurvedLine } from "./connection-line-bezier-curved"; diff --git a/editor-packages/editor-canvas/flow-connections/knob.tsx b/editor-packages/editor-canvas/flow-connections/knob.tsx new file mode 100644 index 00000000..5cdf97d4 --- /dev/null +++ b/editor-packages/editor-canvas/flow-connections/knob.tsx @@ -0,0 +1,27 @@ +import { + color_connection_knob_fill, + color_connection_knob_stroke, +} from "../theme"; +import type { XY } from "../types"; + +export function Knob({ point, size = 6 }: { point: XY; size: number }) { + return ( + + + + ); +} diff --git a/editor-packages/editor-canvas/flow-connections/line.tsx b/editor-packages/editor-canvas/flow-connections/line.tsx new file mode 100644 index 00000000..e69de29b diff --git a/editor-packages/editor-canvas/flow-connections/math.ts b/editor-packages/editor-canvas/flow-connections/math.ts new file mode 100644 index 00000000..1f540f2a --- /dev/null +++ b/editor-packages/editor-canvas/flow-connections/math.ts @@ -0,0 +1,43 @@ +import type { XY } from "../types"; + +/** + * get the direction based on two points (vector), a and b. + * returns the most powerful direction, e.g. [0, 0], [10, 50] -> "s" + * if the power is the same, return "e" | "w" first, then "s" | "n". + * + * examples + * - [0, 0], [10, 50] -> "s" + * - [0, 0], [10, 0] -> "e" + * - [0, 0], [0, 50] -> "s" + * - [0, 0], [0, 0] -> "e" + * - [0, 0], [-10, 50] -> "n" + * - [0, 0], [-10, 0] -> "w" + * - [0, 0], [-10, -50] -> "n" + * - [0, 0], [-10, 0] -> "w" + * - [0, 0], [-100, -100] -> "w" + * + * @param a + * @param b + * @returns + */ +export function get_direction(a: XY, b: XY): "n" | "s" | "e" | "w" { + const [x, y] = a; + const [x2, y2] = b; + + const x_diff = x2 - x; + const y_diff = y2 - y; + + if (Math.abs(x_diff) >= Math.abs(y_diff)) { + if (x_diff > 0) { + return "e"; + } else { + return "w"; + } + } + + if (y_diff > 0) { + return "s"; + } + + return "n"; +} diff --git a/editor-packages/editor-canvas/flow-connections/props.ts b/editor-packages/editor-canvas/flow-connections/props.ts new file mode 100644 index 00000000..ef0b21f2 --- /dev/null +++ b/editor-packages/editor-canvas/flow-connections/props.ts @@ -0,0 +1,6 @@ +import React from "react"; + +export interface ConnectionLineStyleProps { + width?: number; + color?: React.CSSProperties["color"]; +} diff --git a/editor-packages/editor-canvas/theme/default-theme.ts b/editor-packages/editor-canvas/theme/default-theme.ts index de843bed..a63d4be5 100644 --- a/editor-packages/editor-canvas/theme/default-theme.ts +++ b/editor-packages/editor-canvas/theme/default-theme.ts @@ -1,5 +1,8 @@ export const color_layer_highlight = "#0099ff"; export const color_layer_readonly_highlight = "#0099ff"; +export const color_connection_line = "#34AEFF"; +export const color_connection_knob_stroke = "#34AEFF"; +export const color_connection_knob_fill = "white"; export const color_frame_title = { default: "grey", highlight: color_layer_highlight,