TEXTBOX กล่องกว้างคงที่สไตล์ Smallpdf: คลิกเดียวได้กล่อง 30% + ลากขอบซ้าย/ขวาปรับความกว้าง (ฟอนต์คงขนาด ข้อความ wrap ใหม่)
Co-Authored-By: Claude Code <noreply@anthropic.com>
This commit is contained in:
parent
9e6158ed45
commit
ca74fb1843
10 changed files with 248 additions and 41 deletions
|
|
@ -20,9 +20,18 @@ export const COMMENT_PIN_BOX_PCT = 4;
|
|||
// render จริงกว้างสุด 50% ของหน้าแล้ว wrap อัตโนมัติ — bbox ประมาณจากตัวอักษร
|
||||
// กว้าง ~0.6 × fontSize ต่อตัว บรรทัดสูง 1.5 × fontSize (ค่าประมาณพอสำหรับกรอบ selection)
|
||||
export const TEXTBOX_MAX_WIDTH_PCT = 50;
|
||||
export const TEXTBOX_DEFAULT_WIDTH_PCT = 30; // กล่องที่สร้างใหม่ (คลิกเดียว) กว้างเท่านี้ก่อนลากขยาย
|
||||
export const TEXTBOX_CHAR_W = 0.6;
|
||||
export const TEXTBOX_LINE_H = 1.5;
|
||||
|
||||
/** ความกว้างสูงสุดของกล่องข้อความ (% ของความกว้างหน้า) จากขอบซ้าย (position.x = มุมซ้ายบน
|
||||
* เสมอ — align จัดข้อความ*ใน*กล่องอย่างเดียวแบบ Smallpdf กล่องไม่ขยับ) — บีบให้กล่อง
|
||||
* ไม่ล้นขอบขวาของหน้ากระดาษ ใช้ร่วมกันทั้ง render จอ, bbox กรอบ selection และ export PDF
|
||||
* ติดขอบขวาเป๊ะ (x=100) เหลือกว้างขั้นต่ำ 1% กันกล่องพังเป็นศูนย์ */
|
||||
export function textboxMaxWidthPct(leftX: number): number {
|
||||
return Math.min(TEXTBOX_MAX_WIDTH_PCT, Math.max(100 - clamp(leftX, 0, 100), 1));
|
||||
}
|
||||
|
||||
// STAMP (F18/B5 — §5): กรอบตรายางกว้าง = scale% ของความกว้างหน้า สูง = 0.4 เท่าของความกว้าง
|
||||
// (สูตรเดียวกันทั้ง render บนจอ, bbox ของ selection และการวาดใน export)
|
||||
export const STAMP_HEIGHT_RATIO = 0.4;
|
||||
|
|
@ -81,24 +90,25 @@ export function annotationBBox(a: AnnotationLike, size: Size): Rect {
|
|||
return rectToPx(d.rect, size);
|
||||
}
|
||||
if ("fontSize" in d) {
|
||||
// TEXTBOX — ประมาณจากข้อความ (position เป็นมุมซ้ายบนของกล่อง)
|
||||
// TEXTBOX — position เป็นมุมซ้ายบนของกล่องเสมอ (align จัดข้อความในกล่องอย่างเดียว);
|
||||
// กล่องมี width คงที่ (ถ้ามี — สไตล์ Smallpdf) ไม่มี = shrink-to-fit ประมาณจากตัวอักษร
|
||||
const fontSizePx = toPx(d.fontSize, size.width);
|
||||
const charW = fontSizePx * TEXTBOX_CHAR_W;
|
||||
const lineH = fontSizePx * TEXTBOX_LINE_H;
|
||||
const maxW = toPx(TEXTBOX_MAX_WIDTH_PCT, size.width);
|
||||
// ความกว้างสูงสุดถึงขอบขวาหน้า — กล่อง width คงที่ก็ถูกบีบด้วยค่านี้เหมือน render
|
||||
const capPct = textboxMaxWidthPct(d.position.x);
|
||||
const wrapPx = toPx(Math.min(d.width ?? capPct, capPct), size.width);
|
||||
const wrapW = Math.max(wrapPx, charW); // กันหารศูนย์เมื่อกล่องติดขอบขวาเป๊ะ
|
||||
let widest = 0;
|
||||
let lines = 0;
|
||||
for (const raw of d.text.split(/\r?\n/)) {
|
||||
widest = Math.max(widest, raw.length * charW);
|
||||
lines += Math.max(1, Math.ceil((raw.length * charW) / maxW));
|
||||
lines += Math.max(1, Math.ceil((raw.length * charW) / wrapW));
|
||||
}
|
||||
// กล่อง width คงที่กว้างตามที่กำหนด (บีบด้วย cap) — แถวเดิม shrink-to-fit ตามบรรทัดยาวสุด
|
||||
const width = (d.width !== undefined ? wrapPx : Math.min(widest, wrapPx)) || charW;
|
||||
const p = pointToPx(d.position, size);
|
||||
return {
|
||||
x: p.x,
|
||||
y: p.y,
|
||||
width: Math.min(widest, maxW) || charW,
|
||||
height: Math.max(lines, 1) * lineH,
|
||||
};
|
||||
return { x: p.x, y: p.y, width, height: Math.max(lines, 1) * lineH };
|
||||
}
|
||||
if ("scale" in d) {
|
||||
// STAMP — กรอบจริงตามสูตร render (position เป็นมุมซ้ายบน)
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue