How to Implement Drag and Drop in Matter.js

Implementing drag-and-drop functionality in Matter.js allows users to interact directly with physics bodies inside an HTML5 canvas. This guide covers the essential steps to enable object dragging using Matter.js's built-in Mouse and MouseConstraint modules, providing a straightforward code implementation from initializing the physics engine to capturing user input.

1. Include the Matter.js Library

Before writing JavaScript, load the Matter.js library into your HTML file via a CDN or bundle it using a package manager like npm:

<script src="https://cdnjs.cloudflare.com/ajax/libs/matter-js/0.19.0/matter.min.js"></script>

2. Set Up the Engine, Renderer, and Runner

Initialize the core Matter.js modules: Engine, Render, Runner, and Composite.

const { Engine, Render, Runner, Bodies, Composite, Mouse, MouseConstraint } = Matter;

// Create an engine
const engine = Engine.create();
const world = engine.world;

// Create a renderer
const render = Render.create({
  element: document.body,
  engine: engine,
  options: {
    width: 800,
    height: 600,
    wireframes: false
  }
});

Render.run(render);

// Create runner
const runner = Runner.create();
Runner.run(runner, engine);

3. Add Physics Bodies

Create dynamic bodies that can be dragged, along with static bodies to serve as boundaries (such as a floor and walls).

// Add boundaries (static bodies)
const ground = Bodies.rectangle(400, 590, 810, 30, { isStatic: true });
const leftWall = Bodies.rectangle(5, 300, 30, 600, { isStatic: true });
const rightWall = Bodies.rectangle(795, 300, 30, 600, { isStatic: true });

// Add draggable objects
const boxA = Bodies.rectangle(400, 200, 80, 80, { render: { fillStyle: '#e74c3c' } });
const boxB = Bodies.rectangle(450, 50, 80, 80, { render: { fillStyle: '#3498db' } });
const circle = Bodies.circle(380, 100, 40, { render: { fillStyle: '#2ecc71' } });

// Add all bodies to the world
Composite.add(world, [ground, leftWall, rightWall, boxA, boxB, circle]);

4. Implement Mouse and MouseConstraint

The MouseConstraint module binds user mouse inputs (click, drag, release) or touch inputs to bodies within the simulation.

// Create a mouse input linked to the canvas
const mouse = Mouse.create(render.canvas);

// Create the mouse constraint
const mouseConstraint = MouseConstraint.create(engine, {
  mouse: mouse,
  constraint: {
    stiffness: 0.2,
    render: {
      visible: true // Shows the drag line constraint
    }
  }
});

// Add the mouse constraint to the world
Composite.add(world, mouseConstraint);

// Keep the mouse in sync with rendering
render.mouse = mouse;

5. Handling Events (Optional)

You can listen for interaction events emitted by MouseConstraint to trigger custom behaviors, such as logging when an item is grabbed or dropped:

Matter.Events.on(mouseConstraint, 'startdrag', (event) => {
  console.log('Dragging body:', event.body);
});

Matter.Events.on(mouseConstraint, 'enddrag', (event) => {
  console.log('Released body:', event.body);
});

By linking Mouse.create() to the renderer canvas and applying a MouseConstraint to the engine world, any non-static Matter.js body automatically becomes interactive and responsive to mouse clicks and touch dragging.