When you move the cursor outside the image, the mousedown event is lost.

How to create the right handler ?
How to prevent crop out of the image?
How to add the ability to change the size of the crop , with crop_image 256х160 ?

 input = document.querySelector('.box input'); input.onchange = function() { image = new Image(); image.src = window.URL.createObjectURL(this.files[0]); this.parentNode.style = 'display: none'; document.querySelector('.box').innerHTML += "<div class='original_image'>" + image.outerHTML + "<div class='crop' style='margin: 0px 0px'></div></div>" + "<div class='crop_image'>" + image.outerHTML + "</div>"; crop = document.querySelector('.crop'); crop_image = document.querySelector('.crop_image img'); crop.onmousedown = function() { this.onmousemove = function(e) { this.style.marginTop = parseInt(this.style.marginTop) + e.movementY + 'px'; this.style.marginLeft = parseInt(this.style.marginLeft) + e.movementX + 'px'; crop_image.style.marginTop = '-' + this.style.marginTop; crop_image.style.marginLeft = '-' + this.style.marginLeft; return false; } this.onmouseup = function() { this.onmousemove = null; } } } 
 .box { position: relative; width: 768px; height: 256px; background: #FFF; box-shadow: 0 1px 1px 0 rgba(0, 0, 0, .3); padding: 2px; } .select { position: absolute; width: 100%; cursor: pointer; line-height: 256px; text-align: center; font-family: Segoe UI; font-size: 20px; font-weight: 300; color: #C7254E; } .original_image img { max-height: 256px; } .original_image { position: relative; float: left; overflow: hidden; max-height: 256px; margin-right: 2px; } .crop { position: absolute; top: 0; width: 256px; height: 160px; box-shadow: 0 0 0 512px rgba(0, 0, 0, .4); cursor: move; } .crop_image img { max-height: 256px; } .crop_image { width: 256px; height: 160px; overflow: hidden; } 
 <div class='box'> <label class='select'><a>выбрать изображение</a> <input type='file' accept='image/*' style='display: none'> </label> </div> 

shitListener

    2 answers 2

    It is necessary to monitor the cropping shift inside the block with the image and not to let it go beyond the frame width.

     input = document.querySelector('.box input'); input.onchange = function() { image = new Image(); image.src = window.URL.createObjectURL(this.files[0]); this.parentNode.style = 'display: none'; document.querySelector('.box').innerHTML += "<div class='original_image'>" + image.outerHTML + "<div class='crop' style='margin: 0px 0px'></div></div>" + "<div class='crop_image'>" + image.outerHTML + "</div>"; function getOffset(el) { var _x = 0; var _y = 0; while (el && !isNaN(el.offsetLeft) && !isNaN(el.offsetTop)) { _x += el.offsetLeft - el.scrollLeft; _y += el.offsetTop - el.scrollTop; el = el.offsetParent; } return { top: _y, left: _x }; } image.addEventListener("load", function() { var original = document.querySelector('.original_image'); var min_left = 0; var min_top = 0; var max_right = original.offsetWidth; var max_bottom = original.offsetHeight; crop = document.querySelector('.crop'); crop_image = document.querySelector('.crop_image img'); crop.onmousedown = function() { this.onmousemove = function(e) { var top = ((parseInt(this.style.marginTop) + e.movementY) < min_top) ? min_top : (parseInt(this.style.marginTop) + e.movementY); if (top + crop.offsetHeight > max_bottom) { top -= (top + crop.offsetHeight) - max_bottom; } this.style.marginTop = top + 'px'; var left = ((parseInt(this.style.marginLeft) + e.movementX) < min_left) ? min_left : (parseInt(this.style.marginLeft) + e.movementX); if (left + crop.offsetWidth > max_right) { left -= (left + crop.offsetWidth) - max_right; } this.style.marginLeft = left + 'px'; crop_image.style.marginTop = '-' + this.style.marginTop; crop_image.style.marginLeft = '-' + this.style.marginLeft; return false; } this.onmouseup = function() { this.onmousemove = null; this.onmouseleave = null; this.onmouseup = null; } this.onmouseleave = function() { this.onmousemove = null; this.onmouseleave = null; this.onmouseup = null; } } }); } 
     .box { position: relative; width: 768px; height: 256px; background: #FFF; box-shadow: 0 1px 1px 0 rgba(0, 0, 0, .3); padding: 2px; } .select { position: absolute; width: 100%; cursor: pointer; line-height: 256px; text-align: center; font-family: Segoe UI; font-size: 20px; font-weight: 300; color: #C7254E; } .original_image img { max-height: 256px; } .original_image { position: relative; float: left; overflow: hidden; max-height: 256px; margin-right: 2px; } .crop { position: absolute; top: 0; width: 256px; height: 160px; box-shadow: 0 0 0 512px rgba(0, 0, 0, .4); cursor: move; } .crop_image img { max-height: 256px; } .crop_image { width: 256px; height: 160px; overflow: hidden; } 
     <div class='box'> <label class='select'><a>выбрать изображение</a> <input type='file' accept='image/*' style='display: none'> </label> </div> 

    • From above and to the left it works, but from below and to the right it remains as before. Is it possible to do something on all sides, taking into account that the crop will vary in size? - Mr. Black
    • @Doofy yes, I was sealed there in a hurry. :) var max_right = image.width; var max_bottom = image.height; var max_right = image.width; var max_bottom = image.height; Here I take a frame on the size of the image, and the block, which you need to limit, is less in reality. Just need to fix these two variables. I corrected the example. - SlyDeath
    • Restrictions work, and when you pull the crop out of the picture and return, I don’t hold the mouse button anymore, and crop follows the cursor. Actually it was the main question) - Mr. Black
    • @Doofy updated and fixed your problem. You just need to reset events not only on the mouse, but also on leaving the mouse out of the area - this.onmouseleave - SlyDeath
    • Superski, works. Resize crop, I think I will do it myself. ATP Veri Big - Mr. Black

    Save in some variable coordinates of the edges for crop_image (can be obtained through offcet parameters: Xmin - offsetLeft, Xmax - offsetLeft + offsetWidth, etc.), something like craya = {Xmin: 22, Xmax: 222, Ymin: 123 , Ymax: 433}

    Next, in onmousemove, compare the position of the cursor with craya.Xmin, craya.Xmax, etc. - moreover, put the check before assigning the value: i.e. if (mouseX> = Xmin && mouseY> = Ymin && mouseX <= Xmax && mouseY <= Ymax), then the assignment of values ​​occurs, otherwise - nothing happens (do not forget, you may need an amendment to scrolling)