PieChart draggable and tooltip
円グラフ
* 3Dを使わないで3Dっぽく円グラフを作ってみた
/**
* Copyright cuegraphix ( http://wonderfl.net/user/cuegraphix )
* MIT License ( http://www.opensource.org/licenses/mit-license.php )
* Downloaded from: http://wonderfl.net/c/aKxs
*/
// forked from cuegraphix's PieChart
/**
* 円グラフ
* 3Dを使わないで3Dっぽく円グラフを作ってみた
*/
package {
import flash.display.Sprite;
import flash.events.Event;
import flash.events.MouseEvent;
[SWF(width=465, height=465, backgroundColor=0xFFFFFF, frameRate=60)]
public class PieChart extends Sprite {
public var chart:PieChart3D;
public function PieChart() {
//Wonderfl.capture_delay( 2 );
stage.scaleMode = "noScale";
chart = new PieChart3D();
chart.x = 465 / 2;
chart.y = 465 / 2;
chart.pieRadius = 200;
chart.pieGradientAngle = 30;
chart.pieHeight = 100;
chart.addData( new PieChartData( "A", 120 ) );
chart.addData( new PieChartData( "B", 228 ) );
chart.addData( new PieChartData( "C", 15 ) );
chart.addData( new PieChartData( "D", 362 ) );
chart.addData( new PieChartData( "E", 106 ) );
chart.addData( new PieChartData( "F", 149 ) );
chart.addData( new PieChartData( "G", 8 ) );
addChild(chart);
//stage.addEventListener(MouseEvent.CLICK, _click);
_click();
}
private function _click(e:MouseEvent = null):void {
chart.startDraw();
}
}
}
import caurina.transitions.Tweener;
import flash.display.Sprite;
import flash.events.Event;
import flash.events.MouseEvent;
import flash.geom.Matrix;
import flash.text.TextField;
import flash.text.TextFieldAutoSize;
import flash.text.TextFormat;
class PieChart3D extends Sprite {
private static const PI2:Number = 0.01745;
public static var S:int = 1;
public static var V:int = 1;
public var data:Array;
public var sum:Number;
// グラフの半径
public var pieRadius:Number = 100;
// グラフの高さ
public var pieHeight:Number = 50;
// グラフの傾き
public var pieGradientAngle:Number = 45;
private var _currentIndex:Number;
private var _currentAngle:Number;
private var _pies:Array;
private var _dragTarget:Sprite;
private var _toolTip:TextField;
public function get numData():int { return data.length; }
public function PieChart3D():void {
data = [];
}
public function addData(data:PieChartData):PieChartData {
this.data.push(data);
return data;
}
public function getDataAt(index:int):PieChartData {
return data[index] as PieChartData;
}
public function getPieAt(index:int):Sprite {
return _pies[index] as Sprite;
}
public function getPieIndex(display:Sprite):int {
for (var i:int = 0, l:int = _pies.length; i < l; i++ ) {
if (display == _pies[i]) { return i; }
}
return -1;
}
public function startDraw():void {
stopDraw();
while (numChildren) { removeChildAt(numChildren-1); }
// 初期設定
_pies = [];
_initialize();
_currentAngle =
_currentIndex = 0;
addEventListener(Event.ENTER_FRAME, _draw);
}
public function stopDraw():void {
removeEventListener(Event.ENTER_FRAME, _draw);
}
private function _draw(e:Event):void {
_currentAngle++;
var pie:Sprite = getPieAt(_currentIndex);
if (!pie) { return; }
pie.graphics.clear();
var d:PieChartData = getDataAt(_currentIndex);
if ( _currentAngle > d.endAngle) { _currentAngle = d.endAngle; }
var a:Number, b:Number;
var kh:Number = pieGradientAngle / 90;
// 断面1
a = _getX(d.startAngle) * pieRadius;
b = _getY(d.startAngle) * pieRadius * kh;
pie.graphics.beginFill(d.color1);
pie.graphics.moveTo(0, 0);
pie.graphics.lineTo(0, pieHeight);
pie.graphics.lineTo(a, b + pieHeight);
pie.graphics.lineTo(a, b);
pie.graphics.endFill();
// 断面2
a = _getX(_currentAngle) * pieRadius;
b = _getY(_currentAngle) * pieRadius * kh;
pie.graphics.beginFill(d.color1);
pie.graphics.moveTo(0, 0);
pie.graphics.lineTo(0, pieHeight);
pie.graphics.lineTo(a, b + pieHeight);
pie.graphics.lineTo(a, b);
pie.graphics.endFill();
var ang:Number, sep:Number, sepang:Number, r:Number, i:int;
// 外壁
if (_currentAngle > 90 && ((d.startAngle < 180 && d.endAngle >= 90) || (d.endAngle >= 90 && d.startAngle < 270))) {
var colors:Array = [d.color1, d.color2];
var alphas:Array = [100, 100];
var ratios:Array = [0, 0xFF];
var matrix:Matrix = new Matrix();
matrix.createGradientBox(pieRadius * 2, pieRadius * 2, 0, pieRadius, pieRadius * kh);
pie.graphics.beginGradientFill("linear", colors, alphas, ratios, matrix);
var startAngle:Number = Math.max(d.startAngle, 90);
var endAngle:Number = Math.min(_currentAngle, 270);
ang = endAngle - startAngle;
sep = Math.ceil(ang / 30);
sepang = ang / sep;
r = pieRadius / Math.cos(sepang / 2 * PI2);
pie.graphics.moveTo(_getX(startAngle) * pieRadius, _getY(startAngle) * pieRadius * kh);
for ( i = 0; i < sep; i++ ) {
pie.graphics.lineTo(_getX(startAngle + sepang * i) * pieRadius, _getY(startAngle + sepang * i) * pieRadius * kh + pieHeight);
pie.graphics.curveTo(_getX(startAngle + sepang * i + sepang / 2) * r, _getY(startAngle + sepang * i + sepang / 2) * r * kh + pieHeight, _getX(startAngle + sepang * (i + 1)) * pieRadius, _getY(startAngle + sepang * (i + 1)) * pieRadius * kh + pieHeight);
pie.graphics.lineTo(0, 0);
}
pie.graphics.lineTo(_getX(endAngle) * pieRadius, _getY(endAngle) * pieRadius * kh + pieHeight);
pie.graphics.lineTo(_getX(endAngle) * pieRadius, _getY(endAngle) * pieRadius * kh);
pie.graphics.endFill();
}
// 上面
ang = _currentAngle - d.startAngle;
sep = Math.ceil(ang / 30);
sepang = ang / sep;
r = pieRadius / Math.cos(sepang / 2 * PI2);
pie.graphics.beginFill(d.color);
for (i = 0; i < sep; i++) {
pie.graphics.moveTo(0, 0);
pie.graphics.lineTo(_getX(d.startAngle + sepang * i) * pieRadius, _getY(d.startAngle + sepang * i) * pieRadius * kh);
pie.graphics.curveTo(_getX(d.startAngle + sepang * i + sepang / 2) * r, _getY(d.startAngle + sepang * i + sepang / 2) * r * kh, _getX(d.startAngle + sepang * (i + 1)) * pieRadius, _getY(d.startAngle + sepang * (i + 1)) * pieRadius * kh);
pie.graphics.lineTo(0, 0);
}
pie.graphics.endFill();
if (_currentAngle >= d.endAngle) {
_currentIndex++;
if (_currentIndex >= numData) {
removeEventListener(Event.ENTER_FRAME, _draw);
}
}
}
private function _getX(angle:Number):Number { return Math.cos((angle - 90) * PI2); }
private function _getY(angle:Number):Number { return Math.sin((angle - 90) * PI2); }
private function _initialize():void {
// 合計
sum = 0;
data.forEach(function(item:*, index:int, arr:Array):void { sum += item.value; } );
// 多い順にソート
data.sortOn("value", Array.DESCENDING | Array.NUMERIC);
var angle:Number = 0;
var swapArr:Array = [];
for (var i:int = 0, l:int = numData; i < l; i++) {
var d:PieChartData = data[i];
// 角度
d.startAngle = angle;
d.endAngle = angle + d.value / sum * 360;
var argAngle:Number = (d.endAngle - d.startAngle) / 2 + d.startAngle
swapArr.push({ index:i, lebel:argAngle > 180 ? 360 - argAngle : argAngle });
// 色
var c:int =
d.color = angle2RGB(angle);
var r1:int = Math.max(0, ((c >> 16) - 0x22));
var r2:int = Math.max(0, ((c >> 16) - 0x44));
c %= 0x10000;
var g1:int = Math.max(0, ((c >> 8) - 0x22));
var g2:int = Math.max(0, ((c >> 8) - 0x44));
c %= 0x100;
var b1:int = Math.max(0, (c - 0x22));
var b2:int = Math.max(0, (c - 0x44));
d.color1 = r1 << 16 | g1 << 8 | b1;
d.color2 = r2 << 16 | g2 << 8 | b2;
angle = d.endAngle;
}
// 表示順のZソートして Sprite 作成
swapArr.sortOn("lebel", Array.NUMERIC);
swapArr.forEach(function(item:*, index:int, arr:Array):void {
var pie:Sprite = new Sprite();
pie.buttonMode = true;
pie.addEventListener(MouseEvent.ROLL_OVER, _rollOver);
pie.addEventListener(MouseEvent.MOUSE_DOWN, _mouseDown);
addChild(pie);
_pies[item["index"]] = pie;
});
}
private function angle2RGB(angle:Number):uint {
if ( angle < 0 ) { angle += 360; }
angle %= 360;
var h:int = Math.floor( angle / 60 );
var f:Number = angle / 60 - h;
var min:int = 0;
var max:int = 0xFF;
var u:int = min + ( f * max );
var d:int = max - ( f * max );
var r:int, g:int, b:int;
switch (h) {
case 0 : { r = max; g = u; b = min; break; }
case 1 : { r = d; g = max; b = min; break; }
case 2 : { r = min; g = max; b = u; break; }
case 3 : { r = min; g = d; b = max; break; }
case 4 : { r = u; g = min; b = max; break; }
case 5 : { r = max; g = min; b = d; break; }
}
return r << 16 | g << 8 | b;
}
private function angle2Value(angle:Number):uint {
if ( angle < 0 ) { angle += 360; }
angle %= 360;
var val:int;
if (angle < 60) { val = angle / 60; }
else if (angle < 180) { val = 0; }
else if (angle < 240) { val = (240 - angle) / 60; }
else { val = 0; }
trace(angle,val)
return val;
}
private function _rollOver(e:MouseEvent):void {
if (_toolTip) { parent.removeChild(_toolTip); _toolTip = null; }
var d:PieChartData = getDataAt(getPieIndex(Sprite(e.target)));
if (!d) { return; }
_toolTip = new TextField();
_toolTip.autoSize = TextFieldAutoSize.LEFT;
_toolTip.background = true;
_toolTip.backgroundColor = 0xFFFFEE;
_toolTip.border = true;
_toolTip.borderColor = 0x0;
_toolTip.mouseEnabled = false;
_toolTip.text = d.name + ":" + d.value + "/" + sum;
_toolTip.x = stage.mouseX;
_toolTip.y = stage.mouseY - 16;
parent.addChild(_toolTip);
addEventListener(MouseEvent.MOUSE_MOVE, _mouseMove);
}
private function _mouseMove(e:MouseEvent):void {
_toolTip.x = stage.mouseX;
_toolTip.y = stage.mouseY - 16;
}
private function _mouseDown(e:MouseEvent):void {
_dragTarget = Sprite(e.target);
_dragTarget.startDrag();
_dragTarget.addEventListener(MouseEvent.MOUSE_UP, _mouseUp);
stage.addEventListener(MouseEvent.MOUSE_UP, _mouseUp);
}
private function _mouseUp(e:MouseEvent):void {
_dragTarget.removeEventListener(MouseEvent.MOUSE_UP, _mouseUp);
stage.removeEventListener(MouseEvent.MOUSE_UP, _mouseUp);
removeEventListener(MouseEvent.MOUSE_MOVE, _mouseMove);
if (_toolTip) { parent.removeChild(_toolTip); _toolTip = null; }
_dragTarget.stopDrag();
Tweener.addTween(_dragTarget, { x:0, y:0, time:0.2, onComplete:function():void { _dragTarget = null; } } );
}
}
class PieChartData {
public var name:String;
public var value:Number;
public var color:int;
public var color1:int;
public var color2:int;
public var startAngle:Number;
public var endAngle:Number;
public var lebel:int;
public function PieChartData(name:String, value:Number) {
this.name = name;
this.value = value;
}
}