On using Fabric.js 1.7.3, I have noticed an odd behavior when cropping images. Essentially, I have set the clipTo method in an image to display only a small square in the center of the image:
However, the problem is that the image's selection box still takes up the original size rather than the cropped size. When clicking on the image, I would expect the corners to be right next to the edges of the picture; similarly, the selection should only be activated when I click on the cropped picture.
A possible solution for this involves exporting the cropped part of the image as base64, removing the old image and adding the cropped version instead. However, this is rather impractical and feels like overkill. Is there a way in which I could simply adjust the selection box to respect the cropped size?
To build on AndreaBogazzi's answer, here's my complete solution in which I override the _render method. Whenever I create an image, I add a "sizeMode" attribute to it which tells _render how exactly to paint it:
fabric.Image.prototype._render = function(ctx, noTransform) {
/* This is the default behavior. I haven't modified anything in this part. */
let x, y, imageMargins = this._findMargins(), elementToDraw;
x = (noTransform ? this.left : -this.width / 2);
y = (noTransform ? this.top : -this.height / 2);
if (this.meetOrSlice === 'slice') {
ctx.beginPath();
ctx.rect(x, y, this.width, this.height);
ctx.clip();
}
if (this.isMoving === false && this.resizeFilters.length && this._needsResize()) {
this._lastScaleX = this.scaleX;
this._lastScaleY = this.scaleY;
elementToDraw = this.applyFilters(null, this.resizeFilters, this._filteredEl
|| this._originalElement, true);
}
else {
elementToDraw = this._element;
}
/* My changes begin here. */
if (elementToDraw && elementToDraw.naturalHeight > 0) {
if (this.sizeMode === BadgingImageSizeMode.CenterImage) {
drawCenterImage.apply(this, [ctx, elementToDraw, imageMargins, x, y]);
} else {
// Default _render behavior
ctx.drawImage(elementToDraw,
x + imageMargins.marginX,
y + imageMargins.marginY,
imageMargins.width,
imageMargins.height);
}
}
/* And they finish here. */
this._stroke(ctx);
this._renderStroke(ctx);
};
The drawCenterImage function I've defined is here:
const drawCenterImage = function(ctx, elementToDraw, imageMargins, x, y) {
const sx = (elementToDraw.naturalWidth - this.width) / 2;
const sy = (elementToDraw.naturalHeight - this.height) / 2;
ctx.drawImage(elementToDraw,
sx,
sy,
imageMargins.width,
imageMargins.height,
x + imageMargins.marginX,
y + imageMargins.marginY,
imageMargins.width,
imageMargins.height);
};
While this works for centering images (as was my original question), different calls to ctx.drawImage will result in different effects. Here is the documentation for the drawImage method.