2011年4月29日 星期五

html5 - Javascript 3D Engine three.js 實作範例教學 (二)

繼上一篇在空間裡飛行的朋友照
現在將朋友照貼到立體的方塊上
變更Javascript部分
實作範例教學:

var container = new Array();
var camera = new Array();
var scene = new Array();
var renderer = new Array();
var cube = new Array();
var plane = new Array();
var targetRotation = new Array();
var targetRotationOnMouseDown = new Array();
var mouseX = new Array();
var mouseXOnMouseDown = new Array();
var windowHalfX = ($(window).width()) / 2;
var windowHalfY = ($(window).height()) / 2;
var cubeSize = Math.floor(($(window).width())/5);
var aImgData = new Array();
var imgStart = 0;
var total = 5;

$('body').append(
    $('<div id="main"/>').attr(
        {align:'center',width:(cubeSize*3),height:(cubeSize*3)}
    )
);

$(window).load(function() {
    var count = 0;
    $('.img').each(function(index,value){
        aImgData[index] = new Image();
        aImgData[index].src = value.src;
        aImgData[index].onload = function(){
            count++;
            loadImg(count);
        }
    });

});

function loadImg(count){
    if( count == $('.img').length ){
        init();
    }
}

function init(){
    for(var i=0; i<= total; i++ ){
        newCube(i);
    }
    animate();
}

function newCube(num){
    var domId = 'cube'+num;
    var cubeTop = cubeSize*Math.floor(num/3);
    var cubeLeft = (cubeSize)+cubeSize*(num%3);
    cubeTop = cubeTop + 'px';
    cubeLeft = cubeLeft + 'px';
    $('#main').append(
        $('<div id="'+domId+'"/>').css(
                {width:cubeSize+'px',height:cubeSize+'px',position:'absolute',top:cubeTop,left:cubeLeft}
            )
    );
    container[num] = $('#'+domId).get(0);
 camera[num] = new THREE.Camera( 70, ($(window).width()) / ($(window).width()), 1, 1000 );
 camera[num].position.y = 150;
 camera[num].position.z = 500;
 camera[num].target.position.y = 150;

    scene[num] = new THREE.Scene();
    //cube
    var materials = [];
 for ( var i = 0; i < 6; i ++ ) {
     materials.push( [ new THREE.MeshBasicMaterial({map: ImageUtils.loadTexture(aImgData[imgStart].src)}) ] );
        imgStart++;
 }
 cube[num] = new THREE.Mesh( new Cube( cubeSize, cubeSize, cubeSize, 1, 1, 1, materials ), new THREE.MeshFaceMaterial() );
 cube[num].position.y = 180;
 cube[num].overdraw = true;
 scene[num].addObject( cube[num] );

    //plane
 plane[num] = new THREE.Mesh( new Plane( (cubeSize*0.95), (cubeSize*0.95) ), new THREE.MeshBasicMaterial( { color: 0x222222 } ) );
 plane[num].rotation.x = - 90 * ( Math.PI / 180 );
 plane[num].overdraw = true;
 scene[num].addObject( plane[num] );

 renderer[num] = new THREE.CanvasRenderer();
 renderer[num].setSize( cubeSize, cubeSize );

 container[num].appendChild( renderer[num].domElement );
    targetRotation[num] = 0;
    targetRotationOnMouseDown[num] = 0;
    mouseX[num] = 0;
    mouseXOnMouseDown[num] = 0;
    $('#'+domId).mouseover(function(e){
        mouseX[num] = e.clientX - windowHalfX;
        targetRotation[num] = targetRotationOnMouseDown[num] + ( mouseX[num] - mouseXOnMouseDown[num] ) * 0.02;
    });
}

function animate() {
    setTimeout( 'animate();', 1000 / 60 );
 render();
}

function render() {
    for(var i =0; i <= total; i++ ){
        plane[i].rotation.z = cube[i].rotation.y += ( targetRotation[i] - cube[i].rotation.y ) * 0.05;
        renderer[i].render( scene[i], camera[i] );
    }
}

實作範例 : http://excite.978.tw/html5/3d_cube.php

2011年4月27日 星期三

html5 - Javascript 3D Engine three.js 實作範例教學

three.js 一套 Javascript 3D Engine https://github.com/mrdoob/three.js/
實作將facebook的朋友個人照,在3D的空間裡漂浮

實作範例教學:
PHP & HTML部分

$facebook = new Facebook(array(
             'appId'  => $facebook_app_key,
             'secret' => $facebook_app_secret,
             'cookie' => true
            ));
if( !$facebook->getSession() ){
    $auth_url = $facebook->getLoginUrl();
    header('Location: '.$auth_url);
    exit;
}else{
    $fb_id = $facebook->getUser();
    try{
        $aFriendList = $facebook->api(array(
            'method' => 'fql.query',
            'query' => 'select pic_square from user where uid in (select uid2 from friend where uid1 = '.$fb_id.') order by name limit 1000'
        ));
        shuffle($aFriendList);
        foreach( $aFriendList as $k => $v ){
            if( $k > 100 ){
                unset($aFriendList[$k]);
            }  
        }  
    }catch(Exception $e){ $aFriendList = array(); }
}

<html>
<head>
<meta charset="utf-8">
<script src="http://ajax.googleapis.com/ajax/libs/jquery/1.5.1/jquery.min.js"></script>
<!-- 載入 Three.js -->
<script type="text/javascript" src="three/build/Three.js"></script>
<style>
body{
    background-color: #000000;
    margin: 0px;
    overflow: hidden;
}
ul { position:absolute;top:-1000;left:-1000} /* 把圖丟到可視範圍外 */
</style>
</head>
<body>
<ul>
    <?php

    foreach( $aFriendList as $k => $v ){
    ?>
        <li><img class="img" src="img_proxy.php?i=<?php echo urlencode($v['pic_square']); ?>"></li>
    <?php
    }

    ?>
</ul>

Javascript部分

var container,camera, scene, renderer, particle;
var mouseX = 0, mouseY = 0;
var windowHalfX = ($(window).width()) / 2;
var windowHalfY = ($(window).height()) / 2;
var count = 0;
var total = ($('ul li').length) - 1;
var aImgData = new Array();

$(window).load(function() {
    var gogo_count = 0;
    $('.img').each(function(index,value){
        aImgData[index] = new Image();
        aImgData[index].src = value.src;
        aImgData[index].onload = function(){
            gogo_count++;
            gogo(gogo_count);
        }
    });

});

function gogo(gogo_count){
    if( gogo_count == $('.img').length ){
        init();
        animate();
    }
}

function init(){
    $('body').append(
        $('<div id="main"/>')
    );
    container = $('#main').get(0);
    camera = new THREE.Camera( 75, ($(window).width()) / ($(window).height()), 1, 3000 );
 camera.position.z = 1000;
 scene = new THREE.Scene();

 var program = function ( context , color) {
        var t1 = color.__styleString.split(/,/);
        var t2 = t1[2].replace(')','');
        if( aImgData[t2] != undefined ){
            if( aImgData[t2].complete == true ){
                context.save();
                context.translate(12,12);
                context.rotate(180 * Math.PI / 180)
                context.drawImage(aImgData[t2],0,0,12,12);
                context.restore();
                context.rotate(180 * Math.PI / 180)
            }
        }
 }

 for ( var i = 0; i < total; i++ ) {
        count = i;
  particle = new THREE.Particle( new THREE.ParticleCanvasMaterial( 
                                            { color: count, program: program } 
                                        ) 
                                     );
  particle.position.x = Math.random() * 2000 - 1000;
  particle.position.y = Math.random() * 2000 - 1000;
  particle.position.z = Math.random() * 2000 - 1000;
  particle.scale.x = particle.scale.y = Math.random() * 10 + 5;
  scene.addObject( particle );
 }

 renderer = new THREE.CanvasRenderer();
 renderer.setSize( ($(window).width()), ($(window).height()) );
 container.appendChild( renderer.domElement );

    $('body').mousemove(function(e){
  mouseX = e.pageX - windowHalfX;
  mouseY = e.pageY - windowHalfY;
    });

}

function animate() {
    setTimeout( 'animate();', 1000 / 60 );
 render();
}

function render() {
 camera.position.x += ( mouseX - camera.position.x ) * 0.05;
 camera.position.y += ( - mouseY - camera.position.y ) * 0.05;
 renderer.render( scene, camera );
}


實作 : http://excite.978.tw/html5/3d_space.php

2011年4月26日 星期二

html5實作使用opencv進行臉部辨識

使用 open cv javascript 版本 : http://github.com/liuliu/ccv
實作範例教學:
HTML部分:

<canvas id="canvas"/>
<script type="text/javascript" src="ccv.js"></script>
<script type="text/javascript" src="face.js"></script>

javascript部分:

$('#canvas').attr({width:($(window).width())-400,height:$(window).height()});
function face(src){
    $('#msg').html('請等待');
    //圖片位置
    var img_path = 'img_proxy.php?i='+encodeURIComponent(src);
    var image = new Image();
    image.src = img_path;
    var canvas = $('#canvas').get(0);
    var ctx = canvas.getContext("2d");
    ctx.fillStyle = 'white';
    ctx.fillRect(0, 0, $(window).width(), $(window).height());
    image.onload = function () {
     /* call main detect_objects function */
     var elapsed_time = (new Date()).getTime();
     var comp = ccv.detect_objects({ "canvas" : ccv.grayscale(ccv.pre(image)),
             "cascade" : cascade,
             "interval" : 5,
             "min_neighbors" : 1 });
     ctx.drawImage(image, 0, 0);
     ctx.lineWidth = 3;
     ctx.strokeStyle = "#f00";
     /* draw detected area */
     for (var i = 0; i < comp.length; i++){
      ctx.strokeRect(comp[i].x, comp[i].y, comp[i].width, comp[i].height);
        }
        $('#msg').html(' ');
    }
} 

 
實作結果: http://excite.978.tw/html5/opencv_js.php
 

2011年4月22日 星期五

html5實作套用box2d物理引擎效果

使用 https://github.com/jwagner/box2d2-js
實作範例教學:
Javascirpt canvas處理

//圖片位置
$('#imgPath').hide();
var img_path = $('#imgPath').attr('src');
//canvas dom
$('body').append(
    $('<div id="main"/>').append(
        $('<canvas id="canvas"/>').attr(
            {width:$(window).width(),height:$(window).height()}
        )
    )
);

var tmpImg = new Array();
var tmpPosTop = new Array();
var tmpPosLeft = new Array();
var screenTop;
var screenLeft;
var pHeight;
var pWidth;
var imgTop;
var imgLeft;
 
//抓下圖片貼到canvas
var canvasDom = $('#canvas').get(0);
var ctx = canvasDom.getContext('2d');
ctx.fillStyle= 'FFFFFF';
var img = new Image();
img.src = img_path;
img.onload = function(){
    var i = 0;
    screenTop = Math.floor(($(window).height())/2) - this.height;
    screenLeft = Math.floor(($(window).width())/2) - this.width;
    pHeight = Math.floor(this.height/10);
    pWidth = Math.floor(this.width/10);
    imgTop = screenTop;
    imgLeft = screenLeft;
    ctx.drawImage(img,imgLeft,imgTop);
    //把圖存到array裡
    while( imgTop < this.height+screenTop && imgLeft < this.width+screenLeft ){
        tmpImg[i] = ctx.getImageData(imgLeft,imgTop,pWidth,pHeight);
        tmpPosTop[i] = imgTop;
        tmpPosLeft[i] = imgLeft;
        i++;
        imgLeft += pWidth;
        if( imgTop < this.height+screenTop && imgLeft >= this.width+screenLeft ){
            imgLeft = screenLeft;
            imgTop += pHeight;
        }
    }
    init();
}


加上box2d

var c_width = Math.floor(($(window).width())/10);
var ppm = ($(window).width())/c_width;
var c_height = ($(window).height())/ppm;
var worldAABB = new b2AABB();
worldAABB.lowerBound.Set(-1000.0, -1000.0);
worldAABB.upperBound.Set(1000.0, 1000.0);
var world = new b2World(worldAABB, new b2Vec2(0.0, -9.8), true);
window.world = world;

var groundBodyDef = new b2BodyDef();
groundBodyDef.position.Set(c_width/2.0, 3.0);
var groundBody = world.CreateBody(groundBodyDef);
var groundShapeDef = new b2PolygonDef();
groundShapeDef.restitution = 0.0;
groundShapeDef.friction = 0.5;
groundShapeDef.density = 1.0;
groundBody.w = c_width*1.0
groundBody.h = 5.0
groundShapeDef.SetAsBox(groundBody.w, groundBody.h);
groundBody.CreateShape(groundShapeDef);
groundBody.SynchronizeShapes();
var bodies = [groundBody];

function init(){
    ctx.setTransform(ppm, 0, 0, -ppm, 0, $(window).height());  
    for( i=0; i<tmpImg.length; i++ ){
        var bodyDef = new b2BodyDef();
        bodyDef.position.Set(tmpPosLeft[i]/ppm, c_height-(tmpPosTop[i]/ppm));
        //bodyDef.position.Set(5, 5);
        var body = world.CreateBody(bodyDef);
        var shapeDef = new b2PolygonDef();
        shapeDef.SetAsBox(1.0, 1.0);
        body.w = pWidth/ppm;
        body.h = pHeight/ppm;
        shapeDef.restitution = 0.0;
        shapeDef.density = 1.0;
        shapeDef.friction = 0.9;
        body.CreateShape(shapeDef);
        body.SetMassFromShapes();
        bodies.push(body);
    }
}   

var frame = 0;
window.setInterval(function() {
    world.Step(1.0/60.0, 10);
    ctx.fillStyle = 'white';
    ctx.fillRect(0, 0, $(window).width(), $(window).height());
    for(var i = 0; i < bodies.length; i++){
        var body = bodies[i];
        var t = body.m_xf;
        var posX = t.position.x;
        var posY = t.position.y;
        var angle = body.GetAngle();
        //if(tmpImg[i] != undefined){
        if(i>0){
            var x = $(window).width()-($(window).width()-(posX*ppm));
            var y = $(window).height()-(posY*ppm);
            ctx.putImageData(tmpImg[(i-1)],x,y);
        }else{
            ctx.fillStyle = 'white';
            ctx.translate(posX, posY)
            ctx.rotate(angle);
            ctx.fillRect(-body.w, -body.h, body.w*2, body.h*2);
            ctx.rotate(-angle);
            ctx.translate(-posX, -posY)
        }
    }
}, 1000/30); 

 
實作範例 : http://excite.978.tw/html5/particle_box2d.php
 
 

2011年4月21日 星期四

html5實作碎圖效果加上滑鼠座標把碎圖做相對移動

加上滑鼠座標判斷,將破完的圖做相對的移動
實作範例教學:

var middleX = Math.floor(($(window).width())/2);
var middleY = Math.floor(($(window).height())/2);
var capX = Math.floor(($(window).width())/20);
var capY = Math.floor(($(window).height())/20);

$('body').mousemove(function(e){
    if( doMove ){
        for( j=0;j < tmpImg.length; j++ ) {
            ctx.fillRect(tmpPosLeft[j],tmpPosTop[j],pWidth,pHeight);
            var moveX = Math.floor((middleX-e.pageX)/capX);
            var moveY = Math.floor((middleY-e.pageY)/capY);
            if( Math.abs(tmpPosLeft[j]-middleX) < capX * 2 ){
                moveX = moveX/2;
            }

            if( Math.abs(tmpPosTop[j]-middleY) < capY * 2 ){
                moveY = moveY/2;
            }

            tmpPosLeft[j] = tmpPosLeft[j] + moveX;
            tmpPosTop[j] = tmpPosTop[j] + moveY;

            ctx.putImageData(tmpImg[j],tmpPosLeft[j],tmpPosTop[j]);
            //console.log(moveX,moveY);
        }
    }
});
 
 

實作: http://excite.978.tw/html5/particle_v2.php

2011年4月20日 星期三

html5碎圖效果

實作範例教學:
HTML部分
<html>
<head>
<meta charset="utf-8">
<script src="http://ajax.googleapis.com/ajax/libs/jquery/1.5.1/jquery.min.js"></script>
</head>
<body>
<img id="imgPath" src="img_proxy.php?i=http%3A%2F%2Fprofile.ak.fbcdn.net%2Fhprofile-ak-snc4%2F49062_1041673900_6306_n.jpg">
<script src="particle.js"></script>
</body>
</html

 JS部分

//圖片位置
$('#imgPath').hide();
var img_path = $('#imgPath').attr('src');
//canvas dom
$('body').append(
$('<div id="main"/>').append(
$('<canvas id="canvas"/>').attr(
{width:$(window).width(),height:$(window).height()}
)
)
);

參數宣告

var tmpImg = new Array();
var tmpPosTop = new Array();
var tmpPosLeft = new Array();
var aGoTop = new Array();
var aGoLeft = new Array();
var Flag = new Array();
var screenTop;
var screenLeft;
var pHeight;
var pWidth;
var imgTop;
var imgLeft;
var i = 0;

canvas處理
//抓下圖片貼到canvas
var canvasDom = $('#canvas').get(0);
var ctx = canvasDom.getContext('2d');
ctx.fillStyle= 'FFFFFF';
var img = new Image();
img.src = img_path;
img.onload = function(){
    screenTop = Math.floor(($(window).height())/2) - this.height;
    screenLeft = Math.floor(($(window).width())/2) - this.width;
    pHeight = Math.floor(this.height/15);
    pWidth = Math.floor(this.width/15);
    imgTop = screenTop;
    imgLeft = screenLeft;
    ctx.drawImage(img,imgLeft,imgTop);
    //把圖存到array裡
    while( imgTop < this.height+screenTop && imgLeft < this.width+screenLeft ){
        tmpImg[i] = ctx.getImageData(imgLeft,imgTop,pWidth,pHeight);
        tmpPosTop[i] = imgTop;
        tmpPosLeft[i] = imgLeft;
        i++;
        imgLeft += pWidth;
        if( imgTop < this.height+screenTop && imgLeft >= this.width+screenLeft ){
            imgLeft = 0;
            imgTop += pHeight;
        }
    }
    var pImg = new Array();
    i = 0;
    //計算要到達的目的座標
    while(i < tmpImg.length){
        if( pImg[i] != 1 ){
            pImg[i] = 1;
            var randLeft = Math.floor(Math.random()*(img.width));
            var randTop = Math.floor(Math.random()*(img.height));
            var randDir = Math.floor(Math.random()*10);
            if( randDir % 4 == 1 ){
                randLeft  = randLeft * -1;
                randTop = randTop * -1;
            }else if(randDir % 4 == 2){
                randTop = randTop * -1;
            }else if(randDir % 4 == 3){
                randLeft  = randLeft * -1;
            }
            var goLeft = tmpPosLeft[i] + randLeft;
            var goTop = tmpPosTop[i] + randTop;
            if( goLeft < 0 ){
                goLeft = 0;
            }
            if( goTop < 0 ){
                goTop = 0;
            }
            if( goLeft >= $(window).width() ){
                goLeft = $(window).width();
            }
            if( goTop >= $(window).height() ){
                goTop = $(window).height();
            }
            aGoTop[i] = goTop;
            aGoLeft[i] = goLeft;
            i++;
        }
    }
    i = 0;
    while( i < tmpImg.length ){
        //移動圖片區塊
        Flag[i] = setInterval('moveParticle('+i+');',1);
        i++;
    }
}
移動圖塊
var moveParticle = function (i){
    if( Math.abs(tmpPosLeft[i] - aGoLeft[i]) < 5 || Math.abs(tmpPosTop[i] - aGoTop[i]) < 5 ){
        clearInterval(Flag[i]);
    }
    ctx.fillRect(tmpPosLeft[i],tmpPosTop[i],pWidth,pHeight);
    if( aGoLeft[i] > tmpPosLeft[i] ){
        tmpPosLeft[i]++;
    }else{
        tmpPosLeft[i]--;
    }
    if( aGoTop[i] > tmpPosTop[i] ){
        tmpPosTop[i]++;
    }else{
        tmpPosTop[i]--;
    }
    ctx.putImageData(tmpImg[i],tmpPosLeft[i],tmpPosTop[i]);
} 

實作範例: http://excite.978.tw/html5/particle.php

2011年4月19日 星期二

google page speed online 測試網頁速度

http://pagespeed.googlelabs.com/
測試網頁速度,可以測試mobile performance
手機速度通常不快,手機頁面能有工具幫忙調整頁面還真不錯

2011年4月15日 星期五

mac上使用 open vpn 出現錯誤訊息 Cannot allocate TUN/TAP dev dynamically

64bit的macos使用open vpn 時會出現 Cannot allocate TUN/TAP dev dynamically 的錯誤訊息
Terminal下執行
# ls /dev/tap*
原來是沒有tap device
解法:
http://tuntaposx.sourceforge.net/download.xhtml
安裝這一個open source 即可

2011年4月14日 星期四

facebook製作分享按鈕或是按讚按鈕(like button)測試網址

製作facebook分享按鈕或是按讚的like button時,常常都需要按下去後才會知道分享出去的結果
如果meta tag有下錯,分享出去的圖示或是文字就會跟想像中的不一樣
facebook有提供一個線上的debug tool URL Linter
http://developers.facebook.com/tools/lint/
可以節省很多測試的時間

html5實作蒙太奇(montage)效果

html5有canvas標籤可以繪圖
於是試著把facebook上朋友的照片取下來後組合成蒙太奇效果個人圖
實作範例教學:
Part I. php code 取得facebook權限並抓取朋友的個人照

$facebook = new Facebook(array(
             'appId'  => $facebook_app_key,
             'secret' => $facebook_app_secret,
             'cookie' => true
            ));
if( !$facebook->getSession() ){
    $auth_url = $facebook->getLoginUrl();
    header('Location: '.$auth_url);
    exit;
}else{
    $fb_id = $facebook->getUser();
    try{
        $aUserData = $facebook->api(array(
            'method' => 'fql.query',
            'query' => 'select pic_square from user where uid='.$fb_id
        ));
        $UserImg = $aUserData[0]['pic_square'];
    }catch(Exception $e){ }
    try{ //抓取朋友的圖片
        $aFriend = $facebook->api(array(
           'method' => 'fql.query',
           'query' => 'select uid,pic_square from user where uid in (select uid1 from friend where uid2 = '.$fb_id.') limit 360',
        ));
        shuffle($aFriend);
    }catch(Exception $e){ }
}

Part II. HTML部份
CSS
<style>
#friend ul li {list-style-type:none;}
#friend .friendimg{position:absolute;width:10px;top:-1000px;}
#me {position:absolute;top:0px;left:0px;z-index:1;}
#me ul li {list-style-type:none;}
#me .meimg {width:600px;height:600px;position:absolute;top:-1000px;}
#msg {color:#0000FF;}
</style>

BODY
<p>如圖片顯示不正常,重新整理一次即可</p>
<p><span id="msg">正在抓取朋友個人照...請等待</span></p>
<canvas id="img_canvas" width="600" height="600"></canvas><!-- 顯示結果的canvas -->

<canvas id="canvas_me" width="600" height="600"></canvas><!-- 半透明個人用 -->
<div id="me"> <!-- 自己的圖片 -->
    <ul>
        <li><img class="meimg" src="<?php echo htmlspecialchars($UserImg); ?>"></li>
    </ul>
</div>

<div id="friend"> <!-- 朋友的圖片 -->
    <ul>
        <?php foreach( $aFriend as $k => $v ){
                  echo '<li><img class="friendimg" src="'.htmlspecialchars($v['pic_square']).'"></li>'."\n";
              }
        ?>
    </ul>
</div>

Part III. Javascript部分

$(window).load(function() { //全部的圖載完才開始跑
    var canvas = $("#img_canvas").get(0);
    if( typeof canvas.getContext == 'undefined' ){
        $('#msg').html('組圖失敗,原因:瀏覽器不支援HTML5');
        return;
    }
    //將朋友圖加到canvas裡
    var ctx = canvas.getContext("2d");
    var img_top = 0;
    var img_left = 0;
    var total = 3600;
    var max = $('#friend .friendimg').length;
    var i=0;
    while( i<total ){
        var seed = Math.floor(Math.random()*max);
        var img = new Image();
        var img_tmp = $('#friend .friendimg');
        var img_tmp_dom = img_tmp[seed];
        img.src = img_tmp_dom.src;
        if( img.src.length > 3 && img_tmp_dom.complete == true){
            ctx.drawImage(img, img_top,img_left,10,10);
            img_left += 10;
            if( img_left >= 600 ){
                img_left = 0;
                img_top += 10;
            }
            i++;
        }
    }
    //取出自己的圖半透明後再疊到之前做好的朋友組圖上
    var me_img_src = $('#me .meimg').attr('src');
    var img_me = new Image();
    img_me.src = me_img_src;
    var canvasme = document.getElementById("canvas_me");
    var ctx_me = canvasme.getContext("2d");
    ctx_me.globalAlpha = 0.75;
    ctx_me.drawImage(img_me, 0, 0,600,600);
    ctx.drawImage(canvasme, 0,0,600,600);
    canvasme.style.display = 'none';
    $('#msg').html('');
});

結果圖:











範例結果: http://excite.978.tw/html5/montage.php

2011年4月12日 星期二

在網站上放置 facebook like button

參考 : http://developers.facebook.com/docs/reference/plugins/like/
在<header>裡放入meta tag給facebook讀取

<meta property="og:title" content="標題">
<meta property="og:type" content="website">
<meta property="og:url" content="網址">
<meta property="og:image" content="圖片">
<meta property="og:site_name" content="網站名稱">
<meta property="og:description" content="內容文字敘述">

在頁面想要的地方放入 like button 的 iframe

<iframe src="http://www.facebook.com/plugins/like.php?href=http%3A%2F%2Ftw.yahoo.com&amp;layout=standard&amp;show_faces=true&amp;width=450&amp;action=like&amp;font&amp;colorscheme=light&amp;height=80" scrolling="no" frameborder="0" style="border:none; overflow:hidden; width:450px; height:80px;" allowTransparency="true"></iframe>

Firefox記憶體設定

參考 : http://forum.moztw.org/viewtopic.php?f=2&t=11431&view=previous
限制一下Firefox記憶體使用量
步驟
1. about:config
2. browser.sessionhistory.max_total_viewers 30 //30個頁面會cache
3. browser.cache.memory.capacity 20480 //記憶體限制

2011年4月6日 星期三

iphone safari 多點觸控實作

參考一
http://developer.apple.com/library/safari/#documentation/appleapplications/reference/safariwebcontent/HandlingEvents/HandlingEvents.html
參考二
http://developer.apple.com/library/safari/#documentation/AppleApplications/Reference/SafariHTMLRef/Articles/MetaTags.html#//apple_ref/doc/uid/TP40008193-SW1

來製作一個二指劃開後圖片隨二指距離而變化

製作多點觸控,為避免瀏覽器的zoom in zoom out干擾所以要先將zoom的功能關閉

實作範例教學:
<meta name="viewport" content="width=device-width,height=420, initial-scale=1, maximum-scale=1, minimum-scale=1, user-scalable=0"/>   



圖片替換用的 div
<div id="img"><img src="1.png" width="320"></div>



加上感應觸控的 div
<div id="touch" ontouchstart="touchStart(event);" ontouchmove="touchMove(event);" ontouchend="touchEnd(event);" ontouchcancel="touchCancel(event);"></div>



css

html body{
    overflow: hidden;
}
#touch{
    position:absolute;
    top:0;
    left:0;
    width:100%;
    height:100%;
    background-color:#AAAAAA;
    opacity: 0;
}
#img{
    position:absolute;
    top:0;
    left:0;
}



javascript

//預先載入五張圖片
var img1 = new Image(); img1.src = '1.png';
var img2 = new Image(); img2.src = '2.png';
var img3 = new Image(); img3.src = '3.png';
var img4 = new Image(); img4.src = '4.png';
var img5 = new Image(); img5.src = '5.png';

var x_percent = 1; //二點距離指數
//加入觸控event
element.addEventListener("touchstart", touchStart, false);
element.addEventListener("touchmove", touchMove, false);
element.addEventListener("touchend", touchEnd, false);
element.addEventListener("touchcancel", touchCancel, false);

function touchStart(event){
//event 開時換第一張圖
    x_percent = 1;
    changeImg(x_percent);
}
function touchMove(event){
//依二指距離替換五張圖
    var x1 = event.touches[0].pageX;
    var y1 = event.touches[0].pageY;
    var x2 = event.touches[1].pageX;
    var y2 = event.touches[1].pageY;
    var x_diff = Math.abs(x1-x2);
    x_percent = Math.ceil((x_diff/32)/2);
    changeImg(x_percent);
}
function touchEnd(event){
//結束換回第一張圖
    x_percent = 1;
    changeImg(x_percent);
}
function touchCancel(event){
//取消也是換回第一張圖
    x_percent = 1;
    changeImg(x_percent);
}
function changeImg(screen){
    if(screen > 5){
        screen = 5;
    }
    if(screen < 1){
        screen = 1;
    }
    document.getElementById("img").innerHTML = '<img src="'+screen+'.png" width="320">';
}


結果展示:http://excite.978.tw/iphone/mtouch.php
(要用iphone的Safari開啟)
然後二指左右劃開就可以看到效果

facebook check in API (graph) 實作範例教學

facebook在台灣開放打卡後,graph裡的checkin API可以來玩玩
搭配手機定位來做應用 (手機瀏覽器取得geolocation)
以下為使用facebook php SDK 的實作範例教學

include('inc/facebook.php');
$facebook = new Facebook(
    array(
        'appId'  => $facebook_app_key,
        'secret' => $facebook_app_secret,
        'cookie' => true,
    )
);

$lat = filter_input(INPUT_GET, 'lat', FILTER_VALIDATE_FLOAT);
$long = filter_input(INPUT_GET, 'long', FILTER_VALIDATE_FLOAT);
$fb_id = $facebook->getUser();
//檢查登入
if( !$fb_id ){
    echo 'Please login facebook.'; exit;
}
//檢查經緯度
if( !$lat || !$long ){
    echo 'latitude or longitude is null'; exit;
}
//search place
try{
    $place = $facebook->api('/search?type=place¢er='.$lat.','.$long.'&distance=1000');
}catch(Exception $e){ var_dump($e); }
//checkin
try{
    $checkin_res = $facebook->api('/me/checkins'
              ,'post'
              ,array(
                   'message' => '手機綁app來check in,除了阿賢其他人都可以被tag'
                  ,'coordinates' => '{"latitude":"'.$lat.'", "longitude": "'.$long.'"}'
                  ,'place' => $place['data'][0]['id']
                  ,'application' => '{"name":"bruce test","id":"'.$facebook_app_id.'"}'
                  ,'tags' => '朋友id1,朋友id2,朋友id3,朋友id4,朋友id5'
               )
            );
    echo 'check in success.';
}catch(Exception $e){ var_dump($e); }

vim 去除多餘的空白

複製貼上程式碼時,尤其由ssh client複製時會有多餘的空白在每一行後面
這時用vim可簡單快速將空白移除
1. 按 : 進入命令模式
2. 在命令模式裡輸入 % s/\ *$//g
3. 按下enter

手機瀏覽器取得geolocation

多數智慧手機都有gps,內建的瀏覽器也大多支援html5 navigator.geolocation
以下為簡單的javascript code來取得手機裝置目前的經緯度
實作範例教學:

if( navigator.geolocation == undefined ){
    alert('裝置不支援');
}else{
    navigator.geolocation.getCurrentPosition(successCallback,errorCallback,{maximumAge:60});
}
function successCallback(position) {
    lat = position.coords.latitude;
    long = position.coords.longitude;
    alert('lat:'+lat+' long:'+long);
}
function errorCallback(error) {
    alert('無法取得位置');
}

facebook php sdk "SSL certificate problem" 解法

使用 facebook php sdk時
有些機器會出現
SSL certificate problem 的錯誤訊息
只要加上以下二行即可
Facebook::$CURL_OPTS[CURLOPT_SSL_VERIFYPEER] = false;
Facebook::$CURL_OPTS[CURLOPT_SSL_VERIFYHOST] = 2;

範例:

include('inc/facebook.php');
$facebook = new Facebook(
    array(
    'appId'  => $facebook_app_key,
    'secret' => $facebook_app_secret,
    'cookie' => true,
    )
);
Facebook::$CURL_OPTS[CURLOPT_SSL_VERIFYPEER] = false;
Facebook::$CURL_OPTS[CURLOPT_SSL_VERIFYHOST] = 2;

2011年4月1日 星期五

手機瀏覽器上使用facebook登入與請求權限

手機瀏覽器畫面大小與一般螢幕不同
只要在login上傳入 display=touch 就可以換成手機版的頁面
display=wap 也可以,以下的code專給大螢幕的手機使用,像iphone
實作範例教學:

include('inc/facebook.php');
$facebook = new Facebook(
    array(
        'appId'  => $facebook_app_key, //appid
        'secret' => $facebook_app_secret, //appsecret
        'cookie' => true,
    )
);

$aLoginParam = array(
    'display' => 'touch' //手機模式畫面
    ,'req_perms' => 'user_checkins' //打卡權限
    ,'cancel_url' => 'http://'.$server.'/facebook/index.php'
);

if( $session = $facebook->getSession() ){
    $fb_id = $facebook->getUser();
    //檢查權限
    try{
        $perm = $facebook->api(array(
        'method' => 'fql.query',
        'query' => 'select user_checkins from permissions where uid='.$fb_id
    ));
    if( $perm[0]['user_checkins'] != '1' ){ //有權限
        $url = $facebook->getLoginUrl($aLoginParam);
        header('Location: '.$url); exit;
    }
    }catch (Exception $e) { }
}else{
    $url = $facebook->getLoginUrl($aLoginParam);
    header('Location: '.$url); exit;
}