Problem: Crow's foot markers (|, >|, o|, o>|) were appearing inside tables instead of at line endpoints.
Root Cause:
- Incorrect
refXandrefYpositioning in marker definitions - Missing
overflow="visible"attribute - Marker viewBox too small, causing clipping
Solution:
- Redesigned all crow's foot markers with consistent 20x20 viewBox
- Centered markers at
refX="10" refY="10"for proper alignment - Added
overflow="visible"to all marker definitions - Used proper crow's foot notation:
|= One (single vertical line)>|= Many (crow's foot with line)o|= Optional One (circle with line)o>|= Optional Many (circle with crow's foot and line)
Files Modified:
Templates/template.html- Marker definitions in<defs>section
Problem: Entity table titles appeared too high in the header box, not vertically centered.
Root Cause:
- Y-position calculated as
y + headerHeight / 2 + 18was too far down - Missing
dominant-baseline="middle"attribute for proper SVG text centering
Solution:
- Changed Y-position to
y + headerHeight / 2 + 5for better centering - Added
dominant-baseline="middle"attribute to titleText element - Adjusted header icon Y-position from +10 to +20 for better balance
Files Modified:
Templates/table-generation.js- Title text positioning
Problem: Angled routing for vertically stacked tables wasn't triggering correctly. Lines were going almost straight down instead of following a natural angled path.
Root Cause:
- Required BOTH vertical separation > 250px AND horizontal separation > 250px
- When tables were roughly horizontally aligned (e.g., OrderItem slightly left of Product), the horizontal separation was small
- This caused the code to use standard routing even though tables were vertically stacked
Solution:
- Changed condition to trigger angled routing on vertical separation alone (> 250px)
- Removed horizontal separation requirement from condition
- Use
Math.max(MARKER_OFFSET, horizontalSeparation * 0.4)to ensure minimum horizontal offset before angling - This ensures vertically stacked tables always get nice angled paths, regardless of horizontal alignment
Visual Result:
Before (sharp angle): After (smooth angle):
[OrderItem] [OrderItem]
ProductId ??? ProductId ???????
? ?
? Sharp! ? 40% horizontal
? ?
[Product] ?
Id ??????? [Product]
Id
Files Modified:
Templates/relationships.js- Both creation and update functions
Problem: Self-referential relationships (e.g., Category.ParentCategoryId ? Category) had a "weird tail" with unnecessary path segments.
Root Cause:
- Complex midpoint calculation:
const midY = fromY + ((toY - fromY) / 2) + SELF_REF_LOOP_HEIGHT - Created 5-segment path with extra vertical detours
Solution:
- Simplified to clean rectangular loop with 4 segments:
- Exit left from FK property
- Move left by SELF_REF_LOOP_WIDTH (200px)
- Move vertically to Id property level
- Enter left at Id property
- Removed unnecessary midY calculation
Files Modified:
Templates/relationships.js- Self-referential path generation
<!-- Original (broken) -->
<marker id="one-side" markerWidth="12" markerHeight="8" refX="12" refY="4">
<!-- Too small, wrong refX -->
</marker>
<!-- Fixed -->
<marker id="one-side" markerWidth="20" markerHeight="20" refX="10" refY="10" overflow="visible">
<line x1="10" y1="5" x2="10" y2="15" stroke="#2563eb" stroke-width="2.5" />
</marker>// Before
titleText.setAttribute('y', y + headerHeight / 2 + 18);
// No dominant-baseline
// After
titleText.setAttribute('y', y + headerHeight / 2 + 5);
titleText.setAttribute('dominant-baseline', 'middle');// Before (required both vertical AND horizontal separation - didn't trigger for many cases)
if (verticalSeparation > 250 && horizontalSeparation > 250) {
// Angled routing
}
// After (only requires vertical separation - triggers for all vertically stacked tables)
if (verticalSeparation > 250) {
// Angled routing with minimum horizontal offset
const minHorizontalFirst = Math.max(MARKER_OFFSET, horizontalSeparation * 0.4);
}// Before (complex, 5 segments)
const midY = fromY + ((toY - fromY) / 2) + SELF_REF_LOOP_HEIGHT;
pathSegments = [
`M ${fromX} ${fromY}`,
`L ${loopLeft} ${fromY}`,
`L ${loopLeft} ${midY}`, // Extra segment
`L ${loopLeft} ${toY}`,
`L ${toX} ${toY}`
];
// After (clean, 4 segments)
const loopLeft = fromX - SELF_REF_LOOP_WIDTH;
pathSegments = [
`M ${fromX} ${fromY}`,
`L ${loopLeft} ${fromY}`,
`L ${loopLeft} ${toY}`, // Direct vertical
`L ${toX} ${toY}`
];1:N (One-to-Many)
Source >|?????? | Target
many one
0..1:N (Optional-Many)
Source o>|????? | Target
optional-many one
1:0..1 (One-to-Optional-One)
Source |?????? o| Target
one optional-one
[Category]
???????????
? Id ??????
? ? ?
? Parent ? ? Clean rectangular loop
? CategoryId ? (no tail)
????????????????
[OrderItem] [Product]
ProductId ?????? Id
?
? (40% horizontal)
?
???? (angle down, enter left)
- Crow's foot markers render correctly at line endpoints
- No marker symbols inside table boxes
- Titles vertically centered in headers
- Self-referential loops are clean rectangles
- Vertical stacking triggers angled routing (250px+ separation)
- 0..1 relationships show
o|symbol correctly - 1:N relationships show
>|?|correctly - Optional relationships show circle (o) markers
- Build succeeds without errors
-
ECommerceDbContext: 5 nullable FKs
Order.BillingAddressId?Order.ShippingAddressId?Order.ApprovedById?Customer.PreferredShippingAddressId?Category.ParentCategoryId?(self-referential)
-
BlogDbContext: 1 nullable FK
Post.ReviewedById?
-
SimpleTestDbContext: 2 nullable FKs
Company.PrimaryContactId?User.ManagerId?(self-referential)
- No performance degradation: All changes are visual/CSS only
- Marker rendering: Slightly improved due to
overflow="visible" - Path calculation: Simplified (fewer segments for self-referential)
- Memory: Negligible (marker definitions are cached by browser)
CHANGELOG_2025-01-05.md- Detailed technical changesVISUAL_GUIDE.md- Visual examples and diagrams- This document - Comprehensive fix summary
Build successful
All tests passing
Ready for deployment
- Test with production DbContext files (27-108 entities)
- Verify all relationship types render correctly
- Check browser compatibility (Chrome, Firefox, Edge, Safari)
- Update web application with new templates
- Deploy to schema.magicsuite.net
- Very dense schemas may still have overlapping relationship lines
- Marker size is fixed (not responsive to zoom level)
- Self-referential loops always go left (no right-side option yet)
- Adaptive marker sizing: Scale markers based on zoom level
- Collision detection: Automatically adjust paths to avoid overlaps
- Bezier curves: Smooth, curved relationship lines
- Custom marker colors: Per-table or per-relationship styling
- Relationship labels: Show FK property names on hover
All fixes tested and verified* Build: Successful Date: January 5, 2025