fc2ブログ

積み上げ棒グラフ表示JavaScriptライブラリに、縦棒表示機能追加

先日公開した HTML5 Canvasで積み上げ棒グラフを表示するJavaScriptライブラリに、縦棒の積み上げ棒グラフを表示する機能を追加した。
積み上げ棒グラフ2

使用方法の説明、ライブラリのダウンロードは以下からどうぞ。
積み上げ棒グラフ作成 | 無職のHTML5 Canvas

Canvasサイズに応じてグラフ間の余白などが変化するため、横棒と縦棒の違いを考慮して余白を調整するところが苦労した。
ついでにグラフのタイトルを表示する機能も追加した。

昨日の記事に書いた、「表示幅に収まらない文字列をどうするか」対応も結構時間がかかった。
結局、
タイトル、説明文、エラーメッセージ → fontsizeを少しずつ減らして、できるだけ枠内に表示
データ値、見出し → 表示幅に収まらない場合は表示しない
という対応にした。
ブラウザがFirefoxのときだけfillText()のmaxWidth対応を考慮して判定しているため、他のブラウザでは表示されないのにFirefoxでは表示される場合がある。

そんなこんなで、ソースのサイズが前回公開時の倍ぐらいになってしまった。
スポンサーサイト



積み上げ棒グラフを表示するJavaScriptライブラリ修正中

一昨日公開した、積み上げ棒グラフを表示するJavaScriptライブラリに、棒グラフを縦に表示する機能を追加した。
ところがテスト中に問題が発生。
Google Chromeなどは fillText()のmaxWidth に対応していないため、文字が重なってしまう。
横棒グラフでも同じ問題が発生するのだが、テストが甘かった。

とりえあずエラーメッセージ表示部分だけ
「fontsizeを少しずつ減らして、measureText()で枠に収まるかチェック」
を行い、できるだけ枠内に表示するようにした。
他の箇所をどうしようか考え中。

そんなわけで、棒グラフを縦に表示するバージョンの公開は延期。
でも参考にしたAwesomeChartJSは、maxWidth非対応ブラウザ向け対策してないんだよなぁ。

[Google App Engine for Python]静的なテキストファイルの文字コードを指定する

昨日、積み上げ棒グラフを表示するJavaScriptライブラリを公開したのだが、ReadmeをテキストファイルとしてGAEにアップした。
ReadmeはUTF-8で記述したので、文字コードを指定しないと、ブラウザによっては文字化けしてしまう。
GAE/Pで静的なテキストファイルの文字コードを指定する方法を調べたので、忘れないうちに書いておく。

プログラムの出力であれば response.headers['Content-Type'] で文字コードを設定すればいいのだが、静的ファイルの場合はapp.yamlで文字コードを指定する。
  - url: /txt
    static_dir: txt
    mime_type: text/plain; charset=UTF-8
とapp.yamlに記述すれば、/txt以下のファイルに対して、HTTPレスポンスヘッダーに Content-Type text/plain; charset=UTF-8 が付加される。
拡張子にかかわらず、対象となる全てのファイルのHTTPレスポンスヘッダーに付加されるので注意。

static_dirではなく、static_filesを指定することで、対象となるファイルを正規表現で指定できる。
  - url: /fordl/(.+\.txt)
    static_files: fordl/\1
    upload: fordl/(.+\.txt)
    mime_type: text/plain; charset=UTF-8
  - url: /fordl
    static_dir: fordl
こうすれば、/fordl以下の.txtのみ、HTTPレスポンスヘッダーに Content-Type text/plain; charset=UTF-8 が付加される。
URLは上から順に評価されるため、記述順序に注意。

文字コードを考慮してファイル名をつければ、異なる文字コードのファイルを混在させることも可能。
  - url: /fordl/(.*utf.*\.txt)
    static_files: fordl/\1
    upload: fordl/(.*utf.*\.txt)
    mime_type: text/plain; charset=UTF-8
  - url: /fordl/(.*sjis\.txt)
    static_files: fordl/\1
    upload: fordl/(.*sjis\.txt)
    mime_type: text/plain; charset=Shift_JIS
  - url: /fordl
    static_dir: fordl

以上。

HTML5 Canvasで積み上げ棒グラフを表示するJavaScriptライブラリを公開した

このような積み上げ棒グラフを表示するJavaScriptライブラリを公開した。
積み上げ棒グラフ1

使用方法の説明、ライブラリのダウンロードは以下からどうぞ。
積み上げ棒グラフ作成 | 無職のHTML5 Canvas

かなり詳しい使用方法をReadmeに書いたのだが、書いてる途中で「ここまで詳しく書く必要があるのだろうか」と思った。
それ以前に、自分の説明でちゃんと理解してもらえるんだろうか。
孤独なプログラマーなので、客観的な意見をくれる人が周りにいない。

次は縦棒も表示できるように機能追加しようかな。

作ったJavaScriptライブラリを公開しようとする

HTML5 Canvasで 積み上げ棒グラフ を表示するJavaScriptライブラリのテストも一応終わり、さて公開しようと思ったが、公開ページを作らなきゃいけない。
大したプログラムじゃないので、ソースだけどっかにアップしてもいいんだけど。

自分が作ったものを公開しているページに追加することにしたが、紹介文や使い方をどこまでちゃんと書こうか。
デフォルトではCanvasのサイズに応じてグラフ表示関連のサイズが変わるため、期待したサイズでグラフが表示されない場合がある。
表示サイズを調整するための情報はちゃんと書いておきたい。
ライブラリの使用例をちょっと書いて、「クラスのプロパティやメソッドの詳細はReadme.txtを読んでください」にしようかな。

HTML5 Canvasで 積み上げ棒グラフ を表示させてみた

私用で作ったプログラムでグラフ表示をしたくて、HTML5 Canvasで 積み上げ棒グラフ を表示するプログラムを作った。
表示結果はこんな感じ。
積み上げ棒グラフ1
AwesomeChartJS を参考にして作った。
AwesomeChartJSと同様に、Canvasのidを指定してクラスのインスタンスを生成し、プロパティにデータを格納してdraw()メソッドで表示するようにした。

せっかくだから作ったプログラムを公開したいのだが、入力値のチェックやCanvasのサイズに応じて表示サイズを変えるなど、もうちょっと修正する必要がある。
使用方法を書くのも時間がかかりそうだ。
ライセンスについてはよくわからないが、AwesomeChartJSがApache license v2.0だから、公開しても問題ないだろう。元ネタからはだいぶ変わってるし。

横棒だけでなく縦棒表示にも対応させたいが、それだと公開が更に遅れそうだ。

[Google App Engine for Python] webappでDjango1.2のテンプレートを使う

GAE/Pでプログラミングしていたら、
「Djangoのデフォルトのバージョンが変わる予定だから、 use_library() でバージョンを指定してね」
というWARNINGがログに出ていた。
自分が作成したプログラムのDjangoテンプレートを0.96から1.2へ変更したので、やり方をまとめる。

1. Djangoのバージョンを指定する
webappフレームワークでDjangoテンプレートを使用する方法は、テンプレートの使用を参照。
Djangoのバージョンを指定する方法は、Third-party Python Libraries に記述されている。
日本語訳には(現時点では)記述されていない。

App Engine SDKには、Django0.96とDjango1.2が標準で入っている。
以下のようにしてバージョンを指定する。
  from google.appengine.dist import use_library
  use_library('django', '1.2')
  from google.appengine.ext.webapp import template
以下の点に注意すること
・import template の前に use_library() すること
・アプリケーション内でDjangoのバージョンを統一すること
他のプログラムがimport templateした後、use_library()で別のバージョンを指定するとエラーになる。

2. Django1.2のテンプレートに関するドキュメント
Django1.2のテンプレートでは、
  {% if var1 != var2 and var1 != var3 %}
    var1 is not var2 and var1 is not var3<br>
    {% if var1 == 1 and var2 > 1 or var3 == 0 %}
      (var1 equals 1 and var2 is larger than 3) or var3 equals 0<br>
    {% endif %}
  {% endif %}
のような記述ができる。

Djangoテンプレートの日本語訳ドキュメントは、Django1.0しか見つけられなかった。
Django テンプレート言語
組み込みタグ/フィルタリファレンス

Django1.2のテンプレートに関するドキュメント(英語)は以下
The Django template language
Built-in template tags and filters
Built-in template tags and filters を 'New in Django' と 'Changed in Django' でページ内検索すれば、Django1.1以降の変更点がわかる。

3. Django0.96からDjango1.2へ変更する場合の注意点
Django 1.0でHTMLの自動エスケープが導入されている。
< > ' " & が勝手にエスケープされるため、HTML文をテンプレートに渡しているプログラムは動きがおかしくなる。
自動エスケープをオフにする方法は、自動エスケープを切るにはを参照。

以上。
自分はログを見てたまたま気づいたけど、GAEのDjangoデフォルトバージョンが変わったとたんに動かなくなるケースがありそう。開発者が放置しているアプリとか。

JSONを使ってAjaxでデータ受信してみる

Ajaxでのデータ受信はXMLしか知らなかった。
JSONも覚えた方がいいよなと思い立ち、やり方を調べて使ってみた。

結論から言えば、JSONはXMLに比べるとかなり楽。覚えるのもプログラミングも。
JavaScriptで使用するデータを渡す場合はJSONの方がいいな。
XMLパースエラーを気にせずに、< > & をそのまま送れるのもいい。" は \ でエスケープする必要があるが。

去年私用で作ったプログラムを、JSONを使うように変更した。
変更前のDjangoテンプレート
msg は処理結果メッセージ文字列で、outdataLがデータ配列
  <?xml version='1.0' encoding='UTF-8'?>
  <doc>
    <msg>{{ msg }}</msg>
    {% if outdataL %}
      {% for outdata in outdataL %} <data>{{ outdata }}</data>
      {% endfor %}
    {% endif %}
  </doc>

JSON用に変更したDjangoテンプレート
  {"msg" : "{{msg}}"
    {% if outdataL %}
      ,
      "dataL" : [
      {% for outdata in outdataL %} "{{ outdata }}"
        {% if not forloop.last %},{% endif %}
      {% endfor %}
      ]
    {% endif %}
  }
配列の最後にコンマを付加しないよう、forloop.last で判定した。

HTTPヘッダのContent-TypeもJSON用に変更。
  self.response.headers['Content-Type'] = ('text/javascript; '
      'charset=utf-8')
サーバー側の変更はこのぐらい。他にもXMLパースに関する部分を少々変更したが略。

JavaScriptの、JSONを使ってAjaxでデータ受信する部分は以下のようになった。jQueryはver1.4.4を使用。
  $.ajax({
    url: acturl, // 実行されるURL
    type: 'GET',
    dataType: 'json',
    timeout: 20000, // タイムアウト時間(ミリ秒)
    beforeSend: function() { // 送信前に実行される処理
      $sbtn.css('display','none'); // 送信ボタン非表示
      $msgdiv.text('データ送信中'); // 送信メッセージ表示
    },
    success: function(getdata) { // 通信成功時に実行される処理
      var outhtml = getdata.msg + '<br>';
      var dataArr = getdata.dataL;
      for (var i = 0; i < dataArr.length; i++) {
        /* 受信データ処理部分は略 */
      }
      $datadiv.html(outhtml); // 受信データ表示
      $sbtn.css('display','inline'); // 送信ボタン表示
      $msgdiv.remove(); // 送信メッセージ削除
    },
    error: function(XMLHttpRequest, status) { // 通信エラー時に実行される処理
      $sbtn.css('display','inline'); // 送信ボタン表示
      $datadiv.text(status); // エラーステータス表示
      $msgdiv.remove(); // 送信メッセージ削除
    }
  });
受け取ったデータを、そのままオブジェクトとして利用できるから楽だ。

ハマることも無く、すぐにJSONを使うことができた。
Ajaxの勉強は、XMLより先にJSONを使った方がいいんじゃないかと思った。

[JavaScript]小数を整数に変換する望ましい方法は?

昨日書いた 背景をdiv要素に描画して、HTML5 Canvasタグに重ねる だが、
これは HTML5@iPhoneゲーム開発 のCanvas高速化Tipsを参考にしている。
このTipsには「座標や幅、高さの指定はintにする」という項目もあって、深く考えずにparseIntしていたのだが、見直したら「parseIntは使わない」と書いていた。
浮動小数点数を整数にする高速(?)な方法 - JavaScript比較 によると、parseInt(Number)はブラウザによってはかなり遅いようだ。
そもそもparseIntは文字列を変換する関数だし。

じゃあどうすればいいのかと思ったのだが、
Re:浮動小数点数を整数にする高速(?)な方法 - JavaScript比較
によると、
しかし、関数呼び出しである Math.floor よりも、プリミティブ演算 (含ビット演算) を使うほうが格段に速い。
例えば、0以上2147483648未満の少数に限られるが、「その数を越えない最大の整数 (の正部分)」を求めるなら、amachang さんの書いている ~~ 演算が使え、速度は以下のようになる。
だそうで、Firefoxの数値を見ると ~~ 演算を使った場合はMath.floorより10倍速い。

~ 演算は符号つき32bit整数として演算するから、2の31乗である2147483648未満なんだな。
上記引用では「0以上」とあるけど、単に小数部分を切り落とすだけなら負の数でも良くて
~~2147483647.99999 == 2147483647
~~(-2147483647.99999) == -2147483647
となる。
負の数の扱いがMath.floorと異なるので要注意。
~~(-3.14) == -3
Math.floor(-3.14) == -4

~~ 演算を紹介している記事のコメントにある |0 の方が、演算回数が少ない分速いかなと思ったが、計測してみたらさほど変わらない。
というわけで、自分もこれからは ~~ 演算を使って小数を整数に変換しよう。
でも知らない人が見たら、何やってるかわからないだろうな。

<関連エントリ>
Numberの整数化タイミングについて考える

背景をdiv要素に描画して、HTML5 Canvasタグに重ねる

去年作った戦車が撃ちあうゲームをGAEのページへ移行した。
Canvas Tank Battle | 無職のHTML5 Canvas

移行のついでに、地形マップをCanvasタグではなく背景のdiv要素に描画するようにした。
ステージ開始時にだけ地形の描画が行われるようになるので、負荷がちょっと減る。
背景に画像などを使用する場合は、負荷の減少が大きくなるだろう。

やったことをまとめようと思ったが、CSSで要素を重ねただけなので書くことが無い。
HTMLはこんな感じ。
<div class="divcv">
  <div class="backdiv"></div>
  <div id="mcvback" class="landdiv"></div>
  <div class="wrapcv"><canvas id="mcv" class="cv" width="400" height="400"></canvas></div>
</div>
これを、親要素を position: relative 、背景要素を position: absolute にして、z-indexを指定して重ねるだけ。
CSSは以下のとおり。
<style TYPE="text/css">
/* 親要素div */
.divcv {
  position: relative;
  margin: 10px 35px 0px 20px;
  width: 400px;
}
/* Canvas */
.cv {
  border-style: solid;
  border-width: 1px;
  border-color: #808080;
}
/* Canvasを囲うdiv */
.wrapcv {
  position: relative;
  z-index: 5;
}
/* 地形マップを描画する背景div
 * マップのサイズはステージごとに変わるため、top/leftはJavaScriptで設定
 */
.landdiv {
  position: absolute;
  z-index: 1;
}
/* Canvas領域に色をつけるためだけのdiv */
.backdiv {
  position: absolute;
  top: 0;
  left: 0;
  width: 400px;
  height: 400px;
  z-index: 0;
  background-color: #F8F8FF;
}
</style>

JavaScriptで背景を描画したが、地形1マスごとにdiv要素を作ってひたすらappendしただけ。
Canvasのborder-widthの分だけ座標をズラす必要がある。
ソースは以下のとおり。jQueryはver1.4.4を使用。
/* 背景描画
 * return なし
 */
tkgame.drawland = function() {
  var grSep = tkgame.canv.grSep; // マスのサイズ(px)
  // 背景div設定
  var $mcvback = $('#' + tkgame.con.id.mcvback); // 地形マップを描画する背景div
  var bwdth = 1; // Canvasのborder-width
  $mcvback.empty(); // 全ての子要素を削除
  /* tkgame.canv.stgx, tkgame.canv.stgy は、ステージ左上の座標
   * tkgame.canv.axlen, tkgame.canv.aylen は、ステージの横幅何マスか、縦幅何マスか
   */
  $mcvback.css('top', (tkgame.canv.stgy + bwdth) + 'px');
  $mcvback.css('left', (tkgame.canv.stgx + bwdth) + 'px');
  $mcvback.css('width', (tkgame.canv.axlen * grSep) + 'px');
  $mcvback.css('height', (tkgame.canv.aylen * grSep) + 'px');
  // 地形要素設定
  var $landdiv; // 背景の地形要素
  var landname;
  /* tkgame.canv.landAr は、地形情報を格納した二次元配列
   * 詳細は tkland.js を参照
   */
  for (var ix = 0; ix < tkgame.canv.landAr.length; ix++) {
    for (var iy = 0; iy < tkgame.canv.landAr[ix].length; iy++) {
      landname = tkgame.canv.landAr[ix][iy];
      $landdiv = $('<div/>').addClass(tkgame.con.classn.landdiv);
      $landdiv.css('top', (grSep * iy) + 'px');
      $landdiv.css('left', (grSep * ix) + 'px');
      $landdiv.css('width', grSep + 'px');
      $landdiv.css('height', grSep + 'px');
      $landdiv.css('backgroundColor', tkland.type[landname].col);
      $mcvback.append($landdiv);
    }
  }
};
IE + FlashCanvas でもちゃんと表示できることを確認した。

これでひと通りの移行作業が終わった。
さて次は何を作ろうかな。
プロフィール

himax64

Author: 南西
30代後半の無職です。
就活もせずダラダラ生きてます。
作ったもの

最新記事
人気記事
検索フォーム
カテゴリ
月別アーカイブ
最新コメント
最新トラックバック
RSSリンクの表示
QRコード
QRコード
カウンター