How to implement crop tool on the image that is loaded on the canvas using fabric.js ? I have a image loaded on the canvas .Now i want to implement crop tool where the user is allowed to crop the image and reload it on to the canvas when he is done.
(This answer is an iteration on the fiddle in Tom's answer. Thank you, Tom, for getting me down the road.)
You can crop in Fabric.js using either fabric.Object.clipTo() or fabric.Object.toDataURL(). The clipTo()
method retains the original image and displays a crop via a mask. The toDataURL()
method creates a new image.
My full example uses the clipTo()
method. I have included a small chunk of code at the end showing the toDataURL()
method.
Solution 1
Summary
Difference's from Tom's answer
In the fiddle in Tom's answer, there are a couple of minor things I wanted to change. So in my example the differences are
The crop box work from left to right and right to left (Tom's works from right to left only)
You have more than one chance to draw the crop box (attempting to re-draw the crop box in Tom's causes box to jump)
Works with Fabric.js v1.5.0
Less code.
The Code
// set to the event when the user pressed the mouse button down var mouseDown; // only allow one crop. turn it off after that var disabled = false; var rectangle = new fabric.Rect({ fill: 'transparent', stroke: '#ccc', strokeDashArray: [2, 2], visible: false }); var container = document.getElementById('canvas').getBoundingClientRect(); var canvas = new fabric.Canvas('canvas'); canvas.add(rectangle); var image; fabric.util.loadImage("http://fabricjs.com/lib/pug.jpg", function(img) { image = new fabric.Image(img); image.selectable = false; canvas.setWidth(image.getWidth()); canvas.setHeight(image.getHeight()); canvas.add(image); canvas.centerObject(image); canvas.renderAll(); }); // capture the event when the user clicks the mouse button down canvas.on("mouse:down", function(event) { if(!disabled) { rectangle.width = 2; rectangle.height = 2; rectangle.left = event.e.pageX - container.left; rectangle.top = event.e.pageY - container.top; rectangle.visible = true; mouseDown = event.e; canvas.bringToFront(rectangle); } }); // draw the rectangle as the mouse is moved after a down click canvas.on("mouse:move", function(event) { if(mouseDown && !disabled) { rectangle.width = event.e.pageX - mouseDown.pageX; rectangle.height = event.e.pageY - mouseDown.pageY; canvas.renderAll(); } }); // when mouse click is released, end cropping mode canvas.on("mouse:up", function() { mouseDown = null; }); $('#cropB').on('click', function() { image.clipTo = function(ctx) { // origin is the center of the image var x = rectangle.left - image.getWidth() / 2; var y = rectangle.top - image.getHeight() / 2; ctx.rect(x, y, rectangle.width, rectangle.height); }; image.selectable = true; disabled = true; rectangle.visible = false; canvas.renderAll(); });
<head> <script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/2.1.3/jquery.min.js" type="text/javascript"></script> <script src="https://cdnjs.cloudflare.com/ajax/libs/fabric.js/1.5.0/fabric.min.js" type="text/javascript"></script> </head> <body> <canvas style="border: 1px solid black" id="canvas"></canvas> <button id=cropB>crop</button> </body>
Solution 2
Or, instead of using clipTo()
like above, we could generate a new image using toDataURL()
. Something like this
$('#cropB').on('click', function() { image.selectable = true; disabled = true; rectangle.visible = false; var cropped = new Image(); cropped.src = canvas.toDataURL({ left: rectangle.left, top: rectangle.top, width: rectangle.width, height: rectangle.height }); cropped.onload = function() { canvas.clear(); image = new fabric.Image(cropped); image.left = rectangle.left; image.top = rectangle.top; image.setCoords(); canvas.add(image); canvas.renderAll(); }; });
In Summary
el.selectable = false
Sorry, let me explain. The ctx.rect
will crop the image from the center point of the object. Also the scaleX
factor should be taken into account.
x = select_el.left - object.left; y = select_el.top - object.top; x *= 1 / scale; y *= 1 / scale; width = select_el.width * 1 / scale; heigh = select_el.height * 1 / scale; object.clipTo = function (ctx) { ctx.rect (x, y, width, height); }
Complete example: http://jsfiddle.net/hellomaya/kNEaX/1/
And check out this http://jsfiddle.net/hellomaya/hzqrM/ for generating the select box. And a reference for the Fabric events: https://github.com/kangax/fabric.js/wiki/Working-with-events
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With