ZAPAnet総合情報局 > [Z]ZAPAブロ〜グ2.0 > プログラミングTIPS > 3D円グラフを作る上で苦労したこと、捨てたものなど

3D円グラフを作る上で苦労したこと、捨てたものなど

このエントリーをはてなブックマークに追加
2007年04月04日 カテゴリ:プログラミングTIPS
先日リリースした「超かんたん3D円グラフ作成!」ですが、このWebサービスを作る上で苦労したこと、捨てたものなどを書いてみます。
大ヒットしているWii Sportsの野球が「投げることと打つこと」だけに絞られているのと同様、「超かんたん3D円グラフ作成!」もいろいろな機能を犠牲にして完成しました。
作ったことだけを報告すると、まるでプログラム自体も「超かんたん」に作れてしまったように思われてしまいますが、けっこう悩んでたりもしています。

「超かんたん3D円グラフ作成!」のコンセプト

まずプログラムを作る前に、円グラフを作成するサービスのコンセプトを考えました。
コンセプトは、
べつやくメソッド」を導入する際の手助けになり、超かんたんにわかりやすい円グラフ画像が作成できること

なぜこのサービスを作ろうと思ったかというと、今まで円グラフを作成するときには、以下のような問題点があったからです。
1.エクセルなどを使えば円グラフは作成できるが、エクセルに打ち込むのが大変
2.円グラフの見栄えを統一するのが大変
3.できあがった円グラフを画像として保存するのが面倒
4.そもそもエクセルがインストールされていない環境も多くある
これら円グラフを作成する上での問題点を解決するために、「超かんたん3D円グラフ作成!」を作ろうと決めました。
ですが、コンセプトに挙げた「べつやくメソッド」、「超かんたん」という項目が、後に様々な葛藤を生む要因となりました。


円グラフを作る方法を考える

サーバー上で円グラフを作成する方法はいくつもあります。
最初、PHPでJpGraphというライブラリを使って簡単に実現させようと思いましたが、完全フリーのライブラリではないのでやめました。
今回はPHP+GDライブラリを使って実現させることに決めました。

以下のページを参考に、PHP+GDライブラリで円グラフを作成するプログラムを作っていきました。
PHPマニュアル:イメージ関数(image)
円グラフの生成 - PHP/データベース
PHPで円グラフを作ろうPHPで円グラフを作ろう(2)


べつやくメソッドの難しさを痛感

べつやくメソッドに近づけるために、べつやくれいさんが作る円グラフと似ている円グラフを作ろうとしました。
べつやくれいさんが作る円グラフの特徴と言えば…
1.字がかわいくてわかりやすい、読みやすい
2.色もわかりやすくて、きれい
3.面積が小さめな楕円にもきれいに字が収まっている
4.楕円に入りきらない項目は指示線を出して、文字を書いている
です。

この中で、プログラムで実現させることが難しいのは、3の「面積が小さめな楕円にもきれいに字が収まっている」です。
手書きなら簡単ですが、プログラムで実現させようとすると、
1.楕円の面積を計算する
2.文字数、基本フォントサイズによって配置場所、文字の大きさ、文字の方向を動的に変えて、楕円内にきれいに収める
3.楕円に入りきらない項目は指示線を出して、文字を出力する
を計算するアルゴリズムを考えなくてはいけません。
フォントの大きさ、画像の大きさ、円グラフの大きさ、文字数などの仕様が全く決まっていない状態で、このアルゴリズムを考えるのは至難の業です。

この時点で、べつやくさん風の手書きっぽい円グラフ作成は諦めました。


べつやくメソッドの素晴らしさを痛感

楕円の中に文字を収めるのが難しいのなら、円の外に文字を書こう!
そう方針転換して、円グラフを作ってみました。

その結果…
想像以上に見栄えの悪い円グラフができあがりました…
実際に円グラフを作ってみて、円の内側に文字があるか円の外側に文字があるかで、できあがった円グラフの見栄え、わかりやすさが全然違うものだとわかりました。
円グラフという表現方法が優れているのではなく、
べつやくれいさんが作った円グラフの出来映えが素晴らしい!
ということに、ようやく気付きました。

でも、このまま引き下がるのは面白くないので、表現方法を少し変えてみました。
「普通の円グラフがイマイチなら、3D円グラフにしてみよう!」と。


3D円グラフを作る上で捨てたもの-べつやくれいさんを崇拝して-

「べつやくれいさんの円グラフ」のすごさを実感したため、今まで一般的に使われてきた円グラフの表現方法はばっさり捨てました!
画像内に凡例って必要?
凡例が表示されるのは、むしろゴチャゴチャして邪魔!一目でわかりやすい円グラフを求めているのに、いちいち凡例の表示なんていらない!
項目のパーセント表示って必要?
パーセントが表示されるのは、むしろゴチャゴチャして邪魔!楕円内に文字を書けない以上、パーセントを書くスペースがもったいない。一目でわかりやすい円グラフを求めているのに、いちいちパーセントの表示なんていらない!
この2つを捨てたのは、かなり思い切った行動でした。
オプションとして残すこともできましたが、べつやくれいさんを崇拝する上で、見栄えを優先することに決めました。


3D円グラフを作る上で捨てたもの-GDライブラリ性能から-

試しにGDライブラリを使って円グラフを作成してわかったことは、
GDライブラリの円はあまりきれいじゃない
ということでした。
これは、「GDライブラリ」だからというよりは、ピクセルごとに処理している「ラスタ画像」全般の問題点です。
Flashなどで扱える「ベクタ画像」方式ならば、円をきれいに表示させることができ、拡大縮小にも強い画像が扱えます。
円グラフを作るならFlashで
ということに気付きました。
あまりきれいな3D円グラフが作成できないことを理解した上で、そのプライドを捨てて、PHP+GDライブラリで最後まで仕上げることにしました。


3D円グラフを作る上で捨てたもの-フォントで苦労して-

3D円グラフを作る上で、フォントの扱いは本当に苦労しました。
フォントだけでも以下の問題点がありました。
小さいフォントの見栄え
各種フォントの1フォントごとの幅
拡大縮小
文字の重なり
画像右端での文字の折り返し
作成した3D円グラフの回りに文字を出力すれば、長い文字の場合、そのまま右端に行って切れてしまいます。
自動で折り返してくれません。
最初、フォントの種類、フォントのサイズは、ユーザーが自由に選べる形式を考えていました。
ですが、その辺りのアルゴリズムを完璧に作り、ユーザーがいろいろ選べるようにする必要があるかというと、あまりない気がしました。
「超かんたん」のコンセプトの元、「5項目ぐらいの円グラフをブログに貼れるようなサイズの画像」であれば十分だと考えました。
もっと項目が多かったり、大きな画像を出力したい場合は、もっと他のツールを使うべきだと考えました。

そして、以下の項目をばっさり捨てました。
フォントの選択
フォントはTrueTypeフォントのkochi-gothic-subst.ttfに固定(サーバーに入っていたから)
フォントサイズの選択
10ピクセルに固定(これ以上大きいと、文字数が増えたときの見栄えが苦しくなる。小さくても汚い文字になる)
画像サイズの選択
360*240に固定(ブログに貼れるサイズとしてはこれくらいが妥当。画像が小さいのはGDライブラリ的に見栄えが苦しい)
色の選択
パステルカラー風のランダム色(「超かんたん」のコンセプトを考えると、#333333などと1項目ごとに打ち込んでもらうのはNG)
指示線の折り返し
指示線は一直線(文字の手前で少し角度を変えたいところでしたが…。文字の重なりやアルゴリズムなどで難しい面があるので搭載しませんでした。指示線自体はオプションとして残しましたが、見栄えはイマイチです)



生成画像のチューニング

フォント面での苦労から、
可変項目 → 固定項目
へと変化したものがたくさんありました。

これを生かして、固定項目に最適なパラメータをチューニングしていきました。
フォントと画像サイズを固定したことにより、見栄えの良い円グラフ作成がしやすくなりました。
文字の重なり、画像右端での文字の折り返しなども徹底的にチューニングしました。
固定サイズにしたことにより、いちいちアルゴリズムを考えなくても、最適なパラメータを与えるだけで、ある程度見栄えの良い3D円グラフが作成できるようになりました。

項目数が多すぎたりすると文字が重なってしまう問題がありますが、それはそもそもべつやくメソッド風の円グラフではありません。
項目数が多すぎれば、一目でわかりやすい円グラフにはなり得ないはずです。


円グラフの色の決定

円グラフの色について。
何となく「パステルカラー風」の色がランダムで決定されているように感じたかもしれませんが、あれには理由があります。
濃い色に文字が重なると、文字が見えなくなる!
すごく単純な理由です。
黒はもちろんのこと、青などでも文字が重なると文字が見えにくくなります。
文字の背景に色を付けてみる方法も考えましたが、ありえないくらいダサくなるのでやめました。
濃い色に重なった文字部分だけ色を変化させる方法も考えましたが、これはこれで見栄えが悪く、処理も面倒です。
濃い色を使うと文字が見えにくいのなら、薄い色だけを使えば良い
考え方を変えるだけで、簡単に解決できる問題です。
円グラフを作成した人にとっては、
「あっ、パステルカラー風の薄い色でできあがるんだ!」
と思ってもらえるかもしれません。
開発者側に何か言われても、「仕様です」の一言で終了できるようになりました。


複数項目のユーザー入力方法

円グラフを作りたい人は、それぞれ作りたい円グラフの項目数が違います。
複数項目の入力に関しては、以下の方法を考えました。
1.最初に項目数を入力してもらう
画面遷移後に項目数に応じた入力フォームが表示される
2.動的にフォーム数を変化させる
AjaxやFlashなどを用いる
3.カンマ区切りで入力してもらう
サーバー側で項目を分割
1は、「超かんたん」というコンセプトなのに、画面遷移が発生してしまいます。
2は、全てのブラウザに対応したAjaxを作るのが面倒です。また、ここでFlashを使うくらいなら、円グラフ自体もFlashで作成した方がきれいな画像が作れます。
3は、カンマ区切りの入力になれている人なら簡単でわかりやすくなります。複数項目にも簡単に対応できます。欠点は、PC初心者にとっては「カンマ区切り」がよくわからない可能性があるという点です。

この中から、今回は3番の「カンマ区切りで入力してもらう」を選びました。


画像キャッシュの問題でハマる

仕様がほぼ決まったところで、3D円グラフの生成・保存・出力のところまで辿り着きました。
最初、「3D円グラフ作成!」ボタンを押してもらう度に新規に画像を生成する方式にしていました。
途中で、円グラフの色を「ランダムで決まる」という方式に決めたため、生成する画像は項目名をキーにして画像を保存するように変更しました。(すでに同名の画像が存在する場合は上書き)

この変更がハマる原因となりました。

項目名が同じであれば、何度「3D円グラフ作成!」ボタンを押しても同名の3D円グラフ画像が表示されます。
サーバー側では、古い画像から新しい画像に作り替えられていますが、Webブラウザはそんなことを考慮してくれません。
「3D円グラフ作成!」ボタンを押しても、Webブラウザにキャッシュが残っていて、新しい画像が表示されなくなってしまいました。
「F5」ボタンを押して、再更新すれば新しい画像を表示させることができますが、「POST」で送信されたページを再更新すると、もう一度画像を生成し直すことになってしまいます。

そこで、
Webブラウザにキャッシュが残ってしまうのなら、強制的に画像をキャッシュさせなければ良い
ということで、Webブラウザに画像キャッシュを残させない方法を考えました。

httpd.confか.htaccessに画像ディレクトリを指定して、以下の記述をすればキャッシュされなくなります。
<FilesMatch "\.png$">
Header set Pragma no-cache
Header set Cache-Control no-cache
</FilesMatch>
これで、生成したPNG画像がキャッシュされなくなりました。

が、この設定が泥沼へと導いてくれました。

画像も表示されるようになったので、もう完成したと信じて、「超かんたん3D円グラフ作成!」の使い方ページなどを作っていたときに、問題点に気づきました。
生成したPNG画像を保存してみようとしたところ…
BMPでしか保存できない!!
右クリックで3D円グラフを保存しようとしても、BMPでしか保存できませんでした。

どうせ、インターネットエクスプローラのキャッシュが壊れたのだと思って、
IEのメニュー「ツール」→「インターネット オプション」→「インターネット一時ファイル」→「ファイルの削除」
をしました。
キャッシュが壊れてBMPでしか保存できなくなったことは何度かあるので、この操作には慣れています。
が、いくら「ファイルの削除」をしてもPNG画像で保存できるようにはなりませんでした…。
ブラウザの問題かと思って、Operaで試してみたところ、なぜかOperaでは保存できました。

どうして、IEではBMPでしか保存できないのかがわかりませんでした。
PNG画像を出力するときのヘッダーの問題なのかと思って、ヘッダーを出力してみたりもしましたがダメでした。
PNG画像が壊れているのかと思って、imagepngのページなども読んでみましたがわかりませんでした。

BMPでしか保存できないのなら、「ダウンロードした人が各自PNGに変換してください」と注意書きでも書こうかと思いましたが、「超かんたん」のコンセプトでは問題外の仕様です。
何より、PNG画像で4KB程度の画像がBMPでは約250KBになってしまうのが大問題です。

この問題にぶつかって、「イソプレスうぉっち、全記事に「べつやくメソッド」を導入」のエイプリルフールネタに対して、同日で作成ツールをリリースするという作戦が失敗に終わりました。

次の日、この問題をゆっくり調べてみたら、
Header set Pragma no-cache
Header set Cache-Control no-cache
などとしている場合は、キャッシュされないので、BMP画像でしか保存できない
ということがわかりました。
そんなIEの仕様は初めて知りました。

仕方なく、項目名をキーにして画像を保存する方法はやめて、毎回新規に画像を生成して、その画像を表示させる方法に戻しました。



3D円グラフを作る上で捨てたもの-サーバー、回線上の問題で-

実はこのサービスはPOST送信だけではなく、GETでも簡単に受け付けることができました。
現在は、負荷と転送量の問題などを考慮して、POSTのみ受け付けて、10分程度で画像が削除されるようにしています。
やろうと思えば、GETに対応させたり、APIとして公開することも可能です。
ですが、サーバー負荷と転送量を考慮してAPIとしては公開していません。
画像も自動的に削除されるようになっています。
もっとサーバーに余裕のある人は、Flashできれいな円グラフを作成して画像にするAPIなどを作ってください。



はてブコメント最新情報とのマッシュアップ

3D円グラフ画像が簡単に作れるようになったので、はてブコメント最新情報とマッシュアップしました。(→タグクラウドよりも、べつやくメソッド!参照)
わざわざ3D円グラフ画像を作成するツールを作ったわけですから、ついでに他のコンテンツとマッシュアップして、円グラフの活用方法を示してみました。

マッシュアップする上で、「もっと小さい画像で表示する」必要がありました。
3D円グラフ画像が大きすぎると、はてブコメント最新情報のレイアウトが損なわれてしまいます。
できあがった画像を縮小するだけでは、きれいなフォント表示が見込めません。
そこで、小さい画像用にもう一度パラメータを見直して、はてブコメント最新情報に組み込みました。
上位5タグの構成比率しか表示されないのも、グラフを見やすくするための仕様です。


はてなブックマークのコメントに対して

はてなブックマーク - 超かんたん3D円グラフ作成!にいくつかコメントが寄せられていました。
bunoum べつやくメソッドだ!,フォントいじれたらいいのに,もっとビビッドな色がいいな,でも簡単でうれしい!/40,35,20,5

eclucifer グラフ内に数値は表示出来ないのかな|指示線も見易く折れていると言うことないのだけど。

I11 簡単に作れるけど画像URLは短時間で消滅。ずっと画像が残れば使い道が広がるのになァ。はてなラボでつくってほしい。http://f.hatena.ne.jp/I11/20070403182213

kurokuragawa 早速使ってみた。 …微妙。もっと手書き風になるといいのに。
このページを読んでいただけると、なぜそういう仕様になったのか少しはわかってもらえると思います。

また、tamezou456さんが円グラフコミュニティサイト みんなのグラフ(verβ)というサイトを紹介してくれました。
円グラフがきれいですね。


最後に

なんだか予想以上に長文になってしまいましたが、言いたかったことは一つだけです。
開発の裏側ではけっこう悩んでいます
超かんたんにできあがっているかというと、実はそうでもなかったりしますので、心の片隅にでも覚えておいて下さい。


なお、開発しているときの気持ちは、こんな感じになっています。


今回、ところどころべつやくメソッドを用いて3D円グラフを置いてみましたが、
長文の中に円グラフがあると、円グラフしか見ない!
可能性が極めて高くなりますね。
円グラフは、それほど長くない文章に使ったり、効果的に見せたいところに使ったり、段落ごとに全て使ったりする必要があります。
使いどころを考えないと、肝心な文章が読まれない可能性を高くしてしまうことがわかりました。
(長文をやめて、簡潔に書く努力をしろということでもありますね)