今天我在简单的饼图上使用d3.js。
我使用教程here来构建我的第一个饼图,但我想稍微自定义它,所以我的代码看起来不一样。
我在处理第6步时遇到问题,为我的图表添加了一些交互性。
如图here所示,饼图应该允许我点击其图例来切换一些数据。但是,如果悬停工具正在处理我的代码(切换有效地改变了悬停框内的值),则图表本身不会改变。
切换时,我的浏览器控制台会抛出该错误:
d3.v3.js:5737 Uncaught TypeError: Cannot use 'in' operator to search for 'data' in undefined
经过一些测试后,我意识到由于javascript的那部分错误发生了错误:
var path = g.data(pie(data));
path.transition()
.duration(750)
.attrTween('d', function(d) {
var interpolate = d3.interpolate(this._current, d);
this._current = interpolate(0);
return function(t) {
return arc(interpolate(t));
};
与演示中的相同。因此,我的其余代码可能会出现错误,但我不知道是什么导致错误。
这是我到目前为止所做的:
样式:
#chart {
height: 360px;
margin: 0 auto;
position: relative;
width: 360px;
}
.tool {
background: #eee;
box-shadow: 0 0 5px #999999;
color: #333;
display: none;
font-size: 12px;
left: 130px;
padding: 10px;
position: absolute;
text-align: center;
top: 95px;
width: 80px;
z-index: 10;
}
/* replace bootstrap css */
.label {
color: #000000
}
/* css for the legend*/
.legend {
font-size: 12px;
}
rect {
cursor: pointer;
stroke-width: 2;
}
rect.disabled {
fill: transparent !important;
}
脚本:
// var definition
var legendRectSize = 18;
var legendSpacing = 4;
// defines chart boundaries
var width = 960;
var height = 500;
var radius = Math.min(width, height) / 2;
var DonutWidth = 80;
// defines a charter of colors for the chart
var color = d3.scale.ordinal()
.range(["#98abc5", "#8a89a6", "#7b6888", "#6b486b", "#a05d56", "#d0743c", "#ff8c00"]);
// defines graphical attributes for the chart
var arc = d3.svg.arc()
.outerRadius(radius - 10)
.innerRadius(radius - DonutWidth);
var labelArc = d3.svg.arc()
.outerRadius(radius - 40)
.innerRadius(radius - 40);
var pie = d3.layout.pie()
.sort(null)
.value(function(d) { return d.TST; });
// add the chart to the html doc
var svg = d3.select('#chart').append("svg")
.attr("width", width)
.attr("height", height)
.append("g")
.attr("transform", "translate(" + width / 2 + "," + height / 2 + ")");
// add objects needed for the hover tool
var tool = d3.select('#chart')
.append('div')
.attr('class', 'tool');
tool.append('div')
.attr('class', 'label');
tool.append('div')
.attr('class', 'count');
tool.append('div')
.attr('class', 'percent');
// loads data
d3.json("/media/Storage/bar_chart.json", function(data) {
// creates a variable to know if a column will be displayed or not
data.forEach(function(d) {
d.TST = +d.TST;
d.enabled = true;
});
// creates the pie chart from data
var g = svg.selectAll(".arc")
.data(pie(data))
.enter().append("g")
.attr("class", "arc");
g.append("path")
.attr("d", arc)
.attr("fill", function(d, i) { return color(d.data.OPCODE); })
.each(function(d){this._current = d;});
// displays data on hover
g.on('mouseover',function(d){
var total = d3.sum(data.map(function(d) {
return (d.enabled) ? d.TST : 0;
}));
var percent = Math.round(1000 * d.data.TST / total) / 10;
tool.select('.label').html(d.data.OPCODE);
tool.select('.count').html(d.data.TST);
tool.select('.percent').html(percent + '%');
tool.style('display', 'block');
});
// toggles off hoverbox
g.on('mouseout', function(d){
tool.style('display', 'none');
});
// add the legend to the chart
var legend = svg.selectAll('.legend')
.data(color.domain())
.enter()
.append('g')
.attr('class', 'legend')
.attr('transform', function(d, i) {
var height = legendRectSize + legendSpacing;
var offset = height * color.domain().length / 2;
var horz = -2 * legendRectSize;
var vert = i * height - offset;
return 'translate(' + horz + ',' + vert + ')';
});
legend.append('rect')
.attr('width', legendRectSize)
.attr('height', legendRectSize)
.style('fill', color)
.style('stroke', color)
// function which toggles data to exclude of display
.on('click', function(OPCODE){
var rect = d3.select(this);
var enabled = true;
var totalEnabled = d3.sum(data.map(function(d) {
return (d.enabled) ? 1 : 0;
}));
if (rect.attr('class') === 'disabled') {
rect.attr('class', '');
} else {
if (totalEnabled < 2) return;
rect.attr('class', 'disabled');
enabled = false;
}
// defines a new way to retrieve data for the chart, selecting only enabled data
pie.value(function(d) {
if (d.OPCODE === OPCODE) d.enabled = enabled;
return (d.enabled) ? d.TST : 0;
});
//incriminated part of the script
var path = g.data(pie(data));
// animation for the chart
path.transition()
.duration(750)
.attrTween('d', function(d) {
var interpolate = d3.interpolate(this._current, d);
this._current = interpolate(0);
return function(t) {
return arc(interpolate(t));
};
});
});
legend.append('text')
.attr('x', legendRectSize + legendSpacing)
.attr('y', legendRectSize - legendSpacing)
.text(function(d) { return d; });
});
非常感谢你的帮助。
编辑:
由于我正在使用json文件,我在我的应用程序中本地加载,这里我不得不使用我的JSON放置的局部变量,但它显然效率低下并带来了其他错误......
答案 0 :(得分:0)
您在此行this._current
处未定义var i = d3.interpolate(this._current, d);
修复此问题,剩下的就足够了。而不是this.current
尝试使用可在代码中的任何位置访问的temp var
。如果new data
与old data
尝试two sets of json and onClick
不同,您只能看到过渡{1}}传递新的json数据。