<canvas id="full-canvas"></canvas>
<canvas id="prev-canvas"></canvas>
html, body {
  height: 100%;
}
body {
  margin: 0;
}

canvas {
  position: absolute;
  width: 100%;
  height: 100%;
}

#prev-canvas {
  width: 128px;
  height: 128px;
  top: 20px;
  left: 20px;
  outline: 2px solid red;
  pointer-events: none;
}
const imageUrl =
  "https://images.unsplash.com/photo-1548681528-6a5c45b66b42?ixlib=rb-1.2.1&ixid=eyJhcHBfaWQiOjEyMDd9&auto=format&fit=crop&w=1024&q=90";

const previewScale = 1.5;

// const dpr = window.devicePixelRatio || 1;
const dpr = 2;

const canvas = document.getElementById("full-canvas");
canvas.width = window.innerWidth * dpr;
canvas.height = window.innerHeight * dpr;
const ctx = canvas.getContext("2d");

const canvasPrev = document.getElementById("prev-canvas");
canvasPrev.width = 128 * dpr;
canvasPrev.height = 128 * dpr;
const ctxPrev = canvasPrev.getContext("2d");

ctx.scale(dpr, dpr);
ctxPrev.scale(dpr, dpr);

function draw(image) {
  const iw = image.naturalWidth;
  const ih = image.naturalHeight;
  ctx.clearRect(0, 0, canvas.width, canvas.height);

  ctx.drawImage(
    image,
    ...coverImage(window.innerWidth, window.innerHeight, iw, ih)
  );
}

loadImg(imageUrl).then((image) => {
  draw(image);

  window.addEventListener("resize", () => {
    canvas.width = window.innerWidth * dpr;
    canvas.height = window.innerHeight * dpr;
    ctx.scale(dpr, dpr);
    draw(image);
  });

  canvas.addEventListener("mousemove", (event) => {
    const x = event.clientX * dpr;
    const y = event.clientY * dpr;
    const invScale = previewScale <= 0 ? 0 : 1 / previewScale;

    ctxPrev.clearRect(0, 0, canvasPrev.width, canvasPrev.height);
    ctxPrev.drawImage(
      canvas,
      x - (canvasPrev.width / 2) * invScale,
      y - (canvasPrev.height / 2) * invScale,
      canvasPrev.width * invScale,
      canvasPrev.height * invScale,
      0,
      0,
      canvasPrev.width / dpr,
      canvasPrev.height / dpr
    );
  });
});

// ========== utils ==========

function loadImg(src) {
  return new Promise((resolve) => {
    const img = new Image();
    img.addEventListener("load", () => resolve(img));
    // img.crossOrigin = 'Anonymous';
    img.src = src;
  });
}

function coverImage(tSizeX, tSizeY, iSizeX, iSizeY, pivotX = 0.5, pivotY = 0.5) {
  const ratio = Math.max(tSizeX / iSizeX, tSizeY / iSizeY);

  const dw = iSizeX * ratio;
  const dh = iSizeY * ratio;
  const dx = (tSizeX - dw) * pivotX;
  const dy = (tSizeY - dh) * pivotY;

  return [0, 0, iSizeX, iSizeY, dx, dy, dw, dh];
}

External CSS

This Pen doesn't use any external CSS resources.

External JavaScript

This Pen doesn't use any external JavaScript resources.