Canvas Zoom

HTML

<canvas id="canvas"></canvas>

CSS

body {
  background: gainsboro;
  margin: 0;
}

canvas {
  background: white;
  box-shadow: 1px 1px 1px rgba(0, 0, 0, .2);
}

JavaScript

var canvas = document.getElementById("canvas");
var context = canvas.getContext("2d");
canvas.width = 600;
canvas.height = 400;

var global = {
  zoom: {
    scale: 1,
    screen: {
      x: 0,
      y: 0,
    },
    world: {
      x: 0,
      y: 0,
    },
  },
};

var mouse = {
  screen: {
    x: 0,
    y: 0,
  },
  world: {
    x: 0,
    y: 0,
  },
};

function zoomed(number) {
  return Math.floor(number * global.zoom.scale);
}

function zoomedX(number) {
  return Math.floor((number - global.zoom.world.x) * global.zoom.scale + global.zoom.screen.x);
}

function zoomedY(number) {
  return Math.floor((number - global.zoom.world.y) * global.zoom.scale + global.zoom.screen.y);
  
}

function zoomedX_INV(number) {
  return Math.floor((number - global.zoom.screen.x) * (1 / global.zoom.scale) + global.zoom.world.x);
}

function zoomedY_INV(number) {
  return Math.floor((number - global.zoom.screen.y) * (1 / global.zoom.scale) + global.zoom.world.y);
}

function draw() {
  context.clearRect(0, 0, canvas.width, canvas.height);
  context.beginPath();
  context.rect(zoomedX(50), zoomedY(50), zoomed(100), zoomed(100));
  context.fillStyle = 'skyblue';
  context.fill();

  context.beginPath();
  context.arc(zoomedX(350), zoomedY(250), zoomed(50), 0, 2 * Math.PI, false);
  context.fillStyle = 'green';
  context.fill();
}

canvas.addEventListener("mousemove", trackMouse);
canvas.addEventListener("wheel", trackWheel);
canvas.addEventListener("wheel", zoom);

function zoom() {
  global.zoom.world.x = mouse.world.x;
  global.zoom.world.y = mouse.world.y;
  global.zoom.screen.x = mouse.screen.x;
  global.zoom.screen.y = mouse.screen.y;
  mouse.world.x = zoomedX_INV(mouse.screen.x);
  mouse.world.y = zoomedY_INV(mouse.screen.y);
  draw();
}

function trackMouse(event) {
  mouse.screen.x = event.clientX;
  mouse.screen.y = event.clientY;
  mouse.world.x = zoomedX_INV(mouse.screen.x);
  mouse.world.y = zoomedY_INV(mouse.screen.y);
}

function trackWheel(e) {
  if (e.deltaY < 0) {
  ...