jui.define("chart.brush.scatter", [ "util.base" ], function(_) {
/**
* @class chart.brush.scatter
* @extends chart.brush.core
*/
var ScatterBrush = function() {
this.getSymbolType = function(key, value) {
var symbol = this.brush.symbol,
target = this.brush.target[key];
if(_.typeCheck("function", symbol)) {
var res = symbol.apply(this.chart, [ target, value ]);
if (res == "triangle" || res == "cross" || res == "rectangle" || res == "rect" || res == "circle") {
return {
type : "default",
uri : res
};
} else {
return {
type : "image",
uri : res
};
}
}
return {
type : "default",
uri : symbol
};
}
this.createScatter = function(pos, dataIndex, targetIndex, symbol) {
var self = this,
elem = null,
w = h = this.brush.size;
var color = this.color(dataIndex, targetIndex),
borderColor = this.chart.theme("scatterBorderColor"),
borderWidth = this.chart.theme("scatterBorderWidth"),
bgOpacity = this.brush.opacity;
if(symbol.type == "image") {
elem = this.chart.svg.image({
"xlink:href": symbol.uri,
width: w + borderWidth,
height: h + borderWidth,
x: pos.x - (w / 2) - borderWidth,
y: pos.y - (h / 2)
});
} else {
if(symbol.uri == "triangle" || symbol.uri == "cross") {
elem = this.chart.svg.group({
width: w,
height: h,
opacity: bgOpacity,
}, function() {
if(symbol.uri == "triangle") {
var poly = self.chart.svg.polygon();
poly.point(0, h)
.point(w, h)
.point(w / 2, 0);
} else {
self.chart.svg.line({ stroke: color, "stroke-width": borderWidth * 2, x1: 0, y1: 0, x2: w, y2: h });
self.chart.svg.line({ stroke: color, "stroke-width": borderWidth * 2, x1: 0, y1: w, x2: h, y2: 0 });
}
}).translate(pos.x - (w / 2), pos.y - (h / 2));
} else {
if(symbol.uri == "rectangle" || symbol.uri == "rect") {
elem = this.chart.svg.rect({
width: w,
height: h,
x: pos.x - (w / 2),
y: pos.y - (h / 2),
opacity: bgOpacity
});
} else {
elem = this.chart.svg.ellipse({
rx: w / 2,
ry: h / 2,
cx: pos.x,
cy: pos.y,
opacity: bgOpacity
});
}
}
if(symbol.uri != "cross") {
elem.attr({
fill: color,
stroke: borderColor,
"stroke-width": borderWidth
})
.hover(function () {
if(elem == self.activeScatter) return;
var opts = {
fill: self.chart.theme("scatterHoverColor"),
stroke: color,
"stroke-width": borderWidth * 2,
opacity: bgOpacity
};
if(self.brush.hoverSync) {
for(var i = 0; i < self.cachedSymbol[dataIndex].length; i++) {
opts.stroke = self.color(dataIndex, i);
self.cachedSymbol[dataIndex][i].attr(opts);
}
} else {
elem.attr(opts);
}
}, function () {
if(elem == self.activeScatter) return;
var opts = {
fill: color,
stroke: borderColor,
"stroke-width": borderWidth,
opacity: (self.brush.hide) ? 0 : bgOpacity
};
if(self.brush.hoverSync) {
for(var i = 0; i < self.cachedSymbol[dataIndex].length; i++) {
opts.fill = self.color(dataIndex, i);
self.cachedSymbol[dataIndex][i].attr(opts);
}
} else {
elem.attr(opts);
}
});
}
}
return elem;
}
this.drawScatter = function(points) {
// hoverSync 옵션 처리를 위한 캐싱 처리
this.cachedSymbol = {};
var self = this,
g = this.chart.svg.group(),
borderColor = this.chart.theme("scatterBorderColor"),
borderWidth = this.chart.theme("scatterBorderWidth"),
bgOpacity = this.brush.opacity,
isTooltipDraw = false;
for(var i = 0; i < points.length; i++) {
for(var j = 0; j < points[i].length; j++) {
if(!this.cachedSymbol[j]) {
this.cachedSymbol[j] = [];
}
if(this.brush.hideZero && points[i].value[j] === 0) {
continue;
}
var data = {
x: points[i].x[j],
y: points[i].y[j],
max: points[i].max[j],
min: points[i].min[j],
value: points[i].value[j]
};
// 값이 null이나 undefined일 때, 그리지 않음
if(_.typeCheck([ "undefined", "null" ], data.value))
continue;
var symbol = this.getSymbolType(i, data.value),
p = this.createScatter(data, j, i, symbol),
d = this.brush.display;
// hoverSync 옵션을 위한 엘리먼트 캐싱
if(symbol.type == "default" && symbol.uri != "cross") {
this.cachedSymbol[j].push(p);
}
// Max & Min & All 툴팁 생성
if((d == "max" && data.max) || (d == "min" && data.min) || d == "all") {
// 최소/최대 값은 무조건 한개만 보여야 함.
if(d == "all" || !isTooltipDraw) {
g.append(this.drawTooltip(data.x, data.y, this.format(data.value)));
isTooltipDraw = true;
}
}
// 컬럼 및 기본 브러쉬 이벤트 설정
if(this.brush.activeEvent != null) {
(function(scatter, data, color, symbol) {
var x = data.x,
y = data.y,
text = self.format(data.value);
scatter.on(self.brush.activeEvent, function(e) {
if(symbol.type == "default" && symbol.uri != "cross") {
if (self.activeScatter != null) {
self.activeScatter.attr({
fill: self.activeScatter.attributes["stroke"],
stroke: borderColor,
"stroke-width": borderWidth,
opacity: (self.brush.hide) ? 0 : bgOpacity
});
}
self.activeScatter = scatter;
self.activeScatter.attr({
fill: self.chart.theme("scatterHoverColor"),
stroke: color,
"stroke-width": borderWidth * 2,
opacity: bgOpacity
});
}
self.activeTooltip.html(text);
self.activeTooltip.translate(x, y);
});
scatter.attr({ cursor: "pointer" });
})(p, data, this.color(j, i), this.getSymbolType(i, data.value));
}
if(this.brush.hide) {
p.attr({ opacity: 0 });
}
this.addEvent(p, j, i);
g.append(p);
}
}
// 액티브 툴팁
this.activeTooltip = this.drawTooltip(0, 0, "");
g.append(this.activeTooltip);
return g;
}
this.drawTooltip = function(x, y, text) {
return this.chart.text({
y: -this.brush.size,
"text-anchor" : "middle",
fill : this.chart.theme("tooltipPointFontColor"),
"font-size" : this.chart.theme("tooltipPointFontSize"),
"font-weight" : this.chart.theme("tooltipPointFontWeight"),
opacity : this.brush.opacity
}, text).translate(x, y);
}
this.draw = function() {
return this.drawScatter(this.getXY());
}
this.drawAnimate = function() {
var area = this.chart.area();
return this.chart.svg.animateTransform({
attributeName: "transform",
type: "translate",
from: area.x + " " + area.height,
to: area.x + " " + area.y,
begin: "0s" ,
dur: "0.4s",
repeatCount: "1"
});
}
}
ScatterBrush.setup = function() {
return {
/** @cfg {"circle"/"triangle"/"rectangle"/"cross"/"callback"} [symbol="circle"] Determines the shape of a (circle, rectangle, cross, triangle). */
symbol: "circle",
/** @cfg {Number} [size=7] Determines the size of a starter. */
size: 7,
/** @cfg {Boolean} [hide=false] Hide the scatter, will be displayed only when the mouse is over. */
hide: false,
/** @cfg {Boolean} [hideZero=false] When scatter value is zero, will be hidden. */
hideZero: false,
/** @cfg {Boolean} [hoverSync=false] Over effect synchronization of all the target's symbol. */
hoverSync: false,
/** @cfg {String} [activeEvent=null] Activates the scatter in question when a configured event occurs (click, mouseover, etc). */
activeEvent: null,
/** @cfg {"max"/"min"/"all"} [display=null] Shows a tooltip on the scatter for the minimum/maximum value. */
display: null,
/** @cfg {Number} [opacity=1] Stroke opacity. */
opacity: 1,
/** @cfg {Boolean} [clip=false] If the brush is drawn outside of the chart, cut the area. */
clip: false
};
}
return ScatterBrush;
}, "chart.brush.core");