Skip to content
Advertisement

Zoom to specific rectangle multiple times using css matrix3d

I am trying to create a zooming image tool and for this I am using matrix3d with glMAtrix https://glmatrix.net/

I have the following components:

  • canvas (black) which represents the final view
  • smaller resizable rectangle (red) inside canvas
  • an image inside a div (blue with text) behind the canvas which at the beginning has the same position and dimension as the canvas

The idea is that when after I resized the red rectangle I should zoom the image from the smaller rectangle to be full screen in the final view, I have manged to do so for the first time, but then next time when I try to rezoom it translate badly.

enter image description here

If I release the red rectangle the zoom should be done so that I can see what is in red rectangle, fully in the black rectangle.

Here is what I have tried:

_updateViewPortZoom () {
  const imageRect = $('.crop-editor-image').get(0).getBoundingClientRect()
  const zoomLevel = imageRect.width / this._cropRect.getScaledWidth()

  const trans = this._getReversCordsImage({
    x: -this._cropRect.left,
    y: -this._cropRect.top
  });

  translateCurrentMatrix(trans)
  scaleCurrentMatrix([zoomLevel, zoomLevel, 1])
}

_getReversCordsImage(point) {
      const matrix = this.options.stylesBuilder.getCurrentMatrix(PREVIEW_SELECTOR)
  
      const vec = glMatrix.vec3.fromValues(point.x, point.y, 0)
      const invertedMatrix = glMatrix.mat4.create()

      glMatrix.mat4.invert(invertedMatrix, matrix)
      glMatrix.vec3.transformMat4(vec, vec, invertedMatrix)

      return vec
 }

By the way translate and scale are in a deeper component so I mocked them, but they basically do this:

 case constants.SCALE: {
          const scaleMatrix = glMatrix.mat4.create();
          glMatrix.mat4.scale(scaleMatrix, scaleMatrix, parameter);
          glMatrix.mat4.multiply(matrix, scaleMatrix, matrix);
          break
        }
        case constants.TRANSLATE: {
          const translateMatrix = glMatrix.mat4.create();
          glMatrix.mat4.translate(translateMatrix, translateMatrix, parameter);
          glMatrix.mat4.multiply(matrix, translateMatrix, matrix);
          break
        }

My idea is to try to transform the left top point of red rectangle to image coordinates and then to do a translate and scale.

Any idea on how can I do this differently using matrix3d? Or if you know some examples where I can see how to zoom to a rectangle. Thanks.

Advertisement

Answer

I’ve manage to found a solution:

At the end I don’t need to convert the point to another coordinates using matrix invert, but since the matrix is multiplied each time I can use the left top position of small rectangle, relative to the viewport canvas (black) and translate the image to there and then scale.

And the zoom level should be based on the view port (black rect) divided by small rect (not the image!)

const zoomLevel = this.options.canvasWidth / this._cropRect.getScaledWidth()

translateCurrentMatrix([-this._cropRect.left, -this._cropRect.top, 0])
scaleCurrentMatrix([zoomLevel, zoomLevel, 1])

That’s all, and it works perfectly with multiple scales.

User contributions licensed under: CC BY-SA
6 People found this is helpful
Advertisement