0

I am trying to make some 2d circuit simulator. But canvas always scale from 0,0 point. how to achieve screen oriented zooming. I have some html and js code. Help me to solve the zooming or scaling calculation in the zoom function below.

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
    <style>
        canvas {
            border: 1px solid white;
            background-color: black;
        }
        body {
            color: white;
            margin: 0px;
            background-color: black;
        }
    </style>
</head>
<body>
    <canvas id="canvas"></canvas>
    <button onclick="zoom(1)">Zoom+</button>
    <button onclick="zoom(-1)">Zoom-</button>
    <script>
        const canvas = document.getElementById('canvas');
        const ctx = canvas.getContext('2d');
        canvas.width = 960;
        canvas.height = 600;
        var eleMatrix = [];
        var bodyTrans = new DOMMatrix([1, 0, 0, 1, 0, 0]);
        ctx.setTransform(bodyTrans);
        graphPaperDrawer();

       function zoom(p){
       var x;
           var l, t;
           if (p == 1) {
               x = ctx.getTransform().a;
               l = ctx.getTransform().e -480 ;  //- 480)*2;
               t = ctx.getTransform().f -300;  //- 300)*2 ; //  300 * (x * 2 - x);
               x = ctx.getTransform().a*2;
           } else {
               x = ctx.getTransform().a;
               l = ctx.getTransform().e +480;// - 480) / 2;// ctx.getTransform().e //- 480 * (x / 2 - x);
               t = ctx.getTransform().f +360;// - 300) / 2; //ctx.getTransform().f //- 300 * (x / 2 - x);
               x = ctx.getTransform().a/2;
           }
           ctx.setTransform(x, 0, 0, x, l, t);
           graphPaperDrawer();
       }
        dragElement(canvas);
        function dragElement(elmnt) {
            var elpos = [], oldx = 0, oldy = 0, disx = 0, disy = 0, graphxy = [],cusdr, target;
            elmnt.onmousedown = dragMouseDown;
            elmnt.ontouchstart = dragMouseDown;
            function dragMouseDown() {
                event.preventDefault();
                oldx = getXY(event).x;
                oldy = getXY(event).y;
                graphxy = [bodyTrans.e, bodyTrans.f,bodyTrans.a];

                document.onmouseup = closeDragElement;
                document.ontouchend = closeDragElement;
                document.onmousemove = elementDrag;
                document.ontouchmove = elementDrag;
            }
            function elementDrag() {
                event.preventDefault();
                disx = getXY(event).x - oldx;
                disy = getXY(event).y - oldy;
                var subtar = null;
                cusdr = [false];

                    ctx.setTransform(ctx.getTransform().a, 0, 0, ctx.getTransform().a, (graphxy[0] + disx), (graphxy[1] + disy));
                    graphPaperDrawer();
                    elpos = [ctx.getTransform().e,ctx.getTransform().f,ctx.getTransform().a];
            }
            function closeDragElement() {
                 bodyTrans = new DOMMatrix([elpos[2], 0, 0, elpos[2], elpos[0], elpos[1]]);
                document.onmouseup = null;
                document.ontouchend = null;
                document.onmousemove = null;
                document.ontouchmove = null;
                console.log(bodyTrans.e+","+bodyTrans.f)
            }
        }
        function graphPaperDrawer() {   
               var ft = ctx.getTransform().a;
               ctx.clearRect(-ctx.getTransform().e/ft, -ctx.getTransform().f/ft, canvas.width/ft, canvas.height/ft);    
              ctx.fillStyle= "red";
              ctx.fillRect(0, 0, 100, 100);
              ctx.fillStyle = "green";
              ctx.fillRect(860, 0, 100, 100);
              ctx.fillStyle = "blue";
              ctx.fillRect(0, 500, 100, 100);
              ctx.fillStyle = "white";
              ctx.fillRect(480, 300, 100, 100);
            }
                function getXY(event) {
                    const deviceType = window.matchMedia("(pointer: coarse)").matches;
                    var x, y;
                    if (deviceType) {
                        var x = event.touches[0].clientX;
                        var y = event.touches[0].clientY;
                    } else {
                        var x = event.clientX;
                        var y = event.clientY;
                    }
                    return { "x": x, "y": y };
                }
    </script>
</body>
</html>

result of the code expecting image 2 image 2 but got image 3 image 3 I got some hint in this post

Y.Y.
  • 664
  • 1
  • 6
  • 22

1 Answers1

0

For the zoom in/out to keep being centered you should set the translation to canvas half-width/half-height multiplied to the scale factor x: for the zoom in the scale factor of the context after zooming and or the zoom out the context before zooming:

const canvas = document.getElementById('canvas');
const ctx = canvas.getContext('2d');
canvas.width = 960;
canvas.height = 600;
var eleMatrix = [];
var bodyTrans = new DOMMatrix([1, 0, 0, 1, 0, 0]);
ctx.setTransform(bodyTrans);
graphPaperDrawer();

function zoom(p){
    var x;
    var l, t;
    if (p == 1) {
        x = ctx.getTransform().a;
        l = ctx.getTransform().e -480*x;
        t = ctx.getTransform().f -300*x;
        x = x * 2;          
    } else {
        x = ctx.getTransform().a / 2;
        l = ctx.getTransform().e +480 * x; 
        t = ctx.getTransform().f +300 * x;
    }
    ctx.setTransform(x, 0, 0, x, l, t);
    graphPaperDrawer();
}
dragElement(canvas);
function dragElement(elmnt) {
    var elpos = [], oldx = 0, oldy = 0, disx = 0, disy = 0, graphxy = [],cusdr, target;
    elmnt.onmousedown = dragMouseDown;
    elmnt.ontouchstart = dragMouseDown;
    function dragMouseDown() {
        event.preventDefault();
        oldx = getXY(event).x;
        oldy = getXY(event).y;
        graphxy = [bodyTrans.e, bodyTrans.f,bodyTrans.a];
        
        document.onmouseup = closeDragElement;
        document.ontouchend = closeDragElement;
        document.onmousemove = elementDrag;
        document.ontouchmove = elementDrag;
    }
    function elementDrag() {
        event.preventDefault();
        disx = getXY(event).x - oldx;
        disy = getXY(event).y - oldy;
        var subtar = null;
        cusdr = [false];
        
        ctx.setTransform(ctx.getTransform().a, 0, 0, ctx.getTransform().a, (graphxy[0] + disx), (graphxy[1] + disy));
        graphPaperDrawer();
        elpos = [ctx.getTransform().e,ctx.getTransform().f,ctx.getTransform().a];
    }
    function closeDragElement() {
        bodyTrans = new DOMMatrix([elpos[2], 0, 0, elpos[2], elpos[0], elpos[1]]);
        document.onmouseup = null;
        document.ontouchend = null;
        document.onmousemove = null;
        document.ontouchmove = null;
        console.log(bodyTrans.e+","+bodyTrans.f)
    }
}
function graphPaperDrawer() {
    var ft = ctx.getTransform().a;
    ctx.clearRect(-ctx.getTransform().e/ft, -ctx.getTransform().f/ft, canvas.width/ft, canvas.height/ft);
    ctx.fillStyle= "red";
    ctx.fillRect(0, 0, 100, 100);
    ctx.fillStyle = "green";
    ctx.fillRect(860, 0, 100, 100);
    ctx.fillStyle = "blue";
    ctx.fillRect(0, 500, 100, 100);
    ctx.fillStyle = "white";
    ctx.fillRect(480, 300, 100, 100);
}
function getXY(event) {
    const deviceType = window.matchMedia("(pointer: coarse)").matches;
    var x, y;
    if (deviceType) {
        var x = event.touches[0].clientX;
        var y = event.touches[0].clientY;
    } else {
        var x = event.clientX;
        var y = event.clientY;
    }
    return { "x": x, "y": y };
}
canvas {
  border: 1px solid white;
  background-color: black;
}
body {
  color: white;
  margin: 0px;
  background-color: black;
}
<canvas id="canvas"></canvas>
<button onclick="zoom(1)">Zoom+</button>
<button onclick="zoom(-1)">Zoom-</button>
kikon
  • 3,670
  • 3
  • 5
  • 20
  • I recently figured out with more easy ,efficient and productive way with mouse pointer zoom in/out rather than width/2, height/2 . But thanks for you cooperation and suggestion – debarghya mondal Nov 24 '22 at 12:21