7

HTML 5 キャンバスに描画されたベクトルに基づいて、最初のほぼ複雑なマップを作成しようとしています。

スケーリングを除いて、うまく機能します。次のことに気付きました。

  • Firefox では、すべてが正常に動作します (マウスホイールを除くが、これはテスト用です)。
  • Chrome では、マウスホイールを使用して倍率 < 1 にズームアウトすると、描画されるたびに画像が複製されるように見えます
  • Android と iOS では、ズーム ジェスチャを使用すると、最大の問題があります。画像が再描画されるたびに画像が複製されます。

最初は私のせいだと思いました。キャンバスがクリアされないのかもしれません。しかし、いくつかのテストの後、「ゴースト」が消え、新しいゴーストが表示されます。

誰かが助けてくれたら最高です。

コード - HTML:

<div>
    <div style="position:absolute;top:30px;z-index:102;">
        <canvas id="canvas" width="1386" height="747" style="position:absolute;"></canvas>
    </div>
    <div style="position:absolute; top:30px;" id="debugText">Debug</div>
    <div style="position:absolute;top:30px; visibility: hidden;">
        <canvas id="debugCanvas" width="1386" height="747"></canvas>
    </div>
    <div style="position:absolute; left: 200px;z-index:99;" id="debugContols">
        &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
        <a href="#" onClick="javascript:zoomIn(0, 0, 0.5);">Zoom 0.5</a>
        <a href="#" onClick="javascript:zoomIn(0, 0, 2);">Zoom 2</a>
        <a href="#" onClick="javascript:zoomIn(0, 0, 3);">Zoom 3</a>
    </div>
</div>

コード - Javascript:

var canvas = document.getElementById("canvas");
var debugCanvas = document.getElementById("debugCanvas");
var ctx = canvas.getContext("2d");
var ctxDebug = debugCanvas.getContext("2d");
var context = ctx;
var scale = 1;
var originx = 0;
var originy = 0;

function draw() {
    // plne/Straen
[find drawing in fiddle, since its too long]
}

this.onmousewheel = function(event) {
    var mousex = event.clientX - canvas.offsetLeft;
    var mousey = event.clientY - canvas.offsetTop;
    var wheel = event.wheelDelta/120;//n or -n

    //according to Chris comment
    var zoom = Math.pow(1 + Math.abs(wheel)/2 , wheel > 0 ? 1 : -1);

    zoomIn(mousex, mousey, zoom);
    return;
}

var isZooming = false;
var distances = new Array();

function touchStart(e) {
    preventDefaultScroll(e);
    if(e.touches.length > 1 && isZooming == false) {
        var touch1 = event.touches[0];
        var touch2 = event.touches[1];

        x1 = touch1.pageX;
        y1 = touch1.pageY;
        x2 = touch2.pageX;
        y2 = touch2.pageY;

        var diffX = x2 - x1;
        var diffY = y2 - y1;

        var centerX = x1 + diffX/2;
        var centerY = y1 + diffY/2;

        //$("#debugText").text(centerX + " " + centerY);
        debugCanvas.width = debugCanvas.width;
        ctxDebug.beginPath();
        ctxDebug.arc(centerX, centerY, 20, 0, 2 * Math.PI, false);
        ctxDebug.fillStyle = 'green';
        ctxDebug.fill();
        ctxDebug.lineWidth = 5;
        ctxDebug.strokeStyle = '#003300';
        ctxDebug.stroke();

        zoomCenterX = centerX;
        zoomCenterY = centerY;

        var touch1 = event.touches[0];
        var touch2 = event.touches[1];

        x1 = touch1.pageX;
        y1 = touch1.pageY;
        x2 = touch2.pageX;
        y2 = touch2.pageY;

        var distanz = dist(x1,y1,x2,y2);
        lastDistance = distanz;

        distanceInterval = setInterval(checkDistance,50);
        isZooming = true;
    }
}

    var distanceInterval;
    var zoomCenterX;
    var zoomCenterY;
    var lastDistance = 0;
    function checkDistance()
    {
    $("#debugText").text("checkDist");
        if(distances.length == 0) return;





        var distanceGesamt = 0;

        for(var i = 0; i < distances.length; i++)
        {
            distanceGesamt += distances[i];
        }


        var distanceDurchschnitt = distanceGesamt / distances.length;


        var curDist = distanceDurchschnitt - lastDistance;

        var zoomFac = 1 + (curDist / 100);

        $("#debugText").text(distanceDurchschnitt + " " + zoomFac);

        distances = new Array();


        zoomIn(zoomCenterX, zoomCenterY, zoomFac)
        lastDistance = distanceDurchschnitt;
    }

    function touchEnd(e)
    {
        if(e.touches.length < 2)
        {
            isZooming = false;
            clearInterval(distanceInterval);

        }
    }

    function dist(x1,y1,x2,y2)
     {
        return Math.sqrt((x1 -= x2) * x1 + (y1 -= y2) * y1);
     }

    function touchMove(e)
    {
        if(isZooming)
        {
            var touch1 = event.touches[0];
            var touch2 = event.touches[1];

            x1 = touch1.pageX;
            y1 = touch1.pageY;
            x2 = touch2.pageX;
            y2 = touch2.pageY;

            var distanz = dist(x1,y1,x2,y2);
            distances.push(distanz);
        }
    }

    function preventDefaultScroll(event) {
        event.preventDefault();
        window.scroll(0,0);
        return false;
    } 



    canvas.addEventListener('gestureend', function(e) {
        if (e.scale < 1.0) {
            // User moved fingers closer together
        } else if (e.scale > 1.0) {
            // User moved fingers further apart
        }
    }, false);

    function zoomIn(mousex, mousey, zoom)
    {

        canvas.style.display = 'none';
        context.translate(
            originx,
            originy
        );
        context.scale(zoom,zoom);
        context.translate(
            -( mousex / scale + originx - mousex / ( scale * zoom ) ),
            -( mousey / scale + originy - mousey / ( scale * zoom ) )
        );

        originx = ( mousex / scale + originx - mousex / ( scale * zoom ) );
        originy = ( mousey / scale + originy - mousey / ( scale * zoom ) );
        scale *= zoom;





         requestAnimFrame(function() {
            context.clearRect(0,0,canvas.width,canvas.height);
              draw();
        });


        canvas.style.display = 'block';
        //context.clearRect(0,0,canvas.width,canvas.height);
    }

    $(document).ready(function() {
        draw();
        addEventListener('touchstart', touchStart, true);
        addEventListener('touchmove', touchMove, true);
        addEventListener('touchend', touchEnd, true);
        addEventListener('touchcancel', touchEnd, true);


    });
    window.requestAnimFrame = (function(){
      return  window.requestAnimationFrame       ||
              window.webkitRequestAnimationFrame ||
              window.mozRequestAnimationFrame    ||
              function( callback ){
                window.setTimeout(callback, 1000 / 60);
              };
    })();

これがフィドルです

4

2 に答える 2

5

さて、あなたのコードで最初に見つかった問題は、コンテキスト変換を行っているときにcontext代わりに使用していたことだったので、それを修正しました。ctx

次に、 をclearRect関数の先頭に移動し、コンテキストが既に変換された後に描画しました。

最後に、まだ下部にマップが少し複製されていたのでclearRect、キャンバスの実際の高さの 2 倍をクリアするように変更しましたcanvas.height*2

JSFiddle

于 2013-06-07T16:59:30.843 に答える
3

2つの考え:

最初: うわー、マップをレイアウトするためのパスの素晴らしい使用--非常に広範囲です!

2番目:マウスクリックではなくスクロールホイール/タッチでズームを操作しているため、 requestAnimFrame アニメーションを削除する必要があります。

アニメーションは、ユーザーがマウスをクリックしたポイントに徐々にズームすることを意図していました。

于 2013-06-07T15:46:47.903 に答える