Add automatic label length trimming

This commit is contained in:
Mikei386
2026-06-22 13:25:03 +02:00
parent 941c68bbf8
commit e4a7679bc7
6 changed files with 90 additions and 4 deletions
+25 -1
View File
@@ -16,6 +16,7 @@ const state = {
design: {
tapeWidthMm: 24,
lengthMm: 70,
autoLength: true,
marginMm: 2,
orientation: "landscape",
cutMode: "auto",
@@ -31,6 +32,7 @@ const message = document.getElementById("message");
const controls = {
tapeWidth: document.getElementById("tapeWidth"),
lengthMm: document.getElementById("lengthMm"),
autoLength: document.getElementById("autoLength"),
marginMm: document.getElementById("marginMm"),
cutMode: document.getElementById("cutMode"),
copies: document.getElementById("copies"),
@@ -80,6 +82,21 @@ function printablePxPerMm() {
return (PRINTABLE_TAPE_PX[tape] || (tape * 180) / 25.4) / tape;
}
function clamp(value, min, max) {
return Math.min(max, Math.max(min, value));
}
function contentLengthMm() {
if (!state.design.objects.length) return Number(controls.lengthMm.value) || state.design.lengthMm || 70;
const margin = Number(controls.marginMm.value) || 0;
const lengthEnd = state.design.objects.reduce((max, obj) => {
if (obj.hidden) return max;
const end = state.design.orientation === "portrait" ? obj.y + obj.h : obj.x + obj.w;
return Math.max(max, end);
}, margin);
return Math.ceil(clamp(lengthEnd + margin, 10, 500));
}
function selected() {
return state.design.objects.find((obj) => obj.id === state.selectedId) || null;
}
@@ -94,13 +111,20 @@ function syncDesignControls() {
state.design.lengthMm = Number(controls.lengthMm.value);
state.design.marginMm = Number(controls.marginMm.value);
state.design.cutMode = controls.cutMode.value;
state.design.autoLength = controls.autoLength.checked;
state.design.halfcut = "off";
state.design.orientation = document.querySelector("input[name='orientation']:checked").value;
controls.lengthMm.disabled = state.design.autoLength;
if (state.design.autoLength) {
state.design.lengthMm = contentLengthMm();
controls.lengthMm.value = state.design.lengthMm;
}
}
function applyDesignControls() {
controls.tapeWidth.value = state.design.tapeWidthMm;
controls.lengthMm.value = state.design.lengthMm;
controls.autoLength.checked = state.design.autoLength !== false;
controls.marginMm.value = state.design.marginMm;
controls.cutMode.value = state.design.cutMode || "auto";
document.querySelector(`input[name='orientation'][value='${state.design.orientation}']`).checked = true;
@@ -411,7 +435,7 @@ window.addEventListener("keydown", (event) => {
}
});
["tapeWidth", "lengthMm", "marginMm", "cutMode"].forEach((id) => document.getElementById(id).addEventListener("input", draw));
["tapeWidth", "lengthMm", "autoLength", "marginMm", "cutMode"].forEach((id) => document.getElementById(id).addEventListener("input", draw));
document.querySelectorAll("input[name='orientation']").forEach((input) => input.addEventListener("change", draw));
Object.values(controls).forEach((control) => {
if (control && control.id && control.id.startsWith("prop")) control.addEventListener("input", applyProps);
+25 -2
View File
@@ -2,6 +2,7 @@ const fields = {
text: document.getElementById("mobileText"),
tape: document.getElementById("mobileTape"),
length: document.getElementById("mobileLength"),
autoLength: document.getElementById("mobileAutoLength"),
margin: document.getElementById("mobileMargin"),
font: document.getElementById("mobileFont"),
copies: document.getElementById("mobileCopies"),
@@ -13,6 +14,13 @@ const fields = {
message: document.getElementById("mobileMessage"),
};
function estimateTextLengthMm(text, fontSize, margin, frame) {
const lines = String(text || " ").split("\n");
const longest = lines.reduce((max, line) => Math.max(max, line.length), 0);
const textWidth = Math.max(8, longest * fontSize * 0.62);
return Math.min(300, Math.max(20, Math.ceil(textWidth + margin * 2 + (frame ? 4 : 0))));
}
function setMessage(text, type = "") {
fields.message.textContent = text;
fields.message.className = `message ${type}`;
@@ -20,9 +28,15 @@ function setMessage(text, type = "") {
function mobileDesign() {
const tapeWidth = Number(fields.tape.value);
const length = Number(fields.length.value);
const margin = Number(fields.margin.value);
const text = fields.text.value.trim() || " ";
const fontSize = Number(fields.font.value);
const autoLength = fields.autoLength.checked;
const length = autoLength
? estimateTextLengthMm(text, fontSize, margin, fields.frame.checked)
: Number(fields.length.value);
fields.length.value = String(length);
fields.length.disabled = autoLength;
const objects = [];
if (fields.frame.checked) {
objects.push({
@@ -44,7 +58,7 @@ function mobileDesign() {
w: Math.max(2, length - margin * 2 - (fields.frame.checked ? 2 : 0)),
h: Math.max(2, tapeWidth - margin * 2),
text,
fontSizeMm: Number(fields.font.value),
fontSizeMm: fontSize,
bold: fields.bold.checked,
align: fields.align.value,
valign: "middle",
@@ -52,6 +66,7 @@ function mobileDesign() {
return {
tapeWidthMm: tapeWidth,
lengthMm: length,
autoLength,
marginMm: margin,
orientation: "landscape",
cutMode: fields.cutMode.value,
@@ -89,3 +104,11 @@ document.getElementById("mobileDetect").addEventListener("click", async () => {
fields.tape.value = String(payload.width);
setMessage(`Band erkannt: ${payload.width} mm`, "success");
});
["text", "font", "margin", "frame", "autoLength"].forEach((name) => {
fields[name].addEventListener("input", () => {
if (name === "autoLength" || fields.autoLength.checked) mobileDesign();
});
});
mobileDesign();