Canvasを使用して画像をフォーマットする





この記事では HTML5, , , .



- . , . , .



canvas , , . , , .



. . , , . , .



!





:

<img class="resize-image" src="image.jpg" alt="Image" />







! HTML .



CSS

CSS- . resize-container



.



.resize-container { position: relative; display: inline-block; cursor: move; margin: 0 auto; } .resize-container img { display: block } .resize-container:hover img, .resize-container:active img { outline: 2px dashed rgba(222,60,80,.9); }







'resize handles'. , , .



.resize-handle-ne, .resize-handle-ne, .resize-handle-se, .resize-handle-nw, .resize-handle-sw { position: absolute; display: block; width: 10px; height: 10px; background: rgba(222,60,80,.9); z-index: 999; } .resize-handle-nw { top: -5px; left: -5px; cursor: nw-resize; } .resize-handle-sw { bottom: -5px; left: -5px; cursor: sw-resize; } .resize-handle-ne { top: -5px; right: -5px; cursor: ne-resize; } .resize-handle-se { bottom: -5px; right: -5px; cursor: se-resize; }







JavaScript

Canvas.



var resizeableImage = function(image_target) { var $container, orig_src = new Image(), image_target = $(image_target).get(0), event_state = {}, constrain = false, min_width = 60, min_height = 60, max_width = 800, max_height = 900, resize_canvas = document.createElement('canvas'); }); resizeableImage($('.resize-image'));







, . , , . jQuery , .



var resizeableImage = function(image_target) { // ... init = function(){ // Create a new image with a copy of the original src // When resizing, we will always use this original copy as the base orig_src.src=image_target.src; // Add resize handles $(image_target).wrap('<div class="resize-container"></div>') .before('<span class="resize-handle resize-handle-nw"></span>') .before('<span class="resize-handle resize-handle-ne"></span>') .after('<span class="resize-handle resize-handle-se"></span>') .after('<span class="resize-handle resize-handle-sw"></span>'); // Get a variable for the container $container = $(image_target).parent('.resize-container'); // Add events $container.on('mousedown', '.resize-handle', startResize); }; //... init(); }







startResize



endResize



, , .



startResize = function(e){ e.preventDefault(); e.stopPropagation(); saveEventState(e); $(document).on('mousemove', resizing); $(document).on('mouseup', endResize); }; endResize = function(e){ e.preventDefault(); $(document).off('mouseup touchend', endResize); $(document).off('mousemove touchmove', resizing); };







. event_state



.



saveEventState = function(e){ // Save the initial event details and container state event_state.container_width = $container.width(); event_state.container_height = $container.height(); event_state.container_left = $container.offset().left; event_state.container_top = $container.offset().top; event_state.mouse_x = (e.clientX || e.pageX || e.originalEvent.touches[0].clientX) + $(window).scrollLeft(); event_state.mouse_y = (e.clientY || e.pageY || e.originalEvent.touches[0].clientY) + $(window).scrollTop(); // This is a fix for mobile safari // For some reason it does not allow a direct copy of the touches property if(typeof e.originalEvent.touches !== 'undefined'){ event_state.touches = []; $.each(e.originalEvent.touches, function(i, ob){ event_state.touches[i] = {}; event_state.touches[i].clientX = 0+ob.clientX; event_state.touches[i].clientY = 0+ob.clientY; }); } event_state.evnt = e; }







resizing



- . . .



resizing = function(e){ var mouse={},width,height,left,top,offset=$container.offset(); mouse.x = (e.clientX || e.pageX || e.originalEvent.touches[0].clientX) + $(window).scrollLeft(); mouse.y = (e.clientY || e.pageY || e.originalEvent.touches[0].clientY) + $(window).scrollTop(); width = mouse.x - event_state.container_left; height = mouse.y - event_state.container_top; left = event_state.container_left; top = event_state.container_top; if(constrain || e.shiftKey){ height = width / orig_src.width * orig_src.height; } if(width > min_width && height > min_height && width < max_width && height < max_height){ resizeImage(width, height); // Without this Firefox will not re-calculate the the image dimensions until drag end $container.offset({'left': left, 'top': top}); } }







Shift .



.



: , , resizeImage



.





Canvas , drawImage



. , . toDataURL



Base64-encoded .



.



resizeImage = function(width, height){ resize_canvas.width = width; resize_canvas.height = height; resize_canvas.getContext('2d').drawImage(orig_src, 0, 0, width, height); $(image_target).attr('src', resize_canvas.toDataURL("image/png")); };







? : , CORS . , 'tainted canvas'.







. . , . , .



, , .







, . resizing



:



resizing = function(e){ var mouse={},width,height,left,top,offset=$container.offset(); mouse.x = (e.clientX || e.pageX || e.originalEvent.touches[0].clientX) + $(window).scrollLeft(); mouse.y = (e.clientY || e.pageY || e.originalEvent.touches[0].clientY) + $(window).scrollTop(); // Position image differently depending on the corner dragged and constraints if( $(event_state.evnt.target).hasClass('resize-handle-se') ){ width = mouse.x - event_state.container_left; height = mouse.y - event_state.container_top; left = event_state.container_left; top = event_state.container_top; } else if($(event_state.evnt.target).hasClass('resize-handle-sw') ){ width = event_state.container_width - (mouse.x - event_state.container_left); height = mouse.y - event_state.container_top; left = mouse.x; top = event_state.container_top; } else if($(event_state.evnt.target).hasClass('resize-handle-nw') ){ width = event_state.container_width - (mouse.x - event_state.container_left); height = event_state.container_height - (mouse.y - event_state.container_top); left = mouse.x; top = mouse.y; if(constrain || e.shiftKey){ top = mouse.y - ((width / orig_src.width * orig_src.height) - height); } } else if($(event_state.evnt.target).hasClass('resize-handle-ne') ){ width = mouse.x - event_state.container_left; height = event_state.container_height - (mouse.y - event_state.container_top); left = event_state.container_left; top = mouse.y; if(constrain || e.shiftKey){ top = mouse.y - ((width / orig_src.width * orig_src.height) - height); } } // Optionally maintain aspect ratio if(constrain || e.shiftKey){ height = width / orig_src.width * orig_src.height; } if(width > min_width && height > min_height && width < max_width && height < max_height){ // To improve performance you might limit how often resizeImage() is called resizeImage(width, height); // Without this Firefox will not re-calculate the the image dimensions until drag end $container.offset({'left': left, 'top': top}); } }







, resize-handle



, .





, , , , , "". . .



init = function(){ //... $container.on('mousedown', 'img', startMoving); }







startMoving



endMoving



, startResize



endResize



.



startMoving = function(e){ e.preventDefault(); e.stopPropagation(); saveEventState(e); $(document).on('mousemove', moving); $(document).on('mouseup', endMoving); }; endMoving = function(e){ e.preventDefault(); $(document).off('mouseup', endMoving); $(document).off('mousemove', moving); };







moving



. , .



moving = function(e){ var mouse={}; e.preventDefault(); e.stopPropagation(); mouse.x = (e.clientX || e.pageX) + $(window).scrollLeft(); mouse.y = (e.clientY || e.pageY) + $(window).scrollTop(); $container.offset({ 'left': mouse.x - ( event_state.mouse_x - event_state.container_left ), 'top': mouse.y - ( event_state.mouse_y - event_state.container_top ) }); };









, , . , , , , . , , , , .



HTML :



<div class="overlay"> <div class="overlay-inner"> </div> </div> <button class="btn-crop js-crop">Crop</button>







, , .



.overlay { position: absolute; left: 50%; top: 50%; margin-left: -100px; margin-top: -100px; z-index: 999; width: 200px; height: 200px; border: solid 2px rgba(222,60,80,.9); box-sizing: content-box; pointer-events: none; } .overlay:after, .overlay:before { content: ''; position: absolute; display: block; width: 204px; height: 40px; border-left: dashed 2px rgba(222,60,80,.9); border-right: dashed 2px rgba(222,60,80,.9); } .overlay:before { top: 0; margin-left: -2px; margin-top: -40px; } .overlay:after { bottom: 0; margin-left: -2px; margin-bottom: -40px; } .overlay-inner:after, .overlay-inner:before { content: ''; position: absolute; display: block; width: 40px; height: 204px; border-top: dashed 2px rgba(222,60,80,.9); border-bottom: dashed 2px rgba(222,60,80,.9); } .overlay-inner:before { left: 0; margin-left: -40px; margin-top: -2px; } .overlay-inner:after { right: 0; margin-right: -40px; margin-top: -2px; } .btn-crop { position: absolute; vertical-align: bottom; right: 5px; bottom: 5px; padding: 6px 10px; z-index: 999; background-color: rgb(222,60,80); border: none; border-radius: 5px; color: #FFF; }







JavaScript :



init = function(){ //... $('.js-crop').on('click', crop); }; crop = function(){ var crop_canvas, left = $('.overlay').offset().left - $container.offset().left, top = $('.overlay').offset().top - $container.offset().top, width = $('.overlay').width(), height = $('.overlay').height(); crop_canvas = document.createElement('canvas'); crop_canvas.width = width; crop_canvas.height = height; crop_canvas.getContext('2d').drawImage(image_target, left, top, width, height, 0, 0, width, height); window.open(crop_canvas.toDataURL("image/png")); }







crop



resizeImage



. , .



drawImage



canvas. - . - , . - , canvas, .





. .



mousedown



mouseup



- touchstart



touchend



, mousemove



touchmove



. , touchup



touchdown



( ).



touchstart



touchend



, mousedown



, mouseup



touchmove



, mousemove



.



// In init()... $container.on('mousedown touchstart', '.resize-handle', startResize); $container.on('mousedown touchstart', 'img', startMoving); //In startResize() ... $(document).on('mousemove touchmove', moving); $(document).on('mouseup touchend', endMoving); //In endResize()... $(document).off('mouseup touchend', endMoving); $(document).off('mousemove touchmove', moving); //In startMoving()... $(document).on('mousemove touchmove', moving); $(document).on('mouseup touchend', endMoving); //In endMoving()... $(document).off('mouseup touchend', endMoving); $(document).off('mousemove touchmove', moving);







, "" . Hammer, . , , .



, , , saveEventState



. .



" " . , . moving



:



moving = function(e){ var mouse={}, touches; e.preventDefault(); e.stopPropagation(); touches = e.originalEvent.touches; mouse.x = (e.clientX || e.pageX || touches[0].clientX) + $(window).scrollLeft(); mouse.y = (e.clientY || e.pageY || touches[0].clientY) + $(window).scrollTop(); $container.offset({ 'left': mouse.x - ( event_state.mouse_x - event_state.container_left ), 'top': mouse.y - ( event_state.mouse_y - event_state.container_top ) }); // Watch for pinch zoom gesture while moving if(event_state.touches && event_state.touches.length > 1 && touches.length > 1){ var width = event_state.container_width, height = event_state.container_height; var a = event_state.touches[0].clientX - event_state.touches[1].clientX; a = a * a; var b = event_state.touches[0].clientY - event_state.touches[1].clientY; b = b * b; var dist1 = Math.sqrt( a + b ); a = e.originalEvent.touches[0].clientX - touches[1].clientX; a = a * a; b = e.originalEvent.touches[0].clientY - touches[1].clientY; b = b * b; var dist2 = Math.sqrt( a + b ); var ratio = dist2 /dist1; width = width * ratio; height = height * ratio; // To improve performance you might limit how often resizeImage() is called resizeImage(width, height); } };







.







. .



Chrome "", Firefox .



, .








要素を使用して画像のサイズ変更とトリミングを行う方法を学習 HTML5, , , .



- . , . , .



canvas , , . , , .



. . , , . , .



!





:

<img class="resize-image" src="image.jpg" alt="Image" />







! HTML .



CSS

CSS- . resize-container



.



.resize-container { position: relative; display: inline-block; cursor: move; margin: 0 auto; } .resize-container img { display: block } .resize-container:hover img, .resize-container:active img { outline: 2px dashed rgba(222,60,80,.9); }







'resize handles'. , , .



.resize-handle-ne, .resize-handle-ne, .resize-handle-se, .resize-handle-nw, .resize-handle-sw { position: absolute; display: block; width: 10px; height: 10px; background: rgba(222,60,80,.9); z-index: 999; } .resize-handle-nw { top: -5px; left: -5px; cursor: nw-resize; } .resize-handle-sw { bottom: -5px; left: -5px; cursor: sw-resize; } .resize-handle-ne { top: -5px; right: -5px; cursor: ne-resize; } .resize-handle-se { bottom: -5px; right: -5px; cursor: se-resize; }







JavaScript

Canvas.



var resizeableImage = function(image_target) { var $container, orig_src = new Image(), image_target = $(image_target).get(0), event_state = {}, constrain = false, min_width = 60, min_height = 60, max_width = 800, max_height = 900, resize_canvas = document.createElement('canvas'); }); resizeableImage($('.resize-image'));







, . , , . jQuery , .



var resizeableImage = function(image_target) { // ... init = function(){ // Create a new image with a copy of the original src // When resizing, we will always use this original copy as the base orig_src.src=image_target.src; // Add resize handles $(image_target).wrap('<div class="resize-container"></div>') .before('<span class="resize-handle resize-handle-nw"></span>') .before('<span class="resize-handle resize-handle-ne"></span>') .after('<span class="resize-handle resize-handle-se"></span>') .after('<span class="resize-handle resize-handle-sw"></span>'); // Get a variable for the container $container = $(image_target).parent('.resize-container'); // Add events $container.on('mousedown', '.resize-handle', startResize); }; //... init(); }







startResize



endResize



, , .



startResize = function(e){ e.preventDefault(); e.stopPropagation(); saveEventState(e); $(document).on('mousemove', resizing); $(document).on('mouseup', endResize); }; endResize = function(e){ e.preventDefault(); $(document).off('mouseup touchend', endResize); $(document).off('mousemove touchmove', resizing); };







. event_state



.



saveEventState = function(e){ // Save the initial event details and container state event_state.container_width = $container.width(); event_state.container_height = $container.height(); event_state.container_left = $container.offset().left; event_state.container_top = $container.offset().top; event_state.mouse_x = (e.clientX || e.pageX || e.originalEvent.touches[0].clientX) + $(window).scrollLeft(); event_state.mouse_y = (e.clientY || e.pageY || e.originalEvent.touches[0].clientY) + $(window).scrollTop(); // This is a fix for mobile safari // For some reason it does not allow a direct copy of the touches property if(typeof e.originalEvent.touches !== 'undefined'){ event_state.touches = []; $.each(e.originalEvent.touches, function(i, ob){ event_state.touches[i] = {}; event_state.touches[i].clientX = 0+ob.clientX; event_state.touches[i].clientY = 0+ob.clientY; }); } event_state.evnt = e; }







resizing



- . . .



resizing = function(e){ var mouse={},width,height,left,top,offset=$container.offset(); mouse.x = (e.clientX || e.pageX || e.originalEvent.touches[0].clientX) + $(window).scrollLeft(); mouse.y = (e.clientY || e.pageY || e.originalEvent.touches[0].clientY) + $(window).scrollTop(); width = mouse.x - event_state.container_left; height = mouse.y - event_state.container_top; left = event_state.container_left; top = event_state.container_top; if(constrain || e.shiftKey){ height = width / orig_src.width * orig_src.height; } if(width > min_width && height > min_height && width < max_width && height < max_height){ resizeImage(width, height); // Without this Firefox will not re-calculate the the image dimensions until drag end $container.offset({'left': left, 'top': top}); } }







Shift .



.



: , , resizeImage



.





Canvas , drawImage



. , . toDataURL



Base64-encoded .



.



resizeImage = function(width, height){ resize_canvas.width = width; resize_canvas.height = height; resize_canvas.getContext('2d').drawImage(orig_src, 0, 0, width, height); $(image_target).attr('src', resize_canvas.toDataURL("image/png")); };







? : , CORS . , 'tainted canvas'.







. . , . , .



, , .







, . resizing



:



resizing = function(e){ var mouse={},width,height,left,top,offset=$container.offset(); mouse.x = (e.clientX || e.pageX || e.originalEvent.touches[0].clientX) + $(window).scrollLeft(); mouse.y = (e.clientY || e.pageY || e.originalEvent.touches[0].clientY) + $(window).scrollTop(); // Position image differently depending on the corner dragged and constraints if( $(event_state.evnt.target).hasClass('resize-handle-se') ){ width = mouse.x - event_state.container_left; height = mouse.y - event_state.container_top; left = event_state.container_left; top = event_state.container_top; } else if($(event_state.evnt.target).hasClass('resize-handle-sw') ){ width = event_state.container_width - (mouse.x - event_state.container_left); height = mouse.y - event_state.container_top; left = mouse.x; top = event_state.container_top; } else if($(event_state.evnt.target).hasClass('resize-handle-nw') ){ width = event_state.container_width - (mouse.x - event_state.container_left); height = event_state.container_height - (mouse.y - event_state.container_top); left = mouse.x; top = mouse.y; if(constrain || e.shiftKey){ top = mouse.y - ((width / orig_src.width * orig_src.height) - height); } } else if($(event_state.evnt.target).hasClass('resize-handle-ne') ){ width = mouse.x - event_state.container_left; height = event_state.container_height - (mouse.y - event_state.container_top); left = event_state.container_left; top = mouse.y; if(constrain || e.shiftKey){ top = mouse.y - ((width / orig_src.width * orig_src.height) - height); } } // Optionally maintain aspect ratio if(constrain || e.shiftKey){ height = width / orig_src.width * orig_src.height; } if(width > min_width && height > min_height && width < max_width && height < max_height){ // To improve performance you might limit how often resizeImage() is called resizeImage(width, height); // Without this Firefox will not re-calculate the the image dimensions until drag end $container.offset({'left': left, 'top': top}); } }







, resize-handle



, .





, , , , , "". . .



init = function(){ //... $container.on('mousedown', 'img', startMoving); }







startMoving



endMoving



, startResize



endResize



.



startMoving = function(e){ e.preventDefault(); e.stopPropagation(); saveEventState(e); $(document).on('mousemove', moving); $(document).on('mouseup', endMoving); }; endMoving = function(e){ e.preventDefault(); $(document).off('mouseup', endMoving); $(document).off('mousemove', moving); };







moving



. , .



moving = function(e){ var mouse={}; e.preventDefault(); e.stopPropagation(); mouse.x = (e.clientX || e.pageX) + $(window).scrollLeft(); mouse.y = (e.clientY || e.pageY) + $(window).scrollTop(); $container.offset({ 'left': mouse.x - ( event_state.mouse_x - event_state.container_left ), 'top': mouse.y - ( event_state.mouse_y - event_state.container_top ) }); };









, , . , , , , . , , , , .



HTML :



<div class="overlay"> <div class="overlay-inner"> </div> </div> <button class="btn-crop js-crop">Crop</button>







, , .



.overlay { position: absolute; left: 50%; top: 50%; margin-left: -100px; margin-top: -100px; z-index: 999; width: 200px; height: 200px; border: solid 2px rgba(222,60,80,.9); box-sizing: content-box; pointer-events: none; } .overlay:after, .overlay:before { content: ''; position: absolute; display: block; width: 204px; height: 40px; border-left: dashed 2px rgba(222,60,80,.9); border-right: dashed 2px rgba(222,60,80,.9); } .overlay:before { top: 0; margin-left: -2px; margin-top: -40px; } .overlay:after { bottom: 0; margin-left: -2px; margin-bottom: -40px; } .overlay-inner:after, .overlay-inner:before { content: ''; position: absolute; display: block; width: 40px; height: 204px; border-top: dashed 2px rgba(222,60,80,.9); border-bottom: dashed 2px rgba(222,60,80,.9); } .overlay-inner:before { left: 0; margin-left: -40px; margin-top: -2px; } .overlay-inner:after { right: 0; margin-right: -40px; margin-top: -2px; } .btn-crop { position: absolute; vertical-align: bottom; right: 5px; bottom: 5px; padding: 6px 10px; z-index: 999; background-color: rgb(222,60,80); border: none; border-radius: 5px; color: #FFF; }







JavaScript :



init = function(){ //... $('.js-crop').on('click', crop); }; crop = function(){ var crop_canvas, left = $('.overlay').offset().left - $container.offset().left, top = $('.overlay').offset().top - $container.offset().top, width = $('.overlay').width(), height = $('.overlay').height(); crop_canvas = document.createElement('canvas'); crop_canvas.width = width; crop_canvas.height = height; crop_canvas.getContext('2d').drawImage(image_target, left, top, width, height, 0, 0, width, height); window.open(crop_canvas.toDataURL("image/png")); }







crop



resizeImage



. , .



drawImage



canvas. - . - , . - , canvas, .





. .



mousedown



mouseup



- touchstart



touchend



, mousemove



touchmove



. , touchup



touchdown



( ).



touchstart



touchend



, mousedown



, mouseup



touchmove



, mousemove



.



// In init()... $container.on('mousedown touchstart', '.resize-handle', startResize); $container.on('mousedown touchstart', 'img', startMoving); //In startResize() ... $(document).on('mousemove touchmove', moving); $(document).on('mouseup touchend', endMoving); //In endResize()... $(document).off('mouseup touchend', endMoving); $(document).off('mousemove touchmove', moving); //In startMoving()... $(document).on('mousemove touchmove', moving); $(document).on('mouseup touchend', endMoving); //In endMoving()... $(document).off('mouseup touchend', endMoving); $(document).off('mousemove touchmove', moving);







, "" . Hammer, . , , .



, , , saveEventState



. .



" " . , . moving



:



moving = function(e){ var mouse={}, touches; e.preventDefault(); e.stopPropagation(); touches = e.originalEvent.touches; mouse.x = (e.clientX || e.pageX || touches[0].clientX) + $(window).scrollLeft(); mouse.y = (e.clientY || e.pageY || touches[0].clientY) + $(window).scrollTop(); $container.offset({ 'left': mouse.x - ( event_state.mouse_x - event_state.container_left ), 'top': mouse.y - ( event_state.mouse_y - event_state.container_top ) }); // Watch for pinch zoom gesture while moving if(event_state.touches && event_state.touches.length > 1 && touches.length > 1){ var width = event_state.container_width, height = event_state.container_height; var a = event_state.touches[0].clientX - event_state.touches[1].clientX; a = a * a; var b = event_state.touches[0].clientY - event_state.touches[1].clientY; b = b * b; var dist1 = Math.sqrt( a + b ); a = e.originalEvent.touches[0].clientX - touches[1].clientX; a = a * a; b = e.originalEvent.touches[0].clientY - touches[1].clientY; b = b * b; var dist2 = Math.sqrt( a + b ); var ratio = dist2 /dist1; width = width * ratio; height = height * ratio; // To improve performance you might limit how often resizeImage() is called resizeImage(width, height); } };







.







. .



Chrome "", Firefox .



, .








HTML5, , , .



- . , . , .



canvas




, , . , , .



. . , , . , .



!





:

<img class="resize-image" src="image.jpg" alt="Image" />







! HTML .



CSS

CSS- . resize-container



.



.resize-container { position: relative; display: inline-block; cursor: move; margin: 0 auto; } .resize-container img { display: block } .resize-container:hover img, .resize-container:active img { outline: 2px dashed rgba(222,60,80,.9); }







'resize handles'. , , .



.resize-handle-ne, .resize-handle-ne, .resize-handle-se, .resize-handle-nw, .resize-handle-sw { position: absolute; display: block; width: 10px; height: 10px; background: rgba(222,60,80,.9); z-index: 999; } .resize-handle-nw { top: -5px; left: -5px; cursor: nw-resize; } .resize-handle-sw { bottom: -5px; left: -5px; cursor: sw-resize; } .resize-handle-ne { top: -5px; right: -5px; cursor: ne-resize; } .resize-handle-se { bottom: -5px; right: -5px; cursor: se-resize; }







JavaScript

Canvas.



var resizeableImage = function(image_target) { var $container, orig_src = new Image(), image_target = $(image_target).get(0), event_state = {}, constrain = false, min_width = 60, min_height = 60, max_width = 800, max_height = 900, resize_canvas = document.createElement('canvas'); }); resizeableImage($('.resize-image'));







, . , , . jQuery , .



var resizeableImage = function(image_target) { // ... init = function(){ // Create a new image with a copy of the original src // When resizing, we will always use this original copy as the base orig_src.src=image_target.src; // Add resize handles $(image_target).wrap('<div class="resize-container"></div>') .before('<span class="resize-handle resize-handle-nw"></span>') .before('<span class="resize-handle resize-handle-ne"></span>') .after('<span class="resize-handle resize-handle-se"></span>') .after('<span class="resize-handle resize-handle-sw"></span>'); // Get a variable for the container $container = $(image_target).parent('.resize-container'); // Add events $container.on('mousedown', '.resize-handle', startResize); }; //... init(); }







startResize



endResize



, , .



startResize = function(e){ e.preventDefault(); e.stopPropagation(); saveEventState(e); $(document).on('mousemove', resizing); $(document).on('mouseup', endResize); }; endResize = function(e){ e.preventDefault(); $(document).off('mouseup touchend', endResize); $(document).off('mousemove touchmove', resizing); };







. event_state



.



saveEventState = function(e){ // Save the initial event details and container state event_state.container_width = $container.width(); event_state.container_height = $container.height(); event_state.container_left = $container.offset().left; event_state.container_top = $container.offset().top; event_state.mouse_x = (e.clientX || e.pageX || e.originalEvent.touches[0].clientX) + $(window).scrollLeft(); event_state.mouse_y = (e.clientY || e.pageY || e.originalEvent.touches[0].clientY) + $(window).scrollTop(); // This is a fix for mobile safari // For some reason it does not allow a direct copy of the touches property if(typeof e.originalEvent.touches !== 'undefined'){ event_state.touches = []; $.each(e.originalEvent.touches, function(i, ob){ event_state.touches[i] = {}; event_state.touches[i].clientX = 0+ob.clientX; event_state.touches[i].clientY = 0+ob.clientY; }); } event_state.evnt = e; }







resizing



- . . .



resizing = function(e){ var mouse={},width,height,left,top,offset=$container.offset(); mouse.x = (e.clientX || e.pageX || e.originalEvent.touches[0].clientX) + $(window).scrollLeft(); mouse.y = (e.clientY || e.pageY || e.originalEvent.touches[0].clientY) + $(window).scrollTop(); width = mouse.x - event_state.container_left; height = mouse.y - event_state.container_top; left = event_state.container_left; top = event_state.container_top; if(constrain || e.shiftKey){ height = width / orig_src.width * orig_src.height; } if(width > min_width && height > min_height && width < max_width && height < max_height){ resizeImage(width, height); // Without this Firefox will not re-calculate the the image dimensions until drag end $container.offset({'left': left, 'top': top}); } }







Shift .



.



: , , resizeImage



.





Canvas , drawImage



. , . toDataURL



Base64-encoded .



.



resizeImage = function(width, height){ resize_canvas.width = width; resize_canvas.height = height; resize_canvas.getContext('2d').drawImage(orig_src, 0, 0, width, height); $(image_target).attr('src', resize_canvas.toDataURL("image/png")); };







? : , CORS . , 'tainted canvas'.







. . , . , .



, , .







, . resizing



:



resizing = function(e){ var mouse={},width,height,left,top,offset=$container.offset(); mouse.x = (e.clientX || e.pageX || e.originalEvent.touches[0].clientX) + $(window).scrollLeft(); mouse.y = (e.clientY || e.pageY || e.originalEvent.touches[0].clientY) + $(window).scrollTop(); // Position image differently depending on the corner dragged and constraints if( $(event_state.evnt.target).hasClass('resize-handle-se') ){ width = mouse.x - event_state.container_left; height = mouse.y - event_state.container_top; left = event_state.container_left; top = event_state.container_top; } else if($(event_state.evnt.target).hasClass('resize-handle-sw') ){ width = event_state.container_width - (mouse.x - event_state.container_left); height = mouse.y - event_state.container_top; left = mouse.x; top = event_state.container_top; } else if($(event_state.evnt.target).hasClass('resize-handle-nw') ){ width = event_state.container_width - (mouse.x - event_state.container_left); height = event_state.container_height - (mouse.y - event_state.container_top); left = mouse.x; top = mouse.y; if(constrain || e.shiftKey){ top = mouse.y - ((width / orig_src.width * orig_src.height) - height); } } else if($(event_state.evnt.target).hasClass('resize-handle-ne') ){ width = mouse.x - event_state.container_left; height = event_state.container_height - (mouse.y - event_state.container_top); left = event_state.container_left; top = mouse.y; if(constrain || e.shiftKey){ top = mouse.y - ((width / orig_src.width * orig_src.height) - height); } } // Optionally maintain aspect ratio if(constrain || e.shiftKey){ height = width / orig_src.width * orig_src.height; } if(width > min_width && height > min_height && width < max_width && height < max_height){ // To improve performance you might limit how often resizeImage() is called resizeImage(width, height); // Without this Firefox will not re-calculate the the image dimensions until drag end $container.offset({'left': left, 'top': top}); } }







, resize-handle



, .





, , , , , "". . .



init = function(){ //... $container.on('mousedown', 'img', startMoving); }







startMoving



endMoving



, startResize



endResize



.



startMoving = function(e){ e.preventDefault(); e.stopPropagation(); saveEventState(e); $(document).on('mousemove', moving); $(document).on('mouseup', endMoving); }; endMoving = function(e){ e.preventDefault(); $(document).off('mouseup', endMoving); $(document).off('mousemove', moving); };







moving



. , .



moving = function(e){ var mouse={}; e.preventDefault(); e.stopPropagation(); mouse.x = (e.clientX || e.pageX) + $(window).scrollLeft(); mouse.y = (e.clientY || e.pageY) + $(window).scrollTop(); $container.offset({ 'left': mouse.x - ( event_state.mouse_x - event_state.container_left ), 'top': mouse.y - ( event_state.mouse_y - event_state.container_top ) }); };









, , . , , , , . , , , , .



HTML :



<div class="overlay"> <div class="overlay-inner"> </div> </div> <button class="btn-crop js-crop">Crop</button>







, , .



.overlay { position: absolute; left: 50%; top: 50%; margin-left: -100px; margin-top: -100px; z-index: 999; width: 200px; height: 200px; border: solid 2px rgba(222,60,80,.9); box-sizing: content-box; pointer-events: none; } .overlay:after, .overlay:before { content: ''; position: absolute; display: block; width: 204px; height: 40px; border-left: dashed 2px rgba(222,60,80,.9); border-right: dashed 2px rgba(222,60,80,.9); } .overlay:before { top: 0; margin-left: -2px; margin-top: -40px; } .overlay:after { bottom: 0; margin-left: -2px; margin-bottom: -40px; } .overlay-inner:after, .overlay-inner:before { content: ''; position: absolute; display: block; width: 40px; height: 204px; border-top: dashed 2px rgba(222,60,80,.9); border-bottom: dashed 2px rgba(222,60,80,.9); } .overlay-inner:before { left: 0; margin-left: -40px; margin-top: -2px; } .overlay-inner:after { right: 0; margin-right: -40px; margin-top: -2px; } .btn-crop { position: absolute; vertical-align: bottom; right: 5px; bottom: 5px; padding: 6px 10px; z-index: 999; background-color: rgb(222,60,80); border: none; border-radius: 5px; color: #FFF; }







JavaScript :



init = function(){ //... $('.js-crop').on('click', crop); }; crop = function(){ var crop_canvas, left = $('.overlay').offset().left - $container.offset().left, top = $('.overlay').offset().top - $container.offset().top, width = $('.overlay').width(), height = $('.overlay').height(); crop_canvas = document.createElement('canvas'); crop_canvas.width = width; crop_canvas.height = height; crop_canvas.getContext('2d').drawImage(image_target, left, top, width, height, 0, 0, width, height); window.open(crop_canvas.toDataURL("image/png")); }







crop



resizeImage



. , .



drawImage



canvas. - . - , . - , canvas, .





. .



mousedown



mouseup



- touchstart



touchend



, mousemove



touchmove



. , touchup



touchdown



( ).



touchstart



touchend



, mousedown



, mouseup



touchmove



, mousemove



.



// In init()... $container.on('mousedown touchstart', '.resize-handle', startResize); $container.on('mousedown touchstart', 'img', startMoving); //In startResize() ... $(document).on('mousemove touchmove', moving); $(document).on('mouseup touchend', endMoving); //In endResize()... $(document).off('mouseup touchend', endMoving); $(document).off('mousemove touchmove', moving); //In startMoving()... $(document).on('mousemove touchmove', moving); $(document).on('mouseup touchend', endMoving); //In endMoving()... $(document).off('mouseup touchend', endMoving); $(document).off('mousemove touchmove', moving);







, "" . Hammer, . , , .



, , , saveEventState



. .



" " . , . moving



:



moving = function(e){ var mouse={}, touches; e.preventDefault(); e.stopPropagation(); touches = e.originalEvent.touches; mouse.x = (e.clientX || e.pageX || touches[0].clientX) + $(window).scrollLeft(); mouse.y = (e.clientY || e.pageY || touches[0].clientY) + $(window).scrollTop(); $container.offset({ 'left': mouse.x - ( event_state.mouse_x - event_state.container_left ), 'top': mouse.y - ( event_state.mouse_y - event_state.container_top ) }); // Watch for pinch zoom gesture while moving if(event_state.touches && event_state.touches.length > 1 && touches.length > 1){ var width = event_state.container_width, height = event_state.container_height; var a = event_state.touches[0].clientX - event_state.touches[1].clientX; a = a * a; var b = event_state.touches[0].clientY - event_state.touches[1].clientY; b = b * b; var dist1 = Math.sqrt( a + b ); a = e.originalEvent.touches[0].clientX - touches[1].clientX; a = a * a; b = e.originalEvent.touches[0].clientY - touches[1].clientY; b = b * b; var dist2 = Math.sqrt( a + b ); var ratio = dist2 /dist1; width = width * ratio; height = height * ratio; // To improve performance you might limit how often resizeImage() is called resizeImage(width, height); } };







.







. .



Chrome "", Firefox .



, .




HTML5, , , .



- . , . , .



canvas




, , . , , .



. . , , . , .



!





:

<img class="resize-image" src="image.jpg" alt="Image" />







! HTML .



CSS

CSS- . resize-container



.



.resize-container { position: relative; display: inline-block; cursor: move; margin: 0 auto; } .resize-container img { display: block } .resize-container:hover img, .resize-container:active img { outline: 2px dashed rgba(222,60,80,.9); }







'resize handles'. , , .



.resize-handle-ne, .resize-handle-ne, .resize-handle-se, .resize-handle-nw, .resize-handle-sw { position: absolute; display: block; width: 10px; height: 10px; background: rgba(222,60,80,.9); z-index: 999; } .resize-handle-nw { top: -5px; left: -5px; cursor: nw-resize; } .resize-handle-sw { bottom: -5px; left: -5px; cursor: sw-resize; } .resize-handle-ne { top: -5px; right: -5px; cursor: ne-resize; } .resize-handle-se { bottom: -5px; right: -5px; cursor: se-resize; }







JavaScript

Canvas.



var resizeableImage = function(image_target) { var $container, orig_src = new Image(), image_target = $(image_target).get(0), event_state = {}, constrain = false, min_width = 60, min_height = 60, max_width = 800, max_height = 900, resize_canvas = document.createElement('canvas'); }); resizeableImage($('.resize-image'));







, . , , . jQuery , .



var resizeableImage = function(image_target) { // ... init = function(){ // Create a new image with a copy of the original src // When resizing, we will always use this original copy as the base orig_src.src=image_target.src; // Add resize handles $(image_target).wrap('<div class="resize-container"></div>') .before('<span class="resize-handle resize-handle-nw"></span>') .before('<span class="resize-handle resize-handle-ne"></span>') .after('<span class="resize-handle resize-handle-se"></span>') .after('<span class="resize-handle resize-handle-sw"></span>'); // Get a variable for the container $container = $(image_target).parent('.resize-container'); // Add events $container.on('mousedown', '.resize-handle', startResize); }; //... init(); }







startResize



endResize



, , .



startResize = function(e){ e.preventDefault(); e.stopPropagation(); saveEventState(e); $(document).on('mousemove', resizing); $(document).on('mouseup', endResize); }; endResize = function(e){ e.preventDefault(); $(document).off('mouseup touchend', endResize); $(document).off('mousemove touchmove', resizing); };







. event_state



.



saveEventState = function(e){ // Save the initial event details and container state event_state.container_width = $container.width(); event_state.container_height = $container.height(); event_state.container_left = $container.offset().left; event_state.container_top = $container.offset().top; event_state.mouse_x = (e.clientX || e.pageX || e.originalEvent.touches[0].clientX) + $(window).scrollLeft(); event_state.mouse_y = (e.clientY || e.pageY || e.originalEvent.touches[0].clientY) + $(window).scrollTop(); // This is a fix for mobile safari // For some reason it does not allow a direct copy of the touches property if(typeof e.originalEvent.touches !== 'undefined'){ event_state.touches = []; $.each(e.originalEvent.touches, function(i, ob){ event_state.touches[i] = {}; event_state.touches[i].clientX = 0+ob.clientX; event_state.touches[i].clientY = 0+ob.clientY; }); } event_state.evnt = e; }







resizing



- . . .



resizing = function(e){ var mouse={},width,height,left,top,offset=$container.offset(); mouse.x = (e.clientX || e.pageX || e.originalEvent.touches[0].clientX) + $(window).scrollLeft(); mouse.y = (e.clientY || e.pageY || e.originalEvent.touches[0].clientY) + $(window).scrollTop(); width = mouse.x - event_state.container_left; height = mouse.y - event_state.container_top; left = event_state.container_left; top = event_state.container_top; if(constrain || e.shiftKey){ height = width / orig_src.width * orig_src.height; } if(width > min_width && height > min_height && width < max_width && height < max_height){ resizeImage(width, height); // Without this Firefox will not re-calculate the the image dimensions until drag end $container.offset({'left': left, 'top': top}); } }







Shift .



.



: , , resizeImage



.





Canvas , drawImage



. , . toDataURL



Base64-encoded .



.



resizeImage = function(width, height){ resize_canvas.width = width; resize_canvas.height = height; resize_canvas.getContext('2d').drawImage(orig_src, 0, 0, width, height); $(image_target).attr('src', resize_canvas.toDataURL("image/png")); };







? : , CORS . , 'tainted canvas'.







. . , . , .



, , .







, . resizing



:



resizing = function(e){ var mouse={},width,height,left,top,offset=$container.offset(); mouse.x = (e.clientX || e.pageX || e.originalEvent.touches[0].clientX) + $(window).scrollLeft(); mouse.y = (e.clientY || e.pageY || e.originalEvent.touches[0].clientY) + $(window).scrollTop(); // Position image differently depending on the corner dragged and constraints if( $(event_state.evnt.target).hasClass('resize-handle-se') ){ width = mouse.x - event_state.container_left; height = mouse.y - event_state.container_top; left = event_state.container_left; top = event_state.container_top; } else if($(event_state.evnt.target).hasClass('resize-handle-sw') ){ width = event_state.container_width - (mouse.x - event_state.container_left); height = mouse.y - event_state.container_top; left = mouse.x; top = event_state.container_top; } else if($(event_state.evnt.target).hasClass('resize-handle-nw') ){ width = event_state.container_width - (mouse.x - event_state.container_left); height = event_state.container_height - (mouse.y - event_state.container_top); left = mouse.x; top = mouse.y; if(constrain || e.shiftKey){ top = mouse.y - ((width / orig_src.width * orig_src.height) - height); } } else if($(event_state.evnt.target).hasClass('resize-handle-ne') ){ width = mouse.x - event_state.container_left; height = event_state.container_height - (mouse.y - event_state.container_top); left = event_state.container_left; top = mouse.y; if(constrain || e.shiftKey){ top = mouse.y - ((width / orig_src.width * orig_src.height) - height); } } // Optionally maintain aspect ratio if(constrain || e.shiftKey){ height = width / orig_src.width * orig_src.height; } if(width > min_width && height > min_height && width < max_width && height < max_height){ // To improve performance you might limit how often resizeImage() is called resizeImage(width, height); // Without this Firefox will not re-calculate the the image dimensions until drag end $container.offset({'left': left, 'top': top}); } }







, resize-handle



, .





, , , , , "". . .



init = function(){ //... $container.on('mousedown', 'img', startMoving); }







startMoving



endMoving



, startResize



endResize



.



startMoving = function(e){ e.preventDefault(); e.stopPropagation(); saveEventState(e); $(document).on('mousemove', moving); $(document).on('mouseup', endMoving); }; endMoving = function(e){ e.preventDefault(); $(document).off('mouseup', endMoving); $(document).off('mousemove', moving); };







moving



. , .



moving = function(e){ var mouse={}; e.preventDefault(); e.stopPropagation(); mouse.x = (e.clientX || e.pageX) + $(window).scrollLeft(); mouse.y = (e.clientY || e.pageY) + $(window).scrollTop(); $container.offset({ 'left': mouse.x - ( event_state.mouse_x - event_state.container_left ), 'top': mouse.y - ( event_state.mouse_y - event_state.container_top ) }); };









, , . , , , , . , , , , .



HTML :



<div class="overlay"> <div class="overlay-inner"> </div> </div> <button class="btn-crop js-crop">Crop</button>







, , .



.overlay { position: absolute; left: 50%; top: 50%; margin-left: -100px; margin-top: -100px; z-index: 999; width: 200px; height: 200px; border: solid 2px rgba(222,60,80,.9); box-sizing: content-box; pointer-events: none; } .overlay:after, .overlay:before { content: ''; position: absolute; display: block; width: 204px; height: 40px; border-left: dashed 2px rgba(222,60,80,.9); border-right: dashed 2px rgba(222,60,80,.9); } .overlay:before { top: 0; margin-left: -2px; margin-top: -40px; } .overlay:after { bottom: 0; margin-left: -2px; margin-bottom: -40px; } .overlay-inner:after, .overlay-inner:before { content: ''; position: absolute; display: block; width: 40px; height: 204px; border-top: dashed 2px rgba(222,60,80,.9); border-bottom: dashed 2px rgba(222,60,80,.9); } .overlay-inner:before { left: 0; margin-left: -40px; margin-top: -2px; } .overlay-inner:after { right: 0; margin-right: -40px; margin-top: -2px; } .btn-crop { position: absolute; vertical-align: bottom; right: 5px; bottom: 5px; padding: 6px 10px; z-index: 999; background-color: rgb(222,60,80); border: none; border-radius: 5px; color: #FFF; }







JavaScript :



init = function(){ //... $('.js-crop').on('click', crop); }; crop = function(){ var crop_canvas, left = $('.overlay').offset().left - $container.offset().left, top = $('.overlay').offset().top - $container.offset().top, width = $('.overlay').width(), height = $('.overlay').height(); crop_canvas = document.createElement('canvas'); crop_canvas.width = width; crop_canvas.height = height; crop_canvas.getContext('2d').drawImage(image_target, left, top, width, height, 0, 0, width, height); window.open(crop_canvas.toDataURL("image/png")); }







crop



resizeImage



. , .



drawImage



canvas. - . - , . - , canvas, .





. .



mousedown



mouseup



- touchstart



touchend



, mousemove



touchmove



. , touchup



touchdown



( ).



touchstart



touchend



, mousedown



, mouseup



touchmove



, mousemove



.



// In init()... $container.on('mousedown touchstart', '.resize-handle', startResize); $container.on('mousedown touchstart', 'img', startMoving); //In startResize() ... $(document).on('mousemove touchmove', moving); $(document).on('mouseup touchend', endMoving); //In endResize()... $(document).off('mouseup touchend', endMoving); $(document).off('mousemove touchmove', moving); //In startMoving()... $(document).on('mousemove touchmove', moving); $(document).on('mouseup touchend', endMoving); //In endMoving()... $(document).off('mouseup touchend', endMoving); $(document).off('mousemove touchmove', moving);







, "" . Hammer, . , , .



, , , saveEventState



. .



" " . , . moving



:



moving = function(e){ var mouse={}, touches; e.preventDefault(); e.stopPropagation(); touches = e.originalEvent.touches; mouse.x = (e.clientX || e.pageX || touches[0].clientX) + $(window).scrollLeft(); mouse.y = (e.clientY || e.pageY || touches[0].clientY) + $(window).scrollTop(); $container.offset({ 'left': mouse.x - ( event_state.mouse_x - event_state.container_left ), 'top': mouse.y - ( event_state.mouse_y - event_state.container_top ) }); // Watch for pinch zoom gesture while moving if(event_state.touches && event_state.touches.length > 1 && touches.length > 1){ var width = event_state.container_width, height = event_state.container_height; var a = event_state.touches[0].clientX - event_state.touches[1].clientX; a = a * a; var b = event_state.touches[0].clientY - event_state.touches[1].clientY; b = b * b; var dist1 = Math.sqrt( a + b ); a = e.originalEvent.touches[0].clientX - touches[1].clientX; a = a * a; b = e.originalEvent.touches[0].clientY - touches[1].clientY; b = b * b; var dist2 = Math.sqrt( a + b ); var ratio = dist2 /dist1; width = width * ratio; height = height * ratio; // To improve performance you might limit how often resizeImage() is called resizeImage(width, height); } };







.







. .



Chrome "", Firefox .



, .




HTML5, , , .



- . , . , .



canvas




, , . , , .



. . , , . , .



!





:

<img class="resize-image" src="image.jpg" alt="Image" />







! HTML .



CSS

CSS- . resize-container



.



.resize-container { position: relative; display: inline-block; cursor: move; margin: 0 auto; } .resize-container img { display: block } .resize-container:hover img, .resize-container:active img { outline: 2px dashed rgba(222,60,80,.9); }







'resize handles'. , , .



.resize-handle-ne, .resize-handle-ne, .resize-handle-se, .resize-handle-nw, .resize-handle-sw { position: absolute; display: block; width: 10px; height: 10px; background: rgba(222,60,80,.9); z-index: 999; } .resize-handle-nw { top: -5px; left: -5px; cursor: nw-resize; } .resize-handle-sw { bottom: -5px; left: -5px; cursor: sw-resize; } .resize-handle-ne { top: -5px; right: -5px; cursor: ne-resize; } .resize-handle-se { bottom: -5px; right: -5px; cursor: se-resize; }







JavaScript

Canvas.



var resizeableImage = function(image_target) { var $container, orig_src = new Image(), image_target = $(image_target).get(0), event_state = {}, constrain = false, min_width = 60, min_height = 60, max_width = 800, max_height = 900, resize_canvas = document.createElement('canvas'); }); resizeableImage($('.resize-image'));







, . , , . jQuery , .



var resizeableImage = function(image_target) { // ... init = function(){ // Create a new image with a copy of the original src // When resizing, we will always use this original copy as the base orig_src.src=image_target.src; // Add resize handles $(image_target).wrap('<div class="resize-container"></div>') .before('<span class="resize-handle resize-handle-nw"></span>') .before('<span class="resize-handle resize-handle-ne"></span>') .after('<span class="resize-handle resize-handle-se"></span>') .after('<span class="resize-handle resize-handle-sw"></span>'); // Get a variable for the container $container = $(image_target).parent('.resize-container'); // Add events $container.on('mousedown', '.resize-handle', startResize); }; //... init(); }







startResize



endResize



, , .



startResize = function(e){ e.preventDefault(); e.stopPropagation(); saveEventState(e); $(document).on('mousemove', resizing); $(document).on('mouseup', endResize); }; endResize = function(e){ e.preventDefault(); $(document).off('mouseup touchend', endResize); $(document).off('mousemove touchmove', resizing); };







. event_state



.



saveEventState = function(e){ // Save the initial event details and container state event_state.container_width = $container.width(); event_state.container_height = $container.height(); event_state.container_left = $container.offset().left; event_state.container_top = $container.offset().top; event_state.mouse_x = (e.clientX || e.pageX || e.originalEvent.touches[0].clientX) + $(window).scrollLeft(); event_state.mouse_y = (e.clientY || e.pageY || e.originalEvent.touches[0].clientY) + $(window).scrollTop(); // This is a fix for mobile safari // For some reason it does not allow a direct copy of the touches property if(typeof e.originalEvent.touches !== 'undefined'){ event_state.touches = []; $.each(e.originalEvent.touches, function(i, ob){ event_state.touches[i] = {}; event_state.touches[i].clientX = 0+ob.clientX; event_state.touches[i].clientY = 0+ob.clientY; }); } event_state.evnt = e; }







resizing



- . . .



resizing = function(e){ var mouse={},width,height,left,top,offset=$container.offset(); mouse.x = (e.clientX || e.pageX || e.originalEvent.touches[0].clientX) + $(window).scrollLeft(); mouse.y = (e.clientY || e.pageY || e.originalEvent.touches[0].clientY) + $(window).scrollTop(); width = mouse.x - event_state.container_left; height = mouse.y - event_state.container_top; left = event_state.container_left; top = event_state.container_top; if(constrain || e.shiftKey){ height = width / orig_src.width * orig_src.height; } if(width > min_width && height > min_height && width < max_width && height < max_height){ resizeImage(width, height); // Without this Firefox will not re-calculate the the image dimensions until drag end $container.offset({'left': left, 'top': top}); } }







Shift .



.



: , , resizeImage



.





Canvas , drawImage



. , . toDataURL



Base64-encoded .



.



resizeImage = function(width, height){ resize_canvas.width = width; resize_canvas.height = height; resize_canvas.getContext('2d').drawImage(orig_src, 0, 0, width, height); $(image_target).attr('src', resize_canvas.toDataURL("image/png")); };







? : , CORS . , 'tainted canvas'.







. . , . , .



, , .







, . resizing



:



resizing = function(e){ var mouse={},width,height,left,top,offset=$container.offset(); mouse.x = (e.clientX || e.pageX || e.originalEvent.touches[0].clientX) + $(window).scrollLeft(); mouse.y = (e.clientY || e.pageY || e.originalEvent.touches[0].clientY) + $(window).scrollTop(); // Position image differently depending on the corner dragged and constraints if( $(event_state.evnt.target).hasClass('resize-handle-se') ){ width = mouse.x - event_state.container_left; height = mouse.y - event_state.container_top; left = event_state.container_left; top = event_state.container_top; } else if($(event_state.evnt.target).hasClass('resize-handle-sw') ){ width = event_state.container_width - (mouse.x - event_state.container_left); height = mouse.y - event_state.container_top; left = mouse.x; top = event_state.container_top; } else if($(event_state.evnt.target).hasClass('resize-handle-nw') ){ width = event_state.container_width - (mouse.x - event_state.container_left); height = event_state.container_height - (mouse.y - event_state.container_top); left = mouse.x; top = mouse.y; if(constrain || e.shiftKey){ top = mouse.y - ((width / orig_src.width * orig_src.height) - height); } } else if($(event_state.evnt.target).hasClass('resize-handle-ne') ){ width = mouse.x - event_state.container_left; height = event_state.container_height - (mouse.y - event_state.container_top); left = event_state.container_left; top = mouse.y; if(constrain || e.shiftKey){ top = mouse.y - ((width / orig_src.width * orig_src.height) - height); } } // Optionally maintain aspect ratio if(constrain || e.shiftKey){ height = width / orig_src.width * orig_src.height; } if(width > min_width && height > min_height && width < max_width && height < max_height){ // To improve performance you might limit how often resizeImage() is called resizeImage(width, height); // Without this Firefox will not re-calculate the the image dimensions until drag end $container.offset({'left': left, 'top': top}); } }







, resize-handle



, .





, , , , , "". . .



init = function(){ //... $container.on('mousedown', 'img', startMoving); }







startMoving



endMoving



, startResize



endResize



.



startMoving = function(e){ e.preventDefault(); e.stopPropagation(); saveEventState(e); $(document).on('mousemove', moving); $(document).on('mouseup', endMoving); }; endMoving = function(e){ e.preventDefault(); $(document).off('mouseup', endMoving); $(document).off('mousemove', moving); };







moving



. , .



moving = function(e){ var mouse={}; e.preventDefault(); e.stopPropagation(); mouse.x = (e.clientX || e.pageX) + $(window).scrollLeft(); mouse.y = (e.clientY || e.pageY) + $(window).scrollTop(); $container.offset({ 'left': mouse.x - ( event_state.mouse_x - event_state.container_left ), 'top': mouse.y - ( event_state.mouse_y - event_state.container_top ) }); };









, , . , , , , . , , , , .



HTML :



<div class="overlay"> <div class="overlay-inner"> </div> </div> <button class="btn-crop js-crop">Crop</button>







, , .



.overlay { position: absolute; left: 50%; top: 50%; margin-left: -100px; margin-top: -100px; z-index: 999; width: 200px; height: 200px; border: solid 2px rgba(222,60,80,.9); box-sizing: content-box; pointer-events: none; } .overlay:after, .overlay:before { content: ''; position: absolute; display: block; width: 204px; height: 40px; border-left: dashed 2px rgba(222,60,80,.9); border-right: dashed 2px rgba(222,60,80,.9); } .overlay:before { top: 0; margin-left: -2px; margin-top: -40px; } .overlay:after { bottom: 0; margin-left: -2px; margin-bottom: -40px; } .overlay-inner:after, .overlay-inner:before { content: ''; position: absolute; display: block; width: 40px; height: 204px; border-top: dashed 2px rgba(222,60,80,.9); border-bottom: dashed 2px rgba(222,60,80,.9); } .overlay-inner:before { left: 0; margin-left: -40px; margin-top: -2px; } .overlay-inner:after { right: 0; margin-right: -40px; margin-top: -2px; } .btn-crop { position: absolute; vertical-align: bottom; right: 5px; bottom: 5px; padding: 6px 10px; z-index: 999; background-color: rgb(222,60,80); border: none; border-radius: 5px; color: #FFF; }







JavaScript :



init = function(){ //... $('.js-crop').on('click', crop); }; crop = function(){ var crop_canvas, left = $('.overlay').offset().left - $container.offset().left, top = $('.overlay').offset().top - $container.offset().top, width = $('.overlay').width(), height = $('.overlay').height(); crop_canvas = document.createElement('canvas'); crop_canvas.width = width; crop_canvas.height = height; crop_canvas.getContext('2d').drawImage(image_target, left, top, width, height, 0, 0, width, height); window.open(crop_canvas.toDataURL("image/png")); }







crop



resizeImage



. , .



drawImage



canvas. - . - , . - , canvas, .





. .



mousedown



mouseup



- touchstart



touchend



, mousemove



touchmove



. , touchup



touchdown



( ).



touchstart



touchend



, mousedown



, mouseup



touchmove



, mousemove



.



// In init()... $container.on('mousedown touchstart', '.resize-handle', startResize); $container.on('mousedown touchstart', 'img', startMoving); //In startResize() ... $(document).on('mousemove touchmove', moving); $(document).on('mouseup touchend', endMoving); //In endResize()... $(document).off('mouseup touchend', endMoving); $(document).off('mousemove touchmove', moving); //In startMoving()... $(document).on('mousemove touchmove', moving); $(document).on('mouseup touchend', endMoving); //In endMoving()... $(document).off('mouseup touchend', endMoving); $(document).off('mousemove touchmove', moving);







, "" . Hammer, . , , .



, , , saveEventState



. .



" " . , . moving



:



moving = function(e){ var mouse={}, touches; e.preventDefault(); e.stopPropagation(); touches = e.originalEvent.touches; mouse.x = (e.clientX || e.pageX || touches[0].clientX) + $(window).scrollLeft(); mouse.y = (e.clientY || e.pageY || touches[0].clientY) + $(window).scrollTop(); $container.offset({ 'left': mouse.x - ( event_state.mouse_x - event_state.container_left ), 'top': mouse.y - ( event_state.mouse_y - event_state.container_top ) }); // Watch for pinch zoom gesture while moving if(event_state.touches && event_state.touches.length > 1 && touches.length > 1){ var width = event_state.container_width, height = event_state.container_height; var a = event_state.touches[0].clientX - event_state.touches[1].clientX; a = a * a; var b = event_state.touches[0].clientY - event_state.touches[1].clientY; b = b * b; var dist1 = Math.sqrt( a + b ); a = e.originalEvent.touches[0].clientX - touches[1].clientX; a = a * a; b = e.originalEvent.touches[0].clientY - touches[1].clientY; b = b * b; var dist2 = Math.sqrt( a + b ); var ratio = dist2 /dist1; width = width * ratio; height = height * ratio; // To improve performance you might limit how often resizeImage() is called resizeImage(width, height); } };







.







. .



Chrome "", Firefox .



, .




  HTML5,     ,      ,   . 
      



- . , . , .



canvas




, , . , , .



. . , , . , .



!





:

<img class="resize-image" src="image.jpg" alt="Image" />



! HTML .



CSS

CSS- . resize-container



.



.resize-container { position: relative; display: inline-block; cursor: move; margin: 0 auto; } .resize-container img { display: block } .resize-container:hover img, .resize-container:active img { outline: 2px dashed rgba(222,60,80,.9); }







'resize handles'. , , .



.resize-handle-ne, .resize-handle-ne, .resize-handle-se, .resize-handle-nw, .resize-handle-sw { position: absolute; display: block; width: 10px; height: 10px; background: rgba(222,60,80,.9); z-index: 999; } .resize-handle-nw { top: -5px; left: -5px; cursor: nw-resize; } .resize-handle-sw { bottom: -5px; left: -5px; cursor: sw-resize; } .resize-handle-ne { top: -5px; right: -5px; cursor: ne-resize; } .resize-handle-se { bottom: -5px; right: -5px; cursor: se-resize; }







JavaScript

Canvas.



var resizeableImage = function(image_target) { var $container, orig_src = new Image(), image_target = $(image_target).get(0), event_state = {}, constrain = false, min_width = 60, min_height = 60, max_width = 800, max_height = 900, resize_canvas = document.createElement('canvas'); }); resizeableImage($('.resize-image'));







, . , , . jQuery , .



var resizeableImage = function(image_target) { // ... init = function(){ // Create a new image with a copy of the original src // When resizing, we will always use this original copy as the base orig_src.src=image_target.src; // Add resize handles $(image_target).wrap('<div class="resize-container"></div>') .before('<span class="resize-handle resize-handle-nw"></span>') .before('<span class="resize-handle resize-handle-ne"></span>') .after('<span class="resize-handle resize-handle-se"></span>') .after('<span class="resize-handle resize-handle-sw"></span>'); // Get a variable for the container $container = $(image_target).parent('.resize-container'); // Add events $container.on('mousedown', '.resize-handle', startResize); }; //... init(); }







startResize



endResize



, , .



startResize = function(e){ e.preventDefault(); e.stopPropagation(); saveEventState(e); $(document).on('mousemove', resizing); $(document).on('mouseup', endResize); }; endResize = function(e){ e.preventDefault(); $(document).off('mouseup touchend', endResize); $(document).off('mousemove touchmove', resizing); };







. event_state



.



saveEventState = function(e){ // Save the initial event details and container state event_state.container_width = $container.width(); event_state.container_height = $container.height(); event_state.container_left = $container.offset().left; event_state.container_top = $container.offset().top; event_state.mouse_x = (e.clientX || e.pageX || e.originalEvent.touches[0].clientX) + $(window).scrollLeft(); event_state.mouse_y = (e.clientY || e.pageY || e.originalEvent.touches[0].clientY) + $(window).scrollTop(); // This is a fix for mobile safari // For some reason it does not allow a direct copy of the touches property if(typeof e.originalEvent.touches !== 'undefined'){ event_state.touches = []; $.each(e.originalEvent.touches, function(i, ob){ event_state.touches[i] = {}; event_state.touches[i].clientX = 0+ob.clientX; event_state.touches[i].clientY = 0+ob.clientY; }); } event_state.evnt = e; }







resizing



- . . .



resizing = function(e){ var mouse={},width,height,left,top,offset=$container.offset(); mouse.x = (e.clientX || e.pageX || e.originalEvent.touches[0].clientX) + $(window).scrollLeft(); mouse.y = (e.clientY || e.pageY || e.originalEvent.touches[0].clientY) + $(window).scrollTop(); width = mouse.x - event_state.container_left; height = mouse.y - event_state.container_top; left = event_state.container_left; top = event_state.container_top; if(constrain || e.shiftKey){ height = width / orig_src.width * orig_src.height; } if(width > min_width && height > min_height && width < max_width && height < max_height){ resizeImage(width, height); // Without this Firefox will not re-calculate the the image dimensions until drag end $container.offset({'left': left, 'top': top}); } }







Shift .



.



: , , resizeImage



.





Canvas , drawImage



. , . toDataURL



Base64-encoded .



.



resizeImage = function(width, height){ resize_canvas.width = width; resize_canvas.height = height; resize_canvas.getContext('2d').drawImage(orig_src, 0, 0, width, height); $(image_target).attr('src', resize_canvas.toDataURL("image/png")); };







? : , CORS . , 'tainted canvas'.







. . , . , .



, , .







, . resizing



:



resizing = function(e){ var mouse={},width,height,left,top,offset=$container.offset(); mouse.x = (e.clientX || e.pageX || e.originalEvent.touches[0].clientX) + $(window).scrollLeft(); mouse.y = (e.clientY || e.pageY || e.originalEvent.touches[0].clientY) + $(window).scrollTop(); // Position image differently depending on the corner dragged and constraints if( $(event_state.evnt.target).hasClass('resize-handle-se') ){ width = mouse.x - event_state.container_left; height = mouse.y - event_state.container_top; left = event_state.container_left; top = event_state.container_top; } else if($(event_state.evnt.target).hasClass('resize-handle-sw') ){ width = event_state.container_width - (mouse.x - event_state.container_left); height = mouse.y - event_state.container_top; left = mouse.x; top = event_state.container_top; } else if($(event_state.evnt.target).hasClass('resize-handle-nw') ){ width = event_state.container_width - (mouse.x - event_state.container_left); height = event_state.container_height - (mouse.y - event_state.container_top); left = mouse.x; top = mouse.y; if(constrain || e.shiftKey){ top = mouse.y - ((width / orig_src.width * orig_src.height) - height); } } else if($(event_state.evnt.target).hasClass('resize-handle-ne') ){ width = mouse.x - event_state.container_left; height = event_state.container_height - (mouse.y - event_state.container_top); left = event_state.container_left; top = mouse.y; if(constrain || e.shiftKey){ top = mouse.y - ((width / orig_src.width * orig_src.height) - height); } } // Optionally maintain aspect ratio if(constrain || e.shiftKey){ height = width / orig_src.width * orig_src.height; } if(width > min_width && height > min_height && width < max_width && height < max_height){ // To improve performance you might limit how often resizeImage() is called resizeImage(width, height); // Without this Firefox will not re-calculate the the image dimensions until drag end $container.offset({'left': left, 'top': top}); } }







, resize-handle



, .





, , , , , "". . .



init = function(){ //... $container.on('mousedown', 'img', startMoving); }







startMoving



endMoving



, startResize



endResize



.



startMoving = function(e){ e.preventDefault(); e.stopPropagation(); saveEventState(e); $(document).on('mousemove', moving); $(document).on('mouseup', endMoving); }; endMoving = function(e){ e.preventDefault(); $(document).off('mouseup', endMoving); $(document).off('mousemove', moving); };







moving



. , .



moving = function(e){ var mouse={}; e.preventDefault(); e.stopPropagation(); mouse.x = (e.clientX || e.pageX) + $(window).scrollLeft(); mouse.y = (e.clientY || e.pageY) + $(window).scrollTop(); $container.offset({ 'left': mouse.x - ( event_state.mouse_x - event_state.container_left ), 'top': mouse.y - ( event_state.mouse_y - event_state.container_top ) }); };









, , . , , , , . , , , , .



HTML :



<div class="overlay"> <div class="overlay-inner"> </div> </div> <button class="btn-crop js-crop">Crop</button>







, , .



.overlay { position: absolute; left: 50%; top: 50%; margin-left: -100px; margin-top: -100px; z-index: 999; width: 200px; height: 200px; border: solid 2px rgba(222,60,80,.9); box-sizing: content-box; pointer-events: none; } .overlay:after, .overlay:before { content: ''; position: absolute; display: block; width: 204px; height: 40px; border-left: dashed 2px rgba(222,60,80,.9); border-right: dashed 2px rgba(222,60,80,.9); } .overlay:before { top: 0; margin-left: -2px; margin-top: -40px; } .overlay:after { bottom: 0; margin-left: -2px; margin-bottom: -40px; } .overlay-inner:after, .overlay-inner:before { content: ''; position: absolute; display: block; width: 40px; height: 204px; border-top: dashed 2px rgba(222,60,80,.9); border-bottom: dashed 2px rgba(222,60,80,.9); } .overlay-inner:before { left: 0; margin-left: -40px; margin-top: -2px; } .overlay-inner:after { right: 0; margin-right: -40px; margin-top: -2px; } .btn-crop { position: absolute; vertical-align: bottom; right: 5px; bottom: 5px; padding: 6px 10px; z-index: 999; background-color: rgb(222,60,80); border: none; border-radius: 5px; color: #FFF; }







JavaScript :



init = function(){ //... $('.js-crop').on('click', crop); }; crop = function(){ var crop_canvas, left = $('.overlay').offset().left - $container.offset().left, top = $('.overlay').offset().top - $container.offset().top, width = $('.overlay').width(), height = $('.overlay').height(); crop_canvas = document.createElement('canvas'); crop_canvas.width = width; crop_canvas.height = height; crop_canvas.getContext('2d').drawImage(image_target, left, top, width, height, 0, 0, width, height); window.open(crop_canvas.toDataURL("image/png")); }







crop



resizeImage



. , .



drawImage



canvas. - . - , . - , canvas, .





. .



mousedown



mouseup



- touchstart



touchend



, mousemove



touchmove



. , touchup



touchdown



( ).



touchstart



touchend



, mousedown



, mouseup



touchmove



, mousemove



.



// In init()... $container.on('mousedown touchstart', '.resize-handle', startResize); $container.on('mousedown touchstart', 'img', startMoving); //In startResize() ... $(document).on('mousemove touchmove', moving); $(document).on('mouseup touchend', endMoving); //In endResize()... $(document).off('mouseup touchend', endMoving); $(document).off('mousemove touchmove', moving); //In startMoving()... $(document).on('mousemove touchmove', moving); $(document).on('mouseup touchend', endMoving); //In endMoving()... $(document).off('mouseup touchend', endMoving); $(document).off('mousemove touchmove', moving);







, "" . Hammer, . , , .



, , , saveEventState



. .



" " . , . moving



:



moving = function(e){ var mouse={}, touches; e.preventDefault(); e.stopPropagation(); touches = e.originalEvent.touches; mouse.x = (e.clientX || e.pageX || touches[0].clientX) + $(window).scrollLeft(); mouse.y = (e.clientY || e.pageY || touches[0].clientY) + $(window).scrollTop(); $container.offset({ 'left': mouse.x - ( event_state.mouse_x - event_state.container_left ), 'top': mouse.y - ( event_state.mouse_y - event_state.container_top ) }); // Watch for pinch zoom gesture while moving if(event_state.touches && event_state.touches.length > 1 && touches.length > 1){ var width = event_state.container_width, height = event_state.container_height; var a = event_state.touches[0].clientX - event_state.touches[1].clientX; a = a * a; var b = event_state.touches[0].clientY - event_state.touches[1].clientY; b = b * b; var dist1 = Math.sqrt( a + b ); a = e.originalEvent.touches[0].clientX - touches[1].clientX; a = a * a; b = e.originalEvent.touches[0].clientY - touches[1].clientY; b = b * b; var dist2 = Math.sqrt( a + b ); var ratio = dist2 /dist1; width = width * ratio; height = height * ratio; // To improve performance you might limit how often resizeImage() is called resizeImage(width, height); } };







.







. .



Chrome "", Firefox .



, .








HTML5, , , .



- . , . , .



canvas




, , . , , .



. . , , . , .



!





:

<img class="resize-image" src="image.jpg" alt="Image" />







! HTML .



CSS

CSS- . resize-container



.



.resize-container { position: relative; display: inline-block; cursor: move; margin: 0 auto; } .resize-container img { display: block } .resize-container:hover img, .resize-container:active img { outline: 2px dashed rgba(222,60,80,.9); }







'resize handles'. , , .



.resize-handle-ne, .resize-handle-ne, .resize-handle-se, .resize-handle-nw, .resize-handle-sw { position: absolute; display: block; width: 10px; height: 10px; background: rgba(222,60,80,.9); z-index: 999; } .resize-handle-nw { top: -5px; left: -5px; cursor: nw-resize; } .resize-handle-sw { bottom: -5px; left: -5px; cursor: sw-resize; } .resize-handle-ne { top: -5px; right: -5px; cursor: ne-resize; } .resize-handle-se { bottom: -5px; right: -5px; cursor: se-resize; }







JavaScript

Canvas.



var resizeableImage = function(image_target) { var $container, orig_src = new Image(), image_target = $(image_target).get(0), event_state = {}, constrain = false, min_width = 60, min_height = 60, max_width = 800, max_height = 900, resize_canvas = document.createElement('canvas'); }); resizeableImage($('.resize-image'));







, . , , . jQuery , .



var resizeableImage = function(image_target) { // ... init = function(){ // Create a new image with a copy of the original src // When resizing, we will always use this original copy as the base orig_src.src=image_target.src; // Add resize handles $(image_target).wrap('<div class="resize-container"></div>') .before('<span class="resize-handle resize-handle-nw"></span>') .before('<span class="resize-handle resize-handle-ne"></span>') .after('<span class="resize-handle resize-handle-se"></span>') .after('<span class="resize-handle resize-handle-sw"></span>'); // Get a variable for the container $container = $(image_target).parent('.resize-container'); // Add events $container.on('mousedown', '.resize-handle', startResize); }; //... init(); }







startResize



endResize



, , .



startResize = function(e){ e.preventDefault(); e.stopPropagation(); saveEventState(e); $(document).on('mousemove', resizing); $(document).on('mouseup', endResize); }; endResize = function(e){ e.preventDefault(); $(document).off('mouseup touchend', endResize); $(document).off('mousemove touchmove', resizing); };







. event_state



.



saveEventState = function(e){ // Save the initial event details and container state event_state.container_width = $container.width(); event_state.container_height = $container.height(); event_state.container_left = $container.offset().left; event_state.container_top = $container.offset().top; event_state.mouse_x = (e.clientX || e.pageX || e.originalEvent.touches[0].clientX) + $(window).scrollLeft(); event_state.mouse_y = (e.clientY || e.pageY || e.originalEvent.touches[0].clientY) + $(window).scrollTop(); // This is a fix for mobile safari // For some reason it does not allow a direct copy of the touches property if(typeof e.originalEvent.touches !== 'undefined'){ event_state.touches = []; $.each(e.originalEvent.touches, function(i, ob){ event_state.touches[i] = {}; event_state.touches[i].clientX = 0+ob.clientX; event_state.touches[i].clientY = 0+ob.clientY; }); } event_state.evnt = e; }







resizing



- . . .



resizing = function(e){ var mouse={},width,height,left,top,offset=$container.offset(); mouse.x = (e.clientX || e.pageX || e.originalEvent.touches[0].clientX) + $(window).scrollLeft(); mouse.y = (e.clientY || e.pageY || e.originalEvent.touches[0].clientY) + $(window).scrollTop(); width = mouse.x - event_state.container_left; height = mouse.y - event_state.container_top; left = event_state.container_left; top = event_state.container_top; if(constrain || e.shiftKey){ height = width / orig_src.width * orig_src.height; } if(width > min_width && height > min_height && width < max_width && height < max_height){ resizeImage(width, height); // Without this Firefox will not re-calculate the the image dimensions until drag end $container.offset({'left': left, 'top': top}); } }







Shift .



.



: , , resizeImage



.





Canvas , drawImage



. , . toDataURL



Base64-encoded .



.



resizeImage = function(width, height){ resize_canvas.width = width; resize_canvas.height = height; resize_canvas.getContext('2d').drawImage(orig_src, 0, 0, width, height); $(image_target).attr('src', resize_canvas.toDataURL("image/png")); };







? : , CORS . , 'tainted canvas'.







. . , . , .



, , .







, . resizing



:



resizing = function(e){ var mouse={},width,height,left,top,offset=$container.offset(); mouse.x = (e.clientX || e.pageX || e.originalEvent.touches[0].clientX) + $(window).scrollLeft(); mouse.y = (e.clientY || e.pageY || e.originalEvent.touches[0].clientY) + $(window).scrollTop(); // Position image differently depending on the corner dragged and constraints if( $(event_state.evnt.target).hasClass('resize-handle-se') ){ width = mouse.x - event_state.container_left; height = mouse.y - event_state.container_top; left = event_state.container_left; top = event_state.container_top; } else if($(event_state.evnt.target).hasClass('resize-handle-sw') ){ width = event_state.container_width - (mouse.x - event_state.container_left); height = mouse.y - event_state.container_top; left = mouse.x; top = event_state.container_top; } else if($(event_state.evnt.target).hasClass('resize-handle-nw') ){ width = event_state.container_width - (mouse.x - event_state.container_left); height = event_state.container_height - (mouse.y - event_state.container_top); left = mouse.x; top = mouse.y; if(constrain || e.shiftKey){ top = mouse.y - ((width / orig_src.width * orig_src.height) - height); } } else if($(event_state.evnt.target).hasClass('resize-handle-ne') ){ width = mouse.x - event_state.container_left; height = event_state.container_height - (mouse.y - event_state.container_top); left = event_state.container_left; top = mouse.y; if(constrain || e.shiftKey){ top = mouse.y - ((width / orig_src.width * orig_src.height) - height); } } // Optionally maintain aspect ratio if(constrain || e.shiftKey){ height = width / orig_src.width * orig_src.height; } if(width > min_width && height > min_height && width < max_width && height < max_height){ // To improve performance you might limit how often resizeImage() is called resizeImage(width, height); // Without this Firefox will not re-calculate the the image dimensions until drag end $container.offset({'left': left, 'top': top}); } }







, resize-handle



, .





, , , , , "". . .



init = function(){ //... $container.on('mousedown', 'img', startMoving); }







startMoving



endMoving



, startResize



endResize



.



startMoving = function(e){ e.preventDefault(); e.stopPropagation(); saveEventState(e); $(document).on('mousemove', moving); $(document).on('mouseup', endMoving); }; endMoving = function(e){ e.preventDefault(); $(document).off('mouseup', endMoving); $(document).off('mousemove', moving); };







moving



. , .



moving = function(e){ var mouse={}; e.preventDefault(); e.stopPropagation(); mouse.x = (e.clientX || e.pageX) + $(window).scrollLeft(); mouse.y = (e.clientY || e.pageY) + $(window).scrollTop(); $container.offset({ 'left': mouse.x - ( event_state.mouse_x - event_state.container_left ), 'top': mouse.y - ( event_state.mouse_y - event_state.container_top ) }); };









, , . , , , , . , , , , .



HTML :



<div class="overlay"> <div class="overlay-inner"> </div> </div> <button class="btn-crop js-crop">Crop</button>







, , .



.overlay { position: absolute; left: 50%; top: 50%; margin-left: -100px; margin-top: -100px; z-index: 999; width: 200px; height: 200px; border: solid 2px rgba(222,60,80,.9); box-sizing: content-box; pointer-events: none; } .overlay:after, .overlay:before { content: ''; position: absolute; display: block; width: 204px; height: 40px; border-left: dashed 2px rgba(222,60,80,.9); border-right: dashed 2px rgba(222,60,80,.9); } .overlay:before { top: 0; margin-left: -2px; margin-top: -40px; } .overlay:after { bottom: 0; margin-left: -2px; margin-bottom: -40px; } .overlay-inner:after, .overlay-inner:before { content: ''; position: absolute; display: block; width: 40px; height: 204px; border-top: dashed 2px rgba(222,60,80,.9); border-bottom: dashed 2px rgba(222,60,80,.9); } .overlay-inner:before { left: 0; margin-left: -40px; margin-top: -2px; } .overlay-inner:after { right: 0; margin-right: -40px; margin-top: -2px; } .btn-crop { position: absolute; vertical-align: bottom; right: 5px; bottom: 5px; padding: 6px 10px; z-index: 999; background-color: rgb(222,60,80); border: none; border-radius: 5px; color: #FFF; }







JavaScript :



init = function(){ //... $('.js-crop').on('click', crop); }; crop = function(){ var crop_canvas, left = $('.overlay').offset().left - $container.offset().left, top = $('.overlay').offset().top - $container.offset().top, width = $('.overlay').width(), height = $('.overlay').height(); crop_canvas = document.createElement('canvas'); crop_canvas.width = width; crop_canvas.height = height; crop_canvas.getContext('2d').drawImage(image_target, left, top, width, height, 0, 0, width, height); window.open(crop_canvas.toDataURL("image/png")); }







crop



resizeImage



. , .



drawImage



canvas. - . - , . - , canvas, .





. .



mousedown



mouseup



- touchstart



touchend



, mousemove



touchmove



. , touchup



touchdown



( ).



touchstart



touchend



, mousedown



, mouseup



touchmove



, mousemove



.



// In init()... $container.on('mousedown touchstart', '.resize-handle', startResize); $container.on('mousedown touchstart', 'img', startMoving); //In startResize() ... $(document).on('mousemove touchmove', moving); $(document).on('mouseup touchend', endMoving); //In endResize()... $(document).off('mouseup touchend', endMoving); $(document).off('mousemove touchmove', moving); //In startMoving()... $(document).on('mousemove touchmove', moving); $(document).on('mouseup touchend', endMoving); //In endMoving()... $(document).off('mouseup touchend', endMoving); $(document).off('mousemove touchmove', moving);







, "" . Hammer, . , , .



, , , saveEventState



. .



" " . , . moving



:



moving = function(e){ var mouse={}, touches; e.preventDefault(); e.stopPropagation(); touches = e.originalEvent.touches; mouse.x = (e.clientX || e.pageX || touches[0].clientX) + $(window).scrollLeft(); mouse.y = (e.clientY || e.pageY || touches[0].clientY) + $(window).scrollTop(); $container.offset({ 'left': mouse.x - ( event_state.mouse_x - event_state.container_left ), 'top': mouse.y - ( event_state.mouse_y - event_state.container_top ) }); // Watch for pinch zoom gesture while moving if(event_state.touches && event_state.touches.length > 1 && touches.length > 1){ var width = event_state.container_width, height = event_state.container_height; var a = event_state.touches[0].clientX - event_state.touches[1].clientX; a = a * a; var b = event_state.touches[0].clientY - event_state.touches[1].clientY; b = b * b; var dist1 = Math.sqrt( a + b ); a = e.originalEvent.touches[0].clientX - touches[1].clientX; a = a * a; b = e.originalEvent.touches[0].clientY - touches[1].clientY; b = b * b; var dist2 = Math.sqrt( a + b ); var ratio = dist2 /dist1; width = width * ratio; height = height * ratio; // To improve performance you might limit how often resizeImage() is called resizeImage(width, height); } };







.







. .



Chrome "", Firefox .



, .




HTML5, , , .



- . , . , .



canvas




, , . , , .



. . , , . , .



!





:

<img class="resize-image" src="image.jpg" alt="Image" />







! HTML .



CSS

CSS- . resize-container



.



.resize-container { position: relative; display: inline-block; cursor: move; margin: 0 auto; } .resize-container img { display: block } .resize-container:hover img, .resize-container:active img { outline: 2px dashed rgba(222,60,80,.9); }







'resize handles'. , , .



.resize-handle-ne, .resize-handle-ne, .resize-handle-se, .resize-handle-nw, .resize-handle-sw { position: absolute; display: block; width: 10px; height: 10px; background: rgba(222,60,80,.9); z-index: 999; } .resize-handle-nw { top: -5px; left: -5px; cursor: nw-resize; } .resize-handle-sw { bottom: -5px; left: -5px; cursor: sw-resize; } .resize-handle-ne { top: -5px; right: -5px; cursor: ne-resize; } .resize-handle-se { bottom: -5px; right: -5px; cursor: se-resize; }







JavaScript

Canvas.



var resizeableImage = function(image_target) { var $container, orig_src = new Image(), image_target = $(image_target).get(0), event_state = {}, constrain = false, min_width = 60, min_height = 60, max_width = 800, max_height = 900, resize_canvas = document.createElement('canvas'); }); resizeableImage($('.resize-image'));







, . , , . jQuery , .



var resizeableImage = function(image_target) { // ... init = function(){ // Create a new image with a copy of the original src // When resizing, we will always use this original copy as the base orig_src.src=image_target.src; // Add resize handles $(image_target).wrap('<div class="resize-container"></div>') .before('<span class="resize-handle resize-handle-nw"></span>') .before('<span class="resize-handle resize-handle-ne"></span>') .after('<span class="resize-handle resize-handle-se"></span>') .after('<span class="resize-handle resize-handle-sw"></span>'); // Get a variable for the container $container = $(image_target).parent('.resize-container'); // Add events $container.on('mousedown', '.resize-handle', startResize); }; //... init(); }







startResize



endResize



, , .



startResize = function(e){ e.preventDefault(); e.stopPropagation(); saveEventState(e); $(document).on('mousemove', resizing); $(document).on('mouseup', endResize); }; endResize = function(e){ e.preventDefault(); $(document).off('mouseup touchend', endResize); $(document).off('mousemove touchmove', resizing); };







. event_state



.



saveEventState = function(e){ // Save the initial event details and container state event_state.container_width = $container.width(); event_state.container_height = $container.height(); event_state.container_left = $container.offset().left; event_state.container_top = $container.offset().top; event_state.mouse_x = (e.clientX || e.pageX || e.originalEvent.touches[0].clientX) + $(window).scrollLeft(); event_state.mouse_y = (e.clientY || e.pageY || e.originalEvent.touches[0].clientY) + $(window).scrollTop(); // This is a fix for mobile safari // For some reason it does not allow a direct copy of the touches property if(typeof e.originalEvent.touches !== 'undefined'){ event_state.touches = []; $.each(e.originalEvent.touches, function(i, ob){ event_state.touches[i] = {}; event_state.touches[i].clientX = 0+ob.clientX; event_state.touches[i].clientY = 0+ob.clientY; }); } event_state.evnt = e; }







resizing



- . . .



resizing = function(e){ var mouse={},width,height,left,top,offset=$container.offset(); mouse.x = (e.clientX || e.pageX || e.originalEvent.touches[0].clientX) + $(window).scrollLeft(); mouse.y = (e.clientY || e.pageY || e.originalEvent.touches[0].clientY) + $(window).scrollTop(); width = mouse.x - event_state.container_left; height = mouse.y - event_state.container_top; left = event_state.container_left; top = event_state.container_top; if(constrain || e.shiftKey){ height = width / orig_src.width * orig_src.height; } if(width > min_width && height > min_height && width < max_width && height < max_height){ resizeImage(width, height); // Without this Firefox will not re-calculate the the image dimensions until drag end $container.offset({'left': left, 'top': top}); } }







Shift .



.



: , , resizeImage



.





Canvas , drawImage



. , . toDataURL



Base64-encoded .



.



resizeImage = function(width, height){ resize_canvas.width = width; resize_canvas.height = height; resize_canvas.getContext('2d').drawImage(orig_src, 0, 0, width, height); $(image_target).attr('src', resize_canvas.toDataURL("image/png")); };







? : , CORS . , 'tainted canvas'.







. . , . , .



, , .







, . resizing



:



resizing = function(e){ var mouse={},width,height,left,top,offset=$container.offset(); mouse.x = (e.clientX || e.pageX || e.originalEvent.touches[0].clientX) + $(window).scrollLeft(); mouse.y = (e.clientY || e.pageY || e.originalEvent.touches[0].clientY) + $(window).scrollTop(); // Position image differently depending on the corner dragged and constraints if( $(event_state.evnt.target).hasClass('resize-handle-se') ){ width = mouse.x - event_state.container_left; height = mouse.y - event_state.container_top; left = event_state.container_left; top = event_state.container_top; } else if($(event_state.evnt.target).hasClass('resize-handle-sw') ){ width = event_state.container_width - (mouse.x - event_state.container_left); height = mouse.y - event_state.container_top; left = mouse.x; top = event_state.container_top; } else if($(event_state.evnt.target).hasClass('resize-handle-nw') ){ width = event_state.container_width - (mouse.x - event_state.container_left); height = event_state.container_height - (mouse.y - event_state.container_top); left = mouse.x; top = mouse.y; if(constrain || e.shiftKey){ top = mouse.y - ((width / orig_src.width * orig_src.height) - height); } } else if($(event_state.evnt.target).hasClass('resize-handle-ne') ){ width = mouse.x - event_state.container_left; height = event_state.container_height - (mouse.y - event_state.container_top); left = event_state.container_left; top = mouse.y; if(constrain || e.shiftKey){ top = mouse.y - ((width / orig_src.width * orig_src.height) - height); } } // Optionally maintain aspect ratio if(constrain || e.shiftKey){ height = width / orig_src.width * orig_src.height; } if(width > min_width && height > min_height && width < max_width && height < max_height){ // To improve performance you might limit how often resizeImage() is called resizeImage(width, height); // Without this Firefox will not re-calculate the the image dimensions until drag end $container.offset({'left': left, 'top': top}); } }







, resize-handle



, .





, , , , , "". . .



init = function(){ //... $container.on('mousedown', 'img', startMoving); }







startMoving



endMoving



, startResize



endResize



.



startMoving = function(e){ e.preventDefault(); e.stopPropagation(); saveEventState(e); $(document).on('mousemove', moving); $(document).on('mouseup', endMoving); }; endMoving = function(e){ e.preventDefault(); $(document).off('mouseup', endMoving); $(document).off('mousemove', moving); };







moving



. , .



moving = function(e){ var mouse={}; e.preventDefault(); e.stopPropagation(); mouse.x = (e.clientX || e.pageX) + $(window).scrollLeft(); mouse.y = (e.clientY || e.pageY) + $(window).scrollTop(); $container.offset({ 'left': mouse.x - ( event_state.mouse_x - event_state.container_left ), 'top': mouse.y - ( event_state.mouse_y - event_state.container_top ) }); };









, , . , , , , . , , , , .



HTML :



<div class="overlay"> <div class="overlay-inner"> </div> </div> <button class="btn-crop js-crop">Crop</button>







, , .



.overlay { position: absolute; left: 50%; top: 50%; margin-left: -100px; margin-top: -100px; z-index: 999; width: 200px; height: 200px; border: solid 2px rgba(222,60,80,.9); box-sizing: content-box; pointer-events: none; } .overlay:after, .overlay:before { content: ''; position: absolute; display: block; width: 204px; height: 40px; border-left: dashed 2px rgba(222,60,80,.9); border-right: dashed 2px rgba(222,60,80,.9); } .overlay:before { top: 0; margin-left: -2px; margin-top: -40px; } .overlay:after { bottom: 0; margin-left: -2px; margin-bottom: -40px; } .overlay-inner:after, .overlay-inner:before { content: ''; position: absolute; display: block; width: 40px; height: 204px; border-top: dashed 2px rgba(222,60,80,.9); border-bottom: dashed 2px rgba(222,60,80,.9); } .overlay-inner:before { left: 0; margin-left: -40px; margin-top: -2px; } .overlay-inner:after { right: 0; margin-right: -40px; margin-top: -2px; } .btn-crop { position: absolute; vertical-align: bottom; right: 5px; bottom: 5px; padding: 6px 10px; z-index: 999; background-color: rgb(222,60,80); border: none; border-radius: 5px; color: #FFF; }







JavaScript :



init = function(){ //... $('.js-crop').on('click', crop); }; crop = function(){ var crop_canvas, left = $('.overlay').offset().left - $container.offset().left, top = $('.overlay').offset().top - $container.offset().top, width = $('.overlay').width(), height = $('.overlay').height(); crop_canvas = document.createElement('canvas'); crop_canvas.width = width; crop_canvas.height = height; crop_canvas.getContext('2d').drawImage(image_target, left, top, width, height, 0, 0, width, height); window.open(crop_canvas.toDataURL("image/png")); }







crop



resizeImage



. , .



drawImage



canvas. - . - , . - , canvas, .





. .



mousedown



mouseup



- touchstart



touchend



, mousemove



touchmove



. , touchup



touchdown



( ).



touchstart



touchend



, mousedown



, mouseup



touchmove



, mousemove



.



// In init()... $container.on('mousedown touchstart', '.resize-handle', startResize); $container.on('mousedown touchstart', 'img', startMoving); //In startResize() ... $(document).on('mousemove touchmove', moving); $(document).on('mouseup touchend', endMoving); //In endResize()... $(document).off('mouseup touchend', endMoving); $(document).off('mousemove touchmove', moving); //In startMoving()... $(document).on('mousemove touchmove', moving); $(document).on('mouseup touchend', endMoving); //In endMoving()... $(document).off('mouseup touchend', endMoving); $(document).off('mousemove touchmove', moving);







, "" . Hammer, . , , .



, , , saveEventState



. .



" " . , . moving



:



moving = function(e){ var mouse={}, touches; e.preventDefault(); e.stopPropagation(); touches = e.originalEvent.touches; mouse.x = (e.clientX || e.pageX || touches[0].clientX) + $(window).scrollLeft(); mouse.y = (e.clientY || e.pageY || touches[0].clientY) + $(window).scrollTop(); $container.offset({ 'left': mouse.x - ( event_state.mouse_x - event_state.container_left ), 'top': mouse.y - ( event_state.mouse_y - event_state.container_top ) }); // Watch for pinch zoom gesture while moving if(event_state.touches && event_state.touches.length > 1 && touches.length > 1){ var width = event_state.container_width, height = event_state.container_height; var a = event_state.touches[0].clientX - event_state.touches[1].clientX; a = a * a; var b = event_state.touches[0].clientY - event_state.touches[1].clientY; b = b * b; var dist1 = Math.sqrt( a + b ); a = e.originalEvent.touches[0].clientX - touches[1].clientX; a = a * a; b = e.originalEvent.touches[0].clientY - touches[1].clientY; b = b * b; var dist2 = Math.sqrt( a + b ); var ratio = dist2 /dist1; width = width * ratio; height = height * ratio; // To improve performance you might limit how often resizeImage() is called resizeImage(width, height); } };







.







. .



Chrome "", Firefox .



, .




HTML5, , , .



- . , . , .



canvas




, , . , , .



. . , , . , .



!





:

<img class="resize-image" src="image.jpg" alt="Image" />







! HTML .



CSS

CSS- . resize-container



.



.resize-container { position: relative; display: inline-block; cursor: move; margin: 0 auto; } .resize-container img { display: block } .resize-container:hover img, .resize-container:active img { outline: 2px dashed rgba(222,60,80,.9); }







'resize handles'. , , .



.resize-handle-ne, .resize-handle-ne, .resize-handle-se, .resize-handle-nw, .resize-handle-sw { position: absolute; display: block; width: 10px; height: 10px; background: rgba(222,60,80,.9); z-index: 999; } .resize-handle-nw { top: -5px; left: -5px; cursor: nw-resize; } .resize-handle-sw { bottom: -5px; left: -5px; cursor: sw-resize; } .resize-handle-ne { top: -5px; right: -5px; cursor: ne-resize; } .resize-handle-se { bottom: -5px; right: -5px; cursor: se-resize; }







JavaScript

Canvas.



var resizeableImage = function(image_target) { var $container, orig_src = new Image(), image_target = $(image_target).get(0), event_state = {}, constrain = false, min_width = 60, min_height = 60, max_width = 800, max_height = 900, resize_canvas = document.createElement('canvas'); }); resizeableImage($('.resize-image'));







, . , , . jQuery , .



var resizeableImage = function(image_target) { // ... init = function(){ // Create a new image with a copy of the original src // When resizing, we will always use this original copy as the base orig_src.src=image_target.src; // Add resize handles $(image_target).wrap('<div class="resize-container"></div>') .before('<span class="resize-handle resize-handle-nw"></span>') .before('<span class="resize-handle resize-handle-ne"></span>') .after('<span class="resize-handle resize-handle-se"></span>') .after('<span class="resize-handle resize-handle-sw"></span>'); // Get a variable for the container $container = $(image_target).parent('.resize-container'); // Add events $container.on('mousedown', '.resize-handle', startResize); }; //... init(); }







startResize



endResize



, , .



startResize = function(e){ e.preventDefault(); e.stopPropagation(); saveEventState(e); $(document).on('mousemove', resizing); $(document).on('mouseup', endResize); }; endResize = function(e){ e.preventDefault(); $(document).off('mouseup touchend', endResize); $(document).off('mousemove touchmove', resizing); };







. event_state



.



saveEventState = function(e){ // Save the initial event details and container state event_state.container_width = $container.width(); event_state.container_height = $container.height(); event_state.container_left = $container.offset().left; event_state.container_top = $container.offset().top; event_state.mouse_x = (e.clientX || e.pageX || e.originalEvent.touches[0].clientX) + $(window).scrollLeft(); event_state.mouse_y = (e.clientY || e.pageY || e.originalEvent.touches[0].clientY) + $(window).scrollTop(); // This is a fix for mobile safari // For some reason it does not allow a direct copy of the touches property if(typeof e.originalEvent.touches !== 'undefined'){ event_state.touches = []; $.each(e.originalEvent.touches, function(i, ob){ event_state.touches[i] = {}; event_state.touches[i].clientX = 0+ob.clientX; event_state.touches[i].clientY = 0+ob.clientY; }); } event_state.evnt = e; }







resizing



- . . .



resizing = function(e){ var mouse={},width,height,left,top,offset=$container.offset(); mouse.x = (e.clientX || e.pageX || e.originalEvent.touches[0].clientX) + $(window).scrollLeft(); mouse.y = (e.clientY || e.pageY || e.originalEvent.touches[0].clientY) + $(window).scrollTop(); width = mouse.x - event_state.container_left; height = mouse.y - event_state.container_top; left = event_state.container_left; top = event_state.container_top; if(constrain || e.shiftKey){ height = width / orig_src.width * orig_src.height; } if(width > min_width && height > min_height && width < max_width && height < max_height){ resizeImage(width, height); // Without this Firefox will not re-calculate the the image dimensions until drag end $container.offset({'left': left, 'top': top}); } }







Shift .



.



: , , resizeImage



.





Canvas , drawImage



. , . toDataURL



Base64-encoded .



.



resizeImage = function(width, height){ resize_canvas.width = width; resize_canvas.height = height; resize_canvas.getContext('2d').drawImage(orig_src, 0, 0, width, height); $(image_target).attr('src', resize_canvas.toDataURL("image/png")); };







? : , CORS . , 'tainted canvas'.







. . , . , .



, , .







, . resizing



:



resizing = function(e){ var mouse={},width,height,left,top,offset=$container.offset(); mouse.x = (e.clientX || e.pageX || e.originalEvent.touches[0].clientX) + $(window).scrollLeft(); mouse.y = (e.clientY || e.pageY || e.originalEvent.touches[0].clientY) + $(window).scrollTop(); // Position image differently depending on the corner dragged and constraints if( $(event_state.evnt.target).hasClass('resize-handle-se') ){ width = mouse.x - event_state.container_left; height = mouse.y - event_state.container_top; left = event_state.container_left; top = event_state.container_top; } else if($(event_state.evnt.target).hasClass('resize-handle-sw') ){ width = event_state.container_width - (mouse.x - event_state.container_left); height = mouse.y - event_state.container_top; left = mouse.x; top = event_state.container_top; } else if($(event_state.evnt.target).hasClass('resize-handle-nw') ){ width = event_state.container_width - (mouse.x - event_state.container_left); height = event_state.container_height - (mouse.y - event_state.container_top); left = mouse.x; top = mouse.y; if(constrain || e.shiftKey){ top = mouse.y - ((width / orig_src.width * orig_src.height) - height); } } else if($(event_state.evnt.target).hasClass('resize-handle-ne') ){ width = mouse.x - event_state.container_left; height = event_state.container_height - (mouse.y - event_state.container_top); left = event_state.container_left; top = mouse.y; if(constrain || e.shiftKey){ top = mouse.y - ((width / orig_src.width * orig_src.height) - height); } } // Optionally maintain aspect ratio if(constrain || e.shiftKey){ height = width / orig_src.width * orig_src.height; } if(width > min_width && height > min_height && width < max_width && height < max_height){ // To improve performance you might limit how often resizeImage() is called resizeImage(width, height); // Without this Firefox will not re-calculate the the image dimensions until drag end $container.offset({'left': left, 'top': top}); } }







, resize-handle



, .





, , , , , "". . .



init = function(){ //... $container.on('mousedown', 'img', startMoving); }







startMoving



endMoving



, startResize



endResize



.



startMoving = function(e){ e.preventDefault(); e.stopPropagation(); saveEventState(e); $(document).on('mousemove', moving); $(document).on('mouseup', endMoving); }; endMoving = function(e){ e.preventDefault(); $(document).off('mouseup', endMoving); $(document).off('mousemove', moving); };







moving



. , .



moving = function(e){ var mouse={}; e.preventDefault(); e.stopPropagation(); mouse.x = (e.clientX || e.pageX) + $(window).scrollLeft(); mouse.y = (e.clientY || e.pageY) + $(window).scrollTop(); $container.offset({ 'left': mouse.x - ( event_state.mouse_x - event_state.container_left ), 'top': mouse.y - ( event_state.mouse_y - event_state.container_top ) }); };









, , . , , , , . , , , , .



HTML :



<div class="overlay"> <div class="overlay-inner"> </div> </div> <button class="btn-crop js-crop">Crop</button>







, , .



.overlay { position: absolute; left: 50%; top: 50%; margin-left: -100px; margin-top: -100px; z-index: 999; width: 200px; height: 200px; border: solid 2px rgba(222,60,80,.9); box-sizing: content-box; pointer-events: none; } .overlay:after, .overlay:before { content: ''; position: absolute; display: block; width: 204px; height: 40px; border-left: dashed 2px rgba(222,60,80,.9); border-right: dashed 2px rgba(222,60,80,.9); } .overlay:before { top: 0; margin-left: -2px; margin-top: -40px; } .overlay:after { bottom: 0; margin-left: -2px; margin-bottom: -40px; } .overlay-inner:after, .overlay-inner:before { content: ''; position: absolute; display: block; width: 40px; height: 204px; border-top: dashed 2px rgba(222,60,80,.9); border-bottom: dashed 2px rgba(222,60,80,.9); } .overlay-inner:before { left: 0; margin-left: -40px; margin-top: -2px; } .overlay-inner:after { right: 0; margin-right: -40px; margin-top: -2px; } .btn-crop { position: absolute; vertical-align: bottom; right: 5px; bottom: 5px; padding: 6px 10px; z-index: 999; background-color: rgb(222,60,80); border: none; border-radius: 5px; color: #FFF; }







JavaScript :



init = function(){ //... $('.js-crop').on('click', crop); }; crop = function(){ var crop_canvas, left = $('.overlay').offset().left - $container.offset().left, top = $('.overlay').offset().top - $container.offset().top, width = $('.overlay').width(), height = $('.overlay').height(); crop_canvas = document.createElement('canvas'); crop_canvas.width = width; crop_canvas.height = height; crop_canvas.getContext('2d').drawImage(image_target, left, top, width, height, 0, 0, width, height); window.open(crop_canvas.toDataURL("image/png")); }







crop



resizeImage



. , .



drawImage



canvas. - . - , . - , canvas, .





. .



mousedown



mouseup



- touchstart



touchend



, mousemove



touchmove



. , touchup



touchdown



( ).



touchstart



touchend



, mousedown



, mouseup



touchmove



, mousemove



.



// In init()... $container.on('mousedown touchstart', '.resize-handle', startResize); $container.on('mousedown touchstart', 'img', startMoving); //In startResize() ... $(document).on('mousemove touchmove', moving); $(document).on('mouseup touchend', endMoving); //In endResize()... $(document).off('mouseup touchend', endMoving); $(document).off('mousemove touchmove', moving); //In startMoving()... $(document).on('mousemove touchmove', moving); $(document).on('mouseup touchend', endMoving); //In endMoving()... $(document).off('mouseup touchend', endMoving); $(document).off('mousemove touchmove', moving);







, "" . Hammer, . , , .



, , , saveEventState



. .



" " . , . moving



:



moving = function(e){ var mouse={}, touches; e.preventDefault(); e.stopPropagation(); touches = e.originalEvent.touches; mouse.x = (e.clientX || e.pageX || touches[0].clientX) + $(window).scrollLeft(); mouse.y = (e.clientY || e.pageY || touches[0].clientY) + $(window).scrollTop(); $container.offset({ 'left': mouse.x - ( event_state.mouse_x - event_state.container_left ), 'top': mouse.y - ( event_state.mouse_y - event_state.container_top ) }); // Watch for pinch zoom gesture while moving if(event_state.touches && event_state.touches.length > 1 && touches.length > 1){ var width = event_state.container_width, height = event_state.container_height; var a = event_state.touches[0].clientX - event_state.touches[1].clientX; a = a * a; var b = event_state.touches[0].clientY - event_state.touches[1].clientY; b = b * b; var dist1 = Math.sqrt( a + b ); a = e.originalEvent.touches[0].clientX - touches[1].clientX; a = a * a; b = e.originalEvent.touches[0].clientY - touches[1].clientY; b = b * b; var dist2 = Math.sqrt( a + b ); var ratio = dist2 /dist1; width = width * ratio; height = height * ratio; // To improve performance you might limit how often resizeImage() is called resizeImage(width, height); } };







.







. .



Chrome "", Firefox .



, .




  HTML5,     ,      ,   . 
      



- . , . , .



canvas




, , . , , .



. . , , . , .



!





:

<img class="resize-image" src="image.jpg" alt="Image" />







! HTML .



CSS

CSS- . resize-container



.



.resize-container { position: relative; display: inline-block; cursor: move; margin: 0 auto; } .resize-container img { display: block } .resize-container:hover img, .resize-container:active img { outline: 2px dashed rgba(222,60,80,.9); }







'resize handles'. , , .



.resize-handle-ne, .resize-handle-ne, .resize-handle-se, .resize-handle-nw, .resize-handle-sw { position: absolute; display: block; width: 10px; height: 10px; background: rgba(222,60,80,.9); z-index: 999; } .resize-handle-nw { top: -5px; left: -5px; cursor: nw-resize; } .resize-handle-sw { bottom: -5px; left: -5px; cursor: sw-resize; } .resize-handle-ne { top: -5px; right: -5px; cursor: ne-resize; } .resize-handle-se { bottom: -5px; right: -5px; cursor: se-resize; }







JavaScript

Canvas.



var resizeableImage = function(image_target) { var $container, orig_src = new Image(), image_target = $(image_target).get(0), event_state = {}, constrain = false, min_width = 60, min_height = 60, max_width = 800, max_height = 900, resize_canvas = document.createElement('canvas'); }); resizeableImage($('.resize-image'));







, . , , . jQuery , .



var resizeableImage = function(image_target) { // ... init = function(){ // Create a new image with a copy of the original src // When resizing, we will always use this original copy as the base orig_src.src=image_target.src; // Add resize handles $(image_target).wrap('<div class="resize-container"></div>') .before('<span class="resize-handle resize-handle-nw"></span>') .before('<span class="resize-handle resize-handle-ne"></span>') .after('<span class="resize-handle resize-handle-se"></span>') .after('<span class="resize-handle resize-handle-sw"></span>'); // Get a variable for the container $container = $(image_target).parent('.resize-container'); // Add events $container.on('mousedown', '.resize-handle', startResize); }; //... init(); }







startResize



endResize



, , .



startResize = function(e){ e.preventDefault(); e.stopPropagation(); saveEventState(e); $(document).on('mousemove', resizing); $(document).on('mouseup', endResize); }; endResize = function(e){ e.preventDefault(); $(document).off('mouseup touchend', endResize); $(document).off('mousemove touchmove', resizing); };







. event_state



.



saveEventState = function(e){ // Save the initial event details and container state event_state.container_width = $container.width(); event_state.container_height = $container.height(); event_state.container_left = $container.offset().left; event_state.container_top = $container.offset().top; event_state.mouse_x = (e.clientX || e.pageX || e.originalEvent.touches[0].clientX) + $(window).scrollLeft(); event_state.mouse_y = (e.clientY || e.pageY || e.originalEvent.touches[0].clientY) + $(window).scrollTop(); // This is a fix for mobile safari // For some reason it does not allow a direct copy of the touches property if(typeof e.originalEvent.touches !== 'undefined'){ event_state.touches = []; $.each(e.originalEvent.touches, function(i, ob){ event_state.touches[i] = {}; event_state.touches[i].clientX = 0+ob.clientX; event_state.touches[i].clientY = 0+ob.clientY; }); } event_state.evnt = e; }







resizing



- . . .



resizing = function(e){ var mouse={},width,height,left,top,offset=$container.offset(); mouse.x = (e.clientX || e.pageX || e.originalEvent.touches[0].clientX) + $(window).scrollLeft(); mouse.y = (e.clientY || e.pageY || e.originalEvent.touches[0].clientY) + $(window).scrollTop(); width = mouse.x - event_state.container_left; height = mouse.y - event_state.container_top; left = event_state.container_left; top = event_state.container_top; if(constrain || e.shiftKey){ height = width / orig_src.width * orig_src.height; } if(width > min_width && height > min_height && width < max_width && height < max_height){ resizeImage(width, height); // Without this Firefox will not re-calculate the the image dimensions until drag end $container.offset({'left': left, 'top': top}); } }







Shift .



.



: , , resizeImage



.





Canvas , drawImage



. , . toDataURL



Base64-encoded .



.



resizeImage = function(width, height){ resize_canvas.width = width; resize_canvas.height = height; resize_canvas.getContext('2d').drawImage(orig_src, 0, 0, width, height); $(image_target).attr('src', resize_canvas.toDataURL("image/png")); };







? : , CORS . , 'tainted canvas'.







. . , . , .



, , .







, . resizing



:



resizing = function(e){ var mouse={},width,height,left,top,offset=$container.offset(); mouse.x = (e.clientX || e.pageX || e.originalEvent.touches[0].clientX) + $(window).scrollLeft(); mouse.y = (e.clientY || e.pageY || e.originalEvent.touches[0].clientY) + $(window).scrollTop(); // Position image differently depending on the corner dragged and constraints if( $(event_state.evnt.target).hasClass('resize-handle-se') ){ width = mouse.x - event_state.container_left; height = mouse.y - event_state.container_top; left = event_state.container_left; top = event_state.container_top; } else if($(event_state.evnt.target).hasClass('resize-handle-sw') ){ width = event_state.container_width - (mouse.x - event_state.container_left); height = mouse.y - event_state.container_top; left = mouse.x; top = event_state.container_top; } else if($(event_state.evnt.target).hasClass('resize-handle-nw') ){ width = event_state.container_width - (mouse.x - event_state.container_left); height = event_state.container_height - (mouse.y - event_state.container_top); left = mouse.x; top = mouse.y; if(constrain || e.shiftKey){ top = mouse.y - ((width / orig_src.width * orig_src.height) - height); } } else if($(event_state.evnt.target).hasClass('resize-handle-ne') ){ width = mouse.x - event_state.container_left; height = event_state.container_height - (mouse.y - event_state.container_top); left = event_state.container_left; top = mouse.y; if(constrain || e.shiftKey){ top = mouse.y - ((width / orig_src.width * orig_src.height) - height); } } // Optionally maintain aspect ratio if(constrain || e.shiftKey){ height = width / orig_src.width * orig_src.height; } if(width > min_width && height > min_height && width < max_width && height < max_height){ // To improve performance you might limit how often resizeImage() is called resizeImage(width, height); // Without this Firefox will not re-calculate the the image dimensions until drag end $container.offset({'left': left, 'top': top}); } }







, resize-handle



, .





, , , , , "". . .



init = function(){ //... $container.on('mousedown', 'img', startMoving); }







startMoving



endMoving



, startResize



endResize



.



startMoving = function(e){ e.preventDefault(); e.stopPropagation(); saveEventState(e); $(document).on('mousemove', moving); $(document).on('mouseup', endMoving); }; endMoving = function(e){ e.preventDefault(); $(document).off('mouseup', endMoving); $(document).off('mousemove', moving); };







moving



. , .



moving = function(e){ var mouse={}; e.preventDefault(); e.stopPropagation(); mouse.x = (e.clientX || e.pageX) + $(window).scrollLeft(); mouse.y = (e.clientY || e.pageY) + $(window).scrollTop(); $container.offset({ 'left': mouse.x - ( event_state.mouse_x - event_state.container_left ), 'top': mouse.y - ( event_state.mouse_y - event_state.container_top ) }); };









, , . , , , , . , , , , .



HTML :



<div class="overlay"> <div class="overlay-inner"> </div> </div> <button class="btn-crop js-crop">Crop</button>







, , .



.overlay { position: absolute; left: 50%; top: 50%; margin-left: -100px; margin-top: -100px; z-index: 999; width: 200px; height: 200px; border: solid 2px rgba(222,60,80,.9); box-sizing: content-box; pointer-events: none; } .overlay:after, .overlay:before { content: ''; position: absolute; display: block; width: 204px; height: 40px; border-left: dashed 2px rgba(222,60,80,.9); border-right: dashed 2px rgba(222,60,80,.9); } .overlay:before { top: 0; margin-left: -2px; margin-top: -40px; } .overlay:after { bottom: 0; margin-left: -2px; margin-bottom: -40px; } .overlay-inner:after, .overlay-inner:before { content: ''; position: absolute; display: block; width: 40px; height: 204px; border-top: dashed 2px rgba(222,60,80,.9); border-bottom: dashed 2px rgba(222,60,80,.9); } .overlay-inner:before { left: 0; margin-left: -40px; margin-top: -2px; } .overlay-inner:after { right: 0; margin-right: -40px; margin-top: -2px; } .btn-crop { position: absolute; vertical-align: bottom; right: 5px; bottom: 5px; padding: 6px 10px; z-index: 999; background-color: rgb(222,60,80); border: none; border-radius: 5px; color: #FFF; }







JavaScript :



init = function(){ //... $('.js-crop').on('click', crop); }; crop = function(){ var crop_canvas, left = $('.overlay').offset().left - $container.offset().left, top = $('.overlay').offset().top - $container.offset().top, width = $('.overlay').width(), height = $('.overlay').height(); crop_canvas = document.createElement('canvas'); crop_canvas.width = width; crop_canvas.height = height; crop_canvas.getContext('2d').drawImage(image_target, left, top, width, height, 0, 0, width, height); window.open(crop_canvas.toDataURL("image/png")); }







crop



resizeImage



. , .



drawImage



canvas. - . - , . - , canvas, .





. .



mousedown



mouseup



- touchstart



touchend



, mousemove



touchmove



. , touchup



touchdown



( ).



touchstart



touchend



, mousedown



, mouseup



touchmove



, mousemove



.



// In init()... $container.on('mousedown touchstart', '.resize-handle', startResize); $container.on('mousedown touchstart', 'img', startMoving); //In startResize() ... $(document).on('mousemove touchmove', moving); $(document).on('mouseup touchend', endMoving); //In endResize()... $(document).off('mouseup touchend', endMoving); $(document).off('mousemove touchmove', moving); //In startMoving()... $(document).on('mousemove touchmove', moving); $(document).on('mouseup touchend', endMoving); //In endMoving()... $(document).off('mouseup touchend', endMoving); $(document).off('mousemove touchmove', moving);







, "" . Hammer, . , , .



, , , saveEventState



. .



" " . , . moving



:



moving = function(e){ var mouse={}, touches; e.preventDefault(); e.stopPropagation(); touches = e.originalEvent.touches; mouse.x = (e.clientX || e.pageX || touches[0].clientX) + $(window).scrollLeft(); mouse.y = (e.clientY || e.pageY || touches[0].clientY) + $(window).scrollTop(); $container.offset({ 'left': mouse.x - ( event_state.mouse_x - event_state.container_left ), 'top': mouse.y - ( event_state.mouse_y - event_state.container_top ) }); // Watch for pinch zoom gesture while moving if(event_state.touches && event_state.touches.length > 1 && touches.length > 1){ var width = event_state.container_width, height = event_state.container_height; var a = event_state.touches[0].clientX - event_state.touches[1].clientX; a = a * a; var b = event_state.touches[0].clientY - event_state.touches[1].clientY; b = b * b; var dist1 = Math.sqrt( a + b ); a = e.originalEvent.touches[0].clientX - touches[1].clientX; a = a * a; b = e.originalEvent.touches[0].clientY - touches[1].clientY; b = b * b; var dist2 = Math.sqrt( a + b ); var ratio = dist2 /dist1; width = width * ratio; height = height * ratio; // To improve performance you might limit how often resizeImage() is called resizeImage(width, height); } };







.







. .



Chrome "", Firefox .



, .




HTML5, , , .



- . , . , .



canvas




, , . , , .



. . , , . , .



!





:

<img class="resize-image" src="image.jpg" alt="Image" />







! HTML .



CSS

CSS- . resize-container



.



.resize-container { position: relative; display: inline-block; cursor: move; margin: 0 auto; } .resize-container img { display: block } .resize-container:hover img, .resize-container:active img { outline: 2px dashed rgba(222,60,80,.9); }







'resize handles'. , , .



.resize-handle-ne, .resize-handle-ne, .resize-handle-se, .resize-handle-nw, .resize-handle-sw { position: absolute; display: block; width: 10px; height: 10px; background: rgba(222,60,80,.9); z-index: 999; } .resize-handle-nw { top: -5px; left: -5px; cursor: nw-resize; } .resize-handle-sw { bottom: -5px; left: -5px; cursor: sw-resize; } .resize-handle-ne { top: -5px; right: -5px; cursor: ne-resize; } .resize-handle-se { bottom: -5px; right: -5px; cursor: se-resize; }







JavaScript

Canvas.



var resizeableImage = function(image_target) { var $container, orig_src = new Image(), image_target = $(image_target).get(0), event_state = {}, constrain = false, min_width = 60, min_height = 60, max_width = 800, max_height = 900, resize_canvas = document.createElement('canvas'); }); resizeableImage($('.resize-image'));







, . , , . jQuery , .



var resizeableImage = function(image_target) { // ... init = function(){ // Create a new image with a copy of the original src // When resizing, we will always use this original copy as the base orig_src.src=image_target.src; // Add resize handles $(image_target).wrap('<div class="resize-container"></div>') .before('<span class="resize-handle resize-handle-nw"></span>') .before('<span class="resize-handle resize-handle-ne"></span>') .after('<span class="resize-handle resize-handle-se"></span>') .after('<span class="resize-handle resize-handle-sw"></span>'); // Get a variable for the container $container = $(image_target).parent('.resize-container'); // Add events $container.on('mousedown', '.resize-handle', startResize); }; //... init(); }







startResize



endResize



, , .



startResize = function(e){ e.preventDefault(); e.stopPropagation(); saveEventState(e); $(document).on('mousemove', resizing); $(document).on('mouseup', endResize); }; endResize = function(e){ e.preventDefault(); $(document).off('mouseup touchend', endResize); $(document).off('mousemove touchmove', resizing); };







. event_state



.



saveEventState = function(e){ // Save the initial event details and container state event_state.container_width = $container.width(); event_state.container_height = $container.height(); event_state.container_left = $container.offset().left; event_state.container_top = $container.offset().top; event_state.mouse_x = (e.clientX || e.pageX || e.originalEvent.touches[0].clientX) + $(window).scrollLeft(); event_state.mouse_y = (e.clientY || e.pageY || e.originalEvent.touches[0].clientY) + $(window).scrollTop(); // This is a fix for mobile safari // For some reason it does not allow a direct copy of the touches property if(typeof e.originalEvent.touches !== 'undefined'){ event_state.touches = []; $.each(e.originalEvent.touches, function(i, ob){ event_state.touches[i] = {}; event_state.touches[i].clientX = 0+ob.clientX; event_state.touches[i].clientY = 0+ob.clientY; }); } event_state.evnt = e; }







resizing



- . . .



resizing = function(e){ var mouse={},width,height,left,top,offset=$container.offset(); mouse.x = (e.clientX || e.pageX || e.originalEvent.touches[0].clientX) + $(window).scrollLeft(); mouse.y = (e.clientY || e.pageY || e.originalEvent.touches[0].clientY) + $(window).scrollTop(); width = mouse.x - event_state.container_left; height = mouse.y - event_state.container_top; left = event_state.container_left; top = event_state.container_top; if(constrain || e.shiftKey){ height = width / orig_src.width * orig_src.height; } if(width > min_width && height > min_height && width < max_width && height < max_height){ resizeImage(width, height); // Without this Firefox will not re-calculate the the image dimensions until drag end $container.offset({'left': left, 'top': top}); } }







Shift .



.



: , , resizeImage



.





Canvas , drawImage



. , . toDataURL



Base64-encoded .



.



resizeImage = function(width, height){ resize_canvas.width = width; resize_canvas.height = height; resize_canvas.getContext('2d').drawImage(orig_src, 0, 0, width, height); $(image_target).attr('src', resize_canvas.toDataURL("image/png")); };







? : , CORS . , 'tainted canvas'.







. . , . , .



, , .







, . resizing



:



resizing = function(e){ var mouse={},width,height,left,top,offset=$container.offset(); mouse.x = (e.clientX || e.pageX || e.originalEvent.touches[0].clientX) + $(window).scrollLeft(); mouse.y = (e.clientY || e.pageY || e.originalEvent.touches[0].clientY) + $(window).scrollTop(); // Position image differently depending on the corner dragged and constraints if( $(event_state.evnt.target).hasClass('resize-handle-se') ){ width = mouse.x - event_state.container_left; height = mouse.y - event_state.container_top; left = event_state.container_left; top = event_state.container_top; } else if($(event_state.evnt.target).hasClass('resize-handle-sw') ){ width = event_state.container_width - (mouse.x - event_state.container_left); height = mouse.y - event_state.container_top; left = mouse.x; top = event_state.container_top; } else if($(event_state.evnt.target).hasClass('resize-handle-nw') ){ width = event_state.container_width - (mouse.x - event_state.container_left); height = event_state.container_height - (mouse.y - event_state.container_top); left = mouse.x; top = mouse.y; if(constrain || e.shiftKey){ top = mouse.y - ((width / orig_src.width * orig_src.height) - height); } } else if($(event_state.evnt.target).hasClass('resize-handle-ne') ){ width = mouse.x - event_state.container_left; height = event_state.container_height - (mouse.y - event_state.container_top); left = event_state.container_left; top = mouse.y; if(constrain || e.shiftKey){ top = mouse.y - ((width / orig_src.width * orig_src.height) - height); } } // Optionally maintain aspect ratio if(constrain || e.shiftKey){ height = width / orig_src.width * orig_src.height; } if(width > min_width && height > min_height && width < max_width && height < max_height){ // To improve performance you might limit how often resizeImage() is called resizeImage(width, height); // Without this Firefox will not re-calculate the the image dimensions until drag end $container.offset({'left': left, 'top': top}); } }







, resize-handle



, .





, , , , , "". . .



init = function(){ //... $container.on('mousedown', 'img', startMoving); }







startMoving



endMoving



, startResize



endResize



.



startMoving = function(e){ e.preventDefault(); e.stopPropagation(); saveEventState(e); $(document).on('mousemove', moving); $(document).on('mouseup', endMoving); }; endMoving = function(e){ e.preventDefault(); $(document).off('mouseup', endMoving); $(document).off('mousemove', moving); };







moving



. , .



moving = function(e){ var mouse={}; e.preventDefault(); e.stopPropagation(); mouse.x = (e.clientX || e.pageX) + $(window).scrollLeft(); mouse.y = (e.clientY || e.pageY) + $(window).scrollTop(); $container.offset({ 'left': mouse.x - ( event_state.mouse_x - event_state.container_left ), 'top': mouse.y - ( event_state.mouse_y - event_state.container_top ) }); };









, , . , , , , . , , , , .



HTML :



<div class="overlay"> <div class="overlay-inner"> </div> </div> <button class="btn-crop js-crop">Crop</button>







, , .



.overlay { position: absolute; left: 50%; top: 50%; margin-left: -100px; margin-top: -100px; z-index: 999; width: 200px; height: 200px; border: solid 2px rgba(222,60,80,.9); box-sizing: content-box; pointer-events: none; } .overlay:after, .overlay:before { content: ''; position: absolute; display: block; width: 204px; height: 40px; border-left: dashed 2px rgba(222,60,80,.9); border-right: dashed 2px rgba(222,60,80,.9); } .overlay:before { top: 0; margin-left: -2px; margin-top: -40px; } .overlay:after { bottom: 0; margin-left: -2px; margin-bottom: -40px; } .overlay-inner:after, .overlay-inner:before { content: ''; position: absolute; display: block; width: 40px; height: 204px; border-top: dashed 2px rgba(222,60,80,.9); border-bottom: dashed 2px rgba(222,60,80,.9); } .overlay-inner:before { left: 0; margin-left: -40px; margin-top: -2px; } .overlay-inner:after { right: 0; margin-right: -40px; margin-top: -2px; } .btn-crop { position: absolute; vertical-align: bottom; right: 5px; bottom: 5px; padding: 6px 10px; z-index: 999; background-color: rgb(222,60,80); border: none; border-radius: 5px; color: #FFF; }







JavaScript :



init = function(){ //... $('.js-crop').on('click', crop); }; crop = function(){ var crop_canvas, left = $('.overlay').offset().left - $container.offset().left, top = $('.overlay').offset().top - $container.offset().top, width = $('.overlay').width(), height = $('.overlay').height(); crop_canvas = document.createElement('canvas'); crop_canvas.width = width; crop_canvas.height = height; crop_canvas.getContext('2d').drawImage(image_target, left, top, width, height, 0, 0, width, height); window.open(crop_canvas.toDataURL("image/png")); }







crop



resizeImage



. , .



drawImage



canvas. - . - , . - , canvas, .





. .



mousedown



mouseup



- touchstart



touchend



, mousemove



touchmove



. , touchup



touchdown



( ).



touchstart



touchend



, mousedown



, mouseup



touchmove



, mousemove



.



// In init()... $container.on('mousedown touchstart', '.resize-handle', startResize); $container.on('mousedown touchstart', 'img', startMoving); //In startResize() ... $(document).on('mousemove touchmove', moving); $(document).on('mouseup touchend', endMoving); //In endResize()... $(document).off('mouseup touchend', endMoving); $(document).off('mousemove touchmove', moving); //In startMoving()... $(document).on('mousemove touchmove', moving); $(document).on('mouseup touchend', endMoving); //In endMoving()... $(document).off('mouseup touchend', endMoving); $(document).off('mousemove touchmove', moving);







, "" . Hammer, . , , .



, , , saveEventState



. .



" " . , . moving



:



moving = function(e){ var mouse={}, touches; e.preventDefault(); e.stopPropagation(); touches = e.originalEvent.touches; mouse.x = (e.clientX || e.pageX || touches[0].clientX) + $(window).scrollLeft(); mouse.y = (e.clientY || e.pageY || touches[0].clientY) + $(window).scrollTop(); $container.offset({ 'left': mouse.x - ( event_state.mouse_x - event_state.container_left ), 'top': mouse.y - ( event_state.mouse_y - event_state.container_top ) }); // Watch for pinch zoom gesture while moving if(event_state.touches && event_state.touches.length > 1 && touches.length > 1){ var width = event_state.container_width, height = event_state.container_height; var a = event_state.touches[0].clientX - event_state.touches[1].clientX; a = a * a; var b = event_state.touches[0].clientY - event_state.touches[1].clientY; b = b * b; var dist1 = Math.sqrt( a + b ); a = e.originalEvent.touches[0].clientX - touches[1].clientX; a = a * a; b = e.originalEvent.touches[0].clientY - touches[1].clientY; b = b * b; var dist2 = Math.sqrt( a + b ); var ratio = dist2 /dist1; width = width * ratio; height = height * ratio; // To improve performance you might limit how often resizeImage() is called resizeImage(width, height); } };







.







. .



Chrome "", Firefox .



, .




  HTML5,     ,      ,   . 
      



- . , . , .



canvas




, , . , , .



. . , , . , .



!





:

<img class="resize-image" src="image.jpg" alt="Image" />







! HTML .



CSS

CSS- . resize-container



.



.resize-container { position: relative; display: inline-block; cursor: move; margin: 0 auto; } .resize-container img { display: block } .resize-container:hover img, .resize-container:active img { outline: 2px dashed rgba(222,60,80,.9); }







'resize handles'. , , .



.resize-handle-ne, .resize-handle-ne, .resize-handle-se, .resize-handle-nw, .resize-handle-sw { position: absolute; display: block; width: 10px; height: 10px; background: rgba(222,60,80,.9); z-index: 999; } .resize-handle-nw { top: -5px; left: -5px; cursor: nw-resize; } .resize-handle-sw { bottom: -5px; left: -5px; cursor: sw-resize; } .resize-handle-ne { top: -5px; right: -5px; cursor: ne-resize; } .resize-handle-se { bottom: -5px; right: -5px; cursor: se-resize; }







JavaScript

Canvas.



var resizeableImage = function(image_target) { var $container, orig_src = new Image(), image_target = $(image_target).get(0), event_state = {}, constrain = false, min_width = 60, min_height = 60, max_width = 800, max_height = 900, resize_canvas = document.createElement('canvas'); }); resizeableImage($('.resize-image'));







, . , , . jQuery , .



var resizeableImage = function(image_target) { // ... init = function(){ // Create a new image with a copy of the original src // When resizing, we will always use this original copy as the base orig_src.src=image_target.src; // Add resize handles $(image_target).wrap('<div class="resize-container"></div>') .before('<span class="resize-handle resize-handle-nw"></span>') .before('<span class="resize-handle resize-handle-ne"></span>') .after('<span class="resize-handle resize-handle-se"></span>') .after('<span class="resize-handle resize-handle-sw"></span>'); // Get a variable for the container $container = $(image_target).parent('.resize-container'); // Add events $container.on('mousedown', '.resize-handle', startResize); }; //... init(); }







startResize



endResize



, , .



startResize = function(e){ e.preventDefault(); e.stopPropagation(); saveEventState(e); $(document).on('mousemove', resizing); $(document).on('mouseup', endResize); }; endResize = function(e){ e.preventDefault(); $(document).off('mouseup touchend', endResize); $(document).off('mousemove touchmove', resizing); };







. event_state



.



saveEventState = function(e){ // Save the initial event details and container state event_state.container_width = $container.width(); event_state.container_height = $container.height(); event_state.container_left = $container.offset().left; event_state.container_top = $container.offset().top; event_state.mouse_x = (e.clientX || e.pageX || e.originalEvent.touches[0].clientX) + $(window).scrollLeft(); event_state.mouse_y = (e.clientY || e.pageY || e.originalEvent.touches[0].clientY) + $(window).scrollTop(); // This is a fix for mobile safari // For some reason it does not allow a direct copy of the touches property if(typeof e.originalEvent.touches !== 'undefined'){ event_state.touches = []; $.each(e.originalEvent.touches, function(i, ob){ event_state.touches[i] = {}; event_state.touches[i].clientX = 0+ob.clientX; event_state.touches[i].clientY = 0+ob.clientY; }); } event_state.evnt = e; }







resizing



- . . .



resizing = function(e){ var mouse={},width,height,left,top,offset=$container.offset(); mouse.x = (e.clientX || e.pageX || e.originalEvent.touches[0].clientX) + $(window).scrollLeft(); mouse.y = (e.clientY || e.pageY || e.originalEvent.touches[0].clientY) + $(window).scrollTop(); width = mouse.x - event_state.container_left; height = mouse.y - event_state.container_top; left = event_state.container_left; top = event_state.container_top; if(constrain || e.shiftKey){ height = width / orig_src.width * orig_src.height; } if(width > min_width && height > min_height && width < max_width && height < max_height){ resizeImage(width, height); // Without this Firefox will not re-calculate the the image dimensions until drag end $container.offset({'left': left, 'top': top}); } }







Shift .



.



: , , resizeImage



.





Canvas , drawImage



. , . toDataURL



Base64-encoded .



.



resizeImage = function(width, height){ resize_canvas.width = width; resize_canvas.height = height; resize_canvas.getContext('2d').drawImage(orig_src, 0, 0, width, height); $(image_target).attr('src', resize_canvas.toDataURL("image/png")); };







? : , CORS . , 'tainted canvas'.







. . , . , .



, , .







, . resizing



:



resizing = function(e){ var mouse={},width,height,left,top,offset=$container.offset(); mouse.x = (e.clientX || e.pageX || e.originalEvent.touches[0].clientX) + $(window).scrollLeft(); mouse.y = (e.clientY || e.pageY || e.originalEvent.touches[0].clientY) + $(window).scrollTop(); // Position image differently depending on the corner dragged and constraints if( $(event_state.evnt.target).hasClass('resize-handle-se') ){ width = mouse.x - event_state.container_left; height = mouse.y - event_state.container_top; left = event_state.container_left; top = event_state.container_top; } else if($(event_state.evnt.target).hasClass('resize-handle-sw') ){ width = event_state.container_width - (mouse.x - event_state.container_left); height = mouse.y - event_state.container_top; left = mouse.x; top = event_state.container_top; } else if($(event_state.evnt.target).hasClass('resize-handle-nw') ){ width = event_state.container_width - (mouse.x - event_state.container_left); height = event_state.container_height - (mouse.y - event_state.container_top); left = mouse.x; top = mouse.y; if(constrain || e.shiftKey){ top = mouse.y - ((width / orig_src.width * orig_src.height) - height); } } else if($(event_state.evnt.target).hasClass('resize-handle-ne') ){ width = mouse.x - event_state.container_left; height = event_state.container_height - (mouse.y - event_state.container_top); left = event_state.container_left; top = mouse.y; if(constrain || e.shiftKey){ top = mouse.y - ((width / orig_src.width * orig_src.height) - height); } } // Optionally maintain aspect ratio if(constrain || e.shiftKey){ height = width / orig_src.width * orig_src.height; } if(width > min_width && height > min_height && width < max_width && height < max_height){ // To improve performance you might limit how often resizeImage() is called resizeImage(width, height); // Without this Firefox will not re-calculate the the image dimensions until drag end $container.offset({'left': left, 'top': top}); } }







, resize-handle



, .





, , , , , "". . .



init = function(){ //... $container.on('mousedown', 'img', startMoving); }







startMoving



endMoving



, startResize



endResize



.



startMoving = function(e){ e.preventDefault(); e.stopPropagation(); saveEventState(e); $(document).on('mousemove', moving); $(document).on('mouseup', endMoving); }; endMoving = function(e){ e.preventDefault(); $(document).off('mouseup', endMoving); $(document).off('mousemove', moving); };







moving



. , .



moving = function(e){ var mouse={}; e.preventDefault(); e.stopPropagation(); mouse.x = (e.clientX || e.pageX) + $(window).scrollLeft(); mouse.y = (e.clientY || e.pageY) + $(window).scrollTop(); $container.offset({ 'left': mouse.x - ( event_state.mouse_x - event_state.container_left ), 'top': mouse.y - ( event_state.mouse_y - event_state.container_top ) }); };









, , . , , , , . , , , , .



HTML :



<div class="overlay"> <div class="overlay-inner"> </div> </div> <button class="btn-crop js-crop">Crop</button>







, , .



.overlay { position: absolute; left: 50%; top: 50%; margin-left: -100px; margin-top: -100px; z-index: 999; width: 200px; height: 200px; border: solid 2px rgba(222,60,80,.9); box-sizing: content-box; pointer-events: none; } .overlay:after, .overlay:before { content: ''; position: absolute; display: block; width: 204px; height: 40px; border-left: dashed 2px rgba(222,60,80,.9); border-right: dashed 2px rgba(222,60,80,.9); } .overlay:before { top: 0; margin-left: -2px; margin-top: -40px; } .overlay:after { bottom: 0; margin-left: -2px; margin-bottom: -40px; } .overlay-inner:after, .overlay-inner:before { content: ''; position: absolute; display: block; width: 40px; height: 204px; border-top: dashed 2px rgba(222,60,80,.9); border-bottom: dashed 2px rgba(222,60,80,.9); } .overlay-inner:before { left: 0; margin-left: -40px; margin-top: -2px; } .overlay-inner:after { right: 0; margin-right: -40px; margin-top: -2px; } .btn-crop { position: absolute; vertical-align: bottom; right: 5px; bottom: 5px; padding: 6px 10px; z-index: 999; background-color: rgb(222,60,80); border: none; border-radius: 5px; color: #FFF; }







JavaScript :



init = function(){ //... $('.js-crop').on('click', crop); }; crop = function(){ var crop_canvas, left = $('.overlay').offset().left - $container.offset().left, top = $('.overlay').offset().top - $container.offset().top, width = $('.overlay').width(), height = $('.overlay').height(); crop_canvas = document.createElement('canvas'); crop_canvas.width = width; crop_canvas.height = height; crop_canvas.getContext('2d').drawImage(image_target, left, top, width, height, 0, 0, width, height); window.open(crop_canvas.toDataURL("image/png")); }







crop



resizeImage



. , .



drawImage



canvas. - . - , . - , canvas, .





. .



mousedown



mouseup



- touchstart



touchend



, mousemove



touchmove



. , touchup



touchdown



( ).



touchstart



touchend



, mousedown



, mouseup



touchmove



, mousemove



.



// In init()... $container.on('mousedown touchstart', '.resize-handle', startResize); $container.on('mousedown touchstart', 'img', startMoving); //In startResize() ... $(document).on('mousemove touchmove', moving); $(document).on('mouseup touchend', endMoving); //In endResize()... $(document).off('mouseup touchend', endMoving); $(document).off('mousemove touchmove', moving); //In startMoving()... $(document).on('mousemove touchmove', moving); $(document).on('mouseup touchend', endMoving); //In endMoving()... $(document).off('mouseup touchend', endMoving); $(document).off('mousemove touchmove', moving);







, "" . Hammer, . , , .



, , , saveEventState



. .



" " . , . moving



:



moving = function(e){ var mouse={}, touches; e.preventDefault(); e.stopPropagation(); touches = e.originalEvent.touches; mouse.x = (e.clientX || e.pageX || touches[0].clientX) + $(window).scrollLeft(); mouse.y = (e.clientY || e.pageY || touches[0].clientY) + $(window).scrollTop(); $container.offset({ 'left': mouse.x - ( event_state.mouse_x - event_state.container_left ), 'top': mouse.y - ( event_state.mouse_y - event_state.container_top ) }); // Watch for pinch zoom gesture while moving if(event_state.touches && event_state.touches.length > 1 && touches.length > 1){ var width = event_state.container_width, height = event_state.container_height; var a = event_state.touches[0].clientX - event_state.touches[1].clientX; a = a * a; var b = event_state.touches[0].clientY - event_state.touches[1].clientY; b = b * b; var dist1 = Math.sqrt( a + b ); a = e.originalEvent.touches[0].clientX - touches[1].clientX; a = a * a; b = e.originalEvent.touches[0].clientY - touches[1].clientY; b = b * b; var dist2 = Math.sqrt( a + b ); var ratio = dist2 /dist1; width = width * ratio; height = height * ratio; // To improve performance you might limit how often resizeImage() is called resizeImage(width, height); } };







.







. .



Chrome "", Firefox .



, .




HTML5, , , .



- . , . , .



canvas




, , . , , .



. . , , . , .



!





:

<img class="resize-image" src="image.jpg" alt="Image" />







! HTML .



CSS

CSS- . resize-container



.



.resize-container { position: relative; display: inline-block; cursor: move; margin: 0 auto; } .resize-container img { display: block } .resize-container:hover img, .resize-container:active img { outline: 2px dashed rgba(222,60,80,.9); }







'resize handles'. , , .



.resize-handle-ne, .resize-handle-ne, .resize-handle-se, .resize-handle-nw, .resize-handle-sw { position: absolute; display: block; width: 10px; height: 10px; background: rgba(222,60,80,.9); z-index: 999; } .resize-handle-nw { top: -5px; left: -5px; cursor: nw-resize; } .resize-handle-sw { bottom: -5px; left: -5px; cursor: sw-resize; } .resize-handle-ne { top: -5px; right: -5px; cursor: ne-resize; } .resize-handle-se { bottom: -5px; right: -5px; cursor: se-resize; }







JavaScript

Canvas.



var resizeableImage = function(image_target) { var $container, orig_src = new Image(), image_target = $(image_target).get(0), event_state = {}, constrain = false, min_width = 60, min_height = 60, max_width = 800, max_height = 900, resize_canvas = document.createElement('canvas'); }); resizeableImage($('.resize-image'));







, . , , . jQuery , .



var resizeableImage = function(image_target) { // ... init = function(){ // Create a new image with a copy of the original src // When resizing, we will always use this original copy as the base orig_src.src=image_target.src; // Add resize handles $(image_target).wrap('<div class="resize-container"></div>') .before('<span class="resize-handle resize-handle-nw"></span>') .before('<span class="resize-handle resize-handle-ne"></span>') .after('<span class="resize-handle resize-handle-se"></span>') .after('<span class="resize-handle resize-handle-sw"></span>'); // Get a variable for the container $container = $(image_target).parent('.resize-container'); // Add events $container.on('mousedown', '.resize-handle', startResize); }; //... init(); }







startResize



endResize



, , .



startResize = function(e){ e.preventDefault(); e.stopPropagation(); saveEventState(e); $(document).on('mousemove', resizing); $(document).on('mouseup', endResize); }; endResize = function(e){ e.preventDefault(); $(document).off('mouseup touchend', endResize); $(document).off('mousemove touchmove', resizing); };







. event_state



.



saveEventState = function(e){ // Save the initial event details and container state event_state.container_width = $container.width(); event_state.container_height = $container.height(); event_state.container_left = $container.offset().left; event_state.container_top = $container.offset().top; event_state.mouse_x = (e.clientX || e.pageX || e.originalEvent.touches[0].clientX) + $(window).scrollLeft(); event_state.mouse_y = (e.clientY || e.pageY || e.originalEvent.touches[0].clientY) + $(window).scrollTop(); // This is a fix for mobile safari // For some reason it does not allow a direct copy of the touches property if(typeof e.originalEvent.touches !== 'undefined'){ event_state.touches = []; $.each(e.originalEvent.touches, function(i, ob){ event_state.touches[i] = {}; event_state.touches[i].clientX = 0+ob.clientX; event_state.touches[i].clientY = 0+ob.clientY; }); } event_state.evnt = e; }







resizing



- . . .



resizing = function(e){ var mouse={},width,height,left,top,offset=$container.offset(); mouse.x = (e.clientX || e.pageX || e.originalEvent.touches[0].clientX) + $(window).scrollLeft(); mouse.y = (e.clientY || e.pageY || e.originalEvent.touches[0].clientY) + $(window).scrollTop(); width = mouse.x - event_state.container_left; height = mouse.y - event_state.container_top; left = event_state.container_left; top = event_state.container_top; if(constrain || e.shiftKey){ height = width / orig_src.width * orig_src.height; } if(width > min_width && height > min_height && width < max_width && height < max_height){ resizeImage(width, height); // Without this Firefox will not re-calculate the the image dimensions until drag end $container.offset({'left': left, 'top': top}); } }







Shift .



.



: , , resizeImage



.





Canvas , drawImage



. , . toDataURL



Base64-encoded .



.



resizeImage = function(width, height){ resize_canvas.width = width; resize_canvas.height = height; resize_canvas.getContext('2d').drawImage(orig_src, 0, 0, width, height); $(image_target).attr('src', resize_canvas.toDataURL("image/png")); };







? : , CORS . , 'tainted canvas'.







. . , . , .



, , .







, . resizing



:



resizing = function(e){ var mouse={},width,height,left,top,offset=$container.offset(); mouse.x = (e.clientX || e.pageX || e.originalEvent.touches[0].clientX) + $(window).scrollLeft(); mouse.y = (e.clientY || e.pageY || e.originalEvent.touches[0].clientY) + $(window).scrollTop(); // Position image differently depending on the corner dragged and constraints if( $(event_state.evnt.target).hasClass('resize-handle-se') ){ width = mouse.x - event_state.container_left; height = mouse.y - event_state.container_top; left = event_state.container_left; top = event_state.container_top; } else if($(event_state.evnt.target).hasClass('resize-handle-sw') ){ width = event_state.container_width - (mouse.x - event_state.container_left); height = mouse.y - event_state.container_top; left = mouse.x; top = event_state.container_top; } else if($(event_state.evnt.target).hasClass('resize-handle-nw') ){ width = event_state.container_width - (mouse.x - event_state.container_left); height = event_state.container_height - (mouse.y - event_state.container_top); left = mouse.x; top = mouse.y; if(constrain || e.shiftKey){ top = mouse.y - ((width / orig_src.width * orig_src.height) - height); } } else if($(event_state.evnt.target).hasClass('resize-handle-ne') ){ width = mouse.x - event_state.container_left; height = event_state.container_height - (mouse.y - event_state.container_top); left = event_state.container_left; top = mouse.y; if(constrain || e.shiftKey){ top = mouse.y - ((width / orig_src.width * orig_src.height) - height); } } // Optionally maintain aspect ratio if(constrain || e.shiftKey){ height = width / orig_src.width * orig_src.height; } if(width > min_width && height > min_height && width < max_width && height < max_height){ // To improve performance you might limit how often resizeImage() is called resizeImage(width, height); // Without this Firefox will not re-calculate the the image dimensions until drag end $container.offset({'left': left, 'top': top}); } }







, resize-handle



, .





, , , , , "". . .



init = function(){ //... $container.on('mousedown', 'img', startMoving); }







startMoving



endMoving



, startResize



endResize



.



startMoving = function(e){ e.preventDefault(); e.stopPropagation(); saveEventState(e); $(document).on('mousemove', moving); $(document).on('mouseup', endMoving); }; endMoving = function(e){ e.preventDefault(); $(document).off('mouseup', endMoving); $(document).off('mousemove', moving); };







moving



. , .



moving = function(e){ var mouse={}; e.preventDefault(); e.stopPropagation(); mouse.x = (e.clientX || e.pageX) + $(window).scrollLeft(); mouse.y = (e.clientY || e.pageY) + $(window).scrollTop(); $container.offset({ 'left': mouse.x - ( event_state.mouse_x - event_state.container_left ), 'top': mouse.y - ( event_state.mouse_y - event_state.container_top ) }); };









, , . , , , , . , , , , .



HTML :



<div class="overlay"> <div class="overlay-inner"> </div> </div> <button class="btn-crop js-crop">Crop</button>







, , .



.overlay { position: absolute; left: 50%; top: 50%; margin-left: -100px; margin-top: -100px; z-index: 999; width: 200px; height: 200px; border: solid 2px rgba(222,60,80,.9); box-sizing: content-box; pointer-events: none; } .overlay:after, .overlay:before { content: ''; position: absolute; display: block; width: 204px; height: 40px; border-left: dashed 2px rgba(222,60,80,.9); border-right: dashed 2px rgba(222,60,80,.9); } .overlay:before { top: 0; margin-left: -2px; margin-top: -40px; } .overlay:after { bottom: 0; margin-left: -2px; margin-bottom: -40px; } .overlay-inner:after, .overlay-inner:before { content: ''; position: absolute; display: block; width: 40px; height: 204px; border-top: dashed 2px rgba(222,60,80,.9); border-bottom: dashed 2px rgba(222,60,80,.9); } .overlay-inner:before { left: 0; margin-left: -40px; margin-top: -2px; } .overlay-inner:after { right: 0; margin-right: -40px; margin-top: -2px; } .btn-crop { position: absolute; vertical-align: bottom; right: 5px; bottom: 5px; padding: 6px 10px; z-index: 999; background-color: rgb(222,60,80); border: none; border-radius: 5px; color: #FFF; }







JavaScript :



init = function(){ //... $('.js-crop').on('click', crop); }; crop = function(){ var crop_canvas, left = $('.overlay').offset().left - $container.offset().left, top = $('.overlay').offset().top - $container.offset().top, width = $('.overlay').width(), height = $('.overlay').height(); crop_canvas = document.createElement('canvas'); crop_canvas.width = width; crop_canvas.height = height; crop_canvas.getContext('2d').drawImage(image_target, left, top, width, height, 0, 0, width, height); window.open(crop_canvas.toDataURL("image/png")); }







crop



resizeImage



. , .



drawImage



canvas. - . - , . - , canvas, .





. .



mousedown



mouseup



- touchstart



touchend



, mousemove



touchmove



. , touchup



touchdown



( ).



touchstart



touchend



, mousedown



, mouseup



touchmove



, mousemove



.



// In init()... $container.on('mousedown touchstart', '.resize-handle', startResize); $container.on('mousedown touchstart', 'img', startMoving); //In startResize() ... $(document).on('mousemove touchmove', moving); $(document).on('mouseup touchend', endMoving); //In endResize()... $(document).off('mouseup touchend', endMoving); $(document).off('mousemove touchmove', moving); //In startMoving()... $(document).on('mousemove touchmove', moving); $(document).on('mouseup touchend', endMoving); //In endMoving()... $(document).off('mouseup touchend', endMoving); $(document).off('mousemove touchmove', moving);







, "" . Hammer, . , , .



, , , saveEventState



. .



" " . , . moving



:



moving = function(e){ var mouse={}, touches; e.preventDefault(); e.stopPropagation(); touches = e.originalEvent.touches; mouse.x = (e.clientX || e.pageX || touches[0].clientX) + $(window).scrollLeft(); mouse.y = (e.clientY || e.pageY || touches[0].clientY) + $(window).scrollTop(); $container.offset({ 'left': mouse.x - ( event_state.mouse_x - event_state.container_left ), 'top': mouse.y - ( event_state.mouse_y - event_state.container_top ) }); // Watch for pinch zoom gesture while moving if(event_state.touches && event_state.touches.length > 1 && touches.length > 1){ var width = event_state.container_width, height = event_state.container_height; var a = event_state.touches[0].clientX - event_state.touches[1].clientX; a = a * a; var b = event_state.touches[0].clientY - event_state.touches[1].clientY; b = b * b; var dist1 = Math.sqrt( a + b ); a = e.originalEvent.touches[0].clientX - touches[1].clientX; a = a * a; b = e.originalEvent.touches[0].clientY - touches[1].clientY; b = b * b; var dist2 = Math.sqrt( a + b ); var ratio = dist2 /dist1; width = width * ratio; height = height * ratio; // To improve performance you might limit how often resizeImage() is called resizeImage(width, height); } };







.







. .



Chrome "", Firefox .



, .




HTML5, , , .



- . , . , .



canvas




, , . , , .



. . , , . , .



!





:

<img class="resize-image" src="image.jpg" alt="Image" />







! HTML .



CSS

CSS- . resize-container



.



.resize-container { position: relative; display: inline-block; cursor: move; margin: 0 auto; } .resize-container img { display: block } .resize-container:hover img, .resize-container:active img { outline: 2px dashed rgba(222,60,80,.9); }







'resize handles'. , , .



.resize-handle-ne, .resize-handle-ne, .resize-handle-se, .resize-handle-nw, .resize-handle-sw { position: absolute; display: block; width: 10px; height: 10px; background: rgba(222,60,80,.9); z-index: 999; } .resize-handle-nw { top: -5px; left: -5px; cursor: nw-resize; } .resize-handle-sw { bottom: -5px; left: -5px; cursor: sw-resize; } .resize-handle-ne { top: -5px; right: -5px; cursor: ne-resize; } .resize-handle-se { bottom: -5px; right: -5px; cursor: se-resize; }







JavaScript

Canvas.



var resizeableImage = function(image_target) { var $container, orig_src = new Image(), image_target = $(image_target).get(0), event_state = {}, constrain = false, min_width = 60, min_height = 60, max_width = 800, max_height = 900, resize_canvas = document.createElement('canvas'); }); resizeableImage($('.resize-image'));







, . , , . jQuery , .



var resizeableImage = function(image_target) { // ... init = function(){ // Create a new image with a copy of the original src // When resizing, we will always use this original copy as the base orig_src.src=image_target.src; // Add resize handles $(image_target).wrap('<div class="resize-container"></div>') .before('<span class="resize-handle resize-handle-nw"></span>') .before('<span class="resize-handle resize-handle-ne"></span>') .after('<span class="resize-handle resize-handle-se"></span>') .after('<span class="resize-handle resize-handle-sw"></span>'); // Get a variable for the container $container = $(image_target).parent('.resize-container'); // Add events $container.on('mousedown', '.resize-handle', startResize); }; //... init(); }







startResize



endResize



, , .



startResize = function(e){ e.preventDefault(); e.stopPropagation(); saveEventState(e); $(document).on('mousemove', resizing); $(document).on('mouseup', endResize); }; endResize = function(e){ e.preventDefault(); $(document).off('mouseup touchend', endResize); $(document).off('mousemove touchmove', resizing); };







. event_state



.



saveEventState = function(e){ // Save the initial event details and container state event_state.container_width = $container.width(); event_state.container_height = $container.height(); event_state.container_left = $container.offset().left; event_state.container_top = $container.offset().top; event_state.mouse_x = (e.clientX || e.pageX || e.originalEvent.touches[0].clientX) + $(window).scrollLeft(); event_state.mouse_y = (e.clientY || e.pageY || e.originalEvent.touches[0].clientY) + $(window).scrollTop(); // This is a fix for mobile safari // For some reason it does not allow a direct copy of the touches property if(typeof e.originalEvent.touches !== 'undefined'){ event_state.touches = []; $.each(e.originalEvent.touches, function(i, ob){ event_state.touches[i] = {}; event_state.touches[i].clientX = 0+ob.clientX; event_state.touches[i].clientY = 0+ob.clientY; }); } event_state.evnt = e; }







resizing



- . . .



resizing = function(e){ var mouse={},width,height,left,top,offset=$container.offset(); mouse.x = (e.clientX || e.pageX || e.originalEvent.touches[0].clientX) + $(window).scrollLeft(); mouse.y = (e.clientY || e.pageY || e.originalEvent.touches[0].clientY) + $(window).scrollTop(); width = mouse.x - event_state.container_left; height = mouse.y - event_state.container_top; left = event_state.container_left; top = event_state.container_top; if(constrain || e.shiftKey){ height = width / orig_src.width * orig_src.height; } if(width > min_width && height > min_height && width < max_width && height < max_height){ resizeImage(width, height); // Without this Firefox will not re-calculate the the image dimensions until drag end $container.offset({'left': left, 'top': top}); } }







Shift .



.



: , , resizeImage



.





Canvas , drawImage



. , . toDataURL



Base64-encoded .



.



resizeImage = function(width, height){ resize_canvas.width = width; resize_canvas.height = height; resize_canvas.getContext('2d').drawImage(orig_src, 0, 0, width, height); $(image_target).attr('src', resize_canvas.toDataURL("image/png")); };







? : , CORS . , 'tainted canvas'.







. . , . , .



, , .







, . resizing



:



resizing = function(e){ var mouse={},width,height,left,top,offset=$container.offset(); mouse.x = (e.clientX || e.pageX || e.originalEvent.touches[0].clientX) + $(window).scrollLeft(); mouse.y = (e.clientY || e.pageY || e.originalEvent.touches[0].clientY) + $(window).scrollTop(); // Position image differently depending on the corner dragged and constraints if( $(event_state.evnt.target).hasClass('resize-handle-se') ){ width = mouse.x - event_state.container_left; height = mouse.y - event_state.container_top; left = event_state.container_left; top = event_state.container_top; } else if($(event_state.evnt.target).hasClass('resize-handle-sw') ){ width = event_state.container_width - (mouse.x - event_state.container_left); height = mouse.y - event_state.container_top; left = mouse.x; top = event_state.container_top; } else if($(event_state.evnt.target).hasClass('resize-handle-nw') ){ width = event_state.container_width - (mouse.x - event_state.container_left); height = event_state.container_height - (mouse.y - event_state.container_top); left = mouse.x; top = mouse.y; if(constrain || e.shiftKey){ top = mouse.y - ((width / orig_src.width * orig_src.height) - height); } } else if($(event_state.evnt.target).hasClass('resize-handle-ne') ){ width = mouse.x - event_state.container_left; height = event_state.container_height - (mouse.y - event_state.container_top); left = event_state.container_left; top = mouse.y; if(constrain || e.shiftKey){ top = mouse.y - ((width / orig_src.width * orig_src.height) - height); } } // Optionally maintain aspect ratio if(constrain || e.shiftKey){ height = width / orig_src.width * orig_src.height; } if(width > min_width && height > min_height && width < max_width && height < max_height){ // To improve performance you might limit how often resizeImage() is called resizeImage(width, height); // Without this Firefox will not re-calculate the the image dimensions until drag end $container.offset({'left': left, 'top': top}); } }







, resize-handle



, .





, , , , , "". . .



init = function(){ //... $container.on('mousedown', 'img', startMoving); }







startMoving



endMoving



, startResize



endResize



.



startMoving = function(e){ e.preventDefault(); e.stopPropagation(); saveEventState(e); $(document).on('mousemove', moving); $(document).on('mouseup', endMoving); }; endMoving = function(e){ e.preventDefault(); $(document).off('mouseup', endMoving); $(document).off('mousemove', moving); };







moving



. , .



moving = function(e){ var mouse={}; e.preventDefault(); e.stopPropagation(); mouse.x = (e.clientX || e.pageX) + $(window).scrollLeft(); mouse.y = (e.clientY || e.pageY) + $(window).scrollTop(); $container.offset({ 'left': mouse.x - ( event_state.mouse_x - event_state.container_left ), 'top': mouse.y - ( event_state.mouse_y - event_state.container_top ) }); };









, , . , , , , . , , , , .



HTML :



<div class="overlay"> <div class="overlay-inner"> </div> </div> <button class="btn-crop js-crop">Crop</button>







, , .



.overlay { position: absolute; left: 50%; top: 50%; margin-left: -100px; margin-top: -100px; z-index: 999; width: 200px; height: 200px; border: solid 2px rgba(222,60,80,.9); box-sizing: content-box; pointer-events: none; } .overlay:after, .overlay:before { content: ''; position: absolute; display: block; width: 204px; height: 40px; border-left: dashed 2px rgba(222,60,80,.9); border-right: dashed 2px rgba(222,60,80,.9); } .overlay:before { top: 0; margin-left: -2px; margin-top: -40px; } .overlay:after { bottom: 0; margin-left: -2px; margin-bottom: -40px; } .overlay-inner:after, .overlay-inner:before { content: ''; position: absolute; display: block; width: 40px; height: 204px; border-top: dashed 2px rgba(222,60,80,.9); border-bottom: dashed 2px rgba(222,60,80,.9); } .overlay-inner:before { left: 0; margin-left: -40px; margin-top: -2px; } .overlay-inner:after { right: 0; margin-right: -40px; margin-top: -2px; } .btn-crop { position: absolute; vertical-align: bottom; right: 5px; bottom: 5px; padding: 6px 10px; z-index: 999; background-color: rgb(222,60,80); border: none; border-radius: 5px; color: #FFF; }







JavaScript :



init = function(){ //... $('.js-crop').on('click', crop); }; crop = function(){ var crop_canvas, left = $('.overlay').offset().left - $container.offset().left, top = $('.overlay').offset().top - $container.offset().top, width = $('.overlay').width(), height = $('.overlay').height(); crop_canvas = document.createElement('canvas'); crop_canvas.width = width; crop_canvas.height = height; crop_canvas.getContext('2d').drawImage(image_target, left, top, width, height, 0, 0, width, height); window.open(crop_canvas.toDataURL("image/png")); }







crop



resizeImage



. , .



drawImage



canvas. - . - , . - , canvas, .





. .



mousedown



mouseup



- touchstart



touchend



, mousemove



touchmove



. , touchup



touchdown



( ).



touchstart



touchend



, mousedown



, mouseup



touchmove



, mousemove



.



// In init()... $container.on('mousedown touchstart', '.resize-handle', startResize); $container.on('mousedown touchstart', 'img', startMoving); //In startResize() ... $(document).on('mousemove touchmove', moving); $(document).on('mouseup touchend', endMoving); //In endResize()... $(document).off('mouseup touchend', endMoving); $(document).off('mousemove touchmove', moving); //In startMoving()... $(document).on('mousemove touchmove', moving); $(document).on('mouseup touchend', endMoving); //In endMoving()... $(document).off('mouseup touchend', endMoving); $(document).off('mousemove touchmove', moving);







, "" . Hammer, . , , .



, , , saveEventState



. .



" " . , . moving



:



moving = function(e){ var mouse={}, touches; e.preventDefault(); e.stopPropagation(); touches = e.originalEvent.touches; mouse.x = (e.clientX || e.pageX || touches[0].clientX) + $(window).scrollLeft(); mouse.y = (e.clientY || e.pageY || touches[0].clientY) + $(window).scrollTop(); $container.offset({ 'left': mouse.x - ( event_state.mouse_x - event_state.container_left ), 'top': mouse.y - ( event_state.mouse_y - event_state.container_top ) }); // Watch for pinch zoom gesture while moving if(event_state.touches && event_state.touches.length > 1 && touches.length > 1){ var width = event_state.container_width, height = event_state.container_height; var a = event_state.touches[0].clientX - event_state.touches[1].clientX; a = a * a; var b = event_state.touches[0].clientY - event_state.touches[1].clientY; b = b * b; var dist1 = Math.sqrt( a + b ); a = e.originalEvent.touches[0].clientX - touches[1].clientX; a = a * a; b = e.originalEvent.touches[0].clientY - touches[1].clientY; b = b * b; var dist2 = Math.sqrt( a + b ); var ratio = dist2 /dist1; width = width * ratio; height = height * ratio; // To improve performance you might limit how often resizeImage() is called resizeImage(width, height); } };







.







. .



Chrome "", Firefox .



, .




HTML5, , , .



- . , . , .



canvas




, , . , , .



. . , , . , .



!





:

<img class="resize-image" src="image.jpg" alt="Image" />







! HTML .



CSS

CSS- . resize-container



.



.resize-container { position: relative; display: inline-block; cursor: move; margin: 0 auto; } .resize-container img { display: block } .resize-container:hover img, .resize-container:active img { outline: 2px dashed rgba(222,60,80,.9); }







'resize handles'. , , .



.resize-handle-ne, .resize-handle-ne, .resize-handle-se, .resize-handle-nw, .resize-handle-sw { position: absolute; display: block; width: 10px; height: 10px; background: rgba(222,60,80,.9); z-index: 999; } .resize-handle-nw { top: -5px; left: -5px; cursor: nw-resize; } .resize-handle-sw { bottom: -5px; left: -5px; cursor: sw-resize; } .resize-handle-ne { top: -5px; right: -5px; cursor: ne-resize; } .resize-handle-se { bottom: -5px; right: -5px; cursor: se-resize; }







JavaScript

Canvas.



var resizeableImage = function(image_target) { var $container, orig_src = new Image(), image_target = $(image_target).get(0), event_state = {}, constrain = false, min_width = 60, min_height = 60, max_width = 800, max_height = 900, resize_canvas = document.createElement('canvas'); }); resizeableImage($('.resize-image'));







, . , , . jQuery , .



var resizeableImage = function(image_target) { // ... init = function(){ // Create a new image with a copy of the original src // When resizing, we will always use this original copy as the base orig_src.src=image_target.src; // Add resize handles $(image_target).wrap('<div class="resize-container"></div>') .before('<span class="resize-handle resize-handle-nw"></span>') .before('<span class="resize-handle resize-handle-ne"></span>') .after('<span class="resize-handle resize-handle-se"></span>') .after('<span class="resize-handle resize-handle-sw"></span>'); // Get a variable for the container $container = $(image_target).parent('.resize-container'); // Add events $container.on('mousedown', '.resize-handle', startResize); }; //... init(); }







startResize



endResize



, , .



startResize = function(e){ e.preventDefault(); e.stopPropagation(); saveEventState(e); $(document).on('mousemove', resizing); $(document).on('mouseup', endResize); }; endResize = function(e){ e.preventDefault(); $(document).off('mouseup touchend', endResize); $(document).off('mousemove touchmove', resizing); };







. event_state



.



saveEventState = function(e){ // Save the initial event details and container state event_state.container_width = $container.width(); event_state.container_height = $container.height(); event_state.container_left = $container.offset().left; event_state.container_top = $container.offset().top; event_state.mouse_x = (e.clientX || e.pageX || e.originalEvent.touches[0].clientX) + $(window).scrollLeft(); event_state.mouse_y = (e.clientY || e.pageY || e.originalEvent.touches[0].clientY) + $(window).scrollTop(); // This is a fix for mobile safari // For some reason it does not allow a direct copy of the touches property if(typeof e.originalEvent.touches !== 'undefined'){ event_state.touches = []; $.each(e.originalEvent.touches, function(i, ob){ event_state.touches[i] = {}; event_state.touches[i].clientX = 0+ob.clientX; event_state.touches[i].clientY = 0+ob.clientY; }); } event_state.evnt = e; }







resizing



- . . .



resizing = function(e){ var mouse={},width,height,left,top,offset=$container.offset(); mouse.x = (e.clientX || e.pageX || e.originalEvent.touches[0].clientX) + $(window).scrollLeft(); mouse.y = (e.clientY || e.pageY || e.originalEvent.touches[0].clientY) + $(window).scrollTop(); width = mouse.x - event_state.container_left; height = mouse.y - event_state.container_top; left = event_state.container_left; top = event_state.container_top; if(constrain || e.shiftKey){ height = width / orig_src.width * orig_src.height; } if(width > min_width && height > min_height && width < max_width && height < max_height){ resizeImage(width, height); // Without this Firefox will not re-calculate the the image dimensions until drag end $container.offset({'left': left, 'top': top}); } }







Shift .



.



: , , resizeImage



.





Canvas , drawImage



. , . toDataURL



Base64-encoded .



.



resizeImage = function(width, height){ resize_canvas.width = width; resize_canvas.height = height; resize_canvas.getContext('2d').drawImage(orig_src, 0, 0, width, height); $(image_target).attr('src', resize_canvas.toDataURL("image/png")); };







? : , CORS . , 'tainted canvas'.







. . , . , .



, , .







, . resizing



:



resizing = function(e){ var mouse={},width,height,left,top,offset=$container.offset(); mouse.x = (e.clientX || e.pageX || e.originalEvent.touches[0].clientX) + $(window).scrollLeft(); mouse.y = (e.clientY || e.pageY || e.originalEvent.touches[0].clientY) + $(window).scrollTop(); // Position image differently depending on the corner dragged and constraints if( $(event_state.evnt.target).hasClass('resize-handle-se') ){ width = mouse.x - event_state.container_left; height = mouse.y - event_state.container_top; left = event_state.container_left; top = event_state.container_top; } else if($(event_state.evnt.target).hasClass('resize-handle-sw') ){ width = event_state.container_width - (mouse.x - event_state.container_left); height = mouse.y - event_state.container_top; left = mouse.x; top = event_state.container_top; } else if($(event_state.evnt.target).hasClass('resize-handle-nw') ){ width = event_state.container_width - (mouse.x - event_state.container_left); height = event_state.container_height - (mouse.y - event_state.container_top); left = mouse.x; top = mouse.y; if(constrain || e.shiftKey){ top = mouse.y - ((width / orig_src.width * orig_src.height) - height); } } else if($(event_state.evnt.target).hasClass('resize-handle-ne') ){ width = mouse.x - event_state.container_left; height = event_state.container_height - (mouse.y - event_state.container_top); left = event_state.container_left; top = mouse.y; if(constrain || e.shiftKey){ top = mouse.y - ((width / orig_src.width * orig_src.height) - height); } } // Optionally maintain aspect ratio if(constrain || e.shiftKey){ height = width / orig_src.width * orig_src.height; } if(width > min_width && height > min_height && width < max_width && height < max_height){ // To improve performance you might limit how often resizeImage() is called resizeImage(width, height); // Without this Firefox will not re-calculate the the image dimensions until drag end $container.offset({'left': left, 'top': top}); } }







, resize-handle



, .





, , , , , "". . .



init = function(){ //... $container.on('mousedown', 'img', startMoving); }







startMoving



endMoving



, startResize



endResize



.



startMoving = function(e){ e.preventDefault(); e.stopPropagation(); saveEventState(e); $(document).on('mousemove', moving); $(document).on('mouseup', endMoving); }; endMoving = function(e){ e.preventDefault(); $(document).off('mouseup', endMoving); $(document).off('mousemove', moving); };







moving



. , .



moving = function(e){ var mouse={}; e.preventDefault(); e.stopPropagation(); mouse.x = (e.clientX || e.pageX) + $(window).scrollLeft(); mouse.y = (e.clientY || e.pageY) + $(window).scrollTop(); $container.offset({ 'left': mouse.x - ( event_state.mouse_x - event_state.container_left ), 'top': mouse.y - ( event_state.mouse_y - event_state.container_top ) }); };









, , . , , , , . , , , , .



HTML :



<div class="overlay"> <div class="overlay-inner"> </div> </div> <button class="btn-crop js-crop">Crop</button>







, , .



.overlay { position: absolute; left: 50%; top: 50%; margin-left: -100px; margin-top: -100px; z-index: 999; width: 200px; height: 200px; border: solid 2px rgba(222,60,80,.9); box-sizing: content-box; pointer-events: none; } .overlay:after, .overlay:before { content: ''; position: absolute; display: block; width: 204px; height: 40px; border-left: dashed 2px rgba(222,60,80,.9); border-right: dashed 2px rgba(222,60,80,.9); } .overlay:before { top: 0; margin-left: -2px; margin-top: -40px; } .overlay:after { bottom: 0; margin-left: -2px; margin-bottom: -40px; } .overlay-inner:after, .overlay-inner:before { content: ''; position: absolute; display: block; width: 40px; height: 204px; border-top: dashed 2px rgba(222,60,80,.9); border-bottom: dashed 2px rgba(222,60,80,.9); } .overlay-inner:before { left: 0; margin-left: -40px; margin-top: -2px; } .overlay-inner:after { right: 0; margin-right: -40px; margin-top: -2px; } .btn-crop { position: absolute; vertical-align: bottom; right: 5px; bottom: 5px; padding: 6px 10px; z-index: 999; background-color: rgb(222,60,80); border: none; border-radius: 5px; color: #FFF; }







JavaScript :



init = function(){ //... $('.js-crop').on('click', crop); }; crop = function(){ var crop_canvas, left = $('.overlay').offset().left - $container.offset().left, top = $('.overlay').offset().top - $container.offset().top, width = $('.overlay').width(), height = $('.overlay').height(); crop_canvas = document.createElement('canvas'); crop_canvas.width = width; crop_canvas.height = height; crop_canvas.getContext('2d').drawImage(image_target, left, top, width, height, 0, 0, width, height); window.open(crop_canvas.toDataURL("image/png")); }







crop



resizeImage



. , .



drawImage



canvas. - . - , . - , canvas, .





. .



mousedown



mouseup



- touchstart



touchend



, mousemove



touchmove



. , touchup



touchdown



( ).



touchstart



touchend



, mousedown



, mouseup



touchmove



, mousemove



.



// In init()... $container.on('mousedown touchstart', '.resize-handle', startResize); $container.on('mousedown touchstart', 'img', startMoving); //In startResize() ... $(document).on('mousemove touchmove', moving); $(document).on('mouseup touchend', endMoving); //In endResize()... $(document).off('mouseup touchend', endMoving); $(document).off('mousemove touchmove', moving); //In startMoving()... $(document).on('mousemove touchmove', moving); $(document).on('mouseup touchend', endMoving); //In endMoving()... $(document).off('mouseup touchend', endMoving); $(document).off('mousemove touchmove', moving);







, "" . Hammer, . , , .



, , , saveEventState



. .



" " . , . moving



:



moving = function(e){ var mouse={}, touches; e.preventDefault(); e.stopPropagation(); touches = e.originalEvent.touches; mouse.x = (e.clientX || e.pageX || touches[0].clientX) + $(window).scrollLeft(); mouse.y = (e.clientY || e.pageY || touches[0].clientY) + $(window).scrollTop(); $container.offset({ 'left': mouse.x - ( event_state.mouse_x - event_state.container_left ), 'top': mouse.y - ( event_state.mouse_y - event_state.container_top ) }); // Watch for pinch zoom gesture while moving if(event_state.touches && event_state.touches.length > 1 && touches.length > 1){ var width = event_state.container_width, height = event_state.container_height; var a = event_state.touches[0].clientX - event_state.touches[1].clientX; a = a * a; var b = event_state.touches[0].clientY - event_state.touches[1].clientY; b = b * b; var dist1 = Math.sqrt( a + b ); a = e.originalEvent.touches[0].clientX - touches[1].clientX; a = a * a; b = e.originalEvent.touches[0].clientY - touches[1].clientY; b = b * b; var dist2 = Math.sqrt( a + b ); var ratio = dist2 /dist1; width = width * ratio; height = height * ratio; // To improve performance you might limit how often resizeImage() is called resizeImage(width, height); } };







.







. .



Chrome "", Firefox .



, .




  HTML5,     ,      ,   . 
      



- . , . , .



canvas




, , . , , .



. . , , . , .



!





:

<img class="resize-image" src="image.jpg" alt="Image" />







! HTML .



CSS

CSS- . resize-container



.



.resize-container { position: relative; display: inline-block; cursor: move; margin: 0 auto; } .resize-container img { display: block } .resize-container:hover img, .resize-container:active img { outline: 2px dashed rgba(222,60,80,.9); }







'resize handles'. , , .



.resize-handle-ne, .resize-handle-ne, .resize-handle-se, .resize-handle-nw, .resize-handle-sw { position: absolute; display: block; width: 10px; height: 10px; background: rgba(222,60,80,.9); z-index: 999; } .resize-handle-nw { top: -5px; left: -5px; cursor: nw-resize; } .resize-handle-sw { bottom: -5px; left: -5px; cursor: sw-resize; } .resize-handle-ne { top: -5px; right: -5px; cursor: ne-resize; } .resize-handle-se { bottom: -5px; right: -5px; cursor: se-resize; }







JavaScript

Canvas.



var resizeableImage = function(image_target) { var $container, orig_src = new Image(), image_target = $(image_target).get(0), event_state = {}, constrain = false, min_width = 60, min_height = 60, max_width = 800, max_height = 900, resize_canvas = document.createElement('canvas'); }); resizeableImage($('.resize-image'));







, . , , . jQuery , .



var resizeableImage = function(image_target) { // ... init = function(){ // Create a new image with a copy of the original src // When resizing, we will always use this original copy as the base orig_src.src=image_target.src; // Add resize handles $(image_target).wrap('<div class="resize-container"></div>') .before('<span class="resize-handle resize-handle-nw"></span>') .before('<span class="resize-handle resize-handle-ne"></span>') .after('<span class="resize-handle resize-handle-se"></span>') .after('<span class="resize-handle resize-handle-sw"></span>'); // Get a variable for the container $container = $(image_target).parent('.resize-container'); // Add events $container.on('mousedown', '.resize-handle', startResize); }; //... init(); }







startResize



endResize



, , .



startResize = function(e){ e.preventDefault(); e.stopPropagation(); saveEventState(e); $(document).on('mousemove', resizing); $(document).on('mouseup', endResize); }; endResize = function(e){ e.preventDefault(); $(document).off('mouseup touchend', endResize); $(document).off('mousemove touchmove', resizing); };







. event_state



.



saveEventState = function(e){ // Save the initial event details and container state event_state.container_width = $container.width(); event_state.container_height = $container.height(); event_state.container_left = $container.offset().left; event_state.container_top = $container.offset().top; event_state.mouse_x = (e.clientX || e.pageX || e.originalEvent.touches[0].clientX) + $(window).scrollLeft(); event_state.mouse_y = (e.clientY || e.pageY || e.originalEvent.touches[0].clientY) + $(window).scrollTop(); // This is a fix for mobile safari // For some reason it does not allow a direct copy of the touches property if(typeof e.originalEvent.touches !== 'undefined'){ event_state.touches = []; $.each(e.originalEvent.touches, function(i, ob){ event_state.touches[i] = {}; event_state.touches[i].clientX = 0+ob.clientX; event_state.touches[i].clientY = 0+ob.clientY; }); } event_state.evnt = e; }







resizing



- . . .



resizing = function(e){ var mouse={},width,height,left,top,offset=$container.offset(); mouse.x = (e.clientX || e.pageX || e.originalEvent.touches[0].clientX) + $(window).scrollLeft(); mouse.y = (e.clientY || e.pageY || e.originalEvent.touches[0].clientY) + $(window).scrollTop(); width = mouse.x - event_state.container_left; height = mouse.y - event_state.container_top; left = event_state.container_left; top = event_state.container_top; if(constrain || e.shiftKey){ height = width / orig_src.width * orig_src.height; } if(width > min_width && height > min_height && width < max_width && height < max_height){ resizeImage(width, height); // Without this Firefox will not re-calculate the the image dimensions until drag end $container.offset({'left': left, 'top': top}); } }







Shift .



.



: , , resizeImage



.





Canvas , drawImage



. , . toDataURL



Base64-encoded .



.



resizeImage = function(width, height){ resize_canvas.width = width; resize_canvas.height = height; resize_canvas.getContext('2d').drawImage(orig_src, 0, 0, width, height); $(image_target).attr('src', resize_canvas.toDataURL("image/png")); };







? : , CORS . , 'tainted canvas'.







. . , . , .



, , .







, . resizing



:



resizing = function(e){ var mouse={},width,height,left,top,offset=$container.offset(); mouse.x = (e.clientX || e.pageX || e.originalEvent.touches[0].clientX) + $(window).scrollLeft(); mouse.y = (e.clientY || e.pageY || e.originalEvent.touches[0].clientY) + $(window).scrollTop(); // Position image differently depending on the corner dragged and constraints if( $(event_state.evnt.target).hasClass('resize-handle-se') ){ width = mouse.x - event_state.container_left; height = mouse.y - event_state.container_top; left = event_state.container_left; top = event_state.container_top; } else if($(event_state.evnt.target).hasClass('resize-handle-sw') ){ width = event_state.container_width - (mouse.x - event_state.container_left); height = mouse.y - event_state.container_top; left = mouse.x; top = event_state.container_top; } else if($(event_state.evnt.target).hasClass('resize-handle-nw') ){ width = event_state.container_width - (mouse.x - event_state.container_left); height = event_state.container_height - (mouse.y - event_state.container_top); left = mouse.x; top = mouse.y; if(constrain || e.shiftKey){ top = mouse.y - ((width / orig_src.width * orig_src.height) - height); } } else if($(event_state.evnt.target).hasClass('resize-handle-ne') ){ width = mouse.x - event_state.container_left; height = event_state.container_height - (mouse.y - event_state.container_top); left = event_state.container_left; top = mouse.y; if(constrain || e.shiftKey){ top = mouse.y - ((width / orig_src.width * orig_src.height) - height); } } // Optionally maintain aspect ratio if(constrain || e.shiftKey){ height = width / orig_src.width * orig_src.height; } if(width > min_width && height > min_height && width < max_width && height < max_height){ // To improve performance you might limit how often resizeImage() is called resizeImage(width, height); // Without this Firefox will not re-calculate the the image dimensions until drag end $container.offset({'left': left, 'top': top}); } }







, resize-handle



, .





, , , , , "". . .



init = function(){ //... $container.on('mousedown', 'img', startMoving); }







startMoving



endMoving



, startResize



endResize



.



startMoving = function(e){ e.preventDefault(); e.stopPropagation(); saveEventState(e); $(document).on('mousemove', moving); $(document).on('mouseup', endMoving); }; endMoving = function(e){ e.preventDefault(); $(document).off('mouseup', endMoving); $(document).off('mousemove', moving); };







moving



. , .



moving = function(e){ var mouse={}; e.preventDefault(); e.stopPropagation(); mouse.x = (e.clientX || e.pageX) + $(window).scrollLeft(); mouse.y = (e.clientY || e.pageY) + $(window).scrollTop(); $container.offset({ 'left': mouse.x - ( event_state.mouse_x - event_state.container_left ), 'top': mouse.y - ( event_state.mouse_y - event_state.container_top ) }); };









, , . , , , , . , , , , .



HTML :



<div class="overlay"> <div class="overlay-inner"> </div> </div> <button class="btn-crop js-crop">Crop</button>







, , .



.overlay { position: absolute; left: 50%; top: 50%; margin-left: -100px; margin-top: -100px; z-index: 999; width: 200px; height: 200px; border: solid 2px rgba(222,60,80,.9); box-sizing: content-box; pointer-events: none; } .overlay:after, .overlay:before { content: ''; position: absolute; display: block; width: 204px; height: 40px; border-left: dashed 2px rgba(222,60,80,.9); border-right: dashed 2px rgba(222,60,80,.9); } .overlay:before { top: 0; margin-left: -2px; margin-top: -40px; } .overlay:after { bottom: 0; margin-left: -2px; margin-bottom: -40px; } .overlay-inner:after, .overlay-inner:before { content: ''; position: absolute; display: block; width: 40px; height: 204px; border-top: dashed 2px rgba(222,60,80,.9); border-bottom: dashed 2px rgba(222,60,80,.9); } .overlay-inner:before { left: 0; margin-left: -40px; margin-top: -2px; } .overlay-inner:after { right: 0; margin-right: -40px; margin-top: -2px; } .btn-crop { position: absolute; vertical-align: bottom; right: 5px; bottom: 5px; padding: 6px 10px; z-index: 999; background-color: rgb(222,60,80); border: none; border-radius: 5px; color: #FFF; }







JavaScript :



init = function(){ //... $('.js-crop').on('click', crop); }; crop = function(){ var crop_canvas, left = $('.overlay').offset().left - $container.offset().left, top = $('.overlay').offset().top - $container.offset().top, width = $('.overlay').width(), height = $('.overlay').height(); crop_canvas = document.createElement('canvas'); crop_canvas.width = width; crop_canvas.height = height; crop_canvas.getContext('2d').drawImage(image_target, left, top, width, height, 0, 0, width, height); window.open(crop_canvas.toDataURL("image/png")); }







crop



resizeImage



. , .



drawImage



canvas. - . - , . - , canvas, .





. .



mousedown



mouseup



- touchstart



touchend



, mousemove



touchmove



. , touchup



touchdown



( ).



touchstart



touchend



, mousedown



, mouseup



touchmove



, mousemove



.



// In init()... $container.on('mousedown touchstart', '.resize-handle', startResize); $container.on('mousedown touchstart', 'img', startMoving); //In startResize() ... $(document).on('mousemove touchmove', moving); $(document).on('mouseup touchend', endMoving); //In endResize()... $(document).off('mouseup touchend', endMoving); $(document).off('mousemove touchmove', moving); //In startMoving()... $(document).on('mousemove touchmove', moving); $(document).on('mouseup touchend', endMoving); //In endMoving()... $(document).off('mouseup touchend', endMoving); $(document).off('mousemove touchmove', moving);







, "" . Hammer, . , , .



, , , saveEventState



. .



" " . , . moving



:



moving = function(e){ var mouse={}, touches; e.preventDefault(); e.stopPropagation(); touches = e.originalEvent.touches; mouse.x = (e.clientX || e.pageX || touches[0].clientX) + $(window).scrollLeft(); mouse.y = (e.clientY || e.pageY || touches[0].clientY) + $(window).scrollTop(); $container.offset({ 'left': mouse.x - ( event_state.mouse_x - event_state.container_left ), 'top': mouse.y - ( event_state.mouse_y - event_state.container_top ) }); // Watch for pinch zoom gesture while moving if(event_state.touches && event_state.touches.length > 1 && touches.length > 1){ var width = event_state.container_width, height = event_state.container_height; var a = event_state.touches[0].clientX - event_state.touches[1].clientX; a = a * a; var b = event_state.touches[0].clientY - event_state.touches[1].clientY; b = b * b; var dist1 = Math.sqrt( a + b ); a = e.originalEvent.touches[0].clientX - touches[1].clientX; a = a * a; b = e.originalEvent.touches[0].clientY - touches[1].clientY; b = b * b; var dist2 = Math.sqrt( a + b ); var ratio = dist2 /dist1; width = width * ratio; height = height * ratio; // To improve performance you might limit how often resizeImage() is called resizeImage(width, height); } };







.







. .



Chrome "", Firefox .



, .




HTML5, , , .



- . , . , .



canvas




, , . , , .



. . , , . , .



!





:

<img class="resize-image" src="image.jpg" alt="Image" />







! HTML .



CSS

CSS- . resize-container



.



.resize-container { position: relative; display: inline-block; cursor: move; margin: 0 auto; } .resize-container img { display: block } .resize-container:hover img, .resize-container:active img { outline: 2px dashed rgba(222,60,80,.9); }







'resize handles'. , , .



.resize-handle-ne, .resize-handle-ne, .resize-handle-se, .resize-handle-nw, .resize-handle-sw { position: absolute; display: block; width: 10px; height: 10px; background: rgba(222,60,80,.9); z-index: 999; } .resize-handle-nw { top: -5px; left: -5px; cursor: nw-resize; } .resize-handle-sw { bottom: -5px; left: -5px; cursor: sw-resize; } .resize-handle-ne { top: -5px; right: -5px; cursor: ne-resize; } .resize-handle-se { bottom: -5px; right: -5px; cursor: se-resize; }







JavaScript

Canvas.



var resizeableImage = function(image_target) { var $container, orig_src = new Image(), image_target = $(image_target).get(0), event_state = {}, constrain = false, min_width = 60, min_height = 60, max_width = 800, max_height = 900, resize_canvas = document.createElement('canvas'); }); resizeableImage($('.resize-image'));







, . , , . jQuery , .



var resizeableImage = function(image_target) { // ... init = function(){ // Create a new image with a copy of the original src // When resizing, we will always use this original copy as the base orig_src.src=image_target.src; // Add resize handles $(image_target).wrap('<div class="resize-container"></div>') .before('<span class="resize-handle resize-handle-nw"></span>') .before('<span class="resize-handle resize-handle-ne"></span>') .after('<span class="resize-handle resize-handle-se"></span>') .after('<span class="resize-handle resize-handle-sw"></span>'); // Get a variable for the container $container = $(image_target).parent('.resize-container'); // Add events $container.on('mousedown', '.resize-handle', startResize); }; //... init(); }







startResize



endResize



, , .



startResize = function(e){ e.preventDefault(); e.stopPropagation(); saveEventState(e); $(document).on('mousemove', resizing); $(document).on('mouseup', endResize); }; endResize = function(e){ e.preventDefault(); $(document).off('mouseup touchend', endResize); $(document).off('mousemove touchmove', resizing); };







. event_state



.



saveEventState = function(e){ // Save the initial event details and container state event_state.container_width = $container.width(); event_state.container_height = $container.height(); event_state.container_left = $container.offset().left; event_state.container_top = $container.offset().top; event_state.mouse_x = (e.clientX || e.pageX || e.originalEvent.touches[0].clientX) + $(window).scrollLeft(); event_state.mouse_y = (e.clientY || e.pageY || e.originalEvent.touches[0].clientY) + $(window).scrollTop(); // This is a fix for mobile safari // For some reason it does not allow a direct copy of the touches property if(typeof e.originalEvent.touches !== 'undefined'){ event_state.touches = []; $.each(e.originalEvent.touches, function(i, ob){ event_state.touches[i] = {}; event_state.touches[i].clientX = 0+ob.clientX; event_state.touches[i].clientY = 0+ob.clientY; }); } event_state.evnt = e; }







resizing



- . . .



resizing = function(e){ var mouse={},width,height,left,top,offset=$container.offset(); mouse.x = (e.clientX || e.pageX || e.originalEvent.touches[0].clientX) + $(window).scrollLeft(); mouse.y = (e.clientY || e.pageY || e.originalEvent.touches[0].clientY) + $(window).scrollTop(); width = mouse.x - event_state.container_left; height = mouse.y - event_state.container_top; left = event_state.container_left; top = event_state.container_top; if(constrain || e.shiftKey){ height = width / orig_src.width * orig_src.height; } if(width > min_width && height > min_height && width < max_width && height < max_height){ resizeImage(width, height); // Without this Firefox will not re-calculate the the image dimensions until drag end $container.offset({'left': left, 'top': top}); } }







Shift .



.



: , , resizeImage



.





Canvas , drawImage



. , . toDataURL



Base64-encoded .



.



resizeImage = function(width, height){ resize_canvas.width = width; resize_canvas.height = height; resize_canvas.getContext('2d').drawImage(orig_src, 0, 0, width, height); $(image_target).attr('src', resize_canvas.toDataURL("image/png")); };







? : , CORS . , 'tainted canvas'.







. . , . , .



, , .







, . resizing



:



resizing = function(e){ var mouse={},width,height,left,top,offset=$container.offset(); mouse.x = (e.clientX || e.pageX || e.originalEvent.touches[0].clientX) + $(window).scrollLeft(); mouse.y = (e.clientY || e.pageY || e.originalEvent.touches[0].clientY) + $(window).scrollTop(); // Position image differently depending on the corner dragged and constraints if( $(event_state.evnt.target).hasClass('resize-handle-se') ){ width = mouse.x - event_state.container_left; height = mouse.y - event_state.container_top; left = event_state.container_left; top = event_state.container_top; } else if($(event_state.evnt.target).hasClass('resize-handle-sw') ){ width = event_state.container_width - (mouse.x - event_state.container_left); height = mouse.y - event_state.container_top; left = mouse.x; top = event_state.container_top; } else if($(event_state.evnt.target).hasClass('resize-handle-nw') ){ width = event_state.container_width - (mouse.x - event_state.container_left); height = event_state.container_height - (mouse.y - event_state.container_top); left = mouse.x; top = mouse.y; if(constrain || e.shiftKey){ top = mouse.y - ((width / orig_src.width * orig_src.height) - height); } } else if($(event_state.evnt.target).hasClass('resize-handle-ne') ){ width = mouse.x - event_state.container_left; height = event_state.container_height - (mouse.y - event_state.container_top); left = event_state.container_left; top = mouse.y; if(constrain || e.shiftKey){ top = mouse.y - ((width / orig_src.width * orig_src.height) - height); } } // Optionally maintain aspect ratio if(constrain || e.shiftKey){ height = width / orig_src.width * orig_src.height; } if(width > min_width && height > min_height && width < max_width && height < max_height){ // To improve performance you might limit how often resizeImage() is called resizeImage(width, height); // Without this Firefox will not re-calculate the the image dimensions until drag end $container.offset({'left': left, 'top': top}); } }







, resize-handle



, .





, , , , , "". . .



init = function(){ //... $container.on('mousedown', 'img', startMoving); }







startMoving



endMoving



, startResize



endResize



.



startMoving = function(e){ e.preventDefault(); e.stopPropagation(); saveEventState(e); $(document).on('mousemove', moving); $(document).on('mouseup', endMoving); }; endMoving = function(e){ e.preventDefault(); $(document).off('mouseup', endMoving); $(document).off('mousemove', moving); };







moving



. , .



moving = function(e){ var mouse={}; e.preventDefault(); e.stopPropagation(); mouse.x = (e.clientX || e.pageX) + $(window).scrollLeft(); mouse.y = (e.clientY || e.pageY) + $(window).scrollTop(); $container.offset({ 'left': mouse.x - ( event_state.mouse_x - event_state.container_left ), 'top': mouse.y - ( event_state.mouse_y - event_state.container_top ) }); };









, , . , , , , . , , , , .



HTML :



<div class="overlay"> <div class="overlay-inner"> </div> </div> <button class="btn-crop js-crop">Crop</button>







, , .



.overlay { position: absolute; left: 50%; top: 50%; margin-left: -100px; margin-top: -100px; z-index: 999; width: 200px; height: 200px; border: solid 2px rgba(222,60,80,.9); box-sizing: content-box; pointer-events: none; } .overlay:after, .overlay:before { content: ''; position: absolute; display: block; width: 204px; height: 40px; border-left: dashed 2px rgba(222,60,80,.9); border-right: dashed 2px rgba(222,60,80,.9); } .overlay:before { top: 0; margin-left: -2px; margin-top: -40px; } .overlay:after { bottom: 0; margin-left: -2px; margin-bottom: -40px; } .overlay-inner:after, .overlay-inner:before { content: ''; position: absolute; display: block; width: 40px; height: 204px; border-top: dashed 2px rgba(222,60,80,.9); border-bottom: dashed 2px rgba(222,60,80,.9); } .overlay-inner:before { left: 0; margin-left: -40px; margin-top: -2px; } .overlay-inner:after { right: 0; margin-right: -40px; margin-top: -2px; } .btn-crop { position: absolute; vertical-align: bottom; right: 5px; bottom: 5px; padding: 6px 10px; z-index: 999; background-color: rgb(222,60,80); border: none; border-radius: 5px; color: #FFF; }







JavaScript :



init = function(){ //... $('.js-crop').on('click', crop); }; crop = function(){ var crop_canvas, left = $('.overlay').offset().left - $container.offset().left, top = $('.overlay').offset().top - $container.offset().top, width = $('.overlay').width(), height = $('.overlay').height(); crop_canvas = document.createElement('canvas'); crop_canvas.width = width; crop_canvas.height = height; crop_canvas.getContext('2d').drawImage(image_target, left, top, width, height, 0, 0, width, height); window.open(crop_canvas.toDataURL("image/png")); }







crop



resizeImage



. , .



drawImage



canvas. - . - , . - , canvas, .





. .



mousedown



mouseup



- touchstart



touchend



, mousemove



touchmove



. , touchup



touchdown



( ).



touchstart



touchend



, mousedown



, mouseup



touchmove



, mousemove



.



// In init()... $container.on('mousedown touchstart', '.resize-handle', startResize); $container.on('mousedown touchstart', 'img', startMoving); //In startResize() ... $(document).on('mousemove touchmove', moving); $(document).on('mouseup touchend', endMoving); //In endResize()... $(document).off('mouseup touchend', endMoving); $(document).off('mousemove touchmove', moving); //In startMoving()... $(document).on('mousemove touchmove', moving); $(document).on('mouseup touchend', endMoving); //In endMoving()... $(document).off('mouseup touchend', endMoving); $(document).off('mousemove touchmove', moving);







, "" . Hammer, . , , .



, , , saveEventState



. .



" " . , . moving



:



moving = function(e){ var mouse={}, touches; e.preventDefault(); e.stopPropagation(); touches = e.originalEvent.touches; mouse.x = (e.clientX || e.pageX || touches[0].clientX) + $(window).scrollLeft(); mouse.y = (e.clientY || e.pageY || touches[0].clientY) + $(window).scrollTop(); $container.offset({ 'left': mouse.x - ( event_state.mouse_x - event_state.container_left ), 'top': mouse.y - ( event_state.mouse_y - event_state.container_top ) }); // Watch for pinch zoom gesture while moving if(event_state.touches && event_state.touches.length > 1 && touches.length > 1){ var width = event_state.container_width, height = event_state.container_height; var a = event_state.touches[0].clientX - event_state.touches[1].clientX; a = a * a; var b = event_state.touches[0].clientY - event_state.touches[1].clientY; b = b * b; var dist1 = Math.sqrt( a + b ); a = e.originalEvent.touches[0].clientX - touches[1].clientX; a = a * a; b = e.originalEvent.touches[0].clientY - touches[1].clientY; b = b * b; var dist2 = Math.sqrt( a + b ); var ratio = dist2 /dist1; width = width * ratio; height = height * ratio; // To improve performance you might limit how often resizeImage() is called resizeImage(width, height); } };







.







. .



Chrome "", Firefox .



, .




  HTML5,     ,      ,   . 
      



- . , . , .



canvas




, , . , , .



. . , , . , .



!





:

<img class="resize-image" src="image.jpg" alt="Image" />







! HTML .



CSS

CSS- . resize-container



.



.resize-container { position: relative; display: inline-block; cursor: move; margin: 0 auto; } .resize-container img { display: block } .resize-container:hover img, .resize-container:active img { outline: 2px dashed rgba(222,60,80,.9); }







'resize handles'. , , .



.resize-handle-ne, .resize-handle-ne, .resize-handle-se, .resize-handle-nw, .resize-handle-sw { position: absolute; display: block; width: 10px; height: 10px; background: rgba(222,60,80,.9); z-index: 999; } .resize-handle-nw { top: -5px; left: -5px; cursor: nw-resize; } .resize-handle-sw { bottom: -5px; left: -5px; cursor: sw-resize; } .resize-handle-ne { top: -5px; right: -5px; cursor: ne-resize; } .resize-handle-se { bottom: -5px; right: -5px; cursor: se-resize; }







JavaScript

Canvas.



var resizeableImage = function(image_target) { var $container, orig_src = new Image(), image_target = $(image_target).get(0), event_state = {}, constrain = false, min_width = 60, min_height = 60, max_width = 800, max_height = 900, resize_canvas = document.createElement('canvas'); }); resizeableImage($('.resize-image'));







, . , , . jQuery , .



var resizeableImage = function(image_target) { // ... init = function(){ // Create a new image with a copy of the original src // When resizing, we will always use this original copy as the base orig_src.src=image_target.src; // Add resize handles $(image_target).wrap('<div class="resize-container"></div>') .before('<span class="resize-handle resize-handle-nw"></span>') .before('<span class="resize-handle resize-handle-ne"></span>') .after('<span class="resize-handle resize-handle-se"></span>') .after('<span class="resize-handle resize-handle-sw"></span>'); // Get a variable for the container $container = $(image_target).parent('.resize-container'); // Add events $container.on('mousedown', '.resize-handle', startResize); }; //... init(); }







startResize



endResize



, , .



startResize = function(e){ e.preventDefault(); e.stopPropagation(); saveEventState(e); $(document).on('mousemove', resizing); $(document).on('mouseup', endResize); }; endResize = function(e){ e.preventDefault(); $(document).off('mouseup touchend', endResize); $(document).off('mousemove touchmove', resizing); };







. event_state



.



saveEventState = function(e){ // Save the initial event details and container state event_state.container_width = $container.width(); event_state.container_height = $container.height(); event_state.container_left = $container.offset().left; event_state.container_top = $container.offset().top; event_state.mouse_x = (e.clientX || e.pageX || e.originalEvent.touches[0].clientX) + $(window).scrollLeft(); event_state.mouse_y = (e.clientY || e.pageY || e.originalEvent.touches[0].clientY) + $(window).scrollTop(); // This is a fix for mobile safari // For some reason it does not allow a direct copy of the touches property if(typeof e.originalEvent.touches !== 'undefined'){ event_state.touches = []; $.each(e.originalEvent.touches, function(i, ob){ event_state.touches[i] = {}; event_state.touches[i].clientX = 0+ob.clientX; event_state.touches[i].clientY = 0+ob.clientY; }); } event_state.evnt = e; }







resizing



- . . .



resizing = function(e){ var mouse={},width,height,left,top,offset=$container.offset(); mouse.x = (e.clientX || e.pageX || e.originalEvent.touches[0].clientX) + $(window).scrollLeft(); mouse.y = (e.clientY || e.pageY || e.originalEvent.touches[0].clientY) + $(window).scrollTop(); width = mouse.x - event_state.container_left; height = mouse.y - event_state.container_top; left = event_state.container_left; top = event_state.container_top; if(constrain || e.shiftKey){ height = width / orig_src.width * orig_src.height; } if(width > min_width && height > min_height && width < max_width && height < max_height){ resizeImage(width, height); // Without this Firefox will not re-calculate the the image dimensions until drag end $container.offset({'left': left, 'top': top}); } }







Shift .



.



: , , resizeImage



.





Canvas , drawImage



. , . toDataURL



Base64-encoded .



.



resizeImage = function(width, height){ resize_canvas.width = width; resize_canvas.height = height; resize_canvas.getContext('2d').drawImage(orig_src, 0, 0, width, height); $(image_target).attr('src', resize_canvas.toDataURL("image/png")); };







? : , CORS . , 'tainted canvas'.







. . , . , .



, , .







, . resizing



:



resizing = function(e){ var mouse={},width,height,left,top,offset=$container.offset(); mouse.x = (e.clientX || e.pageX || e.originalEvent.touches[0].clientX) + $(window).scrollLeft(); mouse.y = (e.clientY || e.pageY || e.originalEvent.touches[0].clientY) + $(window).scrollTop(); // Position image differently depending on the corner dragged and constraints if( $(event_state.evnt.target).hasClass('resize-handle-se') ){ width = mouse.x - event_state.container_left; height = mouse.y - event_state.container_top; left = event_state.container_left; top = event_state.container_top; } else if($(event_state.evnt.target).hasClass('resize-handle-sw') ){ width = event_state.container_width - (mouse.x - event_state.container_left); height = mouse.y - event_state.container_top; left = mouse.x; top = event_state.container_top; } else if($(event_state.evnt.target).hasClass('resize-handle-nw') ){ width = event_state.container_width - (mouse.x - event_state.container_left); height = event_state.container_height - (mouse.y - event_state.container_top); left = mouse.x; top = mouse.y; if(constrain || e.shiftKey){ top = mouse.y - ((width / orig_src.width * orig_src.height) - height); } } else if($(event_state.evnt.target).hasClass('resize-handle-ne') ){ width = mouse.x - event_state.container_left; height = event_state.container_height - (mouse.y - event_state.container_top); left = event_state.container_left; top = mouse.y; if(constrain || e.shiftKey){ top = mouse.y - ((width / orig_src.width * orig_src.height) - height); } } // Optionally maintain aspect ratio if(constrain || e.shiftKey){ height = width / orig_src.width * orig_src.height; } if(width > min_width && height > min_height && width < max_width && height < max_height){ // To improve performance you might limit how often resizeImage() is called resizeImage(width, height); // Without this Firefox will not re-calculate the the image dimensions until drag end $container.offset({'left': left, 'top': top}); } }







, resize-handle



, .





, , , , , "". . .



init = function(){ //... $container.on('mousedown', 'img', startMoving); }







startMoving



endMoving



, startResize



endResize



.



startMoving = function(e){ e.preventDefault(); e.stopPropagation(); saveEventState(e); $(document).on('mousemove', moving); $(document).on('mouseup', endMoving); }; endMoving = function(e){ e.preventDefault(); $(document).off('mouseup', endMoving); $(document).off('mousemove', moving); };







moving



. , .



moving = function(e){ var mouse={}; e.preventDefault(); e.stopPropagation(); mouse.x = (e.clientX || e.pageX) + $(window).scrollLeft(); mouse.y = (e.clientY || e.pageY) + $(window).scrollTop(); $container.offset({ 'left': mouse.x - ( event_state.mouse_x - event_state.container_left ), 'top': mouse.y - ( event_state.mouse_y - event_state.container_top ) }); };









, , . , , , , . , , , , .



HTML :



<div class="overlay"> <div class="overlay-inner"> </div> </div> <button class="btn-crop js-crop">Crop</button>







, , .



.overlay { position: absolute; left: 50%; top: 50%; margin-left: -100px; margin-top: -100px; z-index: 999; width: 200px; height: 200px; border: solid 2px rgba(222,60,80,.9); box-sizing: content-box; pointer-events: none; } .overlay:after, .overlay:before { content: ''; position: absolute; display: block; width: 204px; height: 40px; border-left: dashed 2px rgba(222,60,80,.9); border-right: dashed 2px rgba(222,60,80,.9); } .overlay:before { top: 0; margin-left: -2px; margin-top: -40px; } .overlay:after { bottom: 0; margin-left: -2px; margin-bottom: -40px; } .overlay-inner:after, .overlay-inner:before { content: ''; position: absolute; display: block; width: 40px; height: 204px; border-top: dashed 2px rgba(222,60,80,.9); border-bottom: dashed 2px rgba(222,60,80,.9); } .overlay-inner:before { left: 0; margin-left: -40px; margin-top: -2px; } .overlay-inner:after { right: 0; margin-right: -40px; margin-top: -2px; } .btn-crop { position: absolute; vertical-align: bottom; right: 5px; bottom: 5px; padding: 6px 10px; z-index: 999; background-color: rgb(222,60,80); border: none; border-radius: 5px; color: #FFF; }







JavaScript :



init = function(){ //... $('.js-crop').on('click', crop); }; crop = function(){ var crop_canvas, left = $('.overlay').offset().left - $container.offset().left, top = $('.overlay').offset().top - $container.offset().top, width = $('.overlay').width(), height = $('.overlay').height(); crop_canvas = document.createElement('canvas'); crop_canvas.width = width; crop_canvas.height = height; crop_canvas.getContext('2d').drawImage(image_target, left, top, width, height, 0, 0, width, height); window.open(crop_canvas.toDataURL("image/png")); }







crop



resizeImage



. , .



drawImage



canvas. - . - , . - , canvas, .





. .



mousedown



mouseup



- touchstart



touchend



, mousemove



touchmove



. , touchup



touchdown



( ).



touchstart



touchend



, mousedown



, mouseup



touchmove



, mousemove



.



// In init()... $container.on('mousedown touchstart', '.resize-handle', startResize); $container.on('mousedown touchstart', 'img', startMoving); //In startResize() ... $(document).on('mousemove touchmove', moving); $(document).on('mouseup touchend', endMoving); //In endResize()... $(document).off('mouseup touchend', endMoving); $(document).off('mousemove touchmove', moving); //In startMoving()... $(document).on('mousemove touchmove', moving); $(document).on('mouseup touchend', endMoving); //In endMoving()... $(document).off('mouseup touchend', endMoving); $(document).off('mousemove touchmove', moving);







, "" . Hammer, . , , .



, , , saveEventState



. .



" " . , . moving



:



moving = function(e){ var mouse={}, touches; e.preventDefault(); e.stopPropagation(); touches = e.originalEvent.touches; mouse.x = (e.clientX || e.pageX || touches[0].clientX) + $(window).scrollLeft(); mouse.y = (e.clientY || e.pageY || touches[0].clientY) + $(window).scrollTop(); $container.offset({ 'left': mouse.x - ( event_state.mouse_x - event_state.container_left ), 'top': mouse.y - ( event_state.mouse_y - event_state.container_top ) }); // Watch for pinch zoom gesture while moving if(event_state.touches && event_state.touches.length > 1 && touches.length > 1){ var width = event_state.container_width, height = event_state.container_height; var a = event_state.touches[0].clientX - event_state.touches[1].clientX; a = a * a; var b = event_state.touches[0].clientY - event_state.touches[1].clientY; b = b * b; var dist1 = Math.sqrt( a + b ); a = e.originalEvent.touches[0].clientX - touches[1].clientX; a = a * a; b = e.originalEvent.touches[0].clientY - touches[1].clientY; b = b * b; var dist2 = Math.sqrt( a + b ); var ratio = dist2 /dist1; width = width * ratio; height = height * ratio; // To improve performance you might limit how often resizeImage() is called resizeImage(width, height); } };







.







. .



Chrome "", Firefox .



, .




HTML5, , , .



- . , . , .



canvas




, , . , , .



. . , , . , .



!





:

<img class="resize-image" src="image.jpg" alt="Image" />







! HTML .



CSS

CSS- . resize-container



.



.resize-container { position: relative; display: inline-block; cursor: move; margin: 0 auto; } .resize-container img { display: block } .resize-container:hover img, .resize-container:active img { outline: 2px dashed rgba(222,60,80,.9); }







'resize handles'. , , .



.resize-handle-ne, .resize-handle-ne, .resize-handle-se, .resize-handle-nw, .resize-handle-sw { position: absolute; display: block; width: 10px; height: 10px; background: rgba(222,60,80,.9); z-index: 999; } .resize-handle-nw { top: -5px; left: -5px; cursor: nw-resize; } .resize-handle-sw { bottom: -5px; left: -5px; cursor: sw-resize; } .resize-handle-ne { top: -5px; right: -5px; cursor: ne-resize; } .resize-handle-se { bottom: -5px; right: -5px; cursor: se-resize; }







JavaScript

Canvas.



var resizeableImage = function(image_target) { var $container, orig_src = new Image(), image_target = $(image_target).get(0), event_state = {}, constrain = false, min_width = 60, min_height = 60, max_width = 800, max_height = 900, resize_canvas = document.createElement('canvas'); }); resizeableImage($('.resize-image'));







, . , , . jQuery , .



var resizeableImage = function(image_target) { // ... init = function(){ // Create a new image with a copy of the original src // When resizing, we will always use this original copy as the base orig_src.src=image_target.src; // Add resize handles $(image_target).wrap('<div class="resize-container"></div>') .before('<span class="resize-handle resize-handle-nw"></span>') .before('<span class="resize-handle resize-handle-ne"></span>') .after('<span class="resize-handle resize-handle-se"></span>') .after('<span class="resize-handle resize-handle-sw"></span>'); // Get a variable for the container $container = $(image_target).parent('.resize-container'); // Add events $container.on('mousedown', '.resize-handle', startResize); }; //... init(); }







startResize



endResize



, , .



startResize = function(e){ e.preventDefault(); e.stopPropagation(); saveEventState(e); $(document).on('mousemove', resizing); $(document).on('mouseup', endResize); }; endResize = function(e){ e.preventDefault(); $(document).off('mouseup touchend', endResize); $(document).off('mousemove touchmove', resizing); };







. event_state



.



saveEventState = function(e){ // Save the initial event details and container state event_state.container_width = $container.width(); event_state.container_height = $container.height(); event_state.container_left = $container.offset().left; event_state.container_top = $container.offset().top; event_state.mouse_x = (e.clientX || e.pageX || e.originalEvent.touches[0].clientX) + $(window).scrollLeft(); event_state.mouse_y = (e.clientY || e.pageY || e.originalEvent.touches[0].clientY) + $(window).scrollTop(); // This is a fix for mobile safari // For some reason it does not allow a direct copy of the touches property if(typeof e.originalEvent.touches !== 'undefined'){ event_state.touches = []; $.each(e.originalEvent.touches, function(i, ob){ event_state.touches[i] = {}; event_state.touches[i].clientX = 0+ob.clientX; event_state.touches[i].clientY = 0+ob.clientY; }); } event_state.evnt = e; }







resizing



- . . .



resizing = function(e){ var mouse={},width,height,left,top,offset=$container.offset(); mouse.x = (e.clientX || e.pageX || e.originalEvent.touches[0].clientX) + $(window).scrollLeft(); mouse.y = (e.clientY || e.pageY || e.originalEvent.touches[0].clientY) + $(window).scrollTop(); width = mouse.x - event_state.container_left; height = mouse.y - event_state.container_top; left = event_state.container_left; top = event_state.container_top; if(constrain || e.shiftKey){ height = width / orig_src.width * orig_src.height; } if(width > min_width && height > min_height && width < max_width && height < max_height){ resizeImage(width, height); // Without this Firefox will not re-calculate the the image dimensions until drag end $container.offset({'left': left, 'top': top}); } }







Shift .



.



: , , resizeImage



.





Canvas , drawImage



. , . toDataURL



Base64-encoded .



.



resizeImage = function(width, height){ resize_canvas.width = width; resize_canvas.height = height; resize_canvas.getContext('2d').drawImage(orig_src, 0, 0, width, height); $(image_target).attr('src', resize_canvas.toDataURL("image/png")); };







? : , CORS . , 'tainted canvas'.







. . , . , .



, , .







, . resizing



:



resizing = function(e){ var mouse={},width,height,left,top,offset=$container.offset(); mouse.x = (e.clientX || e.pageX || e.originalEvent.touches[0].clientX) + $(window).scrollLeft(); mouse.y = (e.clientY || e.pageY || e.originalEvent.touches[0].clientY) + $(window).scrollTop(); // Position image differently depending on the corner dragged and constraints if( $(event_state.evnt.target).hasClass('resize-handle-se') ){ width = mouse.x - event_state.container_left; height = mouse.y - event_state.container_top; left = event_state.container_left; top = event_state.container_top; } else if($(event_state.evnt.target).hasClass('resize-handle-sw') ){ width = event_state.container_width - (mouse.x - event_state.container_left); height = mouse.y - event_state.container_top; left = mouse.x; top = event_state.container_top; } else if($(event_state.evnt.target).hasClass('resize-handle-nw') ){ width = event_state.container_width - (mouse.x - event_state.container_left); height = event_state.container_height - (mouse.y - event_state.container_top); left = mouse.x; top = mouse.y; if(constrain || e.shiftKey){ top = mouse.y - ((width / orig_src.width * orig_src.height) - height); } } else if($(event_state.evnt.target).hasClass('resize-handle-ne') ){ width = mouse.x - event_state.container_left; height = event_state.container_height - (mouse.y - event_state.container_top); left = event_state.container_left; top = mouse.y; if(constrain || e.shiftKey){ top = mouse.y - ((width / orig_src.width * orig_src.height) - height); } } // Optionally maintain aspect ratio if(constrain || e.shiftKey){ height = width / orig_src.width * orig_src.height; } if(width > min_width && height > min_height && width < max_width && height < max_height){ // To improve performance you might limit how often resizeImage() is called resizeImage(width, height); // Without this Firefox will not re-calculate the the image dimensions until drag end $container.offset({'left': left, 'top': top}); } }







, resize-handle



, .





, , , , , "". . .



init = function(){ //... $container.on('mousedown', 'img', startMoving); }







startMoving



endMoving



, startResize



endResize



.



startMoving = function(e){ e.preventDefault(); e.stopPropagation(); saveEventState(e); $(document).on('mousemove', moving); $(document).on('mouseup', endMoving); }; endMoving = function(e){ e.preventDefault(); $(document).off('mouseup', endMoving); $(document).off('mousemove', moving); };







moving



. , .



moving = function(e){ var mouse={}; e.preventDefault(); e.stopPropagation(); mouse.x = (e.clientX || e.pageX) + $(window).scrollLeft(); mouse.y = (e.clientY || e.pageY) + $(window).scrollTop(); $container.offset({ 'left': mouse.x - ( event_state.mouse_x - event_state.container_left ), 'top': mouse.y - ( event_state.mouse_y - event_state.container_top ) }); };









, , . , , , , . , , , , .



HTML :



<div class="overlay"> <div class="overlay-inner"> </div> </div> <button class="btn-crop js-crop">Crop</button>







, , .



.overlay { position: absolute; left: 50%; top: 50%; margin-left: -100px; margin-top: -100px; z-index: 999; width: 200px; height: 200px; border: solid 2px rgba(222,60,80,.9); box-sizing: content-box; pointer-events: none; } .overlay:after, .overlay:before { content: ''; position: absolute; display: block; width: 204px; height: 40px; border-left: dashed 2px rgba(222,60,80,.9); border-right: dashed 2px rgba(222,60,80,.9); } .overlay:before { top: 0; margin-left: -2px; margin-top: -40px; } .overlay:after { bottom: 0; margin-left: -2px; margin-bottom: -40px; } .overlay-inner:after, .overlay-inner:before { content: ''; position: absolute; display: block; width: 40px; height: 204px; border-top: dashed 2px rgba(222,60,80,.9); border-bottom: dashed 2px rgba(222,60,80,.9); } .overlay-inner:before { left: 0; margin-left: -40px; margin-top: -2px; } .overlay-inner:after { right: 0; margin-right: -40px; margin-top: -2px; } .btn-crop { position: absolute; vertical-align: bottom; right: 5px; bottom: 5px; padding: 6px 10px; z-index: 999; background-color: rgb(222,60,80); border: none; border-radius: 5px; color: #FFF; }







JavaScript :



init = function(){ //... $('.js-crop').on('click', crop); }; crop = function(){ var crop_canvas, left = $('.overlay').offset().left - $container.offset().left, top = $('.overlay').offset().top - $container.offset().top, width = $('.overlay').width(), height = $('.overlay').height(); crop_canvas = document.createElement('canvas'); crop_canvas.width = width; crop_canvas.height = height; crop_canvas.getContext('2d').drawImage(image_target, left, top, width, height, 0, 0, width, height); window.open(crop_canvas.toDataURL("image/png")); }







crop



resizeImage



. , .



drawImage



canvas. - . - , . - , canvas, .





. .



mousedown



mouseup



- touchstart



touchend



, mousemove



touchmove



. , touchup



touchdown



( ).



touchstart



touchend



, mousedown



, mouseup



touchmove



, mousemove



.



// In init()... $container.on('mousedown touchstart', '.resize-handle', startResize); $container.on('mousedown touchstart', 'img', startMoving); //In startResize() ... $(document).on('mousemove touchmove', moving); $(document).on('mouseup touchend', endMoving); //In endResize()... $(document).off('mouseup touchend', endMoving); $(document).off('mousemove touchmove', moving); //In startMoving()... $(document).on('mousemove touchmove', moving); $(document).on('mouseup touchend', endMoving); //In endMoving()... $(document).off('mouseup touchend', endMoving); $(document).off('mousemove touchmove', moving);







, "" . Hammer, . , , .



, , , saveEventState



. .



" " . , . moving



:



moving = function(e){ var mouse={}, touches; e.preventDefault(); e.stopPropagation(); touches = e.originalEvent.touches; mouse.x = (e.clientX || e.pageX || touches[0].clientX) + $(window).scrollLeft(); mouse.y = (e.clientY || e.pageY || touches[0].clientY) + $(window).scrollTop(); $container.offset({ 'left': mouse.x - ( event_state.mouse_x - event_state.container_left ), 'top': mouse.y - ( event_state.mouse_y - event_state.container_top ) }); // Watch for pinch zoom gesture while moving if(event_state.touches && event_state.touches.length > 1 && touches.length > 1){ var width = event_state.container_width, height = event_state.container_height; var a = event_state.touches[0].clientX - event_state.touches[1].clientX; a = a * a; var b = event_state.touches[0].clientY - event_state.touches[1].clientY; b = b * b; var dist1 = Math.sqrt( a + b ); a = e.originalEvent.touches[0].clientX - touches[1].clientX; a = a * a; b = e.originalEvent.touches[0].clientY - touches[1].clientY; b = b * b; var dist2 = Math.sqrt( a + b ); var ratio = dist2 /dist1; width = width * ratio; height = height * ratio; // To improve performance you might limit how often resizeImage() is called resizeImage(width, height); } };







.







. .



Chrome "", Firefox .



, .




  HTML5,     ,      ,   . 
      



- . , . , .



canvas




, , . , , .



. . , , . , .



!





:

<img class="resize-image" src="image.jpg" alt="Image" />







! HTML .



CSS

CSS- . resize-container



.



.resize-container { position: relative; display: inline-block; cursor: move; margin: 0 auto; } .resize-container img { display: block } .resize-container:hover img, .resize-container:active img { outline: 2px dashed rgba(222,60,80,.9); }







'resize handles'. , , .



.resize-handle-ne, .resize-handle-ne, .resize-handle-se, .resize-handle-nw, .resize-handle-sw { position: absolute; display: block; width: 10px; height: 10px; background: rgba(222,60,80,.9); z-index: 999; } .resize-handle-nw { top: -5px; left: -5px; cursor: nw-resize; } .resize-handle-sw { bottom: -5px; left: -5px; cursor: sw-resize; } .resize-handle-ne { top: -5px; right: -5px; cursor: ne-resize; } .resize-handle-se { bottom: -5px; right: -5px; cursor: se-resize; }







JavaScript

Canvas.



var resizeableImage = function(image_target) { var $container, orig_src = new Image(), image_target = $(image_target).get(0), event_state = {}, constrain = false, min_width = 60, min_height = 60, max_width = 800, max_height = 900, resize_canvas = document.createElement('canvas'); }); resizeableImage($('.resize-image'));







, . , , . jQuery , .



var resizeableImage = function(image_target) { // ... init = function(){ // Create a new image with a copy of the original src // When resizing, we will always use this original copy as the base orig_src.src=image_target.src; // Add resize handles $(image_target).wrap('<div class="resize-container"></div>') .before('<span class="resize-handle resize-handle-nw"></span>') .before('<span class="resize-handle resize-handle-ne"></span>') .after('<span class="resize-handle resize-handle-se"></span>') .after('<span class="resize-handle resize-handle-sw"></span>'); // Get a variable for the container $container = $(image_target).parent('.resize-container'); // Add events $container.on('mousedown', '.resize-handle', startResize); }; //... init(); }







startResize



endResize



, , .



startResize = function(e){ e.preventDefault(); e.stopPropagation(); saveEventState(e); $(document).on('mousemove', resizing); $(document).on('mouseup', endResize); }; endResize = function(e){ e.preventDefault(); $(document).off('mouseup touchend', endResize); $(document).off('mousemove touchmove', resizing); };







. event_state



.



saveEventState = function(e){ // Save the initial event details and container state event_state.container_width = $container.width(); event_state.container_height = $container.height(); event_state.container_left = $container.offset().left; event_state.container_top = $container.offset().top; event_state.mouse_x = (e.clientX || e.pageX || e.originalEvent.touches[0].clientX) + $(window).scrollLeft(); event_state.mouse_y = (e.clientY || e.pageY || e.originalEvent.touches[0].clientY) + $(window).scrollTop(); // This is a fix for mobile safari // For some reason it does not allow a direct copy of the touches property if(typeof e.originalEvent.touches !== 'undefined'){ event_state.touches = []; $.each(e.originalEvent.touches, function(i, ob){ event_state.touches[i] = {}; event_state.touches[i].clientX = 0+ob.clientX; event_state.touches[i].clientY = 0+ob.clientY; }); } event_state.evnt = e; }







resizing



- . . .



resizing = function(e){ var mouse={},width,height,left,top,offset=$container.offset(); mouse.x = (e.clientX || e.pageX || e.originalEvent.touches[0].clientX) + $(window).scrollLeft(); mouse.y = (e.clientY || e.pageY || e.originalEvent.touches[0].clientY) + $(window).scrollTop(); width = mouse.x - event_state.container_left; height = mouse.y - event_state.container_top; left = event_state.container_left; top = event_state.container_top; if(constrain || e.shiftKey){ height = width / orig_src.width * orig_src.height; } if(width > min_width && height > min_height && width < max_width && height < max_height){ resizeImage(width, height); // Without this Firefox will not re-calculate the the image dimensions until drag end $container.offset({'left': left, 'top': top}); } }







Shift .



.



: , , resizeImage



.





Canvas , drawImage



. , . toDataURL



Base64-encoded .



.



resizeImage = function(width, height){ resize_canvas.width = width; resize_canvas.height = height; resize_canvas.getContext('2d').drawImage(orig_src, 0, 0, width, height); $(image_target).attr('src', resize_canvas.toDataURL("image/png")); };







? : , CORS . , 'tainted canvas'.







. . , . , .



, , .







, . resizing



:



resizing = function(e){ var mouse={},width,height,left,top,offset=$container.offset(); mouse.x = (e.clientX || e.pageX || e.originalEvent.touches[0].clientX) + $(window).scrollLeft(); mouse.y = (e.clientY || e.pageY || e.originalEvent.touches[0].clientY) + $(window).scrollTop(); // Position image differently depending on the corner dragged and constraints if( $(event_state.evnt.target).hasClass('resize-handle-se') ){ width = mouse.x - event_state.container_left; height = mouse.y - event_state.container_top; left = event_state.container_left; top = event_state.container_top; } else if($(event_state.evnt.target).hasClass('resize-handle-sw') ){ width = event_state.container_width - (mouse.x - event_state.container_left); height = mouse.y - event_state.container_top; left = mouse.x; top = event_state.container_top; } else if($(event_state.evnt.target).hasClass('resize-handle-nw') ){ width = event_state.container_width - (mouse.x - event_state.container_left); height = event_state.container_height - (mouse.y - event_state.container_top); left = mouse.x; top = mouse.y; if(constrain || e.shiftKey){ top = mouse.y - ((width / orig_src.width * orig_src.height) - height); } } else if($(event_state.evnt.target).hasClass('resize-handle-ne') ){ width = mouse.x - event_state.container_left; height = event_state.container_height - (mouse.y - event_state.container_top); left = event_state.container_left; top = mouse.y; if(constrain || e.shiftKey){ top = mouse.y - ((width / orig_src.width * orig_src.height) - height); } } // Optionally maintain aspect ratio if(constrain || e.shiftKey){ height = width / orig_src.width * orig_src.height; } if(width > min_width && height > min_height && width < max_width && height < max_height){ // To improve performance you might limit how often resizeImage() is called resizeImage(width, height); // Without this Firefox will not re-calculate the the image dimensions until drag end $container.offset({'left': left, 'top': top}); } }







, resize-handle



, .





, , , , , "". . .



init = function(){ //... $container.on('mousedown', 'img', startMoving); }







startMoving



endMoving



, startResize



endResize



.



startMoving = function(e){ e.preventDefault(); e.stopPropagation(); saveEventState(e); $(document).on('mousemove', moving); $(document).on('mouseup', endMoving); }; endMoving = function(e){ e.preventDefault(); $(document).off('mouseup', endMoving); $(document).off('mousemove', moving); };







moving



. , .



moving = function(e){ var mouse={}; e.preventDefault(); e.stopPropagation(); mouse.x = (e.clientX || e.pageX) + $(window).scrollLeft(); mouse.y = (e.clientY || e.pageY) + $(window).scrollTop(); $container.offset({ 'left': mouse.x - ( event_state.mouse_x - event_state.container_left ), 'top': mouse.y - ( event_state.mouse_y - event_state.container_top ) }); };









, , . , , , , . , , , , .



HTML :



<div class="overlay"> <div class="overlay-inner"> </div> </div> <button class="btn-crop js-crop">Crop</button>







, , .



.overlay { position: absolute; left: 50%; top: 50%; margin-left: -100px; margin-top: -100px; z-index: 999; width: 200px; height: 200px; border: solid 2px rgba(222,60,80,.9); box-sizing: content-box; pointer-events: none; } .overlay:after, .overlay:before { content: ''; position: absolute; display: block; width: 204px; height: 40px; border-left: dashed 2px rgba(222,60,80,.9); border-right: dashed 2px rgba(222,60,80,.9); } .overlay:before { top: 0; margin-left: -2px; margin-top: -40px; } .overlay:after { bottom: 0; margin-left: -2px; margin-bottom: -40px; } .overlay-inner:after, .overlay-inner:before { content: ''; position: absolute; display: block; width: 40px; height: 204px; border-top: dashed 2px rgba(222,60,80,.9); border-bottom: dashed 2px rgba(222,60,80,.9); } .overlay-inner:before { left: 0; margin-left: -40px; margin-top: -2px; } .overlay-inner:after { right: 0; margin-right: -40px; margin-top: -2px; } .btn-crop { position: absolute; vertical-align: bottom; right: 5px; bottom: 5px; padding: 6px 10px; z-index: 999; background-color: rgb(222,60,80); border: none; border-radius: 5px; color: #FFF; }







JavaScript :



init = function(){ //... $('.js-crop').on('click', crop); }; crop = function(){ var crop_canvas, left = $('.overlay').offset().left - $container.offset().left, top = $('.overlay').offset().top - $container.offset().top, width = $('.overlay').width(), height = $('.overlay').height(); crop_canvas = document.createElement('canvas'); crop_canvas.width = width; crop_canvas.height = height; crop_canvas.getContext('2d').drawImage(image_target, left, top, width, height, 0, 0, width, height); window.open(crop_canvas.toDataURL("image/png")); }







crop



resizeImage



. , .



drawImage



canvas. - . - , . - , canvas, .





. .



mousedown



mouseup



- touchstart



touchend



, mousemove



touchmove



. , touchup



touchdown



( ).



touchstart



touchend



, mousedown



, mouseup



touchmove



, mousemove



.



// In init()... $container.on('mousedown touchstart', '.resize-handle', startResize); $container.on('mousedown touchstart', 'img', startMoving); //In startResize() ... $(document).on('mousemove touchmove', moving); $(document).on('mouseup touchend', endMoving); //In endResize()... $(document).off('mouseup touchend', endMoving); $(document).off('mousemove touchmove', moving); //In startMoving()... $(document).on('mousemove touchmove', moving); $(document).on('mouseup touchend', endMoving); //In endMoving()... $(document).off('mouseup touchend', endMoving); $(document).off('mousemove touchmove', moving);







, "" . Hammer, . , , .



, , , saveEventState



. .



" " . , . moving



:



moving = function(e){ var mouse={}, touches; e.preventDefault(); e.stopPropagation(); touches = e.originalEvent.touches; mouse.x = (e.clientX || e.pageX || touches[0].clientX) + $(window).scrollLeft(); mouse.y = (e.clientY || e.pageY || touches[0].clientY) + $(window).scrollTop(); $container.offset({ 'left': mouse.x - ( event_state.mouse_x - event_state.container_left ), 'top': mouse.y - ( event_state.mouse_y - event_state.container_top ) }); // Watch for pinch zoom gesture while moving if(event_state.touches && event_state.touches.length > 1 && touches.length > 1){ var width = event_state.container_width, height = event_state.container_height; var a = event_state.touches[0].clientX - event_state.touches[1].clientX; a = a * a; var b = event_state.touches[0].clientY - event_state.touches[1].clientY; b = b * b; var dist1 = Math.sqrt( a + b ); a = e.originalEvent.touches[0].clientX - touches[1].clientX; a = a * a; b = e.originalEvent.touches[0].clientY - touches[1].clientY; b = b * b; var dist2 = Math.sqrt( a + b ); var ratio = dist2 /dist1; width = width * ratio; height = height * ratio; // To improve performance you might limit how often resizeImage() is called resizeImage(width, height); } };







.







. .



Chrome "", Firefox .



, .




HTML5, , , .



- . , . , .



canvas




, , . , , .



. . , , . , .



!





:

<img class="resize-image" src="image.jpg" alt="Image" />







! HTML .



CSS

CSS- . resize-container



.



.resize-container { position: relative; display: inline-block; cursor: move; margin: 0 auto; } .resize-container img { display: block } .resize-container:hover img, .resize-container:active img { outline: 2px dashed rgba(222,60,80,.9); }







'resize handles'. , , .



.resize-handle-ne, .resize-handle-ne, .resize-handle-se, .resize-handle-nw, .resize-handle-sw { position: absolute; display: block; width: 10px; height: 10px; background: rgba(222,60,80,.9); z-index: 999; } .resize-handle-nw { top: -5px; left: -5px; cursor: nw-resize; } .resize-handle-sw { bottom: -5px; left: -5px; cursor: sw-resize; } .resize-handle-ne { top: -5px; right: -5px; cursor: ne-resize; } .resize-handle-se { bottom: -5px; right: -5px; cursor: se-resize; }







JavaScript

Canvas.



var resizeableImage = function(image_target) { var $container, orig_src = new Image(), image_target = $(image_target).get(0), event_state = {}, constrain = false, min_width = 60, min_height = 60, max_width = 800, max_height = 900, resize_canvas = document.createElement('canvas'); }); resizeableImage($('.resize-image'));







, . , , . jQuery , .



var resizeableImage = function(image_target) { // ... init = function(){ // Create a new image with a copy of the original src // When resizing, we will always use this original copy as the base orig_src.src=image_target.src; // Add resize handles $(image_target).wrap('<div class="resize-container"></div>') .before('<span class="resize-handle resize-handle-nw"></span>') .before('<span class="resize-handle resize-handle-ne"></span>') .after('<span class="resize-handle resize-handle-se"></span>') .after('<span class="resize-handle resize-handle-sw"></span>'); // Get a variable for the container $container = $(image_target).parent('.resize-container'); // Add events $container.on('mousedown', '.resize-handle', startResize); }; //... init(); }







startResize



endResize



, , .



startResize = function(e){ e.preventDefault(); e.stopPropagation(); saveEventState(e); $(document).on('mousemove', resizing); $(document).on('mouseup', endResize); }; endResize = function(e){ e.preventDefault(); $(document).off('mouseup touchend', endResize); $(document).off('mousemove touchmove', resizing); };







. event_state



.



saveEventState = function(e){ // Save the initial event details and container state event_state.container_width = $container.width(); event_state.container_height = $container.height(); event_state.container_left = $container.offset().left; event_state.container_top = $container.offset().top; event_state.mouse_x = (e.clientX || e.pageX || e.originalEvent.touches[0].clientX) + $(window).scrollLeft(); event_state.mouse_y = (e.clientY || e.pageY || e.originalEvent.touches[0].clientY) + $(window).scrollTop(); // This is a fix for mobile safari // For some reason it does not allow a direct copy of the touches property if(typeof e.originalEvent.touches !== 'undefined'){ event_state.touches = []; $.each(e.originalEvent.touches, function(i, ob){ event_state.touches[i] = {}; event_state.touches[i].clientX = 0+ob.clientX; event_state.touches[i].clientY = 0+ob.clientY; }); } event_state.evnt = e; }







resizing



- . . .



resizing = function(e){ var mouse={},width,height,left,top,offset=$container.offset(); mouse.x = (e.clientX || e.pageX || e.originalEvent.touches[0].clientX) + $(window).scrollLeft(); mouse.y = (e.clientY || e.pageY || e.originalEvent.touches[0].clientY) + $(window).scrollTop(); width = mouse.x - event_state.container_left; height = mouse.y - event_state.container_top; left = event_state.container_left; top = event_state.container_top; if(constrain || e.shiftKey){ height = width / orig_src.width * orig_src.height; } if(width > min_width && height > min_height && width < max_width && height < max_height){ resizeImage(width, height); // Without this Firefox will not re-calculate the the image dimensions until drag end $container.offset({'left': left, 'top': top}); } }







Shift .



.



: , , resizeImage



.





Canvas , drawImage



. , . toDataURL



Base64-encoded .



.



resizeImage = function(width, height){ resize_canvas.width = width; resize_canvas.height = height; resize_canvas.getContext('2d').drawImage(orig_src, 0, 0, width, height); $(image_target).attr('src', resize_canvas.toDataURL("image/png")); };







? : , CORS . , 'tainted canvas'.







. . , . , .



, , .







, . resizing



:



resizing = function(e){ var mouse={},width,height,left,top,offset=$container.offset(); mouse.x = (e.clientX || e.pageX || e.originalEvent.touches[0].clientX) + $(window).scrollLeft(); mouse.y = (e.clientY || e.pageY || e.originalEvent.touches[0].clientY) + $(window).scrollTop(); // Position image differently depending on the corner dragged and constraints if( $(event_state.evnt.target).hasClass('resize-handle-se') ){ width = mouse.x - event_state.container_left; height = mouse.y - event_state.container_top; left = event_state.container_left; top = event_state.container_top; } else if($(event_state.evnt.target).hasClass('resize-handle-sw') ){ width = event_state.container_width - (mouse.x - event_state.container_left); height = mouse.y - event_state.container_top; left = mouse.x; top = event_state.container_top; } else if($(event_state.evnt.target).hasClass('resize-handle-nw') ){ width = event_state.container_width - (mouse.x - event_state.container_left); height = event_state.container_height - (mouse.y - event_state.container_top); left = mouse.x; top = mouse.y; if(constrain || e.shiftKey){ top = mouse.y - ((width / orig_src.width * orig_src.height) - height); } } else if($(event_state.evnt.target).hasClass('resize-handle-ne') ){ width = mouse.x - event_state.container_left; height = event_state.container_height - (mouse.y - event_state.container_top); left = event_state.container_left; top = mouse.y; if(constrain || e.shiftKey){ top = mouse.y - ((width / orig_src.width * orig_src.height) - height); } } // Optionally maintain aspect ratio if(constrain || e.shiftKey){ height = width / orig_src.width * orig_src.height; } if(width > min_width && height > min_height && width < max_width && height < max_height){ // To improve performance you might limit how often resizeImage() is called resizeImage(width, height); // Without this Firefox will not re-calculate the the image dimensions until drag end $container.offset({'left': left, 'top': top}); } }







, resize-handle



, .





, , , , , "". . .



init = function(){ //... $container.on('mousedown', 'img', startMoving); }







startMoving



endMoving



, startResize



endResize



.



startMoving = function(e){ e.preventDefault(); e.stopPropagation(); saveEventState(e); $(document).on('mousemove', moving); $(document).on('mouseup', endMoving); }; endMoving = function(e){ e.preventDefault(); $(document).off('mouseup', endMoving); $(document).off('mousemove', moving); };







moving



. , .



moving = function(e){ var mouse={}; e.preventDefault(); e.stopPropagation(); mouse.x = (e.clientX || e.pageX) + $(window).scrollLeft(); mouse.y = (e.clientY || e.pageY) + $(window).scrollTop(); $container.offset({ 'left': mouse.x - ( event_state.mouse_x - event_state.container_left ), 'top': mouse.y - ( event_state.mouse_y - event_state.container_top ) }); };









, , . , , , , . , , , , .



HTML :



<div class="overlay"> <div class="overlay-inner"> </div> </div> <button class="btn-crop js-crop">Crop</button>







, , .



.overlay { position: absolute; left: 50%; top: 50%; margin-left: -100px; margin-top: -100px; z-index: 999; width: 200px; height: 200px; border: solid 2px rgba(222,60,80,.9); box-sizing: content-box; pointer-events: none; } .overlay:after, .overlay:before { content: ''; position: absolute; display: block; width: 204px; height: 40px; border-left: dashed 2px rgba(222,60,80,.9); border-right: dashed 2px rgba(222,60,80,.9); } .overlay:before { top: 0; margin-left: -2px; margin-top: -40px; } .overlay:after { bottom: 0; margin-left: -2px; margin-bottom: -40px; } .overlay-inner:after, .overlay-inner:before { content: ''; position: absolute; display: block; width: 40px; height: 204px; border-top: dashed 2px rgba(222,60,80,.9); border-bottom: dashed 2px rgba(222,60,80,.9); } .overlay-inner:before { left: 0; margin-left: -40px; margin-top: -2px; } .overlay-inner:after { right: 0; margin-right: -40px; margin-top: -2px; } .btn-crop { position: absolute; vertical-align: bottom; right: 5px; bottom: 5px; padding: 6px 10px; z-index: 999; background-color: rgb(222,60,80); border: none; border-radius: 5px; color: #FFF; }







JavaScript :



init = function(){ //... $('.js-crop').on('click', crop); }; crop = function(){ var crop_canvas, left = $('.overlay').offset().left - $container.offset().left, top = $('.overlay').offset().top - $container.offset().top, width = $('.overlay').width(), height = $('.overlay').height(); crop_canvas = document.createElement('canvas'); crop_canvas.width = width; crop_canvas.height = height; crop_canvas.getContext('2d').drawImage(image_target, left, top, width, height, 0, 0, width, height); window.open(crop_canvas.toDataURL("image/png")); }







crop



resizeImage



. , .



drawImage



canvas. - . - , . - , canvas, .





. .



mousedown



mouseup



- touchstart



touchend



, mousemove



touchmove



. , touchup



touchdown



( ).



touchstart



touchend



, mousedown



, mouseup



touchmove



, mousemove



.



// In init()... $container.on('mousedown touchstart', '.resize-handle', startResize); $container.on('mousedown touchstart', 'img', startMoving); //In startResize() ... $(document).on('mousemove touchmove', moving); $(document).on('mouseup touchend', endMoving); //In endResize()... $(document).off('mouseup touchend', endMoving); $(document).off('mousemove touchmove', moving); //In startMoving()... $(document).on('mousemove touchmove', moving); $(document).on('mouseup touchend', endMoving); //In endMoving()... $(document).off('mouseup touchend', endMoving); $(document).off('mousemove touchmove', moving);







, "" . Hammer, . , , .



, , , saveEventState



. .



" " . , . moving



:



moving = function(e){ var mouse={}, touches; e.preventDefault(); e.stopPropagation(); touches = e.originalEvent.touches; mouse.x = (e.clientX || e.pageX || touches[0].clientX) + $(window).scrollLeft(); mouse.y = (e.clientY || e.pageY || touches[0].clientY) + $(window).scrollTop(); $container.offset({ 'left': mouse.x - ( event_state.mouse_x - event_state.container_left ), 'top': mouse.y - ( event_state.mouse_y - event_state.container_top ) }); // Watch for pinch zoom gesture while moving if(event_state.touches && event_state.touches.length > 1 && touches.length > 1){ var width = event_state.container_width, height = event_state.container_height; var a = event_state.touches[0].clientX - event_state.touches[1].clientX; a = a * a; var b = event_state.touches[0].clientY - event_state.touches[1].clientY; b = b * b; var dist1 = Math.sqrt( a + b ); a = e.originalEvent.touches[0].clientX - touches[1].clientX; a = a * a; b = e.originalEvent.touches[0].clientY - touches[1].clientY; b = b * b; var dist2 = Math.sqrt( a + b ); var ratio = dist2 /dist1; width = width * ratio; height = height * ratio; // To improve performance you might limit how often resizeImage() is called resizeImage(width, height); } };







.







. .



Chrome "", Firefox .



, .




  HTML5,     ,      ,   . 
      



- . , . , .



canvas




, , . , , .



. . , , . , .



!





:

<img class="resize-image" src="image.jpg" alt="Image" />







! HTML .



CSS

CSS- . resize-container



.



.resize-container { position: relative; display: inline-block; cursor: move; margin: 0 auto; } .resize-container img { display: block } .resize-container:hover img, .resize-container:active img { outline: 2px dashed rgba(222,60,80,.9); }







'resize handles'. , , .



.resize-handle-ne, .resize-handle-ne, .resize-handle-se, .resize-handle-nw, .resize-handle-sw { position: absolute; display: block; width: 10px; height: 10px; background: rgba(222,60,80,.9); z-index: 999; } .resize-handle-nw { top: -5px; left: -5px; cursor: nw-resize; } .resize-handle-sw { bottom: -5px; left: -5px; cursor: sw-resize; } .resize-handle-ne { top: -5px; right: -5px; cursor: ne-resize; } .resize-handle-se { bottom: -5px; right: -5px; cursor: se-resize; }







JavaScript

Canvas.



var resizeableImage = function(image_target) { var $container, orig_src = new Image(), image_target = $(image_target).get(0), event_state = {}, constrain = false, min_width = 60, min_height = 60, max_width = 800, max_height = 900, resize_canvas = document.createElement('canvas'); }); resizeableImage($('.resize-image'));







, . , , . jQuery , .



var resizeableImage = function(image_target) { // ... init = function(){ // Create a new image with a copy of the original src // When resizing, we will always use this original copy as the base orig_src.src=image_target.src; // Add resize handles $(image_target).wrap('<div class="resize-container"></div>') .before('<span class="resize-handle resize-handle-nw"></span>') .before('<span class="resize-handle resize-handle-ne"></span>') .after('<span class="resize-handle resize-handle-se"></span>') .after('<span class="resize-handle resize-handle-sw"></span>'); // Get a variable for the container $container = $(image_target).parent('.resize-container'); // Add events $container.on('mousedown', '.resize-handle', startResize); }; //... init(); }







startResize



endResize



, , .



startResize = function(e){ e.preventDefault(); e.stopPropagation(); saveEventState(e); $(document).on('mousemove', resizing); $(document).on('mouseup', endResize); }; endResize = function(e){ e.preventDefault(); $(document).off('mouseup touchend', endResize); $(document).off('mousemove touchmove', resizing); };







. event_state



.



saveEventState = function(e){ // Save the initial event details and container state event_state.container_width = $container.width(); event_state.container_height = $container.height(); event_state.container_left = $container.offset().left; event_state.container_top = $container.offset().top; event_state.mouse_x = (e.clientX || e.pageX || e.originalEvent.touches[0].clientX) + $(window).scrollLeft(); event_state.mouse_y = (e.clientY || e.pageY || e.originalEvent.touches[0].clientY) + $(window).scrollTop(); // This is a fix for mobile safari // For some reason it does not allow a direct copy of the touches property if(typeof e.originalEvent.touches !== 'undefined'){ event_state.touches = []; $.each(e.originalEvent.touches, function(i, ob){ event_state.touches[i] = {}; event_state.touches[i].clientX = 0+ob.clientX; event_state.touches[i].clientY = 0+ob.clientY; }); } event_state.evnt = e; }







resizing



- . . .



resizing = function(e){ var mouse={},width,height,left,top,offset=$container.offset(); mouse.x = (e.clientX || e.pageX || e.originalEvent.touches[0].clientX) + $(window).scrollLeft(); mouse.y = (e.clientY || e.pageY || e.originalEvent.touches[0].clientY) + $(window).scrollTop(); width = mouse.x - event_state.container_left; height = mouse.y - event_state.container_top; left = event_state.container_left; top = event_state.container_top; if(constrain || e.shiftKey){ height = width / orig_src.width * orig_src.height; } if(width > min_width && height > min_height && width < max_width && height < max_height){ resizeImage(width, height); // Without this Firefox will not re-calculate the the image dimensions until drag end $container.offset({'left': left, 'top': top}); } }







Shift .



.



: , , resizeImage



.





Canvas , drawImage



. , . toDataURL



Base64-encoded .



.



resizeImage = function(width, height){ resize_canvas.width = width; resize_canvas.height = height; resize_canvas.getContext('2d').drawImage(orig_src, 0, 0, width, height); $(image_target).attr('src', resize_canvas.toDataURL("image/png")); };







? : , CORS . , 'tainted canvas'.







. . , . , .



, , .







, . resizing



:



resizing = function(e){ var mouse={},width,height,left,top,offset=$container.offset(); mouse.x = (e.clientX || e.pageX || e.originalEvent.touches[0].clientX) + $(window).scrollLeft(); mouse.y = (e.clientY || e.pageY || e.originalEvent.touches[0].clientY) + $(window).scrollTop(); // Position image differently depending on the corner dragged and constraints if( $(event_state.evnt.target).hasClass('resize-handle-se') ){ width = mouse.x - event_state.container_left; height = mouse.y - event_state.container_top; left = event_state.container_left; top = event_state.container_top; } else if($(event_state.evnt.target).hasClass('resize-handle-sw') ){ width = event_state.container_width - (mouse.x - event_state.container_left); height = mouse.y - event_state.container_top; left = mouse.x; top = event_state.container_top; } else if($(event_state.evnt.target).hasClass('resize-handle-nw') ){ width = event_state.container_width - (mouse.x - event_state.container_left); height = event_state.container_height - (mouse.y - event_state.container_top); left = mouse.x; top = mouse.y; if(constrain || e.shiftKey){ top = mouse.y - ((width / orig_src.width * orig_src.height) - height); } } else if($(event_state.evnt.target).hasClass('resize-handle-ne') ){ width = mouse.x - event_state.container_left; height = event_state.container_height - (mouse.y - event_state.container_top); left = event_state.container_left; top = mouse.y; if(constrain || e.shiftKey){ top = mouse.y - ((width / orig_src.width * orig_src.height) - height); } } // Optionally maintain aspect ratio if(constrain || e.shiftKey){ height = width / orig_src.width * orig_src.height; } if(width > min_width && height > min_height && width < max_width && height < max_height){ // To improve performance you might limit how often resizeImage() is called resizeImage(width, height); // Without this Firefox will not re-calculate the the image dimensions until drag end $container.offset({'left': left, 'top': top}); } }







, resize-handle



, .





, , , , , "". . .



init = function(){ //... $container.on('mousedown', 'img', startMoving); }







startMoving



endMoving



, startResize



endResize



.



startMoving = function(e){ e.preventDefault(); e.stopPropagation(); saveEventState(e); $(document).on('mousemove', moving); $(document).on('mouseup', endMoving); }; endMoving = function(e){ e.preventDefault(); $(document).off('mouseup', endMoving); $(document).off('mousemove', moving); };







moving



. , .



moving = function(e){ var mouse={}; e.preventDefault(); e.stopPropagation(); mouse.x = (e.clientX || e.pageX) + $(window).scrollLeft(); mouse.y = (e.clientY || e.pageY) + $(window).scrollTop(); $container.offset({ 'left': mouse.x - ( event_state.mouse_x - event_state.container_left ), 'top': mouse.y - ( event_state.mouse_y - event_state.container_top ) }); };









, , . , , , , . , , , , .



HTML :



<div class="overlay"> <div class="overlay-inner"> </div> </div> <button class="btn-crop js-crop">Crop</button>







, , .



.overlay { position: absolute; left: 50%; top: 50%; margin-left: -100px; margin-top: -100px; z-index: 999; width: 200px; height: 200px; border: solid 2px rgba(222,60,80,.9); box-sizing: content-box; pointer-events: none; } .overlay:after, .overlay:before { content: ''; position: absolute; display: block; width: 204px; height: 40px; border-left: dashed 2px rgba(222,60,80,.9); border-right: dashed 2px rgba(222,60,80,.9); } .overlay:before { top: 0; margin-left: -2px; margin-top: -40px; } .overlay:after { bottom: 0; margin-left: -2px; margin-bottom: -40px; } .overlay-inner:after, .overlay-inner:before { content: ''; position: absolute; display: block; width: 40px; height: 204px; border-top: dashed 2px rgba(222,60,80,.9); border-bottom: dashed 2px rgba(222,60,80,.9); } .overlay-inner:before { left: 0; margin-left: -40px; margin-top: -2px; } .overlay-inner:after { right: 0; margin-right: -40px; margin-top: -2px; } .btn-crop { position: absolute; vertical-align: bottom; right: 5px; bottom: 5px; padding: 6px 10px; z-index: 999; background-color: rgb(222,60,80); border: none; border-radius: 5px; color: #FFF; }







JavaScript :



init = function(){ //... $('.js-crop').on('click', crop); }; crop = function(){ var crop_canvas, left = $('.overlay').offset().left - $container.offset().left, top = $('.overlay').offset().top - $container.offset().top, width = $('.overlay').width(), height = $('.overlay').height(); crop_canvas = document.createElement('canvas'); crop_canvas.width = width; crop_canvas.height = height; crop_canvas.getContext('2d').drawImage(image_target, left, top, width, height, 0, 0, width, height); window.open(crop_canvas.toDataURL("image/png")); }







crop



resizeImage



. , .



drawImage



canvas. - . - , . - , canvas, .





. .



mousedown



mouseup



- touchstart



touchend



, mousemove



touchmove



. , touchup



touchdown



( ).



touchstart



touchend



, mousedown



, mouseup



touchmove



, mousemove



.



// In init()... $container.on('mousedown touchstart', '.resize-handle', startResize); $container.on('mousedown touchstart', 'img', startMoving); //In startResize() ... $(document).on('mousemove touchmove', moving); $(document).on('mouseup touchend', endMoving); //In endResize()... $(document).off('mouseup touchend', endMoving); $(document).off('mousemove touchmove', moving); //In startMoving()... $(document).on('mousemove touchmove', moving); $(document).on('mouseup touchend', endMoving); //In endMoving()... $(document).off('mouseup touchend', endMoving); $(document).off('mousemove touchmove', moving);







, "" . Hammer, . , , .



, , , saveEventState



. .



" " . , . moving



:



moving = function(e){ var mouse={}, touches; e.preventDefault(); e.stopPropagation(); touches = e.originalEvent.touches; mouse.x = (e.clientX || e.pageX || touches[0].clientX) + $(window).scrollLeft(); mouse.y = (e.clientY || e.pageY || touches[0].clientY) + $(window).scrollTop(); $container.offset({ 'left': mouse.x - ( event_state.mouse_x - event_state.container_left ), 'top': mouse.y - ( event_state.mouse_y - event_state.container_top ) }); // Watch for pinch zoom gesture while moving if(event_state.touches && event_state.touches.length > 1 && touches.length > 1){ var width = event_state.container_width, height = event_state.container_height; var a = event_state.touches[0].clientX - event_state.touches[1].clientX; a = a * a; var b = event_state.touches[0].clientY - event_state.touches[1].clientY; b = b * b; var dist1 = Math.sqrt( a + b ); a = e.originalEvent.touches[0].clientX - touches[1].clientX; a = a * a; b = e.originalEvent.touches[0].clientY - touches[1].clientY; b = b * b; var dist2 = Math.sqrt( a + b ); var ratio = dist2 /dist1; width = width * ratio; height = height * ratio; // To improve performance you might limit how often resizeImage() is called resizeImage(width, height); } };







.







. .



Chrome "", Firefox .



, .




HTML5, , , .



- . , . , .



canvas




, , . , , .



. . , , . , .



!





:

<img class="resize-image" src="image.jpg" alt="Image" />







! HTML .



CSS

CSS- . resize-container



.



.resize-container { position: relative; display: inline-block; cursor: move; margin: 0 auto; } .resize-container img { display: block } .resize-container:hover img, .resize-container:active img { outline: 2px dashed rgba(222,60,80,.9); }







'resize handles'. , , .



.resize-handle-ne, .resize-handle-ne, .resize-handle-se, .resize-handle-nw, .resize-handle-sw { position: absolute; display: block; width: 10px; height: 10px; background: rgba(222,60,80,.9); z-index: 999; } .resize-handle-nw { top: -5px; left: -5px; cursor: nw-resize; } .resize-handle-sw { bottom: -5px; left: -5px; cursor: sw-resize; } .resize-handle-ne { top: -5px; right: -5px; cursor: ne-resize; } .resize-handle-se { bottom: -5px; right: -5px; cursor: se-resize; }







JavaScript

Canvas.



var resizeableImage = function(image_target) { var $container, orig_src = new Image(), image_target = $(image_target).get(0), event_state = {}, constrain = false, min_width = 60, min_height = 60, max_width = 800, max_height = 900, resize_canvas = document.createElement('canvas'); }); resizeableImage($('.resize-image'));







, . , , . jQuery , .



var resizeableImage = function(image_target) { // ... init = function(){ // Create a new image with a copy of the original src // When resizing, we will always use this original copy as the base orig_src.src=image_target.src; // Add resize handles $(image_target).wrap('<div class="resize-container"></div>') .before('<span class="resize-handle resize-handle-nw"></span>') .before('<span class="resize-handle resize-handle-ne"></span>') .after('<span class="resize-handle resize-handle-se"></span>') .after('<span class="resize-handle resize-handle-sw"></span>'); // Get a variable for the container $container = $(image_target).parent('.resize-container'); // Add events $container.on('mousedown', '.resize-handle', startResize); }; //... init(); }







startResize



endResize



, , .



startResize = function(e){ e.preventDefault(); e.stopPropagation(); saveEventState(e); $(document).on('mousemove', resizing); $(document).on('mouseup', endResize); }; endResize = function(e){ e.preventDefault(); $(document).off('mouseup touchend', endResize); $(document).off('mousemove touchmove', resizing); };







. event_state



.



saveEventState = function(e){ // Save the initial event details and container state event_state.container_width = $container.width(); event_state.container_height = $container.height(); event_state.container_left = $container.offset().left; event_state.container_top = $container.offset().top; event_state.mouse_x = (e.clientX || e.pageX || e.originalEvent.touches[0].clientX) + $(window).scrollLeft(); event_state.mouse_y = (e.clientY || e.pageY || e.originalEvent.touches[0].clientY) + $(window).scrollTop(); // This is a fix for mobile safari // For some reason it does not allow a direct copy of the touches property if(typeof e.originalEvent.touches !== 'undefined'){ event_state.touches = []; $.each(e.originalEvent.touches, function(i, ob){ event_state.touches[i] = {}; event_state.touches[i].clientX = 0+ob.clientX; event_state.touches[i].clientY = 0+ob.clientY; }); } event_state.evnt = e; }







resizing



- . . .



resizing = function(e){ var mouse={},width,height,left,top,offset=$container.offset(); mouse.x = (e.clientX || e.pageX || e.originalEvent.touches[0].clientX) + $(window).scrollLeft(); mouse.y = (e.clientY || e.pageY || e.originalEvent.touches[0].clientY) + $(window).scrollTop(); width = mouse.x - event_state.container_left; height = mouse.y - event_state.container_top; left = event_state.container_left; top = event_state.container_top; if(constrain || e.shiftKey){ height = width / orig_src.width * orig_src.height; } if(width > min_width && height > min_height && width < max_width && height < max_height){ resizeImage(width, height); // Without this Firefox will not re-calculate the the image dimensions until drag end $container.offset({'left': left, 'top': top}); } }







Shift .



.



: , , resizeImage



.





Canvas , drawImage



. , . toDataURL



Base64-encoded .



.



resizeImage = function(width, height){ resize_canvas.width = width; resize_canvas.height = height; resize_canvas.getContext('2d').drawImage(orig_src, 0, 0, width, height); $(image_target).attr('src', resize_canvas.toDataURL("image/png")); };







? : , CORS . , 'tainted canvas'.







. . , . , .



, , .







, . resizing



:



resizing = function(e){ var mouse={},width,height,left,top,offset=$container.offset(); mouse.x = (e.clientX || e.pageX || e.originalEvent.touches[0].clientX) + $(window).scrollLeft(); mouse.y = (e.clientY || e.pageY || e.originalEvent.touches[0].clientY) + $(window).scrollTop(); // Position image differently depending on the corner dragged and constraints if( $(event_state.evnt.target).hasClass('resize-handle-se') ){ width = mouse.x - event_state.container_left; height = mouse.y - event_state.container_top; left = event_state.container_left; top = event_state.container_top; } else if($(event_state.evnt.target).hasClass('resize-handle-sw') ){ width = event_state.container_width - (mouse.x - event_state.container_left); height = mouse.y - event_state.container_top; left = mouse.x; top = event_state.container_top; } else if($(event_state.evnt.target).hasClass('resize-handle-nw') ){ width = event_state.container_width - (mouse.x - event_state.container_left); height = event_state.container_height - (mouse.y - event_state.container_top); left = mouse.x; top = mouse.y; if(constrain || e.shiftKey){ top = mouse.y - ((width / orig_src.width * orig_src.height) - height); } } else if($(event_state.evnt.target).hasClass('resize-handle-ne') ){ width = mouse.x - event_state.container_left; height = event_state.container_height - (mouse.y - event_state.container_top); left = event_state.container_left; top = mouse.y; if(constrain || e.shiftKey){ top = mouse.y - ((width / orig_src.width * orig_src.height) - height); } } // Optionally maintain aspect ratio if(constrain || e.shiftKey){ height = width / orig_src.width * orig_src.height; } if(width > min_width && height > min_height && width < max_width && height < max_height){ // To improve performance you might limit how often resizeImage() is called resizeImage(width, height); // Without this Firefox will not re-calculate the the image dimensions until drag end $container.offset({'left': left, 'top': top}); } }







, resize-handle



, .





, , , , , "". . .



init = function(){ //... $container.on('mousedown', 'img', startMoving); }







startMoving



endMoving



, startResize



endResize



.



startMoving = function(e){ e.preventDefault(); e.stopPropagation(); saveEventState(e); $(document).on('mousemove', moving); $(document).on('mouseup', endMoving); }; endMoving = function(e){ e.preventDefault(); $(document).off('mouseup', endMoving); $(document).off('mousemove', moving); };







moving



. , .



moving = function(e){ var mouse={}; e.preventDefault(); e.stopPropagation(); mouse.x = (e.clientX || e.pageX) + $(window).scrollLeft(); mouse.y = (e.clientY || e.pageY) + $(window).scrollTop(); $container.offset({ 'left': mouse.x - ( event_state.mouse_x - event_state.container_left ), 'top': mouse.y - ( event_state.mouse_y - event_state.container_top ) }); };









, , . , , , , . , , , , .



HTML :



<div class="overlay"> <div class="overlay-inner"> </div> </div> <button class="btn-crop js-crop">Crop</button>







, , .



.overlay { position: absolute; left: 50%; top: 50%; margin-left: -100px; margin-top: -100px; z-index: 999; width: 200px; height: 200px; border: solid 2px rgba(222,60,80,.9); box-sizing: content-box; pointer-events: none; } .overlay:after, .overlay:before { content: ''; position: absolute; display: block; width: 204px; height: 40px; border-left: dashed 2px rgba(222,60,80,.9); border-right: dashed 2px rgba(222,60,80,.9); } .overlay:before { top: 0; margin-left: -2px; margin-top: -40px; } .overlay:after { bottom: 0; margin-left: -2px; margin-bottom: -40px; } .overlay-inner:after, .overlay-inner:before { content: ''; position: absolute; display: block; width: 40px; height: 204px; border-top: dashed 2px rgba(222,60,80,.9); border-bottom: dashed 2px rgba(222,60,80,.9); } .overlay-inner:before { left: 0; margin-left: -40px; margin-top: -2px; } .overlay-inner:after { right: 0; margin-right: -40px; margin-top: -2px; } .btn-crop { position: absolute; vertical-align: bottom; right: 5px; bottom: 5px; padding: 6px 10px; z-index: 999; background-color: rgb(222,60,80); border: none; border-radius: 5px; color: #FFF; }







JavaScript :



init = function(){ //... $('.js-crop').on('click', crop); }; crop = function(){ var crop_canvas, left = $('.overlay').offset().left - $container.offset().left, top = $('.overlay').offset().top - $container.offset().top, width = $('.overlay').width(), height = $('.overlay').height(); crop_canvas = document.createElement('canvas'); crop_canvas.width = width; crop_canvas.height = height; crop_canvas.getContext('2d').drawImage(image_target, left, top, width, height, 0, 0, width, height); window.open(crop_canvas.toDataURL("image/png")); }







crop



resizeImage



. , .



drawImage



canvas. - . - , . - , canvas, .





. .



mousedown



mouseup



- touchstart



touchend



, mousemove



touchmove



. , touchup



touchdown



( ).



touchstart



touchend



, mousedown



, mouseup



touchmove



, mousemove



.



// In init()... $container.on('mousedown touchstart', '.resize-handle', startResize); $container.on('mousedown touchstart', 'img', startMoving); //In startResize() ... $(document).on('mousemove touchmove', moving); $(document).on('mouseup touchend', endMoving); //In endResize()... $(document).off('mouseup touchend', endMoving); $(document).off('mousemove touchmove', moving); //In startMoving()... $(document).on('mousemove touchmove', moving); $(document).on('mouseup touchend', endMoving); //In endMoving()... $(document).off('mouseup touchend', endMoving); $(document).off('mousemove touchmove', moving);







, "" . Hammer, . , , .



, , , saveEventState



. .



" " . , . moving



:



moving = function(e){ var mouse={}, touches; e.preventDefault(); e.stopPropagation(); touches = e.originalEvent.touches; mouse.x = (e.clientX || e.pageX || touches[0].clientX) + $(window).scrollLeft(); mouse.y = (e.clientY || e.pageY || touches[0].clientY) + $(window).scrollTop(); $container.offset({ 'left': mouse.x - ( event_state.mouse_x - event_state.container_left ), 'top': mouse.y - ( event_state.mouse_y - event_state.container_top ) }); // Watch for pinch zoom gesture while moving if(event_state.touches && event_state.touches.length > 1 && touches.length > 1){ var width = event_state.container_width, height = event_state.container_height; var a = event_state.touches[0].clientX - event_state.touches[1].clientX; a = a * a; var b = event_state.touches[0].clientY - event_state.touches[1].clientY; b = b * b; var dist1 = Math.sqrt( a + b ); a = e.originalEvent.touches[0].clientX - touches[1].clientX; a = a * a; b = e.originalEvent.touches[0].clientY - touches[1].clientY; b = b * b; var dist2 = Math.sqrt( a + b ); var ratio = dist2 /dist1; width = width * ratio; height = height * ratio; // To improve performance you might limit how often resizeImage() is called resizeImage(width, height); } };







.







. .



Chrome "", Firefox .



, .




  HTML5,     ,      ,   . 
      



- . , . , .



canvas




, , . , , .



. . , , . , .



!





:

<img class="resize-image" src="image.jpg" alt="Image" />







! HTML .



CSS

CSS- . resize-container



.



.resize-container { position: relative; display: inline-block; cursor: move; margin: 0 auto; } .resize-container img { display: block } .resize-container:hover img, .resize-container:active img { outline: 2px dashed rgba(222,60,80,.9); }







'resize handles'. , , .



.resize-handle-ne, .resize-handle-ne, .resize-handle-se, .resize-handle-nw, .resize-handle-sw { position: absolute; display: block; width: 10px; height: 10px; background: rgba(222,60,80,.9); z-index: 999; } .resize-handle-nw { top: -5px; left: -5px; cursor: nw-resize; } .resize-handle-sw { bottom: -5px; left: -5px; cursor: sw-resize; } .resize-handle-ne { top: -5px; right: -5px; cursor: ne-resize; } .resize-handle-se { bottom: -5px; right: -5px; cursor: se-resize; }







JavaScript

Canvas.



var resizeableImage = function(image_target) { var $container, orig_src = new Image(), image_target = $(image_target).get(0), event_state = {}, constrain = false, min_width = 60, min_height = 60, max_width = 800, max_height = 900, resize_canvas = document.createElement('canvas'); }); resizeableImage($('.resize-image'));







, . , , . jQuery , .



var resizeableImage = function(image_target) { // ... init = function(){ // Create a new image with a copy of the original src // When resizing, we will always use this original copy as the base orig_src.src=image_target.src; // Add resize handles $(image_target).wrap('<div class="resize-container"></div>') .before('<span class="resize-handle resize-handle-nw"></span>') .before('<span class="resize-handle resize-handle-ne"></span>') .after('<span class="resize-handle resize-handle-se"></span>') .after('<span class="resize-handle resize-handle-sw"></span>'); // Get a variable for the container $container = $(image_target).parent('.resize-container'); // Add events $container.on('mousedown', '.resize-handle', startResize); }; //... init(); }







startResize



endResize



, , .



startResize = function(e){ e.preventDefault(); e.stopPropagation(); saveEventState(e); $(document).on('mousemove', resizing); $(document).on('mouseup', endResize); }; endResize = function(e){ e.preventDefault(); $(document).off('mouseup touchend', endResize); $(document).off('mousemove touchmove', resizing); };







. event_state



.



saveEventState = function(e){ // Save the initial event details and container state event_state.container_width = $container.width(); event_state.container_height = $container.height(); event_state.container_left = $container.offset().left; event_state.container_top = $container.offset().top; event_state.mouse_x = (e.clientX || e.pageX || e.originalEvent.touches[0].clientX) + $(window).scrollLeft(); event_state.mouse_y = (e.clientY || e.pageY || e.originalEvent.touches[0].clientY) + $(window).scrollTop(); // This is a fix for mobile safari // For some reason it does not allow a direct copy of the touches property if(typeof e.originalEvent.touches !== 'undefined'){ event_state.touches = []; $.each(e.originalEvent.touches, function(i, ob){ event_state.touches[i] = {}; event_state.touches[i].clientX = 0+ob.clientX; event_state.touches[i].clientY = 0+ob.clientY; }); } event_state.evnt = e; }







resizing



- . . .



resizing = function(e){ var mouse={},width,height,left,top,offset=$container.offset(); mouse.x = (e.clientX || e.pageX || e.originalEvent.touches[0].clientX) + $(window).scrollLeft(); mouse.y = (e.clientY || e.pageY || e.originalEvent.touches[0].clientY) + $(window).scrollTop(); width = mouse.x - event_state.container_left; height = mouse.y - event_state.container_top; left = event_state.container_left; top = event_state.container_top; if(constrain || e.shiftKey){ height = width / orig_src.width * orig_src.height; } if(width > min_width && height > min_height && width < max_width && height < max_height){ resizeImage(width, height); // Without this Firefox will not re-calculate the the image dimensions until drag end $container.offset({'left': left, 'top': top}); } }







Shift .



.



: , , resizeImage



.





Canvas , drawImage



. , . toDataURL



Base64-encoded .



.



resizeImage = function(width, height){ resize_canvas.width = width; resize_canvas.height = height; resize_canvas.getContext('2d').drawImage(orig_src, 0, 0, width, height); $(image_target).attr('src', resize_canvas.toDataURL("image/png")); };







? : , CORS . , 'tainted canvas'.







. . , . , .



, , .







, . resizing



:



resizing = function(e){ var mouse={},width,height,left,top,offset=$container.offset(); mouse.x = (e.clientX || e.pageX || e.originalEvent.touches[0].clientX) + $(window).scrollLeft(); mouse.y = (e.clientY || e.pageY || e.originalEvent.touches[0].clientY) + $(window).scrollTop(); // Position image differently depending on the corner dragged and constraints if( $(event_state.evnt.target).hasClass('resize-handle-se') ){ width = mouse.x - event_state.container_left; height = mouse.y - event_state.container_top; left = event_state.container_left; top = event_state.container_top; } else if($(event_state.evnt.target).hasClass('resize-handle-sw') ){ width = event_state.container_width - (mouse.x - event_state.container_left); height = mouse.y - event_state.container_top; left = mouse.x; top = event_state.container_top; } else if($(event_state.evnt.target).hasClass('resize-handle-nw') ){ width = event_state.container_width - (mouse.x - event_state.container_left); height = event_state.container_height - (mouse.y - event_state.container_top); left = mouse.x; top = mouse.y; if(constrain || e.shiftKey){ top = mouse.y - ((width / orig_src.width * orig_src.height) - height); } } else if($(event_state.evnt.target).hasClass('resize-handle-ne') ){ width = mouse.x - event_state.container_left; height = event_state.container_height - (mouse.y - event_state.container_top); left = event_state.container_left; top = mouse.y; if(constrain || e.shiftKey){ top = mouse.y - ((width / orig_src.width * orig_src.height) - height); } } // Optionally maintain aspect ratio if(constrain || e.shiftKey){ height = width / orig_src.width * orig_src.height; } if(width > min_width && height > min_height && width < max_width && height < max_height){ // To improve performance you might limit how often resizeImage() is called resizeImage(width, height); // Without this Firefox will not re-calculate the the image dimensions until drag end $container.offset({'left': left, 'top': top}); } }







, resize-handle



, .





, , , , , "". . .



init = function(){ //... $container.on('mousedown', 'img', startMoving); }







startMoving



endMoving



, startResize



endResize



.



startMoving = function(e){ e.preventDefault(); e.stopPropagation(); saveEventState(e); $(document).on('mousemove', moving); $(document).on('mouseup', endMoving); }; endMoving = function(e){ e.preventDefault(); $(document).off('mouseup', endMoving); $(document).off('mousemove', moving); };







moving



. , .



moving = function(e){ var mouse={}; e.preventDefault(); e.stopPropagation(); mouse.x = (e.clientX || e.pageX) + $(window).scrollLeft(); mouse.y = (e.clientY || e.pageY) + $(window).scrollTop(); $container.offset({ 'left': mouse.x - ( event_state.mouse_x - event_state.container_left ), 'top': mouse.y - ( event_state.mouse_y - event_state.container_top ) }); };









, , . , , , , . , , , , .



HTML :



<div class="overlay"> <div class="overlay-inner"> </div> </div> <button class="btn-crop js-crop">Crop</button>







, , .



.overlay { position: absolute; left: 50%; top: 50%; margin-left: -100px; margin-top: -100px; z-index: 999; width: 200px; height: 200px; border: solid 2px rgba(222,60,80,.9); box-sizing: content-box; pointer-events: none; } .overlay:after, .overlay:before { content: ''; position: absolute; display: block; width: 204px; height: 40px; border-left: dashed 2px rgba(222,60,80,.9); border-right: dashed 2px rgba(222,60,80,.9); } .overlay:before { top: 0; margin-left: -2px; margin-top: -40px; } .overlay:after { bottom: 0; margin-left: -2px; margin-bottom: -40px; } .overlay-inner:after, .overlay-inner:before { content: ''; position: absolute; display: block; width: 40px; height: 204px; border-top: dashed 2px rgba(222,60,80,.9); border-bottom: dashed 2px rgba(222,60,80,.9); } .overlay-inner:before { left: 0; margin-left: -40px; margin-top: -2px; } .overlay-inner:after { right: 0; margin-right: -40px; margin-top: -2px; } .btn-crop { position: absolute; vertical-align: bottom; right: 5px; bottom: 5px; padding: 6px 10px; z-index: 999; background-color: rgb(222,60,80); border: none; border-radius: 5px; color: #FFF; }







JavaScript :



init = function(){ //... $('.js-crop').on('click', crop); }; crop = function(){ var crop_canvas, left = $('.overlay').offset().left - $container.offset().left, top = $('.overlay').offset().top - $container.offset().top, width = $('.overlay').width(), height = $('.overlay').height(); crop_canvas = document.createElement('canvas'); crop_canvas.width = width; crop_canvas.height = height; crop_canvas.getContext('2d').drawImage(image_target, left, top, width, height, 0, 0, width, height); window.open(crop_canvas.toDataURL("image/png")); }







crop



resizeImage



. , .



drawImage



canvas. - . - , . - , canvas, .





. .



mousedown



mouseup



- touchstart



touchend



, mousemove



touchmove



. , touchup



touchdown



( ).



touchstart



touchend



, mousedown



, mouseup



touchmove



, mousemove



.



// In init()... $container.on('mousedown touchstart', '.resize-handle', startResize); $container.on('mousedown touchstart', 'img', startMoving); //In startResize() ... $(document).on('mousemove touchmove', moving); $(document).on('mouseup touchend', endMoving); //In endResize()... $(document).off('mouseup touchend', endMoving); $(document).off('mousemove touchmove', moving); //In startMoving()... $(document).on('mousemove touchmove', moving); $(document).on('mouseup touchend', endMoving); //In endMoving()... $(document).off('mouseup touchend', endMoving); $(document).off('mousemove touchmove', moving);







, "" . Hammer, . , , .



, , , saveEventState



. .



" " . , . moving



:



moving = function(e){ var mouse={}, touches; e.preventDefault(); e.stopPropagation(); touches = e.originalEvent.touches; mouse.x = (e.clientX || e.pageX || touches[0].clientX) + $(window).scrollLeft(); mouse.y = (e.clientY || e.pageY || touches[0].clientY) + $(window).scrollTop(); $container.offset({ 'left': mouse.x - ( event_state.mouse_x - event_state.container_left ), 'top': mouse.y - ( event_state.mouse_y - event_state.container_top ) }); // Watch for pinch zoom gesture while moving if(event_state.touches && event_state.touches.length > 1 && touches.length > 1){ var width = event_state.container_width, height = event_state.container_height; var a = event_state.touches[0].clientX - event_state.touches[1].clientX; a = a * a; var b = event_state.touches[0].clientY - event_state.touches[1].clientY; b = b * b; var dist1 = Math.sqrt( a + b ); a = e.originalEvent.touches[0].clientX - touches[1].clientX; a = a * a; b = e.originalEvent.touches[0].clientY - touches[1].clientY; b = b * b; var dist2 = Math.sqrt( a + b ); var ratio = dist2 /dist1; width = width * ratio; height = height * ratio; // To improve performance you might limit how often resizeImage() is called resizeImage(width, height); } };







.







. .



Chrome "", Firefox .



, .




HTML5, , , .



- . , . , .



canvas




, , . , , .



. . , , . , .



!





:

<img class="resize-image" src="image.jpg" alt="Image" />







! HTML .



CSS

CSS- . resize-container



.



.resize-container { position: relative; display: inline-block; cursor: move; margin: 0 auto; } .resize-container img { display: block } .resize-container:hover img, .resize-container:active img { outline: 2px dashed rgba(222,60,80,.9); }







'resize handles'. , , .



.resize-handle-ne, .resize-handle-ne, .resize-handle-se, .resize-handle-nw, .resize-handle-sw { position: absolute; display: block; width: 10px; height: 10px; background: rgba(222,60,80,.9); z-index: 999; } .resize-handle-nw { top: -5px; left: -5px; cursor: nw-resize; } .resize-handle-sw { bottom: -5px; left: -5px; cursor: sw-resize; } .resize-handle-ne { top: -5px; right: -5px; cursor: ne-resize; } .resize-handle-se { bottom: -5px; right: -5px; cursor: se-resize; }







JavaScript

Canvas.



var resizeableImage = function(image_target) { var $container, orig_src = new Image(), image_target = $(image_target).get(0), event_state = {}, constrain = false, min_width = 60, min_height = 60, max_width = 800, max_height = 900, resize_canvas = document.createElement('canvas'); }); resizeableImage($('.resize-image'));







, . , , . jQuery , .



var resizeableImage = function(image_target) { // ... init = function(){ // Create a new image with a copy of the original src // When resizing, we will always use this original copy as the base orig_src.src=image_target.src; // Add resize handles $(image_target).wrap('<div class="resize-container"></div>') .before('<span class="resize-handle resize-handle-nw"></span>') .before('<span class="resize-handle resize-handle-ne"></span>') .after('<span class="resize-handle resize-handle-se"></span>') .after('<span class="resize-handle resize-handle-sw"></span>'); // Get a variable for the container $container = $(image_target).parent('.resize-container'); // Add events $container.on('mousedown', '.resize-handle', startResize); }; //... init(); }







startResize



endResize



, , .



startResize = function(e){ e.preventDefault(); e.stopPropagation(); saveEventState(e); $(document).on('mousemove', resizing); $(document).on('mouseup', endResize); }; endResize = function(e){ e.preventDefault(); $(document).off('mouseup touchend', endResize); $(document).off('mousemove touchmove', resizing); };







. event_state



.



saveEventState = function(e){ // Save the initial event details and container state event_state.container_width = $container.width(); event_state.container_height = $container.height(); event_state.container_left = $container.offset().left; event_state.container_top = $container.offset().top; event_state.mouse_x = (e.clientX || e.pageX || e.originalEvent.touches[0].clientX) + $(window).scrollLeft(); event_state.mouse_y = (e.clientY || e.pageY || e.originalEvent.touches[0].clientY) + $(window).scrollTop(); // This is a fix for mobile safari // For some reason it does not allow a direct copy of the touches property if(typeof e.originalEvent.touches !== 'undefined'){ event_state.touches = []; $.each(e.originalEvent.touches, function(i, ob){ event_state.touches[i] = {}; event_state.touches[i].clientX = 0+ob.clientX; event_state.touches[i].clientY = 0+ob.clientY; }); } event_state.evnt = e; }







resizing



- . . .



resizing = function(e){ var mouse={},width,height,left,top,offset=$container.offset(); mouse.x = (e.clientX || e.pageX || e.originalEvent.touches[0].clientX) + $(window).scrollLeft(); mouse.y = (e.clientY || e.pageY || e.originalEvent.touches[0].clientY) + $(window).scrollTop(); width = mouse.x - event_state.container_left; height = mouse.y - event_state.container_top; left = event_state.container_left; top = event_state.container_top; if(constrain || e.shiftKey){ height = width / orig_src.width * orig_src.height; } if(width > min_width && height > min_height && width < max_width && height < max_height){ resizeImage(width, height); // Without this Firefox will not re-calculate the the image dimensions until drag end $container.offset({'left': left, 'top': top}); } }







Shift .



.



: , , resizeImage



.





Canvas , drawImage



. , . toDataURL



Base64-encoded .



.



resizeImage = function(width, height){ resize_canvas.width = width; resize_canvas.height = height; resize_canvas.getContext('2d').drawImage(orig_src, 0, 0, width, height); $(image_target).attr('src', resize_canvas.toDataURL("image/png")); };







? : , CORS . , 'tainted canvas'.







. . , . , .



, , .







, . resizing



:



resizing = function(e){ var mouse={},width,height,left,top,offset=$container.offset(); mouse.x = (e.clientX || e.pageX || e.originalEvent.touches[0].clientX) + $(window).scrollLeft(); mouse.y = (e.clientY || e.pageY || e.originalEvent.touches[0].clientY) + $(window).scrollTop(); // Position image differently depending on the corner dragged and constraints if( $(event_state.evnt.target).hasClass('resize-handle-se') ){ width = mouse.x - event_state.container_left; height = mouse.y - event_state.container_top; left = event_state.container_left; top = event_state.container_top; } else if($(event_state.evnt.target).hasClass('resize-handle-sw') ){ width = event_state.container_width - (mouse.x - event_state.container_left); height = mouse.y - event_state.container_top; left = mouse.x; top = event_state.container_top; } else if($(event_state.evnt.target).hasClass('resize-handle-nw') ){ width = event_state.container_width - (mouse.x - event_state.container_left); height = event_state.container_height - (mouse.y - event_state.container_top); left = mouse.x; top = mouse.y; if(constrain || e.shiftKey){ top = mouse.y - ((width / orig_src.width * orig_src.height) - height); } } else if($(event_state.evnt.target).hasClass('resize-handle-ne') ){ width = mouse.x - event_state.container_left; height = event_state.container_height - (mouse.y - event_state.container_top); left = event_state.container_left; top = mouse.y; if(constrain || e.shiftKey){ top = mouse.y - ((width / orig_src.width * orig_src.height) - height); } } // Optionally maintain aspect ratio if(constrain || e.shiftKey){ height = width / orig_src.width * orig_src.height; } if(width > min_width && height > min_height && width < max_width && height < max_height){ // To improve performance you might limit how often resizeImage() is called resizeImage(width, height); // Without this Firefox will not re-calculate the the image dimensions until drag end $container.offset({'left': left, 'top': top}); } }







, resize-handle



, .





, , , , , "". . .



init = function(){ //... $container.on('mousedown', 'img', startMoving); }







startMoving



endMoving



, startResize



endResize



.



startMoving = function(e){ e.preventDefault(); e.stopPropagation(); saveEventState(e); $(document).on('mousemove', moving); $(document).on('mouseup', endMoving); }; endMoving = function(e){ e.preventDefault(); $(document).off('mouseup', endMoving); $(document).off('mousemove', moving); };







moving



. , .



moving = function(e){ var mouse={}; e.preventDefault(); e.stopPropagation(); mouse.x = (e.clientX || e.pageX) + $(window).scrollLeft(); mouse.y = (e.clientY || e.pageY) + $(window).scrollTop(); $container.offset({ 'left': mouse.x - ( event_state.mouse_x - event_state.container_left ), 'top': mouse.y - ( event_state.mouse_y - event_state.container_top ) }); };









, , . , , , , . , , , , .



HTML :



<div class="overlay"> <div class="overlay-inner"> </div> </div> <button class="btn-crop js-crop">Crop</button>







, , .



.overlay { position: absolute; left: 50%; top: 50%; margin-left: -100px; margin-top: -100px; z-index: 999; width: 200px; height: 200px; border: solid 2px rgba(222,60,80,.9); box-sizing: content-box; pointer-events: none; } .overlay:after, .overlay:before { content: ''; position: absolute; display: block; width: 204px; height: 40px; border-left: dashed 2px rgba(222,60,80,.9); border-right: dashed 2px rgba(222,60,80,.9); } .overlay:before { top: 0; margin-left: -2px; margin-top: -40px; } .overlay:after { bottom: 0; margin-left: -2px; margin-bottom: -40px; } .overlay-inner:after, .overlay-inner:before { content: ''; position: absolute; display: block; width: 40px; height: 204px; border-top: dashed 2px rgba(222,60,80,.9); border-bottom: dashed 2px rgba(222,60,80,.9); } .overlay-inner:before { left: 0; margin-left: -40px; margin-top: -2px; } .overlay-inner:after { right: 0; margin-right: -40px; margin-top: -2px; } .btn-crop { position: absolute; vertical-align: bottom; right: 5px; bottom: 5px; padding: 6px 10px; z-index: 999; background-color: rgb(222,60,80); border: none; border-radius: 5px; color: #FFF; }







JavaScript :



init = function(){ //... $('.js-crop').on('click', crop); }; crop = function(){ var crop_canvas, left = $('.overlay').offset().left - $container.offset().left, top = $('.overlay').offset().top - $container.offset().top, width = $('.overlay').width(), height = $('.overlay').height(); crop_canvas = document.createElement('canvas'); crop_canvas.width = width; crop_canvas.height = height; crop_canvas.getContext('2d').drawImage(image_target, left, top, width, height, 0, 0, width, height); window.open(crop_canvas.toDataURL("image/png")); }







crop



resizeImage



. , .



drawImage



canvas. - . - , . - , canvas, .





. .



mousedown



mouseup



- touchstart



touchend



, mousemove



touchmove



. , touchup



touchdown



( ).



touchstart



touchend



, mousedown



, mouseup



touchmove



, mousemove



.



// In init()... $container.on('mousedown touchstart', '.resize-handle', startResize); $container.on('mousedown touchstart', 'img', startMoving); //In startResize() ... $(document).on('mousemove touchmove', moving); $(document).on('mouseup touchend', endMoving); //In endResize()... $(document).off('mouseup touchend', endMoving); $(document).off('mousemove touchmove', moving); //In startMoving()... $(document).on('mousemove touchmove', moving); $(document).on('mouseup touchend', endMoving); //In endMoving()... $(document).off('mouseup touchend', endMoving); $(document).off('mousemove touchmove', moving);







, "" . Hammer, . , , .



, , , saveEventState



. .



" " . , . moving



:



moving = function(e){ var mouse={}, touches; e.preventDefault(); e.stopPropagation(); touches = e.originalEvent.touches; mouse.x = (e.clientX || e.pageX || touches[0].clientX) + $(window).scrollLeft(); mouse.y = (e.clientY || e.pageY || touches[0].clientY) + $(window).scrollTop(); $container.offset({ 'left': mouse.x - ( event_state.mouse_x - event_state.container_left ), 'top': mouse.y - ( event_state.mouse_y - event_state.container_top ) }); // Watch for pinch zoom gesture while moving if(event_state.touches && event_state.touches.length > 1 && touches.length > 1){ var width = event_state.container_width, height = event_state.container_height; var a = event_state.touches[0].clientX - event_state.touches[1].clientX; a = a * a; var b = event_state.touches[0].clientY - event_state.touches[1].clientY; b = b * b; var dist1 = Math.sqrt( a + b ); a = e.originalEvent.touches[0].clientX - touches[1].clientX; a = a * a; b = e.originalEvent.touches[0].clientY - touches[1].clientY; b = b * b; var dist2 = Math.sqrt( a + b ); var ratio = dist2 /dist1; width = width * ratio; height = height * ratio; // To improve performance you might limit how often resizeImage() is called resizeImage(width, height); } };







.







. .



Chrome "", Firefox .



, .




HTML5, , , .



- . , . , .



canvas




, , . , , .



. . , , . , .



!





:

<img class="resize-image" src="image.jpg" alt="Image" />







! HTML .



CSS

CSS- . resize-container



.



.resize-container { position: relative; display: inline-block; cursor: move; margin: 0 auto; } .resize-container img { display: block } .resize-container:hover img, .resize-container:active img { outline: 2px dashed rgba(222,60,80,.9); }







'resize handles'. , , .



.resize-handle-ne, .resize-handle-ne, .resize-handle-se, .resize-handle-nw, .resize-handle-sw { position: absolute; display: block; width: 10px; height: 10px; background: rgba(222,60,80,.9); z-index: 999; } .resize-handle-nw { top: -5px; left: -5px; cursor: nw-resize; } .resize-handle-sw { bottom: -5px; left: -5px; cursor: sw-resize; } .resize-handle-ne { top: -5px; right: -5px; cursor: ne-resize; } .resize-handle-se { bottom: -5px; right: -5px; cursor: se-resize; }







JavaScript

Canvas.



var resizeableImage = function(image_target) { var $container, orig_src = new Image(), image_target = $(image_target).get(0), event_state = {}, constrain = false, min_width = 60, min_height = 60, max_width = 800, max_height = 900, resize_canvas = document.createElement('canvas'); }); resizeableImage($('.resize-image'));







, . , , . jQuery , .



var resizeableImage = function(image_target) { // ... init = function(){ // Create a new image with a copy of the original src // When resizing, we will always use this original copy as the base orig_src.src=image_target.src; // Add resize handles $(image_target).wrap('<div class="resize-container"></div>') .before('<span class="resize-handle resize-handle-nw"></span>') .before('<span class="resize-handle resize-handle-ne"></span>') .after('<span class="resize-handle resize-handle-se"></span>') .after('<span class="resize-handle resize-handle-sw"></span>'); // Get a variable for the container $container = $(image_target).parent('.resize-container'); // Add events $container.on('mousedown', '.resize-handle', startResize); }; //... init(); }







startResize



endResize



, , .



startResize = function(e){ e.preventDefault(); e.stopPropagation(); saveEventState(e); $(document).on('mousemove', resizing); $(document).on('mouseup', endResize); }; endResize = function(e){ e.preventDefault(); $(document).off('mouseup touchend', endResize); $(document).off('mousemove touchmove', resizing); };







. event_state



.



saveEventState = function(e){ // Save the initial event details and container state event_state.container_width = $container.width(); event_state.container_height = $container.height(); event_state.container_left = $container.offset().left; event_state.container_top = $container.offset().top; event_state.mouse_x = (e.clientX || e.pageX || e.originalEvent.touches[0].clientX) + $(window).scrollLeft(); event_state.mouse_y = (e.clientY || e.pageY || e.originalEvent.touches[0].clientY) + $(window).scrollTop(); // This is a fix for mobile safari // For some reason it does not allow a direct copy of the touches property if(typeof e.originalEvent.touches !== 'undefined'){ event_state.touches = []; $.each(e.originalEvent.touches, function(i, ob){ event_state.touches[i] = {}; event_state.touches[i].clientX = 0+ob.clientX; event_state.touches[i].clientY = 0+ob.clientY; }); } event_state.evnt = e; }







resizing



- . . .



resizing = function(e){ var mouse={},width,height,left,top,offset=$container.offset(); mouse.x = (e.clientX || e.pageX || e.originalEvent.touches[0].clientX) + $(window).scrollLeft(); mouse.y = (e.clientY || e.pageY || e.originalEvent.touches[0].clientY) + $(window).scrollTop(); width = mouse.x - event_state.container_left; height = mouse.y - event_state.container_top; left = event_state.container_left; top = event_state.container_top; if(constrain || e.shiftKey){ height = width / orig_src.width * orig_src.height; } if(width > min_width && height > min_height && width < max_width && height < max_height){ resizeImage(width, height); // Without this Firefox will not re-calculate the the image dimensions until drag end $container.offset({'left': left, 'top': top}); } }







Shift .



.



: , , resizeImage



.





Canvas , drawImage



. , . toDataURL



Base64-encoded .



.



resizeImage = function(width, height){ resize_canvas.width = width; resize_canvas.height = height; resize_canvas.getContext('2d').drawImage(orig_src, 0, 0, width, height); $(image_target).attr('src', resize_canvas.toDataURL("image/png")); };







? : , CORS . , 'tainted canvas'.







. . , . , .



, , .







, . resizing



:



resizing = function(e){ var mouse={},width,height,left,top,offset=$container.offset(); mouse.x = (e.clientX || e.pageX || e.originalEvent.touches[0].clientX) + $(window).scrollLeft(); mouse.y = (e.clientY || e.pageY || e.originalEvent.touches[0].clientY) + $(window).scrollTop(); // Position image differently depending on the corner dragged and constraints if( $(event_state.evnt.target).hasClass('resize-handle-se') ){ width = mouse.x - event_state.container_left; height = mouse.y - event_state.container_top; left = event_state.container_left; top = event_state.container_top; } else if($(event_state.evnt.target).hasClass('resize-handle-sw') ){ width = event_state.container_width - (mouse.x - event_state.container_left); height = mouse.y - event_state.container_top; left = mouse.x; top = event_state.container_top; } else if($(event_state.evnt.target).hasClass('resize-handle-nw') ){ width = event_state.container_width - (mouse.x - event_state.container_left); height = event_state.container_height - (mouse.y - event_state.container_top); left = mouse.x; top = mouse.y; if(constrain || e.shiftKey){ top = mouse.y - ((width / orig_src.width * orig_src.height) - height); } } else if($(event_state.evnt.target).hasClass('resize-handle-ne') ){ width = mouse.x - event_state.container_left; height = event_state.container_height - (mouse.y - event_state.container_top); left = event_state.container_left; top = mouse.y; if(constrain || e.shiftKey){ top = mouse.y - ((width / orig_src.width * orig_src.height) - height); } } // Optionally maintain aspect ratio if(constrain || e.shiftKey){ height = width / orig_src.width * orig_src.height; } if(width > min_width && height > min_height && width < max_width && height < max_height){ // To improve performance you might limit how often resizeImage() is called resizeImage(width, height); // Without this Firefox will not re-calculate the the image dimensions until drag end $container.offset({'left': left, 'top': top}); } }







, resize-handle



, .





, , , , , "". . .



init = function(){ //... $container.on('mousedown', 'img', startMoving); }







startMoving



endMoving



, startResize



endResize



.



startMoving = function(e){ e.preventDefault(); e.stopPropagation(); saveEventState(e); $(document).on('mousemove', moving); $(document).on('mouseup', endMoving); }; endMoving = function(e){ e.preventDefault(); $(document).off('mouseup', endMoving); $(document).off('mousemove', moving); };







moving



. , .



moving = function(e){ var mouse={}; e.preventDefault(); e.stopPropagation(); mouse.x = (e.clientX || e.pageX) + $(window).scrollLeft(); mouse.y = (e.clientY || e.pageY) + $(window).scrollTop(); $container.offset({ 'left': mouse.x - ( event_state.mouse_x - event_state.container_left ), 'top': mouse.y - ( event_state.mouse_y - event_state.container_top ) }); };









, , . , , , , . , , , , .



HTML :



<div class="overlay"> <div class="overlay-inner"> </div> </div> <button class="btn-crop js-crop">Crop</button>







, , .



.overlay { position: absolute; left: 50%; top: 50%; margin-left: -100px; margin-top: -100px; z-index: 999; width: 200px; height: 200px; border: solid 2px rgba(222,60,80,.9); box-sizing: content-box; pointer-events: none; } .overlay:after, .overlay:before { content: ''; position: absolute; display: block; width: 204px; height: 40px; border-left: dashed 2px rgba(222,60,80,.9); border-right: dashed 2px rgba(222,60,80,.9); } .overlay:before { top: 0; margin-left: -2px; margin-top: -40px; } .overlay:after { bottom: 0; margin-left: -2px; margin-bottom: -40px; } .overlay-inner:after, .overlay-inner:before { content: ''; position: absolute; display: block; width: 40px; height: 204px; border-top: dashed 2px rgba(222,60,80,.9); border-bottom: dashed 2px rgba(222,60,80,.9); } .overlay-inner:before { left: 0; margin-left: -40px; margin-top: -2px; } .overlay-inner:after { right: 0; margin-right: -40px; margin-top: -2px; } .btn-crop { position: absolute; vertical-align: bottom; right: 5px; bottom: 5px; padding: 6px 10px; z-index: 999; background-color: rgb(222,60,80); border: none; border-radius: 5px; color: #FFF; }







JavaScript :



init = function(){ //... $('.js-crop').on('click', crop); }; crop = function(){ var crop_canvas, left = $('.overlay').offset().left - $container.offset().left, top = $('.overlay').offset().top - $container.offset().top, width = $('.overlay').width(), height = $('.overlay').height(); crop_canvas = document.createElement('canvas'); crop_canvas.width = width; crop_canvas.height = height; crop_canvas.getContext('2d').drawImage(image_target, left, top, width, height, 0, 0, width, height); window.open(crop_canvas.toDataURL("image/png")); }







crop



resizeImage



. , .



drawImage



canvas. - . - , . - , canvas, .





. .



mousedown



mouseup



- touchstart



touchend



, mousemove



touchmove



. , touchup



touchdown



( ).



touchstart



touchend



, mousedown



, mouseup



touchmove



, mousemove



.



// In init()... $container.on('mousedown touchstart', '.resize-handle', startResize); $container.on('mousedown touchstart', 'img', startMoving); //In startResize() ... $(document).on('mousemove touchmove', moving); $(document).on('mouseup touchend', endMoving); //In endResize()... $(document).off('mouseup touchend', endMoving); $(document).off('mousemove touchmove', moving); //In startMoving()... $(document).on('mousemove touchmove', moving); $(document).on('mouseup touchend', endMoving); //In endMoving()... $(document).off('mouseup touchend', endMoving); $(document).off('mousemove touchmove', moving);







, "" . Hammer, . , , .



, , , saveEventState



. .



" " . , . moving



:



moving = function(e){ var mouse={}, touches; e.preventDefault(); e.stopPropagation(); touches = e.originalEvent.touches; mouse.x = (e.clientX || e.pageX || touches[0].clientX) + $(window).scrollLeft(); mouse.y = (e.clientY || e.pageY || touches[0].clientY) + $(window).scrollTop(); $container.offset({ 'left': mouse.x - ( event_state.mouse_x - event_state.container_left ), 'top': mouse.y - ( event_state.mouse_y - event_state.container_top ) }); // Watch for pinch zoom gesture while moving if(event_state.touches && event_state.touches.length > 1 && touches.length > 1){ var width = event_state.container_width, height = event_state.container_height; var a = event_state.touches[0].clientX - event_state.touches[1].clientX; a = a * a; var b = event_state.touches[0].clientY - event_state.touches[1].clientY; b = b * b; var dist1 = Math.sqrt( a + b ); a = e.originalEvent.touches[0].clientX - touches[1].clientX; a = a * a; b = e.originalEvent.touches[0].clientY - touches[1].clientY; b = b * b; var dist2 = Math.sqrt( a + b ); var ratio = dist2 /dist1; width = width * ratio; height = height * ratio; // To improve performance you might limit how often resizeImage() is called resizeImage(width, height); } };







.







. .



Chrome "", Firefox .



, .




HTML5, , , .



- . , . , .



canvas




, , . , , .



. . , , . , .



!





:

<img class="resize-image" src="image.jpg" alt="Image" />







! HTML .



CSS

CSS- . resize-container



.



.resize-container { position: relative; display: inline-block; cursor: move; margin: 0 auto; } .resize-container img { display: block } .resize-container:hover img, .resize-container:active img { outline: 2px dashed rgba(222,60,80,.9); }







'resize handles'. , , .



.resize-handle-ne, .resize-handle-ne, .resize-handle-se, .resize-handle-nw, .resize-handle-sw { position: absolute; display: block; width: 10px; height: 10px; background: rgba(222,60,80,.9); z-index: 999; } .resize-handle-nw { top: -5px; left: -5px; cursor: nw-resize; } .resize-handle-sw { bottom: -5px; left: -5px; cursor: sw-resize; } .resize-handle-ne { top: -5px; right: -5px; cursor: ne-resize; } .resize-handle-se { bottom: -5px; right: -5px; cursor: se-resize; }







JavaScript

Canvas.



var resizeableImage = function(image_target) { var $container, orig_src = new Image(), image_target = $(image_target).get(0), event_state = {}, constrain = false, min_width = 60, min_height = 60, max_width = 800, max_height = 900, resize_canvas = document.createElement('canvas'); }); resizeableImage($('.resize-image'));







, . , , . jQuery , .



var resizeableImage = function(image_target) { // ... init = function(){ // Create a new image with a copy of the original src // When resizing, we will always use this original copy as the base orig_src.src=image_target.src; // Add resize handles $(image_target).wrap('<div class="resize-container"></div>') .before('<span class="resize-handle resize-handle-nw"></span>') .before('<span class="resize-handle resize-handle-ne"></span>') .after('<span class="resize-handle resize-handle-se"></span>') .after('<span class="resize-handle resize-handle-sw"></span>'); // Get a variable for the container $container = $(image_target).parent('.resize-container'); // Add events $container.on('mousedown', '.resize-handle', startResize); }; //... init(); }







startResize



endResize



, , .



startResize = function(e){ e.preventDefault(); e.stopPropagation(); saveEventState(e); $(document).on('mousemove', resizing); $(document).on('mouseup', endResize); }; endResize = function(e){ e.preventDefault(); $(document).off('mouseup touchend', endResize); $(document).off('mousemove touchmove', resizing); };







. event_state



.



saveEventState = function(e){ // Save the initial event details and container state event_state.container_width = $container.width(); event_state.container_height = $container.height(); event_state.container_left = $container.offset().left; event_state.container_top = $container.offset().top; event_state.mouse_x = (e.clientX || e.pageX || e.originalEvent.touches[0].clientX) + $(window).scrollLeft(); event_state.mouse_y = (e.clientY || e.pageY || e.originalEvent.touches[0].clientY) + $(window).scrollTop(); // This is a fix for mobile safari // For some reason it does not allow a direct copy of the touches property if(typeof e.originalEvent.touches !== 'undefined'){ event_state.touches = []; $.each(e.originalEvent.touches, function(i, ob){ event_state.touches[i] = {}; event_state.touches[i].clientX = 0+ob.clientX; event_state.touches[i].clientY = 0+ob.clientY; }); } event_state.evnt = e; }







resizing



- . . .



resizing = function(e){ var mouse={},width,height,left,top,offset=$container.offset(); mouse.x = (e.clientX || e.pageX || e.originalEvent.touches[0].clientX) + $(window).scrollLeft(); mouse.y = (e.clientY || e.pageY || e.originalEvent.touches[0].clientY) + $(window).scrollTop(); width = mouse.x - event_state.container_left; height = mouse.y - event_state.container_top; left = event_state.container_left; top = event_state.container_top; if(constrain || e.shiftKey){ height = width / orig_src.width * orig_src.height; } if(width > min_width && height > min_height && width < max_width && height < max_height){ resizeImage(width, height); // Without this Firefox will not re-calculate the the image dimensions until drag end $container.offset({'left': left, 'top': top}); } }







Shift .



.



: , , resizeImage



.





Canvas , drawImage



. , . toDataURL



Base64-encoded .



.



resizeImage = function(width, height){ resize_canvas.width = width; resize_canvas.height = height; resize_canvas.getContext('2d').drawImage(orig_src, 0, 0, width, height); $(image_target).attr('src', resize_canvas.toDataURL("image/png")); };







? : , CORS . , 'tainted canvas'.







. . , . , .



, , .







, . resizing



:



resizing = function(e){ var mouse={},width,height,left,top,offset=$container.offset(); mouse.x = (e.clientX || e.pageX || e.originalEvent.touches[0].clientX) + $(window).scrollLeft(); mouse.y = (e.clientY || e.pageY || e.originalEvent.touches[0].clientY) + $(window).scrollTop(); // Position image differently depending on the corner dragged and constraints if( $(event_state.evnt.target).hasClass('resize-handle-se') ){ width = mouse.x - event_state.container_left; height = mouse.y - event_state.container_top; left = event_state.container_left; top = event_state.container_top; } else if($(event_state.evnt.target).hasClass('resize-handle-sw') ){ width = event_state.container_width - (mouse.x - event_state.container_left); height = mouse.y - event_state.container_top; left = mouse.x; top = event_state.container_top; } else if($(event_state.evnt.target).hasClass('resize-handle-nw') ){ width = event_state.container_width - (mouse.x - event_state.container_left); height = event_state.container_height - (mouse.y - event_state.container_top); left = mouse.x; top = mouse.y; if(constrain || e.shiftKey){ top = mouse.y - ((width / orig_src.width * orig_src.height) - height); } } else if($(event_state.evnt.target).hasClass('resize-handle-ne') ){ width = mouse.x - event_state.container_left; height = event_state.container_height - (mouse.y - event_state.container_top); left = event_state.container_left; top = mouse.y; if(constrain || e.shiftKey){ top = mouse.y - ((width / orig_src.width * orig_src.height) - height); } } // Optionally maintain aspect ratio if(constrain || e.shiftKey){ height = width / orig_src.width * orig_src.height; } if(width > min_width && height > min_height && width < max_width && height < max_height){ // To improve performance you might limit how often resizeImage() is called resizeImage(width, height); // Without this Firefox will not re-calculate the the image dimensions until drag end $container.offset({'left': left, 'top': top}); } }







, resize-handle



, .





, , , , , "". . .



init = function(){ //... $container.on('mousedown', 'img', startMoving); }







startMoving



endMoving



, startResize



endResize



.



startMoving = function(e){ e.preventDefault(); e.stopPropagation(); saveEventState(e); $(document).on('mousemove', moving); $(document).on('mouseup', endMoving); }; endMoving = function(e){ e.preventDefault(); $(document).off('mouseup', endMoving); $(document).off('mousemove', moving); };







moving



. , .



moving = function(e){ var mouse={}; e.preventDefault(); e.stopPropagation(); mouse.x = (e.clientX || e.pageX) + $(window).scrollLeft(); mouse.y = (e.clientY || e.pageY) + $(window).scrollTop(); $container.offset({ 'left': mouse.x - ( event_state.mouse_x - event_state.container_left ), 'top': mouse.y - ( event_state.mouse_y - event_state.container_top ) }); };









, , . , , , , . , , , , .



HTML :



<div class="overlay"> <div class="overlay-inner"> </div> </div> <button class="btn-crop js-crop">Crop</button>







, , .



.overlay { position: absolute; left: 50%; top: 50%; margin-left: -100px; margin-top: -100px; z-index: 999; width: 200px; height: 200px; border: solid 2px rgba(222,60,80,.9); box-sizing: content-box; pointer-events: none; } .overlay:after, .overlay:before { content: ''; position: absolute; display: block; width: 204px; height: 40px; border-left: dashed 2px rgba(222,60,80,.9); border-right: dashed 2px rgba(222,60,80,.9); } .overlay:before { top: 0; margin-left: -2px; margin-top: -40px; } .overlay:after { bottom: 0; margin-left: -2px; margin-bottom: -40px; } .overlay-inner:after, .overlay-inner:before { content: ''; position: absolute; display: block; width: 40px; height: 204px; border-top: dashed 2px rgba(222,60,80,.9); border-bottom: dashed 2px rgba(222,60,80,.9); } .overlay-inner:before { left: 0; margin-left: -40px; margin-top: -2px; } .overlay-inner:after { right: 0; margin-right: -40px; margin-top: -2px; } .btn-crop { position: absolute; vertical-align: bottom; right: 5px; bottom: 5px; padding: 6px 10px; z-index: 999; background-color: rgb(222,60,80); border: none; border-radius: 5px; color: #FFF; }







JavaScript :



init = function(){ //... $('.js-crop').on('click', crop); }; crop = function(){ var crop_canvas, left = $('.overlay').offset().left - $container.offset().left, top = $('.overlay').offset().top - $container.offset().top, width = $('.overlay').width(), height = $('.overlay').height(); crop_canvas = document.createElement('canvas'); crop_canvas.width = width; crop_canvas.height = height; crop_canvas.getContext('2d').drawImage(image_target, left, top, width, height, 0, 0, width, height); window.open(crop_canvas.toDataURL("image/png")); }







crop



resizeImage



. , .



drawImage



canvas. - . - , . - , canvas, .





. .



mousedown



mouseup



- touchstart



touchend



, mousemove



touchmove



. , touchup



touchdown



( ).



touchstart



touchend



, mousedown



, mouseup



touchmove



, mousemove



.



// In init()... $container.on('mousedown touchstart', '.resize-handle', startResize); $container.on('mousedown touchstart', 'img', startMoving); //In startResize() ... $(document).on('mousemove touchmove', moving); $(document).on('mouseup touchend', endMoving); //In endResize()... $(document).off('mouseup touchend', endMoving); $(document).off('mousemove touchmove', moving); //In startMoving()... $(document).on('mousemove touchmove', moving); $(document).on('mouseup touchend', endMoving); //In endMoving()... $(document).off('mouseup touchend', endMoving); $(document).off('mousemove touchmove', moving);







, "" . Hammer, . , , .



, , , saveEventState



. .



" " . , . moving



:



moving = function(e){ var mouse={}, touches; e.preventDefault(); e.stopPropagation(); touches = e.originalEvent.touches; mouse.x = (e.clientX || e.pageX || touches[0].clientX) + $(window).scrollLeft(); mouse.y = (e.clientY || e.pageY || touches[0].clientY) + $(window).scrollTop(); $container.offset({ 'left': mouse.x - ( event_state.mouse_x - event_state.container_left ), 'top': mouse.y - ( event_state.mouse_y - event_state.container_top ) }); // Watch for pinch zoom gesture while moving if(event_state.touches && event_state.touches.length > 1 && touches.length > 1){ var width = event_state.container_width, height = event_state.container_height; var a = event_state.touches[0].clientX - event_state.touches[1].clientX; a = a * a; var b = event_state.touches[0].clientY - event_state.touches[1].clientY; b = b * b; var dist1 = Math.sqrt( a + b ); a = e.originalEvent.touches[0].clientX - touches[1].clientX; a = a * a; b = e.originalEvent.touches[0].clientY - touches[1].clientY; b = b * b; var dist2 = Math.sqrt( a + b ); var ratio = dist2 /dist1; width = width * ratio; height = height * ratio; // To improve performance you might limit how often resizeImage() is called resizeImage(width, height); } };







.







. .



Chrome "", Firefox .



, .




  HTML5,     ,      ,   . 
      



- . , . , .



canvas




, , . , , .



. . , , . , .



!





:

<img class="resize-image" src="image.jpg" alt="Image" />







! HTML .



CSS

CSS- . resize-container



.



.resize-container { position: relative; display: inline-block; cursor: move; margin: 0 auto; } .resize-container img { display: block } .resize-container:hover img, .resize-container:active img { outline: 2px dashed rgba(222,60,80,.9); }







'resize handles'. , , .



.resize-handle-ne, .resize-handle-ne, .resize-handle-se, .resize-handle-nw, .resize-handle-sw { position: absolute; display: block; width: 10px; height: 10px; background: rgba(222,60,80,.9); z-index: 999; } .resize-handle-nw { top: -5px; left: -5px; cursor: nw-resize; } .resize-handle-sw { bottom: -5px; left: -5px; cursor: sw-resize; } .resize-handle-ne { top: -5px; right: -5px; cursor: ne-resize; } .resize-handle-se { bottom: -5px; right: -5px; cursor: se-resize; }







JavaScript

Canvas.



var resizeableImage = function(image_target) { var $container, orig_src = new Image(), image_target = $(image_target).get(0), event_state = {}, constrain = false, min_width = 60, min_height = 60, max_width = 800, max_height = 900, resize_canvas = document.createElement('canvas'); }); resizeableImage($('.resize-image'));







, . , , . jQuery , .



var resizeableImage = function(image_target) { // ... init = function(){ // Create a new image with a copy of the original src // When resizing, we will always use this original copy as the base orig_src.src=image_target.src; // Add resize handles $(image_target).wrap('<div class="resize-container"></div>') .before('<span class="resize-handle resize-handle-nw"></span>') .before('<span class="resize-handle resize-handle-ne"></span>') .after('<span class="resize-handle resize-handle-se"></span>') .after('<span class="resize-handle resize-handle-sw"></span>'); // Get a variable for the container $container = $(image_target).parent('.resize-container'); // Add events $container.on('mousedown', '.resize-handle', startResize); }; //... init(); }







startResize



endResize



, , .



startResize = function(e){ e.preventDefault(); e.stopPropagation(); saveEventState(e); $(document).on('mousemove', resizing); $(document).on('mouseup', endResize); }; endResize = function(e){ e.preventDefault(); $(document).off('mouseup touchend', endResize); $(document).off('mousemove touchmove', resizing); };







. event_state



.



saveEventState = function(e){ // Save the initial event details and container state event_state.container_width = $container.width(); event_state.container_height = $container.height(); event_state.container_left = $container.offset().left; event_state.container_top = $container.offset().top; event_state.mouse_x = (e.clientX || e.pageX || e.originalEvent.touches[0].clientX) + $(window).scrollLeft(); event_state.mouse_y = (e.clientY || e.pageY || e.originalEvent.touches[0].clientY) + $(window).scrollTop(); // This is a fix for mobile safari // For some reason it does not allow a direct copy of the touches property if(typeof e.originalEvent.touches !== 'undefined'){ event_state.touches = []; $.each(e.originalEvent.touches, function(i, ob){ event_state.touches[i] = {}; event_state.touches[i].clientX = 0+ob.clientX; event_state.touches[i].clientY = 0+ob.clientY; }); } event_state.evnt = e; }







resizing



- . . .



resizing = function(e){ var mouse={},width,height,left,top,offset=$container.offset(); mouse.x = (e.clientX || e.pageX || e.originalEvent.touches[0].clientX) + $(window).scrollLeft(); mouse.y = (e.clientY || e.pageY || e.originalEvent.touches[0].clientY) + $(window).scrollTop(); width = mouse.x - event_state.container_left; height = mouse.y - event_state.container_top; left = event_state.container_left; top = event_state.container_top; if(constrain || e.shiftKey){ height = width / orig_src.width * orig_src.height; } if(width > min_width && height > min_height && width < max_width && height < max_height){ resizeImage(width, height); // Without this Firefox will not re-calculate the the image dimensions until drag end $container.offset({'left': left, 'top': top}); } }







Shift .



.



: , , resizeImage



.





Canvas , drawImage



. , . toDataURL



Base64-encoded .



.



resizeImage = function(width, height){ resize_canvas.width = width; resize_canvas.height = height; resize_canvas.getContext('2d').drawImage(orig_src, 0, 0, width, height); $(image_target).attr('src', resize_canvas.toDataURL("image/png")); };







? : , CORS . , 'tainted canvas'.







. . , . , .



, , .







, . resizing



:



resizing = function(e){ var mouse={},width,height,left,top,offset=$container.offset(); mouse.x = (e.clientX || e.pageX || e.originalEvent.touches[0].clientX) + $(window).scrollLeft(); mouse.y = (e.clientY || e.pageY || e.originalEvent.touches[0].clientY) + $(window).scrollTop(); // Position image differently depending on the corner dragged and constraints if( $(event_state.evnt.target).hasClass('resize-handle-se') ){ width = mouse.x - event_state.container_left; height = mouse.y - event_state.container_top; left = event_state.container_left; top = event_state.container_top; } else if($(event_state.evnt.target).hasClass('resize-handle-sw') ){ width = event_state.container_width - (mouse.x - event_state.container_left); height = mouse.y - event_state.container_top; left = mouse.x; top = event_state.container_top; } else if($(event_state.evnt.target).hasClass('resize-handle-nw') ){ width = event_state.container_width - (mouse.x - event_state.container_left); height = event_state.container_height - (mouse.y - event_state.container_top); left = mouse.x; top = mouse.y; if(constrain || e.shiftKey){ top = mouse.y - ((width / orig_src.width * orig_src.height) - height); } } else if($(event_state.evnt.target).hasClass('resize-handle-ne') ){ width = mouse.x - event_state.container_left; height = event_state.container_height - (mouse.y - event_state.container_top); left = event_state.container_left; top = mouse.y; if(constrain || e.shiftKey){ top = mouse.y - ((width / orig_src.width * orig_src.height) - height); } } // Optionally maintain aspect ratio if(constrain || e.shiftKey){ height = width / orig_src.width * orig_src.height; } if(width > min_width && height > min_height && width < max_width && height < max_height){ // To improve performance you might limit how often resizeImage() is called resizeImage(width, height); // Without this Firefox will not re-calculate the the image dimensions until drag end $container.offset({'left': left, 'top': top}); } }







, resize-handle



, .





, , , , , "". . .



init = function(){ //... $container.on('mousedown', 'img', startMoving); }







startMoving



endMoving



, startResize



endResize



.



startMoving = function(e){ e.preventDefault(); e.stopPropagation(); saveEventState(e); $(document).on('mousemove', moving); $(document).on('mouseup', endMoving); }; endMoving = function(e){ e.preventDefault(); $(document).off('mouseup', endMoving); $(document).off('mousemove', moving); };







moving



. , .



moving = function(e){ var mouse={}; e.preventDefault(); e.stopPropagation(); mouse.x = (e.clientX || e.pageX) + $(window).scrollLeft(); mouse.y = (e.clientY || e.pageY) + $(window).scrollTop(); $container.offset({ 'left': mouse.x - ( event_state.mouse_x - event_state.container_left ), 'top': mouse.y - ( event_state.mouse_y - event_state.container_top ) }); };









, , . , , , , . , , , , .



HTML :



<div class="overlay"> <div class="overlay-inner"> </div> </div> <button class="btn-crop js-crop">Crop</button>







, , .



.overlay { position: absolute; left: 50%; top: 50%; margin-left: -100px; margin-top: -100px; z-index: 999; width: 200px; height: 200px; border: solid 2px rgba(222,60,80,.9); box-sizing: content-box; pointer-events: none; } .overlay:after, .overlay:before { content: ''; position: absolute; display: block; width: 204px; height: 40px; border-left: dashed 2px rgba(222,60,80,.9); border-right: dashed 2px rgba(222,60,80,.9); } .overlay:before { top: 0; margin-left: -2px; margin-top: -40px; } .overlay:after { bottom: 0; margin-left: -2px; margin-bottom: -40px; } .overlay-inner:after, .overlay-inner:before { content: ''; position: absolute; display: block; width: 40px; height: 204px; border-top: dashed 2px rgba(222,60,80,.9); border-bottom: dashed 2px rgba(222,60,80,.9); } .overlay-inner:before { left: 0; margin-left: -40px; margin-top: -2px; } .overlay-inner:after { right: 0; margin-right: -40px; margin-top: -2px; } .btn-crop { position: absolute; vertical-align: bottom; right: 5px; bottom: 5px; padding: 6px 10px; z-index: 999; background-color: rgb(222,60,80); border: none; border-radius: 5px; color: #FFF; }







JavaScript :



init = function(){ //... $('.js-crop').on('click', crop); }; crop = function(){ var crop_canvas, left = $('.overlay').offset().left - $container.offset().left, top = $('.overlay').offset().top - $container.offset().top, width = $('.overlay').width(), height = $('.overlay').height(); crop_canvas = document.createElement('canvas'); crop_canvas.width = width; crop_canvas.height = height; crop_canvas.getContext('2d').drawImage(image_target, left, top, width, height, 0, 0, width, height); window.open(crop_canvas.toDataURL("image/png")); }







crop



resizeImage



. , .



drawImage



canvas. - . - , . - , canvas, .





. .



mousedown



mouseup



- touchstart



touchend



, mousemove



touchmove



. , touchup



touchdown



( ).



touchstart



touchend



, mousedown



, mouseup



touchmove



, mousemove



.



// In init()... $container.on('mousedown touchstart', '.resize-handle', startResize); $container.on('mousedown touchstart', 'img', startMoving); //In startResize() ... $(document).on('mousemove touchmove', moving); $(document).on('mouseup touchend', endMoving); //In endResize()... $(document).off('mouseup touchend', endMoving); $(document).off('mousemove touchmove', moving); //In startMoving()... $(document).on('mousemove touchmove', moving); $(document).on('mouseup touchend', endMoving); //In endMoving()... $(document).off('mouseup touchend', endMoving); $(document).off('mousemove touchmove', moving);







, "" . Hammer, . , , .



, , , saveEventState



. .



" " . , . moving



:



moving = function(e){ var mouse={}, touches; e.preventDefault(); e.stopPropagation(); touches = e.originalEvent.touches; mouse.x = (e.clientX || e.pageX || touches[0].clientX) + $(window).scrollLeft(); mouse.y = (e.clientY || e.pageY || touches[0].clientY) + $(window).scrollTop(); $container.offset({ 'left': mouse.x - ( event_state.mouse_x - event_state.container_left ), 'top': mouse.y - ( event_state.mouse_y - event_state.container_top ) }); // Watch for pinch zoom gesture while moving if(event_state.touches && event_state.touches.length > 1 && touches.length > 1){ var width = event_state.container_width, height = event_state.container_height; var a = event_state.touches[0].clientX - event_state.touches[1].clientX; a = a * a; var b = event_state.touches[0].clientY - event_state.touches[1].clientY; b = b * b; var dist1 = Math.sqrt( a + b ); a = e.originalEvent.touches[0].clientX - touches[1].clientX; a = a * a; b = e.originalEvent.touches[0].clientY - touches[1].clientY; b = b * b; var dist2 = Math.sqrt( a + b ); var ratio = dist2 /dist1; width = width * ratio; height = height * ratio; // To improve performance you might limit how often resizeImage() is called resizeImage(width, height); } };







.







. .



Chrome "", Firefox .



, .




HTML5, , , .



- . , . , .



canvas




, , . , , .



. . , , . , .



!





:

<img class="resize-image" src="image.jpg" alt="Image" />







! HTML .



CSS

CSS- . resize-container



.



.resize-container { position: relative; display: inline-block; cursor: move; margin: 0 auto; } .resize-container img { display: block } .resize-container:hover img, .resize-container:active img { outline: 2px dashed rgba(222,60,80,.9); }







'resize handles'. , , .



.resize-handle-ne, .resize-handle-ne, .resize-handle-se, .resize-handle-nw, .resize-handle-sw { position: absolute; display: block; width: 10px; height: 10px; background: rgba(222,60,80,.9); z-index: 999; } .resize-handle-nw { top: -5px; left: -5px; cursor: nw-resize; } .resize-handle-sw { bottom: -5px; left: -5px; cursor: sw-resize; } .resize-handle-ne { top: -5px; right: -5px; cursor: ne-resize; } .resize-handle-se { bottom: -5px; right: -5px; cursor: se-resize; }







JavaScript

Canvas.



var resizeableImage = function(image_target) { var $container, orig_src = new Image(), image_target = $(image_target).get(0), event_state = {}, constrain = false, min_width = 60, min_height = 60, max_width = 800, max_height = 900, resize_canvas = document.createElement('canvas'); }); resizeableImage($('.resize-image'));







, . , , . jQuery , .



var resizeableImage = function(image_target) { // ... init = function(){ // Create a new image with a copy of the original src // When resizing, we will always use this original copy as the base orig_src.src=image_target.src; // Add resize handles $(image_target).wrap('<div class="resize-container"></div>') .before('<span class="resize-handle resize-handle-nw"></span>') .before('<span class="resize-handle resize-handle-ne"></span>') .after('<span class="resize-handle resize-handle-se"></span>') .after('<span class="resize-handle resize-handle-sw"></span>'); // Get a variable for the container $container = $(image_target).parent('.resize-container'); // Add events $container.on('mousedown', '.resize-handle', startResize); }; //... init(); }







startResize



endResize



, , .



startResize = function(e){ e.preventDefault(); e.stopPropagation(); saveEventState(e); $(document).on('mousemove', resizing); $(document).on('mouseup', endResize); }; endResize = function(e){ e.preventDefault(); $(document).off('mouseup touchend', endResize); $(document).off('mousemove touchmove', resizing); };







. event_state



.



saveEventState = function(e){ // Save the initial event details and container state event_state.container_width = $container.width(); event_state.container_height = $container.height(); event_state.container_left = $container.offset().left; event_state.container_top = $container.offset().top; event_state.mouse_x = (e.clientX || e.pageX || e.originalEvent.touches[0].clientX) + $(window).scrollLeft(); event_state.mouse_y = (e.clientY || e.pageY || e.originalEvent.touches[0].clientY) + $(window).scrollTop(); // This is a fix for mobile safari // For some reason it does not allow a direct copy of the touches property if(typeof e.originalEvent.touches !== 'undefined'){ event_state.touches = []; $.each(e.originalEvent.touches, function(i, ob){ event_state.touches[i] = {}; event_state.touches[i].clientX = 0+ob.clientX; event_state.touches[i].clientY = 0+ob.clientY; }); } event_state.evnt = e; }







resizing



- . . .



resizing = function(e){ var mouse={},width,height,left,top,offset=$container.offset(); mouse.x = (e.clientX || e.pageX || e.originalEvent.touches[0].clientX) + $(window).scrollLeft(); mouse.y = (e.clientY || e.pageY || e.originalEvent.touches[0].clientY) + $(window).scrollTop(); width = mouse.x - event_state.container_left; height = mouse.y - event_state.container_top; left = event_state.container_left; top = event_state.container_top; if(constrain || e.shiftKey){ height = width / orig_src.width * orig_src.height; } if(width > min_width && height > min_height && width < max_width && height < max_height){ resizeImage(width, height); // Without this Firefox will not re-calculate the the image dimensions until drag end $container.offset({'left': left, 'top': top}); } }







Shift .



.



: , , resizeImage



.





Canvas , drawImage



. , . toDataURL



Base64-encoded .



.



resizeImage = function(width, height){ resize_canvas.width = width; resize_canvas.height = height; resize_canvas.getContext('2d').drawImage(orig_src, 0, 0, width, height); $(image_target).attr('src', resize_canvas.toDataURL("image/png")); };







? : , CORS . , 'tainted canvas'.







. . , . , .



, , .







, . resizing



:



resizing = function(e){ var mouse={},width,height,left,top,offset=$container.offset(); mouse.x = (e.clientX || e.pageX || e.originalEvent.touches[0].clientX) + $(window).scrollLeft(); mouse.y = (e.clientY || e.pageY || e.originalEvent.touches[0].clientY) + $(window).scrollTop(); // Position image differently depending on the corner dragged and constraints if( $(event_state.evnt.target).hasClass('resize-handle-se') ){ width = mouse.x - event_state.container_left; height = mouse.y - event_state.container_top; left = event_state.container_left; top = event_state.container_top; } else if($(event_state.evnt.target).hasClass('resize-handle-sw') ){ width = event_state.container_width - (mouse.x - event_state.container_left); height = mouse.y - event_state.container_top; left = mouse.x; top = event_state.container_top; } else if($(event_state.evnt.target).hasClass('resize-handle-nw') ){ width = event_state.container_width - (mouse.x - event_state.container_left); height = event_state.container_height - (mouse.y - event_state.container_top); left = mouse.x; top = mouse.y; if(constrain || e.shiftKey){ top = mouse.y - ((width / orig_src.width * orig_src.height) - height); } } else if($(event_state.evnt.target).hasClass('resize-handle-ne') ){ width = mouse.x - event_state.container_left; height = event_state.container_height - (mouse.y - event_state.container_top); left = event_state.container_left; top = mouse.y; if(constrain || e.shiftKey){ top = mouse.y - ((width / orig_src.width * orig_src.height) - height); } } // Optionally maintain aspect ratio if(constrain || e.shiftKey){ height = width / orig_src.width * orig_src.height; } if(width > min_width && height > min_height && width < max_width && height < max_height){ // To improve performance you might limit how often resizeImage() is called resizeImage(width, height); // Without this Firefox will not re-calculate the the image dimensions until drag end $container.offset({'left': left, 'top': top}); } }







, resize-handle



, .





, , , , , "". . .



init = function(){ //... $container.on('mousedown', 'img', startMoving); }







startMoving



endMoving



, startResize



endResize



.



startMoving = function(e){ e.preventDefault(); e.stopPropagation(); saveEventState(e); $(document).on('mousemove', moving); $(document).on('mouseup', endMoving); }; endMoving = function(e){ e.preventDefault(); $(document).off('mouseup', endMoving); $(document).off('mousemove', moving); };







moving



. , .



moving = function(e){ var mouse={}; e.preventDefault(); e.stopPropagation(); mouse.x = (e.clientX || e.pageX) + $(window).scrollLeft(); mouse.y = (e.clientY || e.pageY) + $(window).scrollTop(); $container.offset({ 'left': mouse.x - ( event_state.mouse_x - event_state.container_left ), 'top': mouse.y - ( event_state.mouse_y - event_state.container_top ) }); };









, , . , , , , . , , , , .



HTML :



<div class="overlay"> <div class="overlay-inner"> </div> </div> <button class="btn-crop js-crop">Crop</button>







, , .



.overlay { position: absolute; left: 50%; top: 50%; margin-left: -100px; margin-top: -100px; z-index: 999; width: 200px; height: 200px; border: solid 2px rgba(222,60,80,.9); box-sizing: content-box; pointer-events: none; } .overlay:after, .overlay:before { content: ''; position: absolute; display: block; width: 204px; height: 40px; border-left: dashed 2px rgba(222,60,80,.9); border-right: dashed 2px rgba(222,60,80,.9); } .overlay:before { top: 0; margin-left: -2px; margin-top: -40px; } .overlay:after { bottom: 0; margin-left: -2px; margin-bottom: -40px; } .overlay-inner:after, .overlay-inner:before { content: ''; position: absolute; display: block; width: 40px; height: 204px; border-top: dashed 2px rgba(222,60,80,.9); border-bottom: dashed 2px rgba(222,60,80,.9); } .overlay-inner:before { left: 0; margin-left: -40px; margin-top: -2px; } .overlay-inner:after { right: 0; margin-right: -40px; margin-top: -2px; } .btn-crop { position: absolute; vertical-align: bottom; right: 5px; bottom: 5px; padding: 6px 10px; z-index: 999; background-color: rgb(222,60,80); border: none; border-radius: 5px; color: #FFF; }







JavaScript :



init = function(){ //... $('.js-crop').on('click', crop); }; crop = function(){ var crop_canvas, left = $('.overlay').offset().left - $container.offset().left, top = $('.overlay').offset().top - $container.offset().top, width = $('.overlay').width(), height = $('.overlay').height(); crop_canvas = document.createElement('canvas'); crop_canvas.width = width; crop_canvas.height = height; crop_canvas.getContext('2d').drawImage(image_target, left, top, width, height, 0, 0, width, height); window.open(crop_canvas.toDataURL("image/png")); }







crop



resizeImage



. , .



drawImage



canvas. - . - , . - , canvas, .





. .



mousedown



mouseup



- touchstart



touchend



, mousemove



touchmove



. , touchup



touchdown



( ).



touchstart



touchend



, mousedown



, mouseup



touchmove



, mousemove



.



// In init()... $container.on('mousedown touchstart', '.resize-handle', startResize); $container.on('mousedown touchstart', 'img', startMoving); //In startResize() ... $(document).on('mousemove touchmove', moving); $(document).on('mouseup touchend', endMoving); //In endResize()... $(document).off('mouseup touchend', endMoving); $(document).off('mousemove touchmove', moving); //In startMoving()... $(document).on('mousemove touchmove', moving); $(document).on('mouseup touchend', endMoving); //In endMoving()... $(document).off('mouseup touchend', endMoving); $(document).off('mousemove touchmove', moving);







, "" . Hammer, . , , .



, , , saveEventState



. .



" " . , . moving



:



moving = function(e){ var mouse={}, touches; e.preventDefault(); e.stopPropagation(); touches = e.originalEvent.touches; mouse.x = (e.clientX || e.pageX || touches[0].clientX) + $(window).scrollLeft(); mouse.y = (e.clientY || e.pageY || touches[0].clientY) + $(window).scrollTop(); $container.offset({ 'left': mouse.x - ( event_state.mouse_x - event_state.container_left ), 'top': mouse.y - ( event_state.mouse_y - event_state.container_top ) }); // Watch for pinch zoom gesture while moving if(event_state.touches && event_state.touches.length > 1 && touches.length > 1){ var width = event_state.container_width, height = event_state.container_height; var a = event_state.touches[0].clientX - event_state.touches[1].clientX; a = a * a; var b = event_state.touches[0].clientY - event_state.touches[1].clientY; b = b * b; var dist1 = Math.sqrt( a + b ); a = e.originalEvent.touches[0].clientX - touches[1].clientX; a = a * a; b = e.originalEvent.touches[0].clientY - touches[1].clientY; b = b * b; var dist2 = Math.sqrt( a + b ); var ratio = dist2 /dist1; width = width * ratio; height = height * ratio; // To improve performance you might limit how often resizeImage() is called resizeImage(width, height); } };







.







. .



Chrome "", Firefox .



, .




HTML5, , , .



- . , . , .



canvas




, , . , , .



. . , , . , .



!





:

<img class="resize-image" src="image.jpg" alt="Image" />







! HTML .



CSS

CSS- . resize-container



.



.resize-container { position: relative; display: inline-block; cursor: move; margin: 0 auto; } .resize-container img { display: block } .resize-container:hover img, .resize-container:active img { outline: 2px dashed rgba(222,60,80,.9); }







'resize handles'. , , .



.resize-handle-ne, .resize-handle-ne, .resize-handle-se, .resize-handle-nw, .resize-handle-sw { position: absolute; display: block; width: 10px; height: 10px; background: rgba(222,60,80,.9); z-index: 999; } .resize-handle-nw { top: -5px; left: -5px; cursor: nw-resize; } .resize-handle-sw { bottom: -5px; left: -5px; cursor: sw-resize; } .resize-handle-ne { top: -5px; right: -5px; cursor: ne-resize; } .resize-handle-se { bottom: -5px; right: -5px; cursor: se-resize; }







JavaScript

Canvas.



var resizeableImage = function(image_target) { var $container, orig_src = new Image(), image_target = $(image_target).get(0), event_state = {}, constrain = false, min_width = 60, min_height = 60, max_width = 800, max_height = 900, resize_canvas = document.createElement('canvas'); }); resizeableImage($('.resize-image'));







, . , , . jQuery , .



var resizeableImage = function(image_target) { // ... init = function(){ // Create a new image with a copy of the original src // When resizing, we will always use this original copy as the base orig_src.src=image_target.src; // Add resize handles $(image_target).wrap('<div class="resize-container"></div>') .before('<span class="resize-handle resize-handle-nw"></span>') .before('<span class="resize-handle resize-handle-ne"></span>') .after('<span class="resize-handle resize-handle-se"></span>') .after('<span class="resize-handle resize-handle-sw"></span>'); // Get a variable for the container $container = $(image_target).parent('.resize-container'); // Add events $container.on('mousedown', '.resize-handle', startResize); }; //... init(); }







startResize



endResize



, , .



startResize = function(e){ e.preventDefault(); e.stopPropagation(); saveEventState(e); $(document).on('mousemove', resizing); $(document).on('mouseup', endResize); }; endResize = function(e){ e.preventDefault(); $(document).off('mouseup touchend', endResize); $(document).off('mousemove touchmove', resizing); };







. event_state



.



saveEventState = function(e){ // Save the initial event details and container state event_state.container_width = $container.width(); event_state.container_height = $container.height(); event_state.container_left = $container.offset().left; event_state.container_top = $container.offset().top; event_state.mouse_x = (e.clientX || e.pageX || e.originalEvent.touches[0].clientX) + $(window).scrollLeft(); event_state.mouse_y = (e.clientY || e.pageY || e.originalEvent.touches[0].clientY) + $(window).scrollTop(); // This is a fix for mobile safari // For some reason it does not allow a direct copy of the touches property if(typeof e.originalEvent.touches !== 'undefined'){ event_state.touches = []; $.each(e.originalEvent.touches, function(i, ob){ event_state.touches[i] = {}; event_state.touches[i].clientX = 0+ob.clientX; event_state.touches[i].clientY = 0+ob.clientY; }); } event_state.evnt = e; }







resizing



- . . .



resizing = function(e){ var mouse={},width,height,left,top,offset=$container.offset(); mouse.x = (e.clientX || e.pageX || e.originalEvent.touches[0].clientX) + $(window).scrollLeft(); mouse.y = (e.clientY || e.pageY || e.originalEvent.touches[0].clientY) + $(window).scrollTop(); width = mouse.x - event_state.container_left; height = mouse.y - event_state.container_top; left = event_state.container_left; top = event_state.container_top; if(constrain || e.shiftKey){ height = width / orig_src.width * orig_src.height; } if(width > min_width && height > min_height && width < max_width && height < max_height){ resizeImage(width, height); // Without this Firefox will not re-calculate the the image dimensions until drag end $container.offset({'left': left, 'top': top}); } }







Shift .



.



: , , resizeImage



.





Canvas , drawImage



. , . toDataURL



Base64-encoded .



.



resizeImage = function(width, height){ resize_canvas.width = width; resize_canvas.height = height; resize_canvas.getContext('2d').drawImage(orig_src, 0, 0, width, height); $(image_target).attr('src', resize_canvas.toDataURL("image/png")); };







? : , CORS . , 'tainted canvas'.







. . , . , .



, , .







, . resizing



:



resizing = function(e){ var mouse={},width,height,left,top,offset=$container.offset(); mouse.x = (e.clientX || e.pageX || e.originalEvent.touches[0].clientX) + $(window).scrollLeft(); mouse.y = (e.clientY || e.pageY || e.originalEvent.touches[0].clientY) + $(window).scrollTop(); // Position image differently depending on the corner dragged and constraints if( $(event_state.evnt.target).hasClass('resize-handle-se') ){ width = mouse.x - event_state.container_left; height = mouse.y - event_state.container_top; left = event_state.container_left; top = event_state.container_top; } else if($(event_state.evnt.target).hasClass('resize-handle-sw') ){ width = event_state.container_width - (mouse.x - event_state.container_left); height = mouse.y - event_state.container_top; left = mouse.x; top = event_state.container_top; } else if($(event_state.evnt.target).hasClass('resize-handle-nw') ){ width = event_state.container_width - (mouse.x - event_state.container_left); height = event_state.container_height - (mouse.y - event_state.container_top); left = mouse.x; top = mouse.y; if(constrain || e.shiftKey){ top = mouse.y - ((width / orig_src.width * orig_src.height) - height); } } else if($(event_state.evnt.target).hasClass('resize-handle-ne') ){ width = mouse.x - event_state.container_left; height = event_state.container_height - (mouse.y - event_state.container_top); left = event_state.container_left; top = mouse.y; if(constrain || e.shiftKey){ top = mouse.y - ((width / orig_src.width * orig_src.height) - height); } } // Optionally maintain aspect ratio if(constrain || e.shiftKey){ height = width / orig_src.width * orig_src.height; } if(width > min_width && height > min_height && width < max_width && height < max_height){ // To improve performance you might limit how often resizeImage() is called resizeImage(width, height); // Without this Firefox will not re-calculate the the image dimensions until drag end $container.offset({'left': left, 'top': top}); } }







, resize-handle



, .





, , , , , "". . .



init = function(){ //... $container.on('mousedown', 'img', startMoving); }







startMoving



endMoving



, startResize



endResize



.



startMoving = function(e){ e.preventDefault(); e.stopPropagation(); saveEventState(e); $(document).on('mousemove', moving); $(document).on('mouseup', endMoving); }; endMoving = function(e){ e.preventDefault(); $(document).off('mouseup', endMoving); $(document).off('mousemove', moving); };







moving



. , .



moving = function(e){ var mouse={}; e.preventDefault(); e.stopPropagation(); mouse.x = (e.clientX || e.pageX) + $(window).scrollLeft(); mouse.y = (e.clientY || e.pageY) + $(window).scrollTop(); $container.offset({ 'left': mouse.x - ( event_state.mouse_x - event_state.container_left ), 'top': mouse.y - ( event_state.mouse_y - event_state.container_top ) }); };









, , . , , , , . , , , , .



HTML :



<div class="overlay"> <div class="overlay-inner"> </div> </div> <button class="btn-crop js-crop">Crop</button>







, , .



.overlay { position: absolute; left: 50%; top: 50%; margin-left: -100px; margin-top: -100px; z-index: 999; width: 200px; height: 200px; border: solid 2px rgba(222,60,80,.9); box-sizing: content-box; pointer-events: none; } .overlay:after, .overlay:before { content: ''; position: absolute; display: block; width: 204px; height: 40px; border-left: dashed 2px rgba(222,60,80,.9); border-right: dashed 2px rgba(222,60,80,.9); } .overlay:before { top: 0; margin-left: -2px; margin-top: -40px; } .overlay:after { bottom: 0; margin-left: -2px; margin-bottom: -40px; } .overlay-inner:after, .overlay-inner:before { content: ''; position: absolute; display: block; width: 40px; height: 204px; border-top: dashed 2px rgba(222,60,80,.9); border-bottom: dashed 2px rgba(222,60,80,.9); } .overlay-inner:before { left: 0; margin-left: -40px; margin-top: -2px; } .overlay-inner:after { right: 0; margin-right: -40px; margin-top: -2px; } .btn-crop { position: absolute; vertical-align: bottom; right: 5px; bottom: 5px; padding: 6px 10px; z-index: 999; background-color: rgb(222,60,80); border: none; border-radius: 5px; color: #FFF; }







JavaScript :



init = function(){ //... $('.js-crop').on('click', crop); }; crop = function(){ var crop_canvas, left = $('.overlay').offset().left - $container.offset().left, top = $('.overlay').offset().top - $container.offset().top, width = $('.overlay').width(), height = $('.overlay').height(); crop_canvas = document.createElement('canvas'); crop_canvas.width = width; crop_canvas.height = height; crop_canvas.getContext('2d').drawImage(image_target, left, top, width, height, 0, 0, width, height); window.open(crop_canvas.toDataURL("image/png")); }







crop



resizeImage



. , .



drawImage



canvas. - . - , . - , canvas, .





. .



mousedown



mouseup



- touchstart



touchend



, mousemove



touchmove



. , touchup



touchdown



( ).



touchstart



touchend



, mousedown



, mouseup



touchmove



, mousemove



.



// In init()... $container.on('mousedown touchstart', '.resize-handle', startResize); $container.on('mousedown touchstart', 'img', startMoving); //In startResize() ... $(document).on('mousemove touchmove', moving); $(document).on('mouseup touchend', endMoving); //In endResize()... $(document).off('mouseup touchend', endMoving); $(document).off('mousemove touchmove', moving); //In startMoving()... $(document).on('mousemove touchmove', moving); $(document).on('mouseup touchend', endMoving); //In endMoving()... $(document).off('mouseup touchend', endMoving); $(document).off('mousemove touchmove', moving);







, "" . Hammer, . , , .



, , , saveEventState



. .



" " . , . moving



:



moving = function(e){ var mouse={}, touches; e.preventDefault(); e.stopPropagation(); touches = e.originalEvent.touches; mouse.x = (e.clientX || e.pageX || touches[0].clientX) + $(window).scrollLeft(); mouse.y = (e.clientY || e.pageY || touches[0].clientY) + $(window).scrollTop(); $container.offset({ 'left': mouse.x - ( event_state.mouse_x - event_state.container_left ), 'top': mouse.y - ( event_state.mouse_y - event_state.container_top ) }); // Watch for pinch zoom gesture while moving if(event_state.touches && event_state.touches.length > 1 && touches.length > 1){ var width = event_state.container_width, height = event_state.container_height; var a = event_state.touches[0].clientX - event_state.touches[1].clientX; a = a * a; var b = event_state.touches[0].clientY - event_state.touches[1].clientY; b = b * b; var dist1 = Math.sqrt( a + b ); a = e.originalEvent.touches[0].clientX - touches[1].clientX; a = a * a; b = e.originalEvent.touches[0].clientY - touches[1].clientY; b = b * b; var dist2 = Math.sqrt( a + b ); var ratio = dist2 /dist1; width = width * ratio; height = height * ratio; // To improve performance you might limit how often resizeImage() is called resizeImage(width, height); } };







.







. .



Chrome "", Firefox .



, .




HTML5, , , .



- . , . , .



canvas




, , . , , .



. . , , . , .



!





:

<img class="resize-image" src="image.jpg" alt="Image" />







! HTML .



CSS

CSS- . resize-container



.



.resize-container { position: relative; display: inline-block; cursor: move; margin: 0 auto; } .resize-container img { display: block } .resize-container:hover img, .resize-container:active img { outline: 2px dashed rgba(222,60,80,.9); }







'resize handles'. , , .



.resize-handle-ne, .resize-handle-ne, .resize-handle-se, .resize-handle-nw, .resize-handle-sw { position: absolute; display: block; width: 10px; height: 10px; background: rgba(222,60,80,.9); z-index: 999; } .resize-handle-nw { top: -5px; left: -5px; cursor: nw-resize; } .resize-handle-sw { bottom: -5px; left: -5px; cursor: sw-resize; } .resize-handle-ne { top: -5px; right: -5px; cursor: ne-resize; } .resize-handle-se { bottom: -5px; right: -5px; cursor: se-resize; }







JavaScript

Canvas.



var resizeableImage = function(image_target) { var $container, orig_src = new Image(), image_target = $(image_target).get(0), event_state = {}, constrain = false, min_width = 60, min_height = 60, max_width = 800, max_height = 900, resize_canvas = document.createElement('canvas'); }); resizeableImage($('.resize-image'));







, . , , . jQuery , .



var resizeableImage = function(image_target) { // ... init = function(){ // Create a new image with a copy of the original src // When resizing, we will always use this original copy as the base orig_src.src=image_target.src; // Add resize handles $(image_target).wrap('<div class="resize-container"></div>') .before('<span class="resize-handle resize-handle-nw"></span>') .before('<span class="resize-handle resize-handle-ne"></span>') .after('<span class="resize-handle resize-handle-se"></span>') .after('<span class="resize-handle resize-handle-sw"></span>'); // Get a variable for the container $container = $(image_target).parent('.resize-container'); // Add events $container.on('mousedown', '.resize-handle', startResize); }; //... init(); }







startResize



endResize



, , .



startResize = function(e){ e.preventDefault(); e.stopPropagation(); saveEventState(e); $(document).on('mousemove', resizing); $(document).on('mouseup', endResize); }; endResize = function(e){ e.preventDefault(); $(document).off('mouseup touchend', endResize); $(document).off('mousemove touchmove', resizing); };







. event_state



.



saveEventState = function(e){ // Save the initial event details and container state event_state.container_width = $container.width(); event_state.container_height = $container.height(); event_state.container_left = $container.offset().left; event_state.container_top = $container.offset().top; event_state.mouse_x = (e.clientX || e.pageX || e.originalEvent.touches[0].clientX) + $(window).scrollLeft(); event_state.mouse_y = (e.clientY || e.pageY || e.originalEvent.touches[0].clientY) + $(window).scrollTop(); // This is a fix for mobile safari // For some reason it does not allow a direct copy of the touches property if(typeof e.originalEvent.touches !== 'undefined'){ event_state.touches = []; $.each(e.originalEvent.touches, function(i, ob){ event_state.touches[i] = {}; event_state.touches[i].clientX = 0+ob.clientX; event_state.touches[i].clientY = 0+ob.clientY; }); } event_state.evnt = e; }







resizing



- . . .



resizing = function(e){ var mouse={},width,height,left,top,offset=$container.offset(); mouse.x = (e.clientX || e.pageX || e.originalEvent.touches[0].clientX) + $(window).scrollLeft(); mouse.y = (e.clientY || e.pageY || e.originalEvent.touches[0].clientY) + $(window).scrollTop(); width = mouse.x - event_state.container_left; height = mouse.y - event_state.container_top; left = event_state.container_left; top = event_state.container_top; if(constrain || e.shiftKey){ height = width / orig_src.width * orig_src.height; } if(width > min_width && height > min_height && width < max_width && height < max_height){ resizeImage(width, height); // Without this Firefox will not re-calculate the the image dimensions until drag end $container.offset({'left': left, 'top': top}); } }







Shift .



.



: , , resizeImage



.





Canvas , drawImage



. , . toDataURL



Base64-encoded .



.



resizeImage = function(width, height){ resize_canvas.width = width; resize_canvas.height = height; resize_canvas.getContext('2d').drawImage(orig_src, 0, 0, width, height); $(image_target).attr('src', resize_canvas.toDataURL("image/png")); };







? : , CORS . , 'tainted canvas'.







. . , . , .



, , .







, . resizing



:



resizing = function(e){ var mouse={},width,height,left,top,offset=$container.offset(); mouse.x = (e.clientX || e.pageX || e.originalEvent.touches[0].clientX) + $(window).scrollLeft(); mouse.y = (e.clientY || e.pageY || e.originalEvent.touches[0].clientY) + $(window).scrollTop(); // Position image differently depending on the corner dragged and constraints if( $(event_state.evnt.target).hasClass('resize-handle-se') ){ width = mouse.x - event_state.container_left; height = mouse.y - event_state.container_top; left = event_state.container_left; top = event_state.container_top; } else if($(event_state.evnt.target).hasClass('resize-handle-sw') ){ width = event_state.container_width - (mouse.x - event_state.container_left); height = mouse.y - event_state.container_top; left = mouse.x; top = event_state.container_top; } else if($(event_state.evnt.target).hasClass('resize-handle-nw') ){ width = event_state.container_width - (mouse.x - event_state.container_left); height = event_state.container_height - (mouse.y - event_state.container_top); left = mouse.x; top = mouse.y; if(constrain || e.shiftKey){ top = mouse.y - ((width / orig_src.width * orig_src.height) - height); } } else if($(event_state.evnt.target).hasClass('resize-handle-ne') ){ width = mouse.x - event_state.container_left; height = event_state.container_height - (mouse.y - event_state.container_top); left = event_state.container_left; top = mouse.y; if(constrain || e.shiftKey){ top = mouse.y - ((width / orig_src.width * orig_src.height) - height); } } // Optionally maintain aspect ratio if(constrain || e.shiftKey){ height = width / orig_src.width * orig_src.height; } if(width > min_width && height > min_height && width < max_width && height < max_height){ // To improve performance you might limit how often resizeImage() is called resizeImage(width, height); // Without this Firefox will not re-calculate the the image dimensions until drag end $container.offset({'left': left, 'top': top}); } }







, resize-handle



, .





, , , , , "". . .



init = function(){ //... $container.on('mousedown', 'img', startMoving); }







startMoving



endMoving



, startResize



endResize



.



startMoving = function(e){ e.preventDefault(); e.stopPropagation(); saveEventState(e); $(document).on('mousemove', moving); $(document).on('mouseup', endMoving); }; endMoving = function(e){ e.preventDefault(); $(document).off('mouseup', endMoving); $(document).off('mousemove', moving); };







moving



. , .



moving = function(e){ var mouse={}; e.preventDefault(); e.stopPropagation(); mouse.x = (e.clientX || e.pageX) + $(window).scrollLeft(); mouse.y = (e.clientY || e.pageY) + $(window).scrollTop(); $container.offset({ 'left': mouse.x - ( event_state.mouse_x - event_state.container_left ), 'top': mouse.y - ( event_state.mouse_y - event_state.container_top ) }); };









, , . , , , , . , , , , .



HTML :



<div class="overlay"> <div class="overlay-inner"> </div> </div> <button class="btn-crop js-crop">Crop</button>







, , .



.overlay { position: absolute; left: 50%; top: 50%; margin-left: -100px; margin-top: -100px; z-index: 999; width: 200px; height: 200px; border: solid 2px rgba(222,60,80,.9); box-sizing: content-box; pointer-events: none; } .overlay:after, .overlay:before { content: ''; position: absolute; display: block; width: 204px; height: 40px; border-left: dashed 2px rgba(222,60,80,.9); border-right: dashed 2px rgba(222,60,80,.9); } .overlay:before { top: 0; margin-left: -2px; margin-top: -40px; } .overlay:after { bottom: 0; margin-left: -2px; margin-bottom: -40px; } .overlay-inner:after, .overlay-inner:before { content: ''; position: absolute; display: block; width: 40px; height: 204px; border-top: dashed 2px rgba(222,60,80,.9); border-bottom: dashed 2px rgba(222,60,80,.9); } .overlay-inner:before { left: 0; margin-left: -40px; margin-top: -2px; } .overlay-inner:after { right: 0; margin-right: -40px; margin-top: -2px; } .btn-crop { position: absolute; vertical-align: bottom; right: 5px; bottom: 5px; padding: 6px 10px; z-index: 999; background-color: rgb(222,60,80); border: none; border-radius: 5px; color: #FFF; }







JavaScript :



init = function(){ //... $('.js-crop').on('click', crop); }; crop = function(){ var crop_canvas, left = $('.overlay').offset().left - $container.offset().left, top = $('.overlay').offset().top - $container.offset().top, width = $('.overlay').width(), height = $('.overlay').height(); crop_canvas = document.createElement('canvas'); crop_canvas.width = width; crop_canvas.height = height; crop_canvas.getContext('2d').drawImage(image_target, left, top, width, height, 0, 0, width, height); window.open(crop_canvas.toDataURL("image/png")); }







crop



resizeImage



. , .



drawImage



canvas. - . - , . - , canvas, .





. .



mousedown



mouseup



- touchstart



touchend



, mousemove



touchmove



. , touchup



touchdown



( ).



touchstart



touchend



, mousedown



, mouseup



touchmove



, mousemove



.



// In init()... $container.on('mousedown touchstart', '.resize-handle', startResize); $container.on('mousedown touchstart', 'img', startMoving); //In startResize() ... $(document).on('mousemove touchmove', moving); $(document).on('mouseup touchend', endMoving); //In endResize()... $(document).off('mouseup touchend', endMoving); $(document).off('mousemove touchmove', moving); //In startMoving()... $(document).on('mousemove touchmove', moving); $(document).on('mouseup touchend', endMoving); //In endMoving()... $(document).off('mouseup touchend', endMoving); $(document).off('mousemove touchmove', moving);







, "" . Hammer, . , , .



, , , saveEventState



. .



" " . , . moving



:



moving = function(e){ var mouse={}, touches; e.preventDefault(); e.stopPropagation(); touches = e.originalEvent.touches; mouse.x = (e.clientX || e.pageX || touches[0].clientX) + $(window).scrollLeft(); mouse.y = (e.clientY || e.pageY || touches[0].clientY) + $(window).scrollTop(); $container.offset({ 'left': mouse.x - ( event_state.mouse_x - event_state.container_left ), 'top': mouse.y - ( event_state.mouse_y - event_state.container_top ) }); // Watch for pinch zoom gesture while moving if(event_state.touches && event_state.touches.length > 1 && touches.length > 1){ var width = event_state.container_width, height = event_state.container_height; var a = event_state.touches[0].clientX - event_state.touches[1].clientX; a = a * a; var b = event_state.touches[0].clientY - event_state.touches[1].clientY; b = b * b; var dist1 = Math.sqrt( a + b ); a = e.originalEvent.touches[0].clientX - touches[1].clientX; a = a * a; b = e.originalEvent.touches[0].clientY - touches[1].clientY; b = b * b; var dist2 = Math.sqrt( a + b ); var ratio = dist2 /dist1; width = width * ratio; height = height * ratio; // To improve performance you might limit how often resizeImage() is called resizeImage(width, height); } };







.







. .



Chrome "", Firefox .



, .




  HTML5,     ,      ,   . 
      



- . , . , .



canvas




, , . , , .



. . , , . , .



!





:

<img class="resize-image" src="image.jpg" alt="Image" />







! HTML .



CSS

CSS- . resize-container



.



.resize-container { position: relative; display: inline-block; cursor: move; margin: 0 auto; } .resize-container img { display: block } .resize-container:hover img, .resize-container:active img { outline: 2px dashed rgba(222,60,80,.9); }







'resize handles'. , , .



.resize-handle-ne, .resize-handle-ne, .resize-handle-se, .resize-handle-nw, .resize-handle-sw { position: absolute; display: block; width: 10px; height: 10px; background: rgba(222,60,80,.9); z-index: 999; } .resize-handle-nw { top: -5px; left: -5px; cursor: nw-resize; } .resize-handle-sw { bottom: -5px; left: -5px; cursor: sw-resize; } .resize-handle-ne { top: -5px; right: -5px; cursor: ne-resize; } .resize-handle-se { bottom: -5px; right: -5px; cursor: se-resize; }







JavaScript

Canvas.



var resizeableImage = function(image_target) { var $container, orig_src = new Image(), image_target = $(image_target).get(0), event_state = {}, constrain = false, min_width = 60, min_height = 60, max_width = 800, max_height = 900, resize_canvas = document.createElement('canvas'); }); resizeableImage($('.resize-image'));







, . , , . jQuery , .



var resizeableImage = function(image_target) { // ... init = function(){ // Create a new image with a copy of the original src // When resizing, we will always use this original copy as the base orig_src.src=image_target.src; // Add resize handles $(image_target).wrap('<div class="resize-container"></div>') .before('<span class="resize-handle resize-handle-nw"></span>') .before('<span class="resize-handle resize-handle-ne"></span>') .after('<span class="resize-handle resize-handle-se"></span>') .after('<span class="resize-handle resize-handle-sw"></span>'); // Get a variable for the container $container = $(image_target).parent('.resize-container'); // Add events $container.on('mousedown', '.resize-handle', startResize); }; //... init(); }







startResize



endResize



, , .



startResize = function(e){ e.preventDefault(); e.stopPropagation(); saveEventState(e); $(document).on('mousemove', resizing); $(document).on('mouseup', endResize); }; endResize = function(e){ e.preventDefault(); $(document).off('mouseup touchend', endResize); $(document).off('mousemove touchmove', resizing); };







. event_state



.



saveEventState = function(e){ // Save the initial event details and container state event_state.container_width = $container.width(); event_state.container_height = $container.height(); event_state.container_left = $container.offset().left; event_state.container_top = $container.offset().top; event_state.mouse_x = (e.clientX || e.pageX || e.originalEvent.touches[0].clientX) + $(window).scrollLeft(); event_state.mouse_y = (e.clientY || e.pageY || e.originalEvent.touches[0].clientY) + $(window).scrollTop(); // This is a fix for mobile safari // For some reason it does not allow a direct copy of the touches property if(typeof e.originalEvent.touches !== 'undefined'){ event_state.touches = []; $.each(e.originalEvent.touches, function(i, ob){ event_state.touches[i] = {}; event_state.touches[i].clientX = 0+ob.clientX; event_state.touches[i].clientY = 0+ob.clientY; }); } event_state.evnt = e; }







resizing



- . . .



resizing = function(e){ var mouse={},width,height,left,top,offset=$container.offset(); mouse.x = (e.clientX || e.pageX || e.originalEvent.touches[0].clientX) + $(window).scrollLeft(); mouse.y = (e.clientY || e.pageY || e.originalEvent.touches[0].clientY) + $(window).scrollTop(); width = mouse.x - event_state.container_left; height = mouse.y - event_state.container_top; left = event_state.container_left; top = event_state.container_top; if(constrain || e.shiftKey){ height = width / orig_src.width * orig_src.height; } if(width > min_width && height > min_height && width < max_width && height < max_height){ resizeImage(width, height); // Without this Firefox will not re-calculate the the image dimensions until drag end $container.offset({'left': left, 'top': top}); } }







Shift .



.



: , , resizeImage



.





Canvas , drawImage



. , . toDataURL



Base64-encoded .



.



resizeImage = function(width, height){ resize_canvas.width = width; resize_canvas.height = height; resize_canvas.getContext('2d').drawImage(orig_src, 0, 0, width, height); $(image_target).attr('src', resize_canvas.toDataURL("image/png")); };







? : , CORS . , 'tainted canvas'.







. . , . , .



, , .







, . resizing



:



resizing = function(e){ var mouse={},width,height,left,top,offset=$container.offset(); mouse.x = (e.clientX || e.pageX || e.originalEvent.touches[0].clientX) + $(window).scrollLeft(); mouse.y = (e.clientY || e.pageY || e.originalEvent.touches[0].clientY) + $(window).scrollTop(); // Position image differently depending on the corner dragged and constraints if( $(event_state.evnt.target).hasClass('resize-handle-se') ){ width = mouse.x - event_state.container_left; height = mouse.y - event_state.container_top; left = event_state.container_left; top = event_state.container_top; } else if($(event_state.evnt.target).hasClass('resize-handle-sw') ){ width = event_state.container_width - (mouse.x - event_state.container_left); height = mouse.y - event_state.container_top; left = mouse.x; top = event_state.container_top; } else if($(event_state.evnt.target).hasClass('resize-handle-nw') ){ width = event_state.container_width - (mouse.x - event_state.container_left); height = event_state.container_height - (mouse.y - event_state.container_top); left = mouse.x; top = mouse.y; if(constrain || e.shiftKey){ top = mouse.y - ((width / orig_src.width * orig_src.height) - height); } } else if($(event_state.evnt.target).hasClass('resize-handle-ne') ){ width = mouse.x - event_state.container_left; height = event_state.container_height - (mouse.y - event_state.container_top); left = event_state.container_left; top = mouse.y; if(constrain || e.shiftKey){ top = mouse.y - ((width / orig_src.width * orig_src.height) - height); } } // Optionally maintain aspect ratio if(constrain || e.shiftKey){ height = width / orig_src.width * orig_src.height; } if(width > min_width && height > min_height && width < max_width && height < max_height){ // To improve performance you might limit how often resizeImage() is called resizeImage(width, height); // Without this Firefox will not re-calculate the the image dimensions until drag end $container.offset({'left': left, 'top': top}); } }







, resize-handle



, .





, , , , , "". . .



init = function(){ //... $container.on('mousedown', 'img', startMoving); }







startMoving



endMoving



, startResize



endResize



.



startMoving = function(e){ e.preventDefault(); e.stopPropagation(); saveEventState(e); $(document).on('mousemove', moving); $(document).on('mouseup', endMoving); }; endMoving = function(e){ e.preventDefault(); $(document).off('mouseup', endMoving); $(document).off('mousemove', moving); };







moving



. , .



moving = function(e){ var mouse={}; e.preventDefault(); e.stopPropagation(); mouse.x = (e.clientX || e.pageX) + $(window).scrollLeft(); mouse.y = (e.clientY || e.pageY) + $(window).scrollTop(); $container.offset({ 'left': mouse.x - ( event_state.mouse_x - event_state.container_left ), 'top': mouse.y - ( event_state.mouse_y - event_state.container_top ) }); };









, , . , , , , . , , , , .



HTML :



<div class="overlay"> <div class="overlay-inner"> </div> </div> <button class="btn-crop js-crop">Crop</button>







, , .



.overlay { position: absolute; left: 50%; top: 50%; margin-left: -100px; margin-top: -100px; z-index: 999; width: 200px; height: 200px; border: solid 2px rgba(222,60,80,.9); box-sizing: content-box; pointer-events: none; } .overlay:after, .overlay:before { content: ''; position: absolute; display: block; width: 204px; height: 40px; border-left: dashed 2px rgba(222,60,80,.9); border-right: dashed 2px rgba(222,60,80,.9); } .overlay:before { top: 0; margin-left: -2px; margin-top: -40px; } .overlay:after { bottom: 0; margin-left: -2px; margin-bottom: -40px; } .overlay-inner:after, .overlay-inner:before { content: ''; position: absolute; display: block; width: 40px; height: 204px; border-top: dashed 2px rgba(222,60,80,.9); border-bottom: dashed 2px rgba(222,60,80,.9); } .overlay-inner:before { left: 0; margin-left: -40px; margin-top: -2px; } .overlay-inner:after { right: 0; margin-right: -40px; margin-top: -2px; } .btn-crop { position: absolute; vertical-align: bottom; right: 5px; bottom: 5px; padding: 6px 10px; z-index: 999; background-color: rgb(222,60,80); border: none; border-radius: 5px; color: #FFF; }







JavaScript :



init = function(){ //... $('.js-crop').on('click', crop); }; crop = function(){ var crop_canvas, left = $('.overlay').offset().left - $container.offset().left, top = $('.overlay').offset().top - $container.offset().top, width = $('.overlay').width(), height = $('.overlay').height(); crop_canvas = document.createElement('canvas'); crop_canvas.width = width; crop_canvas.height = height; crop_canvas.getContext('2d').drawImage(image_target, left, top, width, height, 0, 0, width, height); window.open(crop_canvas.toDataURL("image/png")); }







crop



resizeImage



. , .



drawImage



canvas. - . - , . - , canvas, .





. .



mousedown



mouseup



- touchstart



touchend



, mousemove



touchmove



. , touchup



touchdown



( ).



touchstart



touchend



, mousedown



, mouseup



touchmove



, mousemove



.



// In init()... $container.on('mousedown touchstart', '.resize-handle', startResize); $container.on('mousedown touchstart', 'img', startMoving); //In startResize() ... $(document).on('mousemove touchmove', moving); $(document).on('mouseup touchend', endMoving); //In endResize()... $(document).off('mouseup touchend', endMoving); $(document).off('mousemove touchmove', moving); //In startMoving()... $(document).on('mousemove touchmove', moving); $(document).on('mouseup touchend', endMoving); //In endMoving()... $(document).off('mouseup touchend', endMoving); $(document).off('mousemove touchmove', moving);







, "" . Hammer, . , , .



, , , saveEventState



. .



" " . , . moving



:



moving = function(e){ var mouse={}, touches; e.preventDefault(); e.stopPropagation(); touches = e.originalEvent.touches; mouse.x = (e.clientX || e.pageX || touches[0].clientX) + $(window).scrollLeft(); mouse.y = (e.clientY || e.pageY || touches[0].clientY) + $(window).scrollTop(); $container.offset({ 'left': mouse.x - ( event_state.mouse_x - event_state.container_left ), 'top': mouse.y - ( event_state.mouse_y - event_state.container_top ) }); // Watch for pinch zoom gesture while moving if(event_state.touches && event_state.touches.length > 1 && touches.length > 1){ var width = event_state.container_width, height = event_state.container_height; var a = event_state.touches[0].clientX - event_state.touches[1].clientX; a = a * a; var b = event_state.touches[0].clientY - event_state.touches[1].clientY; b = b * b; var dist1 = Math.sqrt( a + b ); a = e.originalEvent.touches[0].clientX - touches[1].clientX; a = a * a; b = e.originalEvent.touches[0].clientY - touches[1].clientY; b = b * b; var dist2 = Math.sqrt( a + b ); var ratio = dist2 /dist1; width = width * ratio; height = height * ratio; // To improve performance you might limit how often resizeImage() is called resizeImage(width, height); } };







.







. .



Chrome "", Firefox .



, .




HTML5, , , .



- . , . , .



canvas




, , . , , .



. . , , . , .



!





:

<img class="resize-image" src="image.jpg" alt="Image" />







! HTML .



CSS

CSS- . resize-container



.



.resize-container { position: relative; display: inline-block; cursor: move; margin: 0 auto; } .resize-container img { display: block } .resize-container:hover img, .resize-container:active img { outline: 2px dashed rgba(222,60,80,.9); }







'resize handles'. , , .



.resize-handle-ne, .resize-handle-ne, .resize-handle-se, .resize-handle-nw, .resize-handle-sw { position: absolute; display: block; width: 10px; height: 10px; background: rgba(222,60,80,.9); z-index: 999; } .resize-handle-nw { top: -5px; left: -5px; cursor: nw-resize; } .resize-handle-sw { bottom: -5px; left: -5px; cursor: sw-resize; } .resize-handle-ne { top: -5px; right: -5px; cursor: ne-resize; } .resize-handle-se { bottom: -5px; right: -5px; cursor: se-resize; }







JavaScript

Canvas.



var resizeableImage = function(image_target) { var $container, orig_src = new Image(), image_target = $(image_target).get(0), event_state = {}, constrain = false, min_width = 60, min_height = 60, max_width = 800, max_height = 900, resize_canvas = document.createElement('canvas'); }); resizeableImage($('.resize-image'));







, . , , . jQuery , .



var resizeableImage = function(image_target) { // ... init = function(){ // Create a new image with a copy of the original src // When resizing, we will always use this original copy as the base orig_src.src=image_target.src; // Add resize handles $(image_target).wrap('<div class="resize-container"></div>') .before('<span class="resize-handle resize-handle-nw"></span>') .before('<span class="resize-handle resize-handle-ne"></span>') .after('<span class="resize-handle resize-handle-se"></span>') .after('<span class="resize-handle resize-handle-sw"></span>'); // Get a variable for the container $container = $(image_target).parent('.resize-container'); // Add events $container.on('mousedown', '.resize-handle', startResize); }; //... init(); }







startResize



endResize



, , .



startResize = function(e){ e.preventDefault(); e.stopPropagation(); saveEventState(e); $(document).on('mousemove', resizing); $(document).on('mouseup', endResize); }; endResize = function(e){ e.preventDefault(); $(document).off('mouseup touchend', endResize); $(document).off('mousemove touchmove', resizing); };







. event_state



.



saveEventState = function(e){ // Save the initial event details and container state event_state.container_width = $container.width(); event_state.container_height = $container.height(); event_state.container_left = $container.offset().left; event_state.container_top = $container.offset().top; event_state.mouse_x = (e.clientX || e.pageX || e.originalEvent.touches[0].clientX) + $(window).scrollLeft(); event_state.mouse_y = (e.clientY || e.pageY || e.originalEvent.touches[0].clientY) + $(window).scrollTop(); // This is a fix for mobile safari // For some reason it does not allow a direct copy of the touches property if(typeof e.originalEvent.touches !== 'undefined'){ event_state.touches = []; $.each(e.originalEvent.touches, function(i, ob){ event_state.touches[i] = {}; event_state.touches[i].clientX = 0+ob.clientX; event_state.touches[i].clientY = 0+ob.clientY; }); } event_state.evnt = e; }







resizing



- . . .



resizing = function(e){ var mouse={},width,height,left,top,offset=$container.offset(); mouse.x = (e.clientX || e.pageX || e.originalEvent.touches[0].clientX) + $(window).scrollLeft(); mouse.y = (e.clientY || e.pageY || e.originalEvent.touches[0].clientY) + $(window).scrollTop(); width = mouse.x - event_state.container_left; height = mouse.y - event_state.container_top; left = event_state.container_left; top = event_state.container_top; if(constrain || e.shiftKey){ height = width / orig_src.width * orig_src.height; } if(width > min_width && height > min_height && width < max_width && height < max_height){ resizeImage(width, height); // Without this Firefox will not re-calculate the the image dimensions until drag end $container.offset({'left': left, 'top': top}); } }







Shift .



.



: , , resizeImage



.





Canvas , drawImage



. , . toDataURL



Base64-encoded .



.



resizeImage = function(width, height){ resize_canvas.width = width; resize_canvas.height = height; resize_canvas.getContext('2d').drawImage(orig_src, 0, 0, width, height); $(image_target).attr('src', resize_canvas.toDataURL("image/png")); };







? : , CORS . , 'tainted canvas'.







. . , . , .



, , .







, . resizing



:



resizing = function(e){ var mouse={},width,height,left,top,offset=$container.offset(); mouse.x = (e.clientX || e.pageX || e.originalEvent.touches[0].clientX) + $(window).scrollLeft(); mouse.y = (e.clientY || e.pageY || e.originalEvent.touches[0].clientY) + $(window).scrollTop(); // Position image differently depending on the corner dragged and constraints if( $(event_state.evnt.target).hasClass('resize-handle-se') ){ width = mouse.x - event_state.container_left; height = mouse.y - event_state.container_top; left = event_state.container_left; top = event_state.container_top; } else if($(event_state.evnt.target).hasClass('resize-handle-sw') ){ width = event_state.container_width - (mouse.x - event_state.container_left); height = mouse.y - event_state.container_top; left = mouse.x; top = event_state.container_top; } else if($(event_state.evnt.target).hasClass('resize-handle-nw') ){ width = event_state.container_width - (mouse.x - event_state.container_left); height = event_state.container_height - (mouse.y - event_state.container_top); left = mouse.x; top = mouse.y; if(constrain || e.shiftKey){ top = mouse.y - ((width / orig_src.width * orig_src.height) - height); } } else if($(event_state.evnt.target).hasClass('resize-handle-ne') ){ width = mouse.x - event_state.container_left; height = event_state.container_height - (mouse.y - event_state.container_top); left = event_state.container_left; top = mouse.y; if(constrain || e.shiftKey){ top = mouse.y - ((width / orig_src.width * orig_src.height) - height); } } // Optionally maintain aspect ratio if(constrain || e.shiftKey){ height = width / orig_src.width * orig_src.height; } if(width > min_width && height > min_height && width < max_width && height < max_height){ // To improve performance you might limit how often resizeImage() is called resizeImage(width, height); // Without this Firefox will not re-calculate the the image dimensions until drag end $container.offset({'left': left, 'top': top}); } }







, resize-handle



, .





, , , , , "". . .



init = function(){ //... $container.on('mousedown', 'img', startMoving); }







startMoving



endMoving



, startResize



endResize



.



startMoving = function(e){ e.preventDefault(); e.stopPropagation(); saveEventState(e); $(document).on('mousemove', moving); $(document).on('mouseup', endMoving); }; endMoving = function(e){ e.preventDefault(); $(document).off('mouseup', endMoving); $(document).off('mousemove', moving); };







moving



. , .



moving = function(e){ var mouse={}; e.preventDefault(); e.stopPropagation(); mouse.x = (e.clientX || e.pageX) + $(window).scrollLeft(); mouse.y = (e.clientY || e.pageY) + $(window).scrollTop(); $container.offset({ 'left': mouse.x - ( event_state.mouse_x - event_state.container_left ), 'top': mouse.y - ( event_state.mouse_y - event_state.container_top ) }); };









, , . , , , , . , , , , .



HTML :



<div class="overlay"> <div class="overlay-inner"> </div> </div> <button class="btn-crop js-crop">Crop</button>







, , .



.overlay { position: absolute; left: 50%; top: 50%; margin-left: -100px; margin-top: -100px; z-index: 999; width: 200px; height: 200px; border: solid 2px rgba(222,60,80,.9); box-sizing: content-box; pointer-events: none; } .overlay:after, .overlay:before { content: ''; position: absolute; display: block; width: 204px; height: 40px; border-left: dashed 2px rgba(222,60,80,.9); border-right: dashed 2px rgba(222,60,80,.9); } .overlay:before { top: 0; margin-left: -2px; margin-top: -40px; } .overlay:after { bottom: 0; margin-left: -2px; margin-bottom: -40px; } .overlay-inner:after, .overlay-inner:before { content: ''; position: absolute; display: block; width: 40px; height: 204px; border-top: dashed 2px rgba(222,60,80,.9); border-bottom: dashed 2px rgba(222,60,80,.9); } .overlay-inner:before { left: 0; margin-left: -40px; margin-top: -2px; } .overlay-inner:after { right: 0; margin-right: -40px; margin-top: -2px; } .btn-crop { position: absolute; vertical-align: bottom; right: 5px; bottom: 5px; padding: 6px 10px; z-index: 999; background-color: rgb(222,60,80); border: none; border-radius: 5px; color: #FFF; }







JavaScript :



init = function(){ //... $('.js-crop').on('click', crop); }; crop = function(){ var crop_canvas, left = $('.overlay').offset().left - $container.offset().left, top = $('.overlay').offset().top - $container.offset().top, width = $('.overlay').width(), height = $('.overlay').height(); crop_canvas = document.createElement('canvas'); crop_canvas.width = width; crop_canvas.height = height; crop_canvas.getContext('2d').drawImage(image_target, left, top, width, height, 0, 0, width, height); window.open(crop_canvas.toDataURL("image/png")); }







crop



resizeImage



. , .



drawImage



canvas. - . - , . - , canvas, .





. .



mousedown



mouseup



- touchstart



touchend



, mousemove



touchmove



. , touchup



touchdown



( ).



touchstart



touchend



, mousedown



, mouseup



touchmove



, mousemove



.



// In init()... $container.on('mousedown touchstart', '.resize-handle', startResize); $container.on('mousedown touchstart', 'img', startMoving); //In startResize() ... $(document).on('mousemove touchmove', moving); $(document).on('mouseup touchend', endMoving); //In endResize()... $(document).off('mouseup touchend', endMoving); $(document).off('mousemove touchmove', moving); //In startMoving()... $(document).on('mousemove touchmove', moving); $(document).on('mouseup touchend', endMoving); //In endMoving()... $(document).off('mouseup touchend', endMoving); $(document).off('mousemove touchmove', moving);







, "" . Hammer, . , , .



, , , saveEventState



. .



" " . , . moving



:



moving = function(e){ var mouse={}, touches; e.preventDefault(); e.stopPropagation(); touches = e.originalEvent.touches; mouse.x = (e.clientX || e.pageX || touches[0].clientX) + $(window).scrollLeft(); mouse.y = (e.clientY || e.pageY || touches[0].clientY) + $(window).scrollTop(); $container.offset({ 'left': mouse.x - ( event_state.mouse_x - event_state.container_left ), 'top': mouse.y - ( event_state.mouse_y - event_state.container_top ) }); // Watch for pinch zoom gesture while moving if(event_state.touches && event_state.touches.length > 1 && touches.length > 1){ var width = event_state.container_width, height = event_state.container_height; var a = event_state.touches[0].clientX - event_state.touches[1].clientX; a = a * a; var b = event_state.touches[0].clientY - event_state.touches[1].clientY; b = b * b; var dist1 = Math.sqrt( a + b ); a = e.originalEvent.touches[0].clientX - touches[1].clientX; a = a * a; b = e.originalEvent.touches[0].clientY - touches[1].clientY; b = b * b; var dist2 = Math.sqrt( a + b ); var ratio = dist2 /dist1; width = width * ratio; height = height * ratio; // To improve performance you might limit how often resizeImage() is called resizeImage(width, height); } };







.







. .



Chrome "", Firefox .



, .




HTML5, , , .



- . , . , .



canvas




, , . , , .



. . , , . , .



!





:

<img class="resize-image" src="image.jpg" alt="Image" />







! HTML .



CSS

CSS- . resize-container



.



.resize-container { position: relative; display: inline-block; cursor: move; margin: 0 auto; } .resize-container img { display: block } .resize-container:hover img, .resize-container:active img { outline: 2px dashed rgba(222,60,80,.9); }







'resize handles'. , , .



.resize-handle-ne, .resize-handle-ne, .resize-handle-se, .resize-handle-nw, .resize-handle-sw { position: absolute; display: block; width: 10px; height: 10px; background: rgba(222,60,80,.9); z-index: 999; } .resize-handle-nw { top: -5px; left: -5px; cursor: nw-resize; } .resize-handle-sw { bottom: -5px; left: -5px; cursor: sw-resize; } .resize-handle-ne { top: -5px; right: -5px; cursor: ne-resize; } .resize-handle-se { bottom: -5px; right: -5px; cursor: se-resize; }







JavaScript

Canvas.



var resizeableImage = function(image_target) { var $container, orig_src = new Image(), image_target = $(image_target).get(0), event_state = {}, constrain = false, min_width = 60, min_height = 60, max_width = 800, max_height = 900, resize_canvas = document.createElement('canvas'); }); resizeableImage($('.resize-image'));







, . , , . jQuery , .



var resizeableImage = function(image_target) { // ... init = function(){ // Create a new image with a copy of the original src // When resizing, we will always use this original copy as the base orig_src.src=image_target.src; // Add resize handles $(image_target).wrap('<div class="resize-container"></div>') .before('<span class="resize-handle resize-handle-nw"></span>') .before('<span class="resize-handle resize-handle-ne"></span>') .after('<span class="resize-handle resize-handle-se"></span>') .after('<span class="resize-handle resize-handle-sw"></span>'); // Get a variable for the container $container = $(image_target).parent('.resize-container'); // Add events $container.on('mousedown', '.resize-handle', startResize); }; //... init(); }







startResize



endResize



, , .



startResize = function(e){ e.preventDefault(); e.stopPropagation(); saveEventState(e); $(document).on('mousemove', resizing); $(document).on('mouseup', endResize); }; endResize = function(e){ e.preventDefault(); $(document).off('mouseup touchend', endResize); $(document).off('mousemove touchmove', resizing); };







. event_state



.



saveEventState = function(e){ // Save the initial event details and container state event_state.container_width = $container.width(); event_state.container_height = $container.height(); event_state.container_left = $container.offset().left; event_state.container_top = $container.offset().top; event_state.mouse_x = (e.clientX || e.pageX || e.originalEvent.touches[0].clientX) + $(window).scrollLeft(); event_state.mouse_y = (e.clientY || e.pageY || e.originalEvent.touches[0].clientY) + $(window).scrollTop(); // This is a fix for mobile safari // For some reason it does not allow a direct copy of the touches property if(typeof e.originalEvent.touches !== 'undefined'){ event_state.touches = []; $.each(e.originalEvent.touches, function(i, ob){ event_state.touches[i] = {}; event_state.touches[i].clientX = 0+ob.clientX; event_state.touches[i].clientY = 0+ob.clientY; }); } event_state.evnt = e; }







resizing



- . . .



resizing = function(e){ var mouse={},width,height,left,top,offset=$container.offset(); mouse.x = (e.clientX || e.pageX || e.originalEvent.touches[0].clientX) + $(window).scrollLeft(); mouse.y = (e.clientY || e.pageY || e.originalEvent.touches[0].clientY) + $(window).scrollTop(); width = mouse.x - event_state.container_left; height = mouse.y - event_state.container_top; left = event_state.container_left; top = event_state.container_top; if(constrain || e.shiftKey){ height = width / orig_src.width * orig_src.height; } if(width > min_width && height > min_height && width < max_width && height < max_height){ resizeImage(width, height); // Without this Firefox will not re-calculate the the image dimensions until drag end $container.offset({'left': left, 'top': top}); } }







Shift .



.



: , , resizeImage



.





Canvas , drawImage



. , . toDataURL



Base64-encoded .



.



resizeImage = function(width, height){ resize_canvas.width = width; resize_canvas.height = height; resize_canvas.getContext('2d').drawImage(orig_src, 0, 0, width, height); $(image_target).attr('src', resize_canvas.toDataURL("image/png")); };







? : , CORS . , 'tainted canvas'.







. . , . , .



, , .







, . resizing



:



resizing = function(e){ var mouse={},width,height,left,top,offset=$container.offset(); mouse.x = (e.clientX || e.pageX || e.originalEvent.touches[0].clientX) + $(window).scrollLeft(); mouse.y = (e.clientY || e.pageY || e.originalEvent.touches[0].clientY) + $(window).scrollTop(); // Position image differently depending on the corner dragged and constraints if( $(event_state.evnt.target).hasClass('resize-handle-se') ){ width = mouse.x - event_state.container_left; height = mouse.y - event_state.container_top; left = event_state.container_left; top = event_state.container_top; } else if($(event_state.evnt.target).hasClass('resize-handle-sw') ){ width = event_state.container_width - (mouse.x - event_state.container_left); height = mouse.y - event_state.container_top; left = mouse.x; top = event_state.container_top; } else if($(event_state.evnt.target).hasClass('resize-handle-nw') ){ width = event_state.container_width - (mouse.x - event_state.container_left); height = event_state.container_height - (mouse.y - event_state.container_top); left = mouse.x; top = mouse.y; if(constrain || e.shiftKey){ top = mouse.y - ((width / orig_src.width * orig_src.height) - height); } } else if($(event_state.evnt.target).hasClass('resize-handle-ne') ){ width = mouse.x - event_state.container_left; height = event_state.container_height - (mouse.y - event_state.container_top); left = event_state.container_left; top = mouse.y; if(constrain || e.shiftKey){ top = mouse.y - ((width / orig_src.width * orig_src.height) - height); } } // Optionally maintain aspect ratio if(constrain || e.shiftKey){ height = width / orig_src.width * orig_src.height; } if(width > min_width && height > min_height && width < max_width && height < max_height){ // To improve performance you might limit how often resizeImage() is called resizeImage(width, height); // Without this Firefox will not re-calculate the the image dimensions until drag end $container.offset({'left': left, 'top': top}); } }







, resize-handle



, .





, , , , , "". . .



init = function(){ //... $container.on('mousedown', 'img', startMoving); }







startMoving



endMoving



, startResize



endResize



.



startMoving = function(e){ e.preventDefault(); e.stopPropagation(); saveEventState(e); $(document).on('mousemove', moving); $(document).on('mouseup', endMoving); }; endMoving = function(e){ e.preventDefault(); $(document).off('mouseup', endMoving); $(document).off('mousemove', moving); };







moving



. , .



moving = function(e){ var mouse={}; e.preventDefault(); e.stopPropagation(); mouse.x = (e.clientX || e.pageX) + $(window).scrollLeft(); mouse.y = (e.clientY || e.pageY) + $(window).scrollTop(); $container.offset({ 'left': mouse.x - ( event_state.mouse_x - event_state.container_left ), 'top': mouse.y - ( event_state.mouse_y - event_state.container_top ) }); };









, , . , , , , . , , , , .



HTML :



<div class="overlay"> <div class="overlay-inner"> </div> </div> <button class="btn-crop js-crop">Crop</button>







, , .



.overlay { position: absolute; left: 50%; top: 50%; margin-left: -100px; margin-top: -100px; z-index: 999; width: 200px; height: 200px; border: solid 2px rgba(222,60,80,.9); box-sizing: content-box; pointer-events: none; } .overlay:after, .overlay:before { content: ''; position: absolute; display: block; width: 204px; height: 40px; border-left: dashed 2px rgba(222,60,80,.9); border-right: dashed 2px rgba(222,60,80,.9); } .overlay:before { top: 0; margin-left: -2px; margin-top: -40px; } .overlay:after { bottom: 0; margin-left: -2px; margin-bottom: -40px; } .overlay-inner:after, .overlay-inner:before { content: ''; position: absolute; display: block; width: 40px; height: 204px; border-top: dashed 2px rgba(222,60,80,.9); border-bottom: dashed 2px rgba(222,60,80,.9); } .overlay-inner:before { left: 0; margin-left: -40px; margin-top: -2px; } .overlay-inner:after { right: 0; margin-right: -40px; margin-top: -2px; } .btn-crop { position: absolute; vertical-align: bottom; right: 5px; bottom: 5px; padding: 6px 10px; z-index: 999; background-color: rgb(222,60,80); border: none; border-radius: 5px; color: #FFF; }







JavaScript :



init = function(){ //... $('.js-crop').on('click', crop); }; crop = function(){ var crop_canvas, left = $('.overlay').offset().left - $container.offset().left, top = $('.overlay').offset().top - $container.offset().top, width = $('.overlay').width(), height = $('.overlay').height(); crop_canvas = document.createElement('canvas'); crop_canvas.width = width; crop_canvas.height = height; crop_canvas.getContext('2d').drawImage(image_target, left, top, width, height, 0, 0, width, height); window.open(crop_canvas.toDataURL("image/png")); }







crop



resizeImage



. , .



drawImage



canvas. - . - , . - , canvas, .





. .



mousedown



mouseup



- touchstart



touchend



, mousemove



touchmove



. , touchup



touchdown



( ).



touchstart



touchend



, mousedown



, mouseup



touchmove



, mousemove



.



// In init()... $container.on('mousedown touchstart', '.resize-handle', startResize); $container.on('mousedown touchstart', 'img', startMoving); //In startResize() ... $(document).on('mousemove touchmove', moving); $(document).on('mouseup touchend', endMoving); //In endResize()... $(document).off('mouseup touchend', endMoving); $(document).off('mousemove touchmove', moving); //In startMoving()... $(document).on('mousemove touchmove', moving); $(document).on('mouseup touchend', endMoving); //In endMoving()... $(document).off('mouseup touchend', endMoving); $(document).off('mousemove touchmove', moving);







, "" . Hammer, . , , .



, , , saveEventState



. .



" " . , . moving



:



moving = function(e){ var mouse={}, touches; e.preventDefault(); e.stopPropagation(); touches = e.originalEvent.touches; mouse.x = (e.clientX || e.pageX || touches[0].clientX) + $(window).scrollLeft(); mouse.y = (e.clientY || e.pageY || touches[0].clientY) + $(window).scrollTop(); $container.offset({ 'left': mouse.x - ( event_state.mouse_x - event_state.container_left ), 'top': mouse.y - ( event_state.mouse_y - event_state.container_top ) }); // Watch for pinch zoom gesture while moving if(event_state.touches && event_state.touches.length > 1 && touches.length > 1){ var width = event_state.container_width, height = event_state.container_height; var a = event_state.touches[0].clientX - event_state.touches[1].clientX; a = a * a; var b = event_state.touches[0].clientY - event_state.touches[1].clientY; b = b * b; var dist1 = Math.sqrt( a + b ); a = e.originalEvent.touches[0].clientX - touches[1].clientX; a = a * a; b = e.originalEvent.touches[0].clientY - touches[1].clientY; b = b * b; var dist2 = Math.sqrt( a + b ); var ratio = dist2 /dist1; width = width * ratio; height = height * ratio; // To improve performance you might limit how often resizeImage() is called resizeImage(width, height); } };







.







. .



Chrome "", Firefox .



, .




HTML5, , , .



- . , . , .



canvas




, , . , , .



. . , , . , .



!





:

<img class="resize-image" src="image.jpg" alt="Image" />







! HTML .



CSS

CSS- . resize-container



.



.resize-container { position: relative; display: inline-block; cursor: move; margin: 0 auto; } .resize-container img { display: block } .resize-container:hover img, .resize-container:active img { outline: 2px dashed rgba(222,60,80,.9); }







'resize handles'. , , .



.resize-handle-ne, .resize-handle-ne, .resize-handle-se, .resize-handle-nw, .resize-handle-sw { position: absolute; display: block; width: 10px; height: 10px; background: rgba(222,60,80,.9); z-index: 999; } .resize-handle-nw { top: -5px; left: -5px; cursor: nw-resize; } .resize-handle-sw { bottom: -5px; left: -5px; cursor: sw-resize; } .resize-handle-ne { top: -5px; right: -5px; cursor: ne-resize; } .resize-handle-se { bottom: -5px; right: -5px; cursor: se-resize; }







JavaScript

Canvas.



var resizeableImage = function(image_target) { var $container, orig_src = new Image(), image_target = $(image_target).get(0), event_state = {}, constrain = false, min_width = 60, min_height = 60, max_width = 800, max_height = 900, resize_canvas = document.createElement('canvas'); }); resizeableImage($('.resize-image'));







, . , , . jQuery , .



var resizeableImage = function(image_target) { // ... init = function(){ // Create a new image with a copy of the original src // When resizing, we will always use this original copy as the base orig_src.src=image_target.src; // Add resize handles $(image_target).wrap('<div class="resize-container"></div>') .before('<span class="resize-handle resize-handle-nw"></span>') .before('<span class="resize-handle resize-handle-ne"></span>') .after('<span class="resize-handle resize-handle-se"></span>') .after('<span class="resize-handle resize-handle-sw"></span>'); // Get a variable for the container $container = $(image_target).parent('.resize-container'); // Add events $container.on('mousedown', '.resize-handle', startResize); }; //... init(); }







startResize



endResize



, , .



startResize = function(e){ e.preventDefault(); e.stopPropagation(); saveEventState(e); $(document).on('mousemove', resizing); $(document).on('mouseup', endResize); }; endResize = function(e){ e.preventDefault(); $(document).off('mouseup touchend', endResize); $(document).off('mousemove touchmove', resizing); };







. event_state



.



saveEventState = function(e){ // Save the initial event details and container state event_state.container_width = $container.width(); event_state.container_height = $container.height(); event_state.container_left = $container.offset().left; event_state.container_top = $container.offset().top; event_state.mouse_x = (e.clientX || e.pageX || e.originalEvent.touches[0].clientX) + $(window).scrollLeft(); event_state.mouse_y = (e.clientY || e.pageY || e.originalEvent.touches[0].clientY) + $(window).scrollTop(); // This is a fix for mobile safari // For some reason it does not allow a direct copy of the touches property if(typeof e.originalEvent.touches !== 'undefined'){ event_state.touches = []; $.each(e.originalEvent.touches, function(i, ob){ event_state.touches[i] = {}; event_state.touches[i].clientX = 0+ob.clientX; event_state.touches[i].clientY = 0+ob.clientY; }); } event_state.evnt = e; }







resizing



- . . .



resizing = function(e){ var mouse={},width,height,left,top,offset=$container.offset(); mouse.x = (e.clientX || e.pageX || e.originalEvent.touches[0].clientX) + $(window).scrollLeft(); mouse.y = (e.clientY || e.pageY || e.originalEvent.touches[0].clientY) + $(window).scrollTop(); width = mouse.x - event_state.container_left; height = mouse.y - event_state.container_top; left = event_state.container_left; top = event_state.container_top; if(constrain || e.shiftKey){ height = width / orig_src.width * orig_src.height; } if(width > min_width && height > min_height && width < max_width && height < max_height){ resizeImage(width, height); // Without this Firefox will not re-calculate the the image dimensions until drag end $container.offset({'left': left, 'top': top}); } }







Shift .



.



: , , resizeImage



.





Canvas , drawImage



. , . toDataURL



Base64-encoded .



.



resizeImage = function(width, height){ resize_canvas.width = width; resize_canvas.height = height; resize_canvas.getContext('2d').drawImage(orig_src, 0, 0, width, height); $(image_target).attr('src', resize_canvas.toDataURL("image/png")); };







? : , CORS . , 'tainted canvas'.







. . , . , .



, , .







, . resizing



:



resizing = function(e){ var mouse={},width,height,left,top,offset=$container.offset(); mouse.x = (e.clientX || e.pageX || e.originalEvent.touches[0].clientX) + $(window).scrollLeft(); mouse.y = (e.clientY || e.pageY || e.originalEvent.touches[0].clientY) + $(window).scrollTop(); // Position image differently depending on the corner dragged and constraints if( $(event_state.evnt.target).hasClass('resize-handle-se') ){ width = mouse.x - event_state.container_left; height = mouse.y - event_state.container_top; left = event_state.container_left; top = event_state.container_top; } else if($(event_state.evnt.target).hasClass('resize-handle-sw') ){ width = event_state.container_width - (mouse.x - event_state.container_left); height = mouse.y - event_state.container_top; left = mouse.x; top = event_state.container_top; } else if($(event_state.evnt.target).hasClass('resize-handle-nw') ){ width = event_state.container_width - (mouse.x - event_state.container_left); height = event_state.container_height - (mouse.y - event_state.container_top); left = mouse.x; top = mouse.y; if(constrain || e.shiftKey){ top = mouse.y - ((width / orig_src.width * orig_src.height) - height); } } else if($(event_state.evnt.target).hasClass('resize-handle-ne') ){ width = mouse.x - event_state.container_left; height = event_state.container_height - (mouse.y - event_state.container_top); left = event_state.container_left; top = mouse.y; if(constrain || e.shiftKey){ top = mouse.y - ((width / orig_src.width * orig_src.height) - height); } } // Optionally maintain aspect ratio if(constrain || e.shiftKey){ height = width / orig_src.width * orig_src.height; } if(width > min_width && height > min_height && width < max_width && height < max_height){ // To improve performance you might limit how often resizeImage() is called resizeImage(width, height); // Without this Firefox will not re-calculate the the image dimensions until drag end $container.offset({'left': left, 'top': top}); } }







, resize-handle



, .





, , , , , "". . .



init = function(){ //... $container.on('mousedown', 'img', startMoving); }







startMoving



endMoving



, startResize



endResize



.



startMoving = function(e){ e.preventDefault(); e.stopPropagation(); saveEventState(e); $(document).on('mousemove', moving); $(document).on('mouseup', endMoving); }; endMoving = function(e){ e.preventDefault(); $(document).off('mouseup', endMoving); $(document).off('mousemove', moving); };







moving



. , .



moving = function(e){ var mouse={}; e.preventDefault(); e.stopPropagation(); mouse.x = (e.clientX || e.pageX) + $(window).scrollLeft(); mouse.y = (e.clientY || e.pageY) + $(window).scrollTop(); $container.offset({ 'left': mouse.x - ( event_state.mouse_x - event_state.container_left ), 'top': mouse.y - ( event_state.mouse_y - event_state.container_top ) }); };









, , . , , , , . , , , , .



HTML :



<div class="overlay"> <div class="overlay-inner"> </div> </div> <button class="btn-crop js-crop">Crop</button>







, , .



.overlay { position: absolute; left: 50%; top: 50%; margin-left: -100px; margin-top: -100px; z-index: 999; width: 200px; height: 200px; border: solid 2px rgba(222,60,80,.9); box-sizing: content-box; pointer-events: none; } .overlay:after, .overlay:before { content: ''; position: absolute; display: block; width: 204px; height: 40px; border-left: dashed 2px rgba(222,60,80,.9); border-right: dashed 2px rgba(222,60,80,.9); } .overlay:before { top: 0; margin-left: -2px; margin-top: -40px; } .overlay:after { bottom: 0; margin-left: -2px; margin-bottom: -40px; } .overlay-inner:after, .overlay-inner:before { content: ''; position: absolute; display: block; width: 40px; height: 204px; border-top: dashed 2px rgba(222,60,80,.9); border-bottom: dashed 2px rgba(222,60,80,.9); } .overlay-inner:before { left: 0; margin-left: -40px; margin-top: -2px; } .overlay-inner:after { right: 0; margin-right: -40px; margin-top: -2px; } .btn-crop { position: absolute; vertical-align: bottom; right: 5px; bottom: 5px; padding: 6px 10px; z-index: 999; background-color: rgb(222,60,80); border: none; border-radius: 5px; color: #FFF; }







JavaScript :



init = function(){ //... $('.js-crop').on('click', crop); }; crop = function(){ var crop_canvas, left = $('.overlay').offset().left - $container.offset().left, top = $('.overlay').offset().top - $container.offset().top, width = $('.overlay').width(), height = $('.overlay').height(); crop_canvas = document.createElement('canvas'); crop_canvas.width = width; crop_canvas.height = height; crop_canvas.getContext('2d').drawImage(image_target, left, top, width, height, 0, 0, width, height); window.open(crop_canvas.toDataURL("image/png")); }







crop



resizeImage



. , .



drawImage



canvas. - . - , . - , canvas, .





. .



mousedown



mouseup



- touchstart



touchend



, mousemove



touchmove



. , touchup



touchdown



( ).



touchstart



touchend



, mousedown



, mouseup



touchmove



, mousemove



.



// In init()... $container.on('mousedown touchstart', '.resize-handle', startResize); $container.on('mousedown touchstart', 'img', startMoving); //In startResize() ... $(document).on('mousemove touchmove', moving); $(document).on('mouseup touchend', endMoving); //In endResize()... $(document).off('mouseup touchend', endMoving); $(document).off('mousemove touchmove', moving); //In startMoving()... $(document).on('mousemove touchmove', moving); $(document).on('mouseup touchend', endMoving); //In endMoving()... $(document).off('mouseup touchend', endMoving); $(document).off('mousemove touchmove', moving);







, "" . Hammer, . , , .



, , , saveEventState



. .



" " . , . moving



:



moving = function(e){ var mouse={}, touches; e.preventDefault(); e.stopPropagation(); touches = e.originalEvent.touches; mouse.x = (e.clientX || e.pageX || touches[0].clientX) + $(window).scrollLeft(); mouse.y = (e.clientY || e.pageY || touches[0].clientY) + $(window).scrollTop(); $container.offset({ 'left': mouse.x - ( event_state.mouse_x - event_state.container_left ), 'top': mouse.y - ( event_state.mouse_y - event_state.container_top ) }); // Watch for pinch zoom gesture while moving if(event_state.touches && event_state.touches.length > 1 && touches.length > 1){ var width = event_state.container_width, height = event_state.container_height; var a = event_state.touches[0].clientX - event_state.touches[1].clientX; a = a * a; var b = event_state.touches[0].clientY - event_state.touches[1].clientY; b = b * b; var dist1 = Math.sqrt( a + b ); a = e.originalEvent.touches[0].clientX - touches[1].clientX; a = a * a; b = e.originalEvent.touches[0].clientY - touches[1].clientY; b = b * b; var dist2 = Math.sqrt( a + b ); var ratio = dist2 /dist1; width = width * ratio; height = height * ratio; // To improve performance you might limit how often resizeImage() is called resizeImage(width, height); } };







.







. .



Chrome "", Firefox .



, .




  HTML5,     ,      ,   . 
      



- . , . , .



canvas




, , . , , .



. . , , . , .



!





:

<img class="resize-image" src="image.jpg" alt="Image" />







! HTML .



CSS

CSS- . resize-container



.



.resize-container { position: relative; display: inline-block; cursor: move; margin: 0 auto; } .resize-container img { display: block } .resize-container:hover img, .resize-container:active img { outline: 2px dashed rgba(222,60,80,.9); }







'resize handles'. , , .



.resize-handle-ne, .resize-handle-ne, .resize-handle-se, .resize-handle-nw, .resize-handle-sw { position: absolute; display: block; width: 10px; height: 10px; background: rgba(222,60,80,.9); z-index: 999; } .resize-handle-nw { top: -5px; left: -5px; cursor: nw-resize; } .resize-handle-sw { bottom: -5px; left: -5px; cursor: sw-resize; } .resize-handle-ne { top: -5px; right: -5px; cursor: ne-resize; } .resize-handle-se { bottom: -5px; right: -5px; cursor: se-resize; }







JavaScript

Canvas.



var resizeableImage = function(image_target) { var $container, orig_src = new Image(), image_target = $(image_target).get(0), event_state = {}, constrain = false, min_width = 60, min_height = 60, max_width = 800, max_height = 900, resize_canvas = document.createElement('canvas'); }); resizeableImage($('.resize-image'));







, . , , . jQuery , .



var resizeableImage = function(image_target) { // ... init = function(){ // Create a new image with a copy of the original src // When resizing, we will always use this original copy as the base orig_src.src=image_target.src; // Add resize handles $(image_target).wrap('<div class="resize-container"></div>') .before('<span class="resize-handle resize-handle-nw"></span>') .before('<span class="resize-handle resize-handle-ne"></span>') .after('<span class="resize-handle resize-handle-se"></span>') .after('<span class="resize-handle resize-handle-sw"></span>'); // Get a variable for the container $container = $(image_target).parent('.resize-container'); // Add events $container.on('mousedown', '.resize-handle', startResize); }; //... init(); }







startResize



endResize



, , .



startResize = function(e){ e.preventDefault(); e.stopPropagation(); saveEventState(e); $(document).on('mousemove', resizing); $(document).on('mouseup', endResize); }; endResize = function(e){ e.preventDefault(); $(document).off('mouseup touchend', endResize); $(document).off('mousemove touchmove', resizing); };







. event_state



.



saveEventState = function(e){ // Save the initial event details and container state event_state.container_width = $container.width(); event_state.container_height = $container.height(); event_state.container_left = $container.offset().left; event_state.container_top = $container.offset().top; event_state.mouse_x = (e.clientX || e.pageX || e.originalEvent.touches[0].clientX) + $(window).scrollLeft(); event_state.mouse_y = (e.clientY || e.pageY || e.originalEvent.touches[0].clientY) + $(window).scrollTop(); // This is a fix for mobile safari // For some reason it does not allow a direct copy of the touches property if(typeof e.originalEvent.touches !== 'undefined'){ event_state.touches = []; $.each(e.originalEvent.touches, function(i, ob){ event_state.touches[i] = {}; event_state.touches[i].clientX = 0+ob.clientX; event_state.touches[i].clientY = 0+ob.clientY; }); } event_state.evnt = e; }







resizing



- . . .



resizing = function(e){ var mouse={},width,height,left,top,offset=$container.offset(); mouse.x = (e.clientX || e.pageX || e.originalEvent.touches[0].clientX) + $(window).scrollLeft(); mouse.y = (e.clientY || e.pageY || e.originalEvent.touches[0].clientY) + $(window).scrollTop(); width = mouse.x - event_state.container_left; height = mouse.y - event_state.container_top; left = event_state.container_left; top = event_state.container_top; if(constrain || e.shiftKey){ height = width / orig_src.width * orig_src.height; } if(width > min_width && height > min_height && width < max_width && height < max_height){ resizeImage(width, height); // Without this Firefox will not re-calculate the the image dimensions until drag end $container.offset({'left': left, 'top': top}); } }







Shift .



.



: , , resizeImage



.





Canvas , drawImage



. , . toDataURL



Base64-encoded .



.



resizeImage = function(width, height){ resize_canvas.width = width; resize_canvas.height = height; resize_canvas.getContext('2d').drawImage(orig_src, 0, 0, width, height); $(image_target).attr('src', resize_canvas.toDataURL("image/png")); };







? : , CORS . , 'tainted canvas'.







. . , . , .



, , .







, . resizing



:



resizing = function(e){ var mouse={},width,height,left,top,offset=$container.offset(); mouse.x = (e.clientX || e.pageX || e.originalEvent.touches[0].clientX) + $(window).scrollLeft(); mouse.y = (e.clientY || e.pageY || e.originalEvent.touches[0].clientY) + $(window).scrollTop(); // Position image differently depending on the corner dragged and constraints if( $(event_state.evnt.target).hasClass('resize-handle-se') ){ width = mouse.x - event_state.container_left; height = mouse.y - event_state.container_top; left = event_state.container_left; top = event_state.container_top; } else if($(event_state.evnt.target).hasClass('resize-handle-sw') ){ width = event_state.container_width - (mouse.x - event_state.container_left); height = mouse.y - event_state.container_top; left = mouse.x; top = event_state.container_top; } else if($(event_state.evnt.target).hasClass('resize-handle-nw') ){ width = event_state.container_width - (mouse.x - event_state.container_left); height = event_state.container_height - (mouse.y - event_state.container_top); left = mouse.x; top = mouse.y; if(constrain || e.shiftKey){ top = mouse.y - ((width / orig_src.width * orig_src.height) - height); } } else if($(event_state.evnt.target).hasClass('resize-handle-ne') ){ width = mouse.x - event_state.container_left; height = event_state.container_height - (mouse.y - event_state.container_top); left = event_state.container_left; top = mouse.y; if(constrain || e.shiftKey){ top = mouse.y - ((width / orig_src.width * orig_src.height) - height); } } // Optionally maintain aspect ratio if(constrain || e.shiftKey){ height = width / orig_src.width * orig_src.height; } if(width > min_width && height > min_height && width < max_width && height < max_height){ // To improve performance you might limit how often resizeImage() is called resizeImage(width, height); // Without this Firefox will not re-calculate the the image dimensions until drag end $container.offset({'left': left, 'top': top}); } }







, resize-handle



, .





, , , , , "". . .



init = function(){ //... $container.on('mousedown', 'img', startMoving); }







startMoving



endMoving



, startResize



endResize



.



startMoving = function(e){ e.preventDefault(); e.stopPropagation(); saveEventState(e); $(document).on('mousemove', moving); $(document).on('mouseup', endMoving); }; endMoving = function(e){ e.preventDefault(); $(document).off('mouseup', endMoving); $(document).off('mousemove', moving); };







moving



. , .



moving = function(e){ var mouse={}; e.preventDefault(); e.stopPropagation(); mouse.x = (e.clientX || e.pageX) + $(window).scrollLeft(); mouse.y = (e.clientY || e.pageY) + $(window).scrollTop(); $container.offset({ 'left': mouse.x - ( event_state.mouse_x - event_state.container_left ), 'top': mouse.y - ( event_state.mouse_y - event_state.container_top ) }); };









, , . , , , , . , , , , .



HTML :



<div class="overlay"> <div class="overlay-inner"> </div> </div> <button class="btn-crop js-crop">Crop</button>







, , .



.overlay { position: absolute; left: 50%; top: 50%; margin-left: -100px; margin-top: -100px; z-index: 999; width: 200px; height: 200px; border: solid 2px rgba(222,60,80,.9); box-sizing: content-box; pointer-events: none; } .overlay:after, .overlay:before { content: ''; position: absolute; display: block; width: 204px; height: 40px; border-left: dashed 2px rgba(222,60,80,.9); border-right: dashed 2px rgba(222,60,80,.9); } .overlay:before { top: 0; margin-left: -2px; margin-top: -40px; } .overlay:after { bottom: 0; margin-left: -2px; margin-bottom: -40px; } .overlay-inner:after, .overlay-inner:before { content: ''; position: absolute; display: block; width: 40px; height: 204px; border-top: dashed 2px rgba(222,60,80,.9); border-bottom: dashed 2px rgba(222,60,80,.9); } .overlay-inner:before { left: 0; margin-left: -40px; margin-top: -2px; } .overlay-inner:after { right: 0; margin-right: -40px; margin-top: -2px; } .btn-crop { position: absolute; vertical-align: bottom; right: 5px; bottom: 5px; padding: 6px 10px; z-index: 999; background-color: rgb(222,60,80); border: none; border-radius: 5px; color: #FFF; }







JavaScript :



init = function(){ //... $('.js-crop').on('click', crop); }; crop = function(){ var crop_canvas, left = $('.overlay').offset().left - $container.offset().left, top = $('.overlay').offset().top - $container.offset().top, width = $('.overlay').width(), height = $('.overlay').height(); crop_canvas = document.createElement('canvas'); crop_canvas.width = width; crop_canvas.height = height; crop_canvas.getContext('2d').drawImage(image_target, left, top, width, height, 0, 0, width, height); window.open(crop_canvas.toDataURL("image/png")); }







crop



resizeImage



. , .



drawImage



canvas. - . - , . - , canvas, .





. .



mousedown



mouseup



- touchstart



touchend



, mousemove



touchmove



. , touchup



touchdown



( ).



touchstart



touchend



, mousedown



, mouseup



touchmove



, mousemove



.



// In init()... $container.on('mousedown touchstart', '.resize-handle', startResize); $container.on('mousedown touchstart', 'img', startMoving); //In startResize() ... $(document).on('mousemove touchmove', moving); $(document).on('mouseup touchend', endMoving); //In endResize()... $(document).off('mouseup touchend', endMoving); $(document).off('mousemove touchmove', moving); //In startMoving()... $(document).on('mousemove touchmove', moving); $(document).on('mouseup touchend', endMoving); //In endMoving()... $(document).off('mouseup touchend', endMoving); $(document).off('mousemove touchmove', moving);







, "" . Hammer, . , , .



, , , saveEventState



. .



" " . , . moving



:



moving = function(e){ var mouse={}, touches; e.preventDefault(); e.stopPropagation(); touches = e.originalEvent.touches; mouse.x = (e.clientX || e.pageX || touches[0].clientX) + $(window).scrollLeft(); mouse.y = (e.clientY || e.pageY || touches[0].clientY) + $(window).scrollTop(); $container.offset({ 'left': mouse.x - ( event_state.mouse_x - event_state.container_left ), 'top': mouse.y - ( event_state.mouse_y - event_state.container_top ) }); // Watch for pinch zoom gesture while moving if(event_state.touches && event_state.touches.length > 1 && touches.length > 1){ var width = event_state.container_width, height = event_state.container_height; var a = event_state.touches[0].clientX - event_state.touches[1].clientX; a = a * a; var b = event_state.touches[0].clientY - event_state.touches[1].clientY; b = b * b; var dist1 = Math.sqrt( a + b ); a = e.originalEvent.touches[0].clientX - touches[1].clientX; a = a * a; b = e.originalEvent.touches[0].clientY - touches[1].clientY; b = b * b; var dist2 = Math.sqrt( a + b ); var ratio = dist2 /dist1; width = width * ratio; height = height * ratio; // To improve performance you might limit how often resizeImage() is called resizeImage(width, height); } };







.







. .



Chrome "", Firefox .



, .




HTML5, , , .



- . , . , .



canvas




, , . , , .



. . , , . , .



!





:

<img class="resize-image" src="image.jpg" alt="Image" />







! HTML .



CSS

CSS- . resize-container



.



.resize-container { position: relative; display: inline-block; cursor: move; margin: 0 auto; } .resize-container img { display: block } .resize-container:hover img, .resize-container:active img { outline: 2px dashed rgba(222,60,80,.9); }







'resize handles'. , , .



.resize-handle-ne, .resize-handle-ne, .resize-handle-se, .resize-handle-nw, .resize-handle-sw { position: absolute; display: block; width: 10px; height: 10px; background: rgba(222,60,80,.9); z-index: 999; } .resize-handle-nw { top: -5px; left: -5px; cursor: nw-resize; } .resize-handle-sw { bottom: -5px; left: -5px; cursor: sw-resize; } .resize-handle-ne { top: -5px; right: -5px; cursor: ne-resize; } .resize-handle-se { bottom: -5px; right: -5px; cursor: se-resize; }







JavaScript

Canvas.



var resizeableImage = function(image_target) { var $container, orig_src = new Image(), image_target = $(image_target).get(0), event_state = {}, constrain = false, min_width = 60, min_height = 60, max_width = 800, max_height = 900, resize_canvas = document.createElement('canvas'); }); resizeableImage($('.resize-image'));







, . , , . jQuery , .



var resizeableImage = function(image_target) { // ... init = function(){ // Create a new image with a copy of the original src // When resizing, we will always use this original copy as the base orig_src.src=image_target.src; // Add resize handles $(image_target).wrap('<div class="resize-container"></div>') .before('<span class="resize-handle resize-handle-nw"></span>') .before('<span class="resize-handle resize-handle-ne"></span>') .after('<span class="resize-handle resize-handle-se"></span>') .after('<span class="resize-handle resize-handle-sw"></span>'); // Get a variable for the container $container = $(image_target).parent('.resize-container'); // Add events $container.on('mousedown', '.resize-handle', startResize); }; //... init(); }







startResize



endResize



, , .



startResize = function(e){ e.preventDefault(); e.stopPropagation(); saveEventState(e); $(document).on('mousemove', resizing); $(document).on('mouseup', endResize); }; endResize = function(e){ e.preventDefault(); $(document).off('mouseup touchend', endResize); $(document).off('mousemove touchmove', resizing); };







. event_state



.



saveEventState = function(e){ // Save the initial event details and container state event_state.container_width = $container.width(); event_state.container_height = $container.height(); event_state.container_left = $container.offset().left; event_state.container_top = $container.offset().top; event_state.mouse_x = (e.clientX || e.pageX || e.originalEvent.touches[0].clientX) + $(window).scrollLeft(); event_state.mouse_y = (e.clientY || e.pageY || e.originalEvent.touches[0].clientY) + $(window).scrollTop(); // This is a fix for mobile safari // For some reason it does not allow a direct copy of the touches property if(typeof e.originalEvent.touches !== 'undefined'){ event_state.touches = []; $.each(e.originalEvent.touches, function(i, ob){ event_state.touches[i] = {}; event_state.touches[i].clientX = 0+ob.clientX; event_state.touches[i].clientY = 0+ob.clientY; }); } event_state.evnt = e; }







resizing



- . . .



resizing = function(e){ var mouse={},width,height,left,top,offset=$container.offset(); mouse.x = (e.clientX || e.pageX || e.originalEvent.touches[0].clientX) + $(window).scrollLeft(); mouse.y = (e.clientY || e.pageY || e.originalEvent.touches[0].clientY) + $(window).scrollTop(); width = mouse.x - event_state.container_left; height = mouse.y - event_state.container_top; left = event_state.container_left; top = event_state.container_top; if(constrain || e.shiftKey){ height = width / orig_src.width * orig_src.height; } if(width > min_width && height > min_height && width < max_width && height < max_height){ resizeImage(width, height); // Without this Firefox will not re-calculate the the image dimensions until drag end $container.offset({'left': left, 'top': top}); } }







Shift .



.



: , , resizeImage



.





Canvas , drawImage



. , . toDataURL



Base64-encoded .



.



resizeImage = function(width, height){ resize_canvas.width = width; resize_canvas.height = height; resize_canvas.getContext('2d').drawImage(orig_src, 0, 0, width, height); $(image_target).attr('src', resize_canvas.toDataURL("image/png")); };







? : , CORS . , 'tainted canvas'.







. . , . , .



, , .







, . resizing



:



resizing = function(e){ var mouse={},width,height,left,top,offset=$container.offset(); mouse.x = (e.clientX || e.pageX || e.originalEvent.touches[0].clientX) + $(window).scrollLeft(); mouse.y = (e.clientY || e.pageY || e.originalEvent.touches[0].clientY) + $(window).scrollTop(); // Position image differently depending on the corner dragged and constraints if( $(event_state.evnt.target).hasClass('resize-handle-se') ){ width = mouse.x - event_state.container_left; height = mouse.y - event_state.container_top; left = event_state.container_left; top = event_state.container_top; } else if($(event_state.evnt.target).hasClass('resize-handle-sw') ){ width = event_state.container_width - (mouse.x - event_state.container_left); height = mouse.y - event_state.container_top; left = mouse.x; top = event_state.container_top; } else if($(event_state.evnt.target).hasClass('resize-handle-nw') ){ width = event_state.container_width - (mouse.x - event_state.container_left); height = event_state.container_height - (mouse.y - event_state.container_top); left = mouse.x; top = mouse.y; if(constrain || e.shiftKey){ top = mouse.y - ((width / orig_src.width * orig_src.height) - height); } } else if($(event_state.evnt.target).hasClass('resize-handle-ne') ){ width = mouse.x - event_state.container_left; height = event_state.container_height - (mouse.y - event_state.container_top); left = event_state.container_left; top = mouse.y; if(constrain || e.shiftKey){ top = mouse.y - ((width / orig_src.width * orig_src.height) - height); } } // Optionally maintain aspect ratio if(constrain || e.shiftKey){ height = width / orig_src.width * orig_src.height; } if(width > min_width && height > min_height && width < max_width && height < max_height){ // To improve performance you might limit how often resizeImage() is called resizeImage(width, height); // Without this Firefox will not re-calculate the the image dimensions until drag end $container.offset({'left': left, 'top': top}); } }







, resize-handle



, .





, , , , , "". . .



init = function(){ //... $container.on('mousedown', 'img', startMoving); }







startMoving



endMoving



, startResize



endResize



.



startMoving = function(e){ e.preventDefault(); e.stopPropagation(); saveEventState(e); $(document).on('mousemove', moving); $(document).on('mouseup', endMoving); }; endMoving = function(e){ e.preventDefault(); $(document).off('mouseup', endMoving); $(document).off('mousemove', moving); };







moving



. , .



moving = function(e){ var mouse={}; e.preventDefault(); e.stopPropagation(); mouse.x = (e.clientX || e.pageX) + $(window).scrollLeft(); mouse.y = (e.clientY || e.pageY) + $(window).scrollTop(); $container.offset({ 'left': mouse.x - ( event_state.mouse_x - event_state.container_left ), 'top': mouse.y - ( event_state.mouse_y - event_state.container_top ) }); };









, , . , , , , . , , , , .



HTML :



<div class="overlay"> <div class="overlay-inner"> </div> </div> <button class="btn-crop js-crop">Crop</button>







, , .



.overlay { position: absolute; left: 50%; top: 50%; margin-left: -100px; margin-top: -100px; z-index: 999; width: 200px; height: 200px; border: solid 2px rgba(222,60,80,.9); box-sizing: content-box; pointer-events: none; } .overlay:after, .overlay:before { content: ''; position: absolute; display: block; width: 204px; height: 40px; border-left: dashed 2px rgba(222,60,80,.9); border-right: dashed 2px rgba(222,60,80,.9); } .overlay:before { top: 0; margin-left: -2px; margin-top: -40px; } .overlay:after { bottom: 0; margin-left: -2px; margin-bottom: -40px; } .overlay-inner:after, .overlay-inner:before { content: ''; position: absolute; display: block; width: 40px; height: 204px; border-top: dashed 2px rgba(222,60,80,.9); border-bottom: dashed 2px rgba(222,60,80,.9); } .overlay-inner:before { left: 0; margin-left: -40px; margin-top: -2px; } .overlay-inner:after { right: 0; margin-right: -40px; margin-top: -2px; } .btn-crop { position: absolute; vertical-align: bottom; right: 5px; bottom: 5px; padding: 6px 10px; z-index: 999; background-color: rgb(222,60,80); border: none; border-radius: 5px; color: #FFF; }







JavaScript :



init = function(){ //... $('.js-crop').on('click', crop); }; crop = function(){ var crop_canvas, left = $('.overlay').offset().left - $container.offset().left, top = $('.overlay').offset().top - $container.offset().top, width = $('.overlay').width(), height = $('.overlay').height(); crop_canvas = document.createElement('canvas'); crop_canvas.width = width; crop_canvas.height = height; crop_canvas.getContext('2d').drawImage(image_target, left, top, width, height, 0, 0, width, height); window.open(crop_canvas.toDataURL("image/png")); }







crop



resizeImage



. , .



drawImage



canvas. - . - , . - , canvas, .





. .



mousedown



mouseup



- touchstart



touchend



, mousemove



touchmove



. , touchup



touchdown



( ).



touchstart



touchend



, mousedown



, mouseup



touchmove



, mousemove



.



// In init()... $container.on('mousedown touchstart', '.resize-handle', startResize); $container.on('mousedown touchstart', 'img', startMoving); //In startResize() ... $(document).on('mousemove touchmove', moving); $(document).on('mouseup touchend', endMoving); //In endResize()... $(document).off('mouseup touchend', endMoving); $(document).off('mousemove touchmove', moving); //In startMoving()... $(document).on('mousemove touchmove', moving); $(document).on('mouseup touchend', endMoving); //In endMoving()... $(document).off('mouseup touchend', endMoving); $(document).off('mousemove touchmove', moving);







, "" . Hammer, . , , .



, , , saveEventState



. .



" " . , . moving



:



moving = function(e){ var mouse={}, touches; e.preventDefault(); e.stopPropagation(); touches = e.originalEvent.touches; mouse.x = (e.clientX || e.pageX || touches[0].clientX) + $(window).scrollLeft(); mouse.y = (e.clientY || e.pageY || touches[0].clientY) + $(window).scrollTop(); $container.offset({ 'left': mouse.x - ( event_state.mouse_x - event_state.container_left ), 'top': mouse.y - ( event_state.mouse_y - event_state.container_top ) }); // Watch for pinch zoom gesture while moving if(event_state.touches && event_state.touches.length > 1 && touches.length > 1){ var width = event_state.container_width, height = event_state.container_height; var a = event_state.touches[0].clientX - event_state.touches[1].clientX; a = a * a; var b = event_state.touches[0].clientY - event_state.touches[1].clientY; b = b * b; var dist1 = Math.sqrt( a + b ); a = e.originalEvent.touches[0].clientX - touches[1].clientX; a = a * a; b = e.originalEvent.touches[0].clientY - touches[1].clientY; b = b * b; var dist2 = Math.sqrt( a + b ); var ratio = dist2 /dist1; width = width * ratio; height = height * ratio; // To improve performance you might limit how often resizeImage() is called resizeImage(width, height); } };







.







. .



Chrome "", Firefox .



, .




  HTML5,     ,      ,   . 
      



- . , . , .



canvas




, , . , , .



. . , , . , .



!





:

<img class="resize-image" src="image.jpg" alt="Image" />







! HTML .



CSS

CSS- . resize-container



.



.resize-container { position: relative; display: inline-block; cursor: move; margin: 0 auto; } .resize-container img { display: block } .resize-container:hover img, .resize-container:active img { outline: 2px dashed rgba(222,60,80,.9); }







'resize handles'. , , .



.resize-handle-ne, .resize-handle-ne, .resize-handle-se, .resize-handle-nw, .resize-handle-sw { position: absolute; display: block; width: 10px; height: 10px; background: rgba(222,60,80,.9); z-index: 999; } .resize-handle-nw { top: -5px; left: -5px; cursor: nw-resize; } .resize-handle-sw { bottom: -5px; left: -5px; cursor: sw-resize; } .resize-handle-ne { top: -5px; right: -5px; cursor: ne-resize; } .resize-handle-se { bottom: -5px; right: -5px; cursor: se-resize; }







JavaScript

Canvas.



var resizeableImage = function(image_target) { var $container, orig_src = new Image(), image_target = $(image_target).get(0), event_state = {}, constrain = false, min_width = 60, min_height = 60, max_width = 800, max_height = 900, resize_canvas = document.createElement('canvas'); }); resizeableImage($('.resize-image'));







, . , , . jQuery , .



var resizeableImage = function(image_target) { // ... init = function(){ // Create a new image with a copy of the original src // When resizing, we will always use this original copy as the base orig_src.src=image_target.src; // Add resize handles $(image_target).wrap('<div class="resize-container"></div>') .before('<span class="resize-handle resize-handle-nw"></span>') .before('<span class="resize-handle resize-handle-ne"></span>') .after('<span class="resize-handle resize-handle-se"></span>') .after('<span class="resize-handle resize-handle-sw"></span>'); // Get a variable for the container $container = $(image_target).parent('.resize-container'); // Add events $container.on('mousedown', '.resize-handle', startResize); }; //... init(); }







startResize



endResize



, , .



startResize = function(e){ e.preventDefault(); e.stopPropagation(); saveEventState(e); $(document).on('mousemove', resizing); $(document).on('mouseup', endResize); }; endResize = function(e){ e.preventDefault(); $(document).off('mouseup touchend', endResize); $(document).off('mousemove touchmove', resizing); };







. event_state



.



saveEventState = function(e){ // Save the initial event details and container state event_state.container_width = $container.width(); event_state.container_height = $container.height(); event_state.container_left = $container.offset().left; event_state.container_top = $container.offset().top; event_state.mouse_x = (e.clientX || e.pageX || e.originalEvent.touches[0].clientX) + $(window).scrollLeft(); event_state.mouse_y = (e.clientY || e.pageY || e.originalEvent.touches[0].clientY) + $(window).scrollTop(); // This is a fix for mobile safari // For some reason it does not allow a direct copy of the touches property if(typeof e.originalEvent.touches !== 'undefined'){ event_state.touches = []; $.each(e.originalEvent.touches, function(i, ob){ event_state.touches[i] = {}; event_state.touches[i].clientX = 0+ob.clientX; event_state.touches[i].clientY = 0+ob.clientY; }); } event_state.evnt = e; }







resizing



- . . .



resizing = function(e){ var mouse={},width,height,left,top,offset=$container.offset(); mouse.x = (e.clientX || e.pageX || e.originalEvent.touches[0].clientX) + $(window).scrollLeft(); mouse.y = (e.clientY || e.pageY || e.originalEvent.touches[0].clientY) + $(window).scrollTop(); width = mouse.x - event_state.container_left; height = mouse.y - event_state.container_top; left = event_state.container_left; top = event_state.container_top; if(constrain || e.shiftKey){ height = width / orig_src.width * orig_src.height; } if(width > min_width && height > min_height && width < max_width && height < max_height){ resizeImage(width, height); // Without this Firefox will not re-calculate the the image dimensions until drag end $container.offset({'left': left, 'top': top}); } }







Shift .



.



: , , resizeImage



.





Canvas , drawImage



. , . toDataURL



Base64-encoded .



.



resizeImage = function(width, height){ resize_canvas.width = width; resize_canvas.height = height; resize_canvas.getContext('2d').drawImage(orig_src, 0, 0, width, height); $(image_target).attr('src', resize_canvas.toDataURL("image/png")); };







? : , CORS . , 'tainted canvas'.







. . , . , .



, , .







, . resizing



:



resizing = function(e){ var mouse={},width,height,left,top,offset=$container.offset(); mouse.x = (e.clientX || e.pageX || e.originalEvent.touches[0].clientX) + $(window).scrollLeft(); mouse.y = (e.clientY || e.pageY || e.originalEvent.touches[0].clientY) + $(window).scrollTop(); // Position image differently depending on the corner dragged and constraints if( $(event_state.evnt.target).hasClass('resize-handle-se') ){ width = mouse.x - event_state.container_left; height = mouse.y - event_state.container_top; left = event_state.container_left; top = event_state.container_top; } else if($(event_state.evnt.target).hasClass('resize-handle-sw') ){ width = event_state.container_width - (mouse.x - event_state.container_left); height = mouse.y - event_state.container_top; left = mouse.x; top = event_state.container_top; } else if($(event_state.evnt.target).hasClass('resize-handle-nw') ){ width = event_state.container_width - (mouse.x - event_state.container_left); height = event_state.container_height - (mouse.y - event_state.container_top); left = mouse.x; top = mouse.y; if(constrain || e.shiftKey){ top = mouse.y - ((width / orig_src.width * orig_src.height) - height); } } else if($(event_state.evnt.target).hasClass('resize-handle-ne') ){ width = mouse.x - event_state.container_left; height = event_state.container_height - (mouse.y - event_state.container_top); left = event_state.container_left; top = mouse.y; if(constrain || e.shiftKey){ top = mouse.y - ((width / orig_src.width * orig_src.height) - height); } } // Optionally maintain aspect ratio if(constrain || e.shiftKey){ height = width / orig_src.width * orig_src.height; } if(width > min_width && height > min_height && width < max_width && height < max_height){ // To improve performance you might limit how often resizeImage() is called resizeImage(width, height); // Without this Firefox will not re-calculate the the image dimensions until drag end $container.offset({'left': left, 'top': top}); } }







, resize-handle



, .





, , , , , "". . .



init = function(){ //... $container.on('mousedown', 'img', startMoving); }







startMoving



endMoving



, startResize



endResize



.



startMoving = function(e){ e.preventDefault(); e.stopPropagation(); saveEventState(e); $(document).on('mousemove', moving); $(document).on('mouseup', endMoving); }; endMoving = function(e){ e.preventDefault(); $(document).off('mouseup', endMoving); $(document).off('mousemove', moving); };







moving



. , .



moving = function(e){ var mouse={}; e.preventDefault(); e.stopPropagation(); mouse.x = (e.clientX || e.pageX) + $(window).scrollLeft(); mouse.y = (e.clientY || e.pageY) + $(window).scrollTop(); $container.offset({ 'left': mouse.x - ( event_state.mouse_x - event_state.container_left ), 'top': mouse.y - ( event_state.mouse_y - event_state.container_top ) }); };









, , . , , , , . , , , , .



HTML :



<div class="overlay"> <div class="overlay-inner"> </div> </div> <button class="btn-crop js-crop">Crop</button>







, , .



.overlay { position: absolute; left: 50%; top: 50%; margin-left: -100px; margin-top: -100px; z-index: 999; width: 200px; height: 200px; border: solid 2px rgba(222,60,80,.9); box-sizing: content-box; pointer-events: none; } .overlay:after, .overlay:before { content: ''; position: absolute; display: block; width: 204px; height: 40px; border-left: dashed 2px rgba(222,60,80,.9); border-right: dashed 2px rgba(222,60,80,.9); } .overlay:before { top: 0; margin-left: -2px; margin-top: -40px; } .overlay:after { bottom: 0; margin-left: -2px; margin-bottom: -40px; } .overlay-inner:after, .overlay-inner:before { content: ''; position: absolute; display: block; width: 40px; height: 204px; border-top: dashed 2px rgba(222,60,80,.9); border-bottom: dashed 2px rgba(222,60,80,.9); } .overlay-inner:before { left: 0; margin-left: -40px; margin-top: -2px; } .overlay-inner:after { right: 0; margin-right: -40px; margin-top: -2px; } .btn-crop { position: absolute; vertical-align: bottom; right: 5px; bottom: 5px; padding: 6px 10px; z-index: 999; background-color: rgb(222,60,80); border: none; border-radius: 5px; color: #FFF; }







JavaScript :



init = function(){ //... $('.js-crop').on('click', crop); }; crop = function(){ var crop_canvas, left = $('.overlay').offset().left - $container.offset().left, top = $('.overlay').offset().top - $container.offset().top, width = $('.overlay').width(), height = $('.overlay').height(); crop_canvas = document.createElement('canvas'); crop_canvas.width = width; crop_canvas.height = height; crop_canvas.getContext('2d').drawImage(image_target, left, top, width, height, 0, 0, width, height); window.open(crop_canvas.toDataURL("image/png")); }







crop



resizeImage



. , .



drawImage



canvas. - . - , . - , canvas, .





. .



mousedown



mouseup



- touchstart



touchend



, mousemove



touchmove



. , touchup



touchdown



( ).



touchstart



touchend



, mousedown



, mouseup



touchmove



, mousemove



.



// In init()... $container.on('mousedown touchstart', '.resize-handle', startResize); $container.on('mousedown touchstart', 'img', startMoving); //In startResize() ... $(document).on('mousemove touchmove', moving); $(document).on('mouseup touchend', endMoving); //In endResize()... $(document).off('mouseup touchend', endMoving); $(document).off('mousemove touchmove', moving); //In startMoving()... $(document).on('mousemove touchmove', moving); $(document).on('mouseup touchend', endMoving); //In endMoving()... $(document).off('mouseup touchend', endMoving); $(document).off('mousemove touchmove', moving);







, "" . Hammer, . , , .



, , , saveEventState



. .



" " . , . moving



:



moving = function(e){ var mouse={}, touches; e.preventDefault(); e.stopPropagation(); touches = e.originalEvent.touches; mouse.x = (e.clientX || e.pageX || touches[0].clientX) + $(window).scrollLeft(); mouse.y = (e.clientY || e.pageY || touches[0].clientY) + $(window).scrollTop(); $container.offset({ 'left': mouse.x - ( event_state.mouse_x - event_state.container_left ), 'top': mouse.y - ( event_state.mouse_y - event_state.container_top ) }); // Watch for pinch zoom gesture while moving if(event_state.touches && event_state.touches.length > 1 && touches.length > 1){ var width = event_state.container_width, height = event_state.container_height; var a = event_state.touches[0].clientX - event_state.touches[1].clientX; a = a * a; var b = event_state.touches[0].clientY - event_state.touches[1].clientY; b = b * b; var dist1 = Math.sqrt( a + b ); a = e.originalEvent.touches[0].clientX - touches[1].clientX; a = a * a; b = e.originalEvent.touches[0].clientY - touches[1].clientY; b = b * b; var dist2 = Math.sqrt( a + b ); var ratio = dist2 /dist1; width = width * ratio; height = height * ratio; // To improve performance you might limit how often resizeImage() is called resizeImage(width, height); } };







.







. .



Chrome "", Firefox .



, .




HTML5, , , .



- . , . , .



canvas




, , . , , .



. . , , . , .



!





:

<img class="resize-image" src="image.jpg" alt="Image" />







! HTML .



CSS

CSS- . resize-container



.



.resize-container { position: relative; display: inline-block; cursor: move; margin: 0 auto; } .resize-container img { display: block } .resize-container:hover img, .resize-container:active img { outline: 2px dashed rgba(222,60,80,.9); }







'resize handles'. , , .



.resize-handle-ne, .resize-handle-ne, .resize-handle-se, .resize-handle-nw, .resize-handle-sw { position: absolute; display: block; width: 10px; height: 10px; background: rgba(222,60,80,.9); z-index: 999; } .resize-handle-nw { top: -5px; left: -5px; cursor: nw-resize; } .resize-handle-sw { bottom: -5px; left: -5px; cursor: sw-resize; } .resize-handle-ne { top: -5px; right: -5px; cursor: ne-resize; } .resize-handle-se { bottom: -5px; right: -5px; cursor: se-resize; }







JavaScript

Canvas.



var resizeableImage = function(image_target) { var $container, orig_src = new Image(), image_target = $(image_target).get(0), event_state = {}, constrain = false, min_width = 60, min_height = 60, max_width = 800, max_height = 900, resize_canvas = document.createElement('canvas'); }); resizeableImage($('.resize-image'));







, . , , . jQuery , .



var resizeableImage = function(image_target) { // ... init = function(){ // Create a new image with a copy of the original src // When resizing, we will always use this original copy as the base orig_src.src=image_target.src; // Add resize handles $(image_target).wrap('<div class="resize-container"></div>') .before('<span class="resize-handle resize-handle-nw"></span>') .before('<span class="resize-handle resize-handle-ne"></span>') .after('<span class="resize-handle resize-handle-se"></span>') .after('<span class="resize-handle resize-handle-sw"></span>'); // Get a variable for the container $container = $(image_target).parent('.resize-container'); // Add events $container.on('mousedown', '.resize-handle', startResize); }; //... init(); }







startResize



endResize



, , .



startResize = function(e){ e.preventDefault(); e.stopPropagation(); saveEventState(e); $(document).on('mousemove', resizing); $(document).on('mouseup', endResize); }; endResize = function(e){ e.preventDefault(); $(document).off('mouseup touchend', endResize); $(document).off('mousemove touchmove', resizing); };







. event_state



.



saveEventState = function(e){ // Save the initial event details and container state event_state.container_width = $container.width(); event_state.container_height = $container.height(); event_state.container_left = $container.offset().left; event_state.container_top = $container.offset().top; event_state.mouse_x = (e.clientX || e.pageX || e.originalEvent.touches[0].clientX) + $(window).scrollLeft(); event_state.mouse_y = (e.clientY || e.pageY || e.originalEvent.touches[0].clientY) + $(window).scrollTop(); // This is a fix for mobile safari // For some reason it does not allow a direct copy of the touches property if(typeof e.originalEvent.touches !== 'undefined'){ event_state.touches = []; $.each(e.originalEvent.touches, function(i, ob){ event_state.touches[i] = {}; event_state.touches[i].clientX = 0+ob.clientX; event_state.touches[i].clientY = 0+ob.clientY; }); } event_state.evnt = e; }







resizing



- . . .



resizing = function(e){ var mouse={},width,height,left,top,offset=$container.offset(); mouse.x = (e.clientX || e.pageX || e.originalEvent.touches[0].clientX) + $(window).scrollLeft(); mouse.y = (e.clientY || e.pageY || e.originalEvent.touches[0].clientY) + $(window).scrollTop(); width = mouse.x - event_state.container_left; height = mouse.y - event_state.container_top; left = event_state.container_left; top = event_state.container_top; if(constrain || e.shiftKey){ height = width / orig_src.width * orig_src.height; } if(width > min_width && height > min_height && width < max_width && height < max_height){ resizeImage(width, height); // Without this Firefox will not re-calculate the the image dimensions until drag end $container.offset({'left': left, 'top': top}); } }







Shift .



.



: , , resizeImage



.





Canvas , drawImage



. , . toDataURL



Base64-encoded .



.



resizeImage = function(width, height){ resize_canvas.width = width; resize_canvas.height = height; resize_canvas.getContext('2d').drawImage(orig_src, 0, 0, width, height); $(image_target).attr('src', resize_canvas.toDataURL("image/png")); };







? : , CORS . , 'tainted canvas'.







. . , . , .



, , .







, . resizing



:



resizing = function(e){ var mouse={},width,height,left,top,offset=$container.offset(); mouse.x = (e.clientX || e.pageX || e.originalEvent.touches[0].clientX) + $(window).scrollLeft(); mouse.y = (e.clientY || e.pageY || e.originalEvent.touches[0].clientY) + $(window).scrollTop(); // Position image differently depending on the corner dragged and constraints if( $(event_state.evnt.target).hasClass('resize-handle-se') ){ width = mouse.x - event_state.container_left; height = mouse.y - event_state.container_top; left = event_state.container_left; top = event_state.container_top; } else if($(event_state.evnt.target).hasClass('resize-handle-sw') ){ width = event_state.container_width - (mouse.x - event_state.container_left); height = mouse.y - event_state.container_top; left = mouse.x; top = event_state.container_top; } else if($(event_state.evnt.target).hasClass('resize-handle-nw') ){ width = event_state.container_width - (mouse.x - event_state.container_left); height = event_state.container_height - (mouse.y - event_state.container_top); left = mouse.x; top = mouse.y; if(constrain || e.shiftKey){ top = mouse.y - ((width / orig_src.width * orig_src.height) - height); } } else if($(event_state.evnt.target).hasClass('resize-handle-ne') ){ width = mouse.x - event_state.container_left; height = event_state.container_height - (mouse.y - event_state.container_top); left = event_state.container_left; top = mouse.y; if(constrain || e.shiftKey){ top = mouse.y - ((width / orig_src.width * orig_src.height) - height); } } // Optionally maintain aspect ratio if(constrain || e.shiftKey){ height = width / orig_src.width * orig_src.height; } if(width > min_width && height > min_height && width < max_width && height < max_height){ // To improve performance you might limit how often resizeImage() is called resizeImage(width, height); // Without this Firefox will not re-calculate the the image dimensions until drag end $container.offset({'left': left, 'top': top}); } }







, resize-handle



, .





, , , , , "". . .



init = function(){ //... $container.on('mousedown', 'img', startMoving); }







startMoving



endMoving



, startResize



endResize



.



startMoving = function(e){ e.preventDefault(); e.stopPropagation(); saveEventState(e); $(document).on('mousemove', moving); $(document).on('mouseup', endMoving); }; endMoving = function(e){ e.preventDefault(); $(document).off('mouseup', endMoving); $(document).off('mousemove', moving); };







moving



. , .



moving = function(e){ var mouse={}; e.preventDefault(); e.stopPropagation(); mouse.x = (e.clientX || e.pageX) + $(window).scrollLeft(); mouse.y = (e.clientY || e.pageY) + $(window).scrollTop(); $container.offset({ 'left': mouse.x - ( event_state.mouse_x - event_state.container_left ), 'top': mouse.y - ( event_state.mouse_y - event_state.container_top ) }); };









, , . , , , , . , , , , .



HTML :



<div class="overlay"> <div class="overlay-inner"> </div> </div> <button class="btn-crop js-crop">Crop</button>







, , .



.overlay { position: absolute; left: 50%; top: 50%; margin-left: -100px; margin-top: -100px; z-index: 999; width: 200px; height: 200px; border: solid 2px rgba(222,60,80,.9); box-sizing: content-box; pointer-events: none; } .overlay:after, .overlay:before { content: ''; position: absolute; display: block; width: 204px; height: 40px; border-left: dashed 2px rgba(222,60,80,.9); border-right: dashed 2px rgba(222,60,80,.9); } .overlay:before { top: 0; margin-left: -2px; margin-top: -40px; } .overlay:after { bottom: 0; margin-left: -2px; margin-bottom: -40px; } .overlay-inner:after, .overlay-inner:before { content: ''; position: absolute; display: block; width: 40px; height: 204px; border-top: dashed 2px rgba(222,60,80,.9); border-bottom: dashed 2px rgba(222,60,80,.9); } .overlay-inner:before { left: 0; margin-left: -40px; margin-top: -2px; } .overlay-inner:after { right: 0; margin-right: -40px; margin-top: -2px; } .btn-crop { position: absolute; vertical-align: bottom; right: 5px; bottom: 5px; padding: 6px 10px; z-index: 999; background-color: rgb(222,60,80); border: none; border-radius: 5px; color: #FFF; }







JavaScript :



init = function(){ //... $('.js-crop').on('click', crop); }; crop = function(){ var crop_canvas, left = $('.overlay').offset().left - $container.offset().left, top = $('.overlay').offset().top - $container.offset().top, width = $('.overlay').width(), height = $('.overlay').height(); crop_canvas = document.createElement('canvas'); crop_canvas.width = width; crop_canvas.height = height; crop_canvas.getContext('2d').drawImage(image_target, left, top, width, height, 0, 0, width, height); window.open(crop_canvas.toDataURL("image/png")); }







crop



resizeImage



. , .



drawImage



canvas. - . - , . - , canvas, .





. .



mousedown



mouseup



- touchstart



touchend



, mousemove



touchmove



. , touchup



touchdown



( ).



touchstart



touchend



, mousedown



, mouseup



touchmove



, mousemove



.



// In init()... $container.on('mousedown touchstart', '.resize-handle', startResize); $container.on('mousedown touchstart', 'img', startMoving); //In startResize() ... $(document).on('mousemove touchmove', moving); $(document).on('mouseup touchend', endMoving); //In endResize()... $(document).off('mouseup touchend', endMoving); $(document).off('mousemove touchmove', moving); //In startMoving()... $(document).on('mousemove touchmove', moving); $(document).on('mouseup touchend', endMoving); //In endMoving()... $(document).off('mouseup touchend', endMoving); $(document).off('mousemove touchmove', moving);







, "" . Hammer, . , , .



, , , saveEventState



. .



" " . , . moving



:



moving = function(e){ var mouse={}, touches; e.preventDefault(); e.stopPropagation(); touches = e.originalEvent.touches; mouse.x = (e.clientX || e.pageX || touches[0].clientX) + $(window).scrollLeft(); mouse.y = (e.clientY || e.pageY || touches[0].clientY) + $(window).scrollTop(); $container.offset({ 'left': mouse.x - ( event_state.mouse_x - event_state.container_left ), 'top': mouse.y - ( event_state.mouse_y - event_state.container_top ) }); // Watch for pinch zoom gesture while moving if(event_state.touches && event_state.touches.length > 1 && touches.length > 1){ var width = event_state.container_width, height = event_state.container_height; var a = event_state.touches[0].clientX - event_state.touches[1].clientX; a = a * a; var b = event_state.touches[0].clientY - event_state.touches[1].clientY; b = b * b; var dist1 = Math.sqrt( a + b ); a = e.originalEvent.touches[0].clientX - touches[1].clientX; a = a * a; b = e.originalEvent.touches[0].clientY - touches[1].clientY; b = b * b; var dist2 = Math.sqrt( a + b ); var ratio = dist2 /dist1; width = width * ratio; height = height * ratio; // To improve performance you might limit how often resizeImage() is called resizeImage(width, height); } };







.







. .



Chrome "", Firefox .



, .




  HTML5,     ,      ,   . 
      



- . , . , .



canvas




, , . , , .



. . , , . , .



!





:

<img class="resize-image" src="image.jpg" alt="Image" />







! HTML .



CSS

CSS- . resize-container



.



.resize-container { position: relative; display: inline-block; cursor: move; margin: 0 auto; } .resize-container img { display: block } .resize-container:hover img, .resize-container:active img { outline: 2px dashed rgba(222,60,80,.9); }







'resize handles'. , , .



.resize-handle-ne, .resize-handle-ne, .resize-handle-se, .resize-handle-nw, .resize-handle-sw { position: absolute; display: block; width: 10px; height: 10px; background: rgba(222,60,80,.9); z-index: 999; } .resize-handle-nw { top: -5px; left: -5px; cursor: nw-resize; } .resize-handle-sw { bottom: -5px; left: -5px; cursor: sw-resize; } .resize-handle-ne { top: -5px; right: -5px; cursor: ne-resize; } .resize-handle-se { bottom: -5px; right: -5px; cursor: se-resize; }







JavaScript

Canvas.



var resizeableImage = function(image_target) { var $container, orig_src = new Image(), image_target = $(image_target).get(0), event_state = {}, constrain = false, min_width = 60, min_height = 60, max_width = 800, max_height = 900, resize_canvas = document.createElement('canvas'); }); resizeableImage($('.resize-image'));







, . , , . jQuery , .



var resizeableImage = function(image_target) { // ... init = function(){ // Create a new image with a copy of the original src // When resizing, we will always use this original copy as the base orig_src.src=image_target.src; // Add resize handles $(image_target).wrap('<div class="resize-container"></div>') .before('<span class="resize-handle resize-handle-nw"></span>') .before('<span class="resize-handle resize-handle-ne"></span>') .after('<span class="resize-handle resize-handle-se"></span>') .after('<span class="resize-handle resize-handle-sw"></span>'); // Get a variable for the container $container = $(image_target).parent('.resize-container'); // Add events $container.on('mousedown', '.resize-handle', startResize); }; //... init(); }







startResize



endResize



, , .



startResize = function(e){ e.preventDefault(); e.stopPropagation(); saveEventState(e); $(document).on('mousemove', resizing); $(document).on('mouseup', endResize); }; endResize = function(e){ e.preventDefault(); $(document).off('mouseup touchend', endResize); $(document).off('mousemove touchmove', resizing); };







. event_state



.



saveEventState = function(e){ // Save the initial event details and container state event_state.container_width = $container.width(); event_state.container_height = $container.height(); event_state.container_left = $container.offset().left; event_state.container_top = $container.offset().top; event_state.mouse_x = (e.clientX || e.pageX || e.originalEvent.touches[0].clientX) + $(window).scrollLeft(); event_state.mouse_y = (e.clientY || e.pageY || e.originalEvent.touches[0].clientY) + $(window).scrollTop(); // This is a fix for mobile safari // For some reason it does not allow a direct copy of the touches property if(typeof e.originalEvent.touches !== 'undefined'){ event_state.touches = []; $.each(e.originalEvent.touches, function(i, ob){ event_state.touches[i] = {}; event_state.touches[i].clientX = 0+ob.clientX; event_state.touches[i].clientY = 0+ob.clientY; }); } event_state.evnt = e; }







resizing



- . . .



resizing = function(e){ var mouse={},width,height,left,top,offset=$container.offset(); mouse.x = (e.clientX || e.pageX || e.originalEvent.touches[0].clientX) + $(window).scrollLeft(); mouse.y = (e.clientY || e.pageY || e.originalEvent.touches[0].clientY) + $(window).scrollTop(); width = mouse.x - event_state.container_left; height = mouse.y - event_state.container_top; left = event_state.container_left; top = event_state.container_top; if(constrain || e.shiftKey){ height = width / orig_src.width * orig_src.height; } if(width > min_width && height > min_height && width < max_width && height < max_height){ resizeImage(width, height); // Without this Firefox will not re-calculate the the image dimensions until drag end $container.offset({'left': left, 'top': top}); } }







Shift .



.



: , , resizeImage



.





Canvas , drawImage



. , . toDataURL



Base64-encoded .



.



resizeImage = function(width, height){ resize_canvas.width = width; resize_canvas.height = height; resize_canvas.getContext('2d').drawImage(orig_src, 0, 0, width, height); $(image_target).attr('src', resize_canvas.toDataURL("image/png")); };







? : , CORS . , 'tainted canvas'.







. . , . , .



, , .







, . resizing



:



resizing = function(e){ var mouse={},width,height,left,top,offset=$container.offset(); mouse.x = (e.clientX || e.pageX || e.originalEvent.touches[0].clientX) + $(window).scrollLeft(); mouse.y = (e.clientY || e.pageY || e.originalEvent.touches[0].clientY) + $(window).scrollTop(); // Position image differently depending on the corner dragged and constraints if( $(event_state.evnt.target).hasClass('resize-handle-se') ){ width = mouse.x - event_state.container_left; height = mouse.y - event_state.container_top; left = event_state.container_left; top = event_state.container_top; } else if($(event_state.evnt.target).hasClass('resize-handle-sw') ){ width = event_state.container_width - (mouse.x - event_state.container_left); height = mouse.y - event_state.container_top; left = mouse.x; top = event_state.container_top; } else if($(event_state.evnt.target).hasClass('resize-handle-nw') ){ width = event_state.container_width - (mouse.x - event_state.container_left); height = event_state.container_height - (mouse.y - event_state.container_top); left = mouse.x; top = mouse.y; if(constrain || e.shiftKey){ top = mouse.y - ((width / orig_src.width * orig_src.height) - height); } } else if($(event_state.evnt.target).hasClass('resize-handle-ne') ){ width = mouse.x - event_state.container_left; height = event_state.container_height - (mouse.y - event_state.container_top); left = event_state.container_left; top = mouse.y; if(constrain || e.shiftKey){ top = mouse.y - ((width / orig_src.width * orig_src.height) - height); } } // Optionally maintain aspect ratio if(constrain || e.shiftKey){ height = width / orig_src.width * orig_src.height; } if(width > min_width && height > min_height && width < max_width && height < max_height){ // To improve performance you might limit how often resizeImage() is called resizeImage(width, height); // Without this Firefox will not re-calculate the the image dimensions until drag end $container.offset({'left': left, 'top': top}); } }







, resize-handle



, .





, , , , , "". . .



init = function(){ //... $container.on('mousedown', 'img', startMoving); }







startMoving



endMoving



, startResize



endResize



.



startMoving = function(e){ e.preventDefault(); e.stopPropagation(); saveEventState(e); $(document).on('mousemove', moving); $(document).on('mouseup', endMoving); }; endMoving = function(e){ e.preventDefault(); $(document).off('mouseup', endMoving); $(document).off('mousemove', moving); };







moving



. , .



moving = function(e){ var mouse={}; e.preventDefault(); e.stopPropagation(); mouse.x = (e.clientX || e.pageX) + $(window).scrollLeft(); mouse.y = (e.clientY || e.pageY) + $(window).scrollTop(); $container.offset({ 'left': mouse.x - ( event_state.mouse_x - event_state.container_left ), 'top': mouse.y - ( event_state.mouse_y - event_state.container_top ) }); };









, , . , , , , . , , , , .



HTML :



<div class="overlay"> <div class="overlay-inner"> </div> </div> <button class="btn-crop js-crop">Crop</button>







, , .



.overlay { position: absolute; left: 50%; top: 50%; margin-left: -100px; margin-top: -100px; z-index: 999; width: 200px; height: 200px; border: solid 2px rgba(222,60,80,.9); box-sizing: content-box; pointer-events: none; } .overlay:after, .overlay:before { content: ''; position: absolute; display: block; width: 204px; height: 40px; border-left: dashed 2px rgba(222,60,80,.9); border-right: dashed 2px rgba(222,60,80,.9); } .overlay:before { top: 0; margin-left: -2px; margin-top: -40px; } .overlay:after { bottom: 0; margin-left: -2px; margin-bottom: -40px; } .overlay-inner:after, .overlay-inner:before { content: ''; position: absolute; display: block; width: 40px; height: 204px; border-top: dashed 2px rgba(222,60,80,.9); border-bottom: dashed 2px rgba(222,60,80,.9); } .overlay-inner:before { left: 0; margin-left: -40px; margin-top: -2px; } .overlay-inner:after { right: 0; margin-right: -40px; margin-top: -2px; } .btn-crop { position: absolute; vertical-align: bottom; right: 5px; bottom: 5px; padding: 6px 10px; z-index: 999; background-color: rgb(222,60,80); border: none; border-radius: 5px; color: #FFF; }







JavaScript :



init = function(){ //... $('.js-crop').on('click', crop); }; crop = function(){ var crop_canvas, left = $('.overlay').offset().left - $container.offset().left, top = $('.overlay').offset().top - $container.offset().top, width = $('.overlay').width(), height = $('.overlay').height(); crop_canvas = document.createElement('canvas'); crop_canvas.width = width; crop_canvas.height = height; crop_canvas.getContext('2d').drawImage(image_target, left, top, width, height, 0, 0, width, height); window.open(crop_canvas.toDataURL("image/png")); }







crop



resizeImage



. , .



drawImage



canvas. - . - , . - , canvas, .





. .



mousedown



mouseup



- touchstart



touchend



, mousemove



touchmove



. , touchup



touchdown



( ).



touchstart



touchend



, mousedown



, mouseup



touchmove



, mousemove



.



// In init()... $container.on('mousedown touchstart', '.resize-handle', startResize); $container.on('mousedown touchstart', 'img', startMoving); //In startResize() ... $(document).on('mousemove touchmove', moving); $(document).on('mouseup touchend', endMoving); //In endResize()... $(document).off('mouseup touchend', endMoving); $(document).off('mousemove touchmove', moving); //In startMoving()... $(document).on('mousemove touchmove', moving); $(document).on('mouseup touchend', endMoving); //In endMoving()... $(document).off('mouseup touchend', endMoving); $(document).off('mousemove touchmove', moving);







, "" . Hammer, . , , .



, , , saveEventState



. .



" " . , . moving



:



moving = function(e){ var mouse={}, touches; e.preventDefault(); e.stopPropagation(); touches = e.originalEvent.touches; mouse.x = (e.clientX || e.pageX || touches[0].clientX) + $(window).scrollLeft(); mouse.y = (e.clientY || e.pageY || touches[0].clientY) + $(window).scrollTop(); $container.offset({ 'left': mouse.x - ( event_state.mouse_x - event_state.container_left ), 'top': mouse.y - ( event_state.mouse_y - event_state.container_top ) }); // Watch for pinch zoom gesture while moving if(event_state.touches && event_state.touches.length > 1 && touches.length > 1){ var width = event_state.container_width, height = event_state.container_height; var a = event_state.touches[0].clientX - event_state.touches[1].clientX; a = a * a; var b = event_state.touches[0].clientY - event_state.touches[1].clientY; b = b * b; var dist1 = Math.sqrt( a + b ); a = e.originalEvent.touches[0].clientX - touches[1].clientX; a = a * a; b = e.originalEvent.touches[0].clientY - touches[1].clientY; b = b * b; var dist2 = Math.sqrt( a + b ); var ratio = dist2 /dist1; width = width * ratio; height = height * ratio; // To improve performance you might limit how often resizeImage() is called resizeImage(width, height); } };







.







. .



Chrome "", Firefox .



, .




HTML5, , , .



- . , . , .



canvas




, , . , , .



. . , , . , .



!





:

<img class="resize-image" src="image.jpg" alt="Image" />







! HTML .



CSS

CSS- . resize-container



.



.resize-container { position: relative; display: inline-block; cursor: move; margin: 0 auto; } .resize-container img { display: block } .resize-container:hover img, .resize-container:active img { outline: 2px dashed rgba(222,60,80,.9); }







'resize handles'. , , .



.resize-handle-ne, .resize-handle-ne, .resize-handle-se, .resize-handle-nw, .resize-handle-sw { position: absolute; display: block; width: 10px; height: 10px; background: rgba(222,60,80,.9); z-index: 999; } .resize-handle-nw { top: -5px; left: -5px; cursor: nw-resize; } .resize-handle-sw { bottom: -5px; left: -5px; cursor: sw-resize; } .resize-handle-ne { top: -5px; right: -5px; cursor: ne-resize; } .resize-handle-se { bottom: -5px; right: -5px; cursor: se-resize; }







JavaScript

Canvas.



var resizeableImage = function(image_target) { var $container, orig_src = new Image(), image_target = $(image_target).get(0), event_state = {}, constrain = false, min_width = 60, min_height = 60, max_width = 800, max_height = 900, resize_canvas = document.createElement('canvas'); }); resizeableImage($('.resize-image'));







, . , , . jQuery , .



var resizeableImage = function(image_target) { // ... init = function(){ // Create a new image with a copy of the original src // When resizing, we will always use this original copy as the base orig_src.src=image_target.src; // Add resize handles $(image_target).wrap('<div class="resize-container"></div>') .before('<span class="resize-handle resize-handle-nw"></span>') .before('<span class="resize-handle resize-handle-ne"></span>') .after('<span class="resize-handle resize-handle-se"></span>') .after('<span class="resize-handle resize-handle-sw"></span>'); // Get a variable for the container $container = $(image_target).parent('.resize-container'); // Add events $container.on('mousedown', '.resize-handle', startResize); }; //... init(); }







startResize



endResize



, , .



startResize = function(e){ e.preventDefault(); e.stopPropagation(); saveEventState(e); $(document).on('mousemove', resizing); $(document).on('mouseup', endResize); }; endResize = function(e){ e.preventDefault(); $(document).off('mouseup touchend', endResize); $(document).off('mousemove touchmove', resizing); };







. event_state



.



saveEventState = function(e){ // Save the initial event details and container state event_state.container_width = $container.width(); event_state.container_height = $container.height(); event_state.container_left = $container.offset().left; event_state.container_top = $container.offset().top; event_state.mouse_x = (e.clientX || e.pageX || e.originalEvent.touches[0].clientX) + $(window).scrollLeft(); event_state.mouse_y = (e.clientY || e.pageY || e.originalEvent.touches[0].clientY) + $(window).scrollTop(); // This is a fix for mobile safari // For some reason it does not allow a direct copy of the touches property if(typeof e.originalEvent.touches !== 'undefined'){ event_state.touches = []; $.each(e.originalEvent.touches, function(i, ob){ event_state.touches[i] = {}; event_state.touches[i].clientX = 0+ob.clientX; event_state.touches[i].clientY = 0+ob.clientY; }); } event_state.evnt = e; }







resizing



- . . .



resizing = function(e){ var mouse={},width,height,left,top,offset=$container.offset(); mouse.x = (e.clientX || e.pageX || e.originalEvent.touches[0].clientX) + $(window).scrollLeft(); mouse.y = (e.clientY || e.pageY || e.originalEvent.touches[0].clientY) + $(window).scrollTop(); width = mouse.x - event_state.container_left; height = mouse.y - event_state.container_top; left = event_state.container_left; top = event_state.container_top; if(constrain || e.shiftKey){ height = width / orig_src.width * orig_src.height; } if(width > min_width && height > min_height && width < max_width && height < max_height){ resizeImage(width, height); // Without this Firefox will not re-calculate the the image dimensions until drag end $container.offset({'left': left, 'top': top}); } }







Shift .



.



: , , resizeImage



.





Canvas , drawImage



. , . toDataURL



Base64-encoded .



.



resizeImage = function(width, height){ resize_canvas.width = width; resize_canvas.height = height; resize_canvas.getContext('2d').drawImage(orig_src, 0, 0, width, height); $(image_target).attr('src', resize_canvas.toDataURL("image/png")); };







? : , CORS . , 'tainted canvas'.







. . , . , .



, , .







, . resizing



:



resizing = function(e){ var mouse={},width,height,left,top,offset=$container.offset(); mouse.x = (e.clientX || e.pageX || e.originalEvent.touches[0].clientX) + $(window).scrollLeft(); mouse.y = (e.clientY || e.pageY || e.originalEvent.touches[0].clientY) + $(window).scrollTop(); // Position image differently depending on the corner dragged and constraints if( $(event_state.evnt.target).hasClass('resize-handle-se') ){ width = mouse.x - event_state.container_left; height = mouse.y - event_state.container_top; left = event_state.container_left; top = event_state.container_top; } else if($(event_state.evnt.target).hasClass('resize-handle-sw') ){ width = event_state.container_width - (mouse.x - event_state.container_left); height = mouse.y - event_state.container_top; left = mouse.x; top = event_state.container_top; } else if($(event_state.evnt.target).hasClass('resize-handle-nw') ){ width = event_state.container_width - (mouse.x - event_state.container_left); height = event_state.container_height - (mouse.y - event_state.container_top); left = mouse.x; top = mouse.y; if(constrain || e.shiftKey){ top = mouse.y - ((width / orig_src.width * orig_src.height) - height); } } else if($(event_state.evnt.target).hasClass('resize-handle-ne') ){ width = mouse.x - event_state.container_left; height = event_state.container_height - (mouse.y - event_state.container_top); left = event_state.container_left; top = mouse.y; if(constrain || e.shiftKey){ top = mouse.y - ((width / orig_src.width * orig_src.height) - height); } } // Optionally maintain aspect ratio if(constrain || e.shiftKey){ height = width / orig_src.width * orig_src.height; } if(width > min_width && height > min_height && width < max_width && height < max_height){ // To improve performance you might limit how often resizeImage() is called resizeImage(width, height); // Without this Firefox will not re-calculate the the image dimensions until drag end $container.offset({'left': left, 'top': top}); } }







, resize-handle



, .





, , , , , "". . .



init = function(){ //... $container.on('mousedown', 'img', startMoving); }







startMoving



endMoving



, startResize



endResize



.



startMoving = function(e){ e.preventDefault(); e.stopPropagation(); saveEventState(e); $(document).on('mousemove', moving); $(document).on('mouseup', endMoving); }; endMoving = function(e){ e.preventDefault(); $(document).off('mouseup', endMoving); $(document).off('mousemove', moving); };







moving



. , .



moving = function(e){ var mouse={}; e.preventDefault(); e.stopPropagation(); mouse.x = (e.clientX || e.pageX) + $(window).scrollLeft(); mouse.y = (e.clientY || e.pageY) + $(window).scrollTop(); $container.offset({ 'left': mouse.x - ( event_state.mouse_x - event_state.container_left ), 'top': mouse.y - ( event_state.mouse_y - event_state.container_top ) }); };









, , . , , , , . , , , , .



HTML :



<div class="overlay"> <div class="overlay-inner"> </div> </div> <button class="btn-crop js-crop">Crop</button>







, , .



.overlay { position: absolute; left: 50%; top: 50%; margin-left: -100px; margin-top: -100px; z-index: 999; width: 200px; height: 200px; border: solid 2px rgba(222,60,80,.9); box-sizing: content-box; pointer-events: none; } .overlay:after, .overlay:before { content: ''; position: absolute; display: block; width: 204px; height: 40px; border-left: dashed 2px rgba(222,60,80,.9); border-right: dashed 2px rgba(222,60,80,.9); } .overlay:before { top: 0; margin-left: -2px; margin-top: -40px; } .overlay:after { bottom: 0; margin-left: -2px; margin-bottom: -40px; } .overlay-inner:after, .overlay-inner:before { content: ''; position: absolute; display: block; width: 40px; height: 204px; border-top: dashed 2px rgba(222,60,80,.9); border-bottom: dashed 2px rgba(222,60,80,.9); } .overlay-inner:before { left: 0; margin-left: -40px; margin-top: -2px; } .overlay-inner:after { right: 0; margin-right: -40px; margin-top: -2px; } .btn-crop { position: absolute; vertical-align: bottom; right: 5px; bottom: 5px; padding: 6px 10px; z-index: 999; background-color: rgb(222,60,80); border: none; border-radius: 5px; color: #FFF; }







JavaScript :



init = function(){ //... $('.js-crop').on('click', crop); }; crop = function(){ var crop_canvas, left = $('.overlay').offset().left - $container.offset().left, top = $('.overlay').offset().top - $container.offset().top, width = $('.overlay').width(), height = $('.overlay').height(); crop_canvas = document.createElement('canvas'); crop_canvas.width = width; crop_canvas.height = height; crop_canvas.getContext('2d').drawImage(image_target, left, top, width, height, 0, 0, width, height); window.open(crop_canvas.toDataURL("image/png")); }







crop



resizeImage



. , .



drawImage



canvas. - . - , . - , canvas, .





. .



mousedown



mouseup



- touchstart



touchend



, mousemove



touchmove



. , touchup



touchdown



( ).



touchstart



touchend



, mousedown



, mouseup



touchmove



, mousemove



.



// In init()... $container.on('mousedown touchstart', '.resize-handle', startResize); $container.on('mousedown touchstart', 'img', startMoving); //In startResize() ... $(document).on('mousemove touchmove', moving); $(document).on('mouseup touchend', endMoving); //In endResize()... $(document).off('mouseup touchend', endMoving); $(document).off('mousemove touchmove', moving); //In startMoving()... $(document).on('mousemove touchmove', moving); $(document).on('mouseup touchend', endMoving); //In endMoving()... $(document).off('mouseup touchend', endMoving); $(document).off('mousemove touchmove', moving);







, "" . Hammer, . , , .



, , , saveEventState



. .



" " . , . moving



:



moving = function(e){ var mouse={}, touches; e.preventDefault(); e.stopPropagation(); touches = e.originalEvent.touches; mouse.x = (e.clientX || e.pageX || touches[0].clientX) + $(window).scrollLeft(); mouse.y = (e.clientY || e.pageY || touches[0].clientY) + $(window).scrollTop(); $container.offset({ 'left': mouse.x - ( event_state.mouse_x - event_state.container_left ), 'top': mouse.y - ( event_state.mouse_y - event_state.container_top ) }); // Watch for pinch zoom gesture while moving if(event_state.touches && event_state.touches.length > 1 && touches.length > 1){ var width = event_state.container_width, height = event_state.container_height; var a = event_state.touches[0].clientX - event_state.touches[1].clientX; a = a * a; var b = event_state.touches[0].clientY - event_state.touches[1].clientY; b = b * b; var dist1 = Math.sqrt( a + b ); a = e.originalEvent.touches[0].clientX - touches[1].clientX; a = a * a; b = e.originalEvent.touches[0].clientY - touches[1].clientY; b = b * b; var dist2 = Math.sqrt( a + b ); var ratio = dist2 /dist1; width = width * ratio; height = height * ratio; // To improve performance you might limit how often resizeImage() is called resizeImage(width, height); } };







.







. .



Chrome "", Firefox .



, .




HTML5, , , .



- . , . , .



canvas




, , . , , .



. . , , . , .



!





:

<img class="resize-image" src="image.jpg" alt="Image" />







! HTML .



CSS

CSS- . resize-container



.



.resize-container { position: relative; display: inline-block; cursor: move; margin: 0 auto; } .resize-container img { display: block } .resize-container:hover img, .resize-container:active img { outline: 2px dashed rgba(222,60,80,.9); }







'resize handles'. , , .



.resize-handle-ne, .resize-handle-ne, .resize-handle-se, .resize-handle-nw, .resize-handle-sw { position: absolute; display: block; width: 10px; height: 10px; background: rgba(222,60,80,.9); z-index: 999; } .resize-handle-nw { top: -5px; left: -5px; cursor: nw-resize; } .resize-handle-sw { bottom: -5px; left: -5px; cursor: sw-resize; } .resize-handle-ne { top: -5px; right: -5px; cursor: ne-resize; } .resize-handle-se { bottom: -5px; right: -5px; cursor: se-resize; }







JavaScript

Canvas.



var resizeableImage = function(image_target) { var $container, orig_src = new Image(), image_target = $(image_target).get(0), event_state = {}, constrain = false, min_width = 60, min_height = 60, max_width = 800, max_height = 900, resize_canvas = document.createElement('canvas'); }); resizeableImage($('.resize-image'));







, . , , . jQuery , .



var resizeableImage = function(image_target) { // ... init = function(){ // Create a new image with a copy of the original src // When resizing, we will always use this original copy as the base orig_src.src=image_target.src; // Add resize handles $(image_target).wrap('<div class="resize-container"></div>') .before('<span class="resize-handle resize-handle-nw"></span>') .before('<span class="resize-handle resize-handle-ne"></span>') .after('<span class="resize-handle resize-handle-se"></span>') .after('<span class="resize-handle resize-handle-sw"></span>'); // Get a variable for the container $container = $(image_target).parent('.resize-container'); // Add events $container.on('mousedown', '.resize-handle', startResize); }; //... init(); }







startResize



endResize



, , .



startResize = function(e){ e.preventDefault(); e.stopPropagation(); saveEventState(e); $(document).on('mousemove', resizing); $(document).on('mouseup', endResize); }; endResize = function(e){ e.preventDefault(); $(document).off('mouseup touchend', endResize); $(document).off('mousemove touchmove', resizing); };







. event_state



.



saveEventState = function(e){ // Save the initial event details and container state event_state.container_width = $container.width(); event_state.container_height = $container.height(); event_state.container_left = $container.offset().left; event_state.container_top = $container.offset().top; event_state.mouse_x = (e.clientX || e.pageX || e.originalEvent.touches[0].clientX) + $(window).scrollLeft(); event_state.mouse_y = (e.clientY || e.pageY || e.originalEvent.touches[0].clientY) + $(window).scrollTop(); // This is a fix for mobile safari // For some reason it does not allow a direct copy of the touches property if(typeof e.originalEvent.touches !== 'undefined'){ event_state.touches = []; $.each(e.originalEvent.touches, function(i, ob){ event_state.touches[i] = {}; event_state.touches[i].clientX = 0+ob.clientX; event_state.touches[i].clientY = 0+ob.clientY; }); } event_state.evnt = e; }







resizing



- . . .



resizing = function(e){ var mouse={},width,height,left,top,offset=$container.offset(); mouse.x = (e.clientX || e.pageX || e.originalEvent.touches[0].clientX) + $(window).scrollLeft(); mouse.y = (e.clientY || e.pageY || e.originalEvent.touches[0].clientY) + $(window).scrollTop(); width = mouse.x - event_state.container_left; height = mouse.y - event_state.container_top; left = event_state.container_left; top = event_state.container_top; if(constrain || e.shiftKey){ height = width / orig_src.width * orig_src.height; } if(width > min_width && height > min_height && width < max_width && height < max_height){ resizeImage(width, height); // Without this Firefox will not re-calculate the the image dimensions until drag end $container.offset({'left': left, 'top': top}); } }







Shift .



.



: , , resizeImage



.





Canvas , drawImage



. , . toDataURL



Base64-encoded .



.



resizeImage = function(width, height){ resize_canvas.width = width; resize_canvas.height = height; resize_canvas.getContext('2d').drawImage(orig_src, 0, 0, width, height); $(image_target).attr('src', resize_canvas.toDataURL("image/png")); };







? : , CORS . , 'tainted canvas'.







. . , . , .



, , .







, . resizing



:



resizing = function(e){ var mouse={},width,height,left,top,offset=$container.offset(); mouse.x = (e.clientX || e.pageX || e.originalEvent.touches[0].clientX) + $(window).scrollLeft(); mouse.y = (e.clientY || e.pageY || e.originalEvent.touches[0].clientY) + $(window).scrollTop(); // Position image differently depending on the corner dragged and constraints if( $(event_state.evnt.target).hasClass('resize-handle-se') ){ width = mouse.x - event_state.container_left; height = mouse.y - event_state.container_top; left = event_state.container_left; top = event_state.container_top; } else if($(event_state.evnt.target).hasClass('resize-handle-sw') ){ width = event_state.container_width - (mouse.x - event_state.container_left); height = mouse.y - event_state.container_top; left = mouse.x; top = event_state.container_top; } else if($(event_state.evnt.target).hasClass('resize-handle-nw') ){ width = event_state.container_width - (mouse.x - event_state.container_left); height = event_state.container_height - (mouse.y - event_state.container_top); left = mouse.x; top = mouse.y; if(constrain || e.shiftKey){ top = mouse.y - ((width / orig_src.width * orig_src.height) - height); } } else if($(event_state.evnt.target).hasClass('resize-handle-ne') ){ width = mouse.x - event_state.container_left; height = event_state.container_height - (mouse.y - event_state.container_top); left = event_state.container_left; top = mouse.y; if(constrain || e.shiftKey){ top = mouse.y - ((width / orig_src.width * orig_src.height) - height); } } // Optionally maintain aspect ratio if(constrain || e.shiftKey){ height = width / orig_src.width * orig_src.height; } if(width > min_width && height > min_height && width < max_width && height < max_height){ // To improve performance you might limit how often resizeImage() is called resizeImage(width, height); // Without this Firefox will not re-calculate the the image dimensions until drag end $container.offset({'left': left, 'top': top}); } }







, resize-handle



, .





, , , , , "". . .



init = function(){ //... $container.on('mousedown', 'img', startMoving); }







startMoving



endMoving



, startResize



endResize



.



startMoving = function(e){ e.preventDefault(); e.stopPropagation(); saveEventState(e); $(document).on('mousemove', moving); $(document).on('mouseup', endMoving); }; endMoving = function(e){ e.preventDefault(); $(document).off('mouseup', endMoving); $(document).off('mousemove', moving); };







moving



. , .



moving = function(e){ var mouse={}; e.preventDefault(); e.stopPropagation(); mouse.x = (e.clientX || e.pageX) + $(window).scrollLeft(); mouse.y = (e.clientY || e.pageY) + $(window).scrollTop(); $container.offset({ 'left': mouse.x - ( event_state.mouse_x - event_state.container_left ), 'top': mouse.y - ( event_state.mouse_y - event_state.container_top ) }); };









, , . , , , , . , , , , .



HTML :



<div class="overlay"> <div class="overlay-inner"> </div> </div> <button class="btn-crop js-crop">Crop</button>







, , .



.overlay { position: absolute; left: 50%; top: 50%; margin-left: -100px; margin-top: -100px; z-index: 999; width: 200px; height: 200px; border: solid 2px rgba(222,60,80,.9); box-sizing: content-box; pointer-events: none; } .overlay:after, .overlay:before { content: ''; position: absolute; display: block; width: 204px; height: 40px; border-left: dashed 2px rgba(222,60,80,.9); border-right: dashed 2px rgba(222,60,80,.9); } .overlay:before { top: 0; margin-left: -2px; margin-top: -40px; } .overlay:after { bottom: 0; margin-left: -2px; margin-bottom: -40px; } .overlay-inner:after, .overlay-inner:before { content: ''; position: absolute; display: block; width: 40px; height: 204px; border-top: dashed 2px rgba(222,60,80,.9); border-bottom: dashed 2px rgba(222,60,80,.9); } .overlay-inner:before { left: 0; margin-left: -40px; margin-top: -2px; } .overlay-inner:after { right: 0; margin-right: -40px; margin-top: -2px; } .btn-crop { position: absolute; vertical-align: bottom; right: 5px; bottom: 5px; padding: 6px 10px; z-index: 999; background-color: rgb(222,60,80); border: none; border-radius: 5px; color: #FFF; }







JavaScript :



init = function(){ //... $('.js-crop').on('click', crop); }; crop = function(){ var crop_canvas, left = $('.overlay').offset().left - $container.offset().left, top = $('.overlay').offset().top - $container.offset().top, width = $('.overlay').width(), height = $('.overlay').height(); crop_canvas = document.createElement('canvas'); crop_canvas.width = width; crop_canvas.height = height; crop_canvas.getContext('2d').drawImage(image_target, left, top, width, height, 0, 0, width, height); window.open(crop_canvas.toDataURL("image/png")); }







crop



resizeImage



. , .



drawImage



canvas. - . - , . - , canvas, .





. .



mousedown



mouseup



- touchstart



touchend



, mousemove



touchmove



. , touchup



touchdown



( ).



touchstart



touchend



, mousedown



, mouseup



touchmove



, mousemove



.



// In init()... $container.on('mousedown touchstart', '.resize-handle', startResize); $container.on('mousedown touchstart', 'img', startMoving); //In startResize() ... $(document).on('mousemove touchmove', moving); $(document).on('mouseup touchend', endMoving); //In endResize()... $(document).off('mouseup touchend', endMoving); $(document).off('mousemove touchmove', moving); //In startMoving()... $(document).on('mousemove touchmove', moving); $(document).on('mouseup touchend', endMoving); //In endMoving()... $(document).off('mouseup touchend', endMoving); $(document).off('mousemove touchmove', moving);







, "" . Hammer, . , , .



, , , saveEventState



. .



" " . , . moving



:



moving = function(e){ var mouse={}, touches; e.preventDefault(); e.stopPropagation(); touches = e.originalEvent.touches; mouse.x = (e.clientX || e.pageX || touches[0].clientX) + $(window).scrollLeft(); mouse.y = (e.clientY || e.pageY || touches[0].clientY) + $(window).scrollTop(); $container.offset({ 'left': mouse.x - ( event_state.mouse_x - event_state.container_left ), 'top': mouse.y - ( event_state.mouse_y - event_state.container_top ) }); // Watch for pinch zoom gesture while moving if(event_state.touches && event_state.touches.length > 1 && touches.length > 1){ var width = event_state.container_width, height = event_state.container_height; var a = event_state.touches[0].clientX - event_state.touches[1].clientX; a = a * a; var b = event_state.touches[0].clientY - event_state.touches[1].clientY; b = b * b; var dist1 = Math.sqrt( a + b ); a = e.originalEvent.touches[0].clientX - touches[1].clientX; a = a * a; b = e.originalEvent.touches[0].clientY - touches[1].clientY; b = b * b; var dist2 = Math.sqrt( a + b ); var ratio = dist2 /dist1; width = width * ratio; height = height * ratio; // To improve performance you might limit how often resizeImage() is called resizeImage(width, height); } };







.







. .



Chrome "", Firefox .



, .




HTML5, , , .



- . , . , .



canvas




, , . , , .



. . , , . , .



!





:

<img class="resize-image" src="image.jpg" alt="Image" />







! HTML .



CSS

CSS- . resize-container



.



.resize-container { position: relative; display: inline-block; cursor: move; margin: 0 auto; } .resize-container img { display: block } .resize-container:hover img, .resize-container:active img { outline: 2px dashed rgba(222,60,80,.9); }







'resize handles'. , , .



.resize-handle-ne, .resize-handle-ne, .resize-handle-se, .resize-handle-nw, .resize-handle-sw { position: absolute; display: block; width: 10px; height: 10px; background: rgba(222,60,80,.9); z-index: 999; } .resize-handle-nw { top: -5px; left: -5px; cursor: nw-resize; } .resize-handle-sw { bottom: -5px; left: -5px; cursor: sw-resize; } .resize-handle-ne { top: -5px; right: -5px; cursor: ne-resize; } .resize-handle-se { bottom: -5px; right: -5px; cursor: se-resize; }







JavaScript

Canvas.



var resizeableImage = function(image_target) { var $container, orig_src = new Image(), image_target = $(image_target).get(0), event_state = {}, constrain = false, min_width = 60, min_height = 60, max_width = 800, max_height = 900, resize_canvas = document.createElement('canvas'); }); resizeableImage($('.resize-image'));







, . , , . jQuery , .



var resizeableImage = function(image_target) { // ... init = function(){ // Create a new image with a copy of the original src // When resizing, we will always use this original copy as the base orig_src.src=image_target.src; // Add resize handles $(image_target).wrap('<div class="resize-container"></div>') .before('<span class="resize-handle resize-handle-nw"></span>') .before('<span class="resize-handle resize-handle-ne"></span>') .after('<span class="resize-handle resize-handle-se"></span>') .after('<span class="resize-handle resize-handle-sw"></span>'); // Get a variable for the container $container = $(image_target).parent('.resize-container'); // Add events $container.on('mousedown', '.resize-handle', startResize); }; //... init(); }







startResize



endResize



, , .



startResize = function(e){ e.preventDefault(); e.stopPropagation(); saveEventState(e); $(document).on('mousemove', resizing); $(document).on('mouseup', endResize); }; endResize = function(e){ e.preventDefault(); $(document).off('mouseup touchend', endResize); $(document).off('mousemove touchmove', resizing); };







. event_state



.



saveEventState = function(e){ // Save the initial event details and container state event_state.container_width = $container.width(); event_state.container_height = $container.height(); event_state.container_left = $container.offset().left; event_state.container_top = $container.offset().top; event_state.mouse_x = (e.clientX || e.pageX || e.originalEvent.touches[0].clientX) + $(window).scrollLeft(); event_state.mouse_y = (e.clientY || e.pageY || e.originalEvent.touches[0].clientY) + $(window).scrollTop(); // This is a fix for mobile safari // For some reason it does not allow a direct copy of the touches property if(typeof e.originalEvent.touches !== 'undefined'){ event_state.touches = []; $.each(e.originalEvent.touches, function(i, ob){ event_state.touches[i] = {}; event_state.touches[i].clientX = 0+ob.clientX; event_state.touches[i].clientY = 0+ob.clientY; }); } event_state.evnt = e; }







resizing



- . . .



resizing = function(e){ var mouse={},width,height,left,top,offset=$container.offset(); mouse.x = (e.clientX || e.pageX || e.originalEvent.touches[0].clientX) + $(window).scrollLeft(); mouse.y = (e.clientY || e.pageY || e.originalEvent.touches[0].clientY) + $(window).scrollTop(); width = mouse.x - event_state.container_left; height = mouse.y - event_state.container_top; left = event_state.container_left; top = event_state.container_top; if(constrain || e.shiftKey){ height = width / orig_src.width * orig_src.height; } if(width > min_width && height > min_height && width < max_width && height < max_height){ resizeImage(width, height); // Without this Firefox will not re-calculate the the image dimensions until drag end $container.offset({'left': left, 'top': top}); } }







Shift .



.



: , , resizeImage



.





Canvas , drawImage



. , . toDataURL



Base64-encoded .



.



resizeImage = function(width, height){ resize_canvas.width = width; resize_canvas.height = height; resize_canvas.getContext('2d').drawImage(orig_src, 0, 0, width, height); $(image_target).attr('src', resize_canvas.toDataURL("image/png")); };







? : , CORS . , 'tainted canvas'.







. . , . , .



, , .







, . resizing



:



resizing = function(e){ var mouse={},width,height,left,top,offset=$container.offset(); mouse.x = (e.clientX || e.pageX || e.originalEvent.touches[0].clientX) + $(window).scrollLeft(); mouse.y = (e.clientY || e.pageY || e.originalEvent.touches[0].clientY) + $(window).scrollTop(); // Position image differently depending on the corner dragged and constraints if( $(event_state.evnt.target).hasClass('resize-handle-se') ){ width = mouse.x - event_state.container_left; height = mouse.y - event_state.container_top; left = event_state.container_left; top = event_state.container_top; } else if($(event_state.evnt.target).hasClass('resize-handle-sw') ){ width = event_state.container_width - (mouse.x - event_state.container_left); height = mouse.y - event_state.container_top; left = mouse.x; top = event_state.container_top; } else if($(event_state.evnt.target).hasClass('resize-handle-nw') ){ width = event_state.container_width - (mouse.x - event_state.container_left); height = event_state.container_height - (mouse.y - event_state.container_top); left = mouse.x; top = mouse.y; if(constrain || e.shiftKey){ top = mouse.y - ((width / orig_src.width * orig_src.height) - height); } } else if($(event_state.evnt.target).hasClass('resize-handle-ne') ){ width = mouse.x - event_state.container_left; height = event_state.container_height - (mouse.y - event_state.container_top); left = event_state.container_left; top = mouse.y; if(constrain || e.shiftKey){ top = mouse.y - ((width / orig_src.width * orig_src.height) - height); } } // Optionally maintain aspect ratio if(constrain || e.shiftKey){ height = width / orig_src.width * orig_src.height; } if(width > min_width && height > min_height && width < max_width && height < max_height){ // To improve performance you might limit how often resizeImage() is called resizeImage(width, height); // Without this Firefox will not re-calculate the the image dimensions until drag end $container.offset({'left': left, 'top': top}); } }







, resize-handle



, .





, , , , , "". . .



init = function(){ //... $container.on('mousedown', 'img', startMoving); }







startMoving



endMoving



, startResize



endResize



.



startMoving = function(e){ e.preventDefault(); e.stopPropagation(); saveEventState(e); $(document).on('mousemove', moving); $(document).on('mouseup', endMoving); }; endMoving = function(e){ e.preventDefault(); $(document).off('mouseup', endMoving); $(document).off('mousemove', moving); };







moving



. , .



moving = function(e){ var mouse={}; e.preventDefault(); e.stopPropagation(); mouse.x = (e.clientX || e.pageX) + $(window).scrollLeft(); mouse.y = (e.clientY || e.pageY) + $(window).scrollTop(); $container.offset({ 'left': mouse.x - ( event_state.mouse_x - event_state.container_left ), 'top': mouse.y - ( event_state.mouse_y - event_state.container_top ) }); };









, , . , , , , . , , , , .



HTML :



<div class="overlay"> <div class="overlay-inner"> </div> </div> <button class="btn-crop js-crop">Crop</button>







, , .



.overlay { position: absolute; left: 50%; top: 50%; margin-left: -100px; margin-top: -100px; z-index: 999; width: 200px; height: 200px; border: solid 2px rgba(222,60,80,.9); box-sizing: content-box; pointer-events: none; } .overlay:after, .overlay:before { content: ''; position: absolute; display: block; width: 204px; height: 40px; border-left: dashed 2px rgba(222,60,80,.9); border-right: dashed 2px rgba(222,60,80,.9); } .overlay:before { top: 0; margin-left: -2px; margin-top: -40px; } .overlay:after { bottom: 0; margin-left: -2px; margin-bottom: -40px; } .overlay-inner:after, .overlay-inner:before { content: ''; position: absolute; display: block; width: 40px; height: 204px; border-top: dashed 2px rgba(222,60,80,.9); border-bottom: dashed 2px rgba(222,60,80,.9); } .overlay-inner:before { left: 0; margin-left: -40px; margin-top: -2px; } .overlay-inner:after { right: 0; margin-right: -40px; margin-top: -2px; } .btn-crop { position: absolute; vertical-align: bottom; right: 5px; bottom: 5px; padding: 6px 10px; z-index: 999; background-color: rgb(222,60,80); border: none; border-radius: 5px; color: #FFF; }







JavaScript :



init = function(){ //... $('.js-crop').on('click', crop); }; crop = function(){ var crop_canvas, left = $('.overlay').offset().left - $container.offset().left, top = $('.overlay').offset().top - $container.offset().top, width = $('.overlay').width(), height = $('.overlay').height(); crop_canvas = document.createElement('canvas'); crop_canvas.width = width; crop_canvas.height = height; crop_canvas.getContext('2d').drawImage(image_target, left, top, width, height, 0, 0, width, height); window.open(crop_canvas.toDataURL("image/png")); }







crop



resizeImage



. , .



drawImage



canvas. - . - , . - , canvas, .





. .



mousedown



mouseup



- touchstart



touchend



, mousemove



touchmove



. , touchup



touchdown



( ).



touchstart



touchend



, mousedown



, mouseup



touchmove



, mousemove



.



// In init()... $container.on('mousedown touchstart', '.resize-handle', startResize); $container.on('mousedown touchstart', 'img', startMoving); //In startResize() ... $(document).on('mousemove touchmove', moving); $(document).on('mouseup touchend', endMoving); //In endResize()... $(document).off('mouseup touchend', endMoving); $(document).off('mousemove touchmove', moving); //In startMoving()... $(document).on('mousemove touchmove', moving); $(document).on('mouseup touchend', endMoving); //In endMoving()... $(document).off('mouseup touchend', endMoving); $(document).off('mousemove touchmove', moving);







, "" . Hammer, . , , .



, , , saveEventState



. .



" " . , . moving



:



moving = function(e){ var mouse={}, touches; e.preventDefault(); e.stopPropagation(); touches = e.originalEvent.touches; mouse.x = (e.clientX || e.pageX || touches[0].clientX) + $(window).scrollLeft(); mouse.y = (e.clientY || e.pageY || touches[0].clientY) + $(window).scrollTop(); $container.offset({ 'left': mouse.x - ( event_state.mouse_x - event_state.container_left ), 'top': mouse.y - ( event_state.mouse_y - event_state.container_top ) }); // Watch for pinch zoom gesture while moving if(event_state.touches && event_state.touches.length > 1 && touches.length > 1){ var width = event_state.container_width, height = event_state.container_height; var a = event_state.touches[0].clientX - event_state.touches[1].clientX; a = a * a; var b = event_state.touches[0].clientY - event_state.touches[1].clientY; b = b * b; var dist1 = Math.sqrt( a + b ); a = e.originalEvent.touches[0].clientX - touches[1].clientX; a = a * a; b = e.originalEvent.touches[0].clientY - touches[1].clientY; b = b * b; var dist2 = Math.sqrt( a + b ); var ratio = dist2 /dist1; width = width * ratio; height = height * ratio; // To improve performance you might limit how often resizeImage() is called resizeImage(width, height); } };







.







. .



Chrome "", Firefox .



, .




  HTML5,     ,      ,   . 
      



- . , . , .



canvas




, , . , , .



. . , , . , .



!





:

<img class="resize-image" src="image.jpg" alt="Image" />







! HTML .



CSS

CSS- . resize-container



.



.resize-container { position: relative; display: inline-block; cursor: move; margin: 0 auto; } .resize-container img { display: block } .resize-container:hover img, .resize-container:active img { outline: 2px dashed rgba(222,60,80,.9); }







'resize handles'. , , .



.resize-handle-ne, .resize-handle-ne, .resize-handle-se, .resize-handle-nw, .resize-handle-sw { position: absolute; display: block; width: 10px; height: 10px; background: rgba(222,60,80,.9); z-index: 999; } .resize-handle-nw { top: -5px; left: -5px; cursor: nw-resize; } .resize-handle-sw { bottom: -5px; left: -5px; cursor: sw-resize; } .resize-handle-ne { top: -5px; right: -5px; cursor: ne-resize; } .resize-handle-se { bottom: -5px; right: -5px; cursor: se-resize; }







JavaScript

Canvas.



var resizeableImage = function(image_target) { var $container, orig_src = new Image(), image_target = $(image_target).get(0), event_state = {}, constrain = false, min_width = 60, min_height = 60, max_width = 800, max_height = 900, resize_canvas = document.createElement('canvas'); }); resizeableImage($('.resize-image'));







, . , , . jQuery , .



var resizeableImage = function(image_target) { // ... init = function(){ // Create a new image with a copy of the original src // When resizing, we will always use this original copy as the base orig_src.src=image_target.src; // Add resize handles $(image_target).wrap('<div class="resize-container"></div>') .before('<span class="resize-handle resize-handle-nw"></span>') .before('<span class="resize-handle resize-handle-ne"></span>') .after('<span class="resize-handle resize-handle-se"></span>') .after('<span class="resize-handle resize-handle-sw"></span>'); // Get a variable for the container $container = $(image_target).parent('.resize-container'); // Add events $container.on('mousedown', '.resize-handle', startResize); }; //... init(); }







startResize



endResize



, , .



startResize = function(e){ e.preventDefault(); e.stopPropagation(); saveEventState(e); $(document).on('mousemove', resizing); $(document).on('mouseup', endResize); }; endResize = function(e){ e.preventDefault(); $(document).off('mouseup touchend', endResize); $(document).off('mousemove touchmove', resizing); };







. event_state



.



saveEventState = function(e){ // Save the initial event details and container state event_state.container_width = $container.width(); event_state.container_height = $container.height(); event_state.container_left = $container.offset().left; event_state.container_top = $container.offset().top; event_state.mouse_x = (e.clientX || e.pageX || e.originalEvent.touches[0].clientX) + $(window).scrollLeft(); event_state.mouse_y = (e.clientY || e.pageY || e.originalEvent.touches[0].clientY) + $(window).scrollTop(); // This is a fix for mobile safari // For some reason it does not allow a direct copy of the touches property if(typeof e.originalEvent.touches !== 'undefined'){ event_state.touches = []; $.each(e.originalEvent.touches, function(i, ob){ event_state.touches[i] = {}; event_state.touches[i].clientX = 0+ob.clientX; event_state.touches[i].clientY = 0+ob.clientY; }); } event_state.evnt = e; }







resizing



- . . .



resizing = function(e){ var mouse={},width,height,left,top,offset=$container.offset(); mouse.x = (e.clientX || e.pageX || e.originalEvent.touches[0].clientX) + $(window).scrollLeft(); mouse.y = (e.clientY || e.pageY || e.originalEvent.touches[0].clientY) + $(window).scrollTop(); width = mouse.x - event_state.container_left; height = mouse.y - event_state.container_top; left = event_state.container_left; top = event_state.container_top; if(constrain || e.shiftKey){ height = width / orig_src.width * orig_src.height; } if(width > min_width && height > min_height && width < max_width && height < max_height){ resizeImage(width, height); // Without this Firefox will not re-calculate the the image dimensions until drag end $container.offset({'left': left, 'top': top}); } }







Shift .



.



: , , resizeImage



.





Canvas , drawImage



. , . toDataURL



Base64-encoded .



.



resizeImage = function(width, height){ resize_canvas.width = width; resize_canvas.height = height; resize_canvas.getContext('2d').drawImage(orig_src, 0, 0, width, height); $(image_target).attr('src', resize_canvas.toDataURL("image/png")); };







? : , CORS . , 'tainted canvas'.







. . , . , .



, , .







, . resizing



:



resizing = function(e){ var mouse={},width,height,left,top,offset=$container.offset(); mouse.x = (e.clientX || e.pageX || e.originalEvent.touches[0].clientX) + $(window).scrollLeft(); mouse.y = (e.clientY || e.pageY || e.originalEvent.touches[0].clientY) + $(window).scrollTop(); // Position image differently depending on the corner dragged and constraints if( $(event_state.evnt.target).hasClass('resize-handle-se') ){ width = mouse.x - event_state.container_left; height = mouse.y - event_state.container_top; left = event_state.container_left; top = event_state.container_top; } else if($(event_state.evnt.target).hasClass('resize-handle-sw') ){ width = event_state.container_width - (mouse.x - event_state.container_left); height = mouse.y - event_state.container_top; left = mouse.x; top = event_state.container_top; } else if($(event_state.evnt.target).hasClass('resize-handle-nw') ){ width = event_state.container_width - (mouse.x - event_state.container_left); height = event_state.container_height - (mouse.y - event_state.container_top); left = mouse.x; top = mouse.y; if(constrain || e.shiftKey){ top = mouse.y - ((width / orig_src.width * orig_src.height) - height); } } else if($(event_state.evnt.target).hasClass('resize-handle-ne') ){ width = mouse.x - event_state.container_left; height = event_state.container_height - (mouse.y - event_state.container_top); left = event_state.container_left; top = mouse.y; if(constrain || e.shiftKey){ top = mouse.y - ((width / orig_src.width * orig_src.height) - height); } } // Optionally maintain aspect ratio if(constrain || e.shiftKey){ height = width / orig_src.width * orig_src.height; } if(width > min_width && height > min_height && width < max_width && height < max_height){ // To improve performance you might limit how often resizeImage() is called resizeImage(width, height); // Without this Firefox will not re-calculate the the image dimensions until drag end $container.offset({'left': left, 'top': top}); } }







, resize-handle



, .





, , , , , "". . .



init = function(){ //... $container.on('mousedown', 'img', startMoving); }







startMoving



endMoving



, startResize



endResize



.



startMoving = function(e){ e.preventDefault(); e.stopPropagation(); saveEventState(e); $(document).on('mousemove', moving); $(document).on('mouseup', endMoving); }; endMoving = function(e){ e.preventDefault(); $(document).off('mouseup', endMoving); $(document).off('mousemove', moving); };







moving



. , .



moving = function(e){ var mouse={}; e.preventDefault(); e.stopPropagation(); mouse.x = (e.clientX || e.pageX) + $(window).scrollLeft(); mouse.y = (e.clientY || e.pageY) + $(window).scrollTop(); $container.offset({ 'left': mouse.x - ( event_state.mouse_x - event_state.container_left ), 'top': mouse.y - ( event_state.mouse_y - event_state.container_top ) }); };









, , . , , , , . , , , , .



HTML :



<div class="overlay"> <div class="overlay-inner"> </div> </div> <button class="btn-crop js-crop">Crop</button>







, , .



.overlay { position: absolute; left: 50%; top: 50%; margin-left: -100px; margin-top: -100px; z-index: 999; width: 200px; height: 200px; border: solid 2px rgba(222,60,80,.9); box-sizing: content-box; pointer-events: none; } .overlay:after, .overlay:before { content: ''; position: absolute; display: block; width: 204px; height: 40px; border-left: dashed 2px rgba(222,60,80,.9); border-right: dashed 2px rgba(222,60,80,.9); } .overlay:before { top: 0; margin-left: -2px; margin-top: -40px; } .overlay:after { bottom: 0; margin-left: -2px; margin-bottom: -40px; } .overlay-inner:after, .overlay-inner:before { content: ''; position: absolute; display: block; width: 40px; height: 204px; border-top: dashed 2px rgba(222,60,80,.9); border-bottom: dashed 2px rgba(222,60,80,.9); } .overlay-inner:before { left: 0; margin-left: -40px; margin-top: -2px; } .overlay-inner:after { right: 0; margin-right: -40px; margin-top: -2px; } .btn-crop { position: absolute; vertical-align: bottom; right: 5px; bottom: 5px; padding: 6px 10px; z-index: 999; background-color: rgb(222,60,80); border: none; border-radius: 5px; color: #FFF; }







JavaScript :



init = function(){ //... $('.js-crop').on('click', crop); }; crop = function(){ var crop_canvas, left = $('.overlay').offset().left - $container.offset().left, top = $('.overlay').offset().top - $container.offset().top, width = $('.overlay').width(), height = $('.overlay').height(); crop_canvas = document.createElement('canvas'); crop_canvas.width = width; crop_canvas.height = height; crop_canvas.getContext('2d').drawImage(image_target, left, top, width, height, 0, 0, width, height); window.open(crop_canvas.toDataURL("image/png")); }







crop



resizeImage



. , .



drawImage



canvas. - . - , . - , canvas, .





. .



mousedown



mouseup



- touchstart



touchend



, mousemove



touchmove



. , touchup



touchdown



( ).



touchstart



touchend



, mousedown



, mouseup



touchmove



, mousemove



.



// In init()... $container.on('mousedown touchstart', '.resize-handle', startResize); $container.on('mousedown touchstart', 'img', startMoving); //In startResize() ... $(document).on('mousemove touchmove', moving); $(document).on('mouseup touchend', endMoving); //In endResize()... $(document).off('mouseup touchend', endMoving); $(document).off('mousemove touchmove', moving); //In startMoving()... $(document).on('mousemove touchmove', moving); $(document).on('mouseup touchend', endMoving); //In endMoving()... $(document).off('mouseup touchend', endMoving); $(document).off('mousemove touchmove', moving);







, "" . Hammer, . , , .



, , , saveEventState



. .



" " . , . moving



:



moving = function(e){ var mouse={}, touches; e.preventDefault(); e.stopPropagation(); touches = e.originalEvent.touches; mouse.x = (e.clientX || e.pageX || touches[0].clientX) + $(window).scrollLeft(); mouse.y = (e.clientY || e.pageY || touches[0].clientY) + $(window).scrollTop(); $container.offset({ 'left': mouse.x - ( event_state.mouse_x - event_state.container_left ), 'top': mouse.y - ( event_state.mouse_y - event_state.container_top ) }); // Watch for pinch zoom gesture while moving if(event_state.touches && event_state.touches.length > 1 && touches.length > 1){ var width = event_state.container_width, height = event_state.container_height; var a = event_state.touches[0].clientX - event_state.touches[1].clientX; a = a * a; var b = event_state.touches[0].clientY - event_state.touches[1].clientY; b = b * b; var dist1 = Math.sqrt( a + b ); a = e.originalEvent.touches[0].clientX - touches[1].clientX; a = a * a; b = e.originalEvent.touches[0].clientY - touches[1].clientY; b = b * b; var dist2 = Math.sqrt( a + b ); var ratio = dist2 /dist1; width = width * ratio; height = height * ratio; // To improve performance you might limit how often resizeImage() is called resizeImage(width, height); } };







.







. .



Chrome "", Firefox .



, .




HTML5, , , .



- . , . , .



canvas




, , . , , .



. . , , . , .



!





:

<img class="resize-image" src="image.jpg" alt="Image" />







! HTML .



CSS

CSS- . resize-container



.



.resize-container { position: relative; display: inline-block; cursor: move; margin: 0 auto; } .resize-container img { display: block } .resize-container:hover img, .resize-container:active img { outline: 2px dashed rgba(222,60,80,.9); }







'resize handles'. , , .



.resize-handle-ne, .resize-handle-ne, .resize-handle-se, .resize-handle-nw, .resize-handle-sw { position: absolute; display: block; width: 10px; height: 10px; background: rgba(222,60,80,.9); z-index: 999; } .resize-handle-nw { top: -5px; left: -5px; cursor: nw-resize; } .resize-handle-sw { bottom: -5px; left: -5px; cursor: sw-resize; } .resize-handle-ne { top: -5px; right: -5px; cursor: ne-resize; } .resize-handle-se { bottom: -5px; right: -5px; cursor: se-resize; }







JavaScript

Canvas.



var resizeableImage = function(image_target) { var $container, orig_src = new Image(), image_target = $(image_target).get(0), event_state = {}, constrain = false, min_width = 60, min_height = 60, max_width = 800, max_height = 900, resize_canvas = document.createElement('canvas'); }); resizeableImage($('.resize-image'));







, . , , . jQuery , .



var resizeableImage = function(image_target) { // ... init = function(){ // Create a new image with a copy of the original src // When resizing, we will always use this original copy as the base orig_src.src=image_target.src; // Add resize handles $(image_target).wrap('<div class="resize-container"></div>') .before('<span class="resize-handle resize-handle-nw"></span>') .before('<span class="resize-handle resize-handle-ne"></span>') .after('<span class="resize-handle resize-handle-se"></span>') .after('<span class="resize-handle resize-handle-sw"></span>'); // Get a variable for the container $container = $(image_target).parent('.resize-container'); // Add events $container.on('mousedown', '.resize-handle', startResize); }; //... init(); }







startResize



endResize



, , .



startResize = function(e){ e.preventDefault(); e.stopPropagation(); saveEventState(e); $(document).on('mousemove', resizing); $(document).on('mouseup', endResize); }; endResize = function(e){ e.preventDefault(); $(document).off('mouseup touchend', endResize); $(document).off('mousemove touchmove', resizing); };







. event_state



.



saveEventState = function(e){ // Save the initial event details and container state event_state.container_width = $container.width(); event_state.container_height = $container.height(); event_state.container_left = $container.offset().left; event_state.container_top = $container.offset().top; event_state.mouse_x = (e.clientX || e.pageX || e.originalEvent.touches[0].clientX) + $(window).scrollLeft(); event_state.mouse_y = (e.clientY || e.pageY || e.originalEvent.touches[0].clientY) + $(window).scrollTop(); // This is a fix for mobile safari // For some reason it does not allow a direct copy of the touches property if(typeof e.originalEvent.touches !== 'undefined'){ event_state.touches = []; $.each(e.originalEvent.touches, function(i, ob){ event_state.touches[i] = {}; event_state.touches[i].clientX = 0+ob.clientX; event_state.touches[i].clientY = 0+ob.clientY; }); } event_state.evnt = e; }







resizing



- . . .



resizing = function(e){ var mouse={},width,height,left,top,offset=$container.offset(); mouse.x = (e.clientX || e.pageX || e.originalEvent.touches[0].clientX) + $(window).scrollLeft(); mouse.y = (e.clientY || e.pageY || e.originalEvent.touches[0].clientY) + $(window).scrollTop(); width = mouse.x - event_state.container_left; height = mouse.y - event_state.container_top; left = event_state.container_left; top = event_state.container_top; if(constrain || e.shiftKey){ height = width / orig_src.width * orig_src.height; } if(width > min_width && height > min_height && width < max_width && height < max_height){ resizeImage(width, height); // Without this Firefox will not re-calculate the the image dimensions until drag end $container.offset({'left': left, 'top': top}); } }







Shift .



.



: , , resizeImage



.





Canvas , drawImage



. , . toDataURL



Base64-encoded .



.



resizeImage = function(width, height){ resize_canvas.width = width; resize_canvas.height = height; resize_canvas.getContext('2d').drawImage(orig_src, 0, 0, width, height); $(image_target).attr('src', resize_canvas.toDataURL("image/png")); };







? : , CORS . , 'tainted canvas'.







. . , . , .



, , .







, . resizing



:



resizing = function(e){ var mouse={},width,height,left,top,offset=$container.offset(); mouse.x = (e.clientX || e.pageX || e.originalEvent.touches[0].clientX) + $(window).scrollLeft(); mouse.y = (e.clientY || e.pageY || e.originalEvent.touches[0].clientY) + $(window).scrollTop(); // Position image differently depending on the corner dragged and constraints if( $(event_state.evnt.target).hasClass('resize-handle-se') ){ width = mouse.x - event_state.container_left; height = mouse.y - event_state.container_top; left = event_state.container_left; top = event_state.container_top; } else if($(event_state.evnt.target).hasClass('resize-handle-sw') ){ width = event_state.container_width - (mouse.x - event_state.container_left); height = mouse.y - event_state.container_top; left = mouse.x; top = event_state.container_top; } else if($(event_state.evnt.target).hasClass('resize-handle-nw') ){ width = event_state.container_width - (mouse.x - event_state.container_left); height = event_state.container_height - (mouse.y - event_state.container_top); left = mouse.x; top = mouse.y; if(constrain || e.shiftKey){ top = mouse.y - ((width / orig_src.width * orig_src.height) - height); } } else if($(event_state.evnt.target).hasClass('resize-handle-ne') ){ width = mouse.x - event_state.container_left; height = event_state.container_height - (mouse.y - event_state.container_top); left = event_state.container_left; top = mouse.y; if(constrain || e.shiftKey){ top = mouse.y - ((width / orig_src.width * orig_src.height) - height); } } // Optionally maintain aspect ratio if(constrain || e.shiftKey){ height = width / orig_src.width * orig_src.height; } if(width > min_width && height > min_height && width < max_width && height < max_height){ // To improve performance you might limit how often resizeImage() is called resizeImage(width, height); // Without this Firefox will not re-calculate the the image dimensions until drag end $container.offset({'left': left, 'top': top}); } }







, resize-handle



, .





, , , , , "". . .



init = function(){ //... $container.on('mousedown', 'img', startMoving); }







startMoving



endMoving



, startResize



endResize



.



startMoving = function(e){ e.preventDefault(); e.stopPropagation(); saveEventState(e); $(document).on('mousemove', moving); $(document).on('mouseup', endMoving); }; endMoving = function(e){ e.preventDefault(); $(document).off('mouseup', endMoving); $(document).off('mousemove', moving); };







moving



. , .



moving = function(e){ var mouse={}; e.preventDefault(); e.stopPropagation(); mouse.x = (e.clientX || e.pageX) + $(window).scrollLeft(); mouse.y = (e.clientY || e.pageY) + $(window).scrollTop(); $container.offset({ 'left': mouse.x - ( event_state.mouse_x - event_state.container_left ), 'top': mouse.y - ( event_state.mouse_y - event_state.container_top ) }); };









, , . , , , , . , , , , .



HTML :



<div class="overlay"> <div class="overlay-inner"> </div> </div> <button class="btn-crop js-crop">Crop</button>







, , .



.overlay { position: absolute; left: 50%; top: 50%; margin-left: -100px; margin-top: -100px; z-index: 999; width: 200px; height: 200px; border: solid 2px rgba(222,60,80,.9); box-sizing: content-box; pointer-events: none; } .overlay:after, .overlay:before { content: ''; position: absolute; display: block; width: 204px; height: 40px; border-left: dashed 2px rgba(222,60,80,.9); border-right: dashed 2px rgba(222,60,80,.9); } .overlay:before { top: 0; margin-left: -2px; margin-top: -40px; } .overlay:after { bottom: 0; margin-left: -2px; margin-bottom: -40px; } .overlay-inner:after, .overlay-inner:before { content: ''; position: absolute; display: block; width: 40px; height: 204px; border-top: dashed 2px rgba(222,60,80,.9); border-bottom: dashed 2px rgba(222,60,80,.9); } .overlay-inner:before { left: 0; margin-left: -40px; margin-top: -2px; } .overlay-inner:after { right: 0; margin-right: -40px; margin-top: -2px; } .btn-crop { position: absolute; vertical-align: bottom; right: 5px; bottom: 5px; padding: 6px 10px; z-index: 999; background-color: rgb(222,60,80); border: none; border-radius: 5px; color: #FFF; }







JavaScript :



init = function(){ //... $('.js-crop').on('click', crop); }; crop = function(){ var crop_canvas, left = $('.overlay').offset().left - $container.offset().left, top = $('.overlay').offset().top - $container.offset().top, width = $('.overlay').width(), height = $('.overlay').height(); crop_canvas = document.createElement('canvas'); crop_canvas.width = width; crop_canvas.height = height; crop_canvas.getContext('2d').drawImage(image_target, left, top, width, height, 0, 0, width, height); window.open(crop_canvas.toDataURL("image/png")); }







crop



resizeImage



. , .



drawImage



canvas. - . - , . - , canvas, .





. .



mousedown



mouseup



- touchstart



touchend



, mousemove



touchmove



. , touchup



touchdown



( ).



touchstart



touchend



, mousedown



, mouseup



touchmove



, mousemove



.



// In init()... $container.on('mousedown touchstart', '.resize-handle', startResize); $container.on('mousedown touchstart', 'img', startMoving); //In startResize() ... $(document).on('mousemove touchmove', moving); $(document).on('mouseup touchend', endMoving); //In endResize()... $(document).off('mouseup touchend', endMoving); $(document).off('mousemove touchmove', moving); //In startMoving()... $(document).on('mousemove touchmove', moving); $(document).on('mouseup touchend', endMoving); //In endMoving()... $(document).off('mouseup touchend', endMoving); $(document).off('mousemove touchmove', moving);







, "" . Hammer, . , , .



, , , saveEventState



. .



" " . , . moving



:



moving = function(e){ var mouse={}, touches; e.preventDefault(); e.stopPropagation(); touches = e.originalEvent.touches; mouse.x = (e.clientX || e.pageX || touches[0].clientX) + $(window).scrollLeft(); mouse.y = (e.clientY || e.pageY || touches[0].clientY) + $(window).scrollTop(); $container.offset({ 'left': mouse.x - ( event_state.mouse_x - event_state.container_left ), 'top': mouse.y - ( event_state.mouse_y - event_state.container_top ) }); // Watch for pinch zoom gesture while moving if(event_state.touches && event_state.touches.length > 1 && touches.length > 1){ var width = event_state.container_width, height = event_state.container_height; var a = event_state.touches[0].clientX - event_state.touches[1].clientX; a = a * a; var b = event_state.touches[0].clientY - event_state.touches[1].clientY; b = b * b; var dist1 = Math.sqrt( a + b ); a = e.originalEvent.touches[0].clientX - touches[1].clientX; a = a * a; b = e.originalEvent.touches[0].clientY - touches[1].clientY; b = b * b; var dist2 = Math.sqrt( a + b ); var ratio = dist2 /dist1; width = width * ratio; height = height * ratio; // To improve performance you might limit how often resizeImage() is called resizeImage(width, height); } };







.







. .



Chrome "", Firefox .



, .




  HTML5,     ,      ,   . 
      



- . , . , .



canvas




, , . , , .



. . , , . , .



!





:

<img class="resize-image" src="image.jpg" alt="Image" />







! HTML .



CSS

CSS- . resize-container



.



.resize-container { position: relative; display: inline-block; cursor: move; margin: 0 auto; } .resize-container img { display: block } .resize-container:hover img, .resize-container:active img { outline: 2px dashed rgba(222,60,80,.9); }







'resize handles'. , , .



.resize-handle-ne, .resize-handle-ne, .resize-handle-se, .resize-handle-nw, .resize-handle-sw { position: absolute; display: block; width: 10px; height: 10px; background: rgba(222,60,80,.9); z-index: 999; } .resize-handle-nw { top: -5px; left: -5px; cursor: nw-resize; } .resize-handle-sw { bottom: -5px; left: -5px; cursor: sw-resize; } .resize-handle-ne { top: -5px; right: -5px; cursor: ne-resize; } .resize-handle-se { bottom: -5px; right: -5px; cursor: se-resize; }







JavaScript

Canvas.



var resizeableImage = function(image_target) { var $container, orig_src = new Image(), image_target = $(image_target).get(0), event_state = {}, constrain = false, min_width = 60, min_height = 60, max_width = 800, max_height = 900, resize_canvas = document.createElement('canvas'); }); resizeableImage($('.resize-image'));







, . , , . jQuery , .



var resizeableImage = function(image_target) { // ... init = function(){ // Create a new image with a copy of the original src // When resizing, we will always use this original copy as the base orig_src.src=image_target.src; // Add resize handles $(image_target).wrap('<div class="resize-container"></div>') .before('<span class="resize-handle resize-handle-nw"></span>') .before('<span class="resize-handle resize-handle-ne"></span>') .after('<span class="resize-handle resize-handle-se"></span>') .after('<span class="resize-handle resize-handle-sw"></span>'); // Get a variable for the container $container = $(image_target).parent('.resize-container'); // Add events $container.on('mousedown', '.resize-handle', startResize); }; //... init(); }







startResize



endResize



, , .



startResize = function(e){ e.preventDefault(); e.stopPropagation(); saveEventState(e); $(document).on('mousemove', resizing); $(document).on('mouseup', endResize); }; endResize = function(e){ e.preventDefault(); $(document).off('mouseup touchend', endResize); $(document).off('mousemove touchmove', resizing); };







. event_state



.



saveEventState = function(e){ // Save the initial event details and container state event_state.container_width = $container.width(); event_state.container_height = $container.height(); event_state.container_left = $container.offset().left; event_state.container_top = $container.offset().top; event_state.mouse_x = (e.clientX || e.pageX || e.originalEvent.touches[0].clientX) + $(window).scrollLeft(); event_state.mouse_y = (e.clientY || e.pageY || e.originalEvent.touches[0].clientY) + $(window).scrollTop(); // This is a fix for mobile safari // For some reason it does not allow a direct copy of the touches property if(typeof e.originalEvent.touches !== 'undefined'){ event_state.touches = []; $.each(e.originalEvent.touches, function(i, ob){ event_state.touches[i] = {}; event_state.touches[i].clientX = 0+ob.clientX; event_state.touches[i].clientY = 0+ob.clientY; }); } event_state.evnt = e; }







resizing



- . . .



resizing = function(e){ var mouse={},width,height,left,top,offset=$container.offset(); mouse.x = (e.clientX || e.pageX || e.originalEvent.touches[0].clientX) + $(window).scrollLeft(); mouse.y = (e.clientY || e.pageY || e.originalEvent.touches[0].clientY) + $(window).scrollTop(); width = mouse.x - event_state.container_left; height = mouse.y - event_state.container_top; left = event_state.container_left; top = event_state.container_top; if(constrain || e.shiftKey){ height = width / orig_src.width * orig_src.height; } if(width > min_width && height > min_height && width < max_width && height < max_height){ resizeImage(width, height); // Without this Firefox will not re-calculate the the image dimensions until drag end $container.offset({'left': left, 'top': top}); } }







Shift .



.



: , , resizeImage



.





Canvas , drawImage



. , . toDataURL



Base64-encoded .



.



resizeImage = function(width, height){ resize_canvas.width = width; resize_canvas.height = height; resize_canvas.getContext('2d').drawImage(orig_src, 0, 0, width, height); $(image_target).attr('src', resize_canvas.toDataURL("image/png")); };







? : , CORS . , 'tainted canvas'.







. . , . , .



, , .







, . resizing



:



resizing = function(e){ var mouse={},width,height,left,top,offset=$container.offset(); mouse.x = (e.clientX || e.pageX || e.originalEvent.touches[0].clientX) + $(window).scrollLeft(); mouse.y = (e.clientY || e.pageY || e.originalEvent.touches[0].clientY) + $(window).scrollTop(); // Position image differently depending on the corner dragged and constraints if( $(event_state.evnt.target).hasClass('resize-handle-se') ){ width = mouse.x - event_state.container_left; height = mouse.y - event_state.container_top; left = event_state.container_left; top = event_state.container_top; } else if($(event_state.evnt.target).hasClass('resize-handle-sw') ){ width = event_state.container_width - (mouse.x - event_state.container_left); height = mouse.y - event_state.container_top; left = mouse.x; top = event_state.container_top; } else if($(event_state.evnt.target).hasClass('resize-handle-nw') ){ width = event_state.container_width - (mouse.x - event_state.container_left); height = event_state.container_height - (mouse.y - event_state.container_top); left = mouse.x; top = mouse.y; if(constrain || e.shiftKey){ top = mouse.y - ((width / orig_src.width * orig_src.height) - height); } } else if($(event_state.evnt.target).hasClass('resize-handle-ne') ){ width = mouse.x - event_state.container_left; height = event_state.container_height - (mouse.y - event_state.container_top); left = event_state.container_left; top = mouse.y; if(constrain || e.shiftKey){ top = mouse.y - ((width / orig_src.width * orig_src.height) - height); } } // Optionally maintain aspect ratio if(constrain || e.shiftKey){ height = width / orig_src.width * orig_src.height; } if(width > min_width && height > min_height && width < max_width && height < max_height){ // To improve performance you might limit how often resizeImage() is called resizeImage(width, height); // Without this Firefox will not re-calculate the the image dimensions until drag end $container.offset({'left': left, 'top': top}); } }







, resize-handle



, .





, , , , , "". . .



init = function(){ //... $container.on('mousedown', 'img', startMoving); }







startMoving



endMoving



, startResize



endResize



.



startMoving = function(e){ e.preventDefault(); e.stopPropagation(); saveEventState(e); $(document).on('mousemove', moving); $(document).on('mouseup', endMoving); }; endMoving = function(e){ e.preventDefault(); $(document).off('mouseup', endMoving); $(document).off('mousemove', moving); };







moving



. , .



moving = function(e){ var mouse={}; e.preventDefault(); e.stopPropagation(); mouse.x = (e.clientX || e.pageX) + $(window).scrollLeft(); mouse.y = (e.clientY || e.pageY) + $(window).scrollTop(); $container.offset({ 'left': mouse.x - ( event_state.mouse_x - event_state.container_left ), 'top': mouse.y - ( event_state.mouse_y - event_state.container_top ) }); };









, , . , , , , . , , , , .



HTML :



<div class="overlay"> <div class="overlay-inner"> </div> </div> <button class="btn-crop js-crop">Crop</button>







, , .



.overlay { position: absolute; left: 50%; top: 50%; margin-left: -100px; margin-top: -100px; z-index: 999; width: 200px; height: 200px; border: solid 2px rgba(222,60,80,.9); box-sizing: content-box; pointer-events: none; } .overlay:after, .overlay:before { content: ''; position: absolute; display: block; width: 204px; height: 40px; border-left: dashed 2px rgba(222,60,80,.9); border-right: dashed 2px rgba(222,60,80,.9); } .overlay:before { top: 0; margin-left: -2px; margin-top: -40px; } .overlay:after { bottom: 0; margin-left: -2px; margin-bottom: -40px; } .overlay-inner:after, .overlay-inner:before { content: ''; position: absolute; display: block; width: 40px; height: 204px; border-top: dashed 2px rgba(222,60,80,.9); border-bottom: dashed 2px rgba(222,60,80,.9); } .overlay-inner:before { left: 0; margin-left: -40px; margin-top: -2px; } .overlay-inner:after { right: 0; margin-right: -40px; margin-top: -2px; } .btn-crop { position: absolute; vertical-align: bottom; right: 5px; bottom: 5px; padding: 6px 10px; z-index: 999; background-color: rgb(222,60,80); border: none; border-radius: 5px; color: #FFF; }







JavaScript :



init = function(){ //... $('.js-crop').on('click', crop); }; crop = function(){ var crop_canvas, left = $('.overlay').offset().left - $container.offset().left, top = $('.overlay').offset().top - $container.offset().top, width = $('.overlay').width(), height = $('.overlay').height(); crop_canvas = document.createElement('canvas'); crop_canvas.width = width; crop_canvas.height = height; crop_canvas.getContext('2d').drawImage(image_target, left, top, width, height, 0, 0, width, height); window.open(crop_canvas.toDataURL("image/png")); }







crop



resizeImage



. , .



drawImage



canvas. - . - , . - , canvas, .





. .



mousedown



mouseup



- touchstart



touchend



, mousemove



touchmove



. , touchup



touchdown



( ).



touchstart



touchend



, mousedown



, mouseup



touchmove



, mousemove



.



// In init()... $container.on('mousedown touchstart', '.resize-handle', startResize); $container.on('mousedown touchstart', 'img', startMoving); //In startResize() ... $(document).on('mousemove touchmove', moving); $(document).on('mouseup touchend', endMoving); //In endResize()... $(document).off('mouseup touchend', endMoving); $(document).off('mousemove touchmove', moving); //In startMoving()... $(document).on('mousemove touchmove', moving); $(document).on('mouseup touchend', endMoving); //In endMoving()... $(document).off('mouseup touchend', endMoving); $(document).off('mousemove touchmove', moving);







, "" . Hammer, . , , .



, , , saveEventState



. .



" " . , . moving



:



moving = function(e){ var mouse={}, touches; e.preventDefault(); e.stopPropagation(); touches = e.originalEvent.touches; mouse.x = (e.clientX || e.pageX || touches[0].clientX) + $(window).scrollLeft(); mouse.y = (e.clientY || e.pageY || touches[0].clientY) + $(window).scrollTop(); $container.offset({ 'left': mouse.x - ( event_state.mouse_x - event_state.container_left ), 'top': mouse.y - ( event_state.mouse_y - event_state.container_top ) }); // Watch for pinch zoom gesture while moving if(event_state.touches && event_state.touches.length > 1 && touches.length > 1){ var width = event_state.container_width, height = event_state.container_height; var a = event_state.touches[0].clientX - event_state.touches[1].clientX; a = a * a; var b = event_state.touches[0].clientY - event_state.touches[1].clientY; b = b * b; var dist1 = Math.sqrt( a + b ); a = e.originalEvent.touches[0].clientX - touches[1].clientX; a = a * a; b = e.originalEvent.touches[0].clientY - touches[1].clientY; b = b * b; var dist2 = Math.sqrt( a + b ); var ratio = dist2 /dist1; width = width * ratio; height = height * ratio; // To improve performance you might limit how often resizeImage() is called resizeImage(width, height); } };







.







. .



Chrome "", Firefox .



, .




HTML5, , , .



- . , . , .



canvas




, , . , , .



. . , , . , .



!





:

<img class="resize-image" src="image.jpg" alt="Image" />







! HTML .



CSS

CSS- . resize-container



.



.resize-container { position: relative; display: inline-block; cursor: move; margin: 0 auto; } .resize-container img { display: block } .resize-container:hover img, .resize-container:active img { outline: 2px dashed rgba(222,60,80,.9); }







'resize handles'. , , .



.resize-handle-ne, .resize-handle-ne, .resize-handle-se, .resize-handle-nw, .resize-handle-sw { position: absolute; display: block; width: 10px; height: 10px; background: rgba(222,60,80,.9); z-index: 999; } .resize-handle-nw { top: -5px; left: -5px; cursor: nw-resize; } .resize-handle-sw { bottom: -5px; left: -5px; cursor: sw-resize; } .resize-handle-ne { top: -5px; right: -5px; cursor: ne-resize; } .resize-handle-se { bottom: -5px; right: -5px; cursor: se-resize; }







JavaScript

Canvas.



var resizeableImage = function(image_target) { var $container, orig_src = new Image(), image_target = $(image_target).get(0), event_state = {}, constrain = false, min_width = 60, min_height = 60, max_width = 800, max_height = 900, resize_canvas = document.createElement('canvas'); }); resizeableImage($('.resize-image'));







, . , , . jQuery , .



var resizeableImage = function(image_target) { // ... init = function(){ // Create a new image with a copy of the original src // When resizing, we will always use this original copy as the base orig_src.src=image_target.src; // Add resize handles $(image_target).wrap('<div class="resize-container"></div>') .before('<span class="resize-handle resize-handle-nw"></span>') .before('<span class="resize-handle resize-handle-ne"></span>') .after('<span class="resize-handle resize-handle-se"></span>') .after('<span class="resize-handle resize-handle-sw"></span>'); // Get a variable for the container $container = $(image_target).parent('.resize-container'); // Add events $container.on('mousedown', '.resize-handle', startResize); }; //... init(); }







startResize



endResize



, , .



startResize = function(e){ e.preventDefault(); e.stopPropagation(); saveEventState(e); $(document).on('mousemove', resizing); $(document).on('mouseup', endResize); }; endResize = function(e){ e.preventDefault(); $(document).off('mouseup touchend', endResize); $(document).off('mousemove touchmove', resizing); };







. event_state



.



saveEventState = function(e){ // Save the initial event details and container state event_state.container_width = $container.width(); event_state.container_height = $container.height(); event_state.container_left = $container.offset().left; event_state.container_top = $container.offset().top; event_state.mouse_x = (e.clientX || e.pageX || e.originalEvent.touches[0].clientX) + $(window).scrollLeft(); event_state.mouse_y = (e.clientY || e.pageY || e.originalEvent.touches[0].clientY) + $(window).scrollTop(); // This is a fix for mobile safari // For some reason it does not allow a direct copy of the touches property if(typeof e.originalEvent.touches !== 'undefined'){ event_state.touches = []; $.each(e.originalEvent.touches, function(i, ob){ event_state.touches[i] = {}; event_state.touches[i].clientX = 0+ob.clientX; event_state.touches[i].clientY = 0+ob.clientY; }); } event_state.evnt = e; }







resizing



- . . .



resizing = function(e){ var mouse={},width,height,left,top,offset=$container.offset(); mouse.x = (e.clientX || e.pageX || e.originalEvent.touches[0].clientX) + $(window).scrollLeft(); mouse.y = (e.clientY || e.pageY || e.originalEvent.touches[0].clientY) + $(window).scrollTop(); width = mouse.x - event_state.container_left; height = mouse.y - event_state.container_top; left = event_state.container_left; top = event_state.container_top; if(constrain || e.shiftKey){ height = width / orig_src.width * orig_src.height; } if(width > min_width && height > min_height && width < max_width && height < max_height){ resizeImage(width, height); // Without this Firefox will not re-calculate the the image dimensions until drag end $container.offset({'left': left, 'top': top}); } }







Shift .



.



: , , resizeImage



.





Canvas , drawImage



. , . toDataURL



Base64-encoded .



.



resizeImage = function(width, height){ resize_canvas.width = width; resize_canvas.height = height; resize_canvas.getContext('2d').drawImage(orig_src, 0, 0, width, height); $(image_target).attr('src', resize_canvas.toDataURL("image/png")); };







? : , CORS . , 'tainted canvas'.







. . , . , .



, , .







, . resizing



:



resizing = function(e){ var mouse={},width,height,left,top,offset=$container.offset(); mouse.x = (e.clientX || e.pageX || e.originalEvent.touches[0].clientX) + $(window).scrollLeft(); mouse.y = (e.clientY || e.pageY || e.originalEvent.touches[0].clientY) + $(window).scrollTop(); // Position image differently depending on the corner dragged and constraints if( $(event_state.evnt.target).hasClass('resize-handle-se') ){ width = mouse.x - event_state.container_left; height = mouse.y - event_state.container_top; left = event_state.container_left; top = event_state.container_top; } else if($(event_state.evnt.target).hasClass('resize-handle-sw') ){ width = event_state.container_width - (mouse.x - event_state.container_left); height = mouse.y - event_state.container_top; left = mouse.x; top = event_state.container_top; } else if($(event_state.evnt.target).hasClass('resize-handle-nw') ){ width = event_state.container_width - (mouse.x - event_state.container_left); height = event_state.container_height - (mouse.y - event_state.container_top); left = mouse.x; top = mouse.y; if(constrain || e.shiftKey){ top = mouse.y - ((width / orig_src.width * orig_src.height) - height); } } else if($(event_state.evnt.target).hasClass('resize-handle-ne') ){ width = mouse.x - event_state.container_left; height = event_state.container_height - (mouse.y - event_state.container_top); left = event_state.container_left; top = mouse.y; if(constrain || e.shiftKey){ top = mouse.y - ((width / orig_src.width * orig_src.height) - height); } } // Optionally maintain aspect ratio if(constrain || e.shiftKey){ height = width / orig_src.width * orig_src.height; } if(width > min_width && height > min_height && width < max_width && height < max_height){ // To improve performance you might limit how often resizeImage() is called resizeImage(width, height); // Without this Firefox will not re-calculate the the image dimensions until drag end $container.offset({'left': left, 'top': top}); } }







, resize-handle



, .





, , , , , "". . .



init = function(){ //... $container.on('mousedown', 'img', startMoving); }







startMoving



endMoving



, startResize



endResize



.



startMoving = function(e){ e.preventDefault(); e.stopPropagation(); saveEventState(e); $(document).on('mousemove', moving); $(document).on('mouseup', endMoving); }; endMoving = function(e){ e.preventDefault(); $(document).off('mouseup', endMoving); $(document).off('mousemove', moving); };







moving



. , .



moving = function(e){ var mouse={}; e.preventDefault(); e.stopPropagation(); mouse.x = (e.clientX || e.pageX) + $(window).scrollLeft(); mouse.y = (e.clientY || e.pageY) + $(window).scrollTop(); $container.offset({ 'left': mouse.x - ( event_state.mouse_x - event_state.container_left ), 'top': mouse.y - ( event_state.mouse_y - event_state.container_top ) }); };









, , . , , , , . , , , , .



HTML :



<div class="overlay"> <div class="overlay-inner"> </div> </div> <button class="btn-crop js-crop">Crop</button>







, , .



.overlay { position: absolute; left: 50%; top: 50%; margin-left: -100px; margin-top: -100px; z-index: 999; width: 200px; height: 200px; border: solid 2px rgba(222,60,80,.9); box-sizing: content-box; pointer-events: none; } .overlay:after, .overlay:before { content: ''; position: absolute; display: block; width: 204px; height: 40px; border-left: dashed 2px rgba(222,60,80,.9); border-right: dashed 2px rgba(222,60,80,.9); } .overlay:before { top: 0; margin-left: -2px; margin-top: -40px; } .overlay:after { bottom: 0; margin-left: -2px; margin-bottom: -40px; } .overlay-inner:after, .overlay-inner:before { content: ''; position: absolute; display: block; width: 40px; height: 204px; border-top: dashed 2px rgba(222,60,80,.9); border-bottom: dashed 2px rgba(222,60,80,.9); } .overlay-inner:before { left: 0; margin-left: -40px; margin-top: -2px; } .overlay-inner:after { right: 0; margin-right: -40px; margin-top: -2px; } .btn-crop { position: absolute; vertical-align: bottom; right: 5px; bottom: 5px; padding: 6px 10px; z-index: 999; background-color: rgb(222,60,80); border: none; border-radius: 5px; color: #FFF; }







JavaScript :



init = function(){ //... $('.js-crop').on('click', crop); }; crop = function(){ var crop_canvas, left = $('.overlay').offset().left - $container.offset().left, top = $('.overlay').offset().top - $container.offset().top, width = $('.overlay').width(), height = $('.overlay').height(); crop_canvas = document.createElement('canvas'); crop_canvas.width = width; crop_canvas.height = height; crop_canvas.getContext('2d').drawImage(image_target, left, top, width, height, 0, 0, width, height); window.open(crop_canvas.toDataURL("image/png")); }







crop



resizeImage



. , .



drawImage



canvas. - . - , . - , canvas, .





. .



mousedown



mouseup



- touchstart



touchend



, mousemove



touchmove



. , touchup



touchdown



( ).



touchstart



touchend



, mousedown



, mouseup



touchmove



, mousemove



.



// In init()... $container.on('mousedown touchstart', '.resize-handle', startResize); $container.on('mousedown touchstart', 'img', startMoving); //In startResize() ... $(document).on('mousemove touchmove', moving); $(document).on('mouseup touchend', endMoving); //In endResize()... $(document).off('mouseup touchend', endMoving); $(document).off('mousemove touchmove', moving); //In startMoving()... $(document).on('mousemove touchmove', moving); $(document).on('mouseup touchend', endMoving); //In endMoving()... $(document).off('mouseup touchend', endMoving); $(document).off('mousemove touchmove', moving);







, "" . Hammer, . , , .



, , , saveEventState



. .



" " . , . moving



:



moving = function(e){ var mouse={}, touches; e.preventDefault(); e.stopPropagation(); touches = e.originalEvent.touches; mouse.x = (e.clientX || e.pageX || touches[0].clientX) + $(window).scrollLeft(); mouse.y = (e.clientY || e.pageY || touches[0].clientY) + $(window).scrollTop(); $container.offset({ 'left': mouse.x - ( event_state.mouse_x - event_state.container_left ), 'top': mouse.y - ( event_state.mouse_y - event_state.container_top ) }); // Watch for pinch zoom gesture while moving if(event_state.touches && event_state.touches.length > 1 && touches.length > 1){ var width = event_state.container_width, height = event_state.container_height; var a = event_state.touches[0].clientX - event_state.touches[1].clientX; a = a * a; var b = event_state.touches[0].clientY - event_state.touches[1].clientY; b = b * b; var dist1 = Math.sqrt( a + b ); a = e.originalEvent.touches[0].clientX - touches[1].clientX; a = a * a; b = e.originalEvent.touches[0].clientY - touches[1].clientY; b = b * b; var dist2 = Math.sqrt( a + b ); var ratio = dist2 /dist1; width = width * ratio; height = height * ratio; // To improve performance you might limit how often resizeImage() is called resizeImage(width, height); } };







.







. .



Chrome "", Firefox .



, .




  HTML5,     ,      ,   . 
      



- . , . , .



canvas




, , . , , .



. . , , . , .



!





:

<img class="resize-image" src="image.jpg" alt="Image" />







! HTML .



CSS

CSS- . resize-container



.



.resize-container { position: relative; display: inline-block; cursor: move; margin: 0 auto; } .resize-container img { display: block } .resize-container:hover img, .resize-container:active img { outline: 2px dashed rgba(222,60,80,.9); }







'resize handles'. , , .



.resize-handle-ne, .resize-handle-ne, .resize-handle-se, .resize-handle-nw, .resize-handle-sw { position: absolute; display: block; width: 10px; height: 10px; background: rgba(222,60,80,.9); z-index: 999; } .resize-handle-nw { top: -5px; left: -5px; cursor: nw-resize; } .resize-handle-sw { bottom: -5px; left: -5px; cursor: sw-resize; } .resize-handle-ne { top: -5px; right: -5px; cursor: ne-resize; } .resize-handle-se { bottom: -5px; right: -5px; cursor: se-resize; }







JavaScript

Canvas.



var resizeableImage = function(image_target) { var $container, orig_src = new Image(), image_target = $(image_target).get(0), event_state = {}, constrain = false, min_width = 60, min_height = 60, max_width = 800, max_height = 900, resize_canvas = document.createElement('canvas'); }); resizeableImage($('.resize-image'));







, . , , . jQuery , .



var resizeableImage = function(image_target) { // ... init = function(){ // Create a new image with a copy of the original src // When resizing, we will always use this original copy as the base orig_src.src=image_target.src; // Add resize handles $(image_target).wrap('<div class="resize-container"></div>') .before('<span class="resize-handle resize-handle-nw"></span>') .before('<span class="resize-handle resize-handle-ne"></span>') .after('<span class="resize-handle resize-handle-se"></span>') .after('<span class="resize-handle resize-handle-sw"></span>'); // Get a variable for the container $container = $(image_target).parent('.resize-container'); // Add events $container.on('mousedown', '.resize-handle', startResize); }; //... init(); }







startResize



endResize



, , .



startResize = function(e){ e.preventDefault(); e.stopPropagation(); saveEventState(e); $(document).on('mousemove', resizing); $(document).on('mouseup', endResize); }; endResize = function(e){ e.preventDefault(); $(document).off('mouseup touchend', endResize); $(document).off('mousemove touchmove', resizing); };







. event_state



.



saveEventState = function(e){ // Save the initial event details and container state event_state.container_width = $container.width(); event_state.container_height = $container.height(); event_state.container_left = $container.offset().left; event_state.container_top = $container.offset().top; event_state.mouse_x = (e.clientX || e.pageX || e.originalEvent.touches[0].clientX) + $(window).scrollLeft(); event_state.mouse_y = (e.clientY || e.pageY || e.originalEvent.touches[0].clientY) + $(window).scrollTop(); // This is a fix for mobile safari // For some reason it does not allow a direct copy of the touches property if(typeof e.originalEvent.touches !== 'undefined'){ event_state.touches = []; $.each(e.originalEvent.touches, function(i, ob){ event_state.touches[i] = {}; event_state.touches[i].clientX = 0+ob.clientX; event_state.touches[i].clientY = 0+ob.clientY; }); } event_state.evnt = e; }







resizing



- . . .



resizing = function(e){ var mouse={},width,height,left,top,offset=$container.offset(); mouse.x = (e.clientX || e.pageX || e.originalEvent.touches[0].clientX) + $(window).scrollLeft(); mouse.y = (e.clientY || e.pageY || e.originalEvent.touches[0].clientY) + $(window).scrollTop(); width = mouse.x - event_state.container_left; height = mouse.y - event_state.container_top; left = event_state.container_left; top = event_state.container_top; if(constrain || e.shiftKey){ height = width / orig_src.width * orig_src.height; } if(width > min_width && height > min_height && width < max_width && height < max_height){ resizeImage(width, height); // Without this Firefox will not re-calculate the the image dimensions until drag end $container.offset({'left': left, 'top': top}); } }







Shift .



.



: , , resizeImage



.





Canvas , drawImage



. , . toDataURL



Base64-encoded .



.



resizeImage = function(width, height){ resize_canvas.width = width; resize_canvas.height = height; resize_canvas.getContext('2d').drawImage(orig_src, 0, 0, width, height); $(image_target).attr('src', resize_canvas.toDataURL("image/png")); };







? : , CORS . , 'tainted canvas'.







. . , . , .



, , .







, . resizing



:



resizing = function(e){ var mouse={},width,height,left,top,offset=$container.offset(); mouse.x = (e.clientX || e.pageX || e.originalEvent.touches[0].clientX) + $(window).scrollLeft(); mouse.y = (e.clientY || e.pageY || e.originalEvent.touches[0].clientY) + $(window).scrollTop(); // Position image differently depending on the corner dragged and constraints if( $(event_state.evnt.target).hasClass('resize-handle-se') ){ width = mouse.x - event_state.container_left; height = mouse.y - event_state.container_top; left = event_state.container_left; top = event_state.container_top; } else if($(event_state.evnt.target).hasClass('resize-handle-sw') ){ width = event_state.container_width - (mouse.x - event_state.container_left); height = mouse.y - event_state.container_top; left = mouse.x; top = event_state.container_top; } else if($(event_state.evnt.target).hasClass('resize-handle-nw') ){ width = event_state.container_width - (mouse.x - event_state.container_left); height = event_state.container_height - (mouse.y - event_state.container_top); left = mouse.x; top = mouse.y; if(constrain || e.shiftKey){ top = mouse.y - ((width / orig_src.width * orig_src.height) - height); } } else if($(event_state.evnt.target).hasClass('resize-handle-ne') ){ width = mouse.x - event_state.container_left; height = event_state.container_height - (mouse.y - event_state.container_top); left = event_state.container_left; top = mouse.y; if(constrain || e.shiftKey){ top = mouse.y - ((width / orig_src.width * orig_src.height) - height); } } // Optionally maintain aspect ratio if(constrain || e.shiftKey){ height = width / orig_src.width * orig_src.height; } if(width > min_width && height > min_height && width < max_width && height < max_height){ // To improve performance you might limit how often resizeImage() is called resizeImage(width, height); // Without this Firefox will not re-calculate the the image dimensions until drag end $container.offset({'left': left, 'top': top}); } }







, resize-handle



, .





, , , , , "". . .



init = function(){ //... $container.on('mousedown', 'img', startMoving); }







startMoving



endMoving



, startResize



endResize



.



startMoving = function(e){ e.preventDefault(); e.stopPropagation(); saveEventState(e); $(document).on('mousemove', moving); $(document).on('mouseup', endMoving); }; endMoving = function(e){ e.preventDefault(); $(document).off('mouseup', endMoving); $(document).off('mousemove', moving); };







moving



. , .



moving = function(e){ var mouse={}; e.preventDefault(); e.stopPropagation(); mouse.x = (e.clientX || e.pageX) + $(window).scrollLeft(); mouse.y = (e.clientY || e.pageY) + $(window).scrollTop(); $container.offset({ 'left': mouse.x - ( event_state.mouse_x - event_state.container_left ), 'top': mouse.y - ( event_state.mouse_y - event_state.container_top ) }); };









, , . , , , , . , , , , .



HTML :



<div class="overlay"> <div class="overlay-inner"> </div> </div> <button class="btn-crop js-crop">Crop</button>







, , .



.overlay { position: absolute; left: 50%; top: 50%; margin-left: -100px; margin-top: -100px; z-index: 999; width: 200px; height: 200px; border: solid 2px rgba(222,60,80,.9); box-sizing: content-box; pointer-events: none; } .overlay:after, .overlay:before { content: ''; position: absolute; display: block; width: 204px; height: 40px; border-left: dashed 2px rgba(222,60,80,.9); border-right: dashed 2px rgba(222,60,80,.9); } .overlay:before { top: 0; margin-left: -2px; margin-top: -40px; } .overlay:after { bottom: 0; margin-left: -2px; margin-bottom: -40px; } .overlay-inner:after, .overlay-inner:before { content: ''; position: absolute; display: block; width: 40px; height: 204px; border-top: dashed 2px rgba(222,60,80,.9); border-bottom: dashed 2px rgba(222,60,80,.9); } .overlay-inner:before { left: 0; margin-left: -40px; margin-top: -2px; } .overlay-inner:after { right: 0; margin-right: -40px; margin-top: -2px; } .btn-crop { position: absolute; vertical-align: bottom; right: 5px; bottom: 5px; padding: 6px 10px; z-index: 999; background-color: rgb(222,60,80); border: none; border-radius: 5px; color: #FFF; }







JavaScript :



init = function(){ //... $('.js-crop').on('click', crop); }; crop = function(){ var crop_canvas, left = $('.overlay').offset().left - $container.offset().left, top = $('.overlay').offset().top - $container.offset().top, width = $('.overlay').width(), height = $('.overlay').height(); crop_canvas = document.createElement('canvas'); crop_canvas.width = width; crop_canvas.height = height; crop_canvas.getContext('2d').drawImage(image_target, left, top, width, height, 0, 0, width, height); window.open(crop_canvas.toDataURL("image/png")); }







crop



resizeImage



. , .



drawImage



canvas. - . - , . - , canvas, .





. .



mousedown



mouseup



- touchstart



touchend



, mousemove



touchmove



. , touchup



touchdown



( ).



touchstart



touchend



, mousedown



, mouseup



touchmove



, mousemove



.



// In init()... $container.on('mousedown touchstart', '.resize-handle', startResize); $container.on('mousedown touchstart', 'img', startMoving); //In startResize() ... $(document).on('mousemove touchmove', moving); $(document).on('mouseup touchend', endMoving); //In endResize()... $(document).off('mouseup touchend', endMoving); $(document).off('mousemove touchmove', moving); //In startMoving()... $(document).on('mousemove touchmove', moving); $(document).on('mouseup touchend', endMoving); //In endMoving()... $(document).off('mouseup touchend', endMoving); $(document).off('mousemove touchmove', moving);







, "" . Hammer, . , , .



, , , saveEventState



. .



" " . , . moving



:



moving = function(e){ var mouse={}, touches; e.preventDefault(); e.stopPropagation(); touches = e.originalEvent.touches; mouse.x = (e.clientX || e.pageX || touches[0].clientX) + $(window).scrollLeft(); mouse.y = (e.clientY || e.pageY || touches[0].clientY) + $(window).scrollTop(); $container.offset({ 'left': mouse.x - ( event_state.mouse_x - event_state.container_left ), 'top': mouse.y - ( event_state.mouse_y - event_state.container_top ) }); // Watch for pinch zoom gesture while moving if(event_state.touches && event_state.touches.length > 1 && touches.length > 1){ var width = event_state.container_width, height = event_state.container_height; var a = event_state.touches[0].clientX - event_state.touches[1].clientX; a = a * a; var b = event_state.touches[0].clientY - event_state.touches[1].clientY; b = b * b; var dist1 = Math.sqrt( a + b ); a = e.originalEvent.touches[0].clientX - touches[1].clientX; a = a * a; b = e.originalEvent.touches[0].clientY - touches[1].clientY; b = b * b; var dist2 = Math.sqrt( a + b ); var ratio = dist2 /dist1; width = width * ratio; height = height * ratio; // To improve performance you might limit how often resizeImage() is called resizeImage(width, height); } };







.







. .



Chrome "", Firefox .



, .




HTML5, , , .



- . , . , .



canvas




, , . , , .



. . , , . , .



!





:

<img class="resize-image" src="image.jpg" alt="Image" />







! HTML .



CSS

CSS- . resize-container



.



.resize-container { position: relative; display: inline-block; cursor: move; margin: 0 auto; } .resize-container img { display: block } .resize-container:hover img, .resize-container:active img { outline: 2px dashed rgba(222,60,80,.9); }







'resize handles'. , , .



.resize-handle-ne, .resize-handle-ne, .resize-handle-se, .resize-handle-nw, .resize-handle-sw { position: absolute; display: block; width: 10px; height: 10px; background: rgba(222,60,80,.9); z-index: 999; } .resize-handle-nw { top: -5px; left: -5px; cursor: nw-resize; } .resize-handle-sw { bottom: -5px; left: -5px; cursor: sw-resize; } .resize-handle-ne { top: -5px; right: -5px; cursor: ne-resize; } .resize-handle-se { bottom: -5px; right: -5px; cursor: se-resize; }







JavaScript

Canvas.



var resizeableImage = function(image_target) { var $container, orig_src = new Image(), image_target = $(image_target).get(0), event_state = {}, constrain = false, min_width = 60, min_height = 60, max_width = 800, max_height = 900, resize_canvas = document.createElement('canvas'); }); resizeableImage($('.resize-image'));







, . , , . jQuery , .



var resizeableImage = function(image_target) { // ... init = function(){ // Create a new image with a copy of the original src // When resizing, we will always use this original copy as the base orig_src.src=image_target.src; // Add resize handles $(image_target).wrap('<div class="resize-container"></div>') .before('<span class="resize-handle resize-handle-nw"></span>') .before('<span class="resize-handle resize-handle-ne"></span>') .after('<span class="resize-handle resize-handle-se"></span>') .after('<span class="resize-handle resize-handle-sw"></span>'); // Get a variable for the container $container = $(image_target).parent('.resize-container'); // Add events $container.on('mousedown', '.resize-handle', startResize); }; //... init(); }







startResize



endResize



, , .



startResize = function(e){ e.preventDefault(); e.stopPropagation(); saveEventState(e); $(document).on('mousemove', resizing); $(document).on('mouseup', endResize); }; endResize = function(e){ e.preventDefault(); $(document).off('mouseup touchend', endResize); $(document).off('mousemove touchmove', resizing); };







. event_state



.



saveEventState = function(e){ // Save the initial event details and container state event_state.container_width = $container.width(); event_state.container_height = $container.height(); event_state.container_left = $container.offset().left; event_state.container_top = $container.offset().top; event_state.mouse_x = (e.clientX || e.pageX || e.originalEvent.touches[0].clientX) + $(window).scrollLeft(); event_state.mouse_y = (e.clientY || e.pageY || e.originalEvent.touches[0].clientY) + $(window).scrollTop(); // This is a fix for mobile safari // For some reason it does not allow a direct copy of the touches property if(typeof e.originalEvent.touches !== 'undefined'){ event_state.touches = []; $.each(e.originalEvent.touches, function(i, ob){ event_state.touches[i] = {}; event_state.touches[i].clientX = 0+ob.clientX; event_state.touches[i].clientY = 0+ob.clientY; }); } event_state.evnt = e; }







resizing



- . . .



resizing = function(e){ var mouse={},width,height,left,top,offset=$container.offset(); mouse.x = (e.clientX || e.pageX || e.originalEvent.touches[0].clientX) + $(window).scrollLeft(); mouse.y = (e.clientY || e.pageY || e.originalEvent.touches[0].clientY) + $(window).scrollTop(); width = mouse.x - event_state.container_left; height = mouse.y - event_state.container_top; left = event_state.container_left; top = event_state.container_top; if(constrain || e.shiftKey){ height = width / orig_src.width * orig_src.height; } if(width > min_width && height > min_height && width < max_width && height < max_height){ resizeImage(width, height); // Without this Firefox will not re-calculate the the image dimensions until drag end $container.offset({'left': left, 'top': top}); } }







Shift .



.



: , , resizeImage



.





Canvas , drawImage



. , . toDataURL



Base64-encoded .



.



resizeImage = function(width, height){ resize_canvas.width = width; resize_canvas.height = height; resize_canvas.getContext('2d').drawImage(orig_src, 0, 0, width, height); $(image_target).attr('src', resize_canvas.toDataURL("image/png")); };







? : , CORS . , 'tainted canvas'.







. . , . , .



, , .







, . resizing



:



resizing = function(e){ var mouse={},width,height,left,top,offset=$container.offset(); mouse.x = (e.clientX || e.pageX || e.originalEvent.touches[0].clientX) + $(window).scrollLeft(); mouse.y = (e.clientY || e.pageY || e.originalEvent.touches[0].clientY) + $(window).scrollTop(); // Position image differently depending on the corner dragged and constraints if( $(event_state.evnt.target).hasClass('resize-handle-se') ){ width = mouse.x - event_state.container_left; height = mouse.y - event_state.container_top; left = event_state.container_left; top = event_state.container_top; } else if($(event_state.evnt.target).hasClass('resize-handle-sw') ){ width = event_state.container_width - (mouse.x - event_state.container_left); height = mouse.y - event_state.container_top; left = mouse.x; top = event_state.container_top; } else if($(event_state.evnt.target).hasClass('resize-handle-nw') ){ width = event_state.container_width - (mouse.x - event_state.container_left); height = event_state.container_height - (mouse.y - event_state.container_top); left = mouse.x; top = mouse.y; if(constrain || e.shiftKey){ top = mouse.y - ((width / orig_src.width * orig_src.height) - height); } } else if($(event_state.evnt.target).hasClass('resize-handle-ne') ){ width = mouse.x - event_state.container_left; height = event_state.container_height - (mouse.y - event_state.container_top); left = event_state.container_left; top = mouse.y; if(constrain || e.shiftKey){ top = mouse.y - ((width / orig_src.width * orig_src.height) - height); } } // Optionally maintain aspect ratio if(constrain || e.shiftKey){ height = width / orig_src.width * orig_src.height; } if(width > min_width && height > min_height && width < max_width && height < max_height){ // To improve performance you might limit how often resizeImage() is called resizeImage(width, height); // Without this Firefox will not re-calculate the the image dimensions until drag end $container.offset({'left': left, 'top': top}); } }







, resize-handle



, .





, , , , , "". . .



init = function(){ //... $container.on('mousedown', 'img', startMoving); }







startMoving



endMoving



, startResize



endResize



.



startMoving = function(e){ e.preventDefault(); e.stopPropagation(); saveEventState(e); $(document).on('mousemove', moving); $(document).on('mouseup', endMoving); }; endMoving = function(e){ e.preventDefault(); $(document).off('mouseup', endMoving); $(document).off('mousemove', moving); };







moving



. , .



moving = function(e){ var mouse={}; e.preventDefault(); e.stopPropagation(); mouse.x = (e.clientX || e.pageX) + $(window).scrollLeft(); mouse.y = (e.clientY || e.pageY) + $(window).scrollTop(); $container.offset({ 'left': mouse.x - ( event_state.mouse_x - event_state.container_left ), 'top': mouse.y - ( event_state.mouse_y - event_state.container_top ) }); };









, , . , , , , . , , , , .



HTML :



<div class="overlay"> <div class="overlay-inner"> </div> </div> <button class="btn-crop js-crop">Crop</button>







, , .



.overlay { position: absolute; left: 50%; top: 50%; margin-left: -100px; margin-top: -100px; z-index: 999; width: 200px; height: 200px; border: solid 2px rgba(222,60,80,.9); box-sizing: content-box; pointer-events: none; } .overlay:after, .overlay:before { content: ''; position: absolute; display: block; width: 204px; height: 40px; border-left: dashed 2px rgba(222,60,80,.9); border-right: dashed 2px rgba(222,60,80,.9); } .overlay:before { top: 0; margin-left: -2px; margin-top: -40px; } .overlay:after { bottom: 0; margin-left: -2px; margin-bottom: -40px; } .overlay-inner:after, .overlay-inner:before { content: ''; position: absolute; display: block; width: 40px; height: 204px; border-top: dashed 2px rgba(222,60,80,.9); border-bottom: dashed 2px rgba(222,60,80,.9); } .overlay-inner:before { left: 0; margin-left: -40px; margin-top: -2px; } .overlay-inner:after { right: 0; margin-right: -40px; margin-top: -2px; } .btn-crop { position: absolute; vertical-align: bottom; right: 5px; bottom: 5px; padding: 6px 10px; z-index: 999; background-color: rgb(222,60,80); border: none; border-radius: 5px; color: #FFF; }







JavaScript :



init = function(){ //... $('.js-crop').on('click', crop); }; crop = function(){ var crop_canvas, left = $('.overlay').offset().left - $container.offset().left, top = $('.overlay').offset().top - $container.offset().top, width = $('.overlay').width(), height = $('.overlay').height(); crop_canvas = document.createElement('canvas'); crop_canvas.width = width; crop_canvas.height = height; crop_canvas.getContext('2d').drawImage(image_target, left, top, width, height, 0, 0, width, height); window.open(crop_canvas.toDataURL("image/png")); }







crop



resizeImage



. , .



drawImage



canvas. - . - , . - , canvas, .





. .



mousedown



mouseup



- touchstart



touchend



, mousemove



touchmove



. , touchup



touchdown



( ).



touchstart



touchend



, mousedown



, mouseup



touchmove



, mousemove



.



// In init()... $container.on('mousedown touchstart', '.resize-handle', startResize); $container.on('mousedown touchstart', 'img', startMoving); //In startResize() ... $(document).on('mousemove touchmove', moving); $(document).on('mouseup touchend', endMoving); //In endResize()... $(document).off('mouseup touchend', endMoving); $(document).off('mousemove touchmove', moving); //In startMoving()... $(document).on('mousemove touchmove', moving); $(document).on('mouseup touchend', endMoving); //In endMoving()... $(document).off('mouseup touchend', endMoving); $(document).off('mousemove touchmove', moving);







, "" . Hammer, . , , .



, , , saveEventState



. .



" " . , . moving



:



moving = function(e){ var mouse={}, touches; e.preventDefault(); e.stopPropagation(); touches = e.originalEvent.touches; mouse.x = (e.clientX || e.pageX || touches[0].clientX) + $(window).scrollLeft(); mouse.y = (e.clientY || e.pageY || touches[0].clientY) + $(window).scrollTop(); $container.offset({ 'left': mouse.x - ( event_state.mouse_x - event_state.container_left ), 'top': mouse.y - ( event_state.mouse_y - event_state.container_top ) }); // Watch for pinch zoom gesture while moving if(event_state.touches && event_state.touches.length > 1 && touches.length > 1){ var width = event_state.container_width, height = event_state.container_height; var a = event_state.touches[0].clientX - event_state.touches[1].clientX; a = a * a; var b = event_state.touches[0].clientY - event_state.touches[1].clientY; b = b * b; var dist1 = Math.sqrt( a + b ); a = e.originalEvent.touches[0].clientX - touches[1].clientX; a = a * a; b = e.originalEvent.touches[0].clientY - touches[1].clientY; b = b * b; var dist2 = Math.sqrt( a + b ); var ratio = dist2 /dist1; width = width * ratio; height = height * ratio; // To improve performance you might limit how often resizeImage() is called resizeImage(width, height); } };







.







. .



Chrome "", Firefox .



, .




HTML5, , , .



- . , . , .



canvas




, , . , , .



. . , , . , .



!





:

<img class="resize-image" src="image.jpg" alt="Image" />







! HTML .



CSS

CSS- . resize-container



.



.resize-container { position: relative; display: inline-block; cursor: move; margin: 0 auto; } .resize-container img { display: block } .resize-container:hover img, .resize-container:active img { outline: 2px dashed rgba(222,60,80,.9); }







'resize handles'. , , .



.resize-handle-ne, .resize-handle-ne, .resize-handle-se, .resize-handle-nw, .resize-handle-sw { position: absolute; display: block; width: 10px; height: 10px; background: rgba(222,60,80,.9); z-index: 999; } .resize-handle-nw { top: -5px; left: -5px; cursor: nw-resize; } .resize-handle-sw { bottom: -5px; left: -5px; cursor: sw-resize; } .resize-handle-ne { top: -5px; right: -5px; cursor: ne-resize; } .resize-handle-se { bottom: -5px; right: -5px; cursor: se-resize; }







JavaScript

Canvas.



var resizeableImage = function(image_target) { var $container, orig_src = new Image(), image_target = $(image_target).get(0), event_state = {}, constrain = false, min_width = 60, min_height = 60, max_width = 800, max_height = 900, resize_canvas = document.createElement('canvas'); }); resizeableImage($('.resize-image'));







, . , , . jQuery , .



var resizeableImage = function(image_target) { // ... init = function(){ // Create a new image with a copy of the original src // When resizing, we will always use this original copy as the base orig_src.src=image_target.src; // Add resize handles $(image_target).wrap('<div class="resize-container"></div>') .before('<span class="resize-handle resize-handle-nw"></span>') .before('<span class="resize-handle resize-handle-ne"></span>') .after('<span class="resize-handle resize-handle-se"></span>') .after('<span class="resize-handle resize-handle-sw"></span>'); // Get a variable for the container $container = $(image_target).parent('.resize-container'); // Add events $container.on('mousedown', '.resize-handle', startResize); }; //... init(); }







startResize



endResize



, , .



startResize = function(e){ e.preventDefault(); e.stopPropagation(); saveEventState(e); $(document).on('mousemove', resizing); $(document).on('mouseup', endResize); }; endResize = function(e){ e.preventDefault(); $(document).off('mouseup touchend', endResize); $(document).off('mousemove touchmove', resizing); };







. event_state



.



saveEventState = function(e){ // Save the initial event details and container state event_state.container_width = $container.width(); event_state.container_height = $container.height(); event_state.container_left = $container.offset().left; event_state.container_top = $container.offset().top; event_state.mouse_x = (e.clientX || e.pageX || e.originalEvent.touches[0].clientX) + $(window).scrollLeft(); event_state.mouse_y = (e.clientY || e.pageY || e.originalEvent.touches[0].clientY) + $(window).scrollTop(); // This is a fix for mobile safari // For some reason it does not allow a direct copy of the touches property if(typeof e.originalEvent.touches !== 'undefined'){ event_state.touches = []; $.each(e.originalEvent.touches, function(i, ob){ event_state.touches[i] = {}; event_state.touches[i].clientX = 0+ob.clientX; event_state.touches[i].clientY = 0+ob.clientY; }); } event_state.evnt = e; }







resizing



- . . .



resizing = function(e){ var mouse={},width,height,left,top,offset=$container.offset(); mouse.x = (e.clientX || e.pageX || e.originalEvent.touches[0].clientX) + $(window).scrollLeft(); mouse.y = (e.clientY || e.pageY || e.originalEvent.touches[0].clientY) + $(window).scrollTop(); width = mouse.x - event_state.container_left; height = mouse.y - event_state.container_top; left = event_state.container_left; top = event_state.container_top; if(constrain || e.shiftKey){ height = width / orig_src.width * orig_src.height; } if(width > min_width && height > min_height && width < max_width && height < max_height){ resizeImage(width, height); // Without this Firefox will not re-calculate the the image dimensions until drag end $container.offset({'left': left, 'top': top}); } }







Shift .



.



: , , resizeImage



.





Canvas , drawImage



. , . toDataURL



Base64-encoded .



.



resizeImage = function(width, height){ resize_canvas.width = width; resize_canvas.height = height; resize_canvas.getContext('2d').drawImage(orig_src, 0, 0, width, height); $(image_target).attr('src', resize_canvas.toDataURL("image/png")); };







? : , CORS . , 'tainted canvas'.







. . , . , .



, , .







, . resizing



:



resizing = function(e){ var mouse={},width,height,left,top,offset=$container.offset(); mouse.x = (e.clientX || e.pageX || e.originalEvent.touches[0].clientX) + $(window).scrollLeft(); mouse.y = (e.clientY || e.pageY || e.originalEvent.touches[0].clientY) + $(window).scrollTop(); // Position image differently depending on the corner dragged and constraints if( $(event_state.evnt.target).hasClass('resize-handle-se') ){ width = mouse.x - event_state.container_left; height = mouse.y - event_state.container_top; left = event_state.container_left; top = event_state.container_top; } else if($(event_state.evnt.target).hasClass('resize-handle-sw') ){ width = event_state.container_width - (mouse.x - event_state.container_left); height = mouse.y - event_state.container_top; left = mouse.x; top = event_state.container_top; } else if($(event_state.evnt.target).hasClass('resize-handle-nw') ){ width = event_state.container_width - (mouse.x - event_state.container_left); height = event_state.container_height - (mouse.y - event_state.container_top); left = mouse.x; top = mouse.y; if(constrain || e.shiftKey){ top = mouse.y - ((width / orig_src.width * orig_src.height) - height); } } else if($(event_state.evnt.target).hasClass('resize-handle-ne') ){ width = mouse.x - event_state.container_left; height = event_state.container_height - (mouse.y - event_state.container_top); left = event_state.container_left; top = mouse.y; if(constrain || e.shiftKey){ top = mouse.y - ((width / orig_src.width * orig_src.height) - height); } } // Optionally maintain aspect ratio if(constrain || e.shiftKey){ height = width / orig_src.width * orig_src.height; } if(width > min_width && height > min_height && width < max_width && height < max_height){ // To improve performance you might limit how often resizeImage() is called resizeImage(width, height); // Without this Firefox will not re-calculate the the image dimensions until drag end $container.offset({'left': left, 'top': top}); } }







, resize-handle



, .





, , , , , "". . .



init = function(){ //... $container.on('mousedown', 'img', startMoving); }







startMoving



endMoving



, startResize



endResize



.



startMoving = function(e){ e.preventDefault(); e.stopPropagation(); saveEventState(e); $(document).on('mousemove', moving); $(document).on('mouseup', endMoving); }; endMoving = function(e){ e.preventDefault(); $(document).off('mouseup', endMoving); $(document).off('mousemove', moving); };







moving



. , .



moving = function(e){ var mouse={}; e.preventDefault(); e.stopPropagation(); mouse.x = (e.clientX || e.pageX) + $(window).scrollLeft(); mouse.y = (e.clientY || e.pageY) + $(window).scrollTop(); $container.offset({ 'left': mouse.x - ( event_state.mouse_x - event_state.container_left ), 'top': mouse.y - ( event_state.mouse_y - event_state.container_top ) }); };









, , . , , , , . , , , , .



HTML :



<div class="overlay"> <div class="overlay-inner"> </div> </div> <button class="btn-crop js-crop">Crop</button>







, , .



.overlay { position: absolute; left: 50%; top: 50%; margin-left: -100px; margin-top: -100px; z-index: 999; width: 200px; height: 200px; border: solid 2px rgba(222,60,80,.9); box-sizing: content-box; pointer-events: none; } .overlay:after, .overlay:before { content: ''; position: absolute; display: block; width: 204px; height: 40px; border-left: dashed 2px rgba(222,60,80,.9); border-right: dashed 2px rgba(222,60,80,.9); } .overlay:before { top: 0; margin-left: -2px; margin-top: -40px; } .overlay:after { bottom: 0; margin-left: -2px; margin-bottom: -40px; } .overlay-inner:after, .overlay-inner:before { content: ''; position: absolute; display: block; width: 40px; height: 204px; border-top: dashed 2px rgba(222,60,80,.9); border-bottom: dashed 2px rgba(222,60,80,.9); } .overlay-inner:before { left: 0; margin-left: -40px; margin-top: -2px; } .overlay-inner:after { right: 0; margin-right: -40px; margin-top: -2px; } .btn-crop { position: absolute; vertical-align: bottom; right: 5px; bottom: 5px; padding: 6px 10px; z-index: 999; background-color: rgb(222,60,80); border: none; border-radius: 5px; color: #FFF; }







JavaScript :



init = function(){ //... $('.js-crop').on('click', crop); }; crop = function(){ var crop_canvas, left = $('.overlay').offset().left - $container.offset().left, top = $('.overlay').offset().top - $container.offset().top, width = $('.overlay').width(), height = $('.overlay').height(); crop_canvas = document.createElement('canvas'); crop_canvas.width = width; crop_canvas.height = height; crop_canvas.getContext('2d').drawImage(image_target, left, top, width, height, 0, 0, width, height); window.open(crop_canvas.toDataURL("image/png")); }







crop



resizeImage



. , .



drawImage



canvas. - . - , . - , canvas, .





. .



mousedown



mouseup



- touchstart



touchend



, mousemove



touchmove



. , touchup



touchdown



( ).



touchstart



touchend



, mousedown



, mouseup



touchmove



, mousemove



.



// In init()... $container.on('mousedown touchstart', '.resize-handle', startResize); $container.on('mousedown touchstart', 'img', startMoving); //In startResize() ... $(document).on('mousemove touchmove', moving); $(document).on('mouseup touchend', endMoving); //In endResize()... $(document).off('mouseup touchend', endMoving); $(document).off('mousemove touchmove', moving); //In startMoving()... $(document).on('mousemove touchmove', moving); $(document).on('mouseup touchend', endMoving); //In endMoving()... $(document).off('mouseup touchend', endMoving); $(document).off('mousemove touchmove', moving);







, "" . Hammer, . , , .



, , , saveEventState



. .



" " . , . moving



:



moving = function(e){ var mouse={}, touches; e.preventDefault(); e.stopPropagation(); touches = e.originalEvent.touches; mouse.x = (e.clientX || e.pageX || touches[0].clientX) + $(window).scrollLeft(); mouse.y = (e.clientY || e.pageY || touches[0].clientY) + $(window).scrollTop(); $container.offset({ 'left': mouse.x - ( event_state.mouse_x - event_state.container_left ), 'top': mouse.y - ( event_state.mouse_y - event_state.container_top ) }); // Watch for pinch zoom gesture while moving if(event_state.touches && event_state.touches.length > 1 && touches.length > 1){ var width = event_state.container_width, height = event_state.container_height; var a = event_state.touches[0].clientX - event_state.touches[1].clientX; a = a * a; var b = event_state.touches[0].clientY - event_state.touches[1].clientY; b = b * b; var dist1 = Math.sqrt( a + b ); a = e.originalEvent.touches[0].clientX - touches[1].clientX; a = a * a; b = e.originalEvent.touches[0].clientY - touches[1].clientY; b = b * b; var dist2 = Math.sqrt( a + b ); var ratio = dist2 /dist1; width = width * ratio; height = height * ratio; // To improve performance you might limit how often resizeImage() is called resizeImage(width, height); } };







.







. .



Chrome "", Firefox .



, .




HTML5, , , .



- . , . , .



canvas




, , . , , .



. . , , . , .



!





:

<img class="resize-image" src="image.jpg" alt="Image" />







! HTML .



CSS

CSS- . resize-container



.



.resize-container { position: relative; display: inline-block; cursor: move; margin: 0 auto; } .resize-container img { display: block } .resize-container:hover img, .resize-container:active img { outline: 2px dashed rgba(222,60,80,.9); }







'resize handles'. , , .



.resize-handle-ne, .resize-handle-ne, .resize-handle-se, .resize-handle-nw, .resize-handle-sw { position: absolute; display: block; width: 10px; height: 10px; background: rgba(222,60,80,.9); z-index: 999; } .resize-handle-nw { top: -5px; left: -5px; cursor: nw-resize; } .resize-handle-sw { bottom: -5px; left: -5px; cursor: sw-resize; } .resize-handle-ne { top: -5px; right: -5px; cursor: ne-resize; } .resize-handle-se { bottom: -5px; right: -5px; cursor: se-resize; }







JavaScript

Canvas.



var resizeableImage = function(image_target) { var $container, orig_src = new Image(), image_target = $(image_target).get(0), event_state = {}, constrain = false, min_width = 60, min_height = 60, max_width = 800, max_height = 900, resize_canvas = document.createElement('canvas'); }); resizeableImage($('.resize-image'));







, . , , . jQuery , .



var resizeableImage = function(image_target) { // ... init = function(){ // Create a new image with a copy of the original src // When resizing, we will always use this original copy as the base orig_src.src=image_target.src; // Add resize handles $(image_target).wrap('<div class="resize-container"></div>') .before('<span class="resize-handle resize-handle-nw"></span>') .before('<span class="resize-handle resize-handle-ne"></span>') .after('<span class="resize-handle resize-handle-se"></span>') .after('<span class="resize-handle resize-handle-sw"></span>'); // Get a variable for the container $container = $(image_target).parent('.resize-container'); // Add events $container.on('mousedown', '.resize-handle', startResize); }; //... init(); }







startResize



endResize



, , .



startResize = function(e){ e.preventDefault(); e.stopPropagation(); saveEventState(e); $(document).on('mousemove', resizing); $(document).on('mouseup', endResize); }; endResize = function(e){ e.preventDefault(); $(document).off('mouseup touchend', endResize); $(document).off('mousemove touchmove', resizing); };







. event_state



.



saveEventState = function(e){ // Save the initial event details and container state event_state.container_width = $container.width(); event_state.container_height = $container.height(); event_state.container_left = $container.offset().left; event_state.container_top = $container.offset().top; event_state.mouse_x = (e.clientX || e.pageX || e.originalEvent.touches[0].clientX) + $(window).scrollLeft(); event_state.mouse_y = (e.clientY || e.pageY || e.originalEvent.touches[0].clientY) + $(window).scrollTop(); // This is a fix for mobile safari // For some reason it does not allow a direct copy of the touches property if(typeof e.originalEvent.touches !== 'undefined'){ event_state.touches = []; $.each(e.originalEvent.touches, function(i, ob){ event_state.touches[i] = {}; event_state.touches[i].clientX = 0+ob.clientX; event_state.touches[i].clientY = 0+ob.clientY; }); } event_state.evnt = e; }







resizing



- . . .



resizing = function(e){ var mouse={},width,height,left,top,offset=$container.offset(); mouse.x = (e.clientX || e.pageX || e.originalEvent.touches[0].clientX) + $(window).scrollLeft(); mouse.y = (e.clientY || e.pageY || e.originalEvent.touches[0].clientY) + $(window).scrollTop(); width = mouse.x - event_state.container_left; height = mouse.y - event_state.container_top; left = event_state.container_left; top = event_state.container_top; if(constrain || e.shiftKey){ height = width / orig_src.width * orig_src.height; } if(width > min_width && height > min_height && width < max_width && height < max_height){ resizeImage(width, height); // Without this Firefox will not re-calculate the the image dimensions until drag end $container.offset({'left': left, 'top': top}); } }







Shift .



.



: , , resizeImage



.





Canvas , drawImage



. , . toDataURL



Base64-encoded .



.



resizeImage = function(width, height){ resize_canvas.width = width; resize_canvas.height = height; resize_canvas.getContext('2d').drawImage(orig_src, 0, 0, width, height); $(image_target).attr('src', resize_canvas.toDataURL("image/png")); };







? : , CORS . , 'tainted canvas'.







. . , . , .



, , .







, . resizing



:



resizing = function(e){ var mouse={},width,height,left,top,offset=$container.offset(); mouse.x = (e.clientX || e.pageX || e.originalEvent.touches[0].clientX) + $(window).scrollLeft(); mouse.y = (e.clientY || e.pageY || e.originalEvent.touches[0].clientY) + $(window).scrollTop(); // Position image differently depending on the corner dragged and constraints if( $(event_state.evnt.target).hasClass('resize-handle-se') ){ width = mouse.x - event_state.container_left; height = mouse.y - event_state.container_top; left = event_state.container_left; top = event_state.container_top; } else if($(event_state.evnt.target).hasClass('resize-handle-sw') ){ width = event_state.container_width - (mouse.x - event_state.container_left); height = mouse.y - event_state.container_top; left = mouse.x; top = event_state.container_top; } else if($(event_state.evnt.target).hasClass('resize-handle-nw') ){ width = event_state.container_width - (mouse.x - event_state.container_left); height = event_state.container_height - (mouse.y - event_state.container_top); left = mouse.x; top = mouse.y; if(constrain || e.shiftKey){ top = mouse.y - ((width / orig_src.width * orig_src.height) - height); } } else if($(event_state.evnt.target).hasClass('resize-handle-ne') ){ width = mouse.x - event_state.container_left; height = event_state.container_height - (mouse.y - event_state.container_top); left = event_state.container_left; top = mouse.y; if(constrain || e.shiftKey){ top = mouse.y - ((width / orig_src.width * orig_src.height) - height); } } // Optionally maintain aspect ratio if(constrain || e.shiftKey){ height = width / orig_src.width * orig_src.height; } if(width > min_width && height > min_height && width < max_width && height < max_height){ // To improve performance you might limit how often resizeImage() is called resizeImage(width, height); // Without this Firefox will not re-calculate the the image dimensions until drag end $container.offset({'left': left, 'top': top}); } }







, resize-handle



, .





, , , , , "". . .



init = function(){ //... $container.on('mousedown', 'img', startMoving); }







startMoving



endMoving



, startResize



endResize



.



startMoving = function(e){ e.preventDefault(); e.stopPropagation(); saveEventState(e); $(document).on('mousemove', moving); $(document).on('mouseup', endMoving); }; endMoving = function(e){ e.preventDefault(); $(document).off('mouseup', endMoving); $(document).off('mousemove', moving); };







moving



. , .



moving = function(e){ var mouse={}; e.preventDefault(); e.stopPropagation(); mouse.x = (e.clientX || e.pageX) + $(window).scrollLeft(); mouse.y = (e.clientY || e.pageY) + $(window).scrollTop(); $container.offset({ 'left': mouse.x - ( event_state.mouse_x - event_state.container_left ), 'top': mouse.y - ( event_state.mouse_y - event_state.container_top ) }); };









, , . , , , , . , , , , .



HTML :



<div class="overlay"> <div class="overlay-inner"> </div> </div> <button class="btn-crop js-crop">Crop</button>







, , .



.overlay { position: absolute; left: 50%; top: 50%; margin-left: -100px; margin-top: -100px; z-index: 999; width: 200px; height: 200px; border: solid 2px rgba(222,60,80,.9); box-sizing: content-box; pointer-events: none; } .overlay:after, .overlay:before { content: ''; position: absolute; display: block; width: 204px; height: 40px; border-left: dashed 2px rgba(222,60,80,.9); border-right: dashed 2px rgba(222,60,80,.9); } .overlay:before { top: 0; margin-left: -2px; margin-top: -40px; } .overlay:after { bottom: 0; margin-left: -2px; margin-bottom: -40px; } .overlay-inner:after, .overlay-inner:before { content: ''; position: absolute; display: block; width: 40px; height: 204px; border-top: dashed 2px rgba(222,60,80,.9); border-bottom: dashed 2px rgba(222,60,80,.9); } .overlay-inner:before { left: 0; margin-left: -40px; margin-top: -2px; } .overlay-inner:after { right: 0; margin-right: -40px; margin-top: -2px; } .btn-crop { position: absolute; vertical-align: bottom; right: 5px; bottom: 5px; padding: 6px 10px; z-index: 999; background-color: rgb(222,60,80); border: none; border-radius: 5px; color: #FFF; }







JavaScript :



init = function(){ //... $('.js-crop').on('click', crop); }; crop = function(){ var crop_canvas, left = $('.overlay').offset().left - $container.offset().left, top = $('.overlay').offset().top - $container.offset().top, width = $('.overlay').width(), height = $('.overlay').height(); crop_canvas = document.createElement('canvas'); crop_canvas.width = width; crop_canvas.height = height; crop_canvas.getContext('2d').drawImage(image_target, left, top, width, height, 0, 0, width, height); window.open(crop_canvas.toDataURL("image/png")); }







crop



resizeImage



. , .



drawImage



canvas. - . - , . - , canvas, .





. .



mousedown



mouseup



- touchstart



touchend



, mousemove



touchmove



. , touchup



touchdown



( ).



touchstart



touchend



, mousedown



, mouseup



touchmove



, mousemove



.



// In init()... $container.on('mousedown touchstart', '.resize-handle', startResize); $container.on('mousedown touchstart', 'img', startMoving); //In startResize() ... $(document).on('mousemove touchmove', moving); $(document).on('mouseup touchend', endMoving); //In endResize()... $(document).off('mouseup touchend', endMoving); $(document).off('mousemove touchmove', moving); //In startMoving()... $(document).on('mousemove touchmove', moving); $(document).on('mouseup touchend', endMoving); //In endMoving()... $(document).off('mouseup touchend', endMoving); $(document).off('mousemove touchmove', moving);







, "" . Hammer, . , , .



, , , saveEventState



. .



" " . , . moving



:



moving = function(e){ var mouse={}, touches; e.preventDefault(); e.stopPropagation(); touches = e.originalEvent.touches; mouse.x = (e.clientX || e.pageX || touches[0].clientX) + $(window).scrollLeft(); mouse.y = (e.clientY || e.pageY || touches[0].clientY) + $(window).scrollTop(); $container.offset({ 'left': mouse.x - ( event_state.mouse_x - event_state.container_left ), 'top': mouse.y - ( event_state.mouse_y - event_state.container_top ) }); // Watch for pinch zoom gesture while moving if(event_state.touches && event_state.touches.length > 1 && touches.length > 1){ var width = event_state.container_width, height = event_state.container_height; var a = event_state.touches[0].clientX - event_state.touches[1].clientX; a = a * a; var b = event_state.touches[0].clientY - event_state.touches[1].clientY; b = b * b; var dist1 = Math.sqrt( a + b ); a = e.originalEvent.touches[0].clientX - touches[1].clientX; a = a * a; b = e.originalEvent.touches[0].clientY - touches[1].clientY; b = b * b; var dist2 = Math.sqrt( a + b ); var ratio = dist2 /dist1; width = width * ratio; height = height * ratio; // To improve performance you might limit how often resizeImage() is called resizeImage(width, height); } };







.







. .



Chrome "", Firefox .



, .




  HTML5,     ,      ,   . 
      



- . , . , .



canvas




, , . , , .



. . , , . , .



!





:

<img class="resize-image" src="image.jpg" alt="Image" />







! HTML .



CSS

CSS- . resize-container



.



.resize-container { position: relative; display: inline-block; cursor: move; margin: 0 auto; } .resize-container img { display: block } .resize-container:hover img, .resize-container:active img { outline: 2px dashed rgba(222,60,80,.9); }







'resize handles'. , , .



.resize-handle-ne, .resize-handle-ne, .resize-handle-se, .resize-handle-nw, .resize-handle-sw { position: absolute; display: block; width: 10px; height: 10px; background: rgba(222,60,80,.9); z-index: 999; } .resize-handle-nw { top: -5px; left: -5px; cursor: nw-resize; } .resize-handle-sw { bottom: -5px; left: -5px; cursor: sw-resize; } .resize-handle-ne { top: -5px; right: -5px; cursor: ne-resize; } .resize-handle-se { bottom: -5px; right: -5px; cursor: se-resize; }







JavaScript

Canvas.



var resizeableImage = function(image_target) { var $container, orig_src = new Image(), image_target = $(image_target).get(0), event_state = {}, constrain = false, min_width = 60, min_height = 60, max_width = 800, max_height = 900, resize_canvas = document.createElement('canvas'); }); resizeableImage($('.resize-image'));







, . , , . jQuery , .



var resizeableImage = function(image_target) { // ... init = function(){ // Create a new image with a copy of the original src // When resizing, we will always use this original copy as the base orig_src.src=image_target.src; // Add resize handles $(image_target).wrap('<div class="resize-container"></div>') .before('<span class="resize-handle resize-handle-nw"></span>') .before('<span class="resize-handle resize-handle-ne"></span>') .after('<span class="resize-handle resize-handle-se"></span>') .after('<span class="resize-handle resize-handle-sw"></span>'); // Get a variable for the container $container = $(image_target).parent('.resize-container'); // Add events $container.on('mousedown', '.resize-handle', startResize); }; //... init(); }







startResize



endResize



, , .



startResize = function(e){ e.preventDefault(); e.stopPropagation(); saveEventState(e); $(document).on('mousemove', resizing); $(document).on('mouseup', endResize); }; endResize = function(e){ e.preventDefault(); $(document).off('mouseup touchend', endResize); $(document).off('mousemove touchmove', resizing); };







. event_state



.



saveEventState = function(e){ // Save the initial event details and container state event_state.container_width = $container.width(); event_state.container_height = $container.height(); event_state.container_left = $container.offset().left; event_state.container_top = $container.offset().top; event_state.mouse_x = (e.clientX || e.pageX || e.originalEvent.touches[0].clientX) + $(window).scrollLeft(); event_state.mouse_y = (e.clientY || e.pageY || e.originalEvent.touches[0].clientY) + $(window).scrollTop(); // This is a fix for mobile safari // For some reason it does not allow a direct copy of the touches property if(typeof e.originalEvent.touches !== 'undefined'){ event_state.touches = []; $.each(e.originalEvent.touches, function(i, ob){ event_state.touches[i] = {}; event_state.touches[i].clientX = 0+ob.clientX; event_state.touches[i].clientY = 0+ob.clientY; }); } event_state.evnt = e; }







resizing



- . . .



resizing = function(e){ var mouse={},width,height,left,top,offset=$container.offset(); mouse.x = (e.clientX || e.pageX || e.originalEvent.touches[0].clientX) + $(window).scrollLeft(); mouse.y = (e.clientY || e.pageY || e.originalEvent.touches[0].clientY) + $(window).scrollTop(); width = mouse.x - event_state.container_left; height = mouse.y - event_state.container_top; left = event_state.container_left; top = event_state.container_top; if(constrain || e.shiftKey){ height = width / orig_src.width * orig_src.height; } if(width > min_width && height > min_height && width < max_width && height < max_height){ resizeImage(width, height); // Without this Firefox will not re-calculate the the image dimensions until drag end $container.offset({'left': left, 'top': top}); } }







Shift .



.



: , , resizeImage



.





Canvas , drawImage



. , . toDataURL



Base64-encoded .



.



resizeImage = function(width, height){ resize_canvas.width = width; resize_canvas.height = height; resize_canvas.getContext('2d').drawImage(orig_src, 0, 0, width, height); $(image_target).attr('src', resize_canvas.toDataURL("image/png")); };







? : , CORS . , 'tainted canvas'.







. . , . , .



, , .







, . resizing



:



resizing = function(e){ var mouse={},width,height,left,top,offset=$container.offset(); mouse.x = (e.clientX || e.pageX || e.originalEvent.touches[0].clientX) + $(window).scrollLeft(); mouse.y = (e.clientY || e.pageY || e.originalEvent.touches[0].clientY) + $(window).scrollTop(); // Position image differently depending on the corner dragged and constraints if( $(event_state.evnt.target).hasClass('resize-handle-se') ){ width = mouse.x - event_state.container_left; height = mouse.y - event_state.container_top; left = event_state.container_left; top = event_state.container_top; } else if($(event_state.evnt.target).hasClass('resize-handle-sw') ){ width = event_state.container_width - (mouse.x - event_state.container_left); height = mouse.y - event_state.container_top; left = mouse.x; top = event_state.container_top; } else if($(event_state.evnt.target).hasClass('resize-handle-nw') ){ width = event_state.container_width - (mouse.x - event_state.container_left); height = event_state.container_height - (mouse.y - event_state.container_top); left = mouse.x; top = mouse.y; if(constrain || e.shiftKey){ top = mouse.y - ((width / orig_src.width * orig_src.height) - height); } } else if($(event_state.evnt.target).hasClass('resize-handle-ne') ){ width = mouse.x - event_state.container_left; height = event_state.container_height - (mouse.y - event_state.container_top); left = event_state.container_left; top = mouse.y; if(constrain || e.shiftKey){ top = mouse.y - ((width / orig_src.width * orig_src.height) - height); } } // Optionally maintain aspect ratio if(constrain || e.shiftKey){ height = width / orig_src.width * orig_src.height; } if(width > min_width && height > min_height && width < max_width && height < max_height){ // To improve performance you might limit how often resizeImage() is called resizeImage(width, height); // Without this Firefox will not re-calculate the the image dimensions until drag end $container.offset({'left': left, 'top': top}); } }







, resize-handle



, .





, , , , , "". . .



init = function(){ //... $container.on('mousedown', 'img', startMoving); }







startMoving



endMoving



, startResize



endResize



.



startMoving = function(e){ e.preventDefault(); e.stopPropagation(); saveEventState(e); $(document).on('mousemove', moving); $(document).on('mouseup', endMoving); }; endMoving = function(e){ e.preventDefault(); $(document).off('mouseup', endMoving); $(document).off('mousemove', moving); };







moving



. , .



moving = function(e){ var mouse={}; e.preventDefault(); e.stopPropagation(); mouse.x = (e.clientX || e.pageX) + $(window).scrollLeft(); mouse.y = (e.clientY || e.pageY) + $(window).scrollTop(); $container.offset({ 'left': mouse.x - ( event_state.mouse_x - event_state.container_left ), 'top': mouse.y - ( event_state.mouse_y - event_state.container_top ) }); };









, , . , , , , . , , , , .



HTML :



<div class="overlay"> <div class="overlay-inner"> </div> </div> <button class="btn-crop js-crop">Crop</button>







, , .



.overlay { position: absolute; left: 50%; top: 50%; margin-left: -100px; margin-top: -100px; z-index: 999; width: 200px; height: 200px; border: solid 2px rgba(222,60,80,.9); box-sizing: content-box; pointer-events: none; } .overlay:after, .overlay:before { content: ''; position: absolute; display: block; width: 204px; height: 40px; border-left: dashed 2px rgba(222,60,80,.9); border-right: dashed 2px rgba(222,60,80,.9); } .overlay:before { top: 0; margin-left: -2px; margin-top: -40px; } .overlay:after { bottom: 0; margin-left: -2px; margin-bottom: -40px; } .overlay-inner:after, .overlay-inner:before { content: ''; position: absolute; display: block; width: 40px; height: 204px; border-top: dashed 2px rgba(222,60,80,.9); border-bottom: dashed 2px rgba(222,60,80,.9); } .overlay-inner:before { left: 0; margin-left: -40px; margin-top: -2px; } .overlay-inner:after { right: 0; margin-right: -40px; margin-top: -2px; } .btn-crop { position: absolute; vertical-align: bottom; right: 5px; bottom: 5px; padding: 6px 10px; z-index: 999; background-color: rgb(222,60,80); border: none; border-radius: 5px; color: #FFF; }







JavaScript :



init = function(){ //... $('.js-crop').on('click', crop); }; crop = function(){ var crop_canvas, left = $('.overlay').offset().left - $container.offset().left, top = $('.overlay').offset().top - $container.offset().top, width = $('.overlay').width(), height = $('.overlay').height(); crop_canvas = document.createElement('canvas'); crop_canvas.width = width; crop_canvas.height = height; crop_canvas.getContext('2d').drawImage(image_target, left, top, width, height, 0, 0, width, height); window.open(crop_canvas.toDataURL("image/png")); }







crop



resizeImage



. , .



drawImage



canvas. - . - , . - , canvas, .





. .



mousedown



mouseup



- touchstart



touchend



, mousemove



touchmove



. , touchup



touchdown



( ).



touchstart



touchend



, mousedown



, mouseup



touchmove



, mousemove



.



// In init()... $container.on('mousedown touchstart', '.resize-handle', startResize); $container.on('mousedown touchstart', 'img', startMoving); //In startResize() ... $(document).on('mousemove touchmove', moving); $(document).on('mouseup touchend', endMoving); //In endResize()... $(document).off('mouseup touchend', endMoving); $(document).off('mousemove touchmove', moving); //In startMoving()... $(document).on('mousemove touchmove', moving); $(document).on('mouseup touchend', endMoving); //In endMoving()... $(document).off('mouseup touchend', endMoving); $(document).off('mousemove touchmove', moving);







, "" . Hammer, . , , .



, , , saveEventState



. .



" " . , . moving



:



moving = function(e){ var mouse={}, touches; e.preventDefault(); e.stopPropagation(); touches = e.originalEvent.touches; mouse.x = (e.clientX || e.pageX || touches[0].clientX) + $(window).scrollLeft(); mouse.y = (e.clientY || e.pageY || touches[0].clientY) + $(window).scrollTop(); $container.offset({ 'left': mouse.x - ( event_state.mouse_x - event_state.container_left ), 'top': mouse.y - ( event_state.mouse_y - event_state.container_top ) }); // Watch for pinch zoom gesture while moving if(event_state.touches && event_state.touches.length > 1 && touches.length > 1){ var width = event_state.container_width, height = event_state.container_height; var a = event_state.touches[0].clientX - event_state.touches[1].clientX; a = a * a; var b = event_state.touches[0].clientY - event_state.touches[1].clientY; b = b * b; var dist1 = Math.sqrt( a + b ); a = e.originalEvent.touches[0].clientX - touches[1].clientX; a = a * a; b = e.originalEvent.touches[0].clientY - touches[1].clientY; b = b * b; var dist2 = Math.sqrt( a + b ); var ratio = dist2 /dist1; width = width * ratio; height = height * ratio; // To improve performance you might limit how often resizeImage() is called resizeImage(width, height); } };







.







. .



Chrome "", Firefox .



, .




HTML5, , , .



- . , . , .



canvas




, , . , , .



. . , , . , .



!





:

<img class="resize-image" src="image.jpg" alt="Image" />







! HTML .



CSS

CSS- . resize-container



.



.resize-container { position: relative; display: inline-block; cursor: move; margin: 0 auto; } .resize-container img { display: block } .resize-container:hover img, .resize-container:active img { outline: 2px dashed rgba(222,60,80,.9); }







'resize handles'. , , .



.resize-handle-ne, .resize-handle-ne, .resize-handle-se, .resize-handle-nw, .resize-handle-sw { position: absolute; display: block; width: 10px; height: 10px; background: rgba(222,60,80,.9); z-index: 999; } .resize-handle-nw { top: -5px; left: -5px; cursor: nw-resize; } .resize-handle-sw { bottom: -5px; left: -5px; cursor: sw-resize; } .resize-handle-ne { top: -5px; right: -5px; cursor: ne-resize; } .resize-handle-se { bottom: -5px; right: -5px; cursor: se-resize; }







JavaScript

Canvas.



var resizeableImage = function(image_target) { var $container, orig_src = new Image(), image_target = $(image_target).get(0), event_state = {}, constrain = false, min_width = 60, min_height = 60, max_width = 800, max_height = 900, resize_canvas = document.createElement('canvas'); }); resizeableImage($('.resize-image'));







, . , , . jQuery , .



var resizeableImage = function(image_target) { // ... init = function(){ // Create a new image with a copy of the original src // When resizing, we will always use this original copy as the base orig_src.src=image_target.src; // Add resize handles $(image_target).wrap('<div class="resize-container"></div>') .before('<span class="resize-handle resize-handle-nw"></span>') .before('<span class="resize-handle resize-handle-ne"></span>') .after('<span class="resize-handle resize-handle-se"></span>') .after('<span class="resize-handle resize-handle-sw"></span>'); // Get a variable for the container $container = $(image_target).parent('.resize-container'); // Add events $container.on('mousedown', '.resize-handle', startResize); }; //... init(); }







startResize



endResize



, , .



startResize = function(e){ e.preventDefault(); e.stopPropagation(); saveEventState(e); $(document).on('mousemove', resizing); $(document).on('mouseup', endResize); }; endResize = function(e){ e.preventDefault(); $(document).off('mouseup touchend', endResize); $(document).off('mousemove touchmove', resizing); };







. event_state



.



saveEventState = function(e){ // Save the initial event details and container state event_state.container_width = $container.width(); event_state.container_height = $container.height(); event_state.container_left = $container.offset().left; event_state.container_top = $container.offset().top; event_state.mouse_x = (e.clientX || e.pageX || e.originalEvent.touches[0].clientX) + $(window).scrollLeft(); event_state.mouse_y = (e.clientY || e.pageY || e.originalEvent.touches[0].clientY) + $(window).scrollTop(); // This is a fix for mobile safari // For some reason it does not allow a direct copy of the touches property if(typeof e.originalEvent.touches !== 'undefined'){ event_state.touches = []; $.each(e.originalEvent.touches, function(i, ob){ event_state.touches[i] = {}; event_state.touches[i].clientX = 0+ob.clientX; event_state.touches[i].clientY = 0+ob.clientY; }); } event_state.evnt = e; }







resizing



- . . .



resizing = function(e){ var mouse={},width,height,left,top,offset=$container.offset(); mouse.x = (e.clientX || e.pageX || e.originalEvent.touches[0].clientX) + $(window).scrollLeft(); mouse.y = (e.clientY || e.pageY || e.originalEvent.touches[0].clientY) + $(window).scrollTop(); width = mouse.x - event_state.container_left; height = mouse.y - event_state.container_top; left = event_state.container_left; top = event_state.container_top; if(constrain || e.shiftKey){ height = width / orig_src.width * orig_src.height; } if(width > min_width && height > min_height && width < max_width && height < max_height){ resizeImage(width, height); // Without this Firefox will not re-calculate the the image dimensions until drag end $container.offset({'left': left, 'top': top}); } }







Shift .



.



: , , resizeImage



.





Canvas , drawImage



. , . toDataURL



Base64-encoded .



.



resizeImage = function(width, height){ resize_canvas.width = width; resize_canvas.height = height; resize_canvas.getContext('2d').drawImage(orig_src, 0, 0, width, height); $(image_target).attr('src', resize_canvas.toDataURL("image/png")); };







? : , CORS . , 'tainted canvas'.







. . , . , .



, , .







, . resizing



:



resizing = function(e){ var mouse={},width,height,left,top,offset=$container.offset(); mouse.x = (e.clientX || e.pageX || e.originalEvent.touches[0].clientX) + $(window).scrollLeft(); mouse.y = (e.clientY || e.pageY || e.originalEvent.touches[0].clientY) + $(window).scrollTop(); // Position image differently depending on the corner dragged and constraints if( $(event_state.evnt.target).hasClass('resize-handle-se') ){ width = mouse.x - event_state.container_left; height = mouse.y - event_state.container_top; left = event_state.container_left; top = event_state.container_top; } else if($(event_state.evnt.target).hasClass('resize-handle-sw') ){ width = event_state.container_width - (mouse.x - event_state.container_left); height = mouse.y - event_state.container_top; left = mouse.x; top = event_state.container_top; } else if($(event_state.evnt.target).hasClass('resize-handle-nw') ){ width = event_state.container_width - (mouse.x - event_state.container_left); height = event_state.container_height - (mouse.y - event_state.container_top); left = mouse.x; top = mouse.y; if(constrain || e.shiftKey){ top = mouse.y - ((width / orig_src.width * orig_src.height) - height); } } else if($(event_state.evnt.target).hasClass('resize-handle-ne') ){ width = mouse.x - event_state.container_left; height = event_state.container_height - (mouse.y - event_state.container_top); left = event_state.container_left; top = mouse.y; if(constrain || e.shiftKey){ top = mouse.y - ((width / orig_src.width * orig_src.height) - height); } } // Optionally maintain aspect ratio if(constrain || e.shiftKey){ height = width / orig_src.width * orig_src.height; } if(width > min_width && height > min_height && width < max_width && height < max_height){ // To improve performance you might limit how often resizeImage() is called resizeImage(width, height); // Without this Firefox will not re-calculate the the image dimensions until drag end $container.offset({'left': left, 'top': top}); } }







, resize-handle



, .





, , , , , "". . .



init = function(){ //... $container.on('mousedown', 'img', startMoving); }







startMoving



endMoving



, startResize



endResize



.



startMoving = function(e){ e.preventDefault(); e.stopPropagation(); saveEventState(e); $(document).on('mousemove', moving); $(document).on('mouseup', endMoving); }; endMoving = function(e){ e.preventDefault(); $(document).off('mouseup', endMoving); $(document).off('mousemove', moving); };







moving



. , .



moving = function(e){ var mouse={}; e.preventDefault(); e.stopPropagation(); mouse.x = (e.clientX || e.pageX) + $(window).scrollLeft(); mouse.y = (e.clientY || e.pageY) + $(window).scrollTop(); $container.offset({ 'left': mouse.x - ( event_state.mouse_x - event_state.container_left ), 'top': mouse.y - ( event_state.mouse_y - event_state.container_top ) }); };









, , . , , , , . , , , , .



HTML :



<div class="overlay"> <div class="overlay-inner"> </div> </div> <button class="btn-crop js-crop">Crop</button>







, , .



.overlay { position: absolute; left: 50%; top: 50%; margin-left: -100px; margin-top: -100px; z-index: 999; width: 200px; height: 200px; border: solid 2px rgba(222,60,80,.9); box-sizing: content-box; pointer-events: none; } .overlay:after, .overlay:before { content: ''; position: absolute; display: block; width: 204px; height: 40px; border-left: dashed 2px rgba(222,60,80,.9); border-right: dashed 2px rgba(222,60,80,.9); } .overlay:before { top: 0; margin-left: -2px; margin-top: -40px; } .overlay:after { bottom: 0; margin-left: -2px; margin-bottom: -40px; } .overlay-inner:after, .overlay-inner:before { content: ''; position: absolute; display: block; width: 40px; height: 204px; border-top: dashed 2px rgba(222,60,80,.9); border-bottom: dashed 2px rgba(222,60,80,.9); } .overlay-inner:before { left: 0; margin-left: -40px; margin-top: -2px; } .overlay-inner:after { right: 0; margin-right: -40px; margin-top: -2px; } .btn-crop { position: absolute; vertical-align: bottom; right: 5px; bottom: 5px; padding: 6px 10px; z-index: 999; background-color: rgb(222,60,80); border: none; border-radius: 5px; color: #FFF; }







JavaScript :



init = function(){ //... $('.js-crop').on('click', crop); }; crop = function(){ var crop_canvas, left = $('.overlay').offset().left - $container.offset().left, top = $('.overlay').offset().top - $container.offset().top, width = $('.overlay').width(), height = $('.overlay').height(); crop_canvas = document.createElement('canvas'); crop_canvas.width = width; crop_canvas.height = height; crop_canvas.getContext('2d').drawImage(image_target, left, top, width, height, 0, 0, width, height); window.open(crop_canvas.toDataURL("image/png")); }







crop



resizeImage



. , .



drawImage



canvas. - . - , . - , canvas, .





. .



mousedown



mouseup



- touchstart



touchend



, mousemove



touchmove



. , touchup



touchdown



( ).



touchstart



touchend



, mousedown



, mouseup



touchmove



, mousemove



.



// In init()... $container.on('mousedown touchstart', '.resize-handle', startResize); $container.on('mousedown touchstart', 'img', startMoving); //In startResize() ... $(document).on('mousemove touchmove', moving); $(document).on('mouseup touchend', endMoving); //In endResize()... $(document).off('mouseup touchend', endMoving); $(document).off('mousemove touchmove', moving); //In startMoving()... $(document).on('mousemove touchmove', moving); $(document).on('mouseup touchend', endMoving); //In endMoving()... $(document).off('mouseup touchend', endMoving); $(document).off('mousemove touchmove', moving);







, "" . Hammer, . , , .



, , , saveEventState



. .



" " . , . moving



:



moving = function(e){ var mouse={}, touches; e.preventDefault(); e.stopPropagation(); touches = e.originalEvent.touches; mouse.x = (e.clientX || e.pageX || touches[0].clientX) + $(window).scrollLeft(); mouse.y = (e.clientY || e.pageY || touches[0].clientY) + $(window).scrollTop(); $container.offset({ 'left': mouse.x - ( event_state.mouse_x - event_state.container_left ), 'top': mouse.y - ( event_state.mouse_y - event_state.container_top ) }); // Watch for pinch zoom gesture while moving if(event_state.touches && event_state.touches.length > 1 && touches.length > 1){ var width = event_state.container_width, height = event_state.container_height; var a = event_state.touches[0].clientX - event_state.touches[1].clientX; a = a * a; var b = event_state.touches[0].clientY - event_state.touches[1].clientY; b = b * b; var dist1 = Math.sqrt( a + b ); a = e.originalEvent.touches[0].clientX - touches[1].clientX; a = a * a; b = e.originalEvent.touches[0].clientY - touches[1].clientY; b = b * b; var dist2 = Math.sqrt( a + b ); var ratio = dist2 /dist1; width = width * ratio; height = height * ratio; // To improve performance you might limit how often resizeImage() is called resizeImage(width, height); } };







.







. .



Chrome "", Firefox .



, .




  HTML5,     ,      ,   . 
      



- . , . , .



canvas




, , . , , .



. . , , . , .



!





:

<img class="resize-image" src="image.jpg" alt="Image" />







! HTML .



CSS

CSS- . resize-container



.



.resize-container { position: relative; display: inline-block; cursor: move; margin: 0 auto; } .resize-container img { display: block } .resize-container:hover img, .resize-container:active img { outline: 2px dashed rgba(222,60,80,.9); }







'resize handles'. , , .



.resize-handle-ne, .resize-handle-ne, .resize-handle-se, .resize-handle-nw, .resize-handle-sw { position: absolute; display: block; width: 10px; height: 10px; background: rgba(222,60,80,.9); z-index: 999; } .resize-handle-nw { top: -5px; left: -5px; cursor: nw-resize; } .resize-handle-sw { bottom: -5px; left: -5px; cursor: sw-resize; } .resize-handle-ne { top: -5px; right: -5px; cursor: ne-resize; } .resize-handle-se { bottom: -5px; right: -5px; cursor: se-resize; }







JavaScript

Canvas.



var resizeableImage = function(image_target) { var $container, orig_src = new Image(), image_target = $(image_target).get(0), event_state = {}, constrain = false, min_width = 60, min_height = 60, max_width = 800, max_height = 900, resize_canvas = document.createElement('canvas'); }); resizeableImage($('.resize-image'));







, . , , . jQuery , .



var resizeableImage = function(image_target) { // ... init = function(){ // Create a new image with a copy of the original src // When resizing, we will always use this original copy as the base orig_src.src=image_target.src; // Add resize handles $(image_target).wrap('<div class="resize-container"></div>') .before('<span class="resize-handle resize-handle-nw"></span>') .before('<span class="resize-handle resize-handle-ne"></span>') .after('<span class="resize-handle resize-handle-se"></span>') .after('<span class="resize-handle resize-handle-sw"></span>'); // Get a variable for the container $container = $(image_target).parent('.resize-container'); // Add events $container.on('mousedown', '.resize-handle', startResize); }; //... init(); }







startResize



endResize



, , .



startResize = function(e){ e.preventDefault(); e.stopPropagation(); saveEventState(e); $(document).on('mousemove', resizing); $(document).on('mouseup', endResize); }; endResize = function(e){ e.preventDefault(); $(document).off('mouseup touchend', endResize); $(document).off('mousemove touchmove', resizing); };







. event_state



.



saveEventState = function(e){ // Save the initial event details and container state event_state.container_width = $container.width(); event_state.container_height = $container.height(); event_state.container_left = $container.offset().left; event_state.container_top = $container.offset().top; event_state.mouse_x = (e.clientX || e.pageX || e.originalEvent.touches[0].clientX) + $(window).scrollLeft(); event_state.mouse_y = (e.clientY || e.pageY || e.originalEvent.touches[0].clientY) + $(window).scrollTop(); // This is a fix for mobile safari // For some reason it does not allow a direct copy of the touches property if(typeof e.originalEvent.touches !== 'undefined'){ event_state.touches = []; $.each(e.originalEvent.touches, function(i, ob){ event_state.touches[i] = {}; event_state.touches[i].clientX = 0+ob.clientX; event_state.touches[i].clientY = 0+ob.clientY; }); } event_state.evnt = e; }







resizing



- . . .



resizing = function(e){ var mouse={},width,height,left,top,offset=$container.offset(); mouse.x = (e.clientX || e.pageX || e.originalEvent.touches[0].clientX) + $(window).scrollLeft(); mouse.y = (e.clientY || e.pageY || e.originalEvent.touches[0].clientY) + $(window).scrollTop(); width = mouse.x - event_state.container_left; height = mouse.y - event_state.container_top; left = event_state.container_left; top = event_state.container_top; if(constrain || e.shiftKey){ height = width / orig_src.width * orig_src.height; } if(width > min_width && height > min_height && width < max_width && height < max_height){ resizeImage(width, height); // Without this Firefox will not re-calculate the the image dimensions until drag end $container.offset({'left': left, 'top': top}); } }







Shift .



.



: , , resizeImage



.





Canvas , drawImage



. , . toDataURL



Base64-encoded .



.



resizeImage = function(width, height){ resize_canvas.width = width; resize_canvas.height = height; resize_canvas.getContext('2d').drawImage(orig_src, 0, 0, width, height); $(image_target).attr('src', resize_canvas.toDataURL("image/png")); };







? : , CORS . , 'tainted canvas'.







. . , . , .



, , .







, . resizing



:



resizing = function(e){ var mouse={},width,height,left,top,offset=$container.offset(); mouse.x = (e.clientX || e.pageX || e.originalEvent.touches[0].clientX) + $(window).scrollLeft(); mouse.y = (e.clientY || e.pageY || e.originalEvent.touches[0].clientY) + $(window).scrollTop(); // Position image differently depending on the corner dragged and constraints if( $(event_state.evnt.target).hasClass('resize-handle-se') ){ width = mouse.x - event_state.container_left; height = mouse.y - event_state.container_top; left = event_state.container_left; top = event_state.container_top; } else if($(event_state.evnt.target).hasClass('resize-handle-sw') ){ width = event_state.container_width - (mouse.x - event_state.container_left); height = mouse.y - event_state.container_top; left = mouse.x; top = event_state.container_top; } else if($(event_state.evnt.target).hasClass('resize-handle-nw') ){ width = event_state.container_width - (mouse.x - event_state.container_left); height = event_state.container_height - (mouse.y - event_state.container_top); left = mouse.x; top = mouse.y; if(constrain || e.shiftKey){ top = mouse.y - ((width / orig_src.width * orig_src.height) - height); } } else if($(event_state.evnt.target).hasClass('resize-handle-ne') ){ width = mouse.x - event_state.container_left; height = event_state.container_height - (mouse.y - event_state.container_top); left = event_state.container_left; top = mouse.y; if(constrain || e.shiftKey){ top = mouse.y - ((width / orig_src.width * orig_src.height) - height); } } // Optionally maintain aspect ratio if(constrain || e.shiftKey){ height = width / orig_src.width * orig_src.height; } if(width > min_width && height > min_height && width < max_width && height < max_height){ // To improve performance you might limit how often resizeImage() is called resizeImage(width, height); // Without this Firefox will not re-calculate the the image dimensions until drag end $container.offset({'left': left, 'top': top}); } }







, resize-handle



, .





, , , , , "". . .



init = function(){ //... $container.on('mousedown', 'img', startMoving); }







startMoving



endMoving



, startResize



endResize



.



startMoving = function(e){ e.preventDefault(); e.stopPropagation(); saveEventState(e); $(document).on('mousemove', moving); $(document).on('mouseup', endMoving); }; endMoving = function(e){ e.preventDefault(); $(document).off('mouseup', endMoving); $(document).off('mousemove', moving); };







moving



. , .



moving = function(e){ var mouse={}; e.preventDefault(); e.stopPropagation(); mouse.x = (e.clientX || e.pageX) + $(window).scrollLeft(); mouse.y = (e.clientY || e.pageY) + $(window).scrollTop(); $container.offset({ 'left': mouse.x - ( event_state.mouse_x - event_state.container_left ), 'top': mouse.y - ( event_state.mouse_y - event_state.container_top ) }); };









, , . , , , , . , , , , .



HTML :



<div class="overlay"> <div class="overlay-inner"> </div> </div> <button class="btn-crop js-crop">Crop</button>







, , .



.overlay { position: absolute; left: 50%; top: 50%; margin-left: -100px; margin-top: -100px; z-index: 999; width: 200px; height: 200px; border: solid 2px rgba(222,60,80,.9); box-sizing: content-box; pointer-events: none; } .overlay:after, .overlay:before { content: ''; position: absolute; display: block; width: 204px; height: 40px; border-left: dashed 2px rgba(222,60,80,.9); border-right: dashed 2px rgba(222,60,80,.9); } .overlay:before { top: 0; margin-left: -2px; margin-top: -40px; } .overlay:after { bottom: 0; margin-left: -2px; margin-bottom: -40px; } .overlay-inner:after, .overlay-inner:before { content: ''; position: absolute; display: block; width: 40px; height: 204px; border-top: dashed 2px rgba(222,60,80,.9); border-bottom: dashed 2px rgba(222,60,80,.9); } .overlay-inner:before { left: 0; margin-left: -40px; margin-top: -2px; } .overlay-inner:after { right: 0; margin-right: -40px; margin-top: -2px; } .btn-crop { position: absolute; vertical-align: bottom; right: 5px; bottom: 5px; padding: 6px 10px; z-index: 999; background-color: rgb(222,60,80); border: none; border-radius: 5px; color: #FFF; }







JavaScript :



init = function(){ //... $('.js-crop').on('click', crop); }; crop = function(){ var crop_canvas, left = $('.overlay').offset().left - $container.offset().left, top = $('.overlay').offset().top - $container.offset().top, width = $('.overlay').width(), height = $('.overlay').height(); crop_canvas = document.createElement('canvas'); crop_canvas.width = width; crop_canvas.height = height; crop_canvas.getContext('2d').drawImage(image_target, left, top, width, height, 0, 0, width, height); window.open(crop_canvas.toDataURL("image/png")); }







crop



resizeImage



. , .



drawImage



canvas. - . - , . - , canvas, .





. .



mousedown



mouseup



- touchstart



touchend



, mousemove



touchmove



. , touchup



touchdown



( ).



touchstart



touchend



, mousedown



, mouseup



touchmove



, mousemove



.



// In init()... $container.on('mousedown touchstart', '.resize-handle', startResize); $container.on('mousedown touchstart', 'img', startMoving); //In startResize() ... $(document).on('mousemove touchmove', moving); $(document).on('mouseup touchend', endMoving); //In endResize()... $(document).off('mouseup touchend', endMoving); $(document).off('mousemove touchmove', moving); //In startMoving()... $(document).on('mousemove touchmove', moving); $(document).on('mouseup touchend', endMoving); //In endMoving()... $(document).off('mouseup touchend', endMoving); $(document).off('mousemove touchmove', moving);







, "" . Hammer, . , , .



, , , saveEventState



. .



" " . , . moving



:



moving = function(e){ var mouse={}, touches; e.preventDefault(); e.stopPropagation(); touches = e.originalEvent.touches; mouse.x = (e.clientX || e.pageX || touches[0].clientX) + $(window).scrollLeft(); mouse.y = (e.clientY || e.pageY || touches[0].clientY) + $(window).scrollTop(); $container.offset({ 'left': mouse.x - ( event_state.mouse_x - event_state.container_left ), 'top': mouse.y - ( event_state.mouse_y - event_state.container_top ) }); // Watch for pinch zoom gesture while moving if(event_state.touches && event_state.touches.length > 1 && touches.length > 1){ var width = event_state.container_width, height = event_state.container_height; var a = event_state.touches[0].clientX - event_state.touches[1].clientX; a = a * a; var b = event_state.touches[0].clientY - event_state.touches[1].clientY; b = b * b; var dist1 = Math.sqrt( a + b ); a = e.originalEvent.touches[0].clientX - touches[1].clientX; a = a * a; b = e.originalEvent.touches[0].clientY - touches[1].clientY; b = b * b; var dist2 = Math.sqrt( a + b ); var ratio = dist2 /dist1; width = width * ratio; height = height * ratio; // To improve performance you might limit how often resizeImage() is called resizeImage(width, height); } };







.







. .



Chrome "", Firefox .



, .




HTML5, , , .



- . , . , .



canvas




, , . , , .



. . , , . , .



!





:

<img class="resize-image" src="image.jpg" alt="Image" />







! HTML .



CSS

CSS- . resize-container



.



.resize-container { position: relative; display: inline-block; cursor: move; margin: 0 auto; } .resize-container img { display: block } .resize-container:hover img, .resize-container:active img { outline: 2px dashed rgba(222,60,80,.9); }







'resize handles'. , , .



.resize-handle-ne, .resize-handle-ne, .resize-handle-se, .resize-handle-nw, .resize-handle-sw { position: absolute; display: block; width: 10px; height: 10px; background: rgba(222,60,80,.9); z-index: 999; } .resize-handle-nw { top: -5px; left: -5px; cursor: nw-resize; } .resize-handle-sw { bottom: -5px; left: -5px; cursor: sw-resize; } .resize-handle-ne { top: -5px; right: -5px; cursor: ne-resize; } .resize-handle-se { bottom: -5px; right: -5px; cursor: se-resize; }







JavaScript

Canvas.



var resizeableImage = function(image_target) { var $container, orig_src = new Image(), image_target = $(image_target).get(0), event_state = {}, constrain = false, min_width = 60, min_height = 60, max_width = 800, max_height = 900, resize_canvas = document.createElement('canvas'); }); resizeableImage($('.resize-image'));







, . , , . jQuery , .



var resizeableImage = function(image_target) { // ... init = function(){ // Create a new image with a copy of the original src // When resizing, we will always use this original copy as the base orig_src.src=image_target.src; // Add resize handles $(image_target).wrap('<div class="resize-container"></div>') .before('<span class="resize-handle resize-handle-nw"></span>') .before('<span class="resize-handle resize-handle-ne"></span>') .after('<span class="resize-handle resize-handle-se"></span>') .after('<span class="resize-handle resize-handle-sw"></span>'); // Get a variable for the container $container = $(image_target).parent('.resize-container'); // Add events $container.on('mousedown', '.resize-handle', startResize); }; //... init(); }







startResize



endResize



, , .



startResize = function(e){ e.preventDefault(); e.stopPropagation(); saveEventState(e); $(document).on('mousemove', resizing); $(document).on('mouseup', endResize); }; endResize = function(e){ e.preventDefault(); $(document).off('mouseup touchend', endResize); $(document).off('mousemove touchmove', resizing); };







. event_state



.



saveEventState = function(e){ // Save the initial event details and container state event_state.container_width = $container.width(); event_state.container_height = $container.height(); event_state.container_left = $container.offset().left; event_state.container_top = $container.offset().top; event_state.mouse_x = (e.clientX || e.pageX || e.originalEvent.touches[0].clientX) + $(window).scrollLeft(); event_state.mouse_y = (e.clientY || e.pageY || e.originalEvent.touches[0].clientY) + $(window).scrollTop(); // This is a fix for mobile safari // For some reason it does not allow a direct copy of the touches property if(typeof e.originalEvent.touches !== 'undefined'){ event_state.touches = []; $.each(e.originalEvent.touches, function(i, ob){ event_state.touches[i] = {}; event_state.touches[i].clientX = 0+ob.clientX; event_state.touches[i].clientY = 0+ob.clientY; }); } event_state.evnt = e; }







resizing



- . . .



resizing = function(e){ var mouse={},width,height,left,top,offset=$container.offset(); mouse.x = (e.clientX || e.pageX || e.originalEvent.touches[0].clientX) + $(window).scrollLeft(); mouse.y = (e.clientY || e.pageY || e.originalEvent.touches[0].clientY) + $(window).scrollTop(); width = mouse.x - event_state.container_left; height = mouse.y - event_state.container_top; left = event_state.container_left; top = event_state.container_top; if(constrain || e.shiftKey){ height = width / orig_src.width * orig_src.height; } if(width > min_width && height > min_height && width < max_width && height < max_height){ resizeImage(width, height); // Without this Firefox will not re-calculate the the image dimensions until drag end $container.offset({'left': left, 'top': top}); } }







Shift .



.



: , , resizeImage



.





Canvas , drawImage



. , . toDataURL



Base64-encoded .



.



resizeImage = function(width, height){ resize_canvas.width = width; resize_canvas.height = height; resize_canvas.getContext('2d').drawImage(orig_src, 0, 0, width, height); $(image_target).attr('src', resize_canvas.toDataURL("image/png")); };







? : , CORS . , 'tainted canvas'.







. . , . , .



, , .







, . resizing



:



resizing = function(e){ var mouse={},width,height,left,top,offset=$container.offset(); mouse.x = (e.clientX || e.pageX || e.originalEvent.touches[0].clientX) + $(window).scrollLeft(); mouse.y = (e.clientY || e.pageY || e.originalEvent.touches[0].clientY) + $(window).scrollTop(); // Position image differently depending on the corner dragged and constraints if( $(event_state.evnt.target).hasClass('resize-handle-se') ){ width = mouse.x - event_state.container_left; height = mouse.y - event_state.container_top; left = event_state.container_left; top = event_state.container_top; } else if($(event_state.evnt.target).hasClass('resize-handle-sw') ){ width = event_state.container_width - (mouse.x - event_state.container_left); height = mouse.y - event_state.container_top; left = mouse.x; top = event_state.container_top; } else if($(event_state.evnt.target).hasClass('resize-handle-nw') ){ width = event_state.container_width - (mouse.x - event_state.container_left); height = event_state.container_height - (mouse.y - event_state.container_top); left = mouse.x; top = mouse.y; if(constrain || e.shiftKey){ top = mouse.y - ((width / orig_src.width * orig_src.height) - height); } } else if($(event_state.evnt.target).hasClass('resize-handle-ne') ){ width = mouse.x - event_state.container_left; height = event_state.container_height - (mouse.y - event_state.container_top); left = event_state.container_left; top = mouse.y; if(constrain || e.shiftKey){ top = mouse.y - ((width / orig_src.width * orig_src.height) - height); } } // Optionally maintain aspect ratio if(constrain || e.shiftKey){ height = width / orig_src.width * orig_src.height; } if(width > min_width && height > min_height && width < max_width && height < max_height){ // To improve performance you might limit how often resizeImage() is called resizeImage(width, height); // Without this Firefox will not re-calculate the the image dimensions until drag end $container.offset({'left': left, 'top': top}); } }







, resize-handle



, .





, , , , , "". . .



init = function(){ //... $container.on('mousedown', 'img', startMoving); }







startMoving



endMoving



, startResize



endResize



.



startMoving = function(e){ e.preventDefault(); e.stopPropagation(); saveEventState(e); $(document).on('mousemove', moving); $(document).on('mouseup', endMoving); }; endMoving = function(e){ e.preventDefault(); $(document).off('mouseup', endMoving); $(document).off('mousemove', moving); };







moving



. , .



moving = function(e){ var mouse={}; e.preventDefault(); e.stopPropagation(); mouse.x = (e.clientX || e.pageX) + $(window).scrollLeft(); mouse.y = (e.clientY || e.pageY) + $(window).scrollTop(); $container.offset({ 'left': mouse.x - ( event_state.mouse_x - event_state.container_left ), 'top': mouse.y - ( event_state.mouse_y - event_state.container_top ) }); };









, , . , , , , . , , , , .



HTML :



<div class="overlay"> <div class="overlay-inner"> </div> </div> <button class="btn-crop js-crop">Crop</button>







, , .



.overlay { position: absolute; left: 50%; top: 50%; margin-left: -100px; margin-top: -100px; z-index: 999; width: 200px; height: 200px; border: solid 2px rgba(222,60,80,.9); box-sizing: content-box; pointer-events: none; } .overlay:after, .overlay:before { content: ''; position: absolute; display: block; width: 204px; height: 40px; border-left: dashed 2px rgba(222,60,80,.9); border-right: dashed 2px rgba(222,60,80,.9); } .overlay:before { top: 0; margin-left: -2px; margin-top: -40px; } .overlay:after { bottom: 0; margin-left: -2px; margin-bottom: -40px; } .overlay-inner:after, .overlay-inner:before { content: ''; position: absolute; display: block; width: 40px; height: 204px; border-top: dashed 2px rgba(222,60,80,.9); border-bottom: dashed 2px rgba(222,60,80,.9); } .overlay-inner:before { left: 0; margin-left: -40px; margin-top: -2px; } .overlay-inner:after { right: 0; margin-right: -40px; margin-top: -2px; } .btn-crop { position: absolute; vertical-align: bottom; right: 5px; bottom: 5px; padding: 6px 10px; z-index: 999; background-color: rgb(222,60,80); border: none; border-radius: 5px; color: #FFF; }







JavaScript :



init = function(){ //... $('.js-crop').on('click', crop); }; crop = function(){ var crop_canvas, left = $('.overlay').offset().left - $container.offset().left, top = $('.overlay').offset().top - $container.offset().top, width = $('.overlay').width(), height = $('.overlay').height(); crop_canvas = document.createElement('canvas'); crop_canvas.width = width; crop_canvas.height = height; crop_canvas.getContext('2d').drawImage(image_target, left, top, width, height, 0, 0, width, height); window.open(crop_canvas.toDataURL("image/png")); }







crop



resizeImage



. , .



drawImage



canvas. - . - , . - , canvas, .





. .



mousedown



mouseup



- touchstart



touchend



, mousemove



touchmove



. , touchup



touchdown



( ).



touchstart



touchend



, mousedown



, mouseup



touchmove



, mousemove



.



// In init()... $container.on('mousedown touchstart', '.resize-handle', startResize); $container.on('mousedown touchstart', 'img', startMoving); //In startResize() ... $(document).on('mousemove touchmove', moving); $(document).on('mouseup touchend', endMoving); //In endResize()... $(document).off('mouseup touchend', endMoving); $(document).off('mousemove touchmove', moving); //In startMoving()... $(document).on('mousemove touchmove', moving); $(document).on('mouseup touchend', endMoving); //In endMoving()... $(document).off('mouseup touchend', endMoving); $(document).off('mousemove touchmove', moving);







, "" . Hammer, . , , .



, , , saveEventState



. .



" " . , . moving



:



moving = function(e){ var mouse={}, touches; e.preventDefault(); e.stopPropagation(); touches = e.originalEvent.touches; mouse.x = (e.clientX || e.pageX || touches[0].clientX) + $(window).scrollLeft(); mouse.y = (e.clientY || e.pageY || touches[0].clientY) + $(window).scrollTop(); $container.offset({ 'left': mouse.x - ( event_state.mouse_x - event_state.container_left ), 'top': mouse.y - ( event_state.mouse_y - event_state.container_top ) }); // Watch for pinch zoom gesture while moving if(event_state.touches && event_state.touches.length > 1 && touches.length > 1){ var width = event_state.container_width, height = event_state.container_height; var a = event_state.touches[0].clientX - event_state.touches[1].clientX; a = a * a; var b = event_state.touches[0].clientY - event_state.touches[1].clientY; b = b * b; var dist1 = Math.sqrt( a + b ); a = e.originalEvent.touches[0].clientX - touches[1].clientX; a = a * a; b = e.originalEvent.touches[0].clientY - touches[1].clientY; b = b * b; var dist2 = Math.sqrt( a + b ); var ratio = dist2 /dist1; width = width * ratio; height = height * ratio; // To improve performance you might limit how often resizeImage() is called resizeImage(width, height); } };







.







. .



Chrome "", Firefox .



, .







All Articles