jui.define("chart.widget.tooltip", [ "util.base", "util.color" ], function(_, ColorUtil) {
var PADDING = 7, ANCHOR = 7, RATIO = 1.2;
/**
* @class chart.widget.tooltip
* @extends chart.widget.core
* @alias TooltipWidget
* @requires jquery
*
*/
var TooltipWidget = function(chart, axis, widget) {
var self = this,
tooltips = {},
lineHeight = 0;
function getFormat(k, d) {
var key = null,
value = null;
if(_.typeCheck("function", widget.format)) {
var obj = self.format(d, k);
if(_.typeCheck("object", obj)) {
key = obj.key;
value = obj.value;
} else {
value = obj;
}
} else {
if(k && !d) {
value = k;
}
if(k && d) {
key = k;
value = self.format(d[k]);
}
}
return {
key: key,
value: value
}
}
function printTooltip(obj) {
var tooltip = tooltips[obj.brush.index],
texts = tooltip.get(1).get(1),
width = 0,
height = 0,
onlyValue = false;
if(obj.dataKey && widget.all === false) {
setTextInTooltip([ obj.dataKey ]);
} else {
setTextInTooltip(obj.brush.target);
}
function setTextInTooltip(targets) {
for(var i = 0; i < targets.length; i++) {
var key = targets[i],
msg = getFormat(key, obj.data);
texts.get(i).attr({ x: PADDING });
if(msg.key) {
texts.get(i).get(0).text(msg.key);
} else {
texts.get(i).get(1).attr({ "text-anchor": "middle" });
onlyValue = true;
}
if(!_.typeCheck([ "null", "undefined" ], msg.value)) {
texts.get(i).get(1).attr({ x: 0 }).text(msg.value);
}
width = Math.max(width, texts.get(i).size().width);
}
height = targets.length * lineHeight;
}
return {
width: width + PADDING * 3,
height: height + PADDING,
onlyValue: onlyValue
};
}
function existBrush(index) {
var list = self.getIndexArray(self.widget.brush);
return (_.inArray(index, list) == -1) ? false : true;
}
function getColorByKey(obj) {
var targets = obj.brush.target;
for(var i = 0; i < targets.length; i++) {
if(targets[i] == obj.dataKey) {
return ColorUtil.lighten(self.chart.color(i, obj.brush.colors));
}
}
return null;
}
function getTooltipXY(e, size, orient) {
var x = e.bgX - (size.width / 2),
y = e.bgY - size.height - ANCHOR - (PADDING / 2),
lineX = 2;
if(orient == "left" || orient == "right") {
y = e.bgY - (size.height / 2) - (PADDING / 2);
}
if(orient == "left") {
x = e.bgX - size.width - ANCHOR;
} else if(orient == "right") {
x = e.bgX + ANCHOR;
lineX = -2;
} else if(orient == "bottom") {
y = e.bgY + (ANCHOR * 2);
}
return {
x: x,
y: y,
c: lineX
}
}
function setTooltipEvent() {
var isActive = false,
size = null,
orient = null,
axis = null;
self.on("mouseover", function(obj, e) {
if(isActive || !existBrush(obj.brush.index)) return;
if(!obj.dataKey && !obj.data) return;
// 툴팁 크기 가져오기
size = printTooltip(obj);
orient = widget.orient;
axis = chart.axis(obj.brush.axis);
// 툴팁 좌표 가져오기
var xy = getTooltipXY(e, size, orient),
x = xy.x - chart.padding("left"),
y = xy.y - chart.padding("top");
// 엑시스 범위를 넘었을 경우 처리
if(widget.flip) {
if (orient == "left" && x < 0) {
orient = "right";
} else if (orient == "right" && x + size.width > axis.area("width")) {
orient = "left";
} else if (orient == "top" && y < 0) {
orient = "bottom";
} else if (orient == "bottom" && y + size.height > axis.area("height")) {
orient = "top";
}
}
// 툴팁 엘리먼트 가져오기
var tooltip = tooltips[obj.brush.index],
line = tooltip.get(0),
rect = tooltip.get(1).get(0),
text = tooltip.get(1).get(1).translate(0, (orient != "bottom") ? lineHeight : lineHeight + ANCHOR),
borderColor = chart.theme("tooltipBorderColor") || getColorByKey(obj),
lineColor = chart.theme("tooltipLineColor") || getColorByKey(obj);
rect.attr({
points: self.balloonPoints(orient, size.width, size.height, (widget.anchor) ? ANCHOR : null),
stroke: borderColor
});
line.attr({ stroke: lineColor });
text.each(function(i, elem) {
elem.get(1).attr({ x: (size.onlyValue) ? size.width / 2 : size.width - PADDING });
});
tooltip.attr({ visibility: "visible" });
isActive = true;
});
self.on("mousemove", function(obj, e) {
if(!isActive) return;
var tooltip = tooltips[obj.brush.index],
line = tooltip.get(0),
target = tooltip.get(1),
xy = getTooltipXY(e, size, orient);
line.attr({
x1: e.bgX + xy.c,
y1: chart.padding("top") + axis.area("y"),
x2: e.bgX + xy.c,
y2: chart.padding("top") + axis.area("y2")
});
target.translate(xy.x, xy.y);
});
self.on("mouseout", function(obj, e) {
if(!isActive) return;
var tooltip = tooltips[obj.brush.index];
tooltip.attr({ visibility: "hidden" });
isActive = false;
});
}
this.drawBefore = function() {
lineHeight = chart.theme("tooltipFontSize") * RATIO;
}
this.draw = function() {
var group = chart.svg.group(),
list = this.getIndexArray(this.widget.brush);
for(var i = 0; i < list.length; i++) {
var brush = chart.get("brush", list[i]),
words = [ "" ];
// 모든 타겟을 툴팁에 보여주는 옵션일 경우
if(widget.all && brush.target.length > 1) {
for (var j = 1; j < brush.target.length; j++) {
words.push("");
}
}
tooltips[brush.index] = chart.svg.group({ visibility: "hidden" }, function() {
chart.svg.line({
"stroke-width": chart.theme("tooltipLineWidth"),
visibility: (widget.line) ? "visible" : "hidden"
});
chart.svg.group({}, function () {
chart.svg.polygon({
fill: chart.theme("tooltipBackgroundColor"),
"fill-opacity": chart.theme("tooltipBackgroundOpacity"),
"stroke-width": chart.theme("tooltipBorderWidth")
});
var text = chart.texts({
"font-size": chart.theme("tooltipFontSize"),
"fill": chart.theme("tooltipFontColor")
}, words, RATIO);
for(var i = 0; i < words.length; i++) {
text.get(i).append(chart.svg.tspan({ "text-anchor": "start", "font-weight": "bold", "x": PADDING }));
text.get(i).append(chart.svg.tspan({ "text-anchor": "end" }));
}
});
});
group.append(tooltips[brush.index]);
}
setTooltipEvent();
return group;
}
}
TooltipWidget.setup = function() {
return {
/** @cfg {"bottom"/"top"/"left"/"right"} Determines the side on which the tool tip is displayed (top, bottom, left, right). */
orient: "top",
/** @cfg {Boolean} [anchor=true] Remove tooltip's anchor */
anchor: true,
/** @cfg {Boolean} [all=false] Determines whether to show all values of row data.*/
all: false,
/** @cfg {Boolean} [line=false] Visible Guidelines. */
line: false,
/** @cfg {Boolean} [flip=false] When I went out of the area, reversing the tooltip. */
flip: false,
/** @cfg {Function} [format=null] Sets the format of the value that is displayed on the tool tip. */
format: null,
/** @cfg {Number} [brush=0] Specifies a brush index for which a widget is used. */
brush: 0
};
}
return TooltipWidget;
}, "chart.widget.core");