Merge branch 'butterfly' of git://github.com/TBEDP/datavjs into butterfly

This commit is contained in:
Jackson Tian 2012-11-23 22:10:59 +08:00
commit 76313dd777

View File

@ -15,11 +15,21 @@
/**
* 构造函数
* @param {Object} node 表示在html的哪个容器中绘制该组件
* @param {Object} options 为用户自定义的组件的属性比如画布大小
* Options:
* - `width` 图宽度
* - `height` 图高度
*
* - `width` 图片宽度默认为800表示图片高800px
* - `height` 图片高度默认为800
* - `legend` 图例是否显示默认为 true, 显示设为false则不显示
* - `ms` 动画持续时间默认300
* - `easing` 动画类型默认bounce详见rapheal相关文档可以使用lineareaseIneaseOuteaseInOutbackInbackOutelasticbounce
*
* Examples:
* create Radar Chart in a dom node with id "chart", width is 500; height is 600px;
* ```
* var radar = new Radar("chart", {"width": 500, "height": 600});
* ```
* @param {Object} container 表示在html的哪个容器中绘制该组件
* @param {Object} options 为用户自定义的组件的属性比如画布大小
*/
var Pie = DataV.extend(DataV.Chart, {
type: "Pie",
@ -53,6 +63,8 @@
this.defaults.legend = true;
this.defaults.width = 800;
this.defaults.height = 800;
this.defaults.ms = 300;
this.defaults.easing = "bounce";
//设置用户指定的属性
this.setOptions(options);
@ -98,16 +110,16 @@
* 绘制饼图
*/
Pie.prototype.render = function () {
this.layout();
var conf = this.defaults;
var floatTag = this.floatTag;
var that = this;
this.layout();
var groups = this.groups;
//由内外半径、起始角度计算路径字符串
var pathCalc = d3.svg.arc()
.innerRadius(conf.radius)
.outerRadius(0)
.outerRadius(conf.radius * 0.2)
.startAngle(function (d) {
return d.startAngle;
}).endAngle(function (d) {
@ -121,6 +133,7 @@
that.donutGroups = that.canvas.set();
$(this.node).append(this.floatTag);
//添加透明效果
var mouseOver = function () {
floatTag.html('<div style="text-align:center; margin:auto; color:#ffffff">' + this.data('text') + '</div>');
@ -155,17 +168,34 @@
d.attr('fill-opacity', 1);
});
} else if (!this.data('click')) {
this.attr('fill-opacity', 0.5);
}
};
var mouseClick = function () {
var index = this.data("donutIndex");
var fan = groups[index];
var flag = !this.data('click');
this.data('click', flag);
var a = 0.5 * ((that.groups[index].startAngle + that.groups[index].endAngle) - Math.PI);
var nameX = conf.protrude * Math.cos(a);
var nameY = conf.protrude * Math.sin(a);
var ro = (fan.startAngle + fan.endAngle) * 90 / Math.PI;
var angle = 0.5 * ((fan.startAngle + fan.endAngle) - Math.PI);
var center = {
x: ((conf.width - that.xOffset) / 2 + that.xOffset),
y: conf.height / 2
};
var namePos = {
x: conf.protrude * Math.cos(angle),
y: conf.protrude * Math.sin(angle)
};
var radius = {
x: conf.radius * Math.cos(angle) + namePos.x,
y: conf.radius * Math.sin(angle) + namePos.y
};
var linePos = {
x: 9 * Math.cos(angle),
y: 9 * Math.sin(angle)
};
if (flag) {
if (that.click === 0) {
that.donutGroups.forEach(function (d) {
@ -176,14 +206,28 @@
}
that.underBn[index].attr('opacity', 1).show();
this.attr('fill-opacity', 1);
this.data('nameTag').translate(0, - conf.protrude);
this.data('line').translate(0, - conf.protrude);
this.translate(nameX, nameY);
this.data('nameTag').stop().animate({
transform: "t" + (center.x + radius.x + 2 * namePos.x) + " " + (center.y + radius.y + 2 * namePos.y) + "r" + ro
}, conf.ms, conf.easing);
this.data('line').stop().animate({
transform: "t" + (center.x + radius.x + namePos.x - linePos.x) + " " + (center.y + radius.y + namePos.y - linePos.y) + "r" + ro
}, conf.ms, conf.easing);
this.stop().animate({
transform: "t" + (center.x + namePos.x) + " " + (center.y + namePos.y)
}, conf.ms, conf.easing);
//this.translate(nameX, nameY);
that.click += 1;
} else {
this.data('nameTag').translate(0, conf.protrude);
this.data('line').translate(0, conf.protrude);
this.translate(-nameX, - nameY);
this.data('nameTag').stop().animate({
transform: "t" + (center.x + radius.x + namePos.x) + " " + (center.y + radius.y + namePos.y) + "r" + ro
}, conf.ms, conf.easing);
this.data('line').stop().animate({
transform: "t" + (center.x + radius.x - linePos.x) + " " + (center.y + radius.y - linePos.y) + "r" + ro
}, conf.ms, conf.easing);
this.stop().animate({
transform: "t" + center.x + " " + center.y
}, conf.ms, conf.easing);
//this.translate(-nameX, - nameY);
that.click -= 1;
if (that.click > 0) {
this.attr('fill-opacity', 0.5);
@ -195,12 +239,13 @@
var i;
var nameStr;
var nameX, nameY;
var ro, a;
var ro, angle;
for (i = 0; i <= groups.length - 1; i++) {
var fan = groups[i];
//画外圈的pie图
//计算每个group的path
spline = pathCalc(groups[i]);
tips = that.groupNames[i] + ": " + Math.round(groups[i].value) + " " + (groups[i].value * 100 / this.sum).toFixed(2) + "%";
spline = pathCalc(fan);
tips = fan.nameTag + ": " + Math.round(fan.value) + " " + (fan.value * 100 / this.sum).toFixed(2) + "%";
donutEle = that.canvas.path(spline)
.translate((conf.width - this.xOffset) / 2 + this.xOffset, conf.height / 2)
@ -215,15 +260,17 @@
.click(mouseClick);
//每个donut上显示名称
ro = (groups[i].startAngle + groups[i].endAngle) * 90 / Math.PI;
a = 0.5 * ((groups[i].startAngle + groups[i].endAngle) - Math.PI);
nameX = (conf.radius + 2 * conf.protrude) * Math.cos(a);
nameY = (conf.radius + 2 * conf.protrude) * Math.sin(a);
ro = (fan.startAngle + fan.endAngle) * 90 / Math.PI;
angle = 0.5 * ((fan.startAngle + fan.endAngle) - Math.PI);
nameX = (conf.radius + 2 * conf.protrude) * Math.cos(angle);
nameY = (conf.radius + 2 * conf.protrude) * Math.sin(angle);
nameStr = "T" + ((conf.width - that.xOffset) / 2 + that.xOffset) + "," + conf.height / 2 + "R" + ro + "T" + nameX + "," + nameY;
var line = that.canvas.path("M,0,-" + conf.protrude + "L0," + conf.protrude).transform(nameStr).translate(0, conf.protrude + 9);
var nameTag = that.canvas.text().attr("font", "18px Verdana").attr("text", that.groupNames[i]).transform(nameStr);
var nameTag = that.canvas.text().attr({
"font": "18px Verdana",
"text": fan.nameTag
}).translate(((conf.width - that.xOffset) / 2 + that.xOffset) + nameX, conf.height / 2 + nameY).rotate(ro); //transform(nameStr);
donutEle.data('text', tips).data('click', false).data('nameTag', nameTag).data('line', line);
that.donutGroups.push(donutEle);
}
@ -240,6 +287,7 @@
var that = this;
var conf = this.defaults;
var paper = this.canvas;
var groups = this.groups;
var legendArea = this.legendArea;
this.rectBn = paper.set();
var rectBn = this.rectBn;
@ -250,6 +298,7 @@
underBn.push(paper.rect(legendArea[0] + 10, legendArea[1] + 10 + (20 + 3) * i, 180, 20).attr({
"fill": "#ebebeb",
"stroke": "none"
//"r": 3
}).hide());
//色框
paper.rect(legendArea[0] + 10 + 3, legendArea[1] + 10 + (20 + 3) * i + 6, 16, 8).attr({
@ -257,7 +306,7 @@
"stroke": "none"
});
//文字
paper.text(legendArea[0] + 10 + 3 + 16 + 8, legendArea[1] + 10 + (20 + 3) * i + 10, this.groupNames[i]).attr({
paper.text(legendArea[0] + 10 + 3 + 16 + 8, legendArea[1] + 10 + (20 + 3) * i + 10, this.groups[i].nameTag).attr({
"fill": "black",
"fill-opacity": 1,
"font-family": "Verdana",
@ -269,10 +318,12 @@
"fill": "white",
"fill-opacity": 0,
"stroke": "none"
//"r": 3
}));
}
rectBn.forEach(function (d, i) {
// TODO: 这里的事件建议采用事件委托
var fan = groups[i];
d.mouseover(function () {
if (!that.donutGroups[i].data("click")) {
underBn[i].attr('opacity', 0.5).show();
@ -283,9 +334,24 @@
}
});
d.click(function () {
var a = 0.5 * ((that.groups[i].startAngle + that.groups[i].endAngle) - Math.PI);
var nameX = conf.protrude * Math.cos(a);
var nameY = conf.protrude * Math.sin(a);
var ro = (fan.startAngle + fan.endAngle) * 90 / Math.PI;
var angle = 0.5 * ((fan.startAngle + fan.endAngle) - Math.PI);
var center = {
x: ((conf.width - that.xOffset) / 2 + that.xOffset),
y: conf.height / 2
};
var namePos = {
x: conf.protrude * Math.cos(angle),
y: conf.protrude * Math.sin(angle)
};
var radius = {
x: conf.radius * Math.cos(angle) + namePos.x,
y: conf.radius * Math.sin(angle) + namePos.y
};
var linePos = {
x: 9 * Math.cos(angle),
y: 9 * Math.sin(angle)
};
if (!that.donutGroups[i].data("click")) {
if (that.click === 0) {
that.donutGroups.forEach(function (d) {
@ -296,14 +362,27 @@
}
underBn[i].attr('opacity', 1).show();
that.donutGroups[i].data("click", true).attr('fill-opacity', 1);
that.donutGroups[i].data('nameTag').translate(0, - conf.protrude);
that.donutGroups[i].data('line').translate(0, - conf.protrude);
that.donutGroups[i].translate(nameX, nameY);
that.donutGroups[i].data('nameTag').stop().animate({
transform: "t" + (center.x + radius.x + 2 * namePos.x) + " " + (center.y + radius.y + 2 * namePos.y) + "r" + ro
}, conf.ms, conf.easing);
that.donutGroups[i].data('line').stop().animate({
transform: "t" + (center.x + radius.x + namePos.x - linePos.x) + " " + (center.y + radius.y + namePos.y - linePos.y) + "r" + ro
}, conf.ms, conf.easing);
that.donutGroups[i].stop().animate({
transform: "t" + (center.x + namePos.x) + " " + (center.y + namePos.y)
}, conf.ms, conf.easing);
that.click += 1;
} else if (that.donutGroups[i].data("click")) {
that.donutGroups[i].data('nameTag').translate(0, conf.protrude);
that.donutGroups[i].data('line').translate(0, conf.protrude);
that.donutGroups[i].translate(-nameX, - nameY);
that.donutGroups[i].data('nameTag').stop().animate({
transform: "t" + (center.x + radius.x + namePos.x) + " " + (center.y + radius.y + namePos.y) + "r" + ro
}, conf.ms, conf.easing);
that.donutGroups[i].data('line').stop().animate({
transform: "t" + (center.x + radius.x - linePos.x) + " " + (center.y + radius.y - linePos.y) + "r" + ro
}, conf.ms, conf.easing);
that.donutGroups[i].stop().animate({
transform: "t" + center.x + " " + center.y
}, conf.ms, conf.easing);
that.click -= 1;
if (that.click > 0) {
that.donutGroups[i].attr('fill-opacity', 0.5);
@ -314,6 +393,7 @@
}
underBn[i].hide();
that.donutGroups[i].data("click", false);
}
});
});
@ -336,22 +416,28 @@
*/
Pie.prototype.layout = function () {
var that = this;
that.canvas.clear();
var acc = 0;
this.sum = DataV.sum(this.groupValue);
var sum = this.sum;
this.groups = this.groupValue.map(function (item, index) {
var startAngle = 2 * acc * Math.PI / sum;
acc += item;
var endAngle = 2 * acc * Math.PI / sum;
var ret = {
index: index,
value: item,
startAngle: startAngle,
endAngle: endAngle
nameTag: that.groupNames[index]
};
return ret;
});
this.groups = _.sortBy(that.groups, function (d) {
return -d.value;
});
var acc = 0;
this.groups.forEach(function (d) {
d.startAngle = 2 * acc * Math.PI / sum;
acc += d.value;
d.endAngle = 2 * acc * Math.PI / sum;
});
};
return Pie;