You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在XSLT文件中使用GetBbox()实现SVG绘图文本框居中

问题描述

我有以下XSLT代码(感谢Martin Honnen提供)和SVG文件,想要让生成的文本块居中显示在对应的多边形图形上方。需要为<text x="" y="" id="{$id}-text">和<tspan id="{$id}-tspan" x="" y="">动态计算x、y坐标——因为每个图形的位置都不固定。

我知道需要借助JavaScript,且整体流程要通过调用getBBox()方法的VBA宏触发,但不清楚怎么在XSLT中结合这个方法,也不确定合适的JS代码怎么写。逻辑上x坐标应该是父组的bbox中心x值,y坐标同理,但不知道怎么通过@id关联对应的图形和文本。

现有XSLT代码

<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
    xmlns:svg="http://www.w3.org/2000/svg"
    xmlns="http://www.w3.org/2000/svg"
    exclude-result-prefixes="svg"
    version="1.0">
  
  <xsl:strip-space elements="*"/>
  
  <xsl:template match="svg:g[@id[starts-with(., 'Item')]]">
    <xsl:copy>
      <xsl:apply-templates select="@* | node()"/>
      <xsl:variable name="id" select="substring-before(@id, '-')"/>
      <text x="" y="" id="{$id}-text">
        <tspan id="{$id}-tspan" x="" y="">
          <xsl:value-of select="$id"/>
        </tspan>
      </text>
    </xsl:copy>
  </xsl:template>

  <xsl:template match="@* | node()">
    <xsl:copy>
      <xsl:apply-templates select="@* | node()"/>
    </xsl:copy>
  </xsl:template>
</xsl:stylesheet>

待转换的SVG文件

<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" id="exportSvg" width="400" height="400">
    <defs/>
    <rect width="400" height="400" transform="translate(0, 0)" fill="rgb(255, 255, 255)" style="fill:rgb(255, 255, 255);"/>
    <g>
        <g id="Drawing-svg" clip-path="url(#rect-mask-Drawing)">
            <clipPath id="rect-mask-Drawing">
                <rect x="0" y="0" width="400" height="400"/>
            </clipPath>
            <g id="chart-svg">
                <g id="svg-main" clip-path="url(#rect-mask-Main)">
                    <clipPath id="rect-mask-Main">
                        <rect x="0" y="0" width="400" height="400"/>
                    </clipPath>
                    <g id="Drawing-svg">
                        <g id="Parts-svg">
                            <g id="Section-svg">
                                <g id="Item1-svg">
                                    <path d="M 155.09357,45.542471 104.77897,86.931934 75,200 152.79121,141.87343 200,84.246354 Z" stroke="#e6e6e6" style="fill:#e6e6e6;stroke-width:0.3;stroke-linecap:round;stroke-linejoin:round" id="Item1"/>
                                </g>
                                <g id="Item2-svg">
                                    <path d="M 198.06872,89.614437 -9.21291,31.643703 -23.42303,34.67823 51.52002,20.68699 47.20879,-57.62707 z" stroke="#e6e6e6" style="fill:#e6e6e6;stroke-width:0.3;stroke-linecap:round;stroke-linejoin:round" id="Item2"/>
                                </g>
                                <g id="Item3-svg">
                                    <path d="M 161.0455,182.56778 -41.68122,-5.64443 15.98375,27.05111 67.62172,3.73783 32.80201,-13.55927 z" stroke="#e6e6e6" style="fill:#e6e6e6;stroke-width:0.3;stroke-linecap:round;stroke-linejoin:round" id="Item3"/>
                                </g>
                            </g>
                        </g>
                    </g>
                </g>
            </g>
        </g>
    </g>
</svg>
解决方案

1. 调整XSLT

XSLT仅能完成静态元素生成,无法获取SVG渲染时的边界框属性,所以先修改XSLT,给文本元素添加标识属性并设置初始坐标,同时加入文本居中的样式属性,简化后续JS计算:

<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
    xmlns:svg="http://www.w3.org/2000/svg"
    xmlns="http://www.w3.org/2000/svg"
    exclude-result-prefixes="svg"
    version="1.0">
  
  <xsl:strip-space elements="*"/>
  
  <xsl:template match="svg:g[@id[starts-with(., 'Item')]]">
    <xsl:copy>
      <xsl:apply-templates select="@* | node()"/>
      <xsl:variable name="id" select="substring-before(@id, '-')"/>
      <!-- 添加class便于JS选择,设置文本居中属性 -->
      <text x="0" y="0" id="{$id}-text" class="item-label" text-anchor="middle" dominant-baseline="middle">
        <tspan id="{$id}-tspan">
          <xsl:value-of select="$id"/>
        </tspan>
      </text>
    </xsl:copy>
  </xsl:template>

  <xsl:template match="@* | node()">
    <xsl:copy>
      <xsl:apply-templates select="@* | node()"/>
    </xsl:copy>
  </xsl:template>
</xsl:stylesheet>

2. 编写JavaScript代码

通过JS遍历所有Item组,借助getBBox()获取图形边界框,计算中心坐标后绑定到对应文本元素:

function centerItemLabels() {
  // 筛选所有Item开头的分组
  const itemGroups = document.querySelectorAll('g[id^="Item"]');
  
  itemGroups.forEach(group => {
    const itemId = group.id.split('-')[0];
    // 获取当前组对应的图形路径
    const path = group.querySelector(`#${itemId}`);
    if (!path) return;
    
    // 获取路径的边界框
    const bbox = path.getBBox();
    // 计算边界框中心坐标
    const centerX = bbox.x + bbox.width / 2;
    const centerY = bbox.y + bbox.height / 2;
    
    // 绑定坐标到文本元素
    const text = document.getElementById(`${itemId}-text`);
    if (text) {
      text.setAttribute('x', centerX);
      text.setAttribute('y', centerY);
      // tspan继承text坐标,若需换行可单独调整
      const tspan = document.getElementById(`${itemId}-tspan`);
      if (tspan) {
        tspan.setAttribute('x', centerX);
        tspan.setAttribute('y', centerY);
      }
    }
  });
}

// SVG加载完成后自动执行
window.addEventListener('load', centerItemLabels);

3. VBA宏执行逻辑

在VBA中通过WebBrowser控件加载转换后的SVG,执行JS脚本并保存修改后的文件:

Sub CenterSVGLabels()
    Dim svgPath As String
    Dim objBrowser As Object
    
    svgPath = "C:\你的SVG文件路径\transformed.svg" ' 替换为实际路径
    Set objBrowser = CreateObject("InternetExplorer.Application")
    objBrowser.Visible = False
    
    ' 加载SVG文件
    objBrowser.Navigate "file:///" & Replace(svgPath, "\", "/")
    ' 等待加载完成
    Do While objBrowser.Busy Or objBrowser.ReadyState <> 4
        DoEvents
    Loop
    
    ' 执行居中脚本
    objBrowser.Document.parentWindow.execScript "centerItemLabels();"
    
    ' 保存修改后的SVG
    Dim modifiedSVG As String
    modifiedSVG = objBrowser.Document.DocumentElement.outerHTML
    Open "C:\输出路径\centered.svg" For Output As #1
    Print #1, modifiedSVG
    Close #1
    
    objBrowser.Quit
    Set objBrowser = Nothing
End Sub

关键说明

  • XSLT负责静态生成文本元素,无法获取渲染时的边界框,必须依赖JS在SVG加载后计算坐标。
  • getBBox()返回元素局部坐标系下的边界框,无需额外处理父元素变换,直接计算中心即可。
  • text-anchor和dominant-baseline属性确保文本以设置的x/y为中心对齐,无需额外偏移调整。

内容的提问来源于stack exchange,提问作者Oran G. Utan

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.15 11:30:45