ForcePilot/web/src/utils/svgRenderer.js
supreme0597 3870dc18a0 feat(web): 添加 SVG 操作按钮(复制 SVG 源码/复制为 PNG)及事件委托
- svgRenderer.js 输出中嵌入 .svg-actions 操作按钮
- MarkdownPreview.vue 添加事件委托处理复制逻辑
- PNG 尺寸策略:viewBox 固有坐标 → getBoundingClientRect → 800x600
- Canvas 不强制填充背景色,由 SVG 自身决定
- 深色模式适配
2026-05-25 21:08:37 +08:00

73 lines
2.3 KiB
JavaScript
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

/**
* SVG 渲染工具函数
* 将 Markdown 中的 ```svg 围栏代码块转换为内联 SVG HTML
*/
/**
* 将 Markdown 字符串中的 ```svg 围栏代码块转换为内联 SVG HTML
*
* 使用逐行扫描算法而非单一大正则,以避免嵌套围栏和内容中反引号的误匹配。
* SVG 内容会被压缩为单行,防止 markdown-it HTML 块解析因空白行截断内容。
*
* @param {string} markdown - 原始 Markdown 字符串
* @returns {string} 转换后的字符串SVG 围栏被替换为 <div class="svg-inline-render"><svg>...</svg></div>
*/
export function renderSvgBlocks(markdown) {
const lines = markdown.split('\n')
const output = []
let i = 0
while (i < lines.length) {
const openMatch = lines[i].match(/^( {0,3})(`{3,}|~{3,})\s*(\S*)/)
if (openMatch && openMatch[3].toLowerCase() === 'svg') {
const indent = openMatch[1]
const fenceChar = openMatch[2]
const openLine = lines[i]
const svgLines = []
i++
// 扫描闭合围栏
let closed = false
while (i < lines.length) {
const closeMatch = lines[i].match(/^( {0,3})(`{3,}|~{3,})\s*$/)
if (
closeMatch
&& closeMatch[1].length <= indent.length
&& closeMatch[2][0] === fenceChar[0]
&& closeMatch[2].length >= fenceChar.length
) {
closed = true
// 压缩 SVG 为单行,防止 markdown-it HTML 块解析截断
const singleLine = svgLines
.join('')
.replace(/>\s+</g, '><')
.replace(/\s{2,}/g, ' ')
.trim()
const actionsHtml = [
`<div class="svg-actions">`,
`<button class="svg-action-btn svg-copy-btn" type="button">复制 SVG</button>`,
`<button class="svg-action-btn svg-png-btn" type="button">复制为 PNG</button>`,
`</div>`
].join('')
output.push(`<div class="svg-inline-render">${actionsHtml}${singleLine}</div>`)
i++
break
}
svgLines.push(lines[i])
i++
}
if (!closed) {
// 未闭合的围栏 — 保持原样(流式安全)
output.push(openLine)
output.push(...svgLines)
}
} else {
output.push(lines[i])
i++
}
}
return output.join('\n')
}