NVD3.js - 如何将条形文本添加到堆叠图中的每个条形?
NVD3.js - How to add bar text to each bar in a stacked graph?
我在 NVD3/AngularJS 中创建了一个多条形图。我想在每个矩形条内显示文本及其值,如下面 JSON 所示。
如何在每个条形图内显示文本值?
NVD3 图表定义
multiBarChart: {
options: function(){
return {
chart: {
type: 'multiBarChart',
stacked: true,
x: function(d){return d.x;},
y: function(d){return d.y;},
text: function(d){return d.x;},
showLabels: true,
showLegend: false,
transitionDuration: 500,
forceX: ["Team", "Meeting", "Phase", "Source"],
xAxis: {
axisLabel: 'Category',
axisLabelDistance: -8
},
yAxis: {
axisLabel: 'Number Of Action Items',
}
}
}
},
data: categoryChartData
}
JSON 数据(类别图表数据)
[
{"values" : [
{
"y" :10,
"x" : "Team"
}, {
"y" : 0,
"x" : "Meeting"
},
{
"y" :0,
"x" : "Phase"
}, {
"y" : 0,
"x" : "Source"
}
],
"key" : "Team1"
},
{"values" : [
{
"y" :5,
"x" : "Team"
}, {
"y" : 0,
"x" : "Meeting"
},
{
"y" :0,
"x" : "Phase"
}, {
"y" : 0,
"x" : "Source"
}
],
"key" : "Team2"
},
{"values" : [
{
"y" :0,
"x" : "Team"
}, {
"y" : 7,
"x" : "Meeting"
},
{
"y" :0,
"x" : "Phase"
}, {
"y" : 0,
"x" : "Source"
}
],
"key" : "Meeting1"
},
{"values" : [
{
"y" :0,
"x" : "Team"
}, {
"y" : 3,
"x" : "Meeting"
},
{
"y" :0,
"x" : "Phase"
}, {
"y" : 0,
"x" : "Source"
}
],
"key" : "Meeting2"
},
{"values" : [
{
"y" :0,
"x" : "Team"
}, {
"y" : 0,
"x" : "Meeting"
},
{
"y" :9,
"x" : "Phase"
}, {
"y" : 0,
"x" : "Source"
}
],
"key" : "Phase1"
},
{"values" : [
{
"y" :0,
"x" : "Team"
}, {
"y" : 0,
"x" : "Meeting"
},
{
"y" :5,
"x" : "Phase"
}, {
"y" : 0,
"x" : "Source"
}
],
"key" : "Phase1"
},
{"values" : [
{
"y" :0,
"x" : "Team"
}, {
"y" : 0,
"x" : "Meeting"
},
{
"y" :0,
"x" : "Phase"
}, {
"y" : 2,
"x" : "Source"
}
],
"key" : "Internal"
},
{"values" : [
{
"y" :0,
"x" : "Team"
}, {
"y" : 0,
"x" : "Meeting"
},
{
"y" :0,
"x" : "Phase"
}, {
"y" : 1,
"x" : "Source"
}
],
"key" : "Customer"
}
];
Angular-nvd3 本身不会为 multi-bar 图表执行此操作,因为动画堆叠条形图会带来一些复杂性,但它会为离散条形图执行此操作,因为 explored. However, in an update to his answer to that question, @Topicus linked to a gist they wrote满足您的需求。
我根据你的情况调整了要点;你可以在 this Plunker 中看到结果。如果标签显示有点不稳定,您可以稍微调整一下格式。关键是标签需要在动画完成后追加,所以我设置了一个超时等于(也可以稍微大于)transitionDuration图表的值属性。我还删除了所有零值,这样它们就不会掩盖非零值。
$scope.options = {
chart: {
type: 'multiBarChart',
height: 500,
transitionDuration: 500,
...
}
};
$scope.data...
$timeout(function () {
d3.selectAll('.nv-multibar .nv-group').each(function(group){
var g = d3.select(this);
// Remove previous labels if there is any
g.selectAll('text').remove();
g.selectAll('.nv-bar').each(function(bar) {
var b = d3.select(this);
var barWidth = b.attr('width');
var barHeight = b.attr('height');
g.append('text')
// Transforms shift the origin point then the x and y of the bar
// is altered by this transform. In order to align the labels
// we need to apply this transform to those.
.attr('transform', b.attr('transform'))
.text(function() {
// No decimals format and eliminate zero values
if (bar.y === 0) {
return;
}
return parseFloat(bar.y).toFixed(0);
})
.attr('y', function() {
// Center label vertically
var height = this.getBBox().height;
return parseFloat(b.attr('y')) + 15; // 15 is the label's margin from the top of bar
})
.attr('x', function() {
// Center label horizontally
var width = this.getBBox().width;
return parseFloat(b.attr('x')) + (parseFloat(barWidth) / 2) - (width / 2);
})
.style("stroke","black")
.attr('class', 'bar-values');
});
});
}, 500);
我认为答案有两点需要补充。
1.我们添加代码在回调中添加值文本function.like:
callback: function(chart){
chart.dispatch.on('stateChange', function(e){
setMultiBarValue(e.stacked);
});
setMultiBarValue(config.stacked);
}
2.add 函数在 group/stacked 选项中显示正确的文本
function setMultiBarValue(chart, config, dataRange, stacked, time){
if(config.type === 'multiBarChart'){
if(stacked === true){
//stack set your totalMin, totalMax to make all the value visible.
chart.yDomain([dataRange.totalMin, dataRange.totalMax]);
initStackLables(d3.select(chart.container), time || 1000);
}else{
//group: set your min,max to make all the value visible.
chart.yDomain([dataRange.yMin, dataRange.yMax]);
initGroupLabels(d3.select(chart.container), time || 1000);
}
}
}
定义拖车函数initStackLabels, initGroupLabels,like:
1).initGroupLabels
var initGroupLabels = function(container, time) {
时间=时间|| 500;
container.selectAll('.nv-multibar .nv-group').each(函数(组){
var g = d3.select(这个);
// 如果有的话,移除之前的标签
g.selectAll('text').删除();
});
$超时(功能(){
container.selectAll('.nv-multibar .nv-group').each(函数(组){
var g = d3.select(这个);
g.selectAll('.nv-bar').each(function(bar, index) {
var b = d3.select(this);
var barWidth = b.attr('width');
var barHeight = b.attr('height');
g.append('text')
// Transforms shift the origin point then the x and y of the bar
// is altered by this transform. In order to align the labels
// we need to apply this transform to those.
.attr('transform', b.attr('transform')).text(function() {
// No decimals format and eliminate zero values
if (bar.y === 0) {
return;
}
return parseFloat(bar.y);
}).attr('y',
function() {
// Center label vertically
var height = this.getBBox().height;
return parseFloat(b.attr('y')) - 10; // 10 is the label's margin from the top of bar
}).attr('x',
function() {
// Center label horizontally
var width = this.getBBox().width;
return parseFloat(b.attr('x')) + (parseFloat(barWidth) / 2) - (width / 2);
}).style('stroke', 'black').attr('class', 'bar-values');
});
});
},
time);
}
2)initStackLables
var initStackLables =函数(容器,时间){
时间=时间|| 500;
container.selectAll('.nv-multibar .nv-group').each(function(group){
var g = d3.select(this);
// Remove previous labels if there is any
g.selectAll('text').remove();
});
$timeout(function () {
var length = container.selectAll('.nv-multibar .nv-group').length;
var vArr = []; var yArr = [];
container.selectAll('.nv-multibar .nv-group').each(function(group){
var g = d3.select(this);
g.selectAll('.nv-bar').each(function(bar, index){
var b = d3.select(this); var by = parseFloat(b.attr('y'));
var barHeight = b.attr('y');
vArr[index] = vArr[index] || 0;
vArr[index] += parseFloat(bar.y) || 0;
yArr[index] = yArr[index] || by;
yArr[index] = yArr[index] > by ? by : yArr[index];
});
});
container.selectAll('.nv-multibar .nv-group').each(function(group, index){
if(index === 0){
var g = d3.select(this);
// Remove previous labels if there is any
g.selectAll('text').remove();
g.selectAll('.nv-bar').each(function(bar, index){
var b = d3.select(this);
var barWidth = b.attr('width');
var barHeight = b.attr('height');
g.append('text')
.attr('transform', b.attr('transform'))
.text(function(){
if (bar.y === 0) {
return;
}
return parseFloat(vArr[index];
})
.attr('y', function(){
var height = this.getBBox().height;
return parseFloat(yArr[index]) - 10; // 10 is the label's margin from the top of bar
})
.attr('x', function(){
var width = this.getBBox().width;
return parseFloat(b.attr('x')) + (parseFloat(barWidth) / 2) - (width / 2);
})
.style('stroke','black')
.attr('class', 'bar-values');
});
}
});
}, time);
}
我在 NVD3/AngularJS 中创建了一个多条形图。我想在每个矩形条内显示文本及其值,如下面 JSON 所示。
如何在每个条形图内显示文本值?
NVD3 图表定义
multiBarChart: {
options: function(){
return {
chart: {
type: 'multiBarChart',
stacked: true,
x: function(d){return d.x;},
y: function(d){return d.y;},
text: function(d){return d.x;},
showLabels: true,
showLegend: false,
transitionDuration: 500,
forceX: ["Team", "Meeting", "Phase", "Source"],
xAxis: {
axisLabel: 'Category',
axisLabelDistance: -8
},
yAxis: {
axisLabel: 'Number Of Action Items',
}
}
}
},
data: categoryChartData
}
JSON 数据(类别图表数据)
[
{"values" : [
{
"y" :10,
"x" : "Team"
}, {
"y" : 0,
"x" : "Meeting"
},
{
"y" :0,
"x" : "Phase"
}, {
"y" : 0,
"x" : "Source"
}
],
"key" : "Team1"
},
{"values" : [
{
"y" :5,
"x" : "Team"
}, {
"y" : 0,
"x" : "Meeting"
},
{
"y" :0,
"x" : "Phase"
}, {
"y" : 0,
"x" : "Source"
}
],
"key" : "Team2"
},
{"values" : [
{
"y" :0,
"x" : "Team"
}, {
"y" : 7,
"x" : "Meeting"
},
{
"y" :0,
"x" : "Phase"
}, {
"y" : 0,
"x" : "Source"
}
],
"key" : "Meeting1"
},
{"values" : [
{
"y" :0,
"x" : "Team"
}, {
"y" : 3,
"x" : "Meeting"
},
{
"y" :0,
"x" : "Phase"
}, {
"y" : 0,
"x" : "Source"
}
],
"key" : "Meeting2"
},
{"values" : [
{
"y" :0,
"x" : "Team"
}, {
"y" : 0,
"x" : "Meeting"
},
{
"y" :9,
"x" : "Phase"
}, {
"y" : 0,
"x" : "Source"
}
],
"key" : "Phase1"
},
{"values" : [
{
"y" :0,
"x" : "Team"
}, {
"y" : 0,
"x" : "Meeting"
},
{
"y" :5,
"x" : "Phase"
}, {
"y" : 0,
"x" : "Source"
}
],
"key" : "Phase1"
},
{"values" : [
{
"y" :0,
"x" : "Team"
}, {
"y" : 0,
"x" : "Meeting"
},
{
"y" :0,
"x" : "Phase"
}, {
"y" : 2,
"x" : "Source"
}
],
"key" : "Internal"
},
{"values" : [
{
"y" :0,
"x" : "Team"
}, {
"y" : 0,
"x" : "Meeting"
},
{
"y" :0,
"x" : "Phase"
}, {
"y" : 1,
"x" : "Source"
}
],
"key" : "Customer"
}
];
Angular-nvd3 本身不会为 multi-bar 图表执行此操作,因为动画堆叠条形图会带来一些复杂性,但它会为离散条形图执行此操作,因为
我根据你的情况调整了要点;你可以在 this Plunker 中看到结果。如果标签显示有点不稳定,您可以稍微调整一下格式。关键是标签需要在动画完成后追加,所以我设置了一个超时等于(也可以稍微大于)transitionDuration图表的值属性。我还删除了所有零值,这样它们就不会掩盖非零值。
$scope.options = {
chart: {
type: 'multiBarChart',
height: 500,
transitionDuration: 500,
...
}
};
$scope.data...
$timeout(function () {
d3.selectAll('.nv-multibar .nv-group').each(function(group){
var g = d3.select(this);
// Remove previous labels if there is any
g.selectAll('text').remove();
g.selectAll('.nv-bar').each(function(bar) {
var b = d3.select(this);
var barWidth = b.attr('width');
var barHeight = b.attr('height');
g.append('text')
// Transforms shift the origin point then the x and y of the bar
// is altered by this transform. In order to align the labels
// we need to apply this transform to those.
.attr('transform', b.attr('transform'))
.text(function() {
// No decimals format and eliminate zero values
if (bar.y === 0) {
return;
}
return parseFloat(bar.y).toFixed(0);
})
.attr('y', function() {
// Center label vertically
var height = this.getBBox().height;
return parseFloat(b.attr('y')) + 15; // 15 is the label's margin from the top of bar
})
.attr('x', function() {
// Center label horizontally
var width = this.getBBox().width;
return parseFloat(b.attr('x')) + (parseFloat(barWidth) / 2) - (width / 2);
})
.style("stroke","black")
.attr('class', 'bar-values');
});
});
}, 500);
我认为答案有两点需要补充。 1.我们添加代码在回调中添加值文本function.like:
callback: function(chart){
chart.dispatch.on('stateChange', function(e){
setMultiBarValue(e.stacked);
});
setMultiBarValue(config.stacked);
}
2.add 函数在 group/stacked 选项中显示正确的文本
function setMultiBarValue(chart, config, dataRange, stacked, time){
if(config.type === 'multiBarChart'){
if(stacked === true){
//stack set your totalMin, totalMax to make all the value visible.
chart.yDomain([dataRange.totalMin, dataRange.totalMax]);
initStackLables(d3.select(chart.container), time || 1000);
}else{
//group: set your min,max to make all the value visible.
chart.yDomain([dataRange.yMin, dataRange.yMax]);
initGroupLabels(d3.select(chart.container), time || 1000);
}
}
}
定义拖车函数initStackLabels, initGroupLabels,like:
1).initGroupLabels
var initGroupLabels = function(container, time) { 时间=时间|| 500; container.selectAll('.nv-multibar .nv-group').each(函数(组){ var g = d3.select(这个); // 如果有的话,移除之前的标签 g.selectAll('text').删除(); }); $超时(功能(){ container.selectAll('.nv-multibar .nv-group').each(函数(组){ var g = d3.select(这个);
g.selectAll('.nv-bar').each(function(bar, index) { var b = d3.select(this); var barWidth = b.attr('width'); var barHeight = b.attr('height'); g.append('text') // Transforms shift the origin point then the x and y of the bar // is altered by this transform. In order to align the labels // we need to apply this transform to those. .attr('transform', b.attr('transform')).text(function() { // No decimals format and eliminate zero values if (bar.y === 0) { return; } return parseFloat(bar.y); }).attr('y', function() { // Center label vertically var height = this.getBBox().height; return parseFloat(b.attr('y')) - 10; // 10 is the label's margin from the top of bar }).attr('x', function() { // Center label horizontally var width = this.getBBox().width; return parseFloat(b.attr('x')) + (parseFloat(barWidth) / 2) - (width / 2); }).style('stroke', 'black').attr('class', 'bar-values'); }); }); }, time); }
2)initStackLables
var initStackLables =函数(容器,时间){ 时间=时间|| 500;
container.selectAll('.nv-multibar .nv-group').each(function(group){ var g = d3.select(this); // Remove previous labels if there is any g.selectAll('text').remove(); }); $timeout(function () { var length = container.selectAll('.nv-multibar .nv-group').length; var vArr = []; var yArr = []; container.selectAll('.nv-multibar .nv-group').each(function(group){ var g = d3.select(this); g.selectAll('.nv-bar').each(function(bar, index){ var b = d3.select(this); var by = parseFloat(b.attr('y')); var barHeight = b.attr('y'); vArr[index] = vArr[index] || 0; vArr[index] += parseFloat(bar.y) || 0; yArr[index] = yArr[index] || by; yArr[index] = yArr[index] > by ? by : yArr[index]; }); }); container.selectAll('.nv-multibar .nv-group').each(function(group, index){ if(index === 0){ var g = d3.select(this); // Remove previous labels if there is any g.selectAll('text').remove(); g.selectAll('.nv-bar').each(function(bar, index){ var b = d3.select(this); var barWidth = b.attr('width'); var barHeight = b.attr('height'); g.append('text') .attr('transform', b.attr('transform')) .text(function(){ if (bar.y === 0) { return; } return parseFloat(vArr[index]; }) .attr('y', function(){ var height = this.getBBox().height; return parseFloat(yArr[index]) - 10; // 10 is the label's margin from the top of bar }) .attr('x', function(){ var width = this.getBBox().width; return parseFloat(b.attr('x')) + (parseFloat(barWidth) / 2) - (width / 2); }) .style('stroke','black') .attr('class', 'bar-values'); }); } }); }, time);
}