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
|
|
@ -309,6 +309,13 @@ function validateAnnotationData(type: AnnotationType, v: unknown): AnnotationDat
|
|||
}
|
||||
}
|
||||
const textboxNote = vNote(d.note);
|
||||
// width (กล่องกว้างคงที่) เป็น optional — ไม่มี = shrink-to-fit ตามเดิม (แถวเดิม)
|
||||
if (
|
||||
d.width !== undefined &&
|
||||
(typeof d.width !== "number" || !Number.isFinite(d.width) || d.width <= 0)
|
||||
) {
|
||||
fieldError("data.width", "เป็นตัวเลข > 0");
|
||||
}
|
||||
return {
|
||||
position,
|
||||
text,
|
||||
|
|
@ -318,6 +325,7 @@ function validateAnnotationData(type: AnnotationType, v: unknown): AnnotationDat
|
|||
...(d.opacity !== undefined ? { opacity: d.opacity } : {}),
|
||||
...(d.align !== undefined ? { align: d.align } : {}),
|
||||
...(d.segments !== undefined ? { segments: d.segments } : {}),
|
||||
...(d.width !== undefined ? { width: d.width } : {}),
|
||||
...(textboxNote !== undefined ? { note: textboxNote } : {}),
|
||||
} satisfies TextboxData;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -33,7 +33,7 @@ import {
|
|||
} from "@/utils/pdf-export";
|
||||
import type { Rect } from "@/db/schema";
|
||||
import { toPx, type Point, type Size } from "@/utils/coordinates";
|
||||
import { STAMP_HEIGHT_RATIO, TEXTBOX_MAX_WIDTH_PCT } from "@/utils/geometry";
|
||||
import { STAMP_HEIGHT_RATIO, textboxMaxWidthPct } from "@/utils/geometry";
|
||||
import { STAMP_COLOR, effectiveDrawOpacity, stampFitFontSize } from "@/utils/annotation-display";
|
||||
|
||||
// Export PDF ฝัง annotation (F8/C1 — PLAN-FEAT.md §3)
|
||||
|
|
@ -340,7 +340,14 @@ export async function GET(req: Request) {
|
|||
const { r, g, b } = hexToRgb01(d.color);
|
||||
if (thaiFont) {
|
||||
const fontSize = Math.max(thickness(d.fontSize), 4);
|
||||
const maxWidth = px(TEXTBOX_MAX_WIDTH_PCT, display.width);
|
||||
// clamp ขอบขวาแบบเดียวกับบนจอ (textboxMaxWidthPct) — ไม่งั้นกล่อง
|
||||
// ที่ position.x สูง (ครึ่งขวาของหน้า) ข้อความทุกบรรทัดทะลุขอบหน้ากระดาษ
|
||||
// กล่อง width คงที่ (ถ้ามี) wrap ที่ความกว้างนั้น (บีบด้วย cap เหมือน render จอ)
|
||||
const capPct = textboxMaxWidthPct(d.position.x);
|
||||
const maxWidth = Math.max(
|
||||
px(Math.min(d.width ?? capPct, capPct), display.width),
|
||||
10,
|
||||
);
|
||||
// run ต่อสไตล์: segments (ตัวหนาเฉพาะส่วน) หรือทั้งกล่องตาม d.bold
|
||||
const runs: StyledRun[] = d.segments?.length
|
||||
? d.segments.map((s) => ({ text: s.text, bold: !!(s.bold || d.bold) }))
|
||||
|
|
@ -349,16 +356,25 @@ export async function GET(req: Request) {
|
|||
const widthOf = (s: string, bold: boolean) =>
|
||||
fontFor(bold).widthOfTextAtSize(s, fontSize);
|
||||
const lines = wrapStyledText(runs, maxWidth, widthOf);
|
||||
// จัดแนวในกล่องกว้าง maxWidth — เลื่อน x ต่อบรรทัดตามความกว้างจริงของบรรทัดนั้น
|
||||
// กล่องห้อยจากมุมซ้ายบน (pos) เหมือน render จอ — align จัดบรรทัด*ใน*กล่องอย่างเดียว
|
||||
// (แบบ Smallpdf กล่องไม่ขยับ): กล่อง width คงที่กว้างเต็ม maxWidth ตามที่กำหนด
|
||||
// ส่วนแถวเดิม shrink-to-fit กว้างเท่าบรรทัดยาวสุด (ไม่เกิน maxWidth)
|
||||
const align = d.align ?? "left";
|
||||
const lineWOf = (lineRuns: StyledRun[]) =>
|
||||
lineRuns.reduce((sum, rn) => sum + widthOf(rn.text, rn.bold), 0);
|
||||
const boxW =
|
||||
d.width !== undefined
|
||||
? maxWidth
|
||||
: Math.max(Math.min(...lines.map(lineWOf), maxWidth), 1);
|
||||
const boxLeft = pos.x;
|
||||
lines.forEach((lineRuns, i) => {
|
||||
const lineW = lineRuns.reduce((sum, rn) => sum + widthOf(rn.text, rn.bold), 0);
|
||||
const lineW = lineWOf(lineRuns);
|
||||
let x =
|
||||
align === "center"
|
||||
? pos.x + (maxWidth - lineW) / 2
|
||||
? boxLeft + (boxW - lineW) / 2
|
||||
: align === "right"
|
||||
? pos.x + (maxWidth - lineW)
|
||||
: pos.x;
|
||||
? boxLeft + (boxW - lineW)
|
||||
: boxLeft;
|
||||
for (const rn of lineRuns) {
|
||||
page.drawText(rn.text, {
|
||||
x,
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue