Fix/bubble group geometry#8
Merged
Merged
Conversation
Per-group Padding and Corridor Width sliders multiply the bubblesets-js influence-field radii (nodeR0/R1 and edgeR0/R1) so tight two-node blobs can be shrunk and thin arms to outlying members thickened. Values persist with bubbleSetStyle in JSON; multipliers are clamped to [0.25, 4] in geometry. Also fold each member's on-screen radius into the outline identity checksum: the fit consumes node radii, so a size change (or a post-load size settle) now invalidates the cached hull instead of leaving a stale outline until membership changes.
…d hulls The influence field now scales with the group's mean member radius instead of bubblesets-js' absolute pixel constants (tuned for ~15px nodes), so hulls stay visually proportional at any configured node size and the padding/ corridor knobs read as fractions of a node. The legacy scale option is gone; resolution floors keep every field radius at marching-grid scale and pixelGroup is clamped to [1, 4]px. Members are now guaranteed enclosed: bubblesets-js validates only center points, so avoid-node pressure plus B-spline shrinkage could clip a node by its own hull (measured -12px). Grazed members get full-padding discs unioned in; disconnected pieces are joined with corridor-width capsule links so the result is always one simple ring. Rings are snapped to a 1/32px grid before clipping (polygon-clipping throws on float-noise segments, which silently disabled the guarantee) and the sample stride adapts to the thinnest field feature to prevent B-spline hooks. Interior non-members are carved as holes via polygon difference (the field can only fjord the boundary), rendered even-odd on canvas, PNG and SVG. Avoid-node moves now invalidate the outline cache; morphBuffer no longer scales with the knobs (corridor rerouting painted phantom lobes).
New per-group Avoidance slider (0-3): multiplies the non-member negative field; 0 lets the hull cover other nodes (and skips avoid routing entirely), higher steers around them harder. Defaults retuned for the node-size-aware field: padding 0.1, corridor 0.25 (razor-tight hugs with thin finger corridors, per live feedback); padding/corridor slider minimum lowered to 0.05. Saved workspaces keep their stored values; missing avoidance fills to 1 via the existing defaults merge.
Remove an unused variable and four extraneous f-string prefixes.
Paint bubble rings as Catmull-Rom cubic Béziers (tension 1/6) on both the live canvas and the SVG export, consuming identical control points from the new bubble_smoothing.js — the polygon stays the source of truth for all math, only the painters interpolate. Raise the outline simplify tolerance to half a grid cell (fewer control points now mean smoother curves, not facets) and replace rectangular straggler links with stadium capsules. The member-enclosure guarantee now measures clearance against the sampled smoothed curve (what is actually painted) and repairs in up to three rounds with growing discs, since disc-union junctions can themselves smooth inward past a member. Avoidance becomes boolean in the geometry (any value > 0 = ON; multiplying bubblesets' non-member factor never worked — the library's marching iteration fights back), and squeezed avoid holes fall back to the largest member-clearance-respecting radius instead of silently swallowing the node (floor 0.35× its radius, documented ceiling).
Replace the Avoidance slider with an 'Avoid Other Nodes' switch (the value had no useful continuous range) — persisted as numeric 0/1 so saved workspaces stay compatible; legacy values > 0 load as ON. The switch names its checkbox via aria-label since the row label is a separate element. Retune group defaults from padding 0.1 / corridor 0.25 to 0.15 / 0.3: the marching-grid floor gives small nodes proportionally more margin, so large nodes rendered visibly strangled at the old values (side-by-side r=9 vs r=35 renders). Hole breathing room gets a matching floor of 0.25× the carved node's radius.
…nobs Live feedback on a dense STRING network: the negative field of hundreds of non-members makes the contour visibly wobble wherever it threads between them, and one corridor-severing hole dropped ALL carves wholesale, leaving swallowed non-members with no visual out. The user prefers smooth hulls over avoidance, so: - avoidance now defaults to OFF (per-group switch turns carving back on); saved workspaces keep their stored value - padding/corridor floors drop to 0.01 (slider min/step 0.01) and defaults tighten to 0.05 / 0.1 — the resolution floors plus the enclosure guarantee make near-zero knobs safe, giving hug-tight bodies and finger-like arms - carveAvoidHoles retries discs one by one when the batch difference breaks the one-ring guarantee, so a single bad hole no longer silently swallows every other non-member (subtractHoleDiscs)
Remove the marching-grid floors on the influence-field radii: they fattened minimum knobs to ~half a node radius on dense graphs (small ratio-1 node radii), which is why padding/corridor 0.01 still painted wide. A field thinner than a grid cell now simply registers nothing — skipped entirely when no radius reaches grid scale — and ensureMembersEnclosed reconstructs the hull geometrically: a disc per member (hugging each node's OWN radius, min 2 px pad) joined by thin stadium capsules (min 1.25 px half-width). connectPolygonComponents links each piece to its NEAREST component instead of everything to the largest one — nearest-neighbor rounds grow an MST-like tree of short fingers where the old rule painted a star radiating from one node. Catmull-Rom control offsets are clamped to 0.35× their segment's chord: uniform parameterization overshoots where a short junction segment neighbors a long capsule side, cutting through the discs it should hug (inactive for evenly spaced rings). Outline simplify tolerance rises to one full grid cell — with curve painting, fewer control points mean smoother hulls and less field-summation scallop.
New ⤒ Import button in the data editor header loads an Excel workbook into the current graph instead of replacing it. A preview modal shows what the merge will do before anything is applied: new / updated node and edge counts, new property columns, unchanged and skipped rows, and capped id lists. - src/utilities/excel_merge.js: pure computeMergePlan (id-matched overlay of label/description/type/style + deep D4Data merge, group- contiguous header union, change detection) and the preview modal. - parseExcelToJson gains merge options: a single nodes/edges sheet suffices and edge endpoints validate against existing graph nodes, so a workbook can attach new edges to nodes already in the graph. - DataTable.update() rebuild path extracted into rebuildGraph() and shared with the import flow; workspaces, positions, filters and styles are preserved. X/Y coordinates in the file seed positions for new nodes only. No version bump or changelog entry yet — happens on main after testing.
Remove an unused variable and four extraneous f-string prefixes.
The straight lines below the field's resolution limit were the geometric capsules: the marching grid physically cannot trace corridors thinner than ~two grid cells, so the thin-corridor range is always capsule-built. capsuleRing now runs along a gentle quadratic arc (sagitta 8% of length, capped by tube width, bulge side stable across refits) with semicircular caps — thin corridors read organic instead of ruler-drawn. The leftover space around members at padding 0.01 was the absolute 2 px disc-pad minimum, which is ~a quarter node radius on dense graphs (small ratio-1 radii) and magnifies under zoom. Reconstruction minimums are now PROPORTIONAL: disc pad ≥ 5% of the member's own radius, capsule half-width ≥ 15% of the group's mean radius — knob minimum means visually hugging at every node scale and zoom.
…oid on User-picked defaults after the live tuning rounds: snug-but-not-touching padding, corridor at the field-organic routing threshold, avoidance enabled (per-disc hole fallback makes it safe on dense graphs).
…rge-import) for the 1.16 release
Workbooks re-saved by Excel/LibreOffice can carry rich cell values (rich-text runs, hyperlinks, formulas). The parser passed these through as raw objects, which (a) made every matched row look modified in the import preview — snapshot compare of object vs stored string — and (b) crashed the category filter dropdown after the merge rebuild (TypeError: val.toLowerCase is not a function). Normalize cell values at the parse boundary (richText joined, hyperlink text, formula cached result; error/unevaluated cells become empty) for headers and data alike — this also hardens the full-load path, which had the same latent bug. DropdownChecklist.sortCategories additionally coerces to String so hand-crafted JSON files cannot crash the panel. Adds regression tests incl. merge idempotency (a second import of the same file must report no changes).
The preview modal now offers two merge modes: 'Extend & add (full outer join)' — the previous upsert behavior, still the default — and 'Extend existing only (left join)', which enriches matched rows but ignores file rows without a match in the graph (including edges onto skipped new nodes, so no dangling edges). New property columns apply in both modes. Stats, notes and the Import button state re-render live on toggle, and showMergePreview now resolves the chosen plan instead of a boolean.
Two handleImportFile tests drive the real preview modal against a stubbed parser: choosing left join applies that plan (and reports the ignored rows), canceling leaves the graph untouched. Also extracts the join-mode picker into its own builder.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
1.16.0 - Bubble-set rework & Excel merge-import
Bubble groups
Data editor
Compat: saved files load unchanged; stored bubble knob values keep applying (padding/corridor are now node-radius fractions, avoidance >0 = on).