mirror of
https://github.com/linux-odyssey/linux-odyssey.git
synced 2026-11-06 03:20:13 +08:00
fix: quest map wrap text
This commit is contained in:
1 parent
4260e742df
commit
22c71d367c
1 file changed
+46
-3
@@ -19,6 +19,42 @@ const marginY = 120
|
|||||||
|
|
||||||
const nodeWidth = 160
|
const nodeWidth = 160
|
||||||
const nodeHeight = 50
|
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<Node | null>(null)
|
const opened = ref<Node | null>(null)
|
||||||
type Node = {
|
type Node = {
|
||||||
id: string
|
id: string
|
||||||
@@ -197,11 +233,17 @@ const edgeStyle = computed(() => {
|
|||||||
:x="node.x"
|
:x="node.x"
|
||||||
:y="node.y"
|
:y="node.y"
|
||||||
text-anchor="middle"
|
text-anchor="middle"
|
||||||
alignment-baseline="middle"
|
dominant-baseline="central"
|
||||||
:class="['node-text', nodeStyle(node)]"
|
:class="['node-text', nodeStyle(node)]"
|
||||||
font-size="18"
|
|
||||||
>
|
>
|
||||||
{{ node.title }}
|
<tspan
|
||||||
|
v-for="(line, i) in wrapTitle(node.title)"
|
||||||
|
:key="i"
|
||||||
|
:x="node.x"
|
||||||
|
:dy="i === 0 ? `${-(wrapTitle(node.title).length - 1) * 0.6}em` : '1.2em'"
|
||||||
|
>
|
||||||
|
{{ line }}
|
||||||
|
</tspan>
|
||||||
</text>
|
</text>
|
||||||
</g>
|
</g>
|
||||||
</g>
|
</g>
|
||||||
@@ -235,6 +277,7 @@ svg {
|
|||||||
}
|
}
|
||||||
|
|
||||||
.node-text {
|
.node-text {
|
||||||
|
cursor: pointer;
|
||||||
&.completed {
|
&.completed {
|
||||||
fill: #1d1d1d;
|
fill: #1d1d1d;
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in new issue
Block a user