如何旋转D3图表以使选定的弧线位于底部? [英] How to rotate the D3 chart so that the selected arc is at the bottom?
问题描述
我正在尝试开发一个应用程序,用户可以单击D3饼图并查看与选择有关的信息.如何旋转圆弧,使单击的圆弧位于底部(单击的圆弧的中心应位于底部)?我一直在通过选择弧线组来旋转饼图,但是对于实现该方法的任何想法,我将不胜感激.这是我到目前为止的一些代码.
I am trying to develop an application where users can click on the D3 pie chart and see information which relates to the selection. How can I rotate the arc's so that the clicked arc comes to the bottom (the centre of the arc clicked on should be at the bottom)? I have been playing around with rotating the pie by selecting the arc group but I would appreciate any idea on how to achieve this. Here is some code I have so far.
var self = this;
var instanceId = Math.floor(Math.random() * 100000);
var margin = {
top: 5,
right: 15,
bottom: 50,
left: 20
};
self.width = this.htmlElement.parentElement.parentElement.offsetWidth - margin.right - margin.left;
self.height = window.innerHeight / 3 ;
self.curAngle = 0;
self.svgParent.html("<h4 style='color:green;'>Sponsors </h4><br>");
// Update data for the chart
self.updateChartData = function () {
if(!self.svg) {
this.svg = this.svgParent
.classed("svg-container", true)
.append("svg")
.attr("preserveAspectRatio", "xMinYMin meet")
.attr("viewBox", "0 0 " + this.width + " " + this.height)
.append("g")
.classed("svg-content-responsive", true);
//.attr("transform", "translate(" + this.width / 2 + "," + this.height / 2 + ")");
}
var svgg = this.svg
.append("g")
.classed("svg-content-responsive", true)
.attr("transform", "translate(" + margin.left + "," + margin.top + ")");
self.svg.selectAll(".arctext").remove();
self.svg.selectAll(".pie-widget-total-label").remove();
var pie = d3.pie().sort(sort)(self.selectedData.map(function (d: any) {
return d.count;
}));
var path = d3.arc()
.outerRadius(radius)
.innerRadius(radius / 2);
var outsideLabel = d3.arc()
.outerRadius(radius * 0.9)
.innerRadius(radius * 0.9);
var middleLabel = d3.arc()
.outerRadius(radius * 0.75)
.innerRadius(radius * 0.75);
var insideLabel = d3.arc()
.outerRadius(radius * 0.6)
.innerRadius(radius * 0.6);
var g = self.svg
.attr("width", self.width + margin.left + margin.right)
.attr("height", self.height + margin.top + margin.bottom)
.append("g")
.attr("transform", "translate(" + self.width / 2 + "," + self.height / 2 + ")");
var defs = g.append("defs");
var lightGradients = defs.selectAll(".arc")
.data(pie)
.enter()
.append("radialGradient")
.attr("id", function (d: any) {
return "lightGradient-" + instanceId + "-" + d.index;
})
.attr("gradientUnits", "userSpaceOnUse")
.attr("cx", "0")
.attr("cy", "0")
.attr("r", "120%");
var darkGradients = defs.selectAll(".arc")
.data(pie)
.enter()
.append("radialGradient")
.attr("id", function (d: any) {
return "darkGradient-" + instanceId + "-" + d.index;
})
.attr("gradientUnits", "userSpaceOnUse")
.attr("cx", "0")
.attr("cy", "0")
.attr("r", "120%");
lightGradients.append("stop")
.attr("offset", "0%")
.attr("style", function (d: any) {
return "stop-color: " + d3.color(color(d.index)) + ";";
});
lightGradients.append("stop")
.attr("offset", "100%")
.attr("style", function (d: any) {
return "stop-color: black;";
});
darkGradients.append("stop")
.attr("offset", "0%")
.attr("style", function (d: any) {
return "stop-color: " + d3.color(color(d.index)).darker(0.5) + ";";
});
darkGradients.append("stop")
.attr("offset", "100%")
.attr("style", function (d: any) {
return "stop-color: black;";
});
self.tooltip = d3.select("body")
.append("div")
.attr("class", "pie-widget-tooltip")
.style("opacity", 0);
self.arc = g.selectAll(".arc")
.data(pie)
.enter()
.append("g")
.attr("class", "arc");
var arcpath = self.arc.append("path")
.attr("id", function (d: any) {
return d.index;
})
.attr("d", path)
.attr("stroke", "white")
.attr("stroke-width", "2px")
.attr("fill", function (d: any) {
return "url(#lightGradient-" + instanceId + "-" + d.index + ")";
})
.on("click", function (d: any) {
console.log("About to send::::" + getStudyLabel(d.index));
self.selectedIndustryTypeService.sendMessage(getStudyLabel(d.index));
self.showDialog();
self.rotateChart();
})
.transition()
.duration(function(d:any, i:any) {
return i * 800;
})
.attrTween('d', function(d:any) {
var i = d3.interpolate(d.startAngle + 0.1, d.endAngle);
return function (t: any) {
d.endAngle = i(t);
return path(d);
}
});
function arcTween(a: any) {
var i = d3.interpolate(this._current, a);
this._current = i(0);
return function(t: any) {
return path(i(t));
};
}
var gtext = self.svg
.append("g")
.attr("transform", "translate(" + self.width / 2 + "," + self.height / 2 + ")");
var arctext = gtext.selectAll(".arctext")
.data(pie)
.enter()
.append("g")
.attr("class", "arctext");
var primaryLabelText = arctext.append("text")
.on("click", function (d: any) {
console.log("About to send::::" + getStudyLabel(d.index));
self.selectedIndustryTypeService.sendMessage(getStudyLabel(d.index));
self.showDialog();
})
.transition()
.duration(750)
.attr("transform", function (d: any) {
return "translate(" + middleLabel.centroid(d) + ")";
})
.attr("dy", "-0.75em")
.attr("font-family", "sans-serif")
.attr("font-size", "15px")
.attr("class", "sponsor-pie-widget-label")
.text(function (d: any) {
if (d.endAngle - d.startAngle < 0.3) {
return "";
} else {
return getStudyLabel(d.index);
}
});
var secondaryLabelText = arctext.append("text")
.on("click", function (d: any) {
console.log("About to send::::" + getStudyLabel(d.index));
self.selectedIndustryTypeService.sendMessage(getStudyLabel(d.index));
self.showDialog();
})
.transition()
.duration(750)
.attr("transform", function (d: any) {
return "translate(" + middleLabel.centroid(d) + ")";
})
.attr("dy", "0.75em")
.attr("font-family", "sans-serif")
.attr("font-size", "10px")
.attr("class", "sponsor-pie-widget-label")
.text(function (d: any) {
if (d.endAngle - d.startAngle < 0.3) {
return "";
} else {
return getPatientsLabel(d.index);
}
});
var n = 0;
for (var i = 0; i < self.selectedData.length; i++) {
n = n + this.selectedData[i]["count"];
}
var total = self.svg
.append("g")
.attr("transform", "translate(" + (self.width / 2 - 20 ) + "," + self.height / 2 + ")")
total.append("text")
.attr("class", "pie-widget-total-label")
.text("Total\r\n" + n);
}.bind(self);
self.showDialog = function() {
this.router.navigateByUrl('/myRouteName');
}.bind(self);
self.rotateChart = function() {
self.arc.attr("transform", "rotate(-45)");
}.bind(self);
推荐答案
您可以通过适当地更改圆弧的开始/结束角度来旋转圆弧,但这会比所需的复杂.
You could rotate the arcs by changing their start/end angles as appropriate, but this would be more complex than needed.
一种更简单的解决方案是只旋转保存整个饼图的 g
,同时以其他方式旋转所有标签,以使它们保持水平.
A simpler solution would be to just rotate a g
that holds the entire pie chart, at the same time, rotate any labels the other way so they remain level.
我刚刚使用了此区块中的规范饼图作为示例:
I've just used the canonical pie chart from this block as an example:
var svg = d3.select("svg"),
width = +svg.attr("width"),
height = +svg.attr("height"),
radius = Math.min(width, height) / 2,
g = svg.append("g").attr("transform", "translate(" + width / 2 + "," + height / 2 + ")");
var color = d3.scaleOrdinal(["#98abc5", "#8a89a6", "#7b6888", "#6b486b", "#a05d56", "#d0743c", "#ff8c00"]);
var data = [ {age:"<5", population: 2704659},{age:"5-13", population: 4499890},{age:"14-17", population: 2159981},{age:"18-24", population: 3853788},{age:"25-44", population: 14106543},{age:"45-64", population: 8819342},{age:"≥65", population: 612463} ]
var pie = d3.pie()
.sort(null)
.value(function(d) { return d.population; });
var path = d3.arc()
.outerRadius(radius - 10)
.innerRadius(0);
var label = d3.arc()
.outerRadius(radius - 40)
.innerRadius(radius - 40);
var arc = g.selectAll(".arc")
.data(pie(data))
.enter().append("g")
.attr("class", "arc");
arc.append("path")
.attr("d", path)
.attr("fill", function(d) { return color(d.data.age); })
.on("click",function(d) {
// The amount we need to rotate:
var rotate = 180-(d.startAngle + d.endAngle)/2 / Math.PI * 180;
// Transition the pie chart
g.transition()
.attr("transform", "translate(" + width / 2 + "," + height / 2 + ") rotate(" + rotate + ")")
.duration(1000);
// Τransition the labels:
text.transition()
.attr("transform", function(dd) {
return "translate(" + label.centroid(dd) + ") rotate(" + (-rotate) + ")"; })
.duration(1000);
});
var text = arc.append("text")
.attr("transform", function(d) { return "translate(" + label.centroid(d) + ")"; })
.attr("dy", "0.35em")
.text(function(d) { return d.data.age; });
.arc text {
font: 10px sans-serif;
text-anchor: middle;
}
.arc path {
stroke: #fff;
}
<svg width="960" height="500"></svg>
<script src="https://d3js.org/d3.v4.min.js"></script>
这篇关于如何旋转D3图表以使选定的弧线位于底部?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!