0

Hello I want to crop an image using canvas, but when the image is not on the top of the page, but has a margin or other elements before on the page, the result will get incorrect and has a wrong offset of the margin. I think it is a bad practice to substract the offset. Do I have to wrap the content in a special way or are my position attributes wrong?

the relevant function is cropMedia.

function cropMedia(media, {
  stretch = 1,
  left = 0,
  top = 0,
  width,
  height 
} = {}) {
  const croppedCanvas = document.createElement('canvas');

  croppedCanvas.width = width;
  croppedCanvas.height = height;
  const ctx = croppedCanvas.getContext('2d');

  ctx.drawImage(media, left, top, width, height, 0, 0, width * stretch, height * stretch);

  return croppedCanvas;
}

Here is my codepen for more relevant code: http://codepen.io/anon/pen/YqNaow

thank you ver much

klanm
  • 3,168
  • 3
  • 19
  • 22

1 Answers1

1

Pay attention to mouseup. You try to get correct top and left values for fixed element, but its top and left properties of style calculated by the viewport of browser (not by the top and left of document). This is correct code.

class CanvasCrop {
  constructor(media) {
    let x1 = 0;
    let y1 = 0;
    let x2 = 0;
    let y2 = 0;
    let dragThreshold = 50;

    let mousedown = false;
    let dragging = false;

    const selectionRect = document.getElementById('selectionRect');

    function reCalc() {
      var x3 = Math.min(x1, x2);
      var x4 = Math.max(x1, x2);
      var y3 = Math.min(y1, y2);
      var y4 = Math.max(y1, y2);
      selectionRect.style.left = x3 + 'px';
      selectionRect.style.top = y3 + 'px';
      selectionRect.style.width = x4 - x3 + 'px';
      selectionRect.style.height = y4 - y3 + 'px';
    }

    function cropMedia(media, {
      stretch = 1,
      left = 0,
      top = 0,
      width,
      height 
    } = {}) {
      const croppedCanvas = document.createElement('canvas');

      croppedCanvas.width = width;
      croppedCanvas.height = height;
      const ctx = croppedCanvas.getContext('2d');

      ctx.drawImage(media, left, top, width, height, 0, 0, width * stretch, height * stretch);

      return croppedCanvas;
    }

    media.onmousedown = function(e) {
      mousedown = true;
      selectionRect.hidden = 0;
      x1 = e.clientX;
      y1 = e.clientY;
    };
    onmousemove = function(e) {
      //todo implement isDragging
      if (mousedown) {
        x2 = e.clientX;
        y2 = e.clientY;
        var deltaX = Math.abs(x2 - x1);
        var deltaY = Math.abs(x2 - x1);
        reCalc();
        if (deltaX > dragThreshold || deltaY > dragThreshold) dragging = true;
      }
    };
    onmouseup = (e) => {
      var pic = document.getElementById('pic');
      var offsetTop = pic.offsetTop;
      var offsetLeft = pic.offsetLeft;
      var scrollTop = document.body.scrollTop || document.documentElement.scrollTop;
      var scrollLeft = document.body.scrollLeft || document.documentElement.scrollLeft;
      scrollTop -= offsetTop;
      scrollLeft -= offsetLeft;
      selectionRect.hidden = 1;
      mousedown = false;
      if (dragging) {
        dragging = false;

        let croppedCanvas = cropMedia(media, {
          left: parseInt(selectionRect.style.left, 10) + scrollLeft,
          top: parseInt(selectionRect.style.top, 10) + scrollTop,
          width: parseInt(selectionRect.style.width, 10),
          height: parseInt(selectionRect.style.height, 10)
        });
        const preview = document.getElementById('preview');
        preview.innerHTML = '';
        preview.appendChild(croppedCanvas);
      }
    };
  }
}

const cc = new CanvasCrop(document.getElementById('pic'));
Dmitriy
  • 3,745
  • 16
  • 24
  • wow thank you very much for the explanation. It works flawlessly. One more question, why do you use documentElement as an alternative fallback? isn't there always a body? thanks – klanm Mar 17 '16 at 21:56
  • In some old browsers root element(html) was scrolling instead of body. – Dmitriy Mar 17 '16 at 22:02
  • @DmitriyLoskutov, isn't it the inverse ? In some old browsers body was scrolling instead of root element(html) . Btw do you know how old are these browsers? Was the canvas tag already supported? – Kaiido Mar 18 '16 at 10:45
  • 1
    Yep, so that's what I said, no canvas in quirks mode and `document.body.scrollTop` is the deprecated one. You're doing it wrong but thanks for the link. – Kaiido Mar 18 '16 at 10:52