Google Maps V3をジェスチャーで制御するコードです。

基本は、mapのdraggableをfalseにして、ジェスチャーでmapをコントロール。

ジェスチャーはスワイプとサークル・ジグザグの認識の3つ。

この3つは、アルゴリズム上まったく異なる図形ってことです(まあ、見た目もまったく違いますが)。

3つを識別するには、以下の2つを検証すれば、ええんじゃないか...と。
   1:開いている/閉じている
   2:多い/少ない
あるいは、補助線の考え方を使えば、一回でいける?
   交点が、1なら線、2なら円、それ以上なら...って。

このアルゴリズムはおいおい考えませう。

以下で紹介しているアルゴリズムのコンセプトは、こんな感じ。
ジェスチャーで取得した点座標列を使って「図形そのもの」を認識するわけではないです。
相対判断ってやつで、ベクトル角を使うのは、これって次元が増えても普通に使えるから。
それに、これを使うと「単位」を意識しなくてすみますし....。角度が「何についてのものか」は任意です。

    相隣り合う3点で鋭角の個数を見る。
    円の場合は、相隣り合う3点の鋭角の個数は0。
    相隣り合う3点の鋭角を複数含むならzigzag
    始点・構成点・終点で角度を見て、広角を持つものは円、鋭角のみ(つまり始点から見て
    他の点が終点の方を向いているだけ)なら円ではない。
で、ロジックを組むときに重要なのは、点座標列は、例えばtapholdのような場合、実に無駄なデータを多く採取して、これが誤差を生みます。
これを排除する仕組みも組み込んでおく必要があります(今回は公開してないですが、ちょっと考えれば簡単)。

このアルゴリズムは、他ページでサッカーゲームのリアルタイム分析で使うことにしよう...と目論んでいます(^^)。
こういうことですね

で、ジグザグの場合はちょっとした「コツ」というか「慣れ」が必要ですが、これもジェスチャーの要素と考えます。

表示サンプルとコード








【index.html】

工事中
コードのベース
<!DOCTYPE HTML>
<html>
<head>
    <title>Route Map</title>
    <meta name="viewport" content="width=device-width, initial-scale=1,minimum-scale=1, maximum-scale=1"> 
    <meta charset="UTF-8">
    <link rel="stylesheet" href="http://code.jquery.com/mobile/1.0.1/jquery.mobile-1.0.1.min.css" />
    <link href="http://www.google.com/uds/css/gsearch.css" type="text/css" rel="stylesheet"/>
    <style type="text/css">
        //
    </style>
    <script src="http://code.jquery.com/jquery-1.6.1.min.js"></script>
    <script type="text/javascript" src="http://maps.google.com/maps/api/js?sensor=true&language=ja"></script>
    <script src="g_script.js"></script>
    <script src="http://code.jquery.com/mobile/1.0.1/jquery.mobile-1.0.1.min.js"></script>
    <script type="text/javascript" charset="utf-8" src="phonegap-1.1.0.js"></script>
    <script type="text/javascript" charset="utf-8" src="SpeechRecognizer.js"></script>
    
    <script type="text/javascript" charset="utf-8">
        //*********************************************
        $(document).ready(function(){
            $("#map_canvas").bind("touchstart", function(event){
                //地図をタップした時の振る舞いを記述
            });
            
            $("#map_canvas").bind("taphold", function(){
                    //地図を長押しした時の振る舞いを記述
            });
        });
        
        var eventEasy_Swipe = function(event){
                gesture_x = [];
            gesture_y = [];
                gesture_index = 0;
            
            //初期位置取得
            var start = {
                time: (new Date()).getTime(),
                coords: [event.touches[0].clientX, event.touches[0].clientY]
            };
            var stop = {};
            
            var tap_move = function(event){
                //指を動かしたときの途中の座標を取得しておく
                gesture_x[gesture_index] = event.touches[0].clientX;
                gesture_y[gesture_index] = event.touches[0].clientY;
                gesture_index++;

                if(!start){
                    return;
                }
                
                //最後の座標取得
                stop = {
                    time: (new Date()).getTime(),
                    coords: [event.touches[0].clientX, event.touches[0].clientY]
                };

                if(Math.abs(start.coords[0] - stop.coords[0]) > 10){
                    event.preventDefault();
                }
            };

            var tap_stop = function(){
                document.getElementById('map_canvas').removeEventListener('touchmove', tap_move, false);
                document.getElementById('map_canvas').removeEventListener('touchend', tap_stop, false);
				
				
				//ジェスチャーのタイプを検出
				var g_type = gestureType();
				
				if (g_type == "circle") {
					//
				} else if (g_type == "swipe") {
					//
				} else if (g_type == "zigzag"){
					//
				}
				
				
                start = stop = undefined;
            };
            /*+++++++++++++++++++++++++++++++++*/
            //
            document.getElementById('map_canvas').addEventListener('touchmove', tap_move, false);
            document.getElementById('map_canvas').addEventListener('touchend', tap_stop, false);
        };
        

        function onDeviceReady() {
            document.getElementById('map_canvas').addEventListener('touchstart', eventEasy_Swipe, false);
                
            } 
        
    </script>

</head>
<body onLoad="initialize()">
    <!-- +++++++++++++++++++++++++++++++++++++++++++ -->
    
    <div data-role="page" id="map" data-theme="b">
        <div data-role="header" id="map_header">
        
        </div>
        
        <div data-role="content" id="map_content" style="width:100%;height:440px;">
            
            
            <div id="map_canvas" style="width:0px;left:0px;height:0px;top:0px;transform-origin:'50% 50%';-moz-transform: rotate(0deg);-webkit-transform: rotate(0deg);transform:rotate(0deg);">
                Google Maps
            </div>
        </div>
        <div data-role="footer" id="map_footer">
            Adv
        </div>
    </div>

</body>
</html>

【g_script.js】

工事中
コードのベース
var map;
var F_latlng;

var gesture_x = [];
var gesture_y = [];
var gesture_index = 0;

function initialize() {
    
    document.addEventListener("deviceready", onDeviceReady, false); 
    
    //
    F_latlng = new google.maps.LatLng(34.6060845921693, 135.3076171875);
    
    var map_Options = {
        zoom: 17,
        center: F_latlng,
        mapTypeId: google.maps.MapTypeId.ROADMAP,
        navigationControl:false,
        draggable:false
    };
    map = new google.maps.Map(document.getElementById("map_canvas"), map_Options);
    
    
    //------------------------------------
    var pageHeight = $(document).height();
    var pageWidth = $(document).width();
    
    var new_width = pageWidth * 2;
    var new_height = pageHeight * 1.5;
    var new_top = -(new_height - pageHeight)/2;
    var new_left = -(new_width - pageWidth)/2;
    //alert(new_width + "/" + new_height + "/" + new_top + "/" + new_left);
    $("#map_canvas").css("height",new_height);
      $("#map_canvas").css("width",new_width);
        $("#map_canvas").css("top",new_top);
        $("#map_canvas").css("left",new_left);
    
    
    
}






function get_angle(x1,y1,x2,y2,x3,y3){
    var ax;
    var ay;
    var cx;
    var cy;
    
    ax = x1 - x2;
    ay = y1 - y2;
    cx = x3 - x2;
    cy = y3 - y2;
    
    var θ = Math.acos(((ax * cx) + (ay * cy)) / (Math.sqrt(ax * ax + ay * ay) * Math.sqrt(cx * cx + cy * cy)));
    var deg = 180 * θ / Math.PI;
    deg = Math.ceil(deg);
    
    return deg;
}






function swipe_map(start_x,start_y,stop_x,stop_y,heading_angle){
    
    //地図が回転している場合
    //start_x,start_y:swipeスタート位置
    //stop_x,stop_y:swipeストップ位置
    //heading_angle:地図の回転角
    
    var rad = heading_angle * (Math.PI / 180);
    
    var start_x_r = start_x * Math.cos(rad) - start_y * Math.sin(rad);
    var start_y_r = start_x * Math.sin(rad) + start_y * Math.cos(rad);
    var stop_x_r = stop_x * Math.cos(rad) - stop_y * Math.sin(rad);
    var stop_y_r = stop_x * Math.sin(rad) + stop_y * Math.cos(rad);
    
    var dis_x = -(stop_x_r - start_x_r);
    var dis_y = -(stop_y_r - start_y_r);
    
    //
    map.panBy(dis_x,dis_y);


}






function gestureType(){
    var gesture_type = "";
    
    var angle_count = 0;
    
    angle_count = check_anglecount();
    
    if (angle_count == 0) {
        var res = check_circle();
        if(res == true){
            gesture_type = "circle";
        }else{
            gesture_type = "swipe";
        }
    }else{
        gesture_type = "zigzag";
    }
    
    return gesture_type;
}


function check_anglecount(){
    var check_angle_count = 0;
    var deg;
    var x1;
    var y1;
    var x2;
    var y2;
    var x3;
    var y3;
    
    for (var i = 0;i < gesture_x.length;i++) {
        if (i < gesture_x.length - 3){
            x1 = gesture_x[i];
            y1 = gesture_y[i];
            x2 = gesture_x[i + 1];
            y2 = gesture_y[i + 1];
            x3 = gesture_x[i + 2];
            y3 = gesture_y[i + 2];
            deg = get_angle(x1,y1,x2,y2,x3,y3);
            
            if (deg < 90) {
                check_angle_count++;
            }
        }
    }
    
    return check_angle_count;
}


function check_circle(){
    var deg;
    var x1;
    var y1;
    var x2;
    var y2;
    var x3;
    var y3;
    //
    if (gesture_x.length < 4) {
        return false;
    }else{
        
        var res = false;
        for (var i = 1;i < gesture_x.length - 1;i++) {
            if (i < gesture_x.length - 3){
                x1 = gesture_x[i];
                y1 = gesture_y[i];
                x2 = gesture_x[0];
                y2 = gesture_y[0];
                x3 = gesture_x[gesture_x.length - 1];
                y3 = gesture_y[gesture_x.length - 1];
                
                deg = get_angle(x1,y1,x2,y2,x3,y3);
                
                if (deg > 90) {
                    res = true;
                    break;
                }
            }
            
        }
        
        return res;
    }
    
}


TOP