jui.define("chart.brush.donut", [ "util.base", "util.math", "util.color" ], function(_, math, ColorUtil) {
/**
* @class chart.brush.donut
* @extends chart.brush.pie
*
*/
var DonutBrush = function() {
var self = this,
cache_active = {};
this.drawDonut = function(centerX, centerY, innerRadius, outerRadius, startAngle, endAngle, attr) {
attr['stroke-width'] = outerRadius - innerRadius;
if (endAngle >= 360) { // bugfix : if angle is 360 , donut cang't show
endAngle = 359.9999;
}
var g = this.chart.svg.group(),
path = this.chart.svg.path(attr),
dist = Math.abs(outerRadius - innerRadius);
// 바깥 지름 부터 그림
var obj = math.rotate(0, -outerRadius, math.radian(startAngle)),
startX = obj.x,
startY = obj.y;
// 시작 하는 위치로 옮김
path.MoveTo(startX, startY);
// outer arc 에 대한 지점 설정
obj = math.rotate(startX, startY, math.radian(endAngle));
// 중심점 이동
g.translate(centerX, centerY);
// outer arc 그림
path.Arc(outerRadius, outerRadius, 0, (endAngle > 180) ? 1 : 0, 1, obj.x, obj.y);
// 마우스 이벤트 빈공간 제외
path.css({
"pointer-events": "stroke"
});
g.append(path);
g.order = 1;
return g;
}
this.drawDonut3d = function(centerX, centerY, innerRadius, outerRadius, startAngle, endAngle, attr) {
var g = this.chart.svg.group(),
path = this.chart.svg.path(attr),
dist = Math.abs(outerRadius - innerRadius);
outerRadius += dist/2;
innerRadius = outerRadius - dist;
// 바깥 지름 부터 그림
var obj = math.rotate(0, -outerRadius, math.radian(startAngle)),
startX = obj.x,
startY = obj.y;
var innerObj = math.rotate(0, -innerRadius, math.radian(startAngle)),
innerStartX = innerObj.x,
innerStartY = innerObj.y;
// 시작 하는 위치로 옮김
path.MoveTo(startX, startY);
// outer arc 에 대한 지점 설정
obj = math.rotate(startX, startY, math.radian(endAngle));
innerObj = math.rotate(innerStartX, innerStartY, math.radian(endAngle));
// 중심점 이동
g.translate(centerX, centerY);
// outer arc 그림
path.Arc(outerRadius, outerRadius, 0, (endAngle > 180) ? 1 : 0, 1, obj.x, obj.y);
var y = obj.y + 10,
x = obj.x + 5,
innerY = innerObj.y + 10,
innerX = innerObj.x + 5,
targetX = startX + 5,
targetY = startY + 10,
innerTargetX = innerStartX + 5,
innerTargetY = innerStartY + 10;
path.LineTo(x, y);
path.Arc(outerRadius, outerRadius, 0, (endAngle > 180) ? 1 : 0, 0, targetX, targetY)
path.ClosePath();
g.append(path);
// 안쪽 면 그리기
var innerPath = this.chart.svg.path(attr);
// 시작 하는 위치로 옮김
innerPath.MoveTo(innerStartX, innerStartY);
innerPath.Arc(innerRadius, innerRadius, 0, (endAngle > 180) ? 1 : 0, 1, innerObj.x, innerObj.y);
innerPath.LineTo(innerX, innerY);
innerPath.Arc(innerRadius, innerRadius, 0, (endAngle > 180) ? 1 : 0, 0, innerTargetX, innerTargetY);
innerPath.ClosePath();
g.append(innerPath);
g.order = 1;
return g;
}
this.drawDonut3dBlock = function(centerX, centerY, innerRadius, outerRadius, startAngle, endAngle, attr) {
var g = this.chart.svg.group(),
path = this.chart.svg.path(attr),
dist = Math.abs(outerRadius - innerRadius);
outerRadius += dist/2;
innerRadius = outerRadius - dist;
// 바깥 지름 부터 그림
var obj = math.rotate(0, -outerRadius, math.radian(startAngle)),
startX = obj.x,
startY = obj.y;
var innerObj = math.rotate(0, -innerRadius, math.radian(startAngle)),
innerStartX = innerObj.x,
innerStartY = innerObj.y;
// 시작 하는 위치로 옮김
path.MoveTo(startX, startY);
// outer arc 에 대한 지점 설정
obj = math.rotate(startX, startY, math.radian(endAngle));
innerObj = math.rotate(innerStartX, innerStartY, math.radian(endAngle));
// 중심점 이동
g.translate(centerX, centerY);
var y = obj.y + 10,
x = obj.x + 5,
innerY = innerObj.y + 10,
innerX = innerObj.x + 5;
// 왼쪽면 그리기
var rect = this.chart.svg.path(attr);
rect.MoveTo(obj.x, obj.y).LineTo(x, y).LineTo(innerX, innerY).LineTo(innerObj.x, innerObj.y).ClosePath();
g.append(rect);
g.order = 1;
return g;
}
this.drawUnit = function (index, data, g) {
var props = this.getProperty(index),
centerX = props.centerX,
centerY = props.centerY,
innerRadius = props.innerRadius,
outerRadius = props.outerRadius;
var target = this.brush.target,
active = this.brush.active,
all = 360,
startAngle = 0,
max = 0,
totalValue = 0;
for (var i = 0; i < target.length; i++) {
max += data[target[i]];
}
if (this.brush['3d']) {
// 화면 블럭 그리기
for (var i = 0; i < target.length; i++) {
var value = data[target[i]],
endAngle = all * (value / max),
donut3d = this.drawDonut3dBlock(centerX, centerY, innerRadius, outerRadius, startAngle, endAngle, {
fill : ColorUtil.darken(this.color(i), 0.5)
}, i == target.length - 1);
g.append(donut3d);
startAngle += endAngle;
}
startAngle = 0;
for (var i = 0; i < target.length; i++) {
var value = data[target[i]],
endAngle = all * (value / max),
donut3d = this.drawDonut3d(centerX, centerY, innerRadius, outerRadius, startAngle, endAngle, {
fill : ColorUtil.darken(this.color(i), 0.5)
}, i == target.length - 1);
g.append(donut3d);
startAngle += endAngle;
}
}
startAngle = 0;
for (var i = 0; i < target.length; i++) {
if(data[target[i]] == 0) continue;
var value = data[target[i]],
endAngle = all * (value / max),
centerAngle = startAngle + (endAngle / 2) - 90,
radius = (this.brush.showText == "inside") ? this.brush.size + innerRadius + outerRadius : outerRadius,
donut = this.drawDonut(centerX, centerY, innerRadius, outerRadius, startAngle, endAngle, {
stroke : this.color(i),
fill : 'transparent'
}),
text = this.drawText(centerX, centerY, centerAngle, radius, this.getFormatText(target[i], value));
// 설정된 키 활성화
if (active == target[i] || _.inArray(target[i], active) != -1) {
if(this.brush.showText == "inside") {
this.setActiveTextEvent(text.get(0), centerX, centerY, centerAngle, radius, true);
}
this.setActiveEvent(donut, centerX, centerY, centerAngle);
cache_active[centerAngle] = true;
}
// 활성화 이벤트 설정
if (this.brush.activeEvent != null) {
(function (p, t, cx, cy, ca, r) {
p.on(self.brush.activeEvent, function (e) {
if (!cache_active[ca]) {
if(self.brush.showText == "inside") {
self.setActiveTextEvent(t, cx, cy, ca, r, true);
}
self.setActiveEvent(p, cx, cy, ca);
cache_active[ca] = true;
} else {
if(self.brush.showText == "inside") {
self.setActiveTextEvent(t, cx, cy, ca, r, false);
}
p.translate(cx, cy);
cache_active[ca] = false;
}
});
p.attr({ cursor: "pointer" });
})(donut, text.get(0), centerX, centerY, centerAngle, radius);
}
this.addEvent(donut, index, i);
g.append(donut);
g.append(text);
startAngle += endAngle;
totalValue += value;
}
// Show total value
if(this.brush.showValue) {
this.drawTotalValue(g, centerX, centerY, totalValue);
}
}
this.drawNoData = function(g) {
var props = this.getProperty(0);
g.append(this.drawDonut(props.centerX, props.centerY, props.innerRadius, props.outerRadius, 0, 360, {
stroke : this.chart.theme("pieNoDataBackgroundColor"),
fill : "transparent"
}));
// Show total value
if(this.brush.showValue) {
this.drawTotalValue(g, props.centerX, props.centerY, 0);
}
}
this.drawTotalValue = function(g, centerX, centerY, value) {
var size = this.chart.theme("pieTotalValueFontSize");
var text = this.chart.text({
"font-size": size,
"font-weight": this.chart.theme("pieTotalValueFontWeight"),
fill: this.chart.theme("pieTotalValueFontColor"),
"text-anchor": "middle",
dy: size / 3
}, this.format(value));
text.translate(centerX, centerY);
g.append(text)
}
this.getProperty = function(index) {
var obj = this.axis.c(index);
var width = obj.width,
height = obj.height,
x = obj.x,
y = obj.y,
min = width;
if (height < min) {
min = height;
}
if (this.brush.size >= min/2) {
this.brush.size = min/4;
}
var outerRadius = min / 2 - this.brush.size / 2;
return {
centerX : width / 2 + x,
centerY : height / 2 + y,
outerRadius : outerRadius,
innerRadius : outerRadius - this.brush.size
}
}
}
DonutBrush.setup = function() {
return {
/** @cfg {Number} [size=50] donut stroke width */
size: 50,
/** @cfg {Boolean} [showValue=false] donut stroke width */
showValue: false
};
}
return DonutBrush;
}, "chart.brush.pie");