我正在尝试在http://bl.ocks.org/mbostock/3887235处跟随d3的饼图示例。
我的代码的最小样本:
const container = $('#graph-pie');
const width = container.width() * 0.5;
const height = 256;
const radius = Math.min(width, height) / 2;
const color = d3.scaleOrdinal()
.range(['#869099', '#8c7853', '#007d4a']);
const arc = d3.arc()
.outerRadius(radius - 10)
.innerRadius(0);
const labelArc = d3.arc()
.outerRadius(radius - 40)
.innerRadius(radius - 40);
const pie = d3.pie()
.sort(null)
.value((d) => { return d.value });
const svg = d3.select('#graph-pie').append('svg')
.attr('width', width)
.attr('height', height)
.append('g')
.attr('transform', 'translate(' + width/2 + ',' + height/2 + ')');
const g = svg.selectAll('.arc')
.data(pie(totals))
.enter()
.append('g')
.attr('class', 'arc');
g.append('path')
.attr('d', arc)
.style('fill', (d) => { return color(d.data.name) });
g.append('text')
.attr('transform', (d) => { return 'translate(' + labelArc.centroid(d) + ')' })
.attr('dy', '.35em')
.text((d) => {
return names[d.data.name];
});
问题在于,有时标签的文本会隐藏在饼图片后面。我注意到这种情况主要发生在Chrome上,但我不知道它在其他浏览器中没有发生。几个例子:
如果有帮助,输出的SVG代码如下:
<div id="graph-pie" class="graph pie">
<svg width="668" height="256">
<g transform="translate(334,128)">
<g class="arc">
<path d="M7.225416114969383e-15,-118A118,118,0,0,1,98.56840842206363,-64.87117126383073L0,0Z" style="fill: rgb(134, 144, 153); z-index: 10;">
<text transform="translate(41.753394753534344,-77.46388853237056)" dy=".35em">Sensitive</text>
</g>
<g class="arc">
<path d="M98.56840842206363,-64.87117126383073A118,118,0,0,1,-27.95807360901471,114.64007205193529L0,0Z" style="fill: rgb(140, 120, 83);">
<text transform="translate(71.92851960216296,50.69800851947991)" dy=".35em">Somewhat Sensitive</text>
</g>
<g class="arc">
<path d="M-27.95807360901471,114.64007205193529A118,118,0,0,1,-2.167624834490815e-14,-118L0,0Z" style="fill: rgb(0, 125, 74);">
<text transform="translate(-87.37132713286675,-10.500056906587716)" dy=".35em">Tolerant</text>
</g>
</g>
</svg>
</div>
我已经尝试过使用z-index CSS样式,但它没有任何效果,并且它看起来不像SVG元素具有任何类似的属性。如何强制我的文本元素在我的路径上呈现?
答案 0 :(得分:0)
某些路径涵盖了文本,因为在您的代码中,每个g
(组)都有一个路径元素和一个文本元素。因此,在给定组之后的组内路径(以SVG顺序,&#34;在它上面#34;)将在该特定文本之后呈现,覆盖它。 &#34;绘图顺序&#34;在这篇文章的底部描述了SVG。
因此,您需要做的是在渲染所有路径后渲染文本。有几种方法可以做到这一点,但最简单的方法(肯定不是最优雅的方法)是为文本创建另一组。
例如,这是您现在的代码。你可以看到一些文章被一些片段覆盖:
const width = 400
const height = 400;
const radius = Math.min(width, height) / 2.5;
const totals = [{"name":"Category A long label", "value":20},
{"name":"Category B long label", "value":50},
{"name":"Category C long label", "value":30},
{"name":"Category D long label", "value":20},
{"name":"Category E long label", "value":50},
{"name":"Category F long label", "value":30}];
const color = d3.scaleOrdinal()
.range(['#869099', '#8c7853', '#007d4a']);
const arc = d3.arc()
.outerRadius(radius - 10)
.innerRadius(0);
const labelArc = d3.arc()
.outerRadius(radius - 40)
.innerRadius(radius - 40);
const pie = d3.pie()
.sort(null)
.value((d) => { return d.value });
const svg = d3.select('#graph-pie').append('svg')
.attr('width', width)
.attr('height', height)
.append('g')
.attr('transform', 'translate(' + width/2 + ',' + height/2 + ')');
const g = svg.selectAll('.arc')
.data(pie(totals))
.enter()
.append('g')
.attr('class', 'arc');
g.append('path')
.attr('d', arc)
.style('fill', (d) => { return color(d.data.name) });
g.append('text')
.attr("text-anchor", "middle")
.attr('transform', (d) => { return 'translate(' + labelArc.centroid(d) + ')' })
.attr('dy', '.35em')
.text((d) => {
return d.data.name;
});
&#13;
<script src="https://d3js.org/d3.v4.min.js"></script>
<div id="graph-pie"></div>
&#13;
这是相同的代码,但是对于文本有不同的组,在路径之后呈现:
const width = 400
const height = 400;
const radius = Math.min(width, height) / 2.5;
const totals = [{"name":"Category A long label", "value":20},
{"name":"Category B long label", "value":50},
{"name":"Category C long label", "value":30},
{"name":"Category D long label", "value":20},
{"name":"Category E long label", "value":50},
{"name":"Category F long label", "value":30}];
const color = d3.scaleOrdinal()
.range(['#869099', '#8c7853', '#007d4a']);
const arc = d3.arc()
.outerRadius(radius - 10)
.innerRadius(0);
const labelArc = d3.arc()
.outerRadius(radius - 40)
.innerRadius(radius - 40);
const pie = d3.pie()
.sort(null)
.value((d) => { return d.value });
const svg = d3.select('#graph-pie').append('svg')
.attr('width', width)
.attr('height', height)
.append('g')
.attr('transform', 'translate(' + width/2 + ',' + height/2 + ')');
const g = svg.selectAll('.arc')
.data(pie(totals))
.enter()
.append('g')
.attr('class', 'arc');
const g2 = svg.selectAll('.arc2')
.data(pie(totals))
.enter()
.append('g')
.attr('class', 'arc');
g.append('path')
.attr('d', arc)
.style('fill', (d) => { return color(d.data.name) });
g2.append('text')
.attr("text-anchor", "middle")
.attr('transform', (d) => { return 'translate(' + labelArc.centroid(d) + ')' })
.attr('dy', '.35em')
.text((d) => {
return d.data.name;
});
&#13;
<script src="https://d3js.org/d3.v4.min.js"></script>
<div id="graph-pie"></div>
&#13;
你可以看到,现在,没有任何文字被覆盖。
这很有效,但正如我所说,它并不是最优雅的方法,因为如果你检查SVG,你会看到一堆具有单一元素的群体(这没有任何意义) 。另一种方法是独立创建路径和文本,这需要稍微修改一下代码。
SVG:绘图顺序
这可能令人沮丧:您使用D3.js进行可视化,但您想要在顶部的矩形隐藏在另一个矩形后面,或者您计划在某个圆圈后面的线实际上是在它上面。您尝试使用CSS中的 z-index 解决此问题,但它不起作用(在SVG 1.1中)。
解释很简单:在SVG中,元素的顺序定义了&#34;绘画&#34;的顺序,绘画的顺序定义了谁是最重要的。
SVG文档片段中的元素具有隐式绘制顺序,SVG文档片段中的第一个元素得到&#34;绘制&#34;第一。后续元素绘制在先前绘制的元素之上。
所以,假设我们有这个SVG:
<svg width="400" height=200>
<circle cy="100" cx="80" r="60" fill="blue"></circle>
<circle cy="100" cx="160" r="60" fill="yellow"></circle>
<circle cy="100" cx="240" r="60" fill="red"></circle>
<circle cy="100" cx="320" r="60" fill="green" z-index="-1"></circle>
</svg>
他有四个圆圈。蓝圈是第一个&#34;画&#34;,所以它将落后于其他所有。然后我们有黄色的那个,然后是红色的,最后是绿色的。绿色的是最后一个,它将位于顶部。
它的外观如下:
使用D3更改SVG元素的顺序
那么,是否可以改变元素的顺序?我可以在绿色圆圈前面制作红色圆圈吗?
是。您需要考虑的第一种方法是代码中的行的顺序:首先绘制背景元素,然后在代码中绘制前景元素。
但是我们可以动态地改变元素的顺序,即使它们被绘制后也是如此。您可以编写几个简单的JavaScript函数来执行此操作,但D3已经有2个不错的功能,selection.raise()
和selection.lower()
。
根据API:
selection.raise():按顺序重新插入每个选定元素作为其父元素的最后一个子元素。 selection.lower():按顺序重新插入每个选定元素作为其父元素的第一个子元素。
因此,为了展示如何操纵我们之前SVG中元素的顺序,这里有一个非常小的代码:
d3.selectAll("circle").on("mouseover", function(){
d3.select(this).raise();
});
它做什么?它选择所有圆圈,当用户将鼠标悬停在一个圆圈上时,它会选择该特定圆圈并将其带到前面。很简单!
here is the JSFiddle和实时代码。