From 7c5e5ab984fea53157f2ffff1be1e15805b06fa1 Mon Sep 17 00:00:00 2001 From: minom Date: Thu, 20 Aug 2026 17:46:25 +0800 Subject: [PATCH] =?UTF-8?q?=E8=AA=BF=E6=95=B4=E7=89=8C=E4=BD=8D=EF=BC=8C?= =?UTF-8?q?=E9=82=84=E6=98=AF=E6=9C=89=E9=BB=9E=E6=80=AA=E6=80=AA=E7=9A=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- web/admin/print/print_multi_new.aspx | 274 ++++++++++++++++++++------- 1 file changed, 203 insertions(+), 71 deletions(-) diff --git a/web/admin/print/print_multi_new.aspx b/web/admin/print/print_multi_new.aspx index f35b812..8d3aef7 100644 --- a/web/admin/print/print_multi_new.aspx +++ b/web/admin/print/print_multi_new.aspx @@ -347,86 +347,212 @@ let w = Number(d.width); let th = Number(d.textHeight) || h; let gap = 5; // 對應 span 的 margin-left + let v_gap = Number(d.textSpan) + //let s = Number(d.fontSize); + //let sizes = []; + //let base_s_px = s * 1.333; + + //// 1. 模擬排版:找出能讓全體塞入的最佳字體組合 + //while (s >= 12) { + // let short_s_px = s * 1.333*1.1; + // let hasShort = mid.some(n => (n.length * short_s_px) <=Number(th) + Number(d.textSpan)); + + // let long_s = hasShort ? Math.floor(s * 0.75) : s; // 長字體最多縮小 25% + // if (long_s < 12) long_s = 12; + // let long_s_px = long_s * 1.333*1.1; + + // let currentColHeight = 0; + // let totalWidth = 0; + // let tempSizes = []; + // let anyWrapped = false; + // for (let i = 0; i < mid.length; i++) { + // let name = mid[i]; + // let l = name.length; + // //let isMulti = (l * short_s_px) > th; + // let isShort = (l * short_s_px) <= (Number(th) + Number(d.textSpan)); + // console.log("冷涼:",name,(l * short_s_px), (Number(d.textHeight) + Number(d.textSpan)),s,isShort) + // let size = isShort ? s : long_s;//isMulti ? long_s : s; + // let size_px = size * (4 / 3); //isMulti ? long_s_px : short_s_px; + // let padding = (name.length > 10) ? 5 : 0 + // let isMulti = !isShort && (l * size_px >= h - padding); + // if (isMulti) anyWrapped = true; + + // tempSizes.push({ name: name, size: size, isMulti: isMulti,isShort:isShort }); + + // if (isMulti) { + // // 多行長名 + // let charsPerCol = Math.floor(h / size_px); + // if (charsPerCol < 1) charsPerCol = 1; + // let lines = Math.ceil(l / charsPerCol); + // let nameW = lines * (size_px * 1.1); // 1.1倍行距 + + // if (currentColHeight > 0) currentColHeight = 0; + // totalWidth += nameW + gap; + // } else { + // if (isShort) { + // // 單行短名 + // if (currentColHeight > 0 && (currentColHeight + th + gap) <= h) { + // currentColHeight += th + gap; + // } else { + // currentColHeight = th; + // totalWidth += short_s_px + gap; + // } + // } else { + // currentColHeight = 0; + // totalWidth += size_px + gap; + // } + // } + // } + + // if (totalWidth > 0) totalWidth -= gap; + // console.log("QQ:",name,totalWidth,w) + // // 總寬度未爆框,確定最佳組合 + // if (totalWidth <= w) { + // if (hasShort) { + // sizes = tempSizes; + // break; + // } else { + // if (!anyWrapped || s === 12) { + // sizes = tempSizes; + // break; + // } + // } + + // } + + // s -= 1; + // console.log("計算過:",s) + //} + + //// 處理極端情況 + //if (sizes.length === 0) { + // sizes = mid.map(name => { + // return { name: name, size: 12, isMulti: (name.length * 12 * 1.333) > th }; + // }); + //} let s = Number(d.fontSize); + + + let h_gap = 5; + let base_s_px = Number(d.fontSize) * 1.333; + + // 1. 保留每個名字獨立的「專屬最大字體」,3個字跟5個字的短名大小會各自獨立計算 + let items = mid.map(name => { + let l = name.length; + let isShort = (l * base_s_px) <= (th + v_gap); + + let optimal_s = Math.floor((isShort ? th : h) / (l * 1.333)); + if (optimal_s > Number(d.fontSize)) optimal_s = Number(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 }; + }); + let sizes = []; + let long_ratio = 1.0; + let short_ratio = 1.0; + let shrink_turn = 'long'; - // 1. 模擬排版:找出能讓全體塞入的最佳字體組合 - while (s >= 12) { - let short_s_px = s * 1.333; - let hasShort = mid.some(n => (n.length * short_s_px) <= th); + // 2. 動態排版與比例縮小迴圈 + 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 long_s = hasShort ? Math.floor(s * 0.75) : s; // 長字體最多縮小 25% - if (long_s < 12) long_s = 12; - let long_s_px = long_s * 1.333; + let cols = []; // 用陣列記錄每一實體欄位的寬度 + let current_col_h = 0; + let current_col_w = 0; - let currentColHeight = 0; - let totalWidth = 0; - let tempSizes = []; - let anyWrapped = false; - for (let i = 0; i < mid.length; i++) { - let name = mid[i]; - let l = name.length; - //let isMulti = (l * short_s_px) > th; - let isShort = (l * short_s_px) <= th; - let size = isShort ? s : long_s;//isMulti ? long_s : s; - let size_px = size * 1.333; //isMulti ? long_s_px : short_s_px; + for (let i = 0; i < items.length; i++) { + let item = items[i]; + let size_px = item.size * 1.333; - let isMulti = !isShort && (l * size_px >= h); - if (isMulti) anyWrapped = true; - - tempSizes.push({ name: name, size: size, isMulti: isMulti,isShort:isShort }); - - if (isMulti) { - // 多行長名 - let charsPerCol = Math.floor(h / size_px); - if (charsPerCol < 1) charsPerCol = 1; - let lines = Math.ceil(l / charsPerCol); - let nameW = lines * (size_px * 1.1); // 1.1倍行距 - - if (currentColHeight > 0) currentColHeight = 0; - totalWidth += nameW + gap; - } else { - if (isShort) { - // 單行短名 - if (currentColHeight > 0 && (currentColHeight + th + gap) <= h) { - currentColHeight += th + gap; - } else { - currentColHeight = th; - totalWidth += short_s_px + gap; - } + if (item.isShort) { + 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 { - currentColHeight = 0; - totalWidth += size_px + gap; + cols.push(current_col_w); // 封裝這一行 + current_col_h = item_h; + current_col_w = size_px; } - } - } - - if (totalWidth > 0) totalWidth -= gap; - - // 總寬度未爆框,確定最佳組合 - if (totalWidth <= w) { - if (hasShort) { - sizes = tempSizes; - break; } else { - if (!anyWrapped || s === 12) { - sizes = tempSizes; - break; + // 長名字必定獨佔或多佔欄位,先將前面的短名欄位封裝 + if (current_col_h > 0) { + cols.push(current_col_w); + current_col_h = 0; + current_col_w = 0; } - } + let item_w = size_px; + 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); + } + cols.push(item_w); + } + } + if (current_col_h > 0) cols.push(current_col_w); + + // 總寬度 = 所有欄寬總和 + 欄間距 + let totalWidth = cols.reduce((a, b) => a + b, 0) + (cols.length > 1 ? (cols.length - 1) * h_gap : 0); + + if (totalWidth <= w) { + sizes = items.map(x => ({ name: x.name, size: x.size, isMulti: x.isMulti, isShort: x.isShort })); + break; + } + + // 3. 寬度爆框,啟動「輪流比例縮小」 + let tryShrink = (type) => { + let didShrink = false; + items.forEach(x => { + if ((type === 'long' ? !x.isShort : x.isShort) && x.size > 6) { + // 模擬扣減 5% 後,字體是否真的有變小 + 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; + } + 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 (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; } - s -= 1; } - // 處理極端情況 + // 防呆處理 if (sizes.length === 0) { sizes = mid.map(name => { - return { name: name, size: 12, isMulti: (name.length * 12 * 1.333) > th }; + return { name: name, size: 6, isMulti: false, isShort: true }; }); } - // 2. 建立外層的 Flexbox 容器 let $namelist = $(`
`).css({ "writing-mode": "vertical-rl", @@ -445,9 +571,8 @@ }); sizes.forEach(item => { let th = Number(d.textHeight) || Number(d.height) - let minH = item.isShort ? `${th}px` : `${d.height}px` - ; - let alignStyle = item.isMulti ? "start" : "justify"; + let minH = item.isShort ? `${th}px` : `${d.height}px` ; + let alignStyle = item.isMulti || (!item.isMulti && !item.isShort) ? "start" : "justify"; let $span= $(`${item.name}`).css({ display: "block", @@ -480,14 +605,14 @@ ${parts[1] || ''} `; } else if (d.elementID === "address") { - newFontSize = self.scaleFontSize(mid, d.fontSize, d.width); + newFontSize = self.scaleFontSize(address, d.fontSize, d.height); html = self.renderNormal(address, d) } else if (d.elementID === "lefttitle") { - newFontSize = self.scaleFontSize(mid, d.fontSize, d.width); + newFontSize = self.scaleFontSize(lefttitle, d.fontSize, d.height); html = self.renderNormal(lefttitle, d) } else if (d.elementID === "righttitle") { - newFontSize = self.scaleFontSize(mid, d.fontSize, d.width); + newFontSize = self.scaleFontSize(righttitle, d.fontSize, d.height); html = self.renderNormal(righttitle, d) } if (newFontSize < 10) { @@ -1019,15 +1144,22 @@ let font = this.getTextSize("講", parseInt(fontSize)); //自動判斷縮小字型的規則,要同時縮小間距 - - //if (dStyle.elementID === 'title1') {//表示是一般正名,也就是牌位正中間的一般格式,排法是上下上下 - if ((Math.ceil(txtContent.length / 2) * font.width) * 2 > parseFloat(elementWidth)) { - let newfontSize = parseInt(fontSize) - 1; + // console.log("scaleFontSize:", txtContent, fontSize, elementWidth) + if (Math.ceil(txtContent.length * fontSize * (4 / 3) * 1.1) > Number(elementWidth)) { + let newfontSize = Number(fontSize) - 1; if (newfontSize <= 10) { return newfontSize; } return this.scaleFontSize(txtContent, newfontSize, elementWidth); } + //if (dStyle.elementID === 'title1') {//表示是一般正名,也就是牌位正中間的一般格式,排法是上下上下 + //if ((Math.ceil(txtContent.length / 2) * font.width) * 2 > parseFloat(elementWidth)) { + // let newfontSize = parseInt(fontSize) - 1; + // if (newfontSize <= 10) { + // return newfontSize; + // } + // return this.scaleFontSize(txtContent, newfontSize, elementWidth); + //} return fontSize; }, breakWord(txtContent, style, dStyle) {