From 71e619dda2496f196ec3efd6660e8805a2da69da Mon Sep 17 00:00:00 2001 From: minom Date: Thu, 20 Aug 2026 18:02:53 +0800 Subject: [PATCH] =?UTF-8?q?=E9=82=84=E6=98=AF=E6=9C=89=E5=95=8F=E9=A1=8C?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- web/admin/print/print_multi_new.aspx | 134 ++++++++++++--------------- 1 file changed, 61 insertions(+), 73 deletions(-) diff --git a/web/admin/print/print_multi_new.aspx b/web/admin/print/print_multi_new.aspx index 76e157e..2017b6d 100644 --- a/web/admin/print/print_multi_new.aspx +++ b/web/admin/print/print_multi_new.aspx @@ -432,128 +432,116 @@ // }); //} let s = Number(d.fontSize); - let th = parseFloat(d.textHeight) || Number(h); - let v_gap = parseFloat(d.textSpan) || 0; // 確保強制轉型為數字,避免字串相加錯誤 + let th = Number(d.textHeight) || Number(d.height); + let v_gap = Number(d.textSpan) || 0; let h_gap = 5; - let base_s_px = parseFloat(d.fontSize) * 1.333; - // 1. 保留每個名字獨立的「專屬最大字體」,3個字跟5個字的短名大小會各自獨立計算 + // 1. 設定初始字體 (不再主動放大,統一從預設大小開始測試) + let long_s = Number(d.fontSize); + let short_s = Number(d.fontSize); + let base_s_px = Number(d.fontSize) * 1.333; + + // 2. 判斷誰是長名、誰是短名 (以預設大小判定,判斷後永遠不變) let items = mid.map(name => { let l = name.length; - // 依據原始設定的基準大小,判定是短名還長名 let isShort = (l * base_s_px) <= (th + v_gap); - - // 短名跟長名,各自依照容器 (th 或 h) 算出能放大的極限最佳字體 - let optimal_s = Math.floor((isShort ? th : h) / (l * 1.333)); - if (optimal_s > parseFloat(d.fontSize)) optimal_s = parseFloat(d.fontSize); - if (optimal_s < 6) optimal_s = 6; - - return { name: name, l: l, isShort: isShort, optimal_s: optimal_s, size: optimal_s, isMulti: false }; + return { name: name, l: l, isShort: isShort, isMulti: false, size: 0 }; }); let sizes = []; - let long_ratio = 1.0; - let short_ratio = 1.0; - let shrink_turn = 'long'; // 優先從長名開始縮小 + let shrink_turn = 'long'; // 設定交替縮小指標,優先從長名開始 - // 2. 動態排版預測與比例縮小迴圈 + // 3. 預測排版與縮小迴圈 while (true) { - // 套用當前的縮小比例 - items.forEach(x => { - let s = Math.floor(x.optimal_s * (x.isShort ? short_ratio : long_ratio)); - x.size = s < 6 ? 6 : s; - x.isMulti = false; - }); - - let cols = []; // 用陣列精準記錄每一實體欄位所需的寬度 + let totalWidth = 0; let current_col_h = 0; let current_col_w = 0; + let cols_width = []; // 用來收集每一實體行的真實寬度 for (let i = 0; i < items.length; i++) { let item = items[i]; - let size_px = item.size * 1.333; + + // 賦予當前迴圈測試中的字體大小 + let s = item.isShort ? short_s : long_s; + item.size = s; + let size_px = s * 1.333; if (item.isShort) { + // 短名字計算 (高度至少為 th,若字數過多則取實際字體高度) let item_h = Math.max(th, item.l * size_px); if (current_col_h === 0) { - // 開啟新欄位 + // 開新行 current_col_h = item_h; current_col_w = size_px; - } else if (current_col_h + v_gap + item_h <= h) { - // 高度足夠,與上一個短名字堆疊在同一行 - current_col_h += v_gap + item_h; - if (size_px > current_col_w) current_col_w = size_px; + } else if ((current_col_h + v_gap + item_h) <= h) { + // 該行高度夠放,繼續疊在同一行 + current_col_h += (v_gap + item_h); + if (size_px > current_col_w) current_col_w = size_px; // 取該行最寬的字體寬度 } else { - // 高度不足,結算舊欄位,開啟新欄位 - cols.push(current_col_w); + // 該行放不下,結算並折到下一行 + cols_width.push(current_col_w); current_col_h = item_h; current_col_w = size_px; } } else { - // 長名字必定獨佔或多佔欄位,先將前面累積的短名欄位結算封裝 + // 長名字計算:遇到長名字,必須獨佔或多佔空間,先把前面短名字的行結算掉 if (current_col_h > 0) { - cols.push(current_col_w); + cols_width.push(current_col_w); current_col_h = 0; current_col_w = 0; } let item_w = size_px; - if (item.l * size_px > h) { + // 判斷長名字是否會超過總高度 h,需不需要折成多行 + if ((item.l * size_px) > h) { item.isMulti = true; let chars_per_col = Math.floor(h / size_px); if (chars_per_col < 1) chars_per_col = 1; let item_cols = Math.ceil(item.l / chars_per_col); - item_w = item_cols * (size_px * 1.1); + item_w = item_cols * (size_px * 1.1); // 計算折行後的總寬度 + } else { + item.isMulti = false; } - cols.push(item_w); - // 這裡 current_col_h 保持為 0,確保下一個短名字能順利開啟新欄位! + + cols_width.push(item_w); } } - // 補上最後一個還沒結算的欄位 - if (current_col_h > 0) cols.push(current_col_w); + // 迴圈結束,補上最後一行還沒結算的寬度 + if (current_col_h > 0) cols_width.push(current_col_w); - // 計算總寬度:所有欄寬總和 + 欄間距 - let totalWidth = cols.reduce((a, b) => a + b, 0) + (cols.length > 1 ? (cols.length - 1) * h_gap : 0); + // 4. 結算總寬度 = 所有行寬加總 + 行與行之間的水平間距 + totalWidth = cols_width.reduce((a, b) => a + b, 0) + (cols_width.length > 1 ? (cols_width.length - 1) * h_gap : 0); - // 若總寬度未爆框,則排版完成 + // 判斷是否完美塞進設定的總寬度 w 裡面 if (totalWidth <= w) { sizes = items.map(x => ({ name: x.name, size: x.size, isMulti: x.isMulti, isShort: x.isShort })); break; } - // 3. 若寬度爆框,啟動「輪流比例縮小」機制 (每次扣 5%) - let tryShrink = (type) => { - let didShrink = false; - items.forEach(x => { - if ((type === 'long' ? !x.isShort : x.isShort) && x.size > 6) { - // 預測扣減 5% 後,字體是否真的有變小 (Math.floor 的關係) - let nextRatio = (type === 'long' ? long_ratio : short_ratio) - 0.05; - let nextSize = Math.floor(x.optimal_s * nextRatio); - if (nextSize < x.size) didShrink = true; - } - }); - if (didShrink) { - if (type === 'long') long_ratio -= 0.05; - else short_ratio -= 0.05; + // 5. 若超過寬度,啟動輪流縮小字體再算一次 (每次 -1) + let hasLong = items.some(x => !x.isShort); + let hasShort = items.some(x => x.isShort); + + if (hasLong && hasShort) { + // 長短名皆有,輪流互相縮小 + if (shrink_turn === 'long') { + if (long_s > 6) { long_s--; shrink_turn = 'short'; } + else if (short_s > 6) { short_s--; shrink_turn = 'long'; } + else break; // 都縮到底限,強制跳出 + } else { + if (short_s > 6) { short_s--; shrink_turn = 'long'; } + else if (long_s > 6) { long_s--; shrink_turn = 'short'; } + else break; } - return didShrink; - }; - - let reduced = false; - // 依據回合狀態,輪流要求長、短名字縮小 - if (shrink_turn === 'long') { - if (tryShrink('long')) { reduced = true; shrink_turn = 'short'; } - else if (tryShrink('short')) { reduced = true; shrink_turn = 'long'; } + } else if (hasLong) { + // 只有長名字,一路縮長名字 + if (long_s > 6) long_s--; + else break; } else { - if (tryShrink('short')) { reduced = true; shrink_turn = 'long'; } - else if (tryShrink('long')) { reduced = true; shrink_turn = 'short'; } - } - - // 全部到達極限大小,強制退出迴圈防無窮迴圈 - if (!reduced) { - sizes = items.map(x => ({ name: x.name, size: x.size, isMulti: x.isMulti, isShort: x.isShort })); - break; + // 只有短名字,一路縮短名字 + if (short_s > 6) short_s--; + else break; } }