我这里有一个简单的饼图:
https://jsfiddle.net/5dexn2kn/1/
我尝试将图像附加到每个标签组
https://jsfiddle.net/5dexn2kn/2/
正如您所看到的,因为text-anchor
可能是start
或end
,每个标签的文字长度也不同,我不知道如何查找和放置图像到正确的位置。
我怎样才能做到这一点?
答案 0 :(得分:1)
也许这会有所帮助:https://jsfiddle.net/5dexn2kn/3/
给文字一个id:
labelG.append('text')
.attr('id', function(d) {
return d.data.label + '_text'
})
这必须是独一无二的。在这种情况下它可以工作,但如果你有时候有相同的标签,它就不会。
然后获取相应标签文本的宽度,如下所示:
var thisText = document.getElementById(d.data.label + '_text') //select based on data, as id above is given from data
var thisTextWidth = thisText.clientWidth;
然后使用相同的逻辑来确定您是希望文本锚点start
还是end
来确定图像的位置:
if ((d.endAngle + d.startAngle) / 2 > Math.PI) {
return -35 - thisTextWidth;
} else {
return -25;
}
答案 1 :(得分:1)
您可以使用getBoundingBox()
功能来实现此目的。
<强>代码强>:
labelG.append('image')
.attr('xlink:href', 'https://placekitten.com/20/20?.jpg')
.attr('height', 20)
.attr('width', 20)
.attr("x", function(d) {
var bbox = this.parentNode.getBBox();
return bbox.x;
})
.attr("y", function() {
var bbox = this.parentNode.getBBox();
return bbox.y;
});
labelG.selectAll("text").attr("dx", 25);
完整代码段:
const width = 400
const height = 400
const labelSpace = 50
const donutRadius = Math.min(width, height) / 2
const maxRadius = donutRadius + labelSpace
const colorScheme = d3.scaleOrdinal(d3.schemeCategory20)
const innerRadius = 20
const svgTranslate = [width / 2 + labelSpace * 2, height / 2 + labelSpace * 2]
function getPercent(value, total) {
return Math.round(value / total * 100)
}
const data = [{
label: 'aaaaaaa',
value: 19
}, {
label: 'bbb',
value: 31
}, {
label: 'c',
value: 31
}, {
label: 'ddddddddddd',
value: 8
}, {
label: 'eeee',
value: 10
}]
const total = data.map(d => d.value).reduce((a, b) => a + b)
const svg = d3.select('#donutchart')
.append('svg')
.attr('width', width + maxRadius)
.attr('height', height + maxRadius)
.append('g')
.attr('transform', `translate(${svgTranslate[0]}, ${svgTranslate[1]})`)
const arc = d3.arc()
.innerRadius(innerRadius)
.outerRadius(donutRadius)
const donut = d3.pie()
.sort(null)
.value(d => d.value)
const arcG = svg.selectAll('g.arc-g')
.data(donut(data))
.enter()
.append('g')
arcG.append('path')
.attr('d', arc)
.attr('fill', d => colorScheme(d.data.label))
const labelG = arcG.append('g')
.attr('transform', d => {
const c = arc.centroid(d)
const x = c[0] * 2
const y = c[1] * 2
return `translate(${x}, ${y})`
})
labelG.append('text')
.attr('dy', '.35em')
.html(d =>
`${d.data.label}<tspan class="label-percent"> ${getPercent(d.data.value, total)}%</tspan>`
)
.attr('text-anchor', d =>
(d.endAngle + d.startAngle) / 2 > Math.PI ? 'end' : 'start'
)
labelG.append('image')
.attr('xlink:href', 'https://placekitten.com/20/20?.jpg')
.attr('height', 20)
.attr('width', 20)
.attr("x", function(d) {
var bbox = this.parentNode.getBBox();
return bbox.x;
})
.attr("y", function() {
var bbox = this.parentNode.getBBox();
return bbox.y;
});
labelG.selectAll("text").attr("dx", 25);
body {
font-family: San Francisco Display, sans-serif;
}
.label-percent {
font-weight: bold;
}
<div id="donutchart"></div>
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/4.3.0/d3.min.js"></script>