Align editor canvas text preview

This commit is contained in:
Mikei386
2026-06-22 15:01:44 +02:00
parent 34f0161350
commit 364e6ead33
+47 -11
View File
@@ -86,26 +86,62 @@ function pxToMm(v) {
return v / scale(); return v / scale();
} }
function printablePxPerMm() {
const tape = Number(state.design.tapeWidthMm);
return (PRINTABLE_TAPE_PX[tape] || (tape * 180) / 25.4) / tape;
}
function inkColor() { function inkColor() {
return state.tapeInfo?.textColor?.css || "#000"; return state.tapeInfo?.textColor?.css || "#000";
} }
function objectFont(obj) {
const fontPx = mmToPx(obj.fontSizeMm || 5);
return {
size: fontPx,
value: `${obj.bold ? "700 " : ""}${fontPx}px DejaVu Sans, Arial, system-ui, sans-serif`,
};
}
function clamp(value, min, max) { function clamp(value, min, max) {
return Math.min(max, Math.max(min, value)); return Math.min(max, Math.max(min, value));
} }
function wrapCanvasText(text, maxWidthPx) {
const lines = [];
for (const rawLine of String(text || "").split("\n")) {
let current = "";
for (const word of rawLine.split(" ")) {
const candidate = current ? `${current} ${word}` : word;
if (ctx.measureText(candidate).width <= maxWidthPx) {
current = candidate;
continue;
}
if (current) lines.push(current);
current = word;
}
lines.push(current);
}
return lines.length ? lines : [""];
}
function objectContentEndMm(obj) {
if (obj.hidden) return 0;
if (state.design.orientation === "portrait") return obj.y + obj.h;
if (obj.type !== "text" && obj.type !== "symbol") return obj.x + obj.w;
const { value } = objectFont(obj);
ctx.save();
ctx.font = value;
const lines = wrapCanvasText(obj.text || "", mmToPx(obj.w));
const textWidthMm = Math.max(...lines.map((line) => pxToMm(ctx.measureText(line).width)), 0);
ctx.restore();
if (obj.align === "center") return obj.x + obj.w / 2 + textWidthMm / 2;
if (obj.align === "right") return obj.x + obj.w;
return obj.x + Math.min(obj.w, textWidthMm);
}
function contentLengthMm() { function contentLengthMm() {
if (!state.design.objects.length) return Number(controls.lengthMm.value) || state.design.lengthMm || 70; if (!state.design.objects.length) return Number(controls.lengthMm.value) || state.design.lengthMm || 70;
const margin = Number(controls.marginMm.value) || 0; const margin = Number(controls.marginMm.value) || 0;
const lengthEnd = state.design.objects.reduce((max, obj) => { const lengthEnd = state.design.objects.reduce((max, obj) => {
if (obj.hidden) return max; return Math.max(max, objectContentEndMm(obj));
const end = state.design.orientation === "portrait" ? obj.y + obj.h : obj.x + obj.w;
return Math.max(max, end);
}, margin); }, margin);
return Math.ceil(clamp(lengthEnd + margin, 10, 500)); return Math.ceil(clamp(lengthEnd + margin, 10, 500));
} }
@@ -193,11 +229,11 @@ function drawTextObject(obj) {
ctx.rect(x, y, w, h); ctx.rect(x, y, w, h);
ctx.clip(); ctx.clip();
ctx.fillStyle = inkColor(); ctx.fillStyle = inkColor();
const fontPx = (obj.fontSizeMm || 5) * printablePxPerMm() * state.zoom; const { size: fontPx, value: font } = objectFont(obj);
ctx.font = `${obj.bold ? "700 " : ""}${fontPx}px DejaVu Sans, Arial, system-ui, sans-serif`; ctx.font = font;
ctx.textBaseline = "middle"; ctx.textBaseline = "middle";
ctx.textAlign = obj.align || "left"; ctx.textAlign = obj.align || "left";
const lines = String(obj.text || "").split("\n"); const lines = wrapCanvasText(obj.text || "", w);
const lineHeight = fontPx * 1.15; const lineHeight = fontPx * 1.15;
const total = lineHeight * lines.length; const total = lineHeight * lines.length;
let cy = y + h / 2 - total / 2 + lineHeight / 2; let cy = y + h / 2 - total / 2 + lineHeight / 2;