切片移出 d3.js 切片点击
Slice move out in d3.js slice click
大家好,我是 d3.js 图表的新手,我想在 3D Donut . Please go tho this link Basic Donut Chart ,I want add segment click feature into 3D Donut 中添加一些额外的东西。我试试下面的代码
var arc = d3.svg.arc()
.outerRadius(ir+10);
slices.selectAll("path").on("click",function(d){
d3.select(this)
.attr("stroke","white")
.transition()
.duration(1000)
.attr("d", arc)
.attr("stroke-width",6);
})
与 3D Donut 但未按预期工作。请帮助我实现这一目标。工作示例代码将不胜感激。
谢谢.
在 SVG 元素中添加 onclick
var svg = d3.select("body").append("svg")
//other code
.on('click', function(d,i){ });
这有点烦人。由于每个切片由多条路径组成,我起初认为您可以将它们分组为一个 g
,然后在单击时将其转换为 "bump out"。但看起来“3D 甜甜圈”的作者依赖于绘图堆栈 "hide" 片在彼此后面。因此,我必须为每个片段分配一个唯一的 class,这样我才能找到属于一个切片的所有片段。之后你可以沿着它们的角度的中点将它们转换出来:
function clickHandler(d, i) {
var self = d3.select(this),
pieces = ['innerSlice', 'topSlice', 'outerSlice', 'percent'],
c = self.attr("class").split(" ")[1];
if (self.attr("transform")) {
pieces.forEach(function(d) {
slices.select("." + d + "." + c)
.attr("transform", null);
});
} else {
var a = (d.endAngle + d.startAngle) / 2,
x = (ir + 15) * Math.cos(a),
y = (ir + 15) * Math.sin(a);
pieces.forEach(function(d) {
slices.select("." + d + "." + c)
.attr("transform", "translate(" + [x, y] + ")");
});
}
}
}
这是 运行 代码:
<!DOCTYPE html>
<head>
<meta charset="utf-8">
<style>
body {
font-family: "Helvetica Neue", Helvetica, Arial, sans-serif;
width: 960px;
height: 500px;
position: relative;
}
path.slice {
stroke-width: 2px;
}
polyline {
opacity: .3;
stroke: black;
stroke-width: 2px;
fill: none;
}
svg text.percent {
fill: white;
text-anchor: middle;
font-size: 12px;
}
</style>
<script>
! function() {
var Donut3D = {};
function pieTop(d, rx, ry, ir) {
if (d.endAngle - d.startAngle == 0) return "M 0 0";
var sx = rx * Math.cos(d.startAngle),
sy = ry * Math.sin(d.startAngle),
ex = rx * Math.cos(d.endAngle),
ey = ry * Math.sin(d.endAngle);
var ret = [];
ret.push("M", sx, sy, "A", rx, ry, "0", (d.endAngle - d.startAngle > Math.PI ? 1 : 0), "1", ex, ey, "L", ir * ex, ir * ey);
ret.push("A", ir * rx, ir * ry, "0", (d.endAngle - d.startAngle > Math.PI ? 1 : 0), "0", ir * sx, ir * sy, "z");
return ret.join(" ");
}
function pieOuter(d, rx, ry, h) {
var startAngle = (d.startAngle > Math.PI ? Math.PI : d.startAngle);
var endAngle = (d.endAngle > Math.PI ? Math.PI : d.endAngle);
var sx = rx * Math.cos(startAngle),
sy = ry * Math.sin(startAngle),
ex = rx * Math.cos(endAngle),
ey = ry * Math.sin(endAngle);
var ret = [];
ret.push("M", sx, h + sy, "A", rx, ry, "0 0 1", ex, h + ey, "L", ex, ey, "A", rx, ry, "0 0 0", sx, sy, "z");
return ret.join(" ");
}
function pieInner(d, rx, ry, h, ir) {
var startAngle = (d.startAngle < Math.PI ? Math.PI : d.startAngle);
var endAngle = (d.endAngle < Math.PI ? Math.PI : d.endAngle);
var sx = ir * rx * Math.cos(startAngle),
sy = ir * ry * Math.sin(startAngle),
ex = ir * rx * Math.cos(endAngle),
ey = ir * ry * Math.sin(endAngle);
var ret = [];
ret.push("M", sx, sy, "A", ir * rx, ir * ry, "0 0 1", ex, ey, "L", ex, h + ey, "A", ir * rx, ir * ry, "0 0 0", sx, h + sy, "z");
return ret.join(" ");
}
function getPercent(d) {
return (d.endAngle - d.startAngle > 0.2 ?
Math.round(1000 * (d.endAngle - d.startAngle) / (Math.PI * 2)) / 10 + '%' : '');
}
Donut3D.transition = function(id, data, rx, ry, h, ir) {
function arcTweenInner(a) {
var i = d3.interpolate(this._current, a);
this._current = i(0);
return function(t) {
return pieInner(i(t), rx + 0.5, ry + 0.5, h, ir);
};
}
function arcTweenTop(a) {
var i = d3.interpolate(this._current, a);
this._current = i(0);
return function(t) {
return pieTop(i(t), rx, ry, ir);
};
}
function arcTweenOuter(a) {
var i = d3.interpolate(this._current, a);
this._current = i(0);
return function(t) {
return pieOuter(i(t), rx - .5, ry - .5, h);
};
}
function textTweenX(a) {
var i = d3.interpolate(this._current, a);
this._current = i(0);
return function(t) {
return 0.6 * rx * Math.cos(0.5 * (i(t).startAngle + i(t).endAngle));
};
}
function textTweenY(a) {
var i = d3.interpolate(this._current, a);
this._current = i(0);
return function(t) {
return 0.6 * rx * Math.sin(0.5 * (i(t).startAngle + i(t).endAngle));
};
}
var _data = d3.layout.pie().sort(null).value(function(d) {
return d.value;
})(data);
d3.select("#" + id).selectAll(".innerSlice").data(_data)
.transition().duration(750).attrTween("d", arcTweenInner);
d3.select("#" + id).selectAll(".topSlice").data(_data)
.transition().duration(750).attrTween("d", arcTweenTop);
d3.select("#" + id).selectAll(".outerSlice").data(_data)
.transition().duration(750).attrTween("d", arcTweenOuter);
d3.select("#" + id).selectAll(".percent").data(_data).transition().duration(750)
.attrTween("x", textTweenX).attrTween("y", textTweenY).text(getPercent);
}
Donut3D.draw = function(id, data, x /*center x*/ , y /*center y*/ ,
rx /*radius x*/ , ry /*radius y*/ , h /*height*/ , ir /*inner radius*/ ) {
var _data = d3.layout.pie().sort(null).value(function(d) {
return d.value;
})(data);
var slices = d3.select("#" + id).append("g").attr("transform", "translate(" + x + "," + y + ")")
.attr("class", "slices");
slices.selectAll(".innerSlice").data(_data).enter().append("path")
.style("fill", function(d) {
return d3.hsl(d.data.color).darker(0.7);
})
.attr("d", function(d) {
return pieInner(d, rx + 0.5, ry + 0.5, h, ir);
})
.attr("class", function(d) {
return "innerSlice slice-" + d.data.label;
})
.each(function(d) {
this._current = d;
})
.on('click', clickHandler);
slices.selectAll(".topSlice").data(_data).enter().append("path")
.style("fill", function(d) {
return d.data.color;
})
.style("stroke", function(d) {
return d.data.color;
})
.attr("d", function(d) {
return pieTop(d, rx, ry, ir);
})
.each(function(d) {
this._current = d;
})
.attr("class", function(d) {
return "topSlice slice-" + d.data.label;
})
.on('click', clickHandler);
slices.selectAll(".outerSlice").data(_data).enter().append("path")
.style("fill", function(d) {
return d3.hsl(d.data.color).darker(0.7);
})
.attr("d", function(d) {
return pieOuter(d, rx - .5, ry - .5, h);
})
.attr("class", function(d) {
return "outerSlice slice-" + d.data.label;
})
.each(function(d) {
this._current = d;
})
.on('click', clickHandler);
slices.selectAll(".percent").data(_data).enter().append("text")
.attr("class", function(d) {
return "percent slice-" + d.data.label;
})
.attr("x", function(d) {
return 0.6 * rx * Math.cos(0.5 * (d.startAngle + d.endAngle));
})
.attr("y", function(d) {
return 0.6 * ry * Math.sin(0.5 * (d.startAngle + d.endAngle));
})
.text(getPercent).each(function(d) {
this._current = d;
})
.on('click', clickHandler);
function clickHandler(d, i) {
var self = d3.select(this),
jC = self.attr("transform");
slices.selectAll('path, text').each(function(d) {
d3.select(this)
.attr("transform", null);
});
if (jC) return;
var self = d3.select(this),
pieces = ['innerSlice', 'topSlice', 'outerSlice', 'percent'],
c = self.attr("class").split(" ")[1],
a = (d.endAngle + d.startAngle) / 2,
x = (ir + 15) * Math.cos(a),
y = (ir + 15) * Math.sin(a);
pieces.forEach(function(d) {
slices.select("." + d + "." + c)
.attr("transform", "translate(" + [x, y] + ")");
});
}
}
this.Donut3D = Donut3D;
}();
</script>
</head>
<body>
<button onClick="changeData()">Change Data</button>
<script src="http://d3js.org/d3.v3.min.js"></script>
<script src="Donut3D.js"></script>
<script>
var salesData = [{
label: "Basic",
color: "#3366CC"
}, {
label: "Plus",
color: "#DC3912"
}, {
label: "Lite",
color: "#FF9900"
}, {
label: "Elite",
color: "#109618"
}, {
label: "Delux",
color: "#990099"
}];
var svg = d3.select("body").append("svg").attr("width", 700).attr("height", 300);
svg.append("g").attr("id", "salesDonut");
svg.append("g").attr("id", "quotesDonut");
Donut3D.draw("salesDonut", randomData(), 150, 150, 130, 100, 30, 0.4);
Donut3D.draw("quotesDonut", randomData(), 450, 150, 130, 100, 30, 0);
function changeData() {
Donut3D.transition("salesDonut", randomData(), 130, 100, 30, 0.4);
Donut3D.transition("quotesDonut", randomData(), 130, 100, 30, 0);
}
function randomData() {
return salesData.map(function(d) {
return {
label: d.label,
value: 1000 * Math.random(),
color: d.color
};
});
}
</script>
</body>
大家好,我是 d3.js 图表的新手,我想在 3D Donut . Please go tho this link Basic Donut Chart ,I want add segment click feature into 3D Donut 中添加一些额外的东西。我试试下面的代码
var arc = d3.svg.arc()
.outerRadius(ir+10);
slices.selectAll("path").on("click",function(d){
d3.select(this)
.attr("stroke","white")
.transition()
.duration(1000)
.attr("d", arc)
.attr("stroke-width",6);
})
与 3D Donut 但未按预期工作。请帮助我实现这一目标。工作示例代码将不胜感激。
谢谢.
在 SVG 元素中添加 onclick
var svg = d3.select("body").append("svg")
//other code
.on('click', function(d,i){ });
这有点烦人。由于每个切片由多条路径组成,我起初认为您可以将它们分组为一个 g
,然后在单击时将其转换为 "bump out"。但看起来“3D 甜甜圈”的作者依赖于绘图堆栈 "hide" 片在彼此后面。因此,我必须为每个片段分配一个唯一的 class,这样我才能找到属于一个切片的所有片段。之后你可以沿着它们的角度的中点将它们转换出来:
function clickHandler(d, i) {
var self = d3.select(this),
pieces = ['innerSlice', 'topSlice', 'outerSlice', 'percent'],
c = self.attr("class").split(" ")[1];
if (self.attr("transform")) {
pieces.forEach(function(d) {
slices.select("." + d + "." + c)
.attr("transform", null);
});
} else {
var a = (d.endAngle + d.startAngle) / 2,
x = (ir + 15) * Math.cos(a),
y = (ir + 15) * Math.sin(a);
pieces.forEach(function(d) {
slices.select("." + d + "." + c)
.attr("transform", "translate(" + [x, y] + ")");
});
}
}
}
这是 运行 代码:
<!DOCTYPE html>
<head>
<meta charset="utf-8">
<style>
body {
font-family: "Helvetica Neue", Helvetica, Arial, sans-serif;
width: 960px;
height: 500px;
position: relative;
}
path.slice {
stroke-width: 2px;
}
polyline {
opacity: .3;
stroke: black;
stroke-width: 2px;
fill: none;
}
svg text.percent {
fill: white;
text-anchor: middle;
font-size: 12px;
}
</style>
<script>
! function() {
var Donut3D = {};
function pieTop(d, rx, ry, ir) {
if (d.endAngle - d.startAngle == 0) return "M 0 0";
var sx = rx * Math.cos(d.startAngle),
sy = ry * Math.sin(d.startAngle),
ex = rx * Math.cos(d.endAngle),
ey = ry * Math.sin(d.endAngle);
var ret = [];
ret.push("M", sx, sy, "A", rx, ry, "0", (d.endAngle - d.startAngle > Math.PI ? 1 : 0), "1", ex, ey, "L", ir * ex, ir * ey);
ret.push("A", ir * rx, ir * ry, "0", (d.endAngle - d.startAngle > Math.PI ? 1 : 0), "0", ir * sx, ir * sy, "z");
return ret.join(" ");
}
function pieOuter(d, rx, ry, h) {
var startAngle = (d.startAngle > Math.PI ? Math.PI : d.startAngle);
var endAngle = (d.endAngle > Math.PI ? Math.PI : d.endAngle);
var sx = rx * Math.cos(startAngle),
sy = ry * Math.sin(startAngle),
ex = rx * Math.cos(endAngle),
ey = ry * Math.sin(endAngle);
var ret = [];
ret.push("M", sx, h + sy, "A", rx, ry, "0 0 1", ex, h + ey, "L", ex, ey, "A", rx, ry, "0 0 0", sx, sy, "z");
return ret.join(" ");
}
function pieInner(d, rx, ry, h, ir) {
var startAngle = (d.startAngle < Math.PI ? Math.PI : d.startAngle);
var endAngle = (d.endAngle < Math.PI ? Math.PI : d.endAngle);
var sx = ir * rx * Math.cos(startAngle),
sy = ir * ry * Math.sin(startAngle),
ex = ir * rx * Math.cos(endAngle),
ey = ir * ry * Math.sin(endAngle);
var ret = [];
ret.push("M", sx, sy, "A", ir * rx, ir * ry, "0 0 1", ex, ey, "L", ex, h + ey, "A", ir * rx, ir * ry, "0 0 0", sx, h + sy, "z");
return ret.join(" ");
}
function getPercent(d) {
return (d.endAngle - d.startAngle > 0.2 ?
Math.round(1000 * (d.endAngle - d.startAngle) / (Math.PI * 2)) / 10 + '%' : '');
}
Donut3D.transition = function(id, data, rx, ry, h, ir) {
function arcTweenInner(a) {
var i = d3.interpolate(this._current, a);
this._current = i(0);
return function(t) {
return pieInner(i(t), rx + 0.5, ry + 0.5, h, ir);
};
}
function arcTweenTop(a) {
var i = d3.interpolate(this._current, a);
this._current = i(0);
return function(t) {
return pieTop(i(t), rx, ry, ir);
};
}
function arcTweenOuter(a) {
var i = d3.interpolate(this._current, a);
this._current = i(0);
return function(t) {
return pieOuter(i(t), rx - .5, ry - .5, h);
};
}
function textTweenX(a) {
var i = d3.interpolate(this._current, a);
this._current = i(0);
return function(t) {
return 0.6 * rx * Math.cos(0.5 * (i(t).startAngle + i(t).endAngle));
};
}
function textTweenY(a) {
var i = d3.interpolate(this._current, a);
this._current = i(0);
return function(t) {
return 0.6 * rx * Math.sin(0.5 * (i(t).startAngle + i(t).endAngle));
};
}
var _data = d3.layout.pie().sort(null).value(function(d) {
return d.value;
})(data);
d3.select("#" + id).selectAll(".innerSlice").data(_data)
.transition().duration(750).attrTween("d", arcTweenInner);
d3.select("#" + id).selectAll(".topSlice").data(_data)
.transition().duration(750).attrTween("d", arcTweenTop);
d3.select("#" + id).selectAll(".outerSlice").data(_data)
.transition().duration(750).attrTween("d", arcTweenOuter);
d3.select("#" + id).selectAll(".percent").data(_data).transition().duration(750)
.attrTween("x", textTweenX).attrTween("y", textTweenY).text(getPercent);
}
Donut3D.draw = function(id, data, x /*center x*/ , y /*center y*/ ,
rx /*radius x*/ , ry /*radius y*/ , h /*height*/ , ir /*inner radius*/ ) {
var _data = d3.layout.pie().sort(null).value(function(d) {
return d.value;
})(data);
var slices = d3.select("#" + id).append("g").attr("transform", "translate(" + x + "," + y + ")")
.attr("class", "slices");
slices.selectAll(".innerSlice").data(_data).enter().append("path")
.style("fill", function(d) {
return d3.hsl(d.data.color).darker(0.7);
})
.attr("d", function(d) {
return pieInner(d, rx + 0.5, ry + 0.5, h, ir);
})
.attr("class", function(d) {
return "innerSlice slice-" + d.data.label;
})
.each(function(d) {
this._current = d;
})
.on('click', clickHandler);
slices.selectAll(".topSlice").data(_data).enter().append("path")
.style("fill", function(d) {
return d.data.color;
})
.style("stroke", function(d) {
return d.data.color;
})
.attr("d", function(d) {
return pieTop(d, rx, ry, ir);
})
.each(function(d) {
this._current = d;
})
.attr("class", function(d) {
return "topSlice slice-" + d.data.label;
})
.on('click', clickHandler);
slices.selectAll(".outerSlice").data(_data).enter().append("path")
.style("fill", function(d) {
return d3.hsl(d.data.color).darker(0.7);
})
.attr("d", function(d) {
return pieOuter(d, rx - .5, ry - .5, h);
})
.attr("class", function(d) {
return "outerSlice slice-" + d.data.label;
})
.each(function(d) {
this._current = d;
})
.on('click', clickHandler);
slices.selectAll(".percent").data(_data).enter().append("text")
.attr("class", function(d) {
return "percent slice-" + d.data.label;
})
.attr("x", function(d) {
return 0.6 * rx * Math.cos(0.5 * (d.startAngle + d.endAngle));
})
.attr("y", function(d) {
return 0.6 * ry * Math.sin(0.5 * (d.startAngle + d.endAngle));
})
.text(getPercent).each(function(d) {
this._current = d;
})
.on('click', clickHandler);
function clickHandler(d, i) {
var self = d3.select(this),
jC = self.attr("transform");
slices.selectAll('path, text').each(function(d) {
d3.select(this)
.attr("transform", null);
});
if (jC) return;
var self = d3.select(this),
pieces = ['innerSlice', 'topSlice', 'outerSlice', 'percent'],
c = self.attr("class").split(" ")[1],
a = (d.endAngle + d.startAngle) / 2,
x = (ir + 15) * Math.cos(a),
y = (ir + 15) * Math.sin(a);
pieces.forEach(function(d) {
slices.select("." + d + "." + c)
.attr("transform", "translate(" + [x, y] + ")");
});
}
}
this.Donut3D = Donut3D;
}();
</script>
</head>
<body>
<button onClick="changeData()">Change Data</button>
<script src="http://d3js.org/d3.v3.min.js"></script>
<script src="Donut3D.js"></script>
<script>
var salesData = [{
label: "Basic",
color: "#3366CC"
}, {
label: "Plus",
color: "#DC3912"
}, {
label: "Lite",
color: "#FF9900"
}, {
label: "Elite",
color: "#109618"
}, {
label: "Delux",
color: "#990099"
}];
var svg = d3.select("body").append("svg").attr("width", 700).attr("height", 300);
svg.append("g").attr("id", "salesDonut");
svg.append("g").attr("id", "quotesDonut");
Donut3D.draw("salesDonut", randomData(), 150, 150, 130, 100, 30, 0.4);
Donut3D.draw("quotesDonut", randomData(), 450, 150, 130, 100, 30, 0);
function changeData() {
Donut3D.transition("salesDonut", randomData(), 130, 100, 30, 0.4);
Donut3D.transition("quotesDonut", randomData(), 130, 100, 30, 0);
}
function randomData() {
return salesData.map(function(d) {
return {
label: d.label,
value: 1000 * Math.random(),
color: d.color
};
});
}
</script>
</body>