PhoenixLiveGantt.PathFormat (PhoenixLiveGantt v0.1.0)

Copy Markdown View Source

Single source of truth for the PhoenixLiveGantt connector path string format.

Connector paths come in two shape families:

:forward   "M x1 y1 H mid V y2 H arrow_stop"
            3 segments. Used by FS / SS / FF / SF when there's room
            for a single trunk between source and target.

:detour   — "M x1 y1 H stem_out V detour_y H stem_in V y2 H arrow_stop"
            5 segments. Used by :fs when the forward path can't be
            laid out cleanly (target before source, tight gap, or
            trunk would pierce intermediate bars).

Owning both the BUILDER and the PARSER here keeps PhoenixLiveGantt (which emits paths) and PhoenixLiveGantt.Inspector (which parses them for tests and the dump task) in sync — if a new shape family is added or the format changes, both update at once.

All numeric inputs/outputs are integers. Decimal coords aren't emitted by the renderer today; if that ever changes, extend parse/1.

Summary

Functions

Build the 5-segment detour path string.

Build the 3-segment forward path string.

Parse a path d-string into a structured segment map. Returns one of

All absolute {x, y} points of an M/H/V path, in order. Works for any shape the renderer emits — the 3-segment forward, 5-segment detour, and the consolidator's N-segment jog — not just the two canonical regex forms.

Terminal point + final-segment direction of any M/H/V path. The direction is where the LAST segment travels (:east/:west for a horizontal finish, :south/:north for vertical, nil for a zero-length/degenerate finish). Used to place the arrowhead overlay on the shaft's true end.

Functions

detour(x1, y1, stem_out, detour_y, stem_in, y2, arrow_stop)

@spec detour(
  integer(),
  integer(),
  integer(),
  integer(),
  integer(),
  integer(),
  integer()
) :: String.t()

Build the 5-segment detour path string.

iex> PathFormat.detour(100, 20, 130, 80, 160, 100, 180)
"M 100 20 H 130 V 80 H 160 V 100 H 180"

forward(x1, y1, mid, y2, arrow_stop)

@spec forward(integer(), integer(), integer(), integer(), integer()) :: String.t()

Build the 3-segment forward path string.

iex> PathFormat.forward(100, 20, 130, 60, 180)
"M 100 20 H 130 V 60 H 180"

parse(d)

@spec parse(String.t()) :: map()

Parse a path d-string into a structured segment map. Returns one of:

%{kind: :forward, x1: ..., y1: ..., mid: ..., y2: ..., arrow_stop: ...}
%{kind: :detour,  x1: ..., y1: ..., stem_out: ..., detour_y: ...,
                  stem_in: ..., y2: ..., arrow_stop: ...}
%{kind: :unknown, raw: <input>}

All coords are integers (or floats if a decimal slips into the input).

points(d)

@spec points(String.t()) :: [{number(), number()}]

All absolute {x, y} points of an M/H/V path, in order. Works for any shape the renderer emits — the 3-segment forward, 5-segment detour, and the consolidator's N-segment jog — not just the two canonical regex forms.

iex> PathFormat.points("M 100 20 H 130 V 60 H 180")
[{100, 20}, {130, 20}, {130, 60}, {180, 60}]

terminal(d)

@spec terminal(String.t()) :: %{x: number(), y: number(), dir: atom() | nil}

Terminal point + final-segment direction of any M/H/V path. The direction is where the LAST segment travels (:east/:west for a horizontal finish, :south/:north for vertical, nil for a zero-length/degenerate finish). Used to place the arrowhead overlay on the shaft's true end.

iex> PathFormat.terminal("M 100 20 H 130 V 60 H 180")
%{x: 180, y: 60, dir: :east}