Bug: Rotation Recalculation Corrupts Compound Transforms

SVG-Edit recalculates rotation centers when element attributes change. Two bugs cause this recalculation to corrupt elements with compound transforms (e.g. word art characters on a curve).

Bug 1: Non-geometric attribute change destroys compound transforms (history.js)

When undoing/redoing a stroke-width change, the old code replaces the entire transform attribute with just rotate(...), destroying any translate() or scale() transforms. Characters positioned via compound transforms collapse to the SVG origin.

Original Characters on curve

Each character has translate(x,y) rotate(angle)

S T O R Y

stroke-width: 2

Bug After undo of stroke-width change

Old code replaces transform with just rotate() — translate destroyed

S T O R Y S T O R Y

Characters collapse to origin — translate() destroyed

Fixed After undo of stroke-width change

New code skips recalculation for non-geometric attrs — transform untouched

S T O R Y

Characters unchanged — non-geometric attrs skip recalculation

// history.js — old code (apply/unapply): const rotate = `rotate(${angle}, ${cx}, ${cy})` this.elem.setAttribute('transform', rotate) // replaces ENTIRE transform! // history.js — new code: if (!BBOX_AFFECTING_ATTRS.has(attr)) return // skip for stroke-width, fill, etc. // When needed, update only the rotation entry via transform list API
Bug 2: Pre-rotation translate leaks into rotation center (undo.js)

When a geometric attribute (e.g. width) changes on an element with translate(tx,ty) rotate(angle), the rotation center should be computed from the bbox center alone. The old code transforms the center through all remaining transforms (including the pre-rotation translate), shifting the rotation center by (tx, ty).

Original Rect with translate + rotate

translate(200,60) rotate(25, 50, 40) on 100×80 rect

translate(200, 60) center (50, 40)

Bug After width change: center shifted

Old code: center through all transforms → rotate(25, 260, 100)

wrong! (260, 100)

translate(200,60) leaks into rotation center calculation

Fixed After width change: center correct

New code: center through post-rotation transforms only → rotate(25, 60, 40)

translate(200, 60) correct (60, 40)

Center computed from bbox only, translate excluded

// undo.js — old code (center through ALL remaining transforms): center = transformPoint(bcx, bcy, transformListToTransform(tlist).matrix) // For [translate(200,60), rotate(25)]: includes translate → center = (bcx+200, bcy+60) // undo.js — new code (center through only POST-rotation transforms): centerMatrix = transformListToTransform(tlist, n, tlist.numberOfItems - 1).matrix // For [translate(200,60)]: post-rotation = identity → center = (bcx, bcy)