http://nodejs.jp/
http://nodejs.org/
Node.jsっていまいち意味がわからないんですよね。
ESとかv8ってなんだよ。
http://nodejs.jp/nodejs.org_ja/
> Node.jsは高速でスケーラブルなネットワークアプリケーションを 簡単に構築するためにChrome の JavaScript 実行環境 上に構築されたプラットフォームです。
http://ja.wikipedia.org/wiki/Node.js
> Node.js はイベント化された入出力を扱うUnix系プラットフォーム上のサーバーサイドJavaScript環境である
日本語でおk
とりあえずVagrantを起動。
nodebrewをインストール
https://github.com/hokaccha/nodebrew
nodebrewはNode.js専用のバージョン管理ツールらしい。
ヘルプに従ってインストール。
> Bareword found where operator expected at - line 6, near "<p>Your" (Missing operator before Your?)
> syntax error at - line 2, near "html>"
> Execution of - aborted due to compilation errors.
あれ?
何故かワンライナーが使えないので手動でゲット。
> Add path: export PATH=$HOME/.nodebrew/current/bin:$PATH
インストールされたバージョンは0.7.4だった。
nodebrewパスの追加
インストールの最後にexportしろやと言われたので実行。
Node.jsをインストール
全てnodebrewにお任せ。
実行時点での最新安定版はv0.10.29。
動作確認。
ここまで管理者権限を一切使ってないのが不思議。
JavaScriptファイルを作成
適当な場所にexample.jsを作成。
特にDocumentRoot以下とかでなくてもいい。
というかNode.jsはApacheやnginxと同等のWebサーバ的なものだったようだ。
ここまで進めてきて初めて知る真実。
中身は基礎から学ぶNode.jsのパクリ流用。
起動。
簡単。
何故1337かは不明。
VirtualBox内のゲストOSのブラウザから192.168.33.10:1337にアクセス。
> Hello World
正常に動作した。
ホストOSのWindowsから192.168.33.10:1337にアクセス。
> このウェブページにアクセスできません
あれ?
iptables編集
> Hello World
行けた。
iptablesで1337番ポートが塞がれていたせいだった。
単にオフにするとセキュリティ的に困るので、必要なポートだけ空ける。
REJECTの直前にACCEPT行が挿入され、ポート1337が使えるようになった。
これでサーバサイドJavaScriptが書けるようになった。
が、特段JavaScriptが得意ってわけでもないし特にやりたいこともなかったので何をやったらいいのかわからない。
http://nodejs.org/
Node.jsっていまいち意味がわからないんですよね。
ESとかv8ってなんだよ。
http://nodejs.jp/nodejs.org_ja/
> Node.jsは高速でスケーラブルなネットワークアプリケーションを 簡単に構築するためにChrome の JavaScript 実行環境 上に構築されたプラットフォームです。
http://ja.wikipedia.org/wiki/Node.js
> Node.js はイベント化された入出力を扱うUnix系プラットフォーム上のサーバーサイドJavaScript環境である
日本語でおk
とりあえずVagrantを起動。
nodebrewをインストール
https://github.com/hokaccha/nodebrew
nodebrewはNode.js専用のバージョン管理ツールらしい。
ヘルプに従ってインストール。
$ cd . $ curl -L git.io/nodebrew | perl - setup> Bareword found where operator expected at - line 3, near "400 Bad" (Missing operator before Bad?)
> Bareword found where operator expected at - line 6, near "<p>Your" (Missing operator before Your?)
> syntax error at - line 2, near "html>"
> Execution of - aborted due to compilation errors.
あれ?
何故かワンライナーが使えないので手動でゲット。
$ wget git.io/nodebrew $ perl nodebrew setup> install nodebrew in $HOME/.nodebrew
> Add path: export PATH=$HOME/.nodebrew/current/bin:$PATH
インストールされたバージョンは0.7.4だった。
nodebrewパスの追加
インストールの最後にexportしろやと言われたので実行。
$ export PATH=$HOME/.nodebrew/current/bin:$PATHついでに.bashrcにも入れとく。
$ vi .bashrc`export PATH=$HOME/.nodebrew/current/bin:$PATH`を追加。
$ source ~/.bashrc $ nodebrew helpコマンドが見つかりませんと言われなくなったら成功。
Node.jsをインストール
全てnodebrewにお任せ。
# nodebrew自身を更新 $ nodebrew selfupdate # 全バージョンを確認 $ nodebrew ls-remote # 最新安定版をインストールする。コンパイルが遅い。 $ nodebrew install stable # 最新安定版のコンパイル済のを入れてくれるらしい。早い。 $ nodebrew install-binary stable # 使用するバージョンを選択 $ nodebrew use v0.10.29 # インストールされているバージョンを確認。currentが現在有効なバージョン。 $ nodebrew lsinstall-binary stableした。
実行時点での最新安定版はv0.10.29。
動作確認。
$ node -v > v0.10.29インストールできた。
ここまで管理者権限を一切使ってないのが不思議。
JavaScriptファイルを作成
適当な場所にexample.jsを作成。
特にDocumentRoot以下とかでなくてもいい。
というかNode.jsはApacheやnginxと同等のWebサーバ的なものだったようだ。
ここまで進めてきて初めて知る真実。
中身は基礎から学ぶNode.jsのパクリ流用。
var http = require('http'); http.createServer(function (req, res) { res.writeHead(200, {'Content-Type': 'text/plain'}); res.end('Hello World\n'); }).listen(1337, "192.168.33.10"); console.log('Server running');極普通のJavaScriptである。
起動。
$ node path/to/example.js > Server runningNode.jsが起動して192.168.33.10:1337を待ち受けるようになった。
簡単。
何故1337かは不明。
VirtualBox内のゲストOSのブラウザから192.168.33.10:1337にアクセス。
> Hello World
正常に動作した。
ホストOSのWindowsから192.168.33.10:1337にアクセス。
> このウェブページにアクセスできません
あれ?
iptables編集
# service iptables stopWindowsから192.168.33.10:1337にアクセス。
> Hello World
行けた。
iptablesで1337番ポートが塞がれていたせいだった。
単にオフにするとセキュリティ的に困るので、必要なポートだけ空ける。
# iptables -I INPUT 7 -p tcp --dport 1337 -j ACCEPT # service iptables save # service iptables restart"7"は環境によって違う可能性があり、REJECTと書いてある行を指定する。
REJECTの直前にACCEPT行が挿入され、ポート1337が使えるようになった。
これでサーバサイドJavaScriptが書けるようになった。
が、特段JavaScriptが得意ってわけでもないし特にやりたいこともなかったので何をやったらいいのかわからない。
PR
前回はソースを見ても全く理解できなかったので、とりあえず簡単なところからはじめてみようと思います。
動きのあるものは手に負えないので、完全に静的な図形を描画してみます。
http://nurseangel.sakura.ne.jp/js/jthree/01.html
単に図形を適当に並べているだけという手抜き極まりない代物ですが、非常に少ないコーディング量で図形を描画できました。
01.html
キャンバスを用意してJavaScriptを呼んでいるだけです。
01.js
jThree.goml()を呼び出すだけでお仕事終了です。
jThree.goml()の第二引数でコールバックを受け取ることが可能ですが、どう使っていいかわからなかったので今回は受け取っていません。
drawSampleTxr2()は以下のgomlから呼び出される関数です。
中身はこちらを参考というかコピペ。
01.goml
図形等は以下を参考にしています。
ここらへんっていったいどうやって調べてるんだ?ソース読んでるの?
基本的に<head>内に図形やテクスチャ等の要素を記述し、<body>でそれぞれを配置していくという構造になっているようです。
まず<rdr frame>で描写先を指定。
<gmt>で各図形を記述。
予め定義されている図形であれば、パラメータを適当に設定するだけで非常に簡単に作図できます。
<mtr>は材質を指定します。
種類はTHREE.**Materialで規定されているようで色々種類があるみたいなのですが、どうも指定するとエラーになったりparam要素が効かなかったりでどれを指定していいのかよくわかりません。
<txr>はテクスチャです。
今回のサンプルではdrawSampleTxr2()を呼び出してテクスチャを設定していますが、かわりにsrcで直接画像を貼ったりもできます。
<body>内で各要素を実際に表示します。
<camera>でカメラの位置を指定。
遠く離せば、それだけ見える図形が小さくなります。
<light>で光源を設定。
材質に光源が当たると反射して図形が見えるようになります。
光源が存在しなければ図形は真っ暗です。
ちなみに、光源色と、<mtr>で設定されている材質色は論理積になっています。
どういうことかって、光源が青で材質色が赤だった場合、図形の色は紫ではなく真っ暗になります。なんでだ。
<mesh>で図形を表示。
gmt要素で対象のIDを指定、style要素で描画位置や回転等の見た目を設定。
styleは概ねCSSっぽい書き方ができるようです。
基本的にオブジェクトの設置はmeshで行います。
どうにかこうにか、かろうじてjThreeで図形を描写することに成功しました。
なんかこのままやっていってもミクさんを動かせるようになる気がしないんだが大丈夫か。
動きのあるものは手に負えないので、完全に静的な図形を描画してみます。
http://nurseangel.sakura.ne.jp/js/jthree/01.html
単に図形を適当に並べているだけという手抜き極まりない代物ですが、非常に少ないコーディング量で図形を描画できました。
01.html
<!DOCTYPE html> <html lang="ja"> <head> <meta charset="UTF-8"> <title>jThree - demo</title> <style> #jtreeSample { position: fixed; width: 100%; height: 100%; top: 0%; left: 0%; margin: 0; padding: 0; } </style> </head> <body> <div id="jtreeSample"> <script src="//ajax.googleapis.com/ajax/libs/jquery/2.0.0/jquery.min.js"></script> <script src="script/jThree.js"></script> <script src="01.js"></script> </div> </body> </html>
キャンバスを用意してJavaScriptを呼んでいるだけです。
01.js
/* * * sampleTxr2のテクスチャを作るらしい * @param CanvasRenderingContext2D */ function drawSampleTxr2( ctx ) { var base = "#fff", color = "#2ff"; ctx.fillStyle = base; ctx.fillRect(0, 0, 32, 32); ctx.fillStyle = color; ctx.fillRect(0, 0, 16, 16); ctx.fillStyle = base; ctx.fillRect(8, 8, 8, 8); ctx.fillStyle = color; ctx.fillRect(16, 16, 16, 16); ctx.fillStyle = base; ctx.fillRect(24, 24, 8, 8); } $( function() { // jThree.gomlを呼ぶだけで、中身が描写される jThree.goml("01.goml"); } );
jThree.goml()を呼び出すだけでお仕事終了です。
jThree.goml()の第二引数でコールバックを受け取ることが可能ですが、どう使っていいかわからなかったので今回は受け取っていません。
drawSampleTxr2()は以下のgomlから呼び出される関数です。
中身はこちらを参考というかコピペ。
01.goml
<?xml version="1.0" encoding="UTF-8"?> <goml> <head> <!-- 表示先IDを指定 --> <rdr frame="#jtreeSample" camera="camera:first"/> <!-- gmtは図形 --> <gmt id="Cube1" type="Cube" param="5 1 3 1 1 1" /><!-- 直方体 x/y/z/横分割数/縦分割数/奥分割数 --> <gmt id="Circle1" type="Circle" param="2 36 0 6.28" /><!-- 円 半径/分割数/開始角度/中心角 --> <gmt id="Cylinder1" type="Cylinder" param="1 4 3 15 1 false" /><!-- 円柱 上半径/下半径/z/周囲分割数/縦分割数/筒状か --> <gmt id="Sphere1" type="Sphere" param="2 20 10" /><!-- 球 半径/経度分割数/緯度分割数 --> <gmt id="Plane1" type="Plane" param="5 1 1 1" /><!-- 長方形 x/y/横分割数/縦分割数 --> <!-- mtrは材質 --> <mtr type="MeshLambert" id="sampleMtr" param="side:0;color:#fff;" /> <!--txrはテクスチャ --> <txr type="canvas" id="sampleTxr2" param="width: 32; height: 32; repeat: 5; wrap: 0;" draw="drawSampleTxr2( a );" /> <mtr type="MeshPhong" id="sampleMtr2" param="side:2; map: #sampleTxr2;" /> </head> <body> <scene> <!-- カメラの位置 --> <camera style="positionZ: 10;" /> <!-- 光源 x/y/z --> <light type="Dir" style="light-color: #f00; position: 0 10 5;" /> <light type="Dir" style="light-color: #00f; position: 0 -10 -5;" /> <!-- 図形の描画 --> <mesh gmt="#Cube1" style="position: -1.5 3 0;" /> <mesh gmt="#Circle1" style="position: 2 2.5 0;"/> <mesh gmt="#Cylinder1" style="position: 0 -1 0;"/> <mesh gmt="#Sphere1" style="position: -2.2 0 0;" mtr="#sampleMtr" /> <mesh gmt="#Plane1" style="position: 2.2 0 0;rotate:2.2 0 0;" mtr="#sampleMtr2" /> </scene> </body> </goml>
図形等は以下を参考にしています。
ここらへんっていったいどうやって調べてるんだ?ソース読んでるの?
基本的に<head>内に図形やテクスチャ等の要素を記述し、<body>でそれぞれを配置していくという構造になっているようです。
まず<rdr frame>で描写先を指定。
<gmt>で各図形を記述。
予め定義されている図形であれば、パラメータを適当に設定するだけで非常に簡単に作図できます。
<mtr>は材質を指定します。
種類はTHREE.**Materialで規定されているようで色々種類があるみたいなのですが、どうも指定するとエラーになったりparam要素が効かなかったりでどれを指定していいのかよくわかりません。
<txr>はテクスチャです。
今回のサンプルではdrawSampleTxr2()を呼び出してテクスチャを設定していますが、かわりにsrcで直接画像を貼ったりもできます。
<body>内で各要素を実際に表示します。
<camera>でカメラの位置を指定。
遠く離せば、それだけ見える図形が小さくなります。
<light>で光源を設定。
材質に光源が当たると反射して図形が見えるようになります。
光源が存在しなければ図形は真っ暗です。
ちなみに、光源色と、<mtr>で設定されている材質色は論理積になっています。
どういうことかって、光源が青で材質色が赤だった場合、図形の色は紫ではなく真っ暗になります。なんでだ。
<mesh>で図形を表示。
gmt要素で対象のIDを指定、style要素で描画位置や回転等の見た目を設定。
styleは概ねCSSっぽい書き方ができるようです。
基本的にオブジェクトの設置はmeshで行います。
どうにかこうにか、かろうじてjThreeで図形を描写することに成功しました。
なんかこのままやっていってもミクさんを動かせるようになる気がしないんだが大丈夫か。
http://jthree.jp/
なんだこれすごすぎる。
JavaScriptだけでこんなことができるとか全く意味がわかりません。
とりあえず動かしてみることにします。
公式サイトからjThreeをダウンロード。
バージョンはv1.5.1でした。
適当なところに展開する。
デモ一式が入っているので、後は音源のMP3を配置するだけで動作します。
http://www.nicovideo.jp/watch/sm1715919
からMP3をダウンロードし、MP3をdata/audio/melt.mp3に配置します。
とreadmeではなってますが別に適当なMP3でも問題ないようです。
あとはindex.htmlを開くだけでメルトを歌うミクさんが。
http://nurseangel.sakura.ne.jp/js/jthree/
※MP3は著作権の関係上適当なものに差し替えています。
あっさりできました。
どうなってんだこれ。
さっぱりわからないので中身を見ていくことにします。
以下は上記のソースを見ながら見てください。
index.html
プレイヤーの大きさを指定し、必要なライブラリとindex.jsを読み込んでいるだけです。
公式のサンプルはbodyタグに直接出力しているので、適当にdivで括っておいたほうが使い勝手がいいでしょう。
index.js
jThree.Player.setScript()で必要なライブラリを指定します。
jQuery自体はindex.htmlでも読み込んでいるのだけど、何故かこちらでも記載が必要みたいです。
jquery.easingは動作エフェクトを追加するjQueryプラグインのようです。
jThree.Player()でMP3やMMD、クレジット等を指定。
このあたりは規定通りに指定するだけで、あとはjThreeがよしなに計らってくれます。
『MMDプラグインの貢献者katwat氏に特別な感謝を。』はjThree.Playerに最初から埋め込まれてるみたい。
onLoadは#domeGeoの傾きを指定しているみたいですが、あってもなくても動きが変わらないっぽいんだけどなんだろう。
index.goml
MMDのモデルやモーションを設定するXMLみたい。
MMD方面の知識が全くないので、いったい何が書かれているのか全くわかりません。
gomlのリファレンスみたいなものはないのだろうか。
ここまでが自分で記載する必要がある部分。
以下はjThreeとライブラリです。
script/jThree.js
jThreeの本体。
もちろん中に何が書かれているのか全く理解できません。
plugin/jThree.Player.js
呼び出すだけでYoutubeっぽいインターフェイスが自動的に追加されるというjThreeのプラグイン。
なんだこりゃ凄すぎる。
あと、こちらの解説記事ではファイルが分かれているjThree.Trackball.jsやjThree.Oculus.jsあたりは統合されたようで、一緒に中に入っていました。
plugin/jThree.MMD.js
MMDファイルを読み込んで、JavaScriptから扱えるようにする機能みたい。
なんでこんなものが作れるんだ。
plugin/ammo.js
物理演算エンジンです。
有名な物理エンジンBulletを移植したもので、物理演算が簡単に行えるのだそうです。
後はこれらを適当に組み合わせて呼び出すだけで、いとも簡単にミクさんが踊ってくれます。
…あかん、中を見ても全然わからん。
何をどうすればいいのかさっぱりだ。
なんだこれすごすぎる。
JavaScriptだけでこんなことができるとか全く意味がわかりません。
とりあえず動かしてみることにします。
公式サイトからjThreeをダウンロード。
バージョンはv1.5.1でした。
適当なところに展開する。
デモ一式が入っているので、後は音源のMP3を配置するだけで動作します。
http://www.nicovideo.jp/watch/sm1715919
からMP3をダウンロードし、MP3をdata/audio/melt.mp3に配置します。
とreadmeではなってますが別に適当なMP3でも問題ないようです。
あとはindex.htmlを開くだけでメルトを歌うミクさんが。
http://nurseangel.sakura.ne.jp/js/jthree/
※MP3は著作権の関係上適当なものに差し替えています。
あっさりできました。
どうなってんだこれ。
さっぱりわからないので中身を見ていくことにします。
以下は上記のソースを見ながら見てください。
index.html
<html> <head> <style> #player { position: fixed; width: 100%; height: 100%; top: 0; left: 0; margin: 0; padding: 0; } </style> </head> <body> <div id="player"> <a id="jThree-player" href="http://jthree.jp/">jThreeデモ</a> <script src="http://ajax.googleapis.com/ajax/libs/jquery/2.0.0/jquery.min.js"></script> <script src="plugin/jThree.Player.min.js"></script> <script src="index.js"></script> </div> </body> </html>
プレイヤーの大きさを指定し、必要なライブラリとindex.jsを読み込んでいるだけです。
公式のサンプルはbodyタグに直接出力しているので、適当にdivで括っておいたほうが使い勝手がいいでしょう。
index.js
$( function() { jThree.Player.setScript( { jQuery: "//ajax.googleapis.com/ajax/libs/jquery/2.0.0/jquery.min.js", jThree: "script/jThree.min.js", ammo: "plugin/ammo.js", MMD: "plugin/jThree.MMD.js", other: [ "//cdnjs.cloudflare.com/ajax/libs/jquery-easing/1.3/jquery.easing.min.js" ] } ); jThree.Player( { img: "data/img/test.jpg", goml: "index.goml", audio: { "audio/mp3": "data/audio/melt.mp3", "audio/ogg": "data/audio/melt.ogg" }, credits: [ {type: "楽曲",url: "http://supercell.sc/melt/",name: "supercell"}, {type: "モデリングソフト",url: "http://www.geocities.jp/higuchuu4/",name: "樋口優"}, {type: "モデルデータ仕様",url: "http://kkhk22.seesaa.net/",name: "極北P"}, {type: "モデルデザイン",url: "https://twitter.com/animasasa",name: "あにまさ"}, {type: "モデル・カメラモーション",url: "http://www.nicovideo.jp/watch/sm22045369",name: "pokky"}, {type: "スカイドームテクスチャ",url: "http://seiga.nicovideo.jp/user/illust/11592603",name: "(メ_メ)"} ], onLoad: function() { jThree( "mesh:first" ).animate( { rotateY: "-=1.57" }, 30000, "linear", arguments.callee ); } } ); } );
jThree.Player.setScript()で必要なライブラリを指定します。
jQuery自体はindex.htmlでも読み込んでいるのだけど、何故かこちらでも記載が必要みたいです。
jquery.easingは動作エフェクトを追加するjQueryプラグインのようです。
jThree.Player()でMP3やMMD、クレジット等を指定。
このあたりは規定通りに指定するだけで、あとはjThreeがよしなに計らってくれます。
『MMDプラグインの貢献者katwat氏に特別な感謝を。』はjThree.Playerに最初から埋め込まれてるみたい。
onLoadは#domeGeoの傾きを指定しているみたいですが、あってもなくても動きが変わらないっぽいんだけどなんだろう。
index.goml
<?xml version="1.0" encoding="UTF-8"?> <goml> <head> <model id="mikuPmx" src="data/pmx/miku.pmx" /> <motion id="mainVmd" src="data/vmd/model.vmd" /> <motion id="camVmd" src="data/vmd/camera.vmd" /> <txr id="blueSky" src="data/img/sky.png" /> <txr type="canvas" id="floorTxr" param="width: 32; height: 32; repeat: 10; wrap: 0;" draw="misc.drawFloor(a, '#fff', '#2ff')" /> <gmt type="Plane" id="floorGmt" param="60 60 15 15" /> <gmt type="Sphere" id="domeGeo" param="450 32 16" /> <mtr type="MeshPhong" id="skyMat" param="side:1;ambient: #fff; map:#blueSky;"/> <mtr type="MeshPhong" id="floorMtr" param="side:2; map: #floorTxr;" /> <rdr param="antialias: true;"/> </head> <body> <scene> <mesh gmt="#domeGeo" mtr="#skyMat" /> <mesh gmt="#floorGmt" mtr="#floorMtr" style="rotate:1.57 0 -0.785;" /> <light type="Amb" /> <light type="Dir" style="light-color: #9f9f9f; position:-14 28 24.5;" /> <camera motion="#camVmd" style="position: 0 10 30; lookAt:0 10 0;" /> <mmd model="#mikuPmx" motion="#mainVmd" /> </scene> </body> </goml>
MMDのモデルやモーションを設定するXMLみたい。
MMD方面の知識が全くないので、いったい何が書かれているのか全くわかりません。
gomlのリファレンスみたいなものはないのだろうか。
ここまでが自分で記載する必要がある部分。
以下はjThreeとライブラリです。
script/jThree.js
jThreeの本体。
もちろん中に何が書かれているのか全く理解できません。
plugin/jThree.Player.js
呼び出すだけでYoutubeっぽいインターフェイスが自動的に追加されるというjThreeのプラグイン。
なんだこりゃ凄すぎる。
あと、こちらの解説記事ではファイルが分かれているjThree.Trackball.jsやjThree.Oculus.jsあたりは統合されたようで、一緒に中に入っていました。
plugin/jThree.MMD.js
MMDファイルを読み込んで、JavaScriptから扱えるようにする機能みたい。
なんでこんなものが作れるんだ。
plugin/ammo.js
物理演算エンジンです。
有名な物理エンジンBulletを移植したもので、物理演算が簡単に行えるのだそうです。
後はこれらを適当に組み合わせて呼び出すだけで、いとも簡単にミクさんが踊ってくれます。
…あかん、中を見ても全然わからん。
何をどうすればいいのかさっぱりだ。
Firefox4.0.1
Object | |||||||
---|---|---|---|---|---|---|---|
key | value | ||||||
log |
|
||||||
debug |
|
||||||
info |
|
||||||
warn |
|
||||||
exception |
|
||||||
assert |
|
||||||
dir |
|
||||||
dirxml |
|
||||||
trace |
|
||||||
group |
|
||||||
groupEnd |
|
||||||
groupCollapsed |
|
||||||
time |
|
||||||
timeEnd |
|
||||||
profile |
|
||||||
profileEnd |
|
||||||
count |
|
||||||
clear |
|
||||||
table |
|
||||||
error |
|
||||||
notifyFirebug |
|
||||||
firebug | "1.7.0" |
JavaScriptで定期的に実行したい関数がある場合、window.setIntervalを使用することがあるかもしれません。
window.setIntervalは指定した時間毎に関数を実行してくれる便利な関数です。
で、うっかり関数内でsetIntervalを使用した場合、実際うまく動いているように見えることが多いので気付かないかもしれませんが、実は内部で恐ろしいことが起こっています。
AJAXでhoge.phpを拾ってきて、<div>タグの中身を書き換え、インターバルをセットしています。
これでめでたしかと思いきや、ポイントはsetIntervalは重複するというところです。
どういうことかって、最初にHTMLを呼び出した時点でhoge()が実行され、setIntervalでhoge()が予約されます。
1秒後に予約されたhoge()が実行されます。
で、ここでsetIntervalでhoge()が予約されます。
2秒後には…最初に予約されたhoge()と1秒後に予約されたhoge()で2回のhoge()が実行されます。
で、ここでsetIntervalでhoge()が2回分予約され……
自分で書いたものとはいえ、サービスイン直前に見つけたときはどうしようかと思った。
いや、なんかうっかりsetIntervalとsetTimeoutを混同してしまっていたらしい。
というわけでこのような場合はsetTimeoutで実装します。
これで毎秒一回関数が実行されるようになりました。
ちなみに、setIntervalを使う場合は以下のように関数の外に出します。
何故ならばsetIntervalは杓子定規に動くので、もし前の呼び出しが終了していなくてもさらに実行されてしまうのです。
10秒かかる処理をsetIntervalで実装してしまうと、同じ関数が同時に10本走ったりとかそういう事態になってたいへんです。
setIntervalは忘れてsetTimeoutを使いましょう。
window.setIntervalは指定した時間毎に関数を実行してくれる便利な関数です。
で、うっかり関数内でsetIntervalを使用した場合、実際うまく動いているように見えることが多いので気付かないかもしれませんが、実は内部で恐ろしいことが起こっています。
<div id="hoge"> <script type="text/javascript">hoge();</script> </div> <script type="text/javascript"> function hoge(){ $.get("hoge.php", function(data){ $('#hoge').html(data); window.setInterval(hoge, 1000); }); } </script>よくあるAJAXで自動的に更新されるHTMLです。
AJAXでhoge.phpを拾ってきて、<div>タグの中身を書き換え、インターバルをセットしています。
これでめでたしかと思いきや、ポイントはsetIntervalは重複するというところです。
どういうことかって、最初にHTMLを呼び出した時点でhoge()が実行され、setIntervalでhoge()が予約されます。
1秒後に予約されたhoge()が実行されます。
で、ここでsetIntervalでhoge()が予約されます。
2秒後には…最初に予約されたhoge()と1秒後に予約されたhoge()で2回のhoge()が実行されます。
で、ここでsetIntervalでhoge()が2回分予約され……
自分で書いたものとはいえ、サービスイン直前に見つけたときはどうしようかと思った。
いや、なんかうっかりsetIntervalとsetTimeoutを混同してしまっていたらしい。
というわけでこのような場合はsetTimeoutで実装します。
<div id="hoge"> <script type="text/javascript">hoge();</script> </div> <script type="text/javascript"> function hoge(){ $.get("hoge.php", function(data){ $('#hoge').html(data); window.setTimeout(hoge, 1000); }); } </script>setTimeoutは指定時間後にただ一回だけ実行してくれる、という関数です。
これで毎秒一回関数が実行されるようになりました。
ちなみに、setIntervalを使う場合は以下のように関数の外に出します。
<div id="hoge"> <script type="text/javascript">window.setInterval(hoge, 1000);</script> </div> <script type="text/javascript"> function hoge(){ $.get("hoge.php", function(data){ $('#hoge').html(data); }); } </script>こっちでも一応動くのですが、避けられるようであれば避けた方がいいです。
何故ならばsetIntervalは杓子定規に動くので、もし前の呼び出しが終了していなくてもさらに実行されてしまうのです。
10秒かかる処理をsetIntervalで実装してしまうと、同じ関数が同時に10本走ったりとかそういう事態になってたいへんです。
setIntervalは忘れてsetTimeoutを使いましょう。
Dojox.chartingには、themesディレクトリにたくさんのテーマが格納されています。
なので、用意されているテーマを使用するだけであれば、
このテーマは自作することも可能で、実際にDojo道場ではテーマをひとつ作成して実装しています。
ただこちらは一から全部作っているので大がかりです。
基本的には元々あるテーマでいいんだけど少しだけ変更したい、などという場合は、
楽ですね。
なので、用意されているテーマを使用するだけであれば、
dojo.require("dojox.charting.themes.BlueDusk"); myChart.setTheme(dojox.charting.themes.BlueDusk);とするだけで簡単に利用できます。
このテーマは自作することも可能で、実際にDojo道場ではテーマをひとつ作成して実装しています。
ただこちらは一から全部作っているので大がかりです。
基本的には元々あるテーマでいいんだけど少しだけ変更したい、などという場合は、
dojo.require("dojox.charting.themes.BlueDusk"); dojox.charting.themes.BlueDusk.chart.stroke = "#ff0000"; myChart.setTheme(dojox.charting.themes.BlueDusk);です。
楽ですね。
alert(hoge)すると[object Object]って言われてどういうことだよとなりますが、var_dump()みたいに配列やオブジェクトの中身を出力してくれるライブラリがないかと探してみたらprettyPrint.jsというものがみつかりました。
https://github.com/jamespadolsey/prettyPrint.js
変数とDOMに対して使ってみます。
なお、変数の例はこちらのをそのまま借りています。
prettyってわりにソースはちょっとあれなかんじですが、見事に出力できました。
なお、[DEPTH REACHED]ってなってるところは本来ならクリックすると更に詳細を表示することが出来ます。
さて、prettyPrintの解説記事を見て回ったのですがオプションについて書いてる記事がついぞひとつも見つかりませんでした。
第二引数を渡すことで挙動の変更が可能です。
forceObjectは返り値を強制的にObjectにするみたいなんですが意味がよくわかりませんでした。
expandedはfalseにすると詳細を表示しません。
maxDepthで内部構造を掘り下げる深度を調整できます。
いずれも初期状態では隠れているだけで、各値をクリックすることで詳細を見ることができます。
stylesは出力されるテーブルのスタイルを変更することができます。
例でやってるbackgroundImageは、デフォルトだといちいちインライン画像を作ってしまうためキャンセルさせています。
まあ、所詮開発時にしか使わないはずなのであんまりオプションを指定してもしょうがないんですがね。
ちなみにconsole.dir()のことは秘密だぞ。
https://github.com/jamespadolsey/prettyPrint.js
変数とDOMに対して使ってみます。
なお、変数の例はこちらのをそのまま借りています。
<html> <head> <script src="prettyprint.js"></script> </head> <body> <div id="hoge" title="title">text<span>inner</span></div> <div id="output"></div> <div id="output2"></div> <script type="text/javascript"> var hoge =document.getElementById('hoge'); document.getElementById('output').appendChild(prettyPrint(hoge)); var config = { expanded :true, forceObject: true, maxDepth: 2, styles: { 'default': { th: { backgroundImage:false } } } }; var test = { _arr : ["pretty","print"], _rear : [["pretty","print"]], _reobj : { "a":"pretty", "b":{"b1" : "print"}}, _func : function(_str){ alert(_str); return; } }; document.getElementById('output2').appendChild(prettyPrint(test, config)); </script> </body> </html>出力は以下。
DOMElement | |
---|---|
tag | <div> |
id | hoge |
innerHTML | text<span>inner</span> |
Object | |||||||||
---|---|---|---|---|---|---|---|---|---|
key | value | ||||||||
_arr |
|
||||||||
_rear |
|
||||||||
_reobj |
|
||||||||
_func |
|
prettyってわりにソースはちょっとあれなかんじですが、見事に出力できました。
なお、[DEPTH REACHED]ってなってるところは本来ならクリックすると更に詳細を表示することが出来ます。
さて、prettyPrintの解説記事を見て回ったのですがオプションについて書いてる記事がついぞひとつも見つかりませんでした。
第二引数を渡すことで挙動の変更が可能です。
forceObjectは返り値を強制的にObjectにするみたいなんですが意味がよくわかりませんでした。
expandedはfalseにすると詳細を表示しません。
maxDepthで内部構造を掘り下げる深度を調整できます。
いずれも初期状態では隠れているだけで、各値をクリックすることで詳細を見ることができます。
stylesは出力されるテーブルのスタイルを変更することができます。
例でやってるbackgroundImageは、デフォルトだといちいちインライン画像を作ってしまうためキャンセルさせています。
まあ、所詮開発時にしか使わないはずなのであんまりオプションを指定してもしょうがないんですがね。
ちなみにconsole.dir()のことは秘密だぞ。
前回の続き。
記事では紹介だけに留められている悲しいメソッドたちを簡単に使ってみます。
http://codezine.jp/article/detail/5572?p=3
記事では紹介だけに留められている悲しいメソッドたちを簡単に使ってみます。
http://codezine.jp/article/detail/5572?p=3
<html> <head> <meta http-equiv="Content-Type" content="text/html; charset=UTF-8"> <style type="text/css"> @import "dojo/resources/dojo.css"; @import "dijit/themes/claro/claro.css"; </style> <script type="text/javascript" src="dojo/dojo.js" djConfig="parseOnLoad: true, isDebug: true"></script> <script type="text/javascript"> dojo.require("dojox.charting.Chart2D"); dojo.require("dijit.form.Form"); dojo.require("dijit.form.RadioButton"); dojo.require("dojox.charting.themes.Charged"); //グローバルにする var myChart; //ランダムな値の配列を作成 function getRandArray(count){ if (count == undefined) { var count = 12; } var retArr = new Array(); var i=0; while(i<count){ retArr.push(Math.floor(Math.random() * 1000)); i++; } return retArr; } var drawChart = function(){ //折れ線グラフ myChart = new dojox.charting.Chart2D("myChart"); myChart.addPlot("plot1", {type: "Lines"}); myChart.addPlot("plot2", {type: "ClusteredColumns", vAxis: "right"}); myChart.addAxis("x", {majorTickStep: 1, natural: true}); myChart.addAxis("y", {vertical: true}); myChart.addAxis("right", {vertical: true, leftBottom: false, fixUpper: "major", includeZero: true}); myChart.addPlot("grid", {type: "Grid"}); myChart.addSeries("series1", getRandArray(), {plot: "plot1"}); myChart.addSeries("series2", getRandArray(), {plot: "plot1"}); myChart.addSeries("series3", getRandArray(), {plot: "plot2"}); myChart.setTheme(dojox.charting.themes.Charged); myChart.render(); } //拡大縮小 var resizeChart2DToggle = 0; var resizeChart2D = function(){ resizeChart2DToggle = 1 - resizeChart2DToggle; if(resizeChart2DToggle == 1){ myChart.resize(500, 300); }else{ myChart.resize(400, 200); } } //値の更新 var updateSeries = function(series, span){ myChart.updateSeries("series1", getRandArray(span)); myChart.updateSeries("series2", getRandArray(span)); myChart.updateSeries("series3", getRandArray(span)); myChart.render(); } //Plotの順番入れ替え var movePlotToFrontToggle = 0; var movePlotToFront = function(){ movePlotToFrontToggle = 1 - movePlotToFrontToggle; myChart.movePlotToFront("plot"+(movePlotToFrontToggle+1)); myChart.render(); } //Seriesの順番入れ替え var moveSeriesToFrontToggle = 0; var moveSeriesToFront = function(){ moveSeriesToFrontToggle = 1 - moveSeriesToFrontToggle; myChart.moveSeriesToFront("series"+(moveSeriesToFrontToggle+1)); myChart.render(); } //削除 var removeSeriesToggle = 0; var removeSeries = function(){ removeSeriesToggle = 1 - removeSeriesToggle; if(removeSeriesToggle == 1){ myChart.removeSeries("series1"); myChart.removeSeries("series2"); myChart.removeSeries("series3"); }else{ myChart.addSeries("series1", getRandArray(), {plot: "plot1"}); myChart.addSeries("series2", getRandArray(), {plot: "plot1"}); myChart.addSeries("series3", getRandArray(), {plot: "plot2"}); myChart.render(); } } //起動時実行 dojo.addOnLoad(drawChart); </script> </head> <body class="claro"> <form dojoType="dijit.form.Form"> <input type="radio" dojoType="dijit.form.RadioButton" onClick="resizeChart2D()" name="span" id="formButtonResizeChart2D" /> <label for="formButtonResizeChart2D">拡大/縮小</label> <input type="radio" dojoType="dijit.form.RadioButton" onClick="updateSeries('series1', 12)" name="span" id="formButtonUpdateSeries"/> <label for="formButtonUpdateSeries">値の更新</label> <input type="radio" dojoType="dijit.form.RadioButton" onClick="moveSeriesToFront()" name="span" id="formButtonMoveSeriesToFront"/> <label for="formButtonMoveSeriesToFront">Seriesの順番入れ替え</label> <input type="radio" dojoType="dijit.form.RadioButton" onClick="movePlotToFront()" name="span" id="formButtonMovePlotToFront" /> <label for="formButtonMovePlotToFront">Plotの順番入れ替え</label> <input type="radio" dojoType="dijit.form.RadioButton" onClick="removeSeries()" name="span" id="formButtonRemoveSeries" /> <label for="formButtonRemoveSeries">Series削除/戻す</label> </form> <div id="myChart" style="width: 400px; height: 200px;"></div> </body> </html>
前回の続き。
これまでdojoで作ってきたグラフは単に表示するだけでした。
いよいよグラフに対し動的な変化を与えてやりましょう。
dojox.charting.Chart2D.setAxisWindowメソッドでスケールの変更を行うことができます。
あとはその値を設定するインターフェイスを追加するだけです。
これまでdojoで作ってきたグラフは単に表示するだけでした。
いよいよグラフに対し動的な変化を与えてやりましょう。
dojox.charting.Chart2D.setAxisWindowメソッドでスケールの変更を行うことができます。
あとはその値を設定するインターフェイスを追加するだけです。
<html> <head> <meta http-equiv="Content-Type" content="text/html; charset=UTF-8"> <script type="text/javascript" src="../dojo/dojo.js" djConfig="parseOnLoad: true"></script> <script type="text/javascript"> dojo.require("dojox.charting.DataSeries"); dojo.require("dojo.data.ItemFileWriteStore"); dojo.require("dojox.charting.Chart2D"); dojo.require("dijit.form.Form"); dojo.require("dijit.form.RadioButton"); //グローバルにする var myChart; var drawChart = function(){ //ダミーのストア var store = new dojo.data.ItemFileWriteStore({data:{items:[{value: 0}]}}); //折れ線グラフ myChart = new dojox.charting.Chart2D("myChart"); myChart.addPlot("default", {type: "Lines"}); myChart.addAxis("x", {majorTickStep: 1, natural: true}); myChart.addAxis("y", {vertical: true}); myChart.addPlot("grid", {type: "Grid"}); myChart.addSeries("stockprice", new dojox.charting.DataSeries(store)); myChart.render(); //適当に値を設定 var i=1; while(i<12){ var val = Math.floor(Math.random() * 1000); store.newItem({value: val}); i++; } } //クリックで拡大率変更 var changeView = function(span){ //オンであれば if(dijit.byId(span + "months").get("checked") == true){ // 拡大率の計算 var sx = (12 - 1) / (span - 1); // グラフの表示期間変更 myChart.setAxisWindow("x", sx, 12 - span); myChart.render(); } } //起動時実行 dojo.addOnLoad(drawChart); </script> </head> <body class="claro"> <form dojoType="dijit.form.Form"> <input type="radio" dojoType="dijit.form.RadioButton" onChange="changeView(3)" name="span" id="3months"/> <label for="3months">3ヶ月</label> <input type="radio" dojoType="dijit.form.RadioButton" onChange="changeView(6)" name="span" id="6months"/> <label for="6months">6ヶ月</label> <input type="radio" dojoType="dijit.form.RadioButton" onChange="changeView(12)" name="span" id="12months" checked/> <label for="12months">1年</label> </form> <div id="myChart" style="width: 400px; height: 200px;"></div> </body> </html>
前回の続き。
今回は一度作成したグラフを更新します。
http://codezine.jp/article/detail/5572?p=2
既にグラフの表示自体はできているのでたいして難しいことはありません。
グラフの画面描画はrender()メソッドですが、実は一旦render()してしまえば後はストアに値を突っ込むだけで勝手に画面が更新されます。
今回は一度作成したグラフを更新します。
http://codezine.jp/article/detail/5572?p=2
既にグラフの表示自体はできているのでたいして難しいことはありません。
グラフの画面描画はrender()メソッドですが、実は一旦render()してしまえば後はストアに値を突っ込むだけで勝手に画面が更新されます。
<html> <head> <meta http-equiv="Content-Type" content="text/html; charset=UTF-8"> <script type="text/javascript" src="../dojo/dojo.js" djConfig="parseOnLoad: true, isDebug: true"></script> <script type="text/javascript"> dojo.require("dojox.charting.DataSeries"); dojo.require("dojo.data.ItemFileWriteStore"); dojo.require("dojox.charting.Chart2D"); var drawChart = function(){ //ダミーのストア var store = new dojo.data.ItemFileWriteStore({data:{items:[]}}); //折れ線グラフ var myChart = new dojox.charting.Chart2D("myChart"); myChart.addPlot("default", {type: "Lines"}); myChart.addAxis("x"); myChart.addAxis("y", {vertical: true}); myChart.addPlot("grid", {type: "Grid"}); myChart.addSeries("stockprice", new dojox.charting.DataSeries(store)); myChart.render(); //1秒毎に繰り返し var i = 1; var reloadInterval = setInterval(addItemFileWriteStore, 1000); function addItemFileWriteStore(){ if (i < 30) { var val = Math.floor(Math.random() * 1000); store.newItem({value: val}); } else { clearInterval(reloadInterval); } i++; } } //起動時実行 dojo.addOnLoad(drawChart); </script> </head> <body> <div id="myChart" style="width: 400px; height: 200px;"></div> </body> </html>