2016年5月20日金曜日

【HTML5/Javascript】Canvasを使った損益グラフを作成してみよう

HTML5のCanvasの使い方を【参考URL】にある「損益グラフ」を使って学習してみました。


1. HTML
 index.htmlというファイルを作成して、以下のコードを記載します。

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="utf-8" />
    <title>損益グラフ</title>
    <link rel="stylesheet" href="app.css" type="text/css" />
    <style>
        body {
            margin: 0px;
            padding: 0px;
        }
    </style>
</head>
<body>
    <h1>損益グラフ</h1>
    <canvas id="canvasProfitLoss" width="1200" height="600" style="border:1px solid #000000;"></canvas>
    <script type="text/javascript" src="test.js" charset="Shift-JIS"></script>
</body>
</html>


JavaScriptを外部ファイル(test.js)で記載して、読み込みます。
日本語を使うため、charset="Shift-JIS"を記載してください。


2. Javascript
(1)canvasにグラフ作成する関数を外部ファイル(test.js)に記載する
(ProfitLossChartという関数で、クラスの代わりとなります)
この関数を使って、返り値のインスタンス定義する(this.???がインスタンスが持つパラメータになります)

function ProfitLossChart(minPrice, minProfitLoss, maxPrice, maxProfitLoss, unitsPrice, unitsProfitLoss) {
            this.canvas = document.getElementById("canvasProfitLoss");
            this.minPrice = minPrice;
            this.minProfitLoss = minProfitLoss;
            this.maxPrice = maxPrice;
            this.maxProfitLoss = maxProfitLoss;
            this.unitsPrice = unitsPrice;
            this.unitsProfitLoss = unitsProfitLoss;
            this.tickSize = 20;
            this.context = this.canvas.getContext('2d');
            this.rangePrice = this.maxPrice - this.minPrice;
            this.rangeProfitLoss = this.maxProfitLoss - this.minProfitLoss;
            this.unitPrice = this.canvas.width / this.rangePrice;
            this.unitProfitLoss = this.canvas.height / (this.rangeProfitLoss);
            this.centerProfitLoss = Math.round(Math.abs(this.minProfitLoss / this.rangeProfitLoss) * this.canvas.height) ;
            this.centerPrice =  + Math.round(Math.abs(this.minPrice / this.rangePrice) * this.canvas.width);
            this.iteration = (this.maxPrice - this.minPrice) / 1000;
            this.scalePrice = this.canvas.width / this.rangePrice;
            this.scaleProfitLoss = this.canvas.height / this.rangeProfitLoss;
        };


※javascriptのインスタンスについては、次のURL一読するとよいと思います。
http://qiita.com/nmta/items/696eeab1d6b96e3bfc1a

コンテキスト(this.context)は、canvas に描画するための API にアクセスできるオブジェクトとなっています。

(2)X軸作成
刻みとラベルを表示した軸を作成する関数を定義します。
(クラス(ProfitLossChart)に関数を定義する)

    ProfitLossChart.prototype.drawPriceAxis= function () {
        var context = this.context;
        context.save();
        context.beginPath();   //
現在のパスをリセットします
        //左から10 pix オフセット, y 方向は中心(開始点設定)
        context.moveTo(10, this.centerProfitLoss);
        //水平線を作成
        context.lineTo(this.canvas.width, this.centerProfitLoss);
        context.strokeStyle = this.axisColor;
        context.lineWidth = 2;
        context.stroke();

        // 右側に刻みを書く
        var pricePosIncrement = this.unitsPrice * this.unitPrice;
        var pricePos, unit;
        context.font = this.font;
        context.textAlign = 'center';
        context.textBaseline = 'top';

        pricePos =  pricePosIncrement;
        unit = this.unitsPrice ;
        while (pricePos < this.canvas.width) {
            //刻み描画
            context.moveTo(pricePos , this.centerProfitLoss - this.tickSize / 2);
            context.lineTo(pricePos , this.centerProfitLoss + this.tickSize / 2);
            context.stroke();
            //刻みにラベル描画
            context.fillText(unit + this.minPrice, pricePos, this.centerProfitLoss + this.tickSize / 2 - 30);
            unit += this.unitsPrice;
            pricePos = Math.round(pricePos + pricePosIncrement);
        }

        //X軸中心にラベルを表示
        context.font = "12px 'ヒラギノ角ゴシックProN W3'";
        context.fillStyle = "green";
        context.fillText("価格(円)", this.canvas.width / 2, this.centerProfitLoss + this.tickSize / 2 -50);
        context.restore();
    };


(3) Y軸(利益/損失)作成
ProfitLossChart.prototype.drawProfitLossAxis = function () {
      var context = this.context;
      context.save();
      context.beginPath();
      //縦軸描画
      context.moveTo( 20, 0)
      context.lineTo( 20, this.canvas.height);
      context.strokeStyle = this.axisColor;
      context.lineWidth = 2;
      context.stroke();
      // 刻み描画
      var profitLossPosIncrement = this.unitsProfitLoss * this.unitProfitLoss;
      var profitLossPos, unit;
      context.font = this.font;
      context.textAlign = 'right';
      context.textBaseline = 'middle';
      profitLossPos = this.centerProfitLoss - profitLossPosIncrement;
      unit = this.unitsProfitLoss;
      while (profitLossPos > 0) {
          context.moveTo(20 - this.tickSize / 2, profitLossPos);
          context.lineTo(20 + this.tickSize / 2, profitLossPos);
          context.stroke();
          context.fillText(unit, 70 - this.tickSize / 2 - 3 , profitLossPos);
          unit += this.unitsProfitLoss;
          profitLossPos = Math.round(profitLossPos - profitLossPosIncrement);
      }
      profitLossPos = this.centerProfitLoss + profitLossPosIncrement;
      unit = -1 * this.unitsProfitLoss;
      while (profitLossPos < this.canvas.height) {
          context.moveTo(20- this.tickSize / 2, profitLossPos);
          context.lineTo(20 + this.tickSize / 2, profitLossPos);
          context.stroke();
          context.fillText(unit, 70 - this.tickSize / 2 - 3, profitLossPos);
          unit -= this.unitsProfitLoss;
          profitLossPos = Math.round(profitLossPos + profitLossPosIncrement);
      }
        // Y軸ラベルを作成
      context.font = "12px 'ヒラギノ角ゴシックProN W3'";
      context.fillStyle = "green";
      context.fillText("利益/損失(円)", this.centerPrice + 140, this.canvas.height / 4);
      context.restore();
  };


(4) 損益ライン作成
ProfitLossChart.prototype.drawEquation = function (drawFunction) {
      var context = this.context;
      context.save();
      this.transformContext();

      context.beginPath();
      context.moveTo(this.minPrice, drawFunction(this.minPrice));

      for (var x = this.minPrice + this.iteration; x <= this.maxPrice; x += this.iteration) {
          context.lineTo(x, drawFunction(x));
      }
      context.restore();
      context.lineJoin = 'round';
      context.lineWidth = 3;
      context.strokeStyle = 'red';
      context.stroke();
      context.restore();
  };


(5) コンテキストの変換
    ProfitLossChart.prototype.transformContext = function () {
      var context = this.context;
      this.context.translate(this.centerPrice, this.centerProfitLoss);
      context.scale(this.scalePrice , -this.scaleProfitLoss);
  };


(6) 実行
パラメータを定義し、インスタンス作成し、描画実行する
インスタンスは、ファンクション(ProfitLossChart)をnewすることで作成することができます。 
 
    var minPrice = 0;
    var maxPrice = 2200;
    var minPL = -10000;
    var maxPL = 10000;
    var unitsPrice = 50;
    var unitsProfitLoss = 500;

    // インスタンス(chart)作成
    var chart = new ProfitLossChart(minPrice, minPL, maxPrice, maxPL, unitsPrice, unitsProfitLoss);
  chart.drawPriceAxis();
  chart.drawProfitLossAxis();

  //損益グラフ作成
   var pStrike = 2110;
   var pCall = 5.5;
   chart.drawEquation(function (x) {
        if (x > pStrike)
        {
            return 100 * (x - pStrike - pCall);
        }
        else
        {
            return -(100 * pCall);
        }
   });



【参考URL】
http://www.codeproject.com/Articles/1100873/Charting-Profit-Loss-of-Financial-Options-Using-HT

0 件のコメント:

コメントを投稿