d3v4 Saw Chart -- 半饼图示例和基于圆弧的示例
d3v4 Saw Chart -- half pie chart example and arc based example
我对创建以下模型很感兴趣——其中只呈现了一半的饼图——并且这些段在此曲线中聚成一团。
我已经调整了半饼图来调用类似的方法——但我不确定如何修改圆弧示例以产生相同且更理想的效果——因为没有使用 d3.pie设置 start/end 角度。我正在操纵弧的 start/end 角度,但不确定如何稍微调整它 - 而不会破坏它。
你能做点什么吗
var arc = d3.arc()
.startAngle(-90 * (Math.PI / 180))
.endAngle(120 * (Math.PI / 180))
//只有普通饼图功能的版本
https://jsfiddle.net/wqLzbhud/
//当前版本的弧长相同但高度不同。
https://jsfiddle.net/wqLzbhud/1/
function getArc(){
var arc = d3.arc()
.innerRadius(function(d, i){
return radius-innerradius;
})
.outerRadius(function(d){
var maxHeight = height/2;
var ratio = (d.value/maxHeight * 100)+ radius;
return ratio;
})
.startAngle(function(d, i){
return d.startAngle;
})
.endAngle(function(d, i){
return d.endAngle;
});
return arc;
}
function setData(data, isSorted){
var displacement = 0;
var arcPartition = 2*Math.PI/data.length;
$.each(data, function(ri, value) {
var startAngle = (ri*arcPartition);
var endAngle = ((ri+1)*arcPartition);
if(ri!=0){
startAngle+=displacement;
endAngle+=displacement;
}
data[ri]["startAngle"] = startAngle;
data[ri]["endAngle"] = endAngle;
});
return data;
}
最新代码库 2020 年 6 月 17 日
如本文档中所述,我们可以使用弧度来指定角度。
http://using-d3js.com/05_07_arcs_pie_charts.html
From Documentation: Angles are specified in radians where 0 radians is at 12 o’clock and positive radians trace a path clockwise
0 - 12 O'clock
Math.PI/4 - Half-past one
Math.PI/2 - 3 O'clock
3 * Math.PI/4 - Half-past four
Math.PI - 6 O'clock
5 * Math.PI/4 - Half-past seven
3 * Math.PI/2 - 9 O'clock
7 * Math.PI/4 - Half-past ten
2 * Math.PI - It's again at 12 O'clock
Same works for negative radians, just it will be anti-clockwise
所以在你的情况下,它将是:
.startAngle(-Math.PI / 2)
.endAngle((3 * Math.PI) / 4)
负值将从逆时针方向开始角度。
为了生成不同高度的段,我们可以根据需要以任何方式为每个段修改它,而不是仅仅提供上面创建的弧对象。
// .attr("d", arc)
.attr("d", function (d, i) {
return arc.outerRadius(data[i].outerRadius)(d, i);
})
看看下面的例子,我刚刚修改了你上面分享的jsfiddle例子。如果您有任何问题,请告诉我。
$(document).ready(function() {
var $this = $(".sawchart");
var data = [{
label: "Jam",
value: 5
},
{
label: "Coconut",
value: 15
},
{
label: "Nutmeg",
value: 30
},
{
label: "Tumeric",
value: 50
},
];
var width = $this.data("width"),
height = $this.data("height"),
radius = $this.data("r"),
innerradius = $this.data("ir");
var color = d3
.scaleOrdinal()
.range(["#f0cf85", "#e7f0c3", "#a4d4ae", "#32afa9"]);
var arc = d3
.arc()
.outerRadius(radius)
.innerRadius(innerradius);
var labelArc = d3
.arc()
.outerRadius(radius - 40)
.innerRadius(radius - 40);
var total = 0
data.forEach(function(d) {
total += d.value;
});
//add outer Radius to d object
data.forEach(function(d) {
d.outerRadius = ((d.value / total) * 100) + radius;
});
/**
* Notice I have used Math.PI to generate angle
* From Documentation: Angles are specified in radians where 0 radians is at 12 o’clock and positive radians trace a path clockwise
* 0 - 12 O'clock
* Math.PI/4 - Half past one
* Math.PI/2 - 3 O'clock
* 3 * Math.PI/4 - Half past four
* Math.PI - 6 O'clock
* 5 * Math.PI/4 - Half past seven
* 3 * Math.PI/2 - 9 O'clock
* 7 * Math.PI/4 - Half past ten
* 2 * Math.PI - It's again 12 O'clock
*
* Same works for negative radians, just it will be anti-clockwise
*/
var pie = d3
.pie()
.startAngle(-Math.PI / 2)
.endAngle((3 * Math.PI) / 4)
.sort(null)
.value(function(d) {
return total;
});
var pieData = pie(data);
var svg = d3
.select($this[0])
.append("svg")
.attr("width", width)
.attr("height", height)
.append("g")
.attr("class", "piechart")
.attr("transform", "translate(" + width / 2 + "," + height / 2 + ")");
var segments = svg.append("g").attr("class", "segments");
var slices = segments
.selectAll(".arc")
.data(pieData)
.enter()
.append("g")
.attr("class", "arc");
/**
* Here instead of just providing arc created above, we can modify it for each segment in whatever manner we want to.
* I have changed OuterRadius for each from Data
*/
slices
.append("path")
// .attr("d", arc)
.attr("d", function(d, i) {
return arc.outerRadius(d.data.outerRadius)(d, i);
})
.attr("fill", function(d, i) {
return color(i);
});
//__labels
var labels = svg.append("g").attr("class", "labels");
var label = labels
.selectAll("text")
.data(pieData)
.enter()
.append("text")
.attr("text-anchor", "middle");
label
.attr("x", function(d) {
var a = d.startAngle + (d.endAngle - d.startAngle) / 2 - Math.PI / 2;
d.cx = Math.cos(a) * (innerradius + (d.data.outerRadius - innerradius) / 2);
return (d.x = Math.cos(a) * (d.data.outerRadius + 20));
})
.attr("y", function(d) {
var a = d.startAngle + (d.endAngle - d.startAngle) / 2 - Math.PI / 2;
d.cy = Math.sin(a) * (innerradius + (d.data.outerRadius - innerradius) / 2);
return (d.y = Math.sin(a) * (d.data.outerRadius + 20));
})
.text(function(d) {
return d.data.label;
})
.each(function(d) {
var bbox = this.getBBox();
d.sx = d.x - bbox.width / 2 - 2;
d.ox = d.x + bbox.width / 2 + 2;
d.sy = d.oy = d.y + 5;
})
.transition()
.duration(300);
labels.transition().duration(300);
labels.exit().remove();
//__labels
//__pointers
var pointers = svg.append("g").attr("class", "pointers");
pointers
.append("defs")
.append("marker")
.attr("id", "circ")
.attr("markerWidth", 6)
.attr("markerHeight", 6)
.attr("refX", 3)
.attr("refY", 3)
.append("circle")
.attr("cx", 3)
.attr("cy", 3)
.attr("r", 3);
var pointer = pointers
.selectAll("path.pointer")
.data(pieData)
.enter()
.append("path")
.attr("class", "pointer")
.style("fill", "none")
.style("stroke", "black")
.attr("marker-end", "url(#circ)");
pointer
.attr("d", function(d) {
if (d.cx > d.ox) {
return (
"M" +
d.sx +
"," +
d.sy +
"L" +
d.ox +
"," +
d.oy +
" " +
d.cx +
"," +
d.cy
);
} else {
return (
"M" +
d.ox +
"," +
d.oy +
"L" +
d.sx +
"," +
d.sy +
" " +
d.cx +
"," +
d.cy
);
}
})
.transition()
.duration(300);
pointers.transition().duration(300);
pointers.exit().remove();
//__pointers
});
body {
background: #ffd;
}
.arc text {
font: 10px sans-serif;
text-anchor: middle;
}
.arc path {
stroke: #fff;
}
<script src="https://d3js.org/d3.v4.min.js"></script>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.2.1/jquery.min.js"></script>
<h1>SawChart I</h1>
<!--html-->
<div
class="sawchart"
data-width="500"
data-height="500"
data-r="110"
data-ir="60"
/>
---编辑---
我根据输入值创建了一个动态的外半径,而不是从输入中指定它。
//add outer Radius to d object
data.forEach(function(d) {
d.outerRadius = ((d.value / total) * 100) + radius;
});
.
.
.
.attr("d", function(d, i) {
return arc.outerRadius(d.data.outerRadius)(d, i);
})
另外,以同样的方式更新标签的位置:
label
.attr("x", function(d) {
var a = d.startAngle + (d.endAngle - d.startAngle) / 2 - Math.PI / 2;
d.cx = Math.cos(a) * (innerradius + (d.data.outerRadius - innerradius) / 2);
return (d.x = Math.cos(a) * (d.data.outerRadius + 20));
})
.attr("y", function(d) {
var a = d.startAngle + (d.endAngle - d.startAngle) / 2 - Math.PI / 2;
d.cy = Math.sin(a) * (innerradius + (d.data.outerRadius - innerradius) / 2);
return (d.y = Math.sin(a) * (d.data.outerRadius + 20));
})
我对创建以下模型很感兴趣——其中只呈现了一半的饼图——并且这些段在此曲线中聚成一团。
我已经调整了半饼图来调用类似的方法——但我不确定如何修改圆弧示例以产生相同且更理想的效果——因为没有使用 d3.pie设置 start/end 角度。我正在操纵弧的 start/end 角度,但不确定如何稍微调整它 - 而不会破坏它。 你能做点什么吗
var arc = d3.arc()
.startAngle(-90 * (Math.PI / 180))
.endAngle(120 * (Math.PI / 180))
//只有普通饼图功能的版本 https://jsfiddle.net/wqLzbhud/
//当前版本的弧长相同但高度不同。 https://jsfiddle.net/wqLzbhud/1/
function getArc(){
var arc = d3.arc()
.innerRadius(function(d, i){
return radius-innerradius;
})
.outerRadius(function(d){
var maxHeight = height/2;
var ratio = (d.value/maxHeight * 100)+ radius;
return ratio;
})
.startAngle(function(d, i){
return d.startAngle;
})
.endAngle(function(d, i){
return d.endAngle;
});
return arc;
}
function setData(data, isSorted){
var displacement = 0;
var arcPartition = 2*Math.PI/data.length;
$.each(data, function(ri, value) {
var startAngle = (ri*arcPartition);
var endAngle = ((ri+1)*arcPartition);
if(ri!=0){
startAngle+=displacement;
endAngle+=displacement;
}
data[ri]["startAngle"] = startAngle;
data[ri]["endAngle"] = endAngle;
});
return data;
}
最新代码库 2020 年 6 月 17 日
如本文档中所述,我们可以使用弧度来指定角度。
http://using-d3js.com/05_07_arcs_pie_charts.html
From Documentation: Angles are specified in radians where 0 radians is at 12 o’clock and positive radians trace a path clockwise
0 - 12 O'clock
Math.PI/4 - Half-past one
Math.PI/2 - 3 O'clock
3 * Math.PI/4 - Half-past four
Math.PI - 6 O'clock
5 * Math.PI/4 - Half-past seven
3 * Math.PI/2 - 9 O'clock
7 * Math.PI/4 - Half-past ten
2 * Math.PI - It's again at 12 O'clock
Same works for negative radians, just it will be anti-clockwise
所以在你的情况下,它将是:
.startAngle(-Math.PI / 2)
.endAngle((3 * Math.PI) / 4)
负值将从逆时针方向开始角度。
为了生成不同高度的段,我们可以根据需要以任何方式为每个段修改它,而不是仅仅提供上面创建的弧对象。
// .attr("d", arc)
.attr("d", function (d, i) {
return arc.outerRadius(data[i].outerRadius)(d, i);
})
看看下面的例子,我刚刚修改了你上面分享的jsfiddle例子。如果您有任何问题,请告诉我。
$(document).ready(function() {
var $this = $(".sawchart");
var data = [{
label: "Jam",
value: 5
},
{
label: "Coconut",
value: 15
},
{
label: "Nutmeg",
value: 30
},
{
label: "Tumeric",
value: 50
},
];
var width = $this.data("width"),
height = $this.data("height"),
radius = $this.data("r"),
innerradius = $this.data("ir");
var color = d3
.scaleOrdinal()
.range(["#f0cf85", "#e7f0c3", "#a4d4ae", "#32afa9"]);
var arc = d3
.arc()
.outerRadius(radius)
.innerRadius(innerradius);
var labelArc = d3
.arc()
.outerRadius(radius - 40)
.innerRadius(radius - 40);
var total = 0
data.forEach(function(d) {
total += d.value;
});
//add outer Radius to d object
data.forEach(function(d) {
d.outerRadius = ((d.value / total) * 100) + radius;
});
/**
* Notice I have used Math.PI to generate angle
* From Documentation: Angles are specified in radians where 0 radians is at 12 o’clock and positive radians trace a path clockwise
* 0 - 12 O'clock
* Math.PI/4 - Half past one
* Math.PI/2 - 3 O'clock
* 3 * Math.PI/4 - Half past four
* Math.PI - 6 O'clock
* 5 * Math.PI/4 - Half past seven
* 3 * Math.PI/2 - 9 O'clock
* 7 * Math.PI/4 - Half past ten
* 2 * Math.PI - It's again 12 O'clock
*
* Same works for negative radians, just it will be anti-clockwise
*/
var pie = d3
.pie()
.startAngle(-Math.PI / 2)
.endAngle((3 * Math.PI) / 4)
.sort(null)
.value(function(d) {
return total;
});
var pieData = pie(data);
var svg = d3
.select($this[0])
.append("svg")
.attr("width", width)
.attr("height", height)
.append("g")
.attr("class", "piechart")
.attr("transform", "translate(" + width / 2 + "," + height / 2 + ")");
var segments = svg.append("g").attr("class", "segments");
var slices = segments
.selectAll(".arc")
.data(pieData)
.enter()
.append("g")
.attr("class", "arc");
/**
* Here instead of just providing arc created above, we can modify it for each segment in whatever manner we want to.
* I have changed OuterRadius for each from Data
*/
slices
.append("path")
// .attr("d", arc)
.attr("d", function(d, i) {
return arc.outerRadius(d.data.outerRadius)(d, i);
})
.attr("fill", function(d, i) {
return color(i);
});
//__labels
var labels = svg.append("g").attr("class", "labels");
var label = labels
.selectAll("text")
.data(pieData)
.enter()
.append("text")
.attr("text-anchor", "middle");
label
.attr("x", function(d) {
var a = d.startAngle + (d.endAngle - d.startAngle) / 2 - Math.PI / 2;
d.cx = Math.cos(a) * (innerradius + (d.data.outerRadius - innerradius) / 2);
return (d.x = Math.cos(a) * (d.data.outerRadius + 20));
})
.attr("y", function(d) {
var a = d.startAngle + (d.endAngle - d.startAngle) / 2 - Math.PI / 2;
d.cy = Math.sin(a) * (innerradius + (d.data.outerRadius - innerradius) / 2);
return (d.y = Math.sin(a) * (d.data.outerRadius + 20));
})
.text(function(d) {
return d.data.label;
})
.each(function(d) {
var bbox = this.getBBox();
d.sx = d.x - bbox.width / 2 - 2;
d.ox = d.x + bbox.width / 2 + 2;
d.sy = d.oy = d.y + 5;
})
.transition()
.duration(300);
labels.transition().duration(300);
labels.exit().remove();
//__labels
//__pointers
var pointers = svg.append("g").attr("class", "pointers");
pointers
.append("defs")
.append("marker")
.attr("id", "circ")
.attr("markerWidth", 6)
.attr("markerHeight", 6)
.attr("refX", 3)
.attr("refY", 3)
.append("circle")
.attr("cx", 3)
.attr("cy", 3)
.attr("r", 3);
var pointer = pointers
.selectAll("path.pointer")
.data(pieData)
.enter()
.append("path")
.attr("class", "pointer")
.style("fill", "none")
.style("stroke", "black")
.attr("marker-end", "url(#circ)");
pointer
.attr("d", function(d) {
if (d.cx > d.ox) {
return (
"M" +
d.sx +
"," +
d.sy +
"L" +
d.ox +
"," +
d.oy +
" " +
d.cx +
"," +
d.cy
);
} else {
return (
"M" +
d.ox +
"," +
d.oy +
"L" +
d.sx +
"," +
d.sy +
" " +
d.cx +
"," +
d.cy
);
}
})
.transition()
.duration(300);
pointers.transition().duration(300);
pointers.exit().remove();
//__pointers
});
body {
background: #ffd;
}
.arc text {
font: 10px sans-serif;
text-anchor: middle;
}
.arc path {
stroke: #fff;
}
<script src="https://d3js.org/d3.v4.min.js"></script>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.2.1/jquery.min.js"></script>
<h1>SawChart I</h1>
<!--html-->
<div
class="sawchart"
data-width="500"
data-height="500"
data-r="110"
data-ir="60"
/>
---编辑--- 我根据输入值创建了一个动态的外半径,而不是从输入中指定它。
//add outer Radius to d object
data.forEach(function(d) {
d.outerRadius = ((d.value / total) * 100) + radius;
});
.
.
.
.attr("d", function(d, i) {
return arc.outerRadius(d.data.outerRadius)(d, i);
})
另外,以同样的方式更新标签的位置:
label
.attr("x", function(d) {
var a = d.startAngle + (d.endAngle - d.startAngle) / 2 - Math.PI / 2;
d.cx = Math.cos(a) * (innerradius + (d.data.outerRadius - innerradius) / 2);
return (d.x = Math.cos(a) * (d.data.outerRadius + 20));
})
.attr("y", function(d) {
var a = d.startAngle + (d.endAngle - d.startAngle) / 2 - Math.PI / 2;
d.cy = Math.sin(a) * (innerradius + (d.data.outerRadius - innerradius) / 2);
return (d.y = Math.sin(a) * (d.data.outerRadius + 20));
})