2011年9月26日月曜日

JavaScriptライブラリjQueryその1

こんにちは、Nakajinです。

今回は、jQueryについて書いていこうと思います。

jQueryとは、少ない記述で高度な処理ができる軽量なjavaScriptライブラリです。
CSSに近い形で記述することが可能です。

通常のJavaScript
var element = document.getElementById("test");
element.style.color= "red";

jQuery
$("#test").css("color", "red");

上記のように、jQueryではシンプルな記述で書くことができます。

jQueryを使えば、アニメーション効果を簡単に表現することもできます。

$("#test2").click(function() {
$(this).animate({width: "200px", height: '200px'}, "slow");
});

サンプル
クリックで拡大


jQueryは世界中で多く使われており、様々なプラグインも作成されています。
使っていない人は、是非使ってみるといいと思います。

2011年9月13日火曜日

第3回HTML5のススメ

もうすぐ、ゲームショウの季節になりました。たのしみですね。KOYAです。

さて、今回は、「ネイティブにも負けない!HTML5のタッチイベント」について
話していこうと思います。

で、どうすればタッチイベントが拾えるの?って感じですが、以下の数ステップで
簡単に実現することが可能です。

以下、このような指定。
 
canvas.addEventListener("touchstart", ?????, false);
canvas.addEventListener("touchmove", ?????, false);
canvas.addEventListener("touchend", ?????, false);
canvas.addEventListener("touchcancel", ?????, false);

とまぁタッチに関するイベントが4つあるので、canvasで使用するなら、Eventに登録するだけで使えちゃいます。

※addEventLisstenerの仕様に関しては割愛させて頂きます。

で具体的にどんなイベントの際に発生するのか?ってことですが・・・

touchstart・・・タッチ入力開始時に発生。
touchmove・・・タッチスライド時発生。
touchend・・・タッチイベント終了時発生。
touchcancel・・・今のところ不明。わかる方がいらっしゃいましたら、たゆたうへご連絡ください。


とこんな感じです。

さぁこれでとりあえずタッチイベントは拾えました。
今回もサンプルで何か作りましょう。

ってことで、第1回から引き続き使用している、たゆたうロゴをタッチしてドロップ&ドラッグで
動かしちゃうスクリプトを作ることにします。

さっそく以下ソース。

 
// キャンバス
var canvas;
// コンテキスト
var ctx;
// キャンバス幅
var canvasWidth;
// キャンバス高さ
var canvasHeight;

// 指定オブジェクト
var obj;
// 画像オブジェクト
var img;
// タッチオブジェクト
var touch;

window.onload = function() {
 init();
};

/**
* 初期化処理
*/
function init(){

 // キャンバスの取得を行う。
 canvas = document.getElementById('testCanvas');
 // コンテキストの設定。
 ctx = canvas.getContext('2d');

 // キャンバスの塗りつぶし。
 canvasWidth = 400;
 canvasHeight = 600;

 // イベントの挿入
 canvas.addEventListener("touchstart", startListner, false);
 canvas.addEventListener("touchmove", moveListner, false);
 canvas.addEventListener("touchend", endListner, false);
 canvas.addEventListener("touchcancel", endListner, false);

 // オブジェクトクラスを生成する。
 obj = new Object();
 obj.x = 100;
 obj.y = 100;

 // ドラッグ時のオブジェクト
 touch = new Object();
 touch.x = 0;
 touch.y = 0;
 touch.dropFlag = false;
 touch.startX = 0;
 touch.startY = 0;

 // たゆたうロゴ
 img = new Image();
 img.src = "http://?????????????????/tayutau.png";

 // ロード終了時に描画等開始。
 img.onload  = function() {
  obj.w = img.width;
  obj.h = img.height;
  // 描画処理を行う。

  setInterval("loop()", 50);
 }
}

/**
* ループ処理処理
*/
function loop() {

 // ドロップされていない場合、初期化。
 if (false == touch.dropFlag) {
  obj.x += touch.x;
  obj.y += touch.y;
  touch.x = 0;
  touch.y = 0;

 }

 // 背面を黒塗り
 ctx.fillRect(0, 0, canvasWidth, canvasHeight);
 // 描画
 ctx.drawImage(img, obj.x + touch.x, obj.y + touch.y);
}

/**
* タッチイベント開始
*/
function startListner(event) {

 // キャンバスの絶対座標を取得する。
 var rect = event.target.getBoundingClientRect();

 // キャンバスでのタッチ座標を取得する。
 touch.startX = event.touches[0].pageX - rect.left;
 touch.startY = event.touches[0].pageY - rect.top;
 event.preventDefault() ;

 // 画像に当たっていた場合
 if (touch.startX > obj.x && touch.startX < obj.x + obj.w) {
  if (touch.startY > obj.y && touch.startY < obj.y + obj.h) {
   touch.dropFlag = true;
  }
 }
}

/**
* 移動
*/
function moveListner(event) {

 // つかんでいない場合
 if (false == touch.dropFlag) {
  return;

 }

 // キャンバスの絶対座標を取得する。
 var rect = event.target.getBoundingClientRect();
 // 現在のキャンバス位置から-開始位置の座標の算出

 touch.x = (event.touches[0].pageX - rect.left) - touch.startX;
 touch.y = (event.touches[0].pageY - rect.top) - touch.startY;
}

/**
* 終了イベント
*/
function endListner(event) {
 touch.dropFlag = false;

}

って事で、完成しました。少々長かった。
もっと簡単に実装できそうですが、サンプルソースって事で勘弁して下さい。

一部気になるコードだけ説明します。

1つ目は、

event.touches[0].pageX

なぜか配列になってる。。。
そう、マルチタッチだって対応してるんです。
なので、うまいことやれば結構なリッチでハッピーなゲームが作れるかもしれません。


そして2つ目は、

 event.preventDefault() ;

資料などを読むと、

イベントがキャンセル可能な場合、preventDefault メソッドを使用するとイベントのキャンセルを通知できるため、そのイベントの結果として通常は実装により実行されるデフォルトのアクションが実行されません~


と書いてあります。
何のために必要なのか?

最初はこれを記述せずに実装していたのですが、
タッチして移動するたびにブラウザがスクロールしてしまい、
うまく動作しなかったわけです。

こいつを入れてあげると、タッチイベント以降のイベントがキャンセルされるため、
スクロールせずにうまくタッチイベントが動くのです。

タッチイベントなんか簡単だろう。と思い実装してみたは良いものの
まさかこのような所でハマるとは思いませんでした。

以上、完。


2011年9月11日日曜日

PHPでオブジェクトから別のオブジェクトへプロパティをコピーする

こんにちは、matsuiです。

今回は弊社でソーシャルアプリを開発していく中で作成された共通処理の一部を紹介していきたいと思います。

ご紹介する内容は、指定されたオブジェクト間で同じ名前で定義されているプロパティの中身をコピーするというものです。

弊社内で使われているフレームワークでは、処理のレイヤーごとにデータを受け渡すためのオブジェクトを使ってやり取りしています。
そのような構造をとっているため処理のレイヤーを越える際に、オブジェクト間のデータの詰め替え作業が発生し、開発効率の低下を招く可能性がありました。
開発効率をできる限り下げないようにするために、下記のような「自動的に詰め替え作業を行う共通処理」を作成し、詰め替え作業のコストの削減を図っています。

----------------------------------------------------------------------
 /**
 * 指定されたオブジェクトに定義されているプロパティを詰め替える.
 *
 * 引数に指定された両方オブジェクトを比較し、同一のプロパティが存在した場合に第一引数のオブジェクトから第二引数のオブジェクトに値をコピーする。
 *
 * @param unknown_type $sourceDto
 * @param unknown_type $targetDto
 */
public static function copyProperties($sourceDto, $targetDto)
{
    if ($sourceDto === null || $targetDto === null) {
        return null;
    }
  
    $targetPropertyList = get_class_vars(get_class($targetDto));
  
    foreach ($targetPropertyList as $key =&gt; $value) {
        if (property_exists($sourceDto, $key)) {
            $targetDto-&gt;$key = $sourceDto-&gt;$key;
        }
    }
  
    return $targetDto;
  
}
----------------------------------------------------------------------

なお、お気づきの方もいらっしゃるかもしれませんが、
ご紹介した処理では、正確には「値のコピー」になっていない場合があります。

それはプロパティの中身が参照型と呼ばれる形式になっている場合です。
詳しい説明は割愛しますが、オブジェクト型などに代表される参照型の場合、参照先のオブジェクト自体が複製されるわけではなく、参照先オブジェクトへの参照がコピーされることになります。

さらにオブジェクトがネストされていた場合などは、「シャロー(shallow)コピー」と「ディープ(deep)コピー」の話も絡んできます。

記述された処理が思うような動きをしなかった場合は、参照型・シャローコピー・ディープコピーといった概念について確認していただいた方が良いかもしれません。

追記
PHP(Zend Engine)ではzvalという概念を持ち変数を管理しています。
そのため、変数の代入すら本来の値のコピーではないようです…それは今現在のZend Engineの実装の話なのでここでは取り上げませんが、興味のある方は調べてみるのも面白いと思います。

2011年9月8日木曜日

PHPテンプレートエンジンTwig 番外編:基礎構文サンプル

こんにちは、Yuzuruです。
NakajinさんがTwigについて書かれていたので今回はおまけとして簡単な例を幾つか上げてみようと思います。
変数についてはPHPテンプレートエンジンTwig その2を参照

if
class User {
    public 'age' => string '10'
    public 'name' => string 'Ronaldinho'
    public 'sex' => string 'male'
}
$object = new User();
echo $template->render(array('user' => $object));
[twig]
{% if user.age < 20 and not user.sex == 'female' %}
     こんにちは、{{user.name}}くん
{% else %}
    こんにちは、{{user.name}}さん
{% endif %}

[表示]
こんにちは、Ronaldinhoくん

論理演算子はand, or, not です(&&とかと違うので注意)


for

i=0からi=10まで繰り返す処理

[twig]

{% for i in 0..10 %}
    * {{ i }}
{% endfor %}

[表示]
* 0 * 1 * 2 * 3 * 4 * 5 * 6 * 7 * 8 * 9 * 10

foreach的な繰り返し処理もfor

class User {
    public $id;
    public $name;
}
$object1 = new User();
$object2 = new User();

$object1->id = 1;
$object1->name = 'Carlos';
$object2->id = 2;
$object2->name = 'Sofia';
$objects = array();
$objects[0] = $object1;
$objects[1] = $object2;echo $template->render(array('users' => $objects));

[twig]
{% for user in users %}
    {{user.id}}:{{user.name}}
{% else %}
     ユーザはいません
{% endfor %}

[表示]
1:Carlos 2:Sofia
nullやemptyの時はelseに入ります。

文字列連結
~を使います。
[twig]
{% set name = 'Santiago' %}
{{ "Hello " ~ name ~ "!" }}

[表示]
Hello Santiago!

format
書式フォーマットの指定
[twig]
{% set hoge = 0.21311 %}
    1:{{ hoge }}
    2:{{ "%2.2f"|format(hoge) }}

[表示]
1:0.21311
2:0.21

[twig]
{% set name = 'Santiago' %}
{{ "Hello %s!"|format(name) }}

[表示]
Hello Santiago!

printfの書式指定と同様です。

date
日付の表示形式
[twig]
{% set created = '2011-09-07 11:22:33' %}
①{{ created }}
②{{ created|date("H:i") }}
③{{ created|date("m/d") }}

[表示]
①2011-09-0711:22:33
②11:22
③09/07