diff --git a/web/admin/print/TabletDesign.aspx b/web/admin/print/TabletDesign.aspx index 7fdc846..f736c9b 100644 --- a/web/admin/print/TabletDesign.aspx +++ b/web/admin/print/TabletDesign.aspx @@ -1365,45 +1365,22 @@ html, body, * { // fontSize = el.style.fontSize; // rowWidth = fontSize * 2; //} - - - // 1. 初始化最大字體 - let s = Number(el.style.fontSize); + fontSize = el.style.fontSize; + // 1. 依據 textHeight 與 textSpan 計算一行(垂直列)最多能放幾個名字 + let th = Number(el.textHeight) || 0; + let span = Number(el.textSpan) || 0; let h = Number(el.height); let w = Number(el.width); - let gap = 5; // 對應 span 樣式裡的 margin-left: 5px - // 2. 模擬所有名字的總寬度,找出不會爆框的最佳字體 - while (s >= 8) { - let s_px = s * 2; // 將 pt 轉 px - let charsPerCol = Math.floor(h / s_px); // 這個字體大小下,垂直一行最多能塞幾個字 - console.log(charsPerCol); - if (charsPerCol < 1) charsPerCol = 1; + let namesPerCol = Math.floor((h + span) / (th + span)); + if (namesPerCol < 1) namesPerCol = 1; - let totalWidth = 0; + // 2. 計算總共會產生幾列 (cols),並推算出每個名字能分配到的最大欄寬 + let cols = Math.ceil(slice.length / namesPerCol); + if (cols < 1) cols = 1; + let colWidth = Math.floor(w / cols); - // 加總這批名單的真正排版寬度 - slice.forEach((name, index) => { - let cols = Math.ceil(name.length / charsPerCol); // 計算這個人需要折成幾行 - let nameWidth = cols * (s_px * 2); // 1.1 為緊密行高 (line-height) - - totalWidth += nameWidth; - if (index < slice.length - 1) { - totalWidth += gap; // 加上每個人之間的間距 - } - }); - - // 3. 如果總寬度小於等於容器寬度,代表這個字體剛好能讓所有人塞進去! - if (totalWidth <= w) { - break; - } - - s -= 1; // 放不下就縮小 1pt 繼續嘗試 - } - - // 確保極限最小字體為 4pt - let fontSize = s < 8 ? 8 : s; - html = this.renderNameList(slice, el, 0); + html = this.renderNameList(slice, el, colWidth); } else if (el.id === 'alive') { //console.log("createEl:", slice, el) @@ -1428,6 +1405,35 @@ html, body, * { }) .html(html); }, + calcIndividualFontSize(name, el, maxW) { + let s = Number(el.style.fontSize); + let maxH = Number(el.textHeight); // 限制在單一名字預設的區塊高度內 + let l = Number(name.length); + + while (s >= 12) { + let s_px = s * 1.333; // 將 pt 轉換為 px + + // 如果單行高度夠放,直接回傳當下大小 (不會過度縮小) + if (l * s_px <= maxH) { + return s; + } + + // 單行放不下,模擬多行折疊後的總寬度 + let charsPerCol = Math.floor(maxH / s_px); + if (charsPerCol < 1) charsPerCol = 1; + + let cols = Math.ceil(l / charsPerCol); + let neededWidth = cols * (s_px * 1.1); // 1.1 為緊密行高 + + // 如果折疊後的總寬度不超過分配到的橫向欄寬,就是最佳字體 + if (neededWidth <= maxW) { + return s; + } + s -= 1; // 否則繼續縮小 1pt + } + return 12; // 極限最小字體 + }, + countFontSize(name, el, baseFontSize) { let s = Number(baseFontSize); let h = Number(el.height); @@ -1484,15 +1490,25 @@ html, body, * { }) return $namelist; }, - renderNameSpan(name, el, rowWidth) { - return $(`${name}`).css({ + renderNameSpan(name, el, colWidth) { + // 為「這個名字」獨立計算出專屬的最完美字體大小 + let indSize = this.calcIndividualFontSize(name, el, colWidth); + // 2. 判斷是否發生了折行 (名字長度 * 單字像素高度 > 分配到的最大高度) + let s_px = indSize * 1.333; + let isMultiLine = (name.length * s_px) > Number(el.textHeight); + + // 3. 根據是否折行動態決定對齊方式 + // 單行:分散對齊 (justify) / 多行:置中對齊 (center) 或是改為 靠上對齊 (start) + let alignStyle = isMultiLine ? "start" : "justify"; + + return $(`${name}`).css({ display: "block", - "min-height": `${el.textHeight}px`, // ★ 拿掉原本的 textHeight 限制,避免短字被硬撐 + "min-height": `${el.textHeight}px`, "max-height": `${el.height}px`, - width: "auto", // ★ 讓多行文字自然撐開寬度 - "line-height": "1.1", // ★ 緊密行高,讓折行的「劉三..」跟「陳五」黏緊 - "text-align": "justify", - "text-align-last": "justify", + width: "auto", + "line-height": "1.1", + "text-align": alignStyle, // ★ 動態套用對齊方式 + "text-align-last": alignStyle, // ★ 動態套用最後一行對齊方式 "margin-left": "5px", "text-justify": "inter-character", "word-break": "break-all" @@ -1687,45 +1703,24 @@ html, body, * { // rowWidth = fontSize * 2; //} - // 1. 初始化最大字體 - let s = Number(el.style.fontSize); + // 1. 依據 textHeight 與 textSpan 計算一行(垂直列)最多能放幾個名字 + let th = Number(el.textHeight) || 0; + let span = Number(el.textSpan) || 0; let h = Number(el.height); let w = Number(el.width); - let gap = 5; // 對應 span 樣式裡的 margin-left: 5px - // 2. 模擬所有名字的總寬度,找出不會爆框的最佳字體 - while (s >= 8) { - let s_px = s *2; // 將 pt 轉 px - let charsPerCol = Math.floor(h / s_px); // 這個字體大小下,垂直一行最多能塞幾個字 - if (charsPerCol < 1) charsPerCol = 1; + let namesPerCol = Math.floor((h + span) / (th + span)); + if (namesPerCol < 1) namesPerCol = 1; - let totalWidth = 0; + // 2. 計算總共會產生幾列 (cols),並推算出每個名字能分配到的最大欄寬 + let cols = Math.ceil(slice.length / namesPerCol); + if (cols < 1) cols = 1; + let colWidth = Math.floor(w / cols); - // 加總這批名單的真正排版寬度 - slice.forEach((name, index) => { - let cols = Math.ceil(name.length / charsPerCol); // 計算這個人需要折成幾行 - let nameWidth = cols * (s_px * 2); // 1.1 為緊密行高 (line-height) - - totalWidth += nameWidth; - if (index < slice.length - 1) { - totalWidth += gap; // 加上每個人之間的間距 - } - }); - - // 3. 如果總寬度小於等於容器寬度,代表這個字體剛好能讓所有人塞進去! - if (totalWidth <= w) { - break; - } - - s -= 1; // 放不下就縮小 1pt 繼續嘗試 - } - - // 確保極限最小字體為 4pt - let fontSize = s < 8 ? 8 : s; //console.log(el.height, el.textHeight, perRow, rows, rowWidth, fontSize) - html = this.renderNameList(slice, el, 0);//el.style.fontSize + html = this.renderNameList(slice, el, colWidth);//el.style.fontSize $(`.tablet-element[id="${this.activeId}"]`).css({ - position: "absolute", left: el.x + "mm", top: el.y + "mm", fontSize: fontSize + 'pt', fontFamily: el.style.fontFamily, "z-index": 9999, visibility: el.style.visibility + position: "absolute", left: el.x + "mm", top: el.y + "mm", fontSize: el.style.fontSize + 'pt', fontFamily: el.style.fontFamily, "z-index": 9999, visibility: el.style.visibility }).html(html); } else if (this.activeId === "alive") { let names = el.text.split('\n').filter(s => s.trim());