FabricJs zoom image in canvas

by mmalex

HTML

<script src="https://cdnjs.cloudflare.com/ajax/libs/fabric.js/2.6.0/fabric.js"></script>
<div class="canvas-wrapper">
  <canvas id="c"></canvas>
</div>
<div style="position: fixed; z-index: 999; font-size: 12pt; padding: 12px;">
  Scroll me!
</div>

CSS

body {
  padding: 0;
  margin: 0;
  font-family: consolas;
  font-size: 12px;
}

.canvas-wrapper {
  position: absolute;
  top: 0;
  bottom: 0;
  width: 100%;
  height: 100%;
  background-color: transparent;
}

#c {
  position: absolute;
  top: 0;
  bottom: 0;
  left: 0;
  right: 0;
  width: 100%;
  height: 100%;
}

JavaScript

var canvasEl = document.getElementById("c");
canvasEl.width = canvasEl.parentElement.offsetWidth;
canvasEl.height = canvasEl.parentElement.offsetHeight;

var canvas = new fabric.Canvas('c');
canvas.hoverCursor = 'default';

// add background image, or watermark
var backgroundImg;
fabric.Image.fromURL("http://mbnsay.com/rayys/images/bricks_background.jpg", function(oImg) {
  oImg.set({
    left: 0,
    top: 0,
    centeredScaling: true,
    lockMovementX: true,
    lockMovementY: true,
    hasControls: false
  });

  // remember our background, to ignore mouse events over it
  backgroundImg = oImg;

  canvas.add(oImg);
  canvas.sendToBack(oImg);
  canvas.renderAll();
});

// add some zoomable image
fabric.Image.fromURL("http://mbnsay.com/rayys/images/Super_Paper_Mario_MoP_1.png", function(oImg) {
  const initialMarioScale = 0.5;
  oImg.set({
    left: 100,
    top: 100,
    lockMovementX: true,
    lockMovementY: true,
    scaleX: initialMarioScale,
    scaleY: initialMarioScale,
    centeredScaling: true,
    hasControls: false,
  });
  
  oImg.on('mousewheel', function(options) {
      var scrollDirection = options.e.deltaY > 0 ? -1 : 1;
      console.log(options.deltaY, scrollDirection);

      //find scrolled image
      let target = canvas.findTarget(options.e.target);

      //next code updates mario scale by +/- 5%
      var marioScale = target.scaleX;
      marioScale += scrollDirection * 0.05;

      var scaledWidth = target.getScaledWidth();
      var scaledHeight = target.getScaledHeight();

      //remember where center of the image
      var oldCenter = new fabric.Point(
        target.left + scaledWidth / 2,
        target.top + scaledHeight / 2);

      target.scale(marioScale);

      //after scale center moved, we need to re-center back to old center
      var newScaledWidth = target.getScaledWidth();
      var newScaledHeight = target.getScaledHeight();

      target.left = oldCenter.x - newScaledWidth / 2;
      target.top = oldCenter.x -...