jui.define("chart.brush.stackbar", [ "util.base" ], function(_) {
/**
* @class chart.brush.stackbar
* @extends chart.brush.bar
*
*/
var StackBarBrush = function(chart, axis, brush) {
var g, height, bar_height;
this.addBarElement = function(elem) {
if(this.barList == null) {
this.barList = [];
}
this.barList.push(elem);
}
this.getBarElement = function(dataIndex, targetIndex) {
var style = this.getBarStyle(),
color = this.color(targetIndex),
value = this.getData(dataIndex)[this.brush.target[targetIndex]];
var r = this.chart.svg.rect({
fill : color,
stroke : style.borderColor,
"stroke-width" : style.borderWidth,
"stroke-opacity" : style.borderOpacity
});
// 데이타가 0이면 화면에 표시하지 않음.
if (value == 0) {
r.attr({ display : 'none' });
}
if(value != 0) {
this.addEvent(r, dataIndex, targetIndex);
}
return r;
}
this.setActiveEffect = function(group) {
var style = this.getBarStyle(),
columns = this.barList,
tooltips = this.stackTooltips;
for(var i = 0; i < columns.length; i++) {
var opacity = (group == columns[i]) ? 1 : style.disableOpacity;
if (tooltips) { // bar 가 그려지지 않으면 tooltips 객체가 없을 수 있음.
if(opacity == 1 || _.inArray(i, this.tooltipIndexes) != -1) {
tooltips[i].attr({ opacity: 1 });
} else {
tooltips[i].attr({ opacity: 0 });
}
}
columns[i].attr({ opacity: opacity });
}
}
this.setActiveEffectOption = function() {
var active = this.brush.active;
if(this.barList && this.barList[active]) {
this.setActiveEffect(this.barList[active]);
}
}
this.setActiveEvent = function(group) {
var self = this;
group.on(self.brush.activeEvent, function (e) {
self.setActiveEffect(group);
});
}
this.setActiveEventOption = function(group) {
if(this.brush.activeEvent != null) {
this.setActiveEvent(group);
group.attr({ cursor: "pointer" });
}
}
this.getTargetSize = function() {
var height = this.axis.y.rangeBand();
if(this.brush.size > 0) {
return this.brush.size;
} else {
var size = height - this.brush.outerPadding * 2;
return (size < this.brush.minSize) ? this.brush.minSize : size;
}
}
this.setActiveTooltips = function(minIndex, maxIndex) {
var type = this.brush.display,
activeIndex = (type == "min") ? minIndex : maxIndex;
for(var i = 0; i < this.stackTooltips.length; i++) {
if(i == activeIndex || type == "all") {
this.stackTooltips[i].css({
opacity: 1
});
this.tooltipIndexes.push(i);
}
}
}
this.drawStackTooltip = function(group, index, value, x, y, pos) {
var fontSize = this.chart.theme("tooltipPointFontSize"),
orient = "middle",
dx = 0,
dy = 0;
if(pos == "left") {
orient = "start";
dx = 3;
dy = fontSize / 3;
} else if(pos == "right") {
orient = "end";
dx = -3;
dy = fontSize / 3;
} else if(pos == "top") {
dy = -(fontSize / 3);
} else {
dy = fontSize;
}
var tooltip = this.chart.text({
fill : this.chart.theme("tooltipPointFontColor"),
"font-size" : fontSize,
"font-weight" : this.chart.theme("tooltipPointFontWeight"),
"text-anchor" : orient,
dx: dx,
dy: dy,
opacity: 0
}).text(this.format(value)).translate(x, y);
this.stackTooltips[index] = tooltip;
group.append(tooltip);
}
this.drawStackEdge = function(g) {
var borderWidth = this.chart.theme("barStackEdgeBorderWidth");
for(var i = 1; i < this.edgeData.length; i++) {
var pre = this.edgeData[i - 1],
now = this.edgeData[i];
for(var j = 0; j < this.brush.target.length; j++) {
if(now[j].width > 0 && now[j].height > 0) {
g.append(this.svg.line({
x1: pre[j].x + pre[j].width - pre[j].ex,
x2: now[j].x + now[j].dx - now[j].ex,
y1: pre[j].y + pre[j].height - pre[j].ey,
y2: now[j].y + now[j].dy,
stroke: now[j].color,
"stroke-width": borderWidth
}));
}
}
}
}
this.drawBefore = function() {
g = chart.svg.group();
height = axis.y.rangeBand();
bar_height = this.getTargetSize();
this.stackTooltips = [];
this.tooltipIndexes = [];
this.edgeData = [];
}
this.draw = function() {
var maxIndex = null,
maxValue = 0,
minIndex = null,
minValue = this.axis.x.max(),
isReverse = this.axis.get("x").reverse;
this.eachData(function(data, i) {
var group = chart.svg.group();
var offsetY = this.offset("y", i),
startY = offsetY - bar_height / 2,
startX = axis.x(0),
value = 0,
sumValue = 0;
for(var j = 0; j < brush.target.length; j++) {
var xValue = data[brush.target[j]] + value,
endX = axis.x(xValue),
opts = {
x : (startX < endX) ? startX : endX,
y : startY,
width : Math.abs(startX - endX),
height : bar_height
},
r = this.getBarElement(i, j).attr(opts);
if(!this.edgeData[i]) {
this.edgeData[i] = {};
}
this.edgeData[i][j] = _.extend({
color: this.color(j),
dx: opts.width,
dy: 0,
ex: (isReverse) ? opts.width : 0,
ey: 0
}, opts);
startX = endX;
value = xValue;
sumValue += data[brush.target[j]];
group.append(r);
}
// min & max 인덱스 가져오기
if(sumValue > maxValue) {
maxValue = sumValue;
maxIndex = i;
}
if(sumValue < minValue) {
minValue = sumValue;
minIndex = i;
}
this.drawStackTooltip(group, i, sumValue, startX, offsetY, (isReverse) ? "right" : "left");
this.setActiveEventOption(group); // 액티브 엘리먼트 이벤트 설정
this.addBarElement(group);
g.append(group);
});
// 스탭 연결선 그리기
if(this.brush.edge) {
this.drawStackEdge(g);
}
// 최소/최대/전체 값 표시하기
if(this.brush.display != null) {
this.setActiveTooltips(minIndex, maxIndex);
}
// 액티브 엘리먼트 설정
this.setActiveEffectOption();
return g;
}
}
StackBarBrush.setup = function() {
return {
/** @cfg {Number} [outerPadding=15] Determines the outer margin of a stack bar. */
outerPadding: 15,
/** @cfg {Boolean} [edge=false] */
edge: false
};
}
return StackBarBrush;
}, "chart.brush.bar");