2011年4月15日金曜日

icotileのロゴデザインをしました -icotile のどのあたりが HTML5 なのか? 番外編-

少し前に、icotile(http://icotile.ogaoga.org/)のロゴデザインやその他機能の実装等をやりました。おかげさまでicotile、「第 0 回 HTML5 プログラミング&クリエイティブ・コンテスト」にて優秀作品賞をいただきました
(って書くと作成し終わったかのようですが、icotile自体は今もまだアップデート続いてます)

icotileとは:
Twitter のフォローしている人/されている人やリストを iTunes のような操作感で管理でき、また各ユーザーに対して自分だけのメモも残せる Web アプリケーション。Developed by @ogaoga / Designed by @piyotori
ということですが、僕はCSS3まわりやビジュアル的なデザイン面以外でも普通にJavaScriptのロジック部分も書いたりしてますし、むしろogaogaさんが総合的な意味でデザインやってたりします。


さて、icotile企画者にてUI含めほとんどの部分を作ったogaogaさんが、「icotile のどのあたりが HTML5 なのか? #html5j」を書いてます。その中でCSS3まわりについては piyotori がそのうち書くでしょう、って振られてたのですが、なかなか書けずにいましたが、重い腰を上げて書くことにします。


が、CSS3じゃなくてまずはロゴデザインの話します (キリッ


まず最初に書いておきますが、僕はデザイナーを生業とするものではありません。普段はhtml5はもとよりデザインもWebも関係ないような仕事をしています。ので、そんな風にデザインやってんのかよ的なところ多々あると思いますが、ご容赦ください。

初めに。icotile一緒に作りましょうという話をogaogaさんからいただいのたのが今年1月中旬くらいで、html5コンテストは2/10締め切り。あまり期間がない(ある方か?)けれども、ロゴだけでもまずはなんとしてでも作らねば状態でした。が、Webサービスのコンセプトを聞いた後、さらにはロゴこんな感じと、既存フォントで作ったイメージも提供いただいたので、イメージを掴みやすかったです。

そのときいただいたロゴイメージ:


このイメージと、「icotile」という名前がそもそも「アイコンがタイル上に並ぶ」ことに由来していることから、I, C, O, T, I, L, Eのアルファベットを1文字ずつタイルに描かれた文字みたいに並べてロゴにしようと思いました。
で、iPadですらすらっとお絵描きしてみたのがこれ。
…と思ったらあれ?画像がない。だいぶ前に消しちゃったっぽい。
すいません。
なかったことにして話を進めますが、ラフな絵を描いた段階で頭の中では、タイルの1辺を a pxとして、文字の幅は a/4 pxで、カッチリ計算したフォントみたいなの作ろうと思ってました。


で、計算により描画する、ということで、はいここでhtml5のcanvasです。強引。


っつーわけで僕は canvas 使って ロゴに使う1文字ずつの画像を作成することにしました。

まず正方形のcanvas を用意し、1辺のpxを指定して、そこからすべて計算により図形を描画して文字を作っていきます。
簡単な I を例にすると、仮に1辺が120pxだとして、下図のような、緑の点を基点とした、横幅が 120/4 = 30、高さが120 の長方形描けばいいのです。


緑の点の座標は、まずXは、canvasのセンターが120 / 2 = 60なので、そこから文字幅 120 / 4 = 30をさらに 2 で割った値をマイナスしてあげた、X=45、Yはcanvasの一番上なので0、となります。

JavaScriptはこんな感じ。
    var cnvs = document.createElement("canvas");
cnvs.width = 120;
cnvs.height = 120;
cnvs.id = "id_cnvs_I"
$("body").append(cnvs);

var ctx = document.getElementById("id_cnvs_I").getContext('2d');
ctx.fillStyle = "black";
ctx.fillRect(45, 0, 30, 120);

これで、120x120のcanvasの真ん中に棒が一本みたいなのができます。

でもこれだとカッチリカクカクな棒なので、角丸になるように、半径 r の円弧を使って角丸boxを書く関数を用意します。これはこちらの記事を参考にさせていただきました。

[javascript]canvasで円や角丸の矩形を描画する - 週末ラボ

これでこんな「I」の文字ができます(外枠は本当はありません)。


この文字を一回り大きいサイズの角丸四角で囲みたくなります。「タイル」をイメージするんで。

しかし。僕自身このエントリで書いてるようにロゴ文字を作っていったので、さて外枠描画しようかなってときに、canvasサイズ小さいじゃん!ってなりました。まあいろいろな対応が考えられますが、とりあえずcanvasをひとまわり大きいサイズにするにはしますが、こんな手順で外枠付けました。

0.例では120x120のcanvasだったが128x128のcanvasを最初に用意することにする(外枠マージン上下左右4pxずつ)
1.外枠のマージン分canvasを移動させて文字を描画する
2.canvasを大きくする前と同じままのコードで文字を描画する
3.外枠のマージン分移動したcanvasを元に戻す
4.外枠描く

「canvasの移動」には translate を使います。translateはちょっと混乱しますが、画用紙にひたすら同じ図形を描いているロボットアームがあったとして、画用紙をずらしたらずれた位置に同じ図形描きますよねってのをイメージしていただくとよいかと思います。
実際に I を描いてさらに外枠付けるコードはこんな感じです。
    var cnvs = document.createElement("canvas");
cnvs.width = 128;
cnvs.height = 128;
cnvs.id = "id_cnvs_1"
$("#font_draw_area").append(cnvs);

var ctx = document.getElementById("id_cnvs_1").getContext('2d');
ctx.fillStyle = "black";

pi = Math.PI;
/* 角丸boxパス作成 */
var makeRoundRectPath = function(ctx, x, y, w, h, r){
ctx.beginPath();
ctx.arc(x + r, y + r, r, - pi, - 0.5 * pi, false);
ctx.arc(x + w - r, y + r, r, - 0.5 * pi, 0, false);
ctx.arc(x + w - r, y + h - r, r, 0, 0.5 * pi, false);
ctx.arc(x + r, y + h - r, r, 0.5 * pi, pi, false);
ctx.closePath();
}

/* 文字描画 */
ctx.translate(4, 4); /* canvas移動 */
makeRoundRectPath(ctx, (120 / 2) - (30 / 2), 0, 30, 120, 6);
ctx.fill();
ctx.translate(-4, -4); /* canvas移動戻す */

/* 外枠描画 */
ctx.strokeStyle = "black";
makeRoundRectPath(ctx, 0, 0, 128, 128, 6);
ctx.stroke();

/* 画像オブジェクトに */
var imgObj = new Image(128, 128);
var imgSrcData = document.getElementById("id_cnvs_1").toDataURL("image/png");
imgObj.src = imgSrcData;
$("body").append(imgObj);
$("#id_cnvs_1").remove();
最後の方が妙なことやってますが、後で説明します。
これで、以下のような I の画像ができあがります。


今回説明する都合上単純化しており外枠はstrokeで済ませました。でも実際にはroundRectをさらに改造したもの、を組み合わせて、外枠描画するようにしてます。


「I」は簡単でしたが「T」はどうでしょうか。

まず横棒(X=0, Y=0, W=120, H=30の長方形)と縦棒(X=45, Y=0, W=30,
H=120の長方形)を描画します。(わざと半透明色にしてます)


これでもいいのですが、Tの「脇」が気になります。以下の赤いところ。


今回はここも丸みを持たせるデザインにしようと思います。そこで、角丸boxの外側を描画する関数を用意します。下図のようなイメージで、指定した領域(うす緑)の4つの角を描画するものです。


実際には、どこの角を塗るか指定するMaskもつけて、こんな感じの作りました。

/* 角丸Outerパス作成 */
// mask: bit3=lefttop, bit2=righttop, bit1=rightbottom, bit0=leftbottom
function makeRoundRectOuterPath(ctx, x, y, w, h, r, mask){
ctx.beginPath();
if(mask & 0x08){
ctx.moveTo(x, y);
ctx.arc(x + r, y + r, r, - pi, - 0.5 * pi, false);
ctx.lineTo(x, y);
ctx.lineTo(x, y + r);
}

if(mask & 0x04){
ctx.moveTo(x + w - r, y);
ctx.arc(x + w - r, y + r, r, - 0.5 * pi, 0, false);
ctx.lineTo(x + w, y);
ctx.lineTo(x + w - r, y);
}

if(mask & 0x02){
ctx.moveTo(x + w, y + h - r);
ctx.arc(x + w - r, y + h - r, r, 0, 0.5 * pi, false);
ctx.lineTo(x + w, y + h);
ctx.lineTo(x + w, y + h - r);
}

if(mask & 0x01){
ctx.moveTo(x + r, y + h);
ctx.arc(x + r, y + h - r, r, 0.5 * pi, pi, false);
ctx.lineTo(x, y + h);
ctx.lineTo(x + r, y + h);
}
ctx.closePath();
}
これで両脇を丸くしてやってTができます(外枠付与前)。



こんな感じで残りの、C、O、L、Eも一文字ずつちまちまと計算しながらデザインしました。
Eは、真ん中の横棒を浮かせるか根元に付けるか試して、最終的には浮かせることにしました。




さて、こんな風にすべてcanvasで描画できるのなら、そのままサイトに組み込んでしまえ、と最初はやりました。
canvasそのまま組み込んでもいいのですが、canvas上の描画された絵をimageとして使いたいので、「I」の字描画コードの最後でしてたようなことをやります。

しかし、ロゴというなるべく早く読み込まれて然るべきもの(と思う)をこんな処理してるのもどうかと思ったので、そうやって作った画像を名前をつけて保存してサーバにアップして画像として最初から読み込むようになってます。


こうして1文字ずつの画像はできましたが、今のicotileのsign in後に右上に出てるロゴなんかは、7文字繋がった1枚の画像になってます。
それもcanvas利用して作成してます。
 1.文字の画像をcanvasで描画
 2.image objectに
 3.横長canvasに2のobjectを適切な座標に読み込む
 4.1~3を ICOTILE ぶん繰り返す
 5.横長canvasを image object にして 最後はブラウザ上から「名前を付けて保存」
で、作ってます。

実際のものとは違いますが、たとえば上で作成した「I」の字を128pxじゃなくて36px版にして、7文字連結するコードはこうなります。
    var cnvs = document.createElement("canvas");
cnvs.width = 36;
cnvs.height = 36;
$("body").append(cnvs);

var ctx = cnvs.getContext('2d');

pi = Math.PI;
/* 角丸boxパス作成 */
var makeRoundRectPath = function(ctx, x, y, w, h, r){
ctx.beginPath();
ctx.arc(x + r, y + r, r, - pi, - 0.5 * pi, false);
ctx.arc(x + w - r, y + r, r, - 0.5 * pi, 0, false);
ctx.arc(x + w - r, y + h - r, r, 0, 0.5 * pi, false);
ctx.arc(x + r, y + h - r, r, 0.5 * pi, pi, false);
ctx.closePath();
}

/* 文字描画 */
ctx.translate(2, 2); /* canvas移動 */
makeRoundRectPath(ctx, 12, 0, 8, 32, 2);
ctx.fill();
ctx.translate(-2, -2); /* canvas移動戻す */

/* 外枠描画 */
ctx.strokeStyle = "black";
ctx.lineWidth = 1;
makeRoundRectPath(ctx, 0, 0, 36, 36, 4);
ctx.stroke();

/* 画像オブジェクトに */
var imgObj = new Image(36, 36);
var imgSrcData = cnvs.toDataURL("image/png");
imgObj.src = imgSrcData;
$("body").append(imgObj);
$(cnvs).remove();

/* 横長canvas */
var cnvs = document.createElement("canvas");
cnvs.width = (36 * 7) + 6;
cnvs.height = 36;
$("body").append(cnvs);

ctx = cnvs.getContext('2d');

/* imageをcanvas上の指定位置に読み込む x 7回 */
for(var i = 0; i < 7; i++){
var x = (36 + 1) * i;
var y = 0;
ctx.drawImage(imgObj, x, y);
}
$(imgObj).remove();

/* 画像オブジェクトに */
var imgObj = new Image((36 * 7) + 6, 36);
var imgSrcData = cnvs.toDataURL("image/png");
imgObj.src = imgSrcData;
$("body").append(imgObj);
$(cnvs).remove();
これで258x36の右クリック保存可能なlogo画像ができました。


だいたいこのようにしてicotileの(sign in後の)ロゴ画像は作られました。
実際には、タイルの1辺のサイズを指定すればあとは各文字の描画位置を比率で計算してすべて描画されるようにスクリプトは書いています。
※canvas上に描く図形の座標がキリがいい数字になる(ことが多くなる)ように設計されてないと、意に反したクオリティの画像になる場合があります。

(sign in前のページのロゴ(Tの字がくるくるするやつ)の話は、またicotileのどこがhtml5か -CSS3アニメ編-としてでも書こうと思います)



まあ何面倒なことやってんだってことでもあるのですが、開発段階ではcanvasそのまんまでサイトに組み込んでみることで、文字の色とかサイズとか微調整だとかやりながら、デザインも行えてしまうという、(若干こじつけの)メリットがあります。
また、ブラウザとテキストエディタがあればデザインが行えるというメリットもあります。イラレやフォトショなどなくてもいいのです。

というわけで、「icotile のどのあたりが HTML5 なのか?」の番外編として、ロゴデザインワークが実はcanvasにて行われていた、というお話でした。


番外編な上にさらに番外:
勢い余って、ICOTILEフォントっぽいもの、作りました。すべての文字のための関数用意するのは時間かかりました。
そして案の定、使いどころないです。

0 件のコメント: