1
votes

My issue is this:

I used Matter.js to create a dragabble object on a canvas. But when I scale the canvas my mouse clicks don't drag the object anymore because the clicks are miscalculated due to scaling. Matter.js still thinks the canvas is not scaled. So I have to click next to the object to actually drag it. And the more I scale the more off I have to go with my click from the object. What do I have to do to correct Matter.js that the canvas has been scaled ?

<body>
    <script>
        let Engine = Matter.Engine,
        Render = Matter.Render,
        World = Matter.World,
        Bodies = Matter.Bodies;

        let engine = Engine.create();
        let render = Render.create({
            element: document.body,
            engine: engine
        });

        Engine.run(engine);
        Render.run(render);
            

        let floor = Bodies.rectangle(0, 500, 600, 10, { isStatic: true });
        let ball = Bodies.circle(200, 10, 40);
        World.add(engine.world, [ball, floor]);


        render.canvas.width = 1000;
        render.canvas.height = 800;

        render.canvas.style.transformOrigin = '0 0';
        render.canvas.style.transform = 'scale(.8)';

        let world = engine.world;
        let Mouse = Matter.Mouse;
        let MouseConstraint = Matter.MouseConstraint;
        let mouse = Mouse.create(render.canvas);
        let mouseConstraint = MouseConstraint.create(engine, { mouse: mouse });
        World.add(world, mouseConstraint);
        render.mouse = mouse;
    </script>
</body>

screenshot

Kind regards, Slawek

1
Refraining from scaling the canvas seems like the clearest solution. A good rule of thumb for a canvas that's being rendered by some other library is to mess with its CSS properties as little as possible.ggorlen
If I cannot scale the canvas I cannot make my project the way I want. It would turn up side down everything.Slawomir Jakubek
That seems awfully rigid and I'm struggling to imagine a use case where it's not possible to use canvas width/height instead of a CSS scale. In any case, if Matter.Mouse.setScale(mouse, scale) doesn't help, maybe convert and set the mouse coordinates yourself using Matter.Mouse.setOffset(mouse, offset). I don't expect that Matter.js should understand and be able to adapt to arbitrary canvas transformations, so keeping in mind what could break, probably the way to go is to run it totally headlessly, then adapt what's going on in the engine to your canvas and do the rendering yourself.ggorlen
Great that worked! Thank You so much! If you post that as an answer instead of a comment I can select it as a correct answer. Scaling mouse in direct proportion to the canvas was not as easy as I thought. It took me a while to figure that out, so if anyone needs that, it is: let mouseScale = 1 + (1 / (canvasScale / (1 - canvasScale))); this.Mouse.setScale(this.mouse, {x: mouseScale, y: mouseScale}); I still have other problems so I hope You can help me with them too.Slawomir Jakubek
Great to hear! Since you came up with the solution and have code that works, I recommend you post the answer and accept it. For your other problems, I'd open new questions so that each one is specific/searchable for future users.ggorlen

1 Answers

0
votes

Thanks to the ggorlen the answer is:

Use Matter.Mouse.setScale(mouse, scale);

There you need to supply the right scale, but how would you know that having only the initial scale you used to scale the canvas? The formula is below:

set scale(scale){
        
    let mouseScale = 1 + (1 / (scale / (1 - scale)))
        
    this.Mouse.setScale(this.mouse, {x: mouseScale, y: mouseScale});
}