Mouse coordinates don't match after Scaling and Panning canvas

前端 未结 1 2011
一整个雨季
一整个雨季 2020-12-29 14:14

I\'m very new to javascript and canvas and I have a program that\'s supposed to detect elements animated on an elliptical path. It later on goes to form a tree.. But this is

相关标签:
1条回答
  • 2020-12-29 14:24

    Using the transformation matrix is useful or even necessary in these circumstances:

    • If you are deeply nesting transformations.
    • If you are altering different drawings with different transforms.
    • If you need interim transformation coordinates.
    • If you are doing transformations involving skew.
    • If you are doing transformations involving rotation.

    But for the simpler case of panning and scaling the entire canvas there is a simpler method.

    First, set up variables to hold the current amount of scaling and panning:

    var scaleFactor=1.00;
    var panX=0;
    var panY=0;
    

    Then use these pan & scale variables to do all your drawings.

    • clear the canvas.
    • save the untransformed canvas state.
    • do translations with the panX variable.
    • do scaling with the scaleFactor variable.
    • draw all your elements as if they were in untranformed space.
    • restore the context to its untransformed state.

    Example code:

    function drawTranslated(){
    
        ctx.clearRect(0,0,cw,ch);
    
        ctx.save();
        ctx.translate(panX,panY);
        ctx.scale(scaleFactor,scaleFactor);
    
        ctx.beginPath();
        ctx.arc(circleX,circleY,15,0,Math.PI*2);
        ctx.closePath();
        ctx.fillStyle=randomColor();
        ctx.fill();
    
        ctx.restore();
    
    }
    

    Now, about mouse coordinates:

    The browser always returns the mouse position in untransformed coordinates. Your drawings have been done in transformed space. If you want to know where your mouse is in transformed space, you can convert untransformed mouse coordinates to transformed coordinates like this:

    var mouseXTransformed = (mouseX-panX) / scaleFactor;
    var mouseYTransformed = (mouseY-panY) / scaleFactor;
    

    Here is example code and a Demo: http://jsfiddle.net/m1erickson/HwNp3/

    <!doctype html>
    <html>
    <head>
    <link rel="stylesheet" type="text/css" media="all" href="css/reset.css" /> <!-- reset css -->
    <script type="text/javascript" src="http://code.jquery.com/jquery.min.js"></script>
    <style>
        body{ background-color: ivory; }
        #canvas{border:1px solid red;}
    </style>
    <script>
    $(function(){
    
        var canvas=document.getElementById("canvas");
        var ctx=canvas.getContext("2d");
        var $canvas=$("#canvas");
        var canvasOffset=$canvas.offset();
        var offsetX=canvasOffset.left;
        var offsetY=canvasOffset.top;
        var scrollX=$canvas.scrollLeft();
        var scrollY=$canvas.scrollTop();
        var cw=canvas.width;
        var ch=canvas.height;
    
        var scaleFactor=1.00;
        var panX=0;
        var panY=0;
    
        var circleX=150;
        var circleY=150;
    
        var $screen=$("#screen");
        var $transformed=$("#transformed");
        var $trx=$("#trx");
    
        drawTranslated();
    
        $("#canvas").mousemove(function(e){handleMouseMove(e);});
        $("#scaledown").click(function(){ scaleFactor/=1.1; drawTranslated(); });
        $("#scaleup").click(function(){ scaleFactor*=1.1; drawTranslated(); });
        $("#panleft").click(function(){ panX-=10; drawTranslated(); });
        $("#panright").click(function(){ panX+=10; drawTranslated(); });
    
    
        function drawTranslated(){
            ctx.clearRect(0,0,cw,ch);
    
            ctx.save();
            ctx.translate(panX,panY);
            ctx.scale(scaleFactor,scaleFactor);
    
            ctx.beginPath();
            ctx.arc(circleX,circleY,15,0,Math.PI*2);
            ctx.closePath();
            ctx.fillStyle=randomColor();
            ctx.fill();
    
            ctx.restore();
    
            $trx.text("Pan: "+panX+", Scale: "+scaleFactor);
        }
    
        function handleMouseMove(e){
            e.preventDefault();
            e.stopPropagation();
    
            var mouseX=parseInt(e.clientX-offsetX);
            var mouseY=parseInt(e.clientY-offsetY);
    
            var mouseXT=parseInt((mouseX-panX)/scaleFactor);
            var mouseYT=parseInt((mouseY-panY)/scaleFactor);
    
            $screen.text("Screen Coordinates: "+mouseX+"/"+mouseY);
    
            $transformed.text("Transformed Coordinates: "+mouseXT+"/"+mouseYT);
        }
    
        function randomColor(){ 
            return('#'+Math.floor(Math.random()*16777215).toString(16));
        }
    
    }); // end $(function(){});
    </script>
    </head>
    <body>
        <h3>Transformed coordinates are mouseXY in transformed space.<br>The circles center is always at translated [150,150]</h3>
        <h4 id=screen>Screen Coordinates:</h4>
        <h4 id=transformed>Transformed Coordinates:</h4>
        <h4 id=trx>Pan & Scale</h4>
        <button id=scaledown>Scale Down</button>
        <button id=scaleup>Scale Up</button>
        <button id=panleft>Pan Left</button>
        <button id=panright>Pan Right</button><br>
        <canvas id="canvas" width=350 height=400></canvas>
    </body>
    </html>
    
    0 讨论(0)
提交回复
热议问题