幾何学計算アニメーションを作ってみよう

第3回 JavaScript座標回転プログラムをPHPサーバで動画にしてみよう

この記事を読むのに必要な時間:およそ 5 分

前回は,座標計算の説明をしました。座標をドラッグすると,JavaScriptで結果が見れるようにしました。

せっかくJavaScriptでマウスのドラッグを受け付けているのですから,これがそのまま動画にできたら便利ですね。今回はこれに挑戦してみましょう。

JavaScript座標回転プログラムの動作

まず,前回のvector.htmlを見てみましょう。divタグで作られたテキストは,スタイルがposition:absolute;になっています。ですから,スタイルのleftとtopに値を指定することで,任意の位置に動かすことができます。昔はこういうのをスプライトと呼んでいた時代もありました。

リスト1> vector.html

<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN""http://www.w3.org/TR/html4/loose.dtd">
<!-- copy from: http://musicgroupwork.at.webry.info/200701/article_2.html -->
<!-- copy from: http://jsm.suepon.com/script/jsm31.html -->
<html>
<head>
<script type="text/javascript"><!--

handlelist = null;
vectorlist = new Array();


function    vector(container, arrowsize, width, color) {
    this.sx = 0;
    this.sy = 0;
    this.ex = 0;
    this.ey = 0;
    this.polygon = document.createElementNS("http://www.w3.org/2000/svg", "polygon");
    this.polygon.setAttribute("stroke", color);
    this.polygon.setAttribute("fill", "none");
    this.polygon.setAttribute("stroke-width", width);
    container.appendChild(this.polygon);
    
    this.setup = function() {
        this.calc();
        
        var    vx = this.ex - this.sx;
        var    vy = this.ey - this.sy;
        var    point = this.sx + ", " + this.sy;
        point += ", " + this.ex + ", " + this.ey;
        if (vx || vy) {
            var    length = Math.sqrt(vx * vx + vy * vy);
            vx = vx * arrowsize / length;
            vy = vy * arrowsize / length;
            point += ", " + (this.ex - vx - vy / 2);
            point += ", " + (this.ey - vy + vx / 2);
            point += ", " + (this.ex - vx + vy / 2);
            point += ", " + (this.ey - vy - vx / 2);
            point += ", " + this.ex + ", " + this.ey;
        }
        this.polygon.setAttribute("points", point);
    };
    this.calc = function() {
    };
}


function    setupvector() {
    for (var i=0; i<vectorlist.length; i++)
        vectorlist[i].setup();
}


function    setuphandle(obj) {
    obj.onmousedown = function(e) {
        var    offsetX = e.pageX - parseInt(obj.style.left);
        var    offsetY = e.pageY - parseInt(obj.style.top);
        
        document.onmousemove = function(e) {
            obj.style.left = (e.pageX - offsetX) + 'px';
            obj.style.top = (e.pageY - offsetY) + 'px';
            setupvector();
            return false;
        };
        document.onmouseup = function(e) {
            document.onmousemove(e);
            document.onmouseup = null;
            document.onmousemove = null;
            return false;
        };
        document.onmousemove(e);
        return false;
    };
}


window.onload = function() {
    var    obj;
    var    containerObj = document.createElementNS("http://www.w3.org/2000/svg", "svg");
    document.getElementById("canvas").appendChild(containerObj);
    
    handlelist = document.getElementById("canvas").getElementsByTagName("div");
    for (var i=0; i<handlelist.length; i++)
        setuphandle(handlelist[i]);
    
    vectorlist.push(obj = new vector(containerObj, 10, 4, "#00f"));
    obj.calc = function() {
        this.sx = 200;
        this.sy = 200;
        this.ex = parseInt(handlelist[2].style.left);
        this.ey = 200;
    };
    vectorlist.push(obj = new vector(containerObj, 10, 4, "#f00"));
    obj.calc = function() {
        this.sx = parseInt(handlelist[2].style.left);
        this.sy = 200;
        this.ex = parseInt(handlelist[2].style.left);
        this.ey = parseInt(handlelist[2].style.top);
        handlelist[2].innerHTML = "+ (" + ((this.ex - 200) / 100.0) + ", " + ((200 - this.ey) / 100.0) + ")";
    };
    vectorlist.push(obj = new vector(containerObj, 15, 1, "#0ff"));
    obj.calc = function() {
        this.sx = 600;
        this.sy = 200;
        this.ex = parseInt(handlelist[0].style.left);
        this.ey = parseInt(handlelist[0].style.top);
        handlelist[0].innerHTML = "+ (" + ((this.ex - 600) / 100.0) + ", " + ((200 - this.ey) / 100.0) + ")";
    };
    vectorlist.push(obj = new vector(containerObj, 15, 1, "#fa0"));
    obj.calc = function() {
        this.sx = 600;
        this.sy = 200;
        this.ex = parseInt(handlelist[1].style.left);
        this.ey = parseInt(handlelist[1].style.top);
        handlelist[1].innerHTML = "+ (" + ((this.ex - 600) / 100.0) + ", " + ((200 - this.ey) / 100.0) + ")";
    };
    vectorlist.push(obj = new vector(containerObj, 10, 4, "#00f"));
    obj.calc = function() {
        var    vx0 = parseInt(handlelist[0].style.left) - 600;
        var    vy0 = parseInt(handlelist[0].style.top) - 200;
        
        this.sx = this.ex = 600;
        this.sy = this.ey = 200;
        this.ex += (parseInt(handlelist[2].style.left) - 200) * vx0 / 100;
        this.ey += (parseInt(handlelist[2].style.left) - 200) * vy0 / 100;
    };
    vectorlist.push(obj = new vector(containerObj, 10, 4, "#f00"));
    obj.calc = function() {
        var    vx0 = parseInt(handlelist[0].style.left) - 600;
        var    vy0 = parseInt(handlelist[0].style.top) - 200;
        var    vx1 = parseInt(handlelist[1].style.left) - 600;
        var    vy1 = parseInt(handlelist[1].style.top) - 200;
        
        this.sx = 600;
        this.sy = 200;
        this.sx += (parseInt(handlelist[2].style.left) - 200) * vx0 / 100;
        this.sy += (parseInt(handlelist[2].style.left) - 200) * vy0 / 100;
        this.ex = this.sx;
        this.ey = this.sy;
        this.ex += (200 - parseInt(handlelist[2].style.top)) * vx1 / 100;
        this.ey += (200 - parseInt(handlelist[2].style.top)) * vy1 / 100;
    };
    setupvector();
}


// --></script>
<title>vector operation</title>
</head>
<body>
<div id="canvas" style="width:800px; height:400px;">
    <div style="position:absolute; left:700px; top:200px;">+</div>
    <div style="position:absolute; left:600px; top:100px;">+</div>
    <div style="position:absolute; left:250px; top:150px;">+</div>
</div>
<HR>
</body>
</html>

setuphandle関数では,このdivタグにイベントハンドラを登録しています。手間を省くため,クロージャとコールオブジェクトを用いて,setuphandleに渡されたobjをonmousedownの中で使っています。onmousedownのときのマウスの座標をoffsetXとoffsetYという形で保存し,これもonmousemoveの中で使っています。ちなみにparseIntは,スタイルにつく「px」を取り除いて数値にするのに利用しています。

ドラッグされたときは,setupvector関数を呼んで,すべての矢印を計算しなおしています。矢印はオブジェクトを使っており,calcメソッドの中に,矢印ごとの個別の計算処理をあとから登録してあります(JavaScriptでは,new 関数名()とすると,オブジェクトが作られてから関数名()がコンストラクタとして呼ばれます)⁠矢印のものは多角形(SVGのpolygon)で描いています。矢印の矢の座標は,前回解説した座標計算で求めています。

著者プロフィール

木元峰之(きもとみねゆき)

独立系ソフトハウスに8年間勤務,パッケージソフトの開発や記事執筆などを行う。現在はフリーのコンサルタント。SWESTなどのワークショップで分科会のコーディネータを務める。デジタル回路設計歴30年,プログラミング歴27年。

きもと特急電子設計
URL:http://business.pa-i.org/

コメント

コメントの記入