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'));