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");