iPhoneサイトのモックアップ用にフリックとピンチのJSを作ったのでメモ。
かなり急いで作ったからスパゲッティになってしまった。
写真を見せるギャラリーサイトを想定。
フリックで別の写真へ移動し、ピンチで拡大する。
※別途YUIライブラリ ver:3.0.0が必要です
JavaScript
document.onscroll = function(){
if(window.pageXOffset > 5)scrollTo(0,1);
}
YUI().use('anim', function(Y) {
//アニメーションインスタンス生成
var collectionAnim = new Y.Anim({
node: '#collection',
duration: 1,
easing: Y.Easing.easeOut
});
//イベント登録
var colectionLoaded = function(e) {
//フェードイン
collectionAnim.set('to', { opacity:1 });
collectionAnim.run();
var PHOTO_WIDTH = 320;
var PHOTO_HEIGHT = 427;
var PHOTO_MAX = 6;
var SCROLL_X_MIN = - PHOTO_WIDTH * (PHOTO_MAX - 1);
var startX = 0;//#collectionのタッチ時のx座標
var nowX = 0;//#collectionのタッチ中のx座標
var scroll = 0;//タッチの移動距離
var target = 0;//#collectionの移動先
var startTouch = 0;//タッチ時のタッチ位置のx座標
var nowTouch = 0;//タッチ中のタッチ位置のx座標
var startDis = 0;//タッチ時の2タッチ間の距離
var nowDis = 0;//タッチ中の2タッチ間の距離
var startPhotoWidth = 0;//タッチ時の写真幅
var startPhotoHeight = 0;//タッチ時の写真高さ
var touchCount = 0;//タッチ数
var photoCount = 0;//現在表示している写真のカウント
var collectionElement = document.getElementById("collection");
var zoom = false;//拡大中フラグ
var moving = false;//移動中フラグ
//タッチイベントリスナー登録
collectionElement.addEventListener('touchstart', touchHandler, false);
collectionElement.addEventListener('touchmove', touchHandler, false);
collectionElement.addEventListener('touchend', touchHandler, false);
collectionElement.addEventListener('touchcancel', touchHandler, false);
//タッチイベント処理
function touchHandler(e) {
e.preventDefault();
if (e.type == "touchstart") {
document.getElementById("touchstatus").innerHTML = "タッチスタート";
//タッチ数が1の時でピンチしていない時で移動中じゃないとき
if (e.touches.length == 1 && zoom == false && moving == false) {
touchCount = 1;
startTouch = e.touches[0].pageX;
scroll = 0;
startX = collectionElement.offsetLeft;
document.getElementById("touchmove").innerHTML = "startTouch:" + startTouch + "
startX:" + startX;
}
//タッチ数が2(ピンチ)の時で移動中じゃないとき
if (e.touches.length == 2 && moving == false) {
touchCount = 2;
zoom = true;
var touch1 = e.touches[0];
var touch2 = e.touches[1];
//3平方の定理で最初の距離を取得
startDis = Math.sqrt(Math.pow((touch1.pageX - touch2.pageX), 2)+Math.pow((touch1.pageY - touch2.pageY), 2));
var targetPhoto = document.getElementById("photo"+photoCount);
startPhotoWidth = targetPhoto.offsetWidth;
startPhotoHeight = targetPhoto.offsetHeight;
}
}else if (e.type == "touchmove") {
document.getElementById("touchstatus").innerHTML = "タッチ移動";
document.getElementById("touchx").innerHTML = e.touches[0].pageX;
document.getElementById("touchy").innerHTML = e.touches[0].pageY;
//タッチ数が1の時でピンチしていない時で移動中じゃないとき
if (e.touches.length == 1 && zoom == false && moving == false) {
touchCount = 1;
nowTouch = e.touches[0].pageX;
scroll = nowTouch - startTouch;
target = startX + scroll;
//ステージからはみ出ないようにする
if(target > 0){
target = 0;
}else if(target < SCROLL_X_MIN){
target = SCROLL_X_MIN;
}
collectionElement.style.left = target + "px";
document.getElementById("touchmove").innerHTML = "nowTouch:" + nowTouch + "
scroll:" + scroll + "
target:" + target;
}
//タッチ数が2(ピンチ)の時で移動中じゃないとき
if (e.touches.length == 2 && moving == false) {
touchCount = 2;
var touch1 = e.touches[0];
var touch2 = e.touches[1];
//3平方の定理で現在の距離を取得
nowDis = Math.sqrt(Math.pow((touch1.pageX - touch2.pageX), 2)+Math.pow((touch1.pageY - touch2.pageY), 2));
//倍率
var magnifications = nowDis / startDis;
var targetPhoto = document.getElementById("photo"+photoCount);
if(startPhotoHeight * magnifications > PHOTO_HEIGHT){
//拡大
targetPhoto.style.width = startPhotoWidth * magnifications + "px";
targetPhoto.style.height = startPhotoHeight * magnifications + "px";
//位置調整
collectionElement.style.left = -(PHOTO_WIDTH * photoCount + (startPhotoWidth * magnifications - PHOTO_WIDTH) / 2) + "px";
collectionElement.style.top = -(startPhotoHeight * magnifications - PHOTO_HEIGHT) / 2 + "px";
zoom = true;
}else{
//等倍
targetPhoto.style.width = PHOTO_WIDTH + "px";
targetPhoto.style.height = PHOTO_HEIGHT + "px";
//正常位置
collectionElement.style.left = -PHOTO_WIDTH * photoCount + "px";
collectionElement.style.top = 0 + "px";
zoom = false;
}
document.getElementById("touchmove").innerHTML = "2タッチ間の距離:" + nowDis + "
倍率" + magnifications;
}
}else if (e.type == "touchend" || e.type == "touchcancel") {
document.getElementById("touchstatus").innerHTML = "";
//タッチ数が1の時でピンチしていない時で移動中じゃないとき
if(touchCount == 1 && zoom == false && moving == false){
if(scroll < 0){
photoCount++
if(photoCount >= PHOTO_MAX - 1){photoCount = PHOTO_MAX - 1;}
}else{
photoCount--
if(photoCount <= 0){photoCount = 0;}
}
moving = true;
collectionAnim.set('to', { xy: [-photoCount * PHOTO_WIDTH, 0] });
collectionAnim.run();
collectionAnim.on('end', function(){moving = false;});
document.getElementById("touchend").innerHTML = "photoCount:" + photoCount;
}
touchCount = 0;
}
}
};
Y.on('load', colectionLoaded);
});
HTML
<div id="collection"> <ul> <li class="item"><img id="photo0" src="01.jpg" width="320" height="417" /></li> <li class="item"><img id="photo1" src="02.jpg" width="320" height="417" /></li> <li class="item"><img id="photo2" src="03.jpg" width="320" height="417" /></li> <li class="item"><img id="photo3" src="04.jpg" width="320" height="417" /></li> <li class="item"><img id="photo4" src="05.jpg" width="320" height="417" /></li> <li class="item"><img id="photo5" src="06.jpg" width="320" height="417" /></li> </ul> </div><!--#collection--> <div id="debug"> ステータス: <span id="touchstatus"></span> X: <span id="touchx"></span> Y: <span id="touchy"></span> <span id="touchint"></span> <span id="touchmove"></span> <span id="touchend"></span> </div>
CSS
#collection{
opacity:0;
width: 9999px;
position: absolute;
}
#collection li{
float: left;
}
#debug{
display: none;
position: absolute;
left: 0px;
top: 0px;
color: #FFF;
}
サンプル
http://www.kazy.jp/note/2010/04/yui/
ソース
http://www.kazy.jp/note/2010/04/yui/kazy_jp-note-2010-04-yui.zip

こちらのスクリプトを組み込んでも、ページが白紙になってしまい、どうしてもうまく動作しません。
なにか対処法などありましたらご伝授くださいませ。
よろしくお願いいたします。
コメントありがとうございます。
記事に書いたソースは部分部分なので、
これだけだと動かないかもしれません。
とりあえず、記事の最後にサンプルとソースを置きましたので、
そちらも参考にしてみてください。
でもあまりマネはしない方がいいですよ。
このソース汚いし、改めて見るとバグだらけだし。
あくまで参考ということで…。