From 22c71d367cc3caffd501dea7ebe92fd4db929ad8 Mon Sep 17 00:00:00 2001 From: Justin Lin Date: Fri, 9 Oct 2026 23:14:04 +1100 Subject: [PATCH] fix: quest map wrap text --- app/src/components/QuestMap.vue | 49 +++++++++++++++++++++++++++++++-- 1 file changed, 46 insertions(+), 3 deletions(-) diff --git a/app/src/components/QuestMap.vue b/app/src/components/QuestMap.vue index bf23cd0..3956b14 100644 --- a/app/src/components/QuestMap.vue +++ b/app/src/components/QuestMap.vue @@ -19,6 +19,42 @@ const marginY = 120 const nodeWidth = 160 const nodeHeight = 50 +const maxTextWidth = nodeWidth - 20 +const fontSize = 16 +const maxLines = 2 + +// Approximate glyph width: wide (CJK etc.) chars take a full em, others about half +function charWidth(ch: string) { + return ch.charCodeAt(0) > 0x2e80 ? fontSize : fontSize * 0.55 +} + +function textWidth(s: string) { + return [...s].reduce((w, ch) => w + charWidth(ch), 0) +} + +// SVG text does not wrap, so split the title into lines that fit the node +function wrapTitle(title: string): string[] { + const lines: string[] = [] + let current = '' + // Keep whole words together for spaced languages; CJK splits per character + const tokens = title.match(/[⺀-￿]|\S+\s*/g) ?? [] + for (const token of tokens) { + if (current && textWidth((current + token).trimEnd()) > maxTextWidth) { + lines.push(current.trimEnd()) + current = '' + } + current += token + } + if (current) lines.push(current.trimEnd()) + + if (lines.length <= maxLines) return lines + const kept = lines.slice(0, maxLines) + let last = kept[maxLines - 1] + while (last && textWidth(last + '…') > maxTextWidth) last = last.slice(0, -1) + kept[maxLines - 1] = last + '…' + return kept +} + const opened = ref(null) type Node = { id: string @@ -197,11 +233,17 @@ const edgeStyle = computed(() => { :x="node.x" :y="node.y" text-anchor="middle" - alignment-baseline="middle" + dominant-baseline="central" :class="['node-text', nodeStyle(node)]" - font-size="18" > - {{ node.title }} + + {{ line }} + @@ -235,6 +277,7 @@ svg { } .node-text { + cursor: pointer; &.completed { fill: #1d1d1d; }