tsmallfield's diary

たぶんJavaScriptのお話

SVGを作ってみよう

普通のサイトだとあまり使い道がないと思われがちな SVG。。。

でも場合によっては PNG や JPG よりも便利な場合もあるんです!

最近の案件でもバリバリ使ってます!

 

そんなわけで今回はSVG のつくり方を簡単にご紹介します。

 

まず、イラレで適当に図形を作ります。

f:id:tsmallfield:20140120210112p:plain

 

そして command + shift + s で別名保存。

 

f:id:tsmallfield:20140120210155p:plain

 

ファイル形式を svg にするのを忘れずに!

ファイル名を決めたら save ボタンを押して。。。

 

f:id:tsmallfield:20140120210402p:plain

 

なにやら画面が出ますが気にせず OK を押しましょう。

 

はい、おしまい。

 

作成した svgイラレで編集してもよいですし、

テキストエディタで編集してもよいでしょう。

 

ちなみにテキストエディタで開くとこんな感じ。

f:id:tsmallfield:20140120213135p:plain

 

fill や stroke、stroke-width 等、属性をいろいろ追加&編集して遊んでみましょう!

ちなみにJavaScriptを使って属性を動的に変更すれば、こんなことも。。。

 

次回は SVG の(htmlでの)表示方法について書いてみます。。。

OGP画像の見え方を簡単操作でシミュレート!

デザイナーのみなさんはOGP画像をデザインする機会がたくさんあると思います。
でもFacebookだと、OGP画像が正方形で表示されたり横長で表示されたりで、
レイアウトが大変ですよね。。。

 

そんな時に便利なのがこちら!!

 

og:image Simulator
http://ogimage.tsmallfield.com/

f:id:tsmallfield:20140108014350p:plain

 

作成したOGP画像が、Facebookのタイムライン上でどのように表示されるかを、
簡単操作でシミュレートできるWEBアプリです。

 

使い方はとっても簡単!
画像をブラウザにドラッグ&ドロップするだけ。

f:id:tsmallfield:20140108015154p:plain

正方形の場合と、横長の場合とでどのように表示されるかプレビューできます!

 

また、裏ワザ的な使い方として、
Facebookhttp://ogimage.tsmallfield.com/ をシェアする際に

f:id:tsmallfield:20140108015935p:plain

赤丸のボタン(複数のOGP画像の中から選ぶボタン)を操作することで
いろんな縦横比の画像がどのように切り取られて表示されるかを
検討することも可能です。

 

なお、現在用意しているのは

・630 x 630
・1200 x 630 (Facebook 推奨)
・1200 x 1200

の3つ。(今後増やす可能性あり)

 

OGP画像をデザインする際は
ぜひぜひ使ってみてくださいー

簡易的なBoneアニメーションを作ってみよう

Boneアニメーションと聞くとなんだか難しそうだし
しかもそれをJavaScriptでやるなんて。。。

でも簡易的なものならなんとかなるかも!

というわけで今回は最近制作したBoneアニメーションのサンプルをご紹介します。

まずはBoneを描いてみよう

まずは<canvas>の
translate(), rotate(), moveTo(), lineTo(), stroke()
を駆使して簡単な人型のBoneを描画してみます。

ここまではとっても簡単。
さて、このBoneを歩かせるには、どうすればよいでしょう?

関節を動かすには?

とりあえず、rotate() に指定している角度を動的に変化させれば良さそうです。

でも関節の角度を一つ一つ指定し、
しかもちゃんと歩いている風に調整するのはすごい作業になりそうなので
根元の関節の角度を一つ指定したら、それが先端まで伝搬していく作りにしましょう。

そのためにはBoneが親子関係を持っている必要があります。
例えば「体」の子が「腕」でその子が「手」、という感じです。

さらに親のBoneから子のBoneに角度が伝搬する際、
それぞれに係数を掛けるとよさそうです。
例えば、肩の関節を10度動かしたら、肘の関節も10度動かすのではなく、
10 に 係数 -0.5 を掛けた値、すなわち 10 * -0.5 = -5 度動かす。。。
という具合です。

関節の角度はどうやって計算する?

歩くという動作は周期的(ある一定の動きを繰り返す)なもの。
周期的な関数と聞いてまず思い浮かぶのは 正弦波:Math.sin(), Math.cos() です。
今回はこれをうまく利用しましょう。

【横軸】を歩いた距離、
【縦軸】を関節の角度
とすればいい感じになりそうですね。

体の上下の動きもわすれずに!

人が歩いている時、体は上下に動いているので
それも関節の角度と同じく sin, cos で計算しましょう。
上下の動きは、腕や足のそれと周期が違うので注意しましょう。

サンプル

各関節の角度、係数、角度変化の周期を地道に調整し、歩いている風にしてみました。

Boneの定義をしている部分は以下になります。

this.skeleton = new Skeleton([
    new Bone('body', 150, -80, .2, [
        new Bone('head', 50, 20, 1),
        new Bone('leftArm', 90, 190, -4, [
            new Bone('leftArm2', 80, -50, 1)
        ]),
        new Bone('rightArm', 90, 190, 4, [
            new Bone('rightArm2', 80, -50, 1)
        ])
    ]),
    new Bone('leftLeg', 100, 70, -1, [
        new Bone('leftLeg2', 100, 40, 1, [
            new Bone('leftFoot', 30, -110, .1)
        ])
    ]),
    new Bone('rightLeg', 100, 70, 1, [
        new Bone('rightLeg2', 100, 40, 1, [
            new Bone('rightFoot', 30, -110, .1)
        ])
    ])
]);
new Bone(ラベル, Boneの長さ, デフォルトの関節角, 係数[, 子のBoneの配列]);

Boneの長さとデフォルトの関節角で姿勢を変えることができます。

また係数を変更することで回転方向と俊敏さを調整できます。

以下は関節角を計算している部分のコードです。
移動距離から sin, cos を用いて関節角(の差分)を計算しています。

※目標角ではなく差分を与えているのは、歩く以外の動作を同時に行えるようにするためです。
例えば、吠えるとか口から熱線を出すとか。

/**
 *  @param {number} distance
 */
function update(distance) {
    var OFFSET_Y_MAX   = -10,
        ROTATION_PHASE = 200,
        ROTATION_GAIN  = .04,
        OFFSET_Y_PHASE = 100,
        OFFSET_Y_GAIN  =   3,
        deltaRad;
    
    deltaRad = Math.cos(Math.PI * 2 * (distance % ROTATION_PHASE) / ROTATION_PHASE) * ROTATION_GAIN;
    
    this.skeleton.parts.body.rotate(deltaRad);
    this.skeleton.parts.leftLeg.rotate(deltaRad);
    this.skeleton.parts.rightLeg.rotate(deltaRad);
    
    this.destOffsetY += Math.sin(Math.PI * 2 * (distance % OFFSET_Y_PHASE) / OFFSET_Y_PHASE) * OFFSET_Y_GAIN;
}

Bone の長さや係数、周期を調整するといろんな動きができるので、ぜひお試しあれ!

canvasのコードを見やすくしよう!

明けましておめでとうございます。
本年もどうぞよろしくお願いいたします。

さて、
今年から閃光部(フロントエンド)を離れ
意匠部(デザイン)の所属になるのですが
そうなるとすぐJS忘れちゃいそうで。。。

というわけで忘れないようにブログ始めます!

最初の投稿はcanvasのお話。

canvasで複雑なパスを描こうとすると。。。

(function(win, doc) {

'use strict';

var cvs = doc.createElement('canvas'),
    ctx = cvs.getContext('2d');

cvs.width  = 200;
cvs.height = 300;
doc.body.appendChild(cvs);

ctx.translate(100, 100);
ctx.beginPath();
ctx.arc(0, 0, 30, 0, Math.PI * 2, true);
ctx.save();
for (var i = 8; i--;) {
    ctx.rotate(45 * Math.PI / 180);
    ctx.moveTo(0, -50);
    ctx.lineTo(0, -80);
}
ctx.restore();
ctx.save();
ctx.translate(-50, 100);
ctx.save();
ctx.translate(0, 0);
ctx.moveTo( 0,  0);
ctx.lineTo(20,  0);
ctx.lineTo(20, 20);
ctx.lineTo( 0, 20);
ctx.lineTo( 0, 40);
ctx.lineTo(20, 40);
ctx.restore();
ctx.save();
ctx.translate(30, 0);
ctx.moveTo( 0,  0);
ctx.lineTo(20,  0);
ctx.lineTo(20, 40);
ctx.lineTo( 0, 40);
ctx.lineTo( 0,  0);
ctx.restore();
ctx.save();
ctx.translate(60, 0);
ctx.moveTo( 0, 10);
ctx.lineTo(10,  0);
ctx.lineTo(10, 40);
ctx.moveTo( 0, 40);
ctx.lineTo(20, 40);
ctx.restore();
ctx.save();
ctx.translate(85, 0);
ctx.moveTo(20, 40);
ctx.lineTo(20,  0);
ctx.lineTo( 0, 30);
ctx.lineTo(25, 30);
ctx.restore();
ctx.restore();
ctx.stroke();

}(this, document));

見づらい(T_T)

でも、これを save() / restore() の対でインデントすると。。。

(function(win, doc) {

'use strict';

var cvs = doc.createElement('canvas'),
    ctx = cvs.getContext('2d');

cvs.width  = 200;
cvs.height = 300;
doc.body.appendChild(cvs);

ctx.translate(100, 100);
ctx.beginPath();
ctx.arc(0, 0, 30, 0, Math.PI * 2, true);
ctx.save();
    for (var i = 8; i--;) {
        ctx.rotate(45 * Math.PI / 180);
        ctx.moveTo(0, -50);
        ctx.lineTo(0, -80);
    }
ctx.restore();
ctx.save();
    ctx.translate(-50, 100);
    ctx.save();
        ctx.translate(0, 0);
        ctx.moveTo( 0,  0);
        ctx.lineTo(20,  0);
        ctx.lineTo(20, 20);
        ctx.lineTo( 0, 20);
        ctx.lineTo( 0, 40);
        ctx.lineTo(20, 40);
    ctx.restore();
    ctx.save();
        ctx.translate(30, 0);
        ctx.moveTo( 0,  0);
        ctx.lineTo(20,  0);
        ctx.lineTo(20, 40);
        ctx.lineTo( 0, 40);
        ctx.lineTo( 0,  0);
    ctx.restore();
    ctx.save();
        ctx.translate(60, 0);
        ctx.moveTo( 0, 10);
        ctx.lineTo(10,  0);
        ctx.lineTo(10, 40);
        ctx.moveTo( 0, 40);
        ctx.lineTo(20, 40);
    ctx.restore();
    ctx.save();
        ctx.translate(85, 0);
        ctx.moveTo(20, 40);
        ctx.lineTo(20,  0);
        ctx.lineTo( 0, 30);
        ctx.lineTo(25, 30);
    ctx.restore();
ctx.restore();
ctx.stroke();

}(this, document));

見やすい!

さらに beginPath() と stroke() の対もインデントすると。。。

(function(win, doc) {

'use strict';

var cvs = doc.createElement('canvas'),
    ctx = cvs.getContext('2d');

cvs.width  = 200;
cvs.height = 300;
doc.body.appendChild(cvs);

ctx.translate(100, 100);
ctx.beginPath();
    ctx.arc(0, 0, 30, 0, Math.PI * 2, true);
    ctx.save();
        for (var i = 8; i--;) {
            ctx.rotate(45 * Math.PI / 180);
            ctx.moveTo(0, -50);
            ctx.lineTo(0, -80);
        }
    ctx.restore();
    ctx.save();
        ctx.translate(-50, 100);
        ctx.save();
            ctx.translate(0, 0);
            ctx.moveTo( 0,  0);
            ctx.lineTo(20,  0);
            ctx.lineTo(20, 20);
            ctx.lineTo( 0, 20);
            ctx.lineTo( 0, 40);
            ctx.lineTo(20, 40);
        ctx.restore();
        ctx.save();
            ctx.translate(30, 0);
            ctx.moveTo( 0,  0);
            ctx.lineTo(20,  0);
            ctx.lineTo(20, 40);
            ctx.lineTo( 0, 40);
            ctx.lineTo( 0,  0);
        ctx.restore();
        ctx.save();
            ctx.translate(60, 0);
            ctx.moveTo( 0, 10);
            ctx.lineTo(10,  0);
            ctx.lineTo(10, 40);
            ctx.moveTo( 0, 40);
            ctx.lineTo(20, 40);
        ctx.restore();
        ctx.save();
            ctx.translate(85, 0);
            ctx.moveTo(20, 40);
            ctx.lineTo(20,  0);
            ctx.lineTo( 0, 30);
            ctx.lineTo(25, 30);
        ctx.restore();
    ctx.restore();
ctx.stroke();

}(this, document));

もっと見やすい!!

このお正月、<canvas>でゴニョゴニョする際はぜひお試しください。