我正在开发一个图例切换d3.js饼图应用程序,使用此jsfiddle作为我的最新版本http://jsfiddle.net/Qh9X5/3328/。
我的目标是获得一个简化的工作示例,其中图例可以切换切片,尝试停用所有切片 - 重置中的重新调整会重新激活所有切片。拆分演示文稿和应用层逻辑。
补间也需要改进 - 随着切片的出现,然后顺利地重新补间。
如何改进/修复此代码库中的各种错误?
onLegendClick: function(dt, i){
//_toggle rectangle in legend
var completeData = jQuery.extend(true, [], methods.currentDataSet);
newDataSet = completeData;
if(methods.manipulatedData){
newDataSet = methods.manipulatedData;
}
d3.selectAll('rect')
.data([dt], function(d) {
return d.data.label;
})
.style("fill-opacity", function(d, j) {
var isActive = Math.abs(1-d3.select(this).style("fill-opacity"));
if(isActive){
newDataSet[j].total = completeData[j].total;
}else{
newDataSet[j].total = 0;
}
return isActive;
});
//animate slices
methods.animateSlices(newDataSet);
//stash manipulated data
methods.manipulatedData = newDataSet;
}
答案 0 :(得分:0)
这是整个js代码 - 我已经使用了tidyup。我不确定使用快捷方式,因为我不确定这些值是否正确。最新的小提琴 - http://jsfiddle.net/Qh9X5/3340/
$(document).ready(function () {
var pieChart = {
el: "",
init: function (el, options) {
var clone = jQuery.extend(true, {}, options["data"]);
pieChart.el = el;
pieChart.setup(clone, options["width"], options["height"], options["r"], options["ir"]);
},
getArc: function (radius, innerradius) {
var arc = d3.svg.arc()
.innerRadius(innerradius)
.outerRadius(radius);
return arc;
},
setup: function (dataset, w, h, r, ir) {
var padding = 80;
this.width = w;
this.height = h;
this.radius = r
this.innerradius = ir;
this.color = d3.scale.category20();
this.pie = d3.layout.pie()
.sort(null)
.value(function (d) {
return d.total;
});
this.arc = this.getArc(this.radius, this.innerradius);
this.svg = d3.select(pieChart.el["selector"]).append("svg")
.attr("width", this.width + padding)
.attr("height", this.height + padding);
this.holder = this.svg.append("g")
.attr("transform", "translate(" + ((this.width / 2) + (padding / 2)) + "," + ((this.height / 2) + (padding / 2)) + ")");
this.piec = this.holder.append("g")
.attr("class", "piechart");
this.segments = this.holder.append("g")
.attr("class", "segments");
this.labels = this.holder.append("g")
.attr("class", "labels");
this.pointers = this.holder.append("g")
.attr("class", "pointers");
this.legend = this.svg.append("g")
.attr("class", "legend")
.attr("transform", "translate(" + -(this.width / 4) + "," + this.height + ")");
},
oldPieData: "",
pieTween: function (r, ir, d, i) {
var that = this;
var theOldDataInPie = pieChart.oldPieData;
// Interpolate the arcs in data space
var s0;
var e0;
if (theOldDataInPie[i]) {
s0 = theOldDataInPie[i].startAngle;
e0 = theOldDataInPie[i].endAngle;
} else if (!(theOldDataInPie[i]) && theOldDataInPie[i - 1]) {
s0 = theOldDataInPie[i - 1].endAngle;
e0 = theOldDataInPie[i - 1].endAngle;
} else if (!(theOldDataInPie[i - 1]) && theOldDataInPie.length > 0) {
s0 = theOldDataInPie[theOldDataInPie.length - 1].endAngle;
e0 = theOldDataInPie[theOldDataInPie.length - 1].endAngle;
} else {
s0 = 0;
e0 = 0;
}
var i = d3.interpolate({
startAngle: s0,
endAngle: e0
}, {
startAngle: d.startAngle,
endAngle: d.endAngle
});
return function (t) {
var b = i(t);
return pieChart.getArc(r, ir)(b);
};
},
removePieTween: function (r, ir, d, i) {
var that = this;
s0 = 2 * Math.PI;
e0 = 2 * Math.PI;
var i = d3.interpolate({
startAngle: d.startAngle,
endAngle: d.endAngle
}, {
startAngle: s0,
endAngle: e0
});
return function (t) {
var b = i(t);
return pieChart.getArc(r, ir)(b);
};
},
animateSlices: function (dataSet) {
var r = $(pieChart.el["selector"]).data("r");
var ir = $(pieChart.el["selector"]).data("ir");
this.piedata = pieChart.pie(dataSet);
//__slices
this.path = pieChart.segments.selectAll("path.pie")
.data(this.piedata, function (d) {
return d.data.label
});
this.path.enter().append("path")
.attr("class", "pie")
.attr("fill", function (d, i) {
return pieChart.color(i);
})
.attr("stroke", "#ffffff")
.transition()
.duration(300)
.attrTween("d", function (d, i) {
return pieChart.pieTween(r, ir, d, i);
});
this.path.transition()
.duration(300)
.attrTween("d", function (d, i) {
return pieChart.pieTween(r, ir, d, i);
});
this.path.exit()
.transition()
.duration(300)
.attrTween("d", function (d, i) {
return pieChart.removePieTween(r, ir, d, i);
})
.remove();
//__slices
//__labels
var labels = pieChart.labels.selectAll("text")
.data(this.piedata, function (d) {
return d.data.label
});
labels.enter()
.append("text")
.attr("text-anchor", "middle")
labels.attr("x", function (d) {
var a = d.startAngle + (d.endAngle - d.startAngle) / 2 - Math.PI / 2;
d.cx = Math.cos(a) * (ir + ((r - ir) / 2));
return d.x = Math.cos(a) * (r + 20);
})
.attr("y", function (d) {
var a = d.startAngle + (d.endAngle - d.startAngle) / 2 - Math.PI / 2;
d.cy = Math.sin(a) * (ir + ((r - ir) / 2));
return d.y = Math.sin(a) * (r + 20);
})
.attr("opacity", function (d) {
var opacityLevel = 1;
if (d.value == 0) {
opacityLevel = 0;
}
return opacityLevel;
})
.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
pieChart.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 pointers = pieChart.pointers.selectAll("path.pointer")
.data(this.piedata, function (d) {
return d.data.label
});
pointers.enter()
.append("path")
.attr("class", "pointer")
.style("fill", "none")
.style("stroke", "black")
.attr("marker-end", "url(#circ)");
pointers.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;
}
})
.attr("opacity", function (d) {
var opacityLevel = 1;
if (d.value == 0) {
opacityLevel = 0;
}
return opacityLevel;
})
.transition()
.duration(300)
pointers.transition()
.duration(300)
pointers.exit().remove();
},
onToggle: function (sliceData, index) {
//_toggle rectangle in legend
//_toggle slice
var completeData = jQuery.extend(true, [], pieChart.currentDataSet);
var dataLength = completeData.length;
var newDataSet = completeData;
if (pieChart.manipulatedData) {
newDataSet = pieChart.manipulatedData;
}
d3.selectAll('rect')
.data([sliceData], function (d) {
return d.data.label;
})
.style("fill-opacity", function (d) {
var isActive = Math.abs(1 - d3.select(this).style("fill-opacity"));
if (isActive) {
newDataSet[index].total = completeData[index].total;
newDataSet[index].value = completeData[index].value;
} else {
newDataSet[index].total = 0;
newDataSet[index].value = 0;
}
return isActive;
});
//if all elements are to be not shown - reset to show all slices again.
//animate slices
pieChart.animateSlices(newDataSet);
//stash manipulated data
pieChart.manipulatedData = newDataSet;
},
update: function (el, dataSet) {
var that = this;
pieChart.el = el;
pieChart.svg = d3.select(pieChart.el["selector"] + " .piechart");
pieChart.segments = d3.select(pieChart.el["selector"] + " .segments");
pieChart.labels = d3.select(pieChart.el["selector"] + " .labels");
pieChart.pointers = d3.select(pieChart.el["selector"] + " .pointers");
pieChart.legend = d3.select(pieChart.el["selector"] + " .legend");
dataSet.forEach(function (d) {
d.total = +d.value;
});
pieChart.currentDataSet = dataSet;
pieChart.animateSlices(dataSet);
//__legends
var w = 200;
// add legend
var legend = pieChart.legend; //.append("g")
var legendRects = legend.selectAll('rect')
.data(this.piedata, function (d) {
return d.data.label
});
legendRects.enter()
.append("rect")
.attr("x", w - 65)
.attr("y", function (d, i) {
return i * 20;
})
.attr("width", 10)
.attr("height", 10)
.style("fill", function (d, i) {
return pieChart.color(i);
})
.style("stroke", function (d, i) {
return pieChart.color(i);
})
.on('click', function(d, i){
pieChart.onToggle(d, i);
})
.transition()
.duration(300)
legendRects.style("fill", function (d, i) {
return pieChart.color(i);
})
.style("stroke", function (d, i) {
return pieChart.color(i);
})
.transition()
.duration(300)
legendRects.exit().remove();
var legendText = legend.selectAll('text.label')
.data(this.piedata, function (d) {
return d.data.label
});
legendText.enter()
.append("text")
.attr("class", "label")
.attr("x", w - 52)
.attr("y", function (d, i) {
return i * 20 + 9;
})
.text(function (d) {
return d.data.label;
})
.transition()
.duration(300)
legendText.text(function (d) {
return d.data.label;
})
.transition()
.duration(300)
legendText.exit().remove();
var legendTextVals = legend.selectAll('text.vals')
.data(this.piedata, function (d) {
return d.data.label
});
legendTextVals.enter()
.append("text")
.attr("class", "vals")
.attr("x", w + 20)
.attr("y", function (d, i) {
return i * 20 + 9;
})
.text(function (d) {
return d.data.value;
})
.transition()
.duration(300)
legendTextVals.text(function (d) {
return d.data.value;
})
.transition()
.duration(300)
legendTextVals.exit().remove();
//__pointers
this.oldPieData = this.piedata;
}
};
var dataCharts = [{
"data": [{
"segments": [{
"label": "apple",
"value": 53245
}, {
"label": "cherry",
"value": 145
}, {
"label": "pear",
"value": 2245
}, {
"label": "bananana",
"value": 15325
}]
}]
}, {
"data": [{
"segments": [{
"label": "milk",
"value": 122
}, {
"label": "cheese",
"value": 44
}, {
"label": "grapes",
"value": 533
}]
}]
}, {
"data": [{
"segments": [{
"label": "pineapple",
"value": 1532
}, {
"label": "orange",
"value": 1435
}, {
"label": "grapes",
"value": 22
}]
}]
}, {
"data": [{
"segments": [{
"label": "lemons",
"value": 133
}, {
"label": "mango",
"value": 435
}, {
"label": "melon",
"value": 2122
}]
}]
}];
var clone = jQuery.extend(true, {}, dataCharts);
//__invoke concentric
$('[data-role="piechart"]').each(function (index) {
var selector = "piechart" + index;
$(this).attr("id", selector);
var options = {
data: clone[0].data,
width: $(this).data("width"),
height: $(this).data("height"),
r: $(this).data("r"),
ir: $(this).data("ir")
}
pieChart.init($("#" + selector), options);
pieChart.update($("#" + selector), clone[0].data[0].segments);
});
$(".testers a").on("click", function (e) {
e.preventDefault();
var clone = jQuery.extend(true, {}, dataCharts);
var min = 0;
var max = 3;
//__invoke pie chart
$('[data-role="piechart"]').each(function (index) {
pos = Math.floor(Math.random() * (max - min + 1)) + min;
pieChart.update($("#" + $(this).attr("id")), clone[pos].data[0].segments);
});
});
});