SVG文字交互区域的制作注意:html object in SVG
文章目录[隐藏]
SVG文字交互区域的制作注意
在很多情况下,我们使用d3(或者其他SVG类库)创建交互式图表时,都需要将html元素插入到SVG元素上。典型的例子,就是图表中有需要交互式修改文字的地方,当用户点击了某个svg text元素,这里我们需要将一个html元素 input“放进”SVG元素中,并在这个input元素上绑定事件,从而快速更改文字。而svg本身元素类型是提供不了类似的功能的,所以用到html元素是必须的。
SVG元素主要有如下几类:svg(定义svg文档片段), rect(定义矩形), circle(定义圆形),ellipse(定义椭圆),path(路径),line(线),ploygon(多边形),text(文字),title(标题), desc(描述), g(群组), defs(参考元素), image(图片元素)。详见:http://www.w3school.com.cn/svg/svg_reference.asp
但是,直接将html元素插入SVG元素内是不可以显示的。
如下例,使用d3js设置text元素是可以显示的,但是如果把插入的元素改为div,则div元素虽然可以创建,但是不可见。
node.append("text") .attr("dx", 16) .attr("dy", ".0em") .text(function(d) { return d.name });
html object in SVG
这是使用SVG绘图时经常遇到的问题。有两个解决办法:
1.将div使用SVG元素foreignObject包裹。
这个办法的好处是,通过foreignObject,可以将div元素嵌入SVG片段来处理。详见:http://ajaxian.com/archives/foreignobject-hey-youve-got-html-in-my-svg.
但是此方法不兼容IE任何版本,详见https://developer.mozilla.org/zh-CN/docs/Web/SVG/Element/foreignObject
2.将div定义为浮动层,然后使用left, top属性,等计算位置。
用这种方法制作文字提示框,就像这样:
d3.select("#nytg-tooltip").style('top',ypos+"px").style('left',xpos+"px").style('display','block');
这个方法比起第一种,在位置计算上复杂度是一样的。并且浮动的div更容易控制。具体而言这有一个案例:
http://www.nytimes.com/interactive/2012/10/15/us/politics/swing-history.html?_r=0
结论:
对于要进行交互操作的文字区域,通常要借助html元素的力量来实现效果。将html元素加入SVG有两种方法,其一是将div使用SVG元素foreignObject包裹,其二是将div定义为浮动层,然后使用left, top属性,等计算位置。
这里还要特别提到一个案例:在线思维导图软件mindmo也是这样处理文字区域的交互问题的。它将所有的节点文字区域都用浮动的div显示,使用top,left属性来控制其位置;而svg只用于路径显示。例如:https://www.mindomo.com/mindmap/cd8215d5e5b1427c9c22b4abc6aae5d6
[good]
我用foreignObject嵌入html,再在html使用svg元素text(),这样符合规范吗?为什么text()的元素属性不显示。还有好像google可以显示,其他浏览器都不能显示?这个应该是支持火狐浏览器的吧!
var htmlDOMs = foreignObjects.append("xhtml:body")
.attr("width",function(d){
var arcLength = (radius - innerRadius) * (d.data.score / 100.0);
return arcLength+"px";
})//设计新加的html的高度和宽度,宽度是弧长的长度
.attr("height","14px")
.style("margin",0)
.style("padding",0)
.attr("requiredFeatures","http://www.w3.org/1999/xhtml");
//body里添加div ,text
var htmldivs = htmlDOMs.append("xhtml:div")
.attr("class","textlabel")
.style("color","black")
.style("text-align", function(d){
return d.endAngle > Math.PI ? "right" : "left" ;//文本居于div的右边还是左边
})
.append("text")//添加text
.on('mouseover', tip.show)
.on('mouseout', tip.hide)//让鼠标移动到文本时也出现tip
.text(function(d){return d.data.label;})
.style("text-anchor",function(d){
return d.endAngle > Math.PI ? "end" : "start" ;
});
//text-anchor属性不支持,不显示。
——————章梦依记
第一,你这个顺序反了,foreignObject是SVG的元素,其功能是在SVG中载入html元素,而不是在html元素中载入SVG。
第二,为了浏览器兼容性,我建议还是用“在SVG元素上覆盖html浮动层”的方式来处理这种问题。因为至今IE edge还不支持foreignObject,google chrome偶尔也会出问题。只有火狐是完全支持foreignObject的。
谢谢您的回复。我明白foreignobject作用是在svg元素中嵌入html。我的意思是先用这个元素在svg嵌入html,再在html中添加svg的元素text()可以吗?
这个我没试过,因为foreignObject兼容性太差我早早就放弃使用它了。你可以试试。