我有一个带有交互式图例的分组条形图。所有似乎都显示并正常工作,但传说缺少一个值。我知道问题在于图例是在x0轴上的项目索引而不是条形的索引(x1轴)。但是我不知道如何解决这个问题。
我的数据包括以下内容:
[{
"Group": 1,
"DataPoints": [{
"BarValue": "Extension Cable",
"Value": 1
}]
},
{
"Group": 2,
"DataPoints": [{
"BarValue": "Extension Cable",
"Value": 1
},
{
"BarValue": "LED Light",
"Value": 2
},
{
"BarValue": "USB",
"Value": 4
},
{
"BarValue": "USB Socket",
"Value": 2
}]
},
{
"Group": 3,
"DataPoints": [{
"BarValue": "Extension Cable",
"Value": 2
},
{
"BarValue": "USB",
"Value": 1
}]
}]
在此示例中,该组是一年中的月份数,即1-12。 BarValue是产品的名称。因此,每个月内每个产品都会有一个栏。而Value是用于确定图表高度的Y值。
因此,在我的传说中,我希望有:
延长电缆
LED灯
USB
USB插座
然而,我实际看到的是:
延长电缆
LED灯
USB
这告诉我它正在正确渲染,除了它使用月份的数量而不是产品来确定图例。但是我不确定为什么会这样,我不知道。
这是显示问题的图像。如您所见,粉红色条未显示在图例中:
我的传奇代码如下:
var li = {
w: 120, h: 30, s: 3, r: 3
};
var legendData = d3.set(data.reduce(function (previousValue, currentValue) {
return previousValue.concat(currentValue.DataPoints.map(function (d) {
return d.BarValue;
}))
}, [])).values();
var legend = legend.append("svg:svg")
.attr("width", li.w)
.attr("height", height)
.attr('class', 'legend');
var g = legend.selectAll("g")
.data(data.slice())
.enter().append("svg:g")
.attr("transform", function (d, i) {
return "translate(0," + ((i * (li.h + li.s)) + 20) + ")";
});
g.append("svg:rect")
.datum(function (d) { return d.DataPoints;})
.attr("rx", li.r)
.attr("ry", li.r)
.attr("width", li.w)
.attr("height", li.h)
.attr('class', function (d, i) { return 'bartag' + legendData[i].replace(/\s+/g, '') + 'rect' })
.style("fill", function (d, i) { return color(legendData[i]); })
.on('mouseover', function () {
$(this).css('cursor', 'pointer')
})
.on('click', function (d, i) {
var active = d.active ? false : true,
newOpacity = active ? 1 : 0,
id = '.bartag' + legendData[i];
d3.selectAll('.bartag' + legendData[i])
.transition().duration(100)
.style('opacity', newOpacity);
d.active = active;
if (active) {
var test = '.bartag' + legendData[i] + 'rect';
d3.selectAll('.bartag' + legendData[i] + 'rect').style("opacity", newOpacity);
}
else {
var test = d3.selectAll('.bartag' + legendData[i] + 'rect');
test.style('opacity', newOpacity);
}
});
g.append("svg:text")
.attr("x", 5)
.attr("y", li.h / 2)
.attr("dy", "0.35em")
.attr("text-anchor", "start")
.text(function (d, i) { return legendData[i]; })
.on('mouseover', function () {
$(this).css('cursor', 'pointer')
})
.on('click', function (d, i) {
var active = d.active ? false : true,
newOpacity = active ? 1 : 0,
id = '.bartag' + legendData[i].replace(/\s+/g, '');
d3.selectAll('.bartag' + legendData[i].replace(/\s+/g, ''))
.transition().duration(100)
.style('opacity', newOpacity);
d.active = active;
if (active) {
var test = '.bartag' + legendData[i].replace(/\s+/g, '') + 'rect';
d3.selectAll('.bartag' + legendData[i].replace(/\s+/g, '') + 'rect').style("opacity", newOpacity);
}
else {
var test = d3.selectAll('.bartag' + legendData[i].replace(/\s+/g, '') + 'rect');
test.style('opacity', newOpacity);
}
});
供参考,这是我的完整代码:
var margin = { top: 20, right: 0, bottom: 40, left: 50 },
width = 960 - margin.left - margin.right,
height = 500 - margin.top - margin.bottom,
tooltipTextColour = "white",
color = d3.scale.ordinal().range(["#FF9797", "#86BCFF", "#33FDC0", "#EFA9FE", "#7BCAE1", "#8C8CFF", "#80B584", "#C88E8E", "#DD597D", "#D8F0F8", "#DD597D", "#D6C485", "#990099", "#5B5BFF", "#1FCB4A", "#000000", "#00BFFF", "#BE81F7", "#BDBDBD", "#F79F81"]);
if (data.length > 0) {
var legendData = d3.set(data.reduce(function (previousValue, currentValue) {
return previousValue.concat(currentValue.DataPoints.map(function (d) {
return d.BarValue;
}))
}, [])).values();
var x0 = d3.scale.ordinal()
.rangeRoundBands([0, width], .1);
var x1 = d3.scale.ordinal();
var y = d3.scale.linear().range([height, 0]);
var xAxis = d3.svg.axis()
.scale(x0)
.orient("bottom");
var yAxis = d3.svg.axis()
.scale(y)
.orient("left")
.tickFormat(d3.format(".2s"));
var svg = placeholder.append("svg")
.attr('width', width + margin.left)
.attr('height', height + margin.top + margin.bottom)
.attr('class', 'chart')
.append('g')
.attr('transform', 'translate(' + margin.left + ',' + margin.top + ')');
x0.domain(data.map(function (d) { return d.Group; }));
x1.domain(d3.set(data.reduce(function (previousValue, currentValue) {
return previousValue.concat(currentValue.DataPoints.map(function (d) {
return d.BarValue;
}))
}, [])).values()).rangeRoundBands([0, x0.rangeBand()]);
y.domain([0, d3.max(data, function(d){
return d3.max(d.DataPoints, function (d) {
return d.Value;
})
})]);
svg.append('g')
.attr('class', 'x axis')
.attr('transform', 'translate(0,' + height + ')')
.call(xAxis);
svg.append('g')
.attr('class', 'y axis')
.call(yAxis)
.append('text')
.attr("transform", "rotate(-90)")
.attr("y", 6)
.attr("dy", ".71em")
.style("text-anchor", "end")
.text("Complaints");
var type = svg.selectAll(".type")
.data(data)
.enter()
.append('g')
.attr('class', 'type')
.attr('transform', function (d) { return 'translate(' + x0(d.Group) + ',0)'; });
var rect = type.selectAll("rect")
.data(function (d) { return d.DataPoints; })
.enter()
.append('rect')
.attr('width', x1.rangeBand())
.attr('x', function (d) { return x1(d.BarValue); })
.attr('y', function (d) { return y(d.Value); })
.attr('class', function (d) { return 'bartag' + d.BarValue.replace(/\s+/g, '') })
.attr('height', function (d) { return height - y(d.Value); })
.style('fill', function (d, i) { return color(d.BarValue); });
rect.append('text')
.attr('x', function (d) { return x1(d.BarValue); })
.attr('y', function (d) { return y(d.Value); })
.attr("dy", "0.35em")
.attr("text-anchor", "middle")
.text(function (d, i) { return legendData[i]; });
if (legend != null) {
var li = {
w: 120, h: 30, s: 3, r: 3
};
var legend = legend.append("svg:svg")
.attr("width", li.w)
.attr("height", height)
.attr('class', 'legend');
var g = legend.selectAll("g")
.data(data.slice())
.enter().append("svg:g")
.attr("transform", function (d, i) {
return "translate(0," + ((i * (li.h + li.s)) + 20) + ")";
});
g.append("svg:rect")
.datum(function (d) { return d.DataPoints;})
.attr("rx", li.r)
.attr("ry", li.r)
.attr("width", li.w)
.attr("height", li.h)
.attr('class', function (d, i) { return 'bartag' + legendData[i].replace(/\s+/g, '') + 'rect' })
.style("fill", function (d, i) { return color(legendData[i]); })
.on('mouseover', function () {
$(this).css('cursor', 'pointer')
})
.on('click', function (d, i) {
var active = d.active ? false : true,
newOpacity = active ? 1 : 0,
id = '.bartag' + legendData[i];
d3.selectAll('.bartag' + legendData[i])
.transition().duration(100)
.style('opacity', newOpacity);
d.active = active;
if (active) {
var test = '.bartag' + legendData[i] + 'rect';
d3.selectAll('.bartag' + legendData[i] + 'rect').style("opacity", newOpacity);
}
else {
var test = d3.selectAll('.bartag' + legendData[i] + 'rect');
test.style('opacity', newOpacity);
}
});
g.append("svg:text")
.attr("x", 5)
.attr("y", li.h / 2)
.attr("dy", "0.35em")
.attr("text-anchor", "start")
.text(function (d, i) { return legendData[i]; })
.on('mouseover', function () {
$(this).css('cursor', 'pointer')
})
.on('click', function (d, i) {
var active = d.active ? false : true,
newOpacity = active ? 1 : 0,
id = '.bartag' + legendData[i].replace(/\s+/g, '');
d3.selectAll('.bartag' + legendData[i].replace(/\s+/g, ''))
.transition().duration(100)
.style('opacity', newOpacity);
d.active = active;
if (active) {
var test = '.bartag' + legendData[i].replace(/\s+/g, '') + 'rect';
d3.selectAll('.bartag' + legendData[i].replace(/\s+/g, '') + 'rect').style("opacity", newOpacity);
}
else {
var test = d3.selectAll('.bartag' + legendData[i].replace(/\s+/g, '') + 'rect');
test.style('opacity', newOpacity);
}
});
}
}
else {
placeholder.append('p').text('No Data to Display').style('font-weight', 'bold');
}
if (callback) {
callback();
}
我希望这是足够的信息,如果有任何人可以提供任何帮助,我们将不胜感激。
修改
我不知道哪个更容易解决,所以我会提出来。
如果我使用legendData作为图例的数据,则会显示所有图例选项。但是,问题在于图例不再是交互式的。这是因为legendData只是包含产品名称的字符串,因此当它试图让d.active切换条形图的可见性时,它会失败,因为它是字符串而不是对象。
答案 0 :(得分:1)
我会进行以下修改:
将您的图例作为一个对象数组(而不是字符串),每个对象包含一个字符串的名称和一个活动/非活动的bollean。
var legendData = d3.set(data.reduce(function (previousValue, currentValue) {
return previousValue.concat(currentValue.DataPoints.map(function (d) {
return d.BarValue;
}))
}, [])).values();
//Add this:
legendData=legendData.map(function(s){
return {name:s, active:true};
});
将legendData
映射到您的图例对象
legend.selectAll("g")
.data(legendData)
.enter().append("svg:g")
并删除以前的绑定:
g.append("svg:rect")
//.datum(function (d) { return d.DataPoints;}) //remove this
.attr("rx", li.r)
现在每个图例项都知道相应的字符串及其状态。
name
字段:对于图例部分中的任何legendData[i]
,您应该改为d.name
(注意您没有明确引用{{1}因为你之前完成了绑定,所以已经完成了。 legendData
字段似乎无关(您已使用active
)。