Skip to content Skip to sidebar Skip to footer

Javascript/canvas, Map Style Point Zooming

I have a canvas with a bunch of objects. I have a zoom function that bumps up a zoom variable by which every coordinate is multiplied. I want to be able to point at a coordinate an

Solution 1:

Scale at coordinate

If given a screen coordinate that has scaled content you need to move the origin towards or away from that point at an amount that matches the zoom.

If you zoom in the origin moves towards the position of the mouse. and zoom out away.

So with the mouse get the x,y position and depending on the wheel direction the amount to zoom in or out

// e is the mouse wheel eventconst x = e.offsetX;
const y = e.offsetY;
const amount = e.wheelDelta > 0 ?  1.1 : 1 / 1.1; 

Then you apply that to the current scale and move the origin to match

scale *= amount;  // the new scale// move the origin
origin.x = x - (x - origin.x) * amount;
origin.y = y - (y - origin.y) * amount;

You can then set the 2D position and scale with

ctx.setTransform(scale, 0, 0, scale, origin.x, origin.y);

Example

Below is a simple view example using bits of the code from your fiddle.

The object view keeps track of the current view and maintains a matrix that can be applied to the canvas.

const ctx = canvas.getContext("2d");
canvas.width = 500;
canvas.height = 500;
constrandI = (min, max = min + (min = 0)) => (Math.random() * (max - min) + min) | 0;
constrand = (min, max = min + (min = 0)) => Math.random() * (max - min) + min;

const objects = [];
for (let i = 0; i < 100; i++) {
  objects.push({
    x: rand(canvas.width),
    y: rand(canvas.height),
    w: rand(40),
    h: rand(40),
    col: `rgb(${randI(255)},${randI(255)},${randI(255)})`,
  });
}
canvas.addEventListener("mousewheel", onmousewheel, false);
canvas.addEventListener("DOMMouseScroll", onmousewheel, false);
requestAnimationFrame(drawCanvas); // this will call drawcanvas after all other code has runconst view = (() => {
  const matrix = [1, 0, 0, 1, 0, 0]; // current view transformvar m = matrix; // alias for clear codevar scale = 1; // current scalevar ctx; // reference to the 2D contextconst pos = { x: 0, y: 0 }; // current position of originvar dirty = true;
  constAPI = {
    setContext(_ctx) { ctx = _ctx; dirty = true },
    apply() {
      if (dirty) { this.update() }
      ctx.setTransform(m[0], m[1], m[2], m[3], m[4], m[5])
    },
    getScale() { return scale },
    getPosition() { return pos },
    isDirty() { return dirty },
    update() {
      dirty = false;
      m[3] = m[0] = scale;
      m[2] = m[1] = 0;
      m[4] = pos.x;
      m[5] = pos.y;
    },
    scaleAt(at, amount) { // at in screen coordsif (dirty) { this.update() }
      scale *= amount;
      pos.x = at.x - (at.x - pos.x) * amount;
      pos.y = at.y - (at.y - pos.y) * amount;
      dirty = true;
    },
  };
  returnAPI;
})();
view.setContext(ctx);

functiondrawCanvas() {
  if (view.isDirty()) { // has the view changed, then draw all
    ctx.setTransform(1, 0, 0, 1, 0, 0); // default transform for clear
    ctx.clearRect(0, 0, canvas.width, canvas.height);
    view.apply(); // set the 2D context transform to the viewfor (i = 0; i < objects.length; i++) {
      var obj = objects[i];
      ctx.fillStyle = obj.col;
      ctx.fillRect(obj.x, obj.y, obj.h, obj.h);
    }
  }

  requestAnimationFrame(drawCanvas);
}

functiononmousewheel(event) {
  var e = window.event || event;
  var x = e.offsetX;
  var y = e.offsetY;
  const delta = e.type === "mousewheel" ? e.wheelDelta : -e.detail;
  if (delta > 0) { view.scaleAt({x, y}, 1.1) }
  else { view.scaleAt({x, y}, 1 / 1.1) }
  e.preventDefault();
}
#canvas {
  border: 2px solid;
}
<canvasid="canvas"></canvas>

Post a Comment for "Javascript/canvas, Map Style Point Zooming"