Blog
メモ: Processing.jsでJSON形式のデータを読み込む
Processing.jsで、JSONファイルをパラメータにしてデータを読み込んで表示しようとしたら、思いの他苦労したのでメモ。
Java版のProcessingであれば、ver.2からはJSONをパースするJSONObjectが用意されているので、これを素直に利用すれば良い。しかし、Javascirpt版のProcessing.jsには、まだJSONObjectは組込まれていないので、自分で頑張らなくてはならない。
まず、基本的なやり方を、Processing.jsのチュートリアルのページを参照してみた。基本的な考え方としては、JSONファイルの読み込みとパースは、Processingを表示するCanvasを持つHTML側で行わなくてはならないようだ。
しかし、この通りにやってみても、うまくいかない… うーむ。どうやら、Processingの書類が読み込まれるタイミングとJSONのデータの読み込まれるタイミングの順番が狂ってしまうことがあるみたいだ。
もう少し賢くJSONの読込みとパースをするため、jQueryを使ってみた。また、Processingの書類の読込みが遅れたときの対策として、定期的にProcessingのあるCanvasを取得しに行くように変更。
まず、以下のようなJSON形式のデータを用意してみた。
{"nodes": [ {"x":200,"y":200,"diameter":400,"name":"First"}, {"x":220,"y":240,"diameter":300,"name":"Second"}, {"x":150,"y":180,"diameter":200,"name":"Third"}, {"x":220,"y":200,"diameter":100,"name":"Fourth"}, {"x":300,"y":250,"diameter":50,"name":"Fifth"} ] }
HTMLとJSON処理のJavaScriptは、こんな感じ。
<!DOCTYPE html> <html> <head> <meta charset="utf-8"> <title>My Processing Page</title> <script src="//ajax.googleapis.com/ajax/libs/jquery/1.10.2/jquery.min.js"></script> <script type="text/javascript" src="processing.js"></script> <script type="text/javascript"> // 取得したJSONオブジェクトを格納する配列 var obj_array = new Array(); // JSONを読込み $.ajax({ url:"./test.json", type:'GET', success: function(data){ jQuery.each( data.nodes, function(i) { // JSONから取得したオブジェクトを配列に格納 obj_array[i] = data.nodes[i]; }); } }); var tId, pjs, cnt=0; // 文書全体が読み終わったら $(function(){ // Processingが取得できるまで if (!pjs){ // 100msごとにくりかえし tId=setInterval(function(){ // Processingの貼ってあるCanvasを取得 pjs = Processing.getInstanceById("pjsid"); // 取得できたら if (pjs && obj_array){ // 取得を中止 clearInterval(tId); // Processingの関数を実行して、配列を送信 pjs.addObjects(obj_array); } },100); } }); </script> </head> <body> <canvas id="pjsid" data-processing-sources="p5jsjson.pde"></canvas> <p>Source: <a href="p5jsjson.pde">p5jsjson.pde</a></p> </body> </html>
そして、確認用のProcessing.jsのテストコード。
ArrayList circles; void setup(){ size(400, 400); frameRate(30); circles = new ArrayList(); } void draw(){ background(63); for (int i = 0; i < circles.size(); i++) { circles.get(i).draw(); } } void addObjects(nodes){ for(int i = 0; i < nodes.length; i++){ PVector pos = new PVector(nodes[i].x, nodes[i].y); float diameter = nodes[i].diameter; string name = nodes[i].name; console.log("x: " + pos.x + ", y: " + pos.y + ", diameter: " + diameter + ", name: " + name); circles.add(new MyCircle(pos, diameter, name)); } } class MyCircle{ PVector pos; float diameter; string name; MyCircle(PVector _pos, float _diameter, string _name){ pos = _pos; diameter = _diameter; name = _name; } void draw(){ fill(0, 127, 255, 15) stroke(31, 127, 255); ellipse(pos.x, pos.y, diameter, diameter); fill(255); noStroke() ellipse(pos.x, pos.y, 5, 5); text(name, pos.x+4, pos.y-2); } }
どうやら、これでうまくいっているみたい。
でも、若干煩雑な感じ。もっとシンプルに読みこめる方法をご存知の方いましたら、教えてください…