メモ:万能ではなくてもメモがあれば心理的壁が低くなる
数式をグラフ化してcanvasに表示する
前の記事
★星は暗いのではなく小さいのです-4
で数式をグラフ化してcanvas上に表示しました。
こんな感じのものです。
グラフ-1
軸スケール表示をn倍ベースにもできます
(この例ではX軸表示を63241で1光年としています、Y軸は計算式で対数としています)。
グラフ-2
上のグラフは次のコードで表示しています。
<script type="text/javascript" src="hiGraph.js" charset="UTF-8"></script>
<canvas width=495 height=200 id="graphCanvas2"></canvas>
<script type="text/javascript">
function $E(id){return document.getElementById(id);}
//=========== 計算式-1
function レンズ5mm(x_){
var _y = 1111;
if( x_>150 ){
_y= 25000000/(x_*x_);
}
return _y;
}
function レンズ2mm(x_){
var _y = 177;
if( x_>150 ){
_y= 4000000/(x_*x_);
}
return _y;
}
function 逆2乗(x_){
return 177/(x_*x_);
}
//=========== 説明-1
function 暗順応_説明(param_){
var _ctx= param_.ctx;
_ctx.save();
_ctx.textBaseline = "bottom";
_ctx.fillStyle="#FF0000";
_ctx.fillText("距離の2乗に反比例",param_.start_x+3,param_.end_y-6);
_ctx.fillStyle="#0000FF";
_ctx.fillText("像の明るさ(2mm)",param_.start_x+3,param_.end_y-31);
_ctx.fillStyle="#008800";
_ctx.fillText("像の明るさ(5mm)",param_.start_x+180,param_.end_y-31);
_ctx.restore();
}
//=========== グラフ-1
function 暗順応(canvas_name_){
var _param = new hiGraph_Param();
_param.canvas = $E(canvas_name_);
_param.margin_x = 10;
_param.margin_y = 10;
_param.offset_x = 30;
_param.offset_y = 10;
_param.range_x_s= 0;
_param.range_y_s= 0;
_param.range_x_e= 900;
_param.range_y_e= 1200;
hiGraph.axis(_param);
hiGraph.xScale(_param,200,200,200,200,"天文単位");
hiGraph.yScale(_param,200,200,200,200,"");
hiGraph.calc(_param,逆2乗 ,"#ff0000");
hiGraph.calc(_param,レンズ2mm,"#0000ff");
hiGraph.calc(_param,レンズ5mm,"#008800");
暗順応_説明(_param);
}
暗順応('graphCanvas2');
</script>
<script type="text/javascript" src="hiGraph.js" charset="UTF-8"></script>
<canvas width=495 height=200 id="graphCanvas3"></canvas>
<script type="text/javascript">
function $E(id){return document.getElementById(id);}
//=========== 数式-2
function レンズ5mm対数(x_){
var _y = 1111;
if( x_>150 ){
_y= 25000000/(x_*x_);
}
return Math.LOG10E *Math.log(_y/177);
}
function レンズ2mm対数(x_){
var _y = 177;
if( x_>150 ){
_y= 4000000/(x_*x_);
}
return Math.LOG10E *Math.log(_y/177);
}
function 逆2乗対数(x_){
return Math.LOG10E *Math.log(1/(x_*x_));
}
//=========== 説明-2
function 光年対数_説明(param_){
var _ctx= param_.ctx;
_ctx.save();
_ctx.textBaseline = "bottom";
_ctx.fillStyle="#FF0000";
_ctx.fillText("距離の2乗に反比例",param_.start_x+120,param_.end_y-21);
_ctx.fillStyle="#0000FF";
_ctx.fillText("像の明るさ(瞳径2mm)",param_.start_x+120,param_.end_y-49);
_ctx.fillStyle="#008800";
_ctx.fillText("像の明るさ(瞳径5mm)",param_.start_x+120,param_.end_y-87);
_ctx.restore();
}
//=========== グラフ-2
function 光年対数(canvas_name_){
var _param = new hiGraph_Param();
_param.canvas = $E(canvas_name_);
_param.margin_x = 10;
_param.margin_y = 10;
_param.offset_x = 30;
_param.offset_y = 10;
_param.range_x_s= 0;
_param.range_y_s= -11;
_param.range_x_e= 63241*4;
_param.range_y_e= 2;
hiGraph.axis(_param);
hiGraph.xScale(_param,63241,63241,1,1,"光年");
hiGraph.yScale(_param,-10,2,-10,2,"");
hiGraph.calc(_param,逆2乗対数 ,"#ff0000");
hiGraph.calc(_param,レンズ2mm対数,"#0000ff");
hiGraph.calc(_param,レンズ5mm対数,"#008800");
光年対数_説明(_param);
}
光年対数('graphCanvas3');
<script>
Canvasにグラフを描画するhiGraphクラス(後述)を作り、
パラメタにCanvasと領域サイズを設定し、数式を与え、表示しています。
「像の明るさ(5mm)」などの文字列はhiGraphとは別に描画しています。
hiGraphクラスの使い方
hiGraphは次のAPIを持ちます。全てstaticメソッドです。
// 領域をクリアし縦軸、横軸を表示する
hiGraph.axis(param_:hiGraph_Param
,clear_ :boolean // 領域をクリアする
// 省略時 true
,x_color_:string // 横軸色
// 省略時 "black"
,y_color_:string // 縦線色
// 省略時 "black"
);
// X軸スケール(縦線と値)を描く
hiGraph.xScale(param_:hiGraph_Param
,start_ :number // 開始値
,step_ :number // ステップ値
,unit_start_:number // 値文字表示の開始値
// 省略時 start_
,unit_step_ :number // 値文字表示のステップ値
// 省略時 step_
,unit_str_ :string // 値文字表示の単位名
// 省略時 ""
);
// Y軸スケール(横線と値)を描く
hiGraph.yScale(param_:hiGraph_Param
,start_ :number // 開始値
,step_ :number // ステップ値
,unit_start_:number // 値文字表示の開始値
// 省略時 start_
,unit_step_ :number // 値文字表示のステップ値
// 省略時 step_
,unit_str_ :string // 値文字表示の単位名
// 省略時 "
);
// 式の値をグラフに表示する
hiGraph.calc(param:hiGraph_Param
,式_ :any // y=式_(x,arg) の形の式
// 式はxがstart_からend_までstep_単位で
// 変化しながら繰り返し呼ばれる
,color_ :string // 色
// 省略時 black
):hiGraph_Point[];
// 式の値をグラフに表示する
hiGraph.draw(param:hiGraph_Param
,式_ :any // y=式_(x,arg) の形の式
// 式はxがstart_からend_までstep_単位で
// 変化しながら繰り返し呼ばれる
,arg_ :any // 式(x,arg_)で渡す
// 省略時 undefinedが式に渡る
,color_ :string // 色
// 省略時 black
,start_ :number // 開始x値
// 省略時 param_.range_x_s
,end_ :number // 終了x(含む)
// 省略時 param_.rabge_x_e
,step_ :number // ステップ
// 省略時 param_から計算
):hiGraph_Point[];
// X軸スケール(縦線と値)を利用者のヒント関数を用いて表示する
hiGraph.xScaleWithFunc(param_ :hiGraph_Param
,func_ :any // ヒント関数(index,値配列,オプション)
// 戻り値 { x_ :number, // x値
// text_ :string, // 表示する文字列
// line_color:string, // 文字列の色
// text_color:string} // テキストの色
// null:表示しない
// text_ =null : テキストを表示しない
// line_color="#00000000" : 線を表示しない
,values_:Array // 値の並び
,option_:any
);
// y軸スケール(横線と値)を利用者のヒント関数を用いて表示する
hiGraph.yScaleWithFunc(param_ :hiGraph_Param
,func_ :any // ヒント関数(index,値配列,オプション)
// 戻り値 { y_ :number, // x値
// text_ :string, // 表示する文字列
// line_color:string, // 文字列の色
// text_color:string} // テキストの色
// null:表示しない
// text_ =null : テキストを表示しない
// line_color="#00000000" : 線を表示しない
,values_:Array // 値の並び
,option_:any
);
----
hiGraph.drawの戻り値は次の型の配列です。実際に表示した位置情報が入ります。
class hiGraph_Point {
value:number; // 値
x:number; // canvas内横表示位置(pix)
y:number; // canvas内縦表示位置(pix) 上から下
}
第一引数のparamで領域の定義を行います。
class hiGraph_Param {
// 利用者設定情報
canvas :HTMLCanvasElement; // canvas
margin_x :number; // 左右のマージン(pix)
margin_y :number; // 上下のマージン(pix)
offset_x :number; // X軸の位置(pix:左から)
offset_y :number; // Y軸の位置(pix:下から)
cut_x :number; // X終端側カット(pix:省略可)
cut_y :number; // Y終端側カット(pix:省略可)
range_x_s:number; // Xの開始値
range_y_s:number; // Yの開始値
range_x_e:number; // Xの終了値
range_y_e:number; // Yの終了値
font_size:number; // フォントサイズ(pix) 省略可
clone():hiGraph_Param{..} // データ複製
}
offset_xが負の値の場合、右からのオフセットとなり、軸も右に置かれます。
cut_xは正負は無視されます。
offset_yが負の値の場合、上からのオフセットとなり、軸も上に置かれます。
cut_yは正負は無視されます。
数式の代わりに値配列を表示する例
ここでは数式による数値生成ではなく、予め配列に入れられた数値を表示する例を載せます。
draw()メソッドに値配列を指定すれば、
利用者定義の「式」には引数として値配列が渡されます。
2値表示
左にスケールを置くグラフと右にスケールを置くグラフ2つ同位置に重ね合わせ2値グラフを作ってみました。
2重グラフ
このグラフでは、目盛を利用者関数を使って出しています。詳細説明は今後追加します。
コードを載せます。
// biValGraph.ts:二値グラフサンプル
class biVal {
time:number; // 0 - 23 時 (23の後は0)
valV:number; // 50 - 100 V
valA:number; // 0 - 30 A
}
class biValGraph {
//============================================
// 表示
//============================================
static draw(canvasV_:HTMLCanvasElement
,canvasA_:HTMLCanvasElement
,values_ :biVal[]){
let _paramV:hiGraph_Param= new hiGraph_Param();
_paramV.canvas = canvasV_;
_paramV.margin_x = 5;
_paramV.margin_y = 5;
_paramV.offset_x = 40;
_paramV.offset_y = 30;
_paramV.cut_x = 40;
_paramV.cut_y = 0;
_paramV.range_x_s= 0; // xはvaluesのindex
_paramV.range_x_e= values_.length-1;// xはvaluesのindex
_paramV.range_y_s= 60;
_paramV.range_y_e= 110;
let _paramA:hiGraph_Param=_paramV.clone();
_paramA.canvas = canvasA_;
_paramA.offset_x = -_paramA.offset_x;
_paramA.range_y_s= 0;
_paramA.range_y_e= 25;
//----------------------------------------------
// X軸,Y軸を書く
hiGraph.axis(_paramV,true,"BLACK","BLUE");
hiGraph.axis(_paramA,false,"#00000000","RED");
// 時間目盛を書く
hiGraph.xScaleWithFunc(_paramV
,biValGraph.timeScale
,values_);
// 第一値目盛を書く
let _V_scale=[];
for(let _n=60;_n<=110;_n+=5) _V_scale.push(_n);
hiGraph.yScaleWithFunc(_paramV
,biValGraph.V_scale
,_V_scale);
// 第biVal目盛を書く
let _A_scale=[];
for(let _n=0;_n<=25;_n+=5) _A_scale.push(_n);
hiGraph.yScaleWithFunc(_paramA
,biValGraph.A_scale
,_A_scale);
//-----------------------------------------------
// 第一値を書く
hiGraph.draw(_paramA
,biValGraph.V_value
,values_,"#0000FF"
,0,values_.length-1,1);
// 第biValを書く
hiGraph.draw(_paramB
,biValGraph.a_value
,values_,"#FF0000"
,0,values_.length-1,1);
}
//============================================
// 0時,6時,12時,18時を文字付、強調ライン
// 1時間ごとにライン
// 配列のindexが位置指定値
//============================================
static timeScale(idx_,values_,option_){
let _obj = values_[idx_];
let _time:number = _obj["time"];
if( _time==24 ) _time=0;
if( (_time%6)==0 ) return {x:idx_,text:_time+"時",line_color:"#000000aa"};
return {x:idx_}
}
//============================================
// 10V事にラインを入れる
// 90V,115Vに青ラインを入れる
// valが位置指定値
//============================================
static V_scale(idx_,values_,option_){
let _val = values_[idx_];
if( _val==90 || _val==105 ){
return {y:_val,text:_val+"V"
,text_color:"#0000FFFF",line_color:"#0000FF55"};
}
if( (_val%10)==0 ){
return {y:_val,text:_val+"V", text_color:"#0000FFFF"};
}
return null;// 5Vラインは書かない
}
//============================================
// 5A事にラインを入れる
// 20Aに赤ラインを入れる
// valが位置指定値
//============================================
static A_scale(idx_,values_,option_){
let _val = values_[idx_];
if( _val==20 ){
return {y:_val,text:_val+"A"
,text_color:"#FF0000FF",line_color:"#FF000055"};
}
return {y:_val,text:_val+"A",text_color:"#FF0000FF"};
}
//============================================
// V_valueを得る
//============================================
static V_value(idx_,values_,option_){
let _obj = values_[idx_];
return _obj["valV"];
}
//============================================
// a_valueを得る
//============================================
static a_value(idx_,values_,option_){
let _obj = values_[idx_];
return _obj["valA"];
}
}
//=========================================
// 値サンプル 本来は別の場所で設定する
//=========================================
function sampleValue(len_:number):biVal[]{
let _values:biVal[]=[];
let _time_base:number = 24*Math.random()+24*100;
let _V_val:number = 10*Math.random()+90;
let _A_val:number = 15*Math.random();
for(let _idx=0;_idx<len_;++_idx){
let _time = _time_base+(-len_+_idx);
let _d=(Math.random()-0.5)*2;
if( ((_V_val+_d)<=110)
&&((_V_val+_d)>=80) ) _V_val+=_d;
else _V_val-=_d;
_d =(Math.random()-0.5)*4.0;
if( ((_A_val+_d)<=23)
&&((_A_val+_d)>=0) )_A_val+=_d;
else _A_val-=_d;
_values.push(
{time:Math.round(_time%24)
,valV:_V_val
,valA:_A_val}
);
}
return _values;
}
====================
<!-- 二重グラフ:biValGraph.htm -->
<!-- saved from url=(0014)about:internet -->
<meta http-equiv="Content-Type" content="text/html;charset=utf-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
<script type="text/javascript" src="./hiGraph.js" charset="UTF-8"></script>
<script type="text/javascript" src="./biValGraph.js" charset="UTF-8"></script>
<script type="text/javascript">
function $elm(id){return document.getElementById(id);}
function start(){
_value = sampleValue(48);
biValGraph.draw($elm("graphCanvasM1"),$elm("graphCanvasM1"),_value);
}
</script>
<center>
<p>2重グラフ</p>
<div style="width:495;height:200">
<div style="width:495;height:200;position: absolute;z-index:10;">
<canvas width=495 height=200 id="graphCanvasM1"></canvas>
</div>
<div style="width:495;height:200;position: absolute;z-index:11;">
<canvas width=495 height=200 id="graphCanvasM2"></canvas>
</div>
</div>
</center>
<script type="text/javascript">
start();
</script>
hiGraphのTypeScript版
当初、javascriptで作成してありましたが、APIの互換をほぼ保ったまま、TypeScript化しました。
calcを純粋に数式表示のcalcと値配列によるグラフ表示を行うdrawに分離しました。drawに関してはcolor引数と値配列引数の順番を入れ替えました。
この例では省いていますが、typeDoc用の記述も追加されました。
//
// 汎用数値グラフ
//
// 利用者指定パラメータ
class hiGraph_Param {
// 利用者設定情報
canvas :HTMLCanvasElement; // canvas
margin_x :number; // 左右のマージン(pix)
margin_y :number; // 上下のマージン(pix)
offset_x :number; // X軸の位置(左から)
offset_y :number; // Y軸の位置(下から)
cut_x :number; // X終端側カット(省略可)
cut_y :number; // Y終端側カット(省略可)
range_x_s:number; // Xの開始値
range_y_s:number; // Yの開始値(最下の値)
range_x_e:number; // Xの終了値
range_y_e:number; // Yの終了値 (再上の値)
font_size:number; // フォントサイズ(pix) 省略可
// 以下 work 情報 (axisで設定される)
ctx :CanvasRenderingContext2D=null;
width :number; // canvas幅
height :number; // canvas高
g_width :number; // グラフ部だけの幅(pix)
g_height :number; // グラフ部だけの高(pix)
start_x :number; // グラフ部 左
start_y :number; // グラフ部 上
end_x :number; // グラフ部 右
end_y :number; // グラフ部 下
v_range_x:number; // 最右の値-再左の値
v_range_y:number; // 最上の値-再下の値
p_to_v_x :number; // 1 pixcel -> x値
v_to_p_x :number;
p_to_v_y :number;
v_to_p_y :number; // 値->pixcel変換比
//
font :string;
m_size :number;
//-------------------------
clone():hiGraph_Param{
let _copy= new hiGraph_Param();
_copy.margin_x = this.margin_x;
_copy.margin_y = this.margin_y;
_copy.offset_x = this.offset_x;
_copy.offset_y = this.offset_y;
_copy.cut_x = this.cut_x;
_copy.cut_y = this.cut_y;
_copy.range_x_s= this.range_x_s;
_copy.range_y_s= this.range_y_s;
_copy.range_x_e= this.range_x_e;
_copy.range_y_e= this.range_y_e;
_copy.font_size= this.font_size;
return _copy;
}
}
//
// 表示ポイント情報
//
class hiGraph_Point {
value:number;
x:number;
y:number;
}
//
// 数式グラフメソッド
//
class hiGraph {
static readonly D:boolean = true;
static readonly AXIS_COLOR:string = "#000000";
static readonly TEXT_COLOR:string = "#000000FF";
static readonly LINE_COLOR:string = "#88888833";
static readonly LAVU_COLOR:string = "#000000";
// 領域をクリアし縦軸、横軸を表示する
static axis(param_:hiGraph_Param // パラメタ
,clear_? :boolean // 領域をクリアする
// 省略時 true
,x_color_?:string // 横軸色
// 省略時 "black"
,y_color_?:string // 縦線色
// 省略時 "black"
){
if(!param_.ctx) hiGraph.set_subparam(param_);
if( clear_ ==undefined ) clear_ =true;
if( x_color_==undefined ) x_color_=hiGraph.AXIS_COLOR;
if( y_color_==undefined ) y_color_=hiGraph.AXIS_COLOR;
let _ctx:CanvasRenderingContext2D= param_.ctx;
_ctx.save();
hiGraph.clipMergineArea(param_,clear_);
_ctx.font=param_.font;
// 横軸(x軸)
_ctx.beginPath();
_ctx.strokeStyle=x_color_;
if( param_.offset_y>=0 ){
_ctx.moveTo(param_.start_x,param_.end_y);
_ctx.lineTo(param_.end_x, param_.end_y);
}
else{
_ctx.moveTo(param_.start_x,param_.start_y);
_ctx.lineTo(param_.end_x, param_.start_y);
}
_ctx.stroke();
// 縦軸(y軸)
_ctx.beginPath();
_ctx.strokeStyle=y_color_;
if( param_.offset_x>0 ){
_ctx.moveTo(param_.start_x,param_.start_y);
_ctx.lineTo(param_.start_x,param_.end_y);
}
else{
_ctx.moveTo(param_.end_x,param_.start_y);
_ctx.lineTo(param_.end_x,param_.end_y);
}
_ctx.stroke();
_ctx.restore();
}
// 式の値を表示する
static calc(param_ :hiGraph_Param
,式_ :any // y=式_(x) の形の式
,color_?:string // 色
){
hiGraph.draw(param_,式_,undefined,color_);
}
// 引数で与えられる値をグラフ表示する
static draw(param_ :hiGraph_Param
,式_ :any // y=式_(x,arg) の形の式
,arg_? :any // 式(x,arg)で渡す
,color_?:string // 色
,start_?:number // 開始x値
// 省略時 param_.range_x_s
,end_? :number // 終了x(含む)
// 省略時 param_.range_x_e
,step_? :number // ステップ
// 省略時 param_から計算
):hiGraph_Point[]{
if(!param_.ctx) param_.set_work_info();
if( color_==undefined ) color_ = hiGraph.GRPH_COLOR;
if( start_==undefined ) start_ = param_.range_x_s;
if( end_ ==undefined ) end_ = param_.range_x_e;
if( step_ ==undefined ) step_ = param_.p_to_v_x;
let _res:hiGraph_Point[]=[];
let _ctx:CanvasRenderingContext2D= param_.ctx;
_ctx.save();
hiGraph.clipGraphArea(param_,false);
_ctx.beginPath();
_ctx.strokeStyle = color_;
let _top:boolean = true;
for(let _x=start_;_x<=end_;_x+=step_){
let _y:number = 式_(_x,arg_);
if( _y==undefined ){
_top=true;
continue;
}
let _disp_x = hiGraph.X(param_,_x);
let _disp_y = hiGraph.Y(param_,_y);
let _point:hiGraph_Point={value:_y,x:_disp_x,y:_disp_y};
_res.push(_point);
if( _top ){
_ctx.moveTo(_disp_x,_disp_y);
_top=false;
}
else{
_ctx.lineTo(_disp_x,_disp_y);
}
}
_ctx.stroke();
_ctx.restore();
return _res;
}
// X軸スケール(縦線と値)を描く
static xScale(param_:hiGraph_Param
,start_ :number // 開始値
,step_ :number // ステップ値
,unit_start_?:number // 値文字表示の開始値
// 省略時 start_
,unit_step_? :number // 値文字表示のステップ値
// 省略時 step_
,unit_str_? :string // 値文字表示の単位名
// 省略時 ""
){
if(!param_.ctx) hiGraph.set_subparam(param_);
if( unit_start_==undefined ) unit_start_=start_;
if( unit_step_ ==undefined ) unit_step_ =step_
if( unit_str_ ==undefined ) unit_str_ ="";
let _ctx:CanvasRenderingContext2D= param_.ctx;
_ctx.save();
_ctx.beginPath();
_ctx.fillStyle = hiGraph.TEXT_COLOR;
_ctx.fillStyle = "#FF0000"
_ctx.strokeStyle = hiGraph.LINE_COLOR;
_ctx.font = param_.font;
_ctx.textAlign = "center";
let _x :number = start_;
let _unit:number = unit_start_;
while(_x<=param_.v_range_x){
let _disp_x:number= hiGraph.X(param_,_x);
_ctx.moveTo(_disp_x,param_.start_y);
_ctx.lineTo(_disp_x,param_.end_y);
if( param_.offset_y >= 0 ){
_ctx.textBaseline = "top";
_ctx.fillText(_unit+unit_str_
,_disp_x,param_.end_y+param_.m_size/2);
}
else{
_ctx.textBaseline = "bottom";
_ctx.fillText(_unit+unit_str_
,_disp_x,param_.start_y-param_.m_size/2);
}
_x += step_;
_unit += unit_step_;
_ctx.stroke();
}
_ctx.restore();
}
// X軸スケール(縦線と値)を利用者のヒント関数を用いて表示する
static xScaleWithFunc(param_ :hiGraph_Param
,func_ :any // ヒント関数(index,値配列,オプション)
// 戻り値 { x_ :number, // x値
// text_ :string, // 表示する文字列
// line_color:string, // 文字列の色
// text_color:string} // テキストの色
// null:表示しない
// text_ =null : テキストを表示しない
// line_color="#00000000" : 線を表示しない
,values_?:Array<any> // 値の並び
,option_?:any
){
if(!param_.ctx) hiGraph.set_subparam(param_);
let _ctx:CanvasRenderingContext2D= param_.ctx;
_ctx.save();
_ctx.font = param_.font;
_ctx.textAlign = "center";
_ctx.textBaseline = "top";
for(let _idx:number=0;_idx<values_.length;++_idx){
let _hint= func_(_idx,values_,option_);
if( _hint ){
_ctx.beginPath();
let _disp_x:number= hiGraph.X(param_,_hint["x"]);
if( _hint["line_color"] ) _ctx.strokeStyle= _hint["line_color"];
else _ctx.strokeStyle= hiGraph.LINE_COLOR;
if( _hint["text_color"] ) _ctx.fillStyle = _hint["text_color"];
else _ctx.fillStyle = hiGraph.TEXT_COLOR;
_ctx.moveTo(_disp_x,param_.start_y);
_ctx.lineTo(_disp_x,param_.end_y);
if( _hint["text"] ){
if( param_.offset_y >= 0 ){
_ctx.textBaseline = "top";
_ctx.fillText(_hint["text"]
,_disp_x,param_.end_y+param_.m_size/2);
}
else{
_ctx.textBaseline = "bottom";
_ctx.fillText(_hint["text"]
,_disp_x,param_.start_y-param_.m_size/2);
}
}
_ctx.stroke();
}
}
_ctx.restore();
}
// y軸のスケールライン(横棒)を表示する
static yScale(param_:hiGraph_Param
,start_ :number // 開始値
,step_ :number // ステップ値
,unit_start_?:number // 値文字表示の開始値
// 省略時 start_
,unit_step_? :number // 値文字表示のステップ値
// 省略時 step_
,unit_str_? :string // 値文字表示の単位名
// 省略時 """
){
if(!param_.ctx) hiGraph.set_subparam(param_);
if( unit_start_==undefined ) unit_start_=start_;
if( unit_step_ ==undefined ) unit_step_ =step_
if( unit_str_ ==undefined ) unit_str_ ="";
let _ctx:CanvasRenderingContext2D= param_.ctx;
_ctx.save();
_ctx.beginPath();
_ctx.fillStyle = hiGraph.TEXT_COLOR;
_ctx.strokeStyle = hiGraph.LINE_COLOR;
_ctx.font = param_.font;
_ctx.textBaseline = "middle";
let _y :number = start_;
let _unit:number = unit_start_;
if( !unit_str_ ) unit_str_="";
while(_y<=param_.range_y_e){
let _disp_y= hiGraph.Y(param_,_y);
if( _disp_y<param_.margin_y ) break;
_ctx.moveTo(param_.start_x,_disp_y);
//_ctx.lineTo(param_.width-param_.margin_x,_disp_y);
_ctx.lineTo(param_.end_x,_disp_y);
if( param_.offset_x>= 0 ){
_ctx.textAlign = "right";
_ctx.fillText(_unit+unit_str_,param_.start_x-param_.m_size,_disp_y)
}
else{
_ctx.textAlign = "left";
_ctx.fillText(_unit+unit_str_,param_.end_x+param_.m_size,_disp_y)
}
_y += step_;
_unit += unit_step_;
_ctx.stroke();
}
_ctx.restore();
}
// y軸のスケールライン(横棒)を利用者のヒント関数を用いて表示する
static yScaleWithFunc(param_ :hiGraph_Param
,func_ :any // ヒント関数(index,値配列,オプション)
// 戻り値 { y_ :number, // x値
// text_ :string, // 表示する文字列
// line_color:string, // 文字列の色
// text_color:string} // テキストの色
// null:表示しない
// text_ =null : テキストを表示しない
// line_color="#00000000" : 線を表示しない
,values_?:Array<any> // 値の並び
,option_?:any
){
if(!param_.ctx) hiGraph.set_subparam(param_);
let _ctx:CanvasRenderingContext2D= param_.ctx;
_ctx.save();
_ctx.font = param_.font;
_ctx.textAlign = "right";
_ctx.textBaseline = "middle";
for(let _idx:number=0;_idx<values_.length;++_idx){
let _hint= func_(_idx,values_,option_);
if( _hint ){
let _disp_y:number= hiGraph.Y(param_,_hint["y"]);
//if(hiGraph.D)console.log(" dy:"+_disp_y+" sta:"+param_.start_y+" end:"+param_.end_y);
if( _disp_y<(param_.start_y+param_.m_size/2) || (_disp_y>param_.end_y-param_.m_size/2 ) )continue;
_ctx.beginPath();
if( _hint["line_color"] ) _ctx.strokeStyle= _hint["line_color"];
else _ctx.strokeStyle= hiGraph.LINE_COLOR;
if( _hint["text_color"] ) _ctx.fillStyle = _hint["text_color"];
else _ctx.fillStyle = hiGraph.TEXT_COLOR;
_ctx.moveTo(param_.start_x,_disp_y);
_ctx.lineTo(param_.end_x,_disp_y);
if( _hint["text"] ){
if( param_.offset_x>= 0 ){
_ctx.textAlign = "right";
_ctx.fillText(_hint["text"],param_.start_x-param_.m_size,_disp_y)
}
else{
_ctx.textAlign = "left";
_ctx.fillText(_hint["text"],param_.end_x+param_.m_size,_disp_y)
}
}
_ctx.stroke();
}
}
_ctx.restore();
}
//-- 以下privateメソッド
private constructor(){}
private static X(param_:hiGraph_Param,x_){
return param_.start_x // グラフ最左
+ param_.v_to_p_x // 実値・pixel比率
*(x_-param_.range_x_s);// 最下値との実値差分
}
private static Y(param_:hiGraph_Param,y_){
return param_.end_y // グラフ最下
- param_.v_to_p_y // 実値・pixel比率
*(y_-param_.range_y_s); // 最下値との実値差分
}
private static set_subparam(param_:hiGraph_Param){
param_.ctx = param_.canvas.getContext('2d');
param_.width = param_.canvas.width-param_.margin_x*2;
param_.height = param_.canvas.height-param_.margin_y*2;
if( param_.cut_x==undefined ) param_.cut_x=0;
if( param_.cut_y==undefined ) param_.cut_y=0;
if( param_.cut_x<0 ) param_.cut_x=-param_.cut_x;
if( param_.cut_y<0 ) param_.cut_x=-param_.cut_y;
if( param_.offset_x>=0 ){
param_.g_width = param_.width-param_.offset_x-param_.cut_x;
param_.start_x = param_.margin_x+param_.offset_x;
param_.end_x = param_.start_x+param_.g_width; // 右マージンを削除した位置
}
else{
// offset_xは負
param_.g_width = param_.width+param_.offset_x-param_.cut_x;
param_.start_x = param_.margin_x+param_.cut_x;
param_.end_x = param_.start_x+param_.g_width;
}
if( param_.offset_y>=0 ){
param_.g_height = param_.height-param_.offset_y;
param_.start_y = param_.margin_y;
param_.end_y = param_.start_y+param_.g_height;
//param_.end_y = param_.height-param_.margin_y*2-param_.offset_y;
}
else{
// offset_yは負: 座標は下が正
param_.g_height = param_.height+param_.offset_y;
param_.start_y = param_.margin_y-param_.offset_y;
param_.end_y = param_.start_y+param_.g_height;
}
param_.v_range_x = param_.range_x_e-param_.range_x_s;
param_.v_range_y = param_.range_y_e-param_.range_y_s;
param_.v_range_x = param_.range_x_e-param_.range_x_s;
param_.v_range_y = param_.range_y_e-param_.range_y_s;
param_.p_to_v_x = param_.v_range_x/param_.g_width;
param_.v_to_p_x = param_.g_width/param_.v_range_x;
param_.p_to_v_y = param_.v_range_y/param_.g_height;
param_.v_to_p_y = param_.g_height/param_.v_range_y;
//
param_.m_size = ((param_.font_size==undefined)?11.5:param_.font_size);
param_.font = param_.m_size+"px sans-serif";
param_.ctx.font = param_.font;
}
static clearCanvas(param_:hiGraph_Param,clear_:boolean){
let _ctx:CanvasRenderingContext2D= param_.ctx;
_ctx.beginPath();
_ctx.rect(0,0,param_.width,param_.height);
_ctx.clip();
if(clear_)_ctx.clearRect(param_.margin_x,param_.margin_y,param_.width,param_.height);
}
private static clipMergineArea(param_:hiGraph_Param,clear_:boolean){
let _ctx:CanvasRenderingContext2D= param_.ctx;
_ctx.beginPath();
_ctx.rect(param_.margin_x,param_.margin_y,param_.width,param_.height);
_ctx.clip();
if(clear_)_ctx.clearRect(param_.margin_x,param_.margin_y,param_.width,param_.height);
}
private static clipGraphArea(param_:hiGraph_Param,clear_:boolean){
let _ctx:CanvasRenderingContext2D= param_.ctx;
_ctx.beginPath();
_ctx.rect(param_.start_x,param_.start_y,param_.g_width,param_.g_height);
_ctx.clip();
if(clear_)_ctx.clearRect(param_.start_x,param_.start_y,param_.g_width,param_.g_height);
}
}
ダウンロード
TypeScriptコードとビルド用バッチおよびビルド結果のjavascriptが次の場所からダウンロード出来ます。
二値グラフサンプルも入っています。
higraphsrc.zip
次のものから構成されます。
・A00_clean.bat : 二次ファイルを削除する
・A01_hi_build.bat : hiGraph.jsをビルドする
・hiGraph.ts : ソース
・hiGraph.js : 生成されたjavascript
・hiGraph.d.ts : 他のTypeScriptから呼び出すための定義
・A02_bi_build.bat : biValGraph.js(二値グラフサンプル)をビルドする
・biValGraph.ts : 二値グラフサンプル
・biValGraph.js : 生成されたjavascript
・biValGraph.htm : 二値グラフ表示html