小提琴:https://jsfiddle.net/vpkarep8/
我有三个饼图在使用新数据进行更新时动画,我似乎无法让标签正确更新。上面附有一个小提琴。
要使文本更改,我必须在文本上进行另一个数据连接(第486-489行),但后来我无法使用arc.centroid()。将其缩小到我如何处理更新,但不知道处理所有这些的最佳方法。似乎质心需要d,但要更新文本需要d.values。
有什么想法吗?
尝试了Label outside arc (Pie chart) d3.js和How to update both the content and location of text labels on a D3 pie chart的答案。
likeButton.transform = CGAffineTransformMakeScale(2, 2) //doubles the button's size
答案 0 :(得分:1)
首先,不要在两个不同的对象上重用类名arc
;您在每个切片的父g
和子path
上都有它。
其次,将数据重新绑定到父g
,以便path
和text
都可以使用它。
var slice = svg.selectAll('.slice') //<-- for the g
.data(function(d) {
return pie(d.values);
})
.enter()
.append('g')
.attr('class', 'slice');
稍后更新:
var npath = nslice.selectAll('.slice') //<-- rebind to `g`
.data(function(d) {
return pie(d.values);
});
npath
.select("path")
.attr('class', function(d) {
return 'arc ' + d.data.platform;
})
.transition().duration(1000)
.attrTween('d', arcTween); //<-- update the paths
npath.exit()
.remove(); //<-- remove the whole g
npath.select("text") //<-- update the text
.transition()
.duration(1000)
.style('opacity', 1)
.text(function(d) {
if (d.data.val > 0) {
return d.data.val + '%';
}
})
.attr('transform', function(d) {
console.log(arc.centroid(d)); //<-- you can now use centroid
});
<强> EDITS 强>
我的坏,我应该抓住了。问题是您将.selectAll
和.data
与显式循环相结合。 d3
数据绑定是关于它根据数据进行循环的全部内容。那么,我们该如何解决呢?
我们从get go开始正确的数据绑定。
var svg = d3.select('.ES__graph__container')
.selectAll('svg')
.data(brandDataByYear)
.enter()
.append('svg')
.style('margin-top', '25px')
.attr('width', (r + m) * 2)
.attr('height', (r + m) * 2)
.attr('class', 'pie') //<-- give each svg a class, not id
...
然后在您的更新中:
// for (x in newdata) { //<-- NO EXPLICIT LOOPING!
var nslice = d3.selectAll('.pie')
.data(newdata);
更新完整代码:
<!DOCTYPE html>
<html>
<head>
<script data-require="jquery@2.1.4" data-semver="2.1.4" src="https://code.jquery.com/jquery-2.1.4.js"></script>
<script src="//d3js.org/d3.v3.js" charset="utf-8"></script>
<style>
.arc.platform1 {
fill: #e74341;
}
.arc.platform2 {
fill: #3c5a96;
}
.arc.platform3 {
fill: #3c94d1;
}
.arc.platform4 {
fill: #837369;
}
</style>
</head>
<body>
<div class="ES__buttons"></div>
<div class="ES__graph__container"></div>
<script>
function drawESGraph() {
d3.selectAll('.ES__graph__container svg')
.remove();
d3.selectAll('.ES__buttons button')
.remove();
var $container = $('.ES__graph__container');
var width = $container.width() / 3;
var m = 40,
r = width / 3,
labelr = r + 20;
var arc = d3.svg.arc()
.outerRadius(r)
.innerRadius(r / 2);
var pie = d3.layout.pie()
.value(function(d) {
return +d.val;
})
.sort(null);
var data = [{
brand: 'brand1',
platform: 'platform1',
year: '2012-2013',
val: 85.8
}, {
brand: 'brand1',
platform: 'platform2',
year: '2012-2013',
val: 14
}, {
brand: 'brand1',
platform: 'platform3',
year: '2012-2013',
val: 0.2
}, {
brand: 'brand1',
platform: 'platform4',
year: '2012-2013',
val: 0
}, {
brand: 'brand1',
platform: 'platform1',
year: '2013-2014',
val: 91
}, {
brand: 'brand1',
platform: 'platform2',
year: '2013-2014',
val: 8
}, {
brand: 'brand1',
platform: 'platform3',
year: '2013-2014',
val: 1
}, {
brand: 'brand1',
platform: 'platform4',
year: '2013-2014',
val: 0
}, {
brand: 'brand1',
platform: 'platform1',
year: '2014-2015',
val: 77
}, {
brand: 'brand1',
platform: 'platform2',
year: '2014-2015',
val: 8
}, {
brand: 'brand1',
platform: 'platform3',
year: '2014-2015',
val: 2
}, {
brand: 'brand1',
platform: 'platform4',
year: '2014-2015',
val: 13
}, {
brand: 'brand2',
platform: 'platform1',
year: '2012-2013',
val: 76.9
}, {
brand: 'brand2',
platform: 'platform2',
year: '2012-2013',
val: 23
}, {
brand: 'brand2',
platform: 'platform3',
year: '2012-2013',
val: 0.1
}, {
brand: 'brand2',
platform: 'platform4',
year: '2012-2013',
val: 0
}, {
brand: 'brand2',
platform: 'platform1',
year: '2013-2014',
val: 87.6
}, {
brand: 'brand2',
platform: 'platform2',
year: '2013-2014',
val: 7
}, {
brand: 'brand2',
platform: 'platform3',
year: '2013-2014',
val: 0.4
}, {
brand: 'brand2',
platform: 'platform4',
year: '2013-2014',
val: 5
}, {
brand: 'brand2',
platform: 'platform1',
year: '2014-2015',
val: 55
}, {
brand: 'brand2',
platform: 'platform2',
year: '2014-2015',
val: 7
}, {
brand: 'brand2',
platform: 'platform3',
year: '2014-2015',
val: 1
}, {
brand: 'brand2',
platform: 'platform4',
year: '2014-2015',
val: 37
}, {
brand: 'brand3',
platform: 'platform1',
year: '2012-2013',
val: 72.9
}, {
brand: 'brand3',
platform: 'platform2',
year: '2012-2013',
val: 24
}, {
brand: 'brand3',
platform: 'platform3',
year: '2012-2013',
val: 0.1
}, {
brand: 'brand3',
platform: 'platform4',
year: '2012-2013',
val: 3
}, {
brand: 'brand3',
platform: 'platform1',
year: '2013-2014',
val: 76
}, {
brand: 'brand3',
platform: 'platform2',
year: '2013-2014',
val: 10
}, {
brand: 'brand3',
platform: 'platform3',
year: '2013-2014',
val: 1
}, {
brand: 'brand3',
platform: 'platform4',
year: '2013-2014',
val: 13
}, {
brand: 'brand3',
platform: 'platform1',
year: '2014-2015',
val: 56
}, {
brand: 'brand3',
platform: 'platform2',
year: '2014-2015',
val: 12
}, {
brand: 'brand3',
platform: 'platform3',
year: '2014-2015',
val: 1
}, {
brand: 'brand3',
platform: 'platform4',
year: '2014-2015',
val: 31
}, {
brand: 'brand4',
platform: 'platform1',
year: '2012-2013',
val: 1
}, {
brand: 'brand4',
platform: 'platform2',
year: '2012-2013',
val: 63
}, {
brand: 'brand4',
platform: 'platform3',
year: '2012-2013',
val: 1
}, {
brand: 'brand4',
platform: 'platform4',
year: '2012-2013',
val: 35
}, {
brand: 'brand4',
platform: 'platform1',
year: '2013-2014',
val: 0
}, {
brand: 'brand4',
platform: 'platform2',
year: '2013-2014',
val: 22
}, {
brand: 'brand4',
platform: 'platform3',
year: '2013-2014',
val: 1
}, {
brand: 'brand4',
platform: 'platform4',
year: '2013-2014',
val: 77
}, {
brand: 'brand4',
platform: 'platform1',
year: '2014-2015',
val: 0
}, {
brand: 'brand4',
platform: 'platform2',
year: '2014-2015',
val: 14
}, {
brand: 'brand4',
platform: 'platform3',
year: '2014-2015',
val: 1
}, {
brand: 'brand4',
platform: 'platform4',
year: '2014-2015',
val: 85
}]
var allBrands = d3.set(data.map(function(d) {
return d.brand;
})).values();
var buttons = d3.select('.ES__buttons')
.selectAll('button')
.data(allBrands)
.enter()
.append('button')
.attr('class', function(d) {
return d + ' button';
})
.text(function(d) {
return d;
})
.on('click', function(d) {
updateChart(d);
})
.style('opacity', 0);
buttons.transition().duration(1000)
.style('opacity', 1);
d3.select('.brand1.button')
.attr('class', 'brand1 button active');
function updateChart(brand) {
var brandData = data.filter(function(d) {
return d.brand === brand;
});
var brandDataByYear = d3.nest()
.key(function(d) {
return d.year;
})
.entries(brandData);
var svg = d3.select('.ES__graph__container')
.selectAll('svg')
.data(brandDataByYear)
.enter()
.append('svg')
.style('margin-top', '25px')
.attr('width', (r + m) * 2)
.attr('height', (r + m) * 2)
.attr('class', 'pie')
.append('svg:g')
.attr('transform', 'translate(' + (r + m) + ',' + (r + m) + ')');
var pieLabel = svg.append('svg:text')
.attr('dy', '.35em')
.attr('text-anchor', 'middle')
.text(function(d) {
return d.key;
})
.style('fill', 'black')
.style('opacity', 0);
pieLabel.transition().duration(1000)
.style('opacity', 1);
var slice = svg.selectAll('.slice')
.data(function(d) {
return pie(d.values);
})
.enter()
.append('g')
.attr('class', 'slice');
var path = slice.append('svg:path')
.attr('d', arc)
.attr('class', function(d) {
return 'arc ' + d.data.platform;
})
.each(function(d) {
this._current = d;
});
var text = slice.append('text')
.text(function(d) {
if (d.data.val > 0) {
return d.data.val + '%';
}
})
.attr('transform', function(d) {
if (d.data.val > 3) {
return 'translate(' + arc.centroid(d) + ')';
} else {
var c = arc.centroid(d),
x = c[0],
y = c[1],
h = Math.sqrt(x * x + y * y);
return 'translate(' + (x / h * labelr) + ',' + (y / h * labelr) + ')';
}
})
.attr('text-anchor', function(d) {
if (d.data.val < 3) {
return (d.endAngle + d.startAngle) / 2 > Math.PI ? 'end' : 'start';
}
})
.attr('dx', function(d) {
return d.data.val > 3 ? -15 : 18;
})
.attr('dy', function(d) {
return d.data.val > 3 ? 5 : 3;
})
.style('fill', function(d) {
return d.data.val > 3 ? 'white' : 'black';
})
.attr('class', 'label');
change();
function change() {
var newdata = brandDataByYear;
// for (x in newdata) {
var nslice = d3.selectAll('.pie')
.data(newdata);
//return;
var npath = nslice.selectAll('.slice')
.data(function(d) {
console.log(d);
return pie(d.values);
});
npath
.select("path")
.attr('class', function(d) {
return 'arc ' + d.data.platform;
})
.transition().duration(1000)
.attrTween('d', arcTween);
npath.exit()
.remove();
npath.select("text")
.transition()
.duration(1000)
.style('opacity', 1)
.text(function(d) {
if (d.data.val > 0) {
return d.data.val + '%';
}
})
.attr('transform', function(d) {
if (d.data.val > 3) {
return 'translate(' + arc.centroid(d) + ')';
} else {
var c = arc.centroid(d),
x = c[0],
y = c[1],
h = Math.sqrt(x * x + y * y);
return 'translate(' + (x / h * labelr) + ',' + (y / h * labelr) + ')';
}
});
// .attr("transform", function(d) {
// return "translate(" +
// ( (radius - 12) * Math.sin( ((d.endAngle - d.startAngle) / 2) + d.startAngle ) ) +
// ", " +
// ( -1 * (radius - 12) * Math.cos( ((d.endAngle - d.startAngle) / 2) + d.startAngle ) ) +
// ")";
// })
// .style("text-anchor", function(d) {
// var rads = ((d.endAngle - d.startAngle) / 2) + d.startAngle;
// if ( (rads > 7 * Math.PI / 4 && rads < Math.PI / 4) || (rads > 3 * Math.PI / 4 && rads < 5 * Math.PI / 4) ) {
// return "middle";
// } else if (rads >= Math.PI / 4 && rads <= 3 * Math.PI / 4) {
// return "start";
// } else if (rads >= 5 * Math.PI / 4 && rads <= 7 * Math.PI / 4) {
// return "end";
// } else {
// return "middle";
// }
// })
// ntext.exit()
// .remove();
}
// }
function arcTween(a) {
var i = d3.interpolate(this._current, a);
this._current = i(0);
return function(t) {
return arc(i(t));
}
}
}
updateChart('brand1');
}
drawESGraph();
</script>
</body>
</html>