nodeInfo
引き出し線(leader line)
/**
* Copyright tepe ( http://wonderfl.net/user/tepe )
* MIT License ( http://www.opensource.org/licenses/mit-license.php )
* Downloaded from: http://wonderfl.net/c/bBN7
*/
// forked from umhr's 敵機急速接近中!
package
{
import flash.display.GradientType;
import flash.display.Sprite;
import flash.events.Event;
import flash.geom.Matrix;
import flash.geom.Matrix3D;
import flash.geom.Vector3D;
/**
* 引き出し線(leader line)
*/
[SWF(width = 465, height = 465, backgroundColor = 0x000000, frameRate = 30)]
public class Main extends Sprite
{
private var _canvas:Sprite = new Sprite();
private var _count:int;
private var _nodeList:Vector.<Node> = new Vector.<Node>();
/**
* Nodeにまとめちゃうともっとみやすいコードになりそうだけど、
* 計算時間が倍近くかかるので、躊躇
*/
private var _pointXList:Vector.<Number> = new Vector.<Number>();
private var _pointYList:Vector.<Number> = new Vector.<Number>();
private var _pointList:Vector.<Vector3D> = new Vector.<Vector3D>();
public function Main()
{
init();
}
private function init():void
{
if (stage) onInit();
else addEventListener(Event.ADDED_TO_STAGE, onInit);
}
private function onInit(event:Event = null):void
{
removeEventListener(Event.ADDED_TO_STAGE, init);
// entry point
with(_canvas.graphics){//背景描画
beginFill(0x000000);
drawRect(-200,-200, 465, 465);
endFill();
}
this.addChild(_canvas);
var n:int = 20;
_canvas.x = 200;
_canvas.y = 200;
for (var i:int = 0; i < n; i++)
{
_nodeList[i] = new Node(i);
_nodeList[i].text = "node "+(i+1);
_canvas.addChild(_nodeList[i]);
_pointList[i] = new Vector3D(400 * (Math.random() - 0.5), 400 * (Math.random() - 0.5), 400 * (Math.random() - 0.5));
_nodeList[i].color = 0x00ff00;
_nodeList[i].alpha = 0.5;
}
//onEnterFrame(null);
this.addEventListener(Event.ENTER_FRAME, onEnterFrame);
}
private function onEnterFrame(e:Event):void
{
var matrix3D:Matrix3D = new Matrix3D();
var vector3D:Vector3D = new Vector3D(0.5, 0.8, 0.4);
vector3D.normalize();
matrix3D.appendRotation(_count, vector3D);
var n:int = _pointList.length;
for (var i:int = 0; i < n; i++)
{
vector3D = pertrans(matrix3D.transformVector(_pointList[i]));
_pointXList[i] = vector3D.x;
_pointYList[i] = vector3D.y;
}
escaper();
_count ++;
}
private function pertrans(vector3D:Vector3D):Vector3D {
var result:Vector3D = new Vector3D();
var per:Number = 1000 / (1000 + vector3D.z);
return new Vector3D(vector3D.x * per, vector3D.y * per, per);
}
/**
* 文字がぶつからないように、近くのノードとは反対方向を割り出す。
* 10フレームに一度だけにして、計算コストを低減。
*/
private function escaper():void {
//var time:Number = new Date().time;
var _radianList:Vector.<Number> = new Vector.<Number>();
var n:int = _pointXList.length;
var direction:Array = [];
var i:int;
var j:int;
if (_count%20 == 0) {//処理間隔
for (i = 0; i < n; i++) {//ノード
//八方向に
direction = [0, 0, 0, 0, 0, 0, 0, 0];
for (j = 0; j < n; j++){
if (i == j) { continue };//同一ノードを省略
var px:Number = _pointXList[i] - _pointXList[j];
var py:Number = _pointYList[i] - _pointYList[j];
var length:Number = px * px + py * py;
if (length > 2500) { continue };
var r:int = int((8.5 + 4 * Math.atan2(py, px) / Math.PI) %8);
length = 1 / length;
direction[(6 + r) % 8] += length * 0.5;
direction[(7 + r) % 8] += length * 0.7;
direction[r] += length;
direction[(1 + r) % 8] += length * 0.7;
direction[(2 + r) % 8] += length * 0.5;
}
var compass:int = direction.sort(Array.NUMERIC | Array.RETURNINDEXEDARRAY)[7];
_nodeList[i].radian = Math.PI * compass / 4;
}
}
for (i = 0; i < n; i++){
_nodeList[i].draw(_pointXList[i], _pointYList[i]);
}
}
}
}
/**
* ノードです。
*/
import flash.display.*;
import flash.text.TextField;
class Node extends Sprite {
private var _radian:Number;
private var direction:Number = 0;
private var _textField:TextField = new TextField();
private var _target:Shape = new Shape();
private var _color:uint = 0xccccff;
//エントリ
public function Node(index:int) {
with(_textField){//テキストスタイル
textColor = _color;//カラー
autoSize = "left";
cacheAsBitmap = true;//内部表現キャッシュ
multiline = false;
selectable = false;//テキスト選択不可
}
this.addChild(_textField);
if(index == 0){
_target.graphics.beginFill(0xFF0000, 1);
}else {
_target.graphics.beginFill(0x009966, 1);
}
_target.graphics.drawCircle(x , y , 2);//ノード
_target.graphics.endFill();
this.addChild(_target);
}
public function draw2(x:Number,y:Number,tx:Number,ty:Number):void{
this.graphics.clear();
StageAlign.TOP_LEFT
_textField.y = ty;
_target.x = x;
_target.y = y;
with(this.graphics){
lineStyle(0, _color);
moveTo(x , y );
if(x+tx < x){
_textField.x = tx + x-_textField.textWidth;
lineTo(x+tx, ty +_textField.textHeight);
moveTo(x+tx,ty+_textField.textHeight);
lineTo(x+tx-_textField.textWidth,ty+_textField.textHeight);
}
else{
_textField.x = tx + x;
lineTo(tx + x, ty +_textField.textHeight);
moveTo(x+tx,ty+_textField.textHeight);
lineTo(x+tx+_textField.textWidth,ty+_textField.textHeight);
}
}
}
//描画
public function draw(x:Number, y:Number, tx:Number=0, ty:Number=0):void {
this.graphics.clear();
direction = radian * 0.1 + direction * 0.9;
//テキスト位置
var tx:Number = Math.cos(direction) * 40;
var ty:Number = Math.sin(direction) * 20;
var x2:Number = x+(tx/4);
var y2:Number = y+(ty/4);
_textField.y = ty + y2 -_textField.height;
_target.x = x;
_target.y = y;
with(this.graphics){
lineStyle(0, _color);
moveTo(x2 , y2 );
if(x+tx < x){
_textField.x = tx + x2-_textField.textWidth;
lineTo(x2+tx, ty + y2 );
moveTo(x2+tx,y2+ty);
lineTo(x2+tx-_textField.textWidth,y2+ty);
}
else{
_textField.x = tx + x2;
lineTo(tx + x2, ty + y2 );
moveTo(x2+tx,y2+ty);
lineTo(x2+tx+_textField.textWidth,y2+ty);
}
}
}
public function get color():uint { return _color; };
public function set color( value:uint ):void {
_color = value;
_textField.textColor = _color;
}
public function get text():String{ return _textField.text; };
public function set text(s:String):void{ _textField.text = s; };
public function get radian():Number { return _radian; }
public function set radian(value:Number):void
{
if (Math.abs(value-direction) > Math.PI) {
if (value>direction) {
value -= Math.PI * 2;
}else {
direction -= Math.PI * 2;
}
}
_radian = value;
}
}