在SVG中创建表格

30

我正在尝试在SVG文档中创建类似表格的对象。目前,由于SVG没有表格元素,我正在使用HTML解析器来遍历并将用户在HTML表格构建器中创建的HTML表转换为一组SVG对象,然后将其添加到我的整个SVG绘图中。我想知道是否有更好的替代方法,例如SVG表格构建器?我希望使用Javascript或jquery实现这一点。如果您有任何想法或建议,将不胜感激。

7个回答

34

我会在SVG中嵌入一个真实的表格:

<?xml version="1.0" standalone="yes"?>
<svg xmlns="http://www.w3.org/2000/svg">
  <foreignObject x="10" y="10" width="100" height="150">
    <body xmlns="http://www.w3.org/1999/xhtml">
      <table><!-- ... --></table>
    </body>
  </foreignObject>
  <!-- ... -->
</svg>

这其实是一个非常好的想法。但是,我的问题在于我不能使用foreignobject元素。很难解释,但是我已经创建了一个自定义的SVG画布对象,我需要使用SVG而不是HTML(或XHTML)来呈现表格。此外,在使用SVG图像时会引起问题吗?如果我在HTML中定义表格,它不会正确缩放,因为它不是矢量格式。 - RestingRobot
1
另一种方法是在普通表格上叠加一个 SVG 元素,例如,如果您只想在单元格之间绘制箭头。这样,您可以将 SVG 与表格结合起来,而不必使用 foreignobject。但原始问题仍然很好,我的用例是将一个表格带入 Inkscape 以用于更大的图表中。 - drewp
2
Chrome对ForeignObject的支持非常不稳定,这真是太遗憾了。因此,我不得不使用本地SVG元素来实现许多事情。首先,存在一些渲染错误。如果您拖动一个ForeignObject,它会留下阴影,这些阴影在页面滚动后会消失,但会分散注意力。在Chrome中,SVG变换不适用于ForeignObject元素,但在Firefox中并非如此。 - arunkjn
1
不支持任何IE版本的外部对象。最近遇到了同样的问题。考虑使用group(g),text和tspan作为替代方案。 - Dayne Mentier
3
"foreignobject" 应该改为 "foreignObject"。 - shaneparsons
2
@Shane 谢谢。我很惊讶这个错误的大小写在这个答案中存在了将近5年。 :) - Phrogz

27

您可以使用以下方法:

SVG中没有“表”类型的元素,但是您可以使用“text”和“tspan”元素实现类似的视觉和交互效果。左侧是2个这样的表格表示,上面一个是列布局(即用户可以选择列中的所有文本),底部表格是基于行的布局。显然,这种方法的一个缺点是您无法创建既具有垂直又具有水平可选性的表格。不明显的缺陷是创建表格外观并不能赋予真正表格的语义特性,这对于可访问性是不利的,并且不利于丰富的交互和导航。

示例:

<?xml version='1.0' standalone='no'?>
<!DOCTYPE svg PUBLIC '-//W3C//DTD SVG 1.1//EN'
  'http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd'>
<svg width='100%' height='100%' xmlns='http://www.w3.org/2000/svg' xmlns:xlink='http://www.w3.org/1999/xlink'>

   <title>SVG Table</title>

   <g id='columnGroup'>
      <rect x='65' y='10' width='75' height='110' fill='gainsboro'/>
      <rect x='265' y='10' width='75' height='110' fill='gainsboro'/>

      <text x='30' y='30' font-size='18px' font-weight='bold' fill='crimson'>
         <tspan x='30' dy='1.5em'>Q1</tspan>
         <tspan x='30' dy='1em'>Q2</tspan>
         <tspan x='30' dy='1em'>Q3</tspan>
         <tspan x='30' dy='1em'>Q4</tspan>
      </text>

      <text x='100' y='30' font-size='18px' text-anchor='middle'>
         <tspan x='100' font-weight='bold' fill='crimson'>Sales</tspan>
         <tspan x='100' dy='1.5em'>$ 223</tspan>
         <tspan x='100' dy='1em'>$ 183</tspan>
         <tspan x='100' dy='1em'>$ 277</tspan>
         <tspan x='100' dy='1em'>$ 402</tspan>
      </text>

      <text x='200' y='30' font-size='18px' text-anchor='middle'>
         <tspan x='200' font-weight='bold' fill='crimson'>Expenses</tspan>
         <tspan x='200' dy='1.5em'>$ 195</tspan>
         <tspan x='200' dy='1em'>$ 70</tspan>
         <tspan x='200' dy='1em'>$ 88</tspan>
         <tspan x='200' dy='1em'>$ 133</tspan>
      </text>

      <text x='300' y='30' font-size='18px' text-anchor='middle'>
         <tspan x='300' font-weight='bold' fill='crimson'>Net</tspan>
         <tspan x='300' dy='1.5em'>$ 28</tspan>
         <tspan x='300' dy='1em'>$ 113</tspan>
         <tspan x='300' dy='1em'>$ 189</tspan>
         <tspan x='300' dy='1em'>$ 269</tspan>
      </text>
   </g>
</svg>

来源: http://svg-whiz.com/svg/table.svg


1
我很惊讶没有人编写JavaScript/D3插件,使用svg.g对象生成表格? - John Zabroski
1
一个SVG表格和一个普通HTML中的<table>之间的主要区别是,这个SVG表格是基于列的,而HTML表格是基于行的。 - Nate Anderson
2
@TheRedPea:在链接的页面上,您还可以看到一种面向行的变体。 - bodo
1
Mozilla在https://developer.mozilla.org/en-US/docs/Web/SVG/Element/tspan上提供了tspan元素的良好参考。 - Paulo Bueno

6

我有类似的需求,但找不到一个合适的工具来自动生成SVG图像以显示表格数据(通过Google能找到的工具产生了难以辨认或无法使用的结果),所以我自己构建了一个。如果您或其他人在搜索此类工具时找到本页面,可能会发现这个工具有用:

https://topherrhodes.com/svg-table/

这个工具使用CSV作为输入,因此如果您需要从HTML表格转换,可以修改脚本将表格转换为JavaScript对象或生成CSV作为中间步骤。
一般来说,我同意其他用户提出的SVG不是显示表格数据的好格式,并且为了可用性和兼容性,您应该尽可能使用实际的HTML表格。但是在某些情况下可能无法使用HTML表格。

2

我想就这个问题提出我的看法以供后人参考。虽然有很多相当复杂的选项,但如果你只是想要一个看起来像表格的东西,那么这个可能会让你开始...

//assuming you have a table with an ID of src_table
var my_svg = '<svg xmlns:svg="http://www.w3.org/2000/svg" xmlns="http://www.w3.org/2000/svg" id="svg_table" width="'+$("#src_table").width()+'px" height="'+$("#src_table").height()+'px">'
var table_offset = $('#src_table').offset();
$('#src_table').find('td').each(function() {
        //Add a rectangle for each <td> in the same place in SVG as the <td> is in relation to the top left of where the table is on page
        my_svg += '<rect x="'+(this_offset.left - table_offset.left)+'" y="'+(this_offset.top - table_offset.top)+'" width="'+$(this).width()+'" height="'+$(this).height()+'" stroke="black" stroke-width="'+$(this).css('border-width').replace('px','')+'"/>';

       //Text is assumed to be in a <p> tag. If it's not, just use the .html() of the <td> element
       (this).children('p').each(function(){
                t_offset = $(this).offset();
                var this_text = '<text x="'+(t_offset.left - table_offset.left)+'" y="'+(t_offset.top - table_offset.top)+'"  style="font-size:'+$(this).css('font-size')+'; fill: #ffffff">';
                    // Look for <br> tags and split them onto new lines.
                    var this_lines = $(this).html().split('<br>');
                    for(var i=0;i<this_lines.length;i++){
                        this_text += '<tspan x="'+(t_offset.left - table_offset.left)+'" dy="'+$(this).css('font-size')+'">'+this_lines[i]+'</tspan>';
                    }
            this_text += '</text>';
            my_svg +=  this_text;
        })
    }
});
my_svg += '</svg>';

//Either append my_svg to a div or pass the code onto whatever else you need to do with it.

这显然很粗糙,但可能会让你朝着正确的方向开始。

1
我在Github上找到了一个项目,它可以从JavaScript数据结构自动生成类似HTML的表格:https://github.com/cocuh/SVG-Table 由于它不依赖于foreignObject,所以在各种浏览器中的可移植性更好。

1
从 README 中的引用:已弃用:强烈建议不要使用此库 - ceving
那个已经被弃用了,于2019年9月7日。感谢您提醒大家,我会考虑如何更新答案,但由于最近Stackoverflow的领导层变化,我在这里的贡献欲望降低了许多。 - John Zabroski

0

死灵术。
问题是,当你需要一个可以有无限行和列的表格,行高未知且可变,以及在编译时未知的文本,需要调整大小以适应容器,并且既不被裁剪也不溢出。

幸运的是,我找到了解决方案!
尽管需要使用JavaScript在运行时设置viewBox。
适用于Firefox和Chrome。

<?xml version="1.0" standalone="yes"?>
<html>
    <head>
        <title>Evacuation Plan</title>
        
        <style type="text/css">
        /*<![CDATA[*/
            
            .A4 
            { 
                width: 21cm; 
                height: 29.7cm;
            } 
            
        /*]]>*/
        </style>
        
    </head>
    <body class="A4">
        <div id="positionRoot" style="position: relative;">
        
        <div id="sizerForTable" style="position: absolute; display: block; top: 2.5cm; left: 5cm; width: 2.5cm; height: 2.5cm; background-color: hotpink;">
            <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 0 0" preserveAspectRatio="xMinYMin meet" width="100%" height="100%" >
              
              <rect id="rectBG" x="0" y="0" width="0" height="0" fill="#FF0000" />
              <foreignObject id="foTableContainer" x="0" y="0" width="100%" height="100%">
                <body xmlns="http://www.w3.org/1999/xhtml">
                  
                  <!--
                  <style type="text/css">
                  /*<![CDATA[*/
                        
                        .testTableLayout 
                        { 
                            font-size: 5px; 
                            line-height: 1em; 
                        } 
                        
                  /*]]>*/
                  </style>
                  -->
                  
                  <!-- also: Tabelle ausmessen - dies in Viewbox - dann verkleiners sich automatisch -->
                  
                  <table id="tblTest" class="testTableLayout" style="border-collapse: collapse; border: none;" cellpadding="0" cellspacing="0">
                    <tr style="background-color: orange;">
                        <td>Row1</td>
                        <td>C1.2</td>
                        <td>Test<br />Me<br />More</td>
                    </tr>
                    <tr>
                        <td>Row2</td>
                        <td>C2.2</td>
                        <td>Test<!--&nbsp;Me&nbsp;More--></td>
                    </tr>
                    <tr>
                        <td>Row3</td>
                        <td>C3.2</td>
                        <td>Test</td>
                    </tr>
                    
                    <tr>
                        <td>Row4</td>
                        <td>C4.2</td>
                        <td>Test</td>
                    </tr>
                    <tr>
                        <td>Row5</td>
                        <td>C5.2</td>
                        <td>Test</td>
                    </tr>
                    <!--
                    -->
                    
                  </table>
                  
                  <script type="text/javascript">
                    //<![CDATA[
                    
                    (function () {
                        
                        var tbl = document.getElementById("tblTest"); 
                        var bg = document.getElementById("rectBG"); 
                        var nvb = ["0", "0", Math.ceil(tbl.offsetWidth).toString(), Math.ceil(tbl.offsetHeight).toString()]; 
                        
                        bg.setAttribute("width", nvb[2]); 
                        bg.setAttribute("height", nvb[3]); 
                        document.getElementById("foTableContainer").ownerSVGElement.setAttribute("viewBox", nvb.join(" ") ); 
                        
                        // console.log("newViewBox:", nvb); 
                        // console.log("w,h:", tbl.offsetWidth, tbl.offsetHeight); 
                        // console.log(document.getElementById("foTableContainer").ownerSVGElement.getAttribute("viewBox")); 
                    })();
                    
                    //]]>
                  </script>
                  
                </body>
              </foreignObject>
            </svg>
        </div>
        </div>
    </body>
</html>

0
这里有一个示例,展示了一个包含嵌套的SVG元素表格布局的SVG foreignobject。但它只在Chrome中有效。
它包括使用div元素的HTML table布局和flexbox布局。
jsfiddle在这里
<body>
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
    <defs>
        <g id="shape">
            <rect x="0" y="0" rx="5" ry="5" width="100%" height="100%" fill="inherit" />
            <circle cx="50%" cy="50%" r="8" fill="yellow" />
        </g>
    </defs>
    <foreignobject width="100%" height="50px" y="0">

        <body xmlns="http://www.w3.org/1999/xhtml">
            <table width="100%">
                <tr>
                    <td colspan="3">
                        <div style="height:20px">
                            <svg>
                                <use xlink:href="#shape" fill="CornflowerBlue" />
                            </svg>
                        </div>
                    </td>
                </tr>
                <tr>
                    <td>
                        <div style="height:20px">
                            <svg>
                                <use xlink:href="#shape" fill="SlateBlue" />
                            </svg>
                        </div>
                    </td>
                    <td>
                        <div style="height:20px">
                            <svg>
                                <use xlink:href="#shape" fill="SlateBlue" />
                            </svg>
                        </div>
                    </td>
                    <td>
                        <div style="height:20px">
                            <svg>
                                <use xlink:href="#shape" fill="SlateBlue" />
                            </svg>
                        </div>
                    </td>
                </tr>
            </table>
        </body>
    </foreignobject>
    <foreignobject width="100%" height="50px" y="60">

        <body xmlns="http://www.w3.org/1999/xhtml">
            <div style="display:flex;flex-direction:column">
                <div>
                    <div style="height:20px;padding:2px">
                        <svg>
                            <use xlink:href="#shape" fill="orange" />
                        </svg>
                    </div>
                </div>
                <div style="display:flex;flex-direction:row;align-items:stretch">
                    <div style="width:33.333%;height:20px;padding:2px">
                        <svg>
                            <use xlink:href="#shape" fill="forestgreen" />
                        </svg>
                    </div>
                    <div style="width:33.333%;height:20px;padding:2px">
                        <svg>
                            <use xlink:href="#shape" fill="forestgreen" />
                        </svg>
                    </div>
                    <div style="width:33.333%;height:20px;padding:2px">
                        <svg>
                            <use xlink:href="#shape" fill="forestgreen" />
                        </svg>
                    </div>
                </div>
            </div>
        </body>
    </foreignobject>
</svg>


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接