フキダシセットの作成

フキダシに必要なデータをまとめたものをフキダシセットと言います。管理者がフキダシセットをインポートすると、使えるフキダシを増やせます。通常フキダシセットは配布サイトから入手しますが、希望のフキダシが入手できない場合、自作することになります。

参照:AboutSpeechBalloon SpeechBalloonTemplateModel NewSpeechBalloon ClientBalloonEditor( 吹き出し編集時の UI について )

フキダシセットの構成

フキダシセットは次のファイルで構成されています。

  • 説明書(ReadMe.txt)
  • ベクターコード(xxx_.js)
  • テンプレート(xxx.json)

ベクターコードは含まれていないこともあります。

以降は古くてデタラメ

テンプレートの作り方

テンプレートがわからないなら、こちら→AboutSpeechBalloon

テンプレートは次のモデルで構成される。

これらが階層構造でjson記述されています。

早い話がこんなカンジ。

xxx.json

  1. {
  2. "name": "hoge", "caption": "ほげ", ...
  3. "balloon_template_attributes": {
  4. ...
  5. },
  6. "speech_template_attributes": {
  7. ...
  8. }
  9. }
複数のテンプレートを一つのファイルにまとめて(配列として列挙)記述できます。

簡単な例

シンプルな例として長方形フキダシを考えてみます。

square1.PNG

このフキダシは次の2つの部品でできています。

フキダシ画像imgタグ+テキストpタグ=長方形フキダシ
squarev2.PNG+square3.PNG=square1.PNG

フキダシ画像をimgタグで表示し、そこにpタグなどのテキスト系タグを重ね合わせたのが画像フキダシです。コマエディタでサイズをいじる行為はwidthやheight属性を増減させることで表現できます。つまり、フキダシテンプレートは画像を使ったhtml表現です。

では、このフキダシにsquareという名前をつけてテンプレートを作成しましょう。

まずはフキダシのデフォルトサイズを決めておかなければなりません。このフキダシはエディタでコマに添付されたとき、どの程度の大きさであれば良いでしょうか?これは常識的には使いやすいサイズをデフォルトにしておけば間違いはないですが、ここでは画像サイズに合わせて幅170px高さ100pxとしておきます。

これでフキダシテンプレートは完成です。

namecaptiondefault_widthdefault_height
square長方形170100

次にフキダシ枠テンプレートを作成します。

フキダシ枠はフキダシ画像そのものです。フキダシ画像はシステムの共通財産なので、システム画像として管理します。フキダシ枠テンプレートは、フキダシテンプレートとシステム画像をリンクさせるデータです。当然ながらフキダシ画像はシステム画像としてアップロードされているとします。

squarev2.PNG

フキダシ枠テンプレートはフキダシ画像のidを指定します。画像のidが2とすると、次のように完成されます。

system_picture_id
2

※idではなく、画像データを入れればシステム画像を作成しつつフキダシテンプレートを作成できます。このとき画像データはBase64でエンコードしておかなければなりません。

最後にセリフテンプレートを作成します。

セリフテンプレートでは、いくつかの座標あるいは比率を設定します。これは、ある程度マージンを取らないとテキストが画像の枠と被ってしまうので重ならないようにするためのデータです。長方形だと影響は小さく見えますが、円形になると如実に差が出ます。

ピクセル数・比率どちらでも使えますが、両者ともに設定した場合はピクセル指定が優先されます。今回は比率で上下左右10%のマージンを指定しておきます。

x_ratey_ratewidth_rateheight_rate
10108080

これでsquareテンプレートは完成です。

square.json

  1. {
  2. "name": "square",
  3. "caption": "長方形",
  4. "default_width": 170,
  5. "default_height": 100,
  6. "balloon_template_attributes": {
  7. "new": {
  8. "system_picture_id": 2
  9. }
  10. },
  11. "speech_template_attributes": {
  12. "new": {
  13. "x_rate": 10,
  14. "y_rate": 10,
  15. "width_rate": 80,
  16. "height_rate": 80
  17. }
  18. }
  19. }

ベクターフキダシの作り方

画像フキダシはimgタグで表示された画像を使ってフキダシを表現しました。それに対してベクターフキダシはhtml5やcss3などを駆使してJavaScriptで描画する形で表現します。画像を使わず描画するので、画像のような伸縮劣化しません。描画にはプログラムが必要です。そのプログラムをベクターコードと呼ぶことにします。

先ほどのsquareテンプレートをベクターで表現するには、divタグでborder属性を指定するのが簡単でしょう。

画像フキダシとベクターフキダシの互換

ベクターフキダシはJavaScriptで動きます。JavaScriptが動かない環境では、ベクターフキダシはまったく機能しません。そのために、ベクターフキダシには、常に互換性のあるフキダシテンプレートを用意しなければなりません。よって、ベクターフキダシを作るときは、必ずフキダシテンプレートのことも留意しながら進めなければなりません。

一方、テンプレートフキダシはベクターコードを用意しなくても動きます。とはいえ、優れたフキダシであれば、いずれベクター化されるかもしれず、長期的に見ればベクター化できそうな構造に落としこんだ方が良いでしょう。

フキダシテンプレートの要素拡張

要素拡張(サイズの追加)

問題

先ほどの例で、squareテンプレートは完成しました。長方形のフキダシを自由に操れます。しかし、今のままでは弱点があります。このフキダシを極端に扁平させてみましょう。

square4.PNG

縦と横で線の太さが大きく違います。画像を使ったフキダシでは拡大縮小時に扁平の影響を避けられません。拡大率が大きくなるほど画像は粗くなり、小さくなるほど線がかすれます。

対策の検討

そこで、フキダシのサイズを数種類用意します。大中小三つの画像をフキダシサイズに応じて使い分ける作戦です。

小(100x50)
square11.png
中(300x150)
square12.png
大(500x250)
square13.png

幅が0~200なら小を拡縮し、200~400なら中を拡縮し、400以上なら大を拡縮します。同様に、高さが0~100なら小を拡縮し、100~200なら中を拡縮し、200以上なら大を拡縮します。

こうやって最適な画像を選べば、幾分かは問題が解消するはずです。

実装への落とし込み

しかし、今のデータ構造では画像の使い分けはできません。問題が二点あります。

  • フキダシテンプレートとフキダシ枠テンプレートが一対一の関係
    • フキダシ枠テンプレートには画像が一つしか指定できない
  • 判断材料の不足
    • 最適なサイズを求めるための数値が保存できない

前者はフキダシ枠テンプレートにユニークキーの第二カラムを追加し、後者はフキダシテンプレートに状況判断できるようなカラムを追加します。

フキダシ枠テンプレートの拡張

まずフキダシ枠画像を複数化するために、フキダシ枠テンプレートにカラムを追加します。

フキダシ枠テンプレート

name和名typedefaultnulllimitnote
sizeサイズのバリエーションinteger0FALSE 0~

テーブル全体のカラムは、こうなります。

name和名typedefaultnulllimitnote
speech_balloon_template_idフキダシテンプレートidinteger FALSE
sizeサイズのバリエーションinteger0FALSE 0~
system_picture_idフキダシ素材idinteger FALSE

これでフキダシ画像をサーチするためのキーがspeech_balloon_template_idとsizeの2つになり、一対多の関係になりました。squareに従属するフキダシ枠テンプレートは、size:0(小)ならid:2の画像、size:1(中)ならid:3の画像…のように管理できるようなりました。データにすると、こうなります。

sizesystem_picture_id
02
13
24

※もちろんフキダシ画像は、システム画像としてアップロードされていなければなりません。

フキダシテンプレートの拡張

さらにフキダシテンプレートに下記のカラムを追加します。

フキダシテンプレート

name和名typedefaultnulllimitnote
size_countサイズのバリエーションの数integer1FALSE
width_stepサイズが変わる幅integer0FALSE 0のとき切り替えしない
height_stepサイズが変わる高さinteger0FALSE 0のとき切り替えしない

これらの情報から、フキダシ画像が何枚あるか、どんな大きさのフキダシ画像があるか、を知ることができ、フキダシ(BalloonModel)のサイズから使うべき画像を逆算できるようになります。

データにすると、こうなります。

namecaptiondefault_widthdefault_heightsize_countwidth_stepheight_step
square長方形1501003200100

逆算にはプログラムが必要です。算出はコマの投稿時にフキダシテンプレート(SpeechBalloonTemplateModel)に対して、拡張要素名+_indexを呼ぶ形で発生します。この処理がフキダシ(BalloonModel)のサイズから、最も相応しい画像を算出するとしてください。今回のsquare例ではこんな感じです。

models/speech_balloon_template.rb

  1. def square_index balloon
  2. ...
  3. end

今回用意した画像は、小(100x50)、中(300x150)、大(500x250)です。これは幅が0~200なら小を拡縮し、200~400なら中を拡縮し、400以上なら大を拡縮するんでした。つまり、幅200高さ100ずつ大きくなる画像を3枚用意したことになります。逆から見れば、このような一定の法則で算出できるようにフキダシ画像を作成したということです。突っ込んだ説明をするなら、それらの画像が最も効率良く拡縮できるように、小は幅100(0~200=100を中心に±100)、中は幅300(200~400=100を中心に±100)、大は幅500(400~=100を中心に±100)としたわけです。

コードにすると、こんな感じ。square_indexがballoonをもらって、sizeが0~2のうち、最適なものがどれかを返します。なお、幅と高さのsizeに相違があるときは、大きい方が選ばれます。

models/speech_balloon_template.rb

  1. def square_index balloon
  2. w = balloon.width / self.width_step
  3. h = balloon.height / self.height_step
  4. w = self.size_count - 1 if w >= self.size_count
  5. h = self.size_count - 1 if h >= self.size_count
  6. w > h ? w : h
  7. end

サイズ要素を拡張したsquareテンプレートは、こうなります。

square.json

  1. {
  2. "name": "square",
  3. "caption": "長方形",
  4. "default_width": 150,
  5. "default_height": 100,
  6. "size_count": 3,
  7. "width_step": 200,
  8. "height_step": 100,
  9. "balloon_template_attributes": {
  10. "small": {
  11. "size": 0,
  12. "system_picture_id": 2
  13. },
  14. "middle": {
  15. "size": 1,
  16. "system_picture_id": 3
  17. },
  18. "large": {
  19. "size": 2,
  20. "system_picture_id": 4
  21. }
  22. },
  23. "speech_template_attributes": {
  24. "new": {
  25. "x_rate": 10,
  26. "y_rate": 10,
  27. "width_rate": 80,
  28. "height_rate": 80
  29. }
  30. }
  31. }

もう少し考える

扁平対策は終わりました。しかし、この際ですから、もう少し考えましょう。サイズの切り替え間隔が倍率だけしか指定できないと、何かと画像を作りづらいです。こういうのはy=ax+bな感じで倍率の他にオフセット値があった方が柔軟に指定できます。

同じ長方形テンプレートでも、用意した画像がこんな感じだったら、どうでしょう。

小(170x100)
square11.png
中(235x150)
square6.png
大(340x250)
square5.png

幅が0~200なら小を拡縮し、200~400なら中を拡縮し、400以上なら大を拡縮します。同様に、高さが0~100なら小を拡縮し、100~200なら中を拡縮し、200以上なら大を拡縮します。

フキダシテンプレート

name和名typedefaultnulllimitnote
width_offset最小サイズ画像の幅integer0FALSE
height_offset最小サイズ画像の高さinteger0FALSE

幅170高さ100を基本として

namecaptiondefault_widthdefault_heightsize_countwidth_offsety_offsetwidth_stepheight_step
square長方形17010031701008550

サイズ要素を拡張したsquareテンプレートは、こうなります。

square.json

  1. {
  2. "name": "square",
  3. "caption": "長方形",
  4. "default_width": 170,
  5. "default_height": 100,
  6. "size_count": 3,
  7. "width_offset": 170,
  8. "height_offset": 100,
  9. "width_step": 85,
  10. "height_step": 50,
  11. "balloon_template_attributes": {
  12. "small": {
  13. "size": 0,
  14. "system_picture_id": 2
  15. },
  16. "middle": {
  17. "size": 1,
  18. "system_picture_id": 3
  19. },
  20. "large": {
  21. "size": 2,
  22. "system_picture_id": 4
  23. }
  24. },
  25. "speech_template_attributes": {
  26. "new": {
  27. "x_rate": 10,
  28. "y_rate": 10,
  29. "width_rate": 80,
  30. "height_rate": 80
  31. }
  32. }
  33. }

デフォルト値

扁平の影響を無視できるフキダシであれば、扁平対策に関するデータを作らなくても済むようにしてあるべきです。今回追加したカラムは、次でした。

フキダシ枠テンプレート

name和名typedefaultnulllimitnote
sizeサイズのバリエーションinteger0FALSE 0~

デフォルト値をゼロにしておきます。

フキダシテンプレート

name和名typedefaultnulllimitnote
size_countサイズのバリエーションの数integer1FALSE
width_stepサイズが変わる幅integer0FALSE 0のとき切り替えしない
height_stepサイズが変わる高さinteger0FALSE 0のとき切り替えしない
width_offset最小サイズ画像の幅integer0FALSE
height_offset最小サイズ画像の高さinteger0FALSE

size_countは、最低限の1種類で1にしておきます。

さらにwidth_stepとheight_stepは0にしておきます。

要素拡張(尻尾の追加)

次に要素拡張を使ってフキダシに尻尾を追加します。尻尾とは、発言者の口元に向かって伸びるフキダシ口のことです。

circle3.png

フキダシ口は、様々な角度で出ますから、当然一枚では足りません。360枚あれば360度一回転に対応できますが、画像が多すぎると管理が大変なので、ここでは4枚用意します。名前はcircle(円形)とでもしましょうか。

右上45度circle3.png
右下135度circle4.png
左下225度circle1.PNG
左上315度circle2.png

フキダシテンプレート

namecaptiondefault_widthdefault_height
circle円形170100

ここに尻尾の要素tailを追加します。 まずフキダシ枠画像を複数化するために、フキダシ枠テンプレートにカラムを追加します。

フキダシ枠テンプレート

name和名typedefaultnulllimitnote
tail尻尾のバリエーションinteger0FALSE 0~

テーブル全体のカラムは、こうなります。

name和名typedefaultnulllimitnote
speech_balloon_template_idフキダシテンプレートidinteger FALSE
tail尻尾のバリエーションinteger0FALSE 0~
system_picture_idフキダシ素材idinteger FALSE
created_atdatetime
updated_atdatetime

これでフキダシテンプレートcircleに関するフキダシ枠テンプレートは、tail:0(右上)はid:6の画像、tail:1(右下)はid:7の画像…のように管理できます。もちろんフキダシ画像は、システム画像としてアップロードされていなければなりません。データにすると、こうなります。

tailsystem_picture_id
06
17
28
39

さらにフキダシテンプレートに下記のカラムを追加します。

フキダシテンプレート

name和名typedefaultnulllimitnote
r_offset尻尾の向きinteger0FALSE
r_step尻尾の向きが変わる角度integer360FALSE

これらの情報から、どんな向きのフキダシ画像があるかを知ることができ、角度から使うべき画像を逆算できるようになります。逆算にはプログラムが必要ですが、ここはテンプレート作成の段階ですから、詳しくは触れません。フキダシテンプレートには、(コマの上の)尻尾の向きから、最も相応しい画像を算出する機能が備わっているとしてください。

今回用意した画像は、小(170x100)、中(255x150)、大(340x200)です。これは幅170高さ100を基本として幅85高さ50ずつ大きくなる画像を3枚用意したことになります。逆から見れば、このような一定の法則で算出できるようにフキダシ画像を作成したということです。データにすると、こうなります。

namecaptiondefault_widthdefault_heightsize_countx_offsety_offsetwidth_stepheight_step
square長方形17010031701008550

サイズ要素を拡張したsquareテンプレートは、こうなります。

  1. {
  2. "name": "square",
  3. "caption": "長方形",
  4. "system_picture_id": 1,
  5. "default_width": 170,
  6. "default_height": 100,
  7. "size_count": 3,
  8. "x_offset": 170,
  9. "y_offset": 100,
  10. "width_step": 85,
  11. "height_step": 50,
  12. "balloon_template_attributes": {
  13. "small": {
  14. "size": 0,
  15. "system_picture_id": 2
  16. },
  17. "middle": {
  18. "size": 1,
  19. "system_picture_id": 3
  20. },
  21. "large": {
  22. "size": 2,
  23. "system_picture_id": 4
  24. }
  25. },
  26. "speech_template_attributes": {
  27. "new": {
  28. "x_rate": 10,
  29. "y_rate": 10,
  30. "width_rate": 80,
  31. "height_rate": 80
  32. }
  33. }
  34. }

  • フキダシテンプレートとは、フキダシを統括するデータです。SpeechBalloonTemplate
  • フキダシ枠テンプレートとは、フキダシ画像を管理するデータで、画像の使い分けを定義します。
      • 同じフキダシでも条件によって違う画像を使いたいケースがある。
      • この条件のときはこの絵を使えと指定できる。
      • 例えば、フキダシ口(尻尾)がどちらを向いているか。
      • 角度が0のときは右側に、180のときは左側に、といった具合。
      • 条件やパラメータはいろいろある。
  • セリフテンプレートとは、テキスト表示を管理するデータです。
    • テキストはフキダシ画像の上に重ねて表示される。
    • フキダシの枠線に重ならないよう、内側に表示する必要がある。
    • そのためのxyオフセット値と幅高さを定義する。
    • システム画像もidでリンクしていなければならない。
    • よって、これらを同時に作成できなければならない。

尻尾の向きについて

  • 尻尾の向きは度で表す。
  • 画面に向かって上が0度。
  • 時計回りで増加。
    • 右の頂点が90度。
    • 左の頂点が270度。
    • 負で表すこともできる。
    • 360度で0度に戻る。
  • ただし、上向きからしか始まれないのは残念なのでオフセット値を与えられる。
    • r_offsetがそれ。
    • エディタでのデフォルト値。
      • コマエディタでフキダシがパネルに貼られたときは、必ずその角度で貼られなければならない。
  • r_step
    • 画像フキダシだと決まった角度のフキダシしか用意できない。
    • 用意した画像が何度ごとに尻尾がついているかを指定する。
    • 例えば、これが60のとき、0、60、120、180、240、300の6つの角度に尻尾が向いた画像が用意されているということ。
    • 当たり前だが、360を割り切れる数でないとダメ。
    • 画像フキダシだとrがこれらのうちから最も近い角度に丸められる。
    • 先ほどの例だと、50度のときは60度版の画像が使用される。
    • r_offsetも、これらの角度に一致してないとダメ。
    • エディタではこの角度がわかるよう表示する必要がある。