グラフ。リアルタイムに波形を生成描画
/**
* Copyright shinano_cake_koubou ( http://wonderfl.net/user/shinano_cake_koubou )
* MIT License ( http://www.opensource.org/licenses/mit-license.php )
* Downloaded from: http://wonderfl.net/c/mEij
*/
package {
import flash.display.Bitmap;
import flash.display.BitmapData;
import flash.display.Shape;
import flash.display.Sprite;
import flash.display.StageAlign;
import flash.display.StageQuality;
import flash.display.StageScaleMode;
import flash.events.Event;
import flash.events.TimerEvent;
import flash.text.AntiAliasType;
import flash.text.TextField;
import flash.text.TextFieldAutoSize;
import flash.text.TextFormat;
import flash.utils.Timer;
[SWF (width=465, height=465, backgroundColor="#666666")]
public class GraphSprite extends Sprite
{
/*======================================================================================*/
/* データ用 */
/*======================================================================================*/
private var data:Array = new Array();
private var xAxisData:Array = null;
private var line:Sprite = new Sprite();
/*======================================================================================*/
/* Variables */
/*======================================================================================*/
/* ------------- グラフの幅、高さなど -------------- */
private var _graphWidth:int = 400; /* グラフの幅 */
private var _graphHeight:int = 250; /* グラフの高さ */
private var _graphPaddingLeft:int = 60; /* グラフの余白(左)*/
private var _graphPaddingRight:int = 40; /* グラフの余白(右)*/
private var _graphPaddingTop:int = 40; /* グラフの余白(上)*/
private var _graphPaddingBottom:int = 40; /* グラフの余白(下)*/
/* ---------- 表示するテキストの値など ------------ */
private var _title:String = "title"; /* タイトル */
/* --------- 色など、描画オブジェクトの設定値 -------- */
/* #public */
/** 背景色 */
public var bgColor:int = 0xFFFFFF;
/** 軸の色 */
public var baseLineColor:int = 0xAA0000;
/** 補助線の色 */
public var auxLineColor:int = 0xBBBBBB;
/* #private */
private const scaleTextColor:int = 0x555555; /* 目盛のテキストの色 */
private const titleTextColor:int = 0x333333; /* タイトルのテキストの色 */
private const labelTextColor:int = 0x333333; /* 軸ラベルのテキストの色 */
private const titleFontSize:int = 16; /* タイトルのフォントサイズ */
private const scaleFontSize:int = 12; /* 目盛のフォントサイズ */
private const labelFontSize:int = 12; /* 軸ラベルのフォントサイズ */
private var _scaleTextFormat:TextFormat; /* 目盛用のテキストフォーマット */
private var _titleTextFormat:TextFormat; /* タイトル用のテキストフォーマット */
private var _xLabelTextFormat:TextFormat; /* x軸ラベル用のテキストフォーマット */
private var _yLabelTextFormat:TextFormat; /* y軸ラべル用のテキストフォーマット */
/* ----------- 座標などのパラメータ -------------- */
private var graphAxisX:int = 0; /* x軸の位置 */
private var graphAxisY:int = ((_graphHeight/2)-_graphPaddingTop); /* y軸の位置 */
private var base_sx:int; /* x軸方向描画始点(左) */
private var base_ex:int; /* x軸方向描画終点(右) */
private var base_sy:int; /* y軸方向描画始点(上) */
private var base_ey:int; /* y軸方向描画終点(下) */
private var gl_x:int; /* 描画開始地点を考慮した、軸 の位置 (x)*/
private var gl_y:int; /* 描画開始地点を考慮した、軸 の位置 (y)*/
private var stepX:int = 0; /* 目盛の間隔(データの間隔) (x軸方向) */
private var stepY:int = 0; /* 目盛の間隔(ピクセル間隔) (y軸方向) */
private var _autoScaleX:Number = 1.0; /* x軸方向倍率(セットされたデータに対して自動的にリスケールを実施するための倍率) */
private var _autoScaleY:Number = 1.0; /* y軸方向倍率(セットされたデータに対して自動的にリスケールを実施するための倍率) */
/* ---------- 描画のためのオブジェクト ------------ */
private var axisLine:Shape = new Shape(); /* 軸線 */
private var auxLineX:Shape = new Shape(); /* 補助目盛線 (x座標) */
private var auxLineY:Shape = new Shape(); /* 補助目盛線 (y座標) */
private var base:Shape = new Shape(); /* 背景 */
private var scaleTexts:Array = new Array(); /* 目盛用のテキストを保持する配列 */
private var xLabelText:TextField; /* x軸に付ける名前 */
private var yLabelText:TextField; /* y軸に付ける名前 */
private var titleText:TextField; /* グラフのタイトル */
/*======================================================================================*/
/* Public function */
/*======================================================================================*/
/** コンストラクタ */
public function GraphSprite()
{
initSetting(); /* 初期設定 */
initPosVal(); /* 座標の初期化 */
createBackGround(); /* 背景の描画 */
createTitle(); /* タイトルの描画 */
createAxisLabel(); /* 軸のラベルの描画 */
createBaseLine(); /* 軸などの描画 */
exec(); /* データの生成 */
}
/*======================================================================================*/
/* Internal function */
/*======================================================================================*/
/*======================================================================================*/
/* 初期化関数 */
/*======================================================================================*/
/** スプライトの初期化 */
private function initSetting():void
{
//stage.quality = StageQuality.HIGH;
//stage.frameRate = 60;
stage.scaleMode = StageScaleMode.NO_SCALE;
stage.align = StageAlign.TOP;
}
/** 座標系の変数の初期化 */
private function initPosVal():void
{
base_sx = _graphPaddingLeft + 10; /* x軸方向描画始点(左) */
base_ex = _graphWidth - _graphPaddingRight+ 10; /* x軸方向描画終点(右) */
base_sy = _graphPaddingTop + 10; /* y軸方向描画始点(上) */
base_ey = _graphHeight - _graphPaddingBottom + 10; /* y軸方向描画終点(下) */
gl_x = base_sx + graphAxisX; /* 描画開始地点を考慮した、軸 の位置 (x)*/
gl_y = base_sy + graphAxisY; /* 描画開始地点を考慮した、軸 の位置 (y)*/
}
/*======================================================================================*/
/* オブジェクトの追加、作成など */
/*======================================================================================*/
/** 背景の作成 */
private function createBackGround():void
{
/* base */
this.addChild(base);
this.drawBackGround();
}
/** 軸、メモリなどの作成 */
private function createBaseLine():void
{
this.addChild(auxLineX);
this.addChild(auxLineY);
this.addChild(axisLine);
this._scaleTextFormat = new TextFormat();
this._scaleTextFormat.color = this.scaleTextColor;
this._scaleTextFormat.size = this.scaleFontSize;
drawBaseLine();
}
/** タイトルの作成 */
private function createTitle():void
{
this.titleText = createTextField(this._title,0,0); /* テキストフィールドの作成 */
this._titleTextFormat = new TextFormat(); /* テキストフォーマットの作成 */
this._titleTextFormat.color = this.titleTextColor; /* テキストの色 */
this._titleTextFormat.size = this.titleFontSize; /* フォントサイズ */
this.titleText.setTextFormat(this._titleTextFormat);/* テキストフィールドに適用 */
this.addChild(titleText); /* 追加 */
this.drawTitle(); /* タイトルの描画 */
}
/** 軸のラベルを作成 */
private function createAxisLabel():void
{
/* x軸のラベル */
this.xLabelText = createTextField("Time(sec)",0,0);/* テキストフィールドの作成 */
this._xLabelTextFormat = new TextFormat(); /* テキストフォーマットの作成 */
this._xLabelTextFormat.color = this.labelTextColor; /* テキストの色 */
this._xLabelTextFormat.size = this.labelFontSize; /* フォントサイズ */
this.xLabelText.setTextFormat(this._titleTextFormat);/* テキストフィールドにフォーマットの適用 */
this.addChild(xLabelText);
/* y軸のラベル */
this.yLabelText = createTextField("Amplitude",0,0);/* テキストフィールドの作成 */
this._yLabelTextFormat = new TextFormat(); /* テキストフォーマットの作成 */
this._yLabelTextFormat.color = this.labelTextColor; /* テキストの色 */
this._yLabelTextFormat.size = this.labelFontSize; /* フォントサイズ */
this.yLabelText.setTextFormat(this._titleTextFormat);/* テキストフィールドにフォーマットの適用 */
/* ビットマップにして回転 */
var yLabelTextBmpData:BitmapData = new BitmapData(this.yLabelText.textWidth+5,this.yLabelText.textHeight+5,true);
yLabelTextBmpData.draw(this.yLabelText);
var yLabelTextBmp:Bitmap = new Bitmap(yLabelTextBmpData,"auto",true);
yLabelTextBmp.rotation = -90;
/* 真ん中になるようにする */
yLabelTextBmp.x = ((this._graphPaddingLeft - yLabelTextBmpData.height) >>1) - (yLabelTextBmpData.height>>1) + 10;
yLabelTextBmp.y = ((this._graphHeight - yLabelTextBmpData.width) >>1) + (yLabelTextBmpData.width) + 10;
this.addChild(yLabelTextBmp);
this.drawAxisLabel();
}
/*======================================================================================*/
/* 背景の描画 */
/*======================================================================================*/
private function drawBackGround():void
{
base.graphics.clear();
base.graphics.beginFill(bgColor,1);
base.graphics.drawRoundRect(10,10,_graphWidth,_graphHeight,10,10);
base.graphics.endFill();
}
/*======================================================================================*/
/* 軸の描画 */
/*======================================================================================*/
/** 軸の描画 */
private function drawBaseLine():void
{
/* 初期化 */
this.axisLine.graphics.clear();
this.axisLine.graphics.lineStyle(1,baseLineColor,100,true);
this.auxLineX.graphics.clear();
this.auxLineX.graphics.lineStyle(1,auxLineColor,100,true);
this.auxLineY.graphics.clear();
this.auxLineY.graphics.lineStyle(1,auxLineColor,100,true);
/* 以前追加した目盛のラベルを削除 */
while(scaleTexts.length > 0){
this.removeChild(this.scaleTexts.pop());
}
/* 描画処理 */
this.drawAxis(); /* 軸の描画 */
this.drawScale(); /* 軸の目盛の描画 */
this.drawAuxScaleX(); /* x軸方向の補助目盛の描画 */
this.drawAuxScaleY(); /* y軸方向の補助目盛の描画 */
}
/** x軸,y軸の描画 */
private function drawAxis():void
{
axisLine.graphics.moveTo(base_sx ,gl_y); /* x軸の描画 */
axisLine.graphics.lineTo(base_ex ,gl_y);
axisLine.graphics.moveTo(gl_x ,base_sy); /* y軸の描画 */
axisLine.graphics.lineTo(gl_x ,base_ey);
}
/** 目盛の描画 */
private function drawScale():void
{
/* ----------- x軸の目盛の描画 --------------*/
var l_StepX:int = stepX; /* 軸の間隔 */
if(l_StepX == 0){ /* 軸の間隔が設定されていないとき */
l_StepX = this.data.length / 10; /* 自動設定 する*/
}
var i:int = 0;
for(i = 1; i < (this._graphWidth - (this._graphPaddingLeft+this._graphPaddingRight )-1) ; i++ ){
if( i % int(this._autoScaleX*l_StepX) == 0){
axisLine.graphics.moveTo(gl_x+i ,gl_y-7); /* 軸の線を描画 */
axisLine.graphics.lineTo(gl_x+i ,gl_y);
/* 軸の文字列を描画 */
if(xAxisData != null){ /* 文字列用データがセットしてあるとき */
addScaleTextX(xAxisData[int(i/this._autoScaleX)]+"",gl_x+i,gl_y);
}else{
addScaleTextX(i+"",gl_x+i,gl_y);
}
}
}
/* ----------- y軸の目盛の描画 --------------*/
var l_StepY:int = stepY; /* 軸の間隔 */
if(l_StepY == 0){ /* 軸の間隔が設定されていないとき */
/* 自動設定する */
l_StepY = (this._graphHeight-(this._graphPaddingTop+this._graphPaddingBottom))/10;
}
var labelVal:Number;
/* GLより上 */
for(i = 0; i <= Math.abs(base_sy-gl_y) ; i++ ){
labelVal = Math.round((i/this._autoScaleY)*100.0)/100.0; /* 自動スケール時の計算 */
if( i % l_StepY == 0){
axisLine.graphics.moveTo(gl_x-7,gl_y-i);
axisLine.graphics.lineTo(gl_x,gl_y-i);
addScaleTextY(labelVal+"",gl_x,gl_y-i);
}
}
/* GLより下 */
for(i = 1 ; i <= Math.abs(base_ey-gl_y) ; i++ ){
labelVal = Math.round((-i/this._autoScaleY)*100.0)/100.0;
if( i % l_StepY == 0){
axisLine.graphics.moveTo(gl_x-7,gl_y+i);
axisLine.graphics.lineTo(gl_x,gl_y+i);
addScaleTextY(labelVal+"",gl_x,gl_y+i);
}
}
}
/** x軸方向の軸の項目を描画 */
private function addScaleTextX(val:String,x:int,y:int):void
{
var t:TextField = this.createTextField(val,x,y); /* テキストの作成 */
t.defaultTextFormat = this._scaleTextFormat; /* テキストフォーマットの設定 */
t.setTextFormat(this._scaleTextFormat);
t.x = x - t.textWidth/2; /* x座標(軸の中心 */
this.addChild(t); /* 追加 */
scaleTexts.push(t); /* 削除用にとっておく */
}
/** y軸方向の軸の項目を描画 */
private function addScaleTextY(val:String,x:int,y:int):void
{
var t:TextField = this.createTextField(val,x,y); /* テキストの作成 */
t.defaultTextFormat = this._scaleTextFormat; /* テキストフォーマットの設定 */
t.setTextFormat(this._scaleTextFormat);
t.x = x - t.textWidth-10; /* x座標(軸の左に寄せる) */
t.y = y - t.textHeight/2; /* y座標(軸の中心) */
this.addChild(t); /* 追加 */
scaleTexts.push(t); /* 削除用にとっておく */
}
/** 軸目盛用テキストの作成 */
private function createTextField(val:String,x:int,y:int):TextField
{
var t:TextField = new TextField();
t.antiAliasType = AntiAliasType.ADVANCED;
t.autoSize = TextFieldAutoSize.NONE;
t.text = val;
t.x = x;
t.y = y;
return t;
}
/*======================================================================================*/
/* 補助目盛線の描画 */
/*======================================================================================*/
/** 補助目盛線を描画(X軸) */
private function drawAuxScaleX():void
{
var l_StepX:int = stepX; /* 軸の間隔 */
if(l_StepX == 0){ /* 軸の間隔が設定されていないとき */
l_StepX = this.data.length / 10; /* 自動設定 する*/
}
/* 描画の終点 */
var endX:int = (this._graphWidth - /* 幅 */
(this._graphPaddingLeft+this._graphPaddingRight) /* 余白 */
-1) ;
for(var i:int = 1; i < endX; i++ ){
if( i % int(this._autoScaleX*l_StepX) == 0){ /* 指定した間隔ごとに */
auxLineX.graphics.moveTo(base_sx+i ,base_sy); /* 軸の線を描画 */
auxLineX.graphics.lineTo(base_sx+i ,base_ey);
}
}
}
/** 補助目盛線を描画(Y軸) */
private function drawAuxScaleY():void
{
var l_StepY:int = stepY; /* 軸の間隔 */
if(l_StepY == 0){ /* 軸の間隔が設定されていないとき */
/* 自動設定する */
l_StepY = (this._graphHeight-(this._graphPaddingTop+this._graphPaddingBottom))/10;
}
var i:int = 0;
/* GLより上 */
for(i = 1; i <= Math.abs(base_sy-gl_y) ; i++ ){
if( i % l_StepY == 0){
auxLineY.graphics.moveTo(base_sx,gl_y-i);
auxLineY.graphics.lineTo(base_ex,gl_y-i);
}
}
/* GLより下 */
for(i = 1 ; i <= Math.abs(base_ey-gl_y) ; i++ ){
if( i % l_StepY == 0){
auxLineY.graphics.moveTo(base_sx-7,gl_y+i);
auxLineY.graphics.lineTo(base_ex,gl_y+i);
}
}
}
/*======================================================================================*/
/* その他の描画 */
/*======================================================================================*/
/** タイトルの描画 */
private function drawTitle():void
{
this.titleText.autoSize = TextFieldAutoSize.CENTER;
this.titleText.x = ((this._graphWidth - titleText.textWidth) >>1) + 10; /* 真ん中になるようにする */
this.titleText.y = ((this._graphPaddingTop - titleText.textHeight) >>1) + 10 ;
this.titleText.text = this._title;
this.titleText.setTextFormat(this._titleTextFormat);
}
/** 軸のラベルの描画 */
private function drawAxisLabel():void
{
this.xLabelText.autoSize = TextFieldAutoSize.CENTER;
this.xLabelText.x = ((this._graphWidth - xLabelText.textWidth) >>1) + 10 ;/* 真ん中になるようにする */
this.xLabelText.y = this._graphHeight - this._graphPaddingBottom + ((this._graphPaddingBottom - xLabelText.textHeight) >>1) + 10;
this.xLabelText.setTextFormat(this._titleTextFormat);
}
/*======================================================================================*/
/* その他描画関連 */
/*======================================================================================*/
/** 自動スケール処理を行う */
public function doAutoScale():void
{
/* 自動スケールのための倍率を計算 */
var max:Number = getMaxValue();
var min:Number = getMinValue();
/* y軸方向の倍率 */
var upper:Number = Math.abs(this.base_sy-gl_y);
var under:Number = Math.abs(this.base_ey-gl_y);
var tArea:Number = (upper) < (under) ? upper : under;
max = max > Math.abs(min) ? max : Math.abs(min);
if(max != 0){
this._autoScaleY = tArea / Math.abs(max);
}else{
this._autoScaleY = 1;
}
/* x軸方向の倍率 */
this._autoScaleX = Number(this._graphWidth) / Number(this.data.length) ;
}
/** 再描画 */
public function refleshLines():void
{
this.drawBaseLine();
this.drawGraph();
}
/** 再描画 */
public function refleshAll():void
{
this.initPosVal(); /* 座標再調整 */
this.doAutoScale(); /* 自動拡大縮小 */
this.drawBackGround(); /* 背景の描画 */
this.drawTitle(); /* タイトルの描画 */
this.drawAxisLabel(); /* 軸のラベルの描画 */
this.refleshLines(); /* 線の再描画 */
}
/*======================================================================================*/
/* その他 */
/*======================================================================================*/
/** データの最大値を得る */
private function getMaxValue():Number
{
var max:Number = data[0]; /* 最大値 */
for(var i:int = 1; i < data.length; i++){
if(max < data[i]){ /* 一番大きなデータを探す */
max = data[i];
}
}
return max;
}
/** データの最小値を得る */
private function getMinValue():Number
{
var min:Number = data[0]; /* 最小値 */
for(var i:int = 1; i < data.length; i++){
if(min > data[i]){ /* 一番大きなデータを探す */
min = data[i];
}
}
return min;
}
/** 表示するデータの変更 */
public function setData(data:Array):void
{
if( data == null || data.length == 0){
return ;
}
this.data = data;
this.doAutoScale();
}
/** x軸方向の軸用データ */
public function setXAxisData(data:Array):void
{
this.xAxisData = data;
}
/*======================================================================================*/
/* 作業用 */
/*======================================================================================*/
public function exec():void
{
/* データ の作成 */
var data:Array = new Array();
/* サイン波初期化 */
initSinGen(2,250,1);
/* x軸方向のデータ */
var xdata:Array = new Array();
for(var i:int = 0;i < 400 ; i++){
data[i] = nextWave();
xdata[i] = Number(i)/Number(250);
}
/* データのセット */
this._title = "Sine Wave";
this.setData(data);
this.setXAxisData(xdata);
this.refleshAll();
/* タイマー起動 */
var timer:Timer = new Timer(30);
timer.addEventListener(TimerEvent.TIMER,onTimer);
timer.start();
this.addChild(line);
}
/** タイマ関数 */
private function onTimer(e:Event):void
{
/** グラフのシフト */
for(var j:int = 0; j < 4 ; j++){
for(var i:int = 0;i < 400 ; i++){
data[i] = data[i+1];
}
data[400-1] = nextWave();
}
this.setData(data);
this.refleshLines();
}
/** グラフの描画 */
private function drawGraph():void
{
line.graphics.clear();
line.graphics.lineStyle(1,0x5c3f4b,100,true);
for(var i:int = 0; i*this._autoScaleX < this._graphWidth - (this._graphPaddingLeft+this._graphPaddingRight) -1 ; i++ ){
var startX:int = base_sx + (i) *this._autoScaleX;
var endX:int = base_sx + (i+1) *this._autoScaleX;
var startY:int = gl_y - data[i] *this._autoScaleY;
var endY:int = gl_y - data[i+1] *this._autoScaleY;
line.graphics.moveTo(startX ,startY);
line.graphics.lineTo(endX ,endY);
}
}
/*======================================================================================*/
/* 信号生成 */
/*======================================================================================*/
private var siny:Array = new Array(3); /* サイン波生成用 バッファ */
private var angle:Number = 0; /* 角度(ラジアン) */
private var a1:Number = 0.0; /* 係数1 */
private var a2:Number = 0.0; /* 係数2 */
private var freq:int = 0; /* 周波数 */
private var amp:Number = 1; /* 振幅 */
private var sample:int = 250; /* サンプリングレート */
/**
* サイン波生成のための変数の初期化処理をする
* @param freq 生成するサイン波の周波数
* @param sample サンプリング周波数
* @param amp 生成するサイン波の振幅
*/
public function initSinGen(freq:int,sample:int,amp:Number):void{
/* 一回あたりに変化する角度の量 */
angle = (2 * Math.PI * Number(freq)) / Number(sample);
siny[0] = 0.0;
siny[1] = Math.sin(angle);
siny[2] = 0.0;
a1 = 2.0 * Math.cos(this.angle);
a2 = -1.0;
}
/**
* つぎのサイン波を返す
* @return つぎのサイン波
*/
public function nextWave():Number{
var wave:Number = (siny[0]*amp);
siny[0] = a1 * siny[1] + a2 * siny[2];
//シフト
siny[2] = siny[1];
siny[1] = siny[0];
return wave;
}
}
}