mirror of
https://github.com/screentinker/screentinker.git
synced 2026-06-15 02:33:15 -06:00
Merge pull request #60 from screentinker/fix/ai-deoverlap
fix(ai): de-overlap text + layer shapes behind text (#41)
This commit is contained in:
commit
df4110d9ca
|
|
@ -95,9 +95,45 @@ function normalizeDesign(raw) {
|
|||
});
|
||||
}
|
||||
}
|
||||
|
||||
// De-overlap text lines (models stack them at the same y) and order shapes
|
||||
// behind text so accent bands never hide the words.
|
||||
const shapes = out.elements.filter((e) => e.type === 'shape');
|
||||
const texts = out.elements.filter((e) => e.type === 'text');
|
||||
deoverlapTexts(texts);
|
||||
out.elements = [...shapes, ...texts];
|
||||
return out;
|
||||
}
|
||||
|
||||
// Push text lines apart so they don't sit on top of each other. Only nudges a
|
||||
// line down when it also overlaps horizontally (leaves side-by-side text alone),
|
||||
// then shifts the whole stack up if it ran past the bottom margin. CW/CH match
|
||||
// fitText's width/height estimates.
|
||||
function deoverlapTexts(texts) {
|
||||
const M = 4, GAP = 2.5, CW = 0.075, CH = 0.26;
|
||||
const widthOf = (el) => Math.max(1, el.text.length) * el.fontSize * CW;
|
||||
const heightOf = (el) => el.fontSize * CH;
|
||||
const ordered = texts.map((el, i) => ({ el, i })).sort((a, b) => a.el.y - b.el.y || a.i - b.i);
|
||||
const placed = [];
|
||||
for (const cur of ordered) {
|
||||
const cw = widthOf(cur.el);
|
||||
let minY = M;
|
||||
for (const p of placed) {
|
||||
const hOverlap = cur.el.x < p.el.x + widthOf(p.el) && p.el.x < cur.el.x + cw;
|
||||
if (hOverlap) minY = Math.max(minY, p.el.y + heightOf(p.el) + GAP);
|
||||
}
|
||||
if (cur.el.y < minY) cur.el.y = Math.round(minY * 10) / 10;
|
||||
placed.push(cur);
|
||||
}
|
||||
let maxBottom = 0;
|
||||
for (const p of placed) maxBottom = Math.max(maxBottom, p.el.y + heightOf(p.el));
|
||||
const overflow = maxBottom - (100 - M);
|
||||
if (overflow > 0 && placed.length) {
|
||||
const shift = Math.min(overflow, Math.min(...placed.map((p) => p.el.y)) - M);
|
||||
if (shift > 0) for (const p of placed) p.el.y = Math.round((p.el.y - shift) * 10) / 10;
|
||||
}
|
||||
}
|
||||
|
||||
// GET /api/ai/settings — workspace members (never returns the key)
|
||||
router.get('/settings', (req, res) => {
|
||||
const row = db.prepare('SELECT base_url, model, image_base_url, image_model, api_key_enc FROM ai_settings WHERE workspace_id = ?').get(req.workspaceId);
|
||||
|
|
|
|||
|
|
@ -26,8 +26,9 @@ test('normalizeDesign: keeps valid text+shape, sets background', () => {
|
|||
]});
|
||||
assert.equal(d.background, '#102030');
|
||||
assert.equal(d.elements.length, 2);
|
||||
assert.equal(d.elements[0].text, 'HELLO');
|
||||
assert.equal(d.elements[0].fontFamily, 'Arial');
|
||||
const txt = d.elements.find((e) => e.type === 'text');
|
||||
assert.equal(txt.text, 'HELLO');
|
||||
assert.equal(txt.fontFamily, 'Arial');
|
||||
});
|
||||
|
||||
test('normalizeDesign: converts pixel shape dims to %, clamps ranges', () => {
|
||||
|
|
@ -86,3 +87,16 @@ test('normalizeDesign: long/large text is shrunk + repositioned to fit canvas',
|
|||
assert.ok(e.fontSize < 160, 'fontSize was shrunk');
|
||||
assert.ok(e.x >= 4 && e.y >= 4, 'within margins');
|
||||
});
|
||||
|
||||
test('normalizeDesign: separates overlapping text + orders shapes behind text', () => {
|
||||
const d = normalizeDesign({ elements: [
|
||||
{ type: 'text', x: 5, y: 40, text: 'HEADLINE TEXT HERE', fontSize: 60, color: '#fff' },
|
||||
{ type: 'text', x: 5, y: 41, text: 'SUBTEXT OVERLAPPING IT', fontSize: 40, color: '#fff' },
|
||||
{ type: 'shape', x: 0, y: 0, width: 100, height: 100, color: '#000', opacity: 0.5 },
|
||||
]});
|
||||
assert.equal(d.elements[0].type, 'shape', 'shape rendered behind (first in array)');
|
||||
const texts = d.elements.filter((e) => e.type === 'text');
|
||||
const hi = texts[0].y <= texts[1].y ? texts[0] : texts[1];
|
||||
const lo = texts[0].y <= texts[1].y ? texts[1] : texts[0];
|
||||
assert.ok(lo.y >= hi.y + hi.fontSize * 0.22, 'text lines no longer overlap vertically');
|
||||
});
|
||||
|
|
|
|||
Loading…
Reference in a new issue