

// 角度の正規化 deg [-360, 360] -> [-180, 180]
function normalze_deg(a) {
    ans = 0;
    if (a) {
        ans = (a + 360) % 360;
        if (ans > 180) ans -= 360;
        if (ans < -180) ans += 360;
    }
    return Math.floor(ans);  // 整数に丸める
}

const COMPASS_X = 70; // コンパスの中心 X
const COMPASS_Y = 70; // コンパスの中心 y
const TRANSLATE_X_Y = '' + COMPASS_X + ' ' + COMPASS_Y;
const ROTATE_CENTER = ' ' + COMPASS_X + ' ' + COMPASS_Y;
const CR1 = 40; // 外側の円の半径
const CR2 = 20; // 内側の円の半径
const AXIS_PATH = Raphael.format(
    'M -{0},0 L {0},0 M 0,-{0} L 0,{0}', CR1 + 4);
const RECT_PATH = Raphael.format(
    'M 0,-{0} L {0},0 L 0,{0} L -{0},0 L 0,-{0} L 0,{0}', CR1);
const T_SIZE = 20.0;  // 文字列サイズ
const TX = CR1 + T_SIZE * 0.8; // 文字位置の X

const MX = -2, MY = -2; // 計算方法は？
var ROOT_COMPASS; // コンパスのコンテナ

var current_deg = 0;

//===================================
function draw_compass(paper, root, draw_handler) {
    ROOT_COMPASS = root;

    // 回転させるコンパスの要素
    var compass_objs = new Array();

    const dirs = [{
        'text': 'N',
        'dir': 0
    },
    {
        'text': 'E',
        'dir': 90
    },
    {
        'text': 'W',
        'dir': -90
    },
    {
        'text': 'S',
        'dir': 180
    }
    ];

    var north_t; // "North" の Text 要素。(コンパス回転の基準)
    for (var i in dirs) {
        var x = paper.text(0, - TX, dirs[i]['text']).attr({
            'font-size': T_SIZE,
            rotation: dirs[i]['dir'] + ' 0 0',
            translation: TRANSLATE_X_Y
        });
        compass_objs.push(x);
        if (i === '0') north_t = x;
    }
    // 外側の円
    var c1 = paper.circle(0, 0, CR1).attr({
        gradient: '90-#00F-#F00',
        translation: TRANSLATE_X_Y,
        rotation: '0' + ROTATE_CENTER,
        cursor: 'crosshair'
    });
    // 内側の円
    var c2 = paper.circle(0, 0, CR2).attr({
        translation: TRANSLATE_X_Y,
        fill: '#FFF'
    });
    // 固定軸
    var axis = paper.path(AXIS_PATH).attr({
        'stroke-width': 1,
        stroke: '#666',
        translation: TRANSLATE_X_Y,
        rotation: '0' + ROTATE_CENTER
    });

    // 回転軸
    var rect = paper.path(RECT_PATH).attr({
        translation: TRANSLATE_X_Y,
        rotation: '0' + ROTATE_CENTER
    });

    compass_objs.push(c1);
    compass_objs.push(rect);

    // マウスイベント取得エリア
    var c0 = paper.circle(0, 0, CR1).attr({
        translation: TRANSLATE_X_Y,
        opacity: 0.0,
        fill: '#00F',
        cursor: 'crosshair'
    });
    c0.click(compass_handler);
    c0.drag(
        function(dx, dy, x1, y1) {// move
            // TODO: 画面がスクロールされている場合に対応すること。
            var b = ROOT_COMPASS.getBoundingClientRect();
            var x = x1 - b.left + MX;
            var y = y1 - b.top + MY;

            var angle = normalze_deg(
                Raphael.angle(x, y, COMPASS_X, COMPASS_Y) + 90);
            compass_handler_angle(angle, false);
        },
        function() {// start
            this.attr({
                'opacity' : 0.2
            });
        },
        function() {// end
            this.attr({
                'opacity' : 0.0
            });
        }
        );

    function compass_handler(event) {
        var b = ROOT_COMPASS.getBoundingClientRect();
        var x = event.clientX - b.left + MX;
        var y = event.clientY - b.top + MY;
        // alert(x + ',' + y);
        var angle = normalze_deg(
            Raphael.angle(x, y, COMPASS_X, COMPASS_Y) + 90);
        compass_handler_angle(angle, true);
    }

    function compass_handler_angle(angle, is_animate) {

        current_deg = Number(north_t.attr('rotation').split(' ')[0]);
        const delta = normalze_deg(angle - current_deg);
        //alert('' + current_deg + ', delta: ' + delta );

        if (Math.abs(delta) < 2) return;

        var speed = 0;
        if (is_animate) {
            // See http://kichon.net/wiki/wiki.cgi?page=Raphael#p2
            const effect = 'backOut';
            speed = 500 + 1000 * Math.abs(1.0 * delta / 180);
            for (var i in compass_objs) {
                var ang = Number(
                    compass_objs[i].attr('rotation').split(' ')[0]);
                compass_objs[i].animate({
                    rotation: ang + delta + ROTATE_CENTER
                }, speed, effect);
            }
        } else {
            for (var i in compass_objs) {
                var ang = Number(
                    compass_objs[i].attr('rotation').split(' ')[0]);
                compass_objs[i].attr({
                    rotation: ang + delta + ROTATE_CENTER
                });
            }
        }

        draw_handler(current_deg, delta, is_animate, speed * 0.8);
        current_deg = normalze_deg(current_deg + delta);
        show_angle();
    }
}
//==========================
