回転の実装

前回の続きです。回転を実装するにあたり、kaiten関数でcanvas をclearRect してテキストボックスに入力した数値を配列にメモ、var draw = function(x)を呼び出して再描画しています。

https://stuffy.mydns.jp/~gusachan/javascript/rotate.html

<body>
<th>rotate 関数</th><br>
<canvas id="graph" width="400" height="400"> </canvas><br>
<form>回転角度: <input type="text" id='degree'> <button type='button' onclick="kaiten();">回転</button></form>
<script type="text/javascript">
var i = 0, dgr = [0];
var c=document.getElementById("graph");
var ctx=c.getContext("2d"); 

function rads(x) {
  return Math.PI*x/180;
}
function coordinate() {
  ctx.beginPath();
  ctx.moveTo(0,200);
  ctx.lineTo(400,200);
  ctx.moveTo(200,0);
  ctx.lineTo(200,400);
  ctx.closePath();
  ctx.stroke();
  ctx.beginPath();
  ctx.arc(200,200,150,0,rads(360),false);
  ctx.stroke();
}
var draw = function(x) {
  ctx.beginPath();
  ctx.moveTo(200,200);
  ctx.lineTo(200 + 150*Math.cos(rads(x)), 200 - 150*Math.sin(rads(x)));
  ctx.closePath();
  ctx.stroke();
};
var sum = function(arr) {
  var sum = 0;
  arr.forEach(function(elm) {
    sum += elm;
  });
  return sum;
};
function kaiten() {
  var e = document.getElementById('degree');
  var arg = Number(e.value);
  i += 1;
  dgr[i] = arg;
  ctx.clearRect(0,0,400,400);
  coordinate();
  draw(sum(dgr));
}
coordinate();
</script>
</body>

追記)

var c=document.getElementById("graph");
var ctx=c.getContext("2d");

上記のコンストラクタ変数オブジェクト宣言は、coordinate, draw 関数のローカル内で宣言していましたが、グローバルオブジェクト(正確にはwindowオブジェクトのプロパティ)として宣言しても問題なかったようです。

canvas への描画

時間切れで回転を実装できなかったヘタレです。コードは以下。

<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="ja" lang="ja">
<head>
  <meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
  <meta http-equiv="Content-Style-Type" content="text/css" />
  <meta http-equiv="Content-Script-Type" content="text/javascript" />
<style type="text/css">
  canvas {border: 1px solid #999; }
</style>
</head><style type="text/css">
  canvas {border: 1px solid #999; }
</style>
</head>
<body>
<th>rotate 関数</th><br>
<canvas id="graph" width="400" height="400"> </canvas><br>
<form>回転角度: <input type="text" id='degree'> <button type='button' onclick="draw();">回転</button></form>
<script type="text/javascript">
function rads(x) {
  return Math.PI*x/180;
}
function draw(){
  var e = document.getElementById('degree');
  var c=document.getElementById("graph");
  var ctx=c.getContext("2d");
  ctx.beginPath();
  ctx.moveTo(200,200);
  ctx.lineTo(200 + 150*Math.cos(rads(e.value)), 200 - 150*Math.sin(rads(e.value)));
  ctx.closePath();
  ctx.stroke();
}
var c=document.getElementById("graph");
var ctx=c.getContext("2d");
  ctx.beginPath();
  ctx.moveTo(0,200);
  ctx.lineTo(400,200);
  ctx.moveTo(200,0);
  ctx.lineTo(200,400);
  ctx.closePath();
  ctx.stroke();
  ctx.beginPath();
  ctx.arc(200,200,150,0,rads(360),false);
  ctx.stroke();
</script>
</body>
</html>

rotate

SCRIPTタグをBODYタグの中に入れるのがポイントです。

javascriptのクロージャ

メモ化された fibonacci.js

var fibonacci = function () {
    var memo = [0, 1];
    var fib = function (n) {
      var result = memo[n];
      if (typeof result !== 'number') {
        result = fib(n -1) + fib(n -2);
        memo[n] = result;
      };
      return result;
    };
    return fib;
}();
for (var i = 0; i <=100; i +=1) {
    document.writeln('// ' + i + ': ' + fibonacci(i) +'<br>');
}

入れ子状になった関数の戻り値を、配列やオブジェクトに記録(メモ化)すると、再帰的な関数の呼び出し回数を大幅に減らすことができます。メモ化についてはクロージャを使ってメモ化 – maru source  で、フィボナッチ数列を例に詳しく解説されていますので割愛して、今回は関数のクロージャについていまいち良く分からなかったので調べてみました。

8.6 クロージャ

最近の多くのプログラム言語と同じように、JavaScript では構文スコープを使います。つまり、関数を実行するときには、関数が定義されたときに有効であった変数スコープを使います。関数が呼び出されたときに有効な変数スコープではありません。(中略) 関数オブジェクトと、関数の変数の名前解決に使われるスコープを組み合わせたものを、コンピュータサイエンスの分野ではクロージャと呼んでいます。
正確に言えば、JavaScript の関数はすべてクロージャです。

ここまでは何を言っているのか良く解りませんね。実際にコードを見てみましょう。
クロージャを理解するためには、まず入れ子型関数の構文スコープについて考えてみましょう。

var scope = "global scope";        // グローバル変数。
function checkscope() {
    var scope = "local scope";        // ローカル変数。
    function f() { return scope; }  // ここでのスコープ中の値が戻される。
    return f();
}
checkscope()                        // => "local scope"

checkscope()関数は、ローカル変数を宣言し、その後、この変数の値を返す関数を定義し呼び出されます。checkscope() を呼び出したときに、”local scope” が戻されることに疑問を抱かないと思います。ここで、このコードを少し変更してみましょう。次のコードでは何が返されるかわかりますか。

var scope = "global scope";        // グローバル変数。
function checkscope() {
    var scope = "local scope";        // ローカル変数。
    function f() { return scope; }  // ここでのスコープ中の値が戻される。
    return f;
}
checkscope()()                        // 何が返されるか?

今回のコードでは括弧がcheckscope()から外に移動しただけです。入れ子型の関数を呼び出して戻りを返すのではなく、入れ子型の関数オブジェクト自身を返しています。括弧をコードの最後の行に動かすことで、入れ子型の関数を定義した場所の外側で呼び出した場合、どうなるでしょう。構文スコープの基本となる規則を思い出してください。JavaScript の関数は、定義されたときに有効なスコープチェーンを使って、実行される、という規則です。入れ子型の関数 f() は、変数 scope の値が “local scope” にバインド(束縛)されているスコープチェーンの下で定義されました。この変数バインドは、 f を実行するときも有効です。どこで呼び出されたとしても、これは変わりません。したがって、先のコードの最後の行が返すのは  “local scope” です。”global scope” ではありません。

先の fibonacci.js の例では入れ子になったローカル 関数、 fib = function (n) がfibonacci(i)で呼び出されて、ローカル変数が返されたというわけです。();

JSONのコールバック関数

配列とオブジェクトの入れ子になったJSON形式を、var json={…}; として試みに以下のコールバック関数を用いて再帰的に読み込ませると、10MB程度のデータ(例えばMTG JSON)でタイムアウト、スタックオーバーフローを起こす件。

【JavaScript】ネストされたJSONのすべての要素にアクセスする

var walkJSON = function walkJSON(data, callback){
     for (var key in data) {
         callback(key, data[key]);
         if (typeof data[key] === "object") {
             walkJSON(data[key], callback);
         }
     }
 }
   walkJSON(json, function(key, value) {
     document.writeln(key + ":" + value);
     document.writeln("<br>");
  });

これはjavascript がブラウザのプログラムである意味、仕様なのかもしれませんが本来は、XMLHttpRequest するべきなのでしょうね、とほほ。

javascriptの2次元配列の生成

JavaScriptではネイティブオブジェクトに対してメソッドを追加して、2次元配列を定義することができます。(ここではArrayオブジェクトのプロトタイプに対して。)

『JavaScript では2次元以上の配列は用意されていない。しかし、C言語とほぼ同じ方法で、配列の配列を作ることができる。』(JavaScript: The Good Parts 良いパーツによるベストプラクティス p.73)

Array.matrix = function (m, n, initial) {
    var a, i, j, mat = [];
      for (i=0; i < m; i += 1) {
        a = [];
        for (j = 0; j < n; j += 1) {
          a[j] = initial;
        }
        mat[i] = a;
      }
      return mat;
}
// ゼロで埋められた 4 X 4 の行列を生成する

var myMatrix = Array.matrix(4, 4, 0);

// 単位行列を生成するメソッド

Array.identity = function (n) {
    var i, mat = Array.matrix(n, n, 0);
    for (i=0; i < n; i += 1) {
      mat[i][i] = 1;
    }
    return mat;
};
myMatrix = Array.identity(4);

配列の出力メソッドがありませんでしたがせっかくなので、自作してみました。

// 生成された行列を書き出すメソッド
Array.output = function (n) {
  var i,j, mat = Array.identity(n);
    for (i=0; i < n; i += 1) {
      for (j=0; j < n; j += 1) {
        document.writeln(myMatrix[i][j]);
      }
      document.writeln("<br>");
    }
    return mat;
};
printMatrix = Array.output(4);

以上のコードは、概ね期待した結果が得られました。

Kasperskyのトラフィックスキャン

Kaspersky インターネットセキュリティではトラフィックのスキャンのため、ブラウザにあらかじめJavaScriptが埋め込まれる設定があります。

無効にするには、[設定]-[詳細]-[ネットワーク]から[Webページと連携するためWeb トラフィック内にスクリプトを埋め込む]チェックを外しておきます。

2016-11-03

javascript で遊んでみた

2016-11-02

[tab_panel.html]


<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Trasitional//EN" "http://www.w3c.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="ja" lang="ja">
<head>
  <meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
  <meta http-equiv="Content-Style-Type" content="text/css" />
  <meta http-equiv="Content-Script-Type" content="text/javascript" />
  <script type="text/javascript" src="jquery-3.1.1.min.js"></script>
  <script type="text/javascript" src="tab_panel.js"></script>
  <link rel="stylesheet" href="tab_panel.css" type="text/css" />
 <title>タブパネル</title>
</head>
<body>
  <div id="container">
    <ul class="tab">
      <li>prototype.js</li>
      <li>script.aculo.us</li>
      <li>jQuery</li>
      <li>YUI</li>
    </ul>
    <ul class="panel">
      <li>代表的なJavaScript ライブラリの中でも歴史が古く、最も普及しているJavaScript ライブラリです。</li>
      <li>prototype.js と同時に利用するアニメーションなどのEffect処理に特化した JavaScript ライブラリです。</li>
      <li>jQuery は、非常に軽量なJavaScript ライブラリです。</li>
      <li>YUI は、非常に多彩な機能を持つ JavaScript ライブラリです。</li>
    </ul>
  </div>
</body>
</html>

[tab_panel.css]

* {
  margin: 0;
  padding: 0;
  list-style-type: none;
}
 div#container {
  margin: 10px auto;
  width: 500px;
}
 ul.tab li {
  float: left;
  padding: 4px 10px;
  cursor: pointer;
  background: #ddd;
  border: 1px solid #999;
  margin-right: 1px;
  position: relative;
  top: 1px;
}
  ul.tab li.selected {
  border-bottom: 1px solid #eee;
  background: #eee;
}
ul.panel li {
  clear: both;
  background: #eee;
  border: 1px solid #999;
  padding: 10px;
}

[tab_panel.js]


$(function() {
  $(".tab li:first-child").addClass("selected");
  $(".panel li:not(:first)").css("display","none");
  $(".tab li").click(function() {
    $(".tab li").removeClass("selected");
    $(this).addClass("selected");
    $(".panel li").css("display","none");
    $(".panel li:eq("+$(".tab li").index(this)+")").css("display","block");
  });
});

Amazon でポチった

本が自宅に届きましたよ。開眼! JavaScriptは読んでいて面白い。

定番のO’REILLY(オライリー)品質。他にJavaScript : The Good Parts 、JavaScriptパターンも見てみたい、見てみたくない?

JavaScript 第6版
David Flanagan
¥ 4,536javascript_

 

JavaScriptリファレンス 第6版 
David Flanagan
¥ 3,024

51hqwyi1aul__sx352_bo1204203200_

開眼! JavaScript ―言語仕様から学ぶJavaScriptの本質 
Cody Lindley
¥ 2,376

javascript

JSONを扱うならPHPの方が良いかもね。

JSON(JavaScript Object Notation) は、ブラウザとサーバー間でデータをやり取りするために使われる一般的なデータフォーマットである。JSONは本質的に軽く、使いやすく、JavaScript で解析しやすい。(jQuery クックブック p.415)

PHP のオブジェクトとJSONのオブジェクトとの間での直接の変換は出来ません。(中略) しかし、JsonSerializableインターフェイスを使えば、オブジェクトをお好みの形式のJSONデータに変換できます。(プログラミングPHP第3版 p.350)

だそうです。

プログラミングPHP 第3版
Kevin Tatroe
¥ 4,104

php