cropperjs icon indicating copy to clipboard operation
cropperjs copied to clipboard

How i can prenvent cropperselector to overlap on canvas on v2?

Open mjapadilla opened this issue 2 years ago • 4 comments

What is the equivalent of viewMode 1 on version 2?

mjapadilla avatar Sep 12 '22 12:09 mjapadilla

May not support that currently.

PS: As of v2-beta, the cropper canvas is a window, and within the window, it is entirely free.

fengyuanchen avatar Sep 18 '22 07:09 fengyuanchen

这个功能还是有必要的

captainIT avatar Jan 18 '23 02:01 captainIT

I tried canceling the move event on certain conditions (like x or y < 0), but then I realised that is not not exactly true, as there could be image outside of the visible canvas area, so also getting the image size and matrix (for the scaling) does not satisfy the needs completely. I will try other approaches and keep an eye on this thread.

o15a3d4l11s2 avatar Feb 05 '23 22:02 o15a3d4l11s2

If you need restrictions, you can add the logic in the action event listener. This is how I use it in react. This code restricts the selection to the image on "move", "resize" and "scale".

useEffect(() => {
  const cropperCanvas = document.querySelector('cropper-canvas')
  if (!cropperCanvas) return

  cropperCanvas.addEventListener('action', actionHandler)

  return () => {
    cropperCanvas.removeEventListener('action', actionHandler)
  }
}, [])

function actionHandler(event) {
  const cropperCanvas = document.querySelector('cropper-canvas')
  if (!cropperCanvas) return
  const cropperImage = cropperRef.current.getCropperImage()
  if (!cropperImage) return
  const selection = cropperRef.current.getCropperSelection()
  if (!selection) return

  const actionType = event.detail.action
  // Extract image transform matrix
  const matrix = cropperImage.$getTransform()

  // Calculate the actual dimensions and position of the image
  const imageActualWidth = cropperImage.$image.width * matrix[0]
  const imageActualHeight = cropperImage.$image.height * matrix[3]
  const imageActualX = matrix[4] + (cropperImage.$image.width - imageActualWidth) / 2
  const imageActualY = matrix[5] + (cropperImage.$image.height - imageActualHeight) / 2

  // Initialize new position and size with current values
  let newX = selection.x
  let newY = selection.y
  let newWidth = selection.width
  let newHeight = selection.height

  if (actionType === 'move' || actionType === 'scale') {
    // Calculate new position ensuring selection does not exceed image boundaries
    newX = Math.max(imageActualX, Math.min(selection.x, imageActualX + imageActualWidth - selection.width))
    newY = Math.max(imageActualY, Math.min(selection.y, imageActualY + imageActualHeight - selection.height))
    
    if (actionType === 'scale') {
      // Adjust the selection size if the image is scaled
      newWidth = Math.min(newWidth, imageActualWidth)
      newHeight = Math.min(newHeight, imageActualHeight)

      // Adjust selection position again in case resizing has pushed it outside the image
      if (newX + newWidth > imageActualX + imageActualWidth) {
        newX = imageActualX + imageActualWidth - newWidth
      }
      if (newY + newHeight > imageActualY + imageActualHeight) {
        newY = imageActualY + imageActualHeight - newHeight
      }
    }
    
  } else if (actionType.includes('resize')) {
    // Handle specific resize actions here
    if (actionType === 'ne-resize') {
      if (newX + newWidth > imageActualX + imageActualWidth) {
        newWidth = imageActualX + imageActualWidth - newX // Prevent right side from going outside
      }
      // Ensure top edge does not exceed the image boundary
      if (newY < imageActualY) {
        newHeight += newY - imageActualY // Increase height to compensate for the upward movement
        newY = imageActualY
      }
    }

    // Correct resizing for 'sw-resize'
    if (actionType === 'sw-resize') {
      // Ensure bottom edge does not exceed the image boundary
      if (newY + newHeight > imageActualY + imageActualHeight) {
        newHeight = imageActualY + imageActualHeight - newY
      }
      // Adjust newX for 'sw-resize' if necessary (moved to the left beyond image boundary)
      if (newX < imageActualX) {
        newWidth += newX - imageActualX // Adjust width to maintain size while moving left
        newX = imageActualX
      }
    }

    // For north and west resize, adjust newX and newY
    if (actionType === 'n-resize' || actionType === 'nw-resize') {
      if (newY < imageActualY) {
        newHeight += newY - imageActualY // Increase height to compensate for the upward movement
        newY = imageActualY
      }
      newHeight = Math.min(newHeight, imageActualY + imageActualHeight - newY)
    }

    if (actionType === 'w-resize' || actionType === 'nw-resize') {
      if (newX < imageActualX) {
        newWidth += newX - imageActualX // Increase width to compensate for the leftward movement
        newX = imageActualX
      }
      newWidth = Math.min(newWidth, imageActualX + imageActualWidth - newX)
    }

    // Correct newWidth and newHeight for south and east directions to not exceed image boundaries
    if (actionType === 's-resize' || actionType === 'se-resize' || actionType === 'e-resize') {
      if (newX + newWidth > imageActualX + imageActualWidth) {
        newWidth = imageActualX + imageActualWidth - newX
      }
      if (newY + newHeight > imageActualY + imageActualHeight) {
        newHeight = imageActualY + imageActualHeight - newY
      }
    }
  }

  // Ensure selection does not exceed canvas boundaries (optional check for resize)
  if (newX + newWidth > cropperCanvas.clientWidth) {
    newWidth = cropperCanvas.clientWidth - newX
  }
  if (newY + newHeight > cropperCanvas.clientHeight) {
    newHeight = cropperCanvas.clientHeight - newY
  }

  // Update the selection if necessary
  if (newX !== selection.x || newY !== selection.y || newWidth !== selection.width || newHeight !== selection.height) {
    selection.$change(newX, newY, newWidth, newHeight)
  }
}

carlbrn avatar Feb 16 '24 21:02 carlbrn

As of v2.0.0-rc, you can use the <cropper-image> element's transform event to limit image boundaries, or use the <cropper-selection> element's change event to limit selection boundaries.

fengyuanchen avatar May 26 '24 13:05 fengyuanchen