supports-thickness slider — relative shaft width for supports edges

A LINEAR 0–1 multiplier of Edge width (default 0.5, dead-center at step
0.1 — 11 stops like the ladder rows but ratio-valued), grayed out by the
supports-edges toggle (the Dilation dependency pattern). Renderer splits
supports shafts into their own Path2D and strokes a second pass at
edgeWidth × supportsWidth; arrowheads stay full-geometry in the one shared
path (owner pick: shaft only). A true 0-width stroke is undefined on
canvas — the 0 end floors to a 0.5px on-screen hairline; hiding remains
the toggle's job. Sanitizer: real numbers clamp to [0,1], everything else
resets to 0.5; clamps pinned in render-settings.test.
This commit is contained in:
amosblomqvist
2026-09-29 03:00:57 +03:00
parent 6543d4f886
commit f5a9ed59c7
4 changed files with 69 additions and 7 deletions
+15
View File
@@ -59,6 +59,14 @@ export interface GraphRenderSettings {
* them (settings never shift the graph: camera, one frame), and node
* detail cards still list them. */
showSupports: boolean;
/** Relative SHAFT thickness of supports edges (owner, 2026-09-29):
* a 0–1 multiplier of edgeWidth — default 0.5, the single-line
* relation reads as the lighter one. SHAFT ONLY: arrowheads keep
* full Arrowhead-size geometry (owner pick). Linear, not a ladder —
* it's a ratio; exactly 0 floors to a hairline in the renderer
* (canvas cannot stroke a true 0-width line; hiding is the toggle's
* job). */
supportsWidth: number;
/** Toggle for the cluster region labels (hulls always draw). */
clusterLabels: boolean;
/** Cluster label font size, px on screen (camera-compensated —
@@ -102,6 +110,12 @@ export function sanitizeRenderSettings(raw: unknown): GraphRenderSettings {
labelSize: legacySizes ? DEFAULT_RENDER_SETTINGS.labelSize : ladd(r.labelSize, LABEL_SIZE_LADDER, DEFAULT_RENDER_SETTINGS.labelSize),
showSupports:
typeof r.showSupports === "boolean" ? r.showSupports : DEFAULT_RENDER_SETTINGS.showSupports,
// Linear ratio, not a ladder: real numbers clamp to [0, 1]; anything
// else resets to the default.
supportsWidth:
typeof r.supportsWidth === "number" && Number.isFinite(r.supportsWidth)
? clamp(r.supportsWidth, 0, 1)
: DEFAULT_RENDER_SETTINGS.supportsWidth,
clusterLabels:
typeof r.clusterLabels === "boolean" ? r.clusterLabels : DEFAULT_RENDER_SETTINGS.clusterLabels,
clusterLabelSize: ladd(
@@ -270,6 +284,7 @@ export const DEFAULT_RENDER_SETTINGS: GraphRenderSettings = {
labelZoom: 4,
labelSize: 3,
showSupports: true,
supportsWidth: 0.5,
clusterLabels: true,
clusterLabelSize: 14,
regions: DEFAULT_REGION_TUNING,