還是有問題

This commit is contained in:
2026-08-20 18:02:53 +08:00
parent 24de2c6071
commit 71e619dda2
+61 -73
View File
@@ -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;
}
}