RESIZE COORDINATE FIX FINAL

Comprehensive guidelines for AI-assisted development within the Editor platform

Resize Coordinate System - Final Fix ✅

🔴 The REAL Problem

The resize logic was calculating newBounds with x and y coordinates that represented temporary calculation values, not the actual element-relative bounds. This caused confusion because:

  1. bounds.x and bounds.y should ALWAYS be 0 for standalone elements
  2. The old code was setting newBounds.y = baseBounds.y + dy for top resize
  3. Then calculating deltaY = newBounds.y - startBounds.y
  4. This worked mathematically, but was conceptually wrong and error-prone

Example of the Old (Wrong) Approach

// Resizing from top (handle 'n'), user drags up 50px (dy = -50)
newBounds = {
  x: 0,
  y: 0 + (-50) = -50,  // ← WRONG! bounds.y should stay 0
  width: 100,
  height: 100 - (-50) = 150
};

// Then calculate delta
deltaY = -50 - 0 = -50;  // ← Correct value, but derived wrong

The delta was correct by accident, but newBounds.y = -50 violated the principle that bounds are element-relative.


✅ The Solution: Direct Delta Calculation

Instead of temporarily storing deltas in newBounds.x/y, calculate them directly and only emit size + delta:

New Approach

// Separate concerns: size vs position change
let newWidth = baseBounds.width;
let newHeight = baseBounds.height;
let deltaX = 0;  // Position change
let deltaY = 0;  // Position change

switch (handle) {
  case 'n':  // Top-center
    newHeight = baseBounds.height - dy;
    deltaY = dy;  // Position moves up/down
    break;
    
  case 'e':  // Right-center
    newWidth = baseBounds.width + dx;
    // deltaX = 0, deltaY = 0 (position doesn't change)
    break;
    
  case 'nw':  // Top-left corner
    newWidth = baseBounds.width - dx;
    newHeight = baseBounds.height - dy;
    deltaX = dx;  // Position moves left/right
    deltaY = dy;  // Position moves up/down
    break;
}

// Emit clean, semantic data
this.elementResize.emit({
  width: newWidth,
  height: newHeight,
  deltaX: deltaX,  // How much position changes in X
  deltaY: deltaY   // How much position changes in Y
});

🎯 All 8 Handle Behaviors

Edges (no corners)

Handle Position Change Size Change
N (top) deltaY = dy height -= dy
E (right) none width += dx
S (bottom) none height += dy
W (left) deltaX = dx width -= dx

Corners

Handle Position Change Size Change
NW (top-left) deltaX = dx, deltaY = dy width -= dx, height -= dy
NE (top-right) deltaY = dy width += dx, height -= dy
SE (bottom-right) none width += dx, height += dy
SW (bottom-left) deltaX = dx width -= dx, height += dy

🔧 Code Changes

Before (Conceptually Wrong)

// Stored deltas in bounds.x/y temporarily
newBounds = {
  x: baseBounds.x + dx,  // ← Mixing coordinate spaces
  y: baseBounds.y + dy,
  width: baseBounds.width - dx,
  height: baseBounds.height - dy
};

// Calculated delta from bounds
const deltaX = newBounds.x - this.startBounds.x;
const deltaY = newBounds.y - this.startBounds.y;

After (Conceptually Correct)

// Calculate deltas directly
let newWidth = baseBounds.width - dx;
let newHeight = baseBounds.height - dy;
let deltaX = dx;  // Direct assignment
let deltaY = dy;

// Emit clean data
this.elementResize.emit({ width: newWidth, height: newHeight, deltaX, deltaY });

✅ Benefits

1. Conceptual Clarity

2. Correctness

3. Maintainability

4. Performance


🧪 Testing

Handle 'N' (Top-Center)

Initial: position {x: 100, y: 100}, bounds {x: 0, y: 0, width: 100, height: 100}
User drags up 30px (dy = -30)

Calculation:
  newHeight = 100 - (-30) = 130
  deltaY = -30

Result:
  position: {x: 100, y: 70}  (moved up 30px)
  bounds: {x: 0, y: 0, width: 100, height: 130}  (grew 30px taller)

Handle 'E' (Right-Center)

Initial: position {x: 100, y: 100}, bounds {x: 0, y: 0, width: 100, height: 100}
User drags right 40px (dx = 40)

Calculation:
  newWidth = 100 + 40 = 140
  deltaX = 0, deltaY = 0

Result:
  position: {x: 100, y: 100}  (unchanged)
  bounds: {x: 0, y: 0, width: 140, height: 100}  (grew 40px wider)

Handle 'NW' (Top-Left Corner)

Initial: position {x: 100, y: 100}, bounds {x: 0, y: 0, width: 100, height: 100}
User drags up-left (-20, -20)

Calculation:
  newWidth = 100 - (-20) = 120
  newHeight = 100 - (-20) = 120
  deltaX = -20
  deltaY = -20

Result:
  position: {x: 80, y: 80}  (moved up-left 20px each)
  bounds: {x: 0, y: 0, width: 120, height: 120}  (grew 20px in both dimensions)

🎨 Architectural Principle

Separation of Concerns: Size and position are independent properties that change together during resize, but should be calculated and represented separately in the code.

Coordinate System Purity: Element-relative coordinates (bounds) should never contain temporary canvas-space calculations.

Event Semantics: Events should emit semantic, purpose-specific data (width, height, deltaX, deltaY) rather than overloaded structures (bounds with temporary x/y values).


📊 Verification Checklist


🚀 What's Next

User Testing Required:

  1. Test resize from all 8 handles
  2. Verify no "sliding" behavior
  3. Confirm SVG scales proportionally
  4. Check minimum size enforcement
  5. Test with different initial positions/sizes

Expected Result: Clean, predictable, professional-grade resize behavior with zero coordinate system confusion.


Status: 🟢 Final Fix Applied Confidence: Very High - addressed root conceptual issue Ready for Testing: Yes