smartcrop.js icon indicating copy to clipboard operation
smartcrop.js copied to clipboard

Is is possible to generate a percentage center point instead of absolute boundary?

Open lijunle opened this issue 7 years ago • 3 comments
trafficstars

Hi, @jwagner

This is an awesome library, thank you for creating it!

I am considering to use the library in production environment, with responsiveness support. However, the absolute cropped boundary numbers are not very friendly to responsiveness. If the calculation result is a center point with percentage, we can use the following CSS styles to stick to that center point, then it will show good in PC view or mobile view.

const style = {
  backgroundImage: `url("${imageURL}")`,
  backgroundPosition: `${centerPoint.x}% ${centerPoint.y}%`
}

Now, I am calculating the central point of the crop result as the center point. That is working but not really accurate.

More ideas?

lijunle avatar Jun 28 '18 03:06 lijunle

I found another workaround, set the width=height=50px (or small), minScale=0,5 (or small). It will generate a square cropped area, use the central point of this area as center point. The result is more making sense.

lijunle avatar Jun 28 '18 03:06 lijunle

just take x/width*100 to get %.

jwagner avatar Jun 29 '18 13:06 jwagner

Here is the full code to convert the crop to css background-position:

var img = document.getElementById('imgId');

// adjust settings to your needs
smartcrop.crop(img, {
    width    : 100,
    height   : 100,
    minScale : .75
}).then(function(result) {
    var crop    = result.topCrop;

    var X_total = img.naturalWidth - crop.width; 
    var X_perc  = crop.x/X_total;

    var Y_total = img.naturalHeight - crop.height;
    var Y_perc  = crop.y/Y_total;

    var cssBgPos = (X_perc*100).toFixed(0) + '% ' + (Y_perc*100).toFixed(0) + '%');

    // your code...
});

Personally I only use background-size: cover; in my projects. To find the best fit for multiple target aspect ratios I calculate two crops with an ratio of 3:2 (for the y-axis) and 2:3 (for the x-axis) and translate these crops to background-position values. My complete code looks like this:

// calculate best crops for 3:2 and 2:3
var img = document.getElementById(imgId);
var naturalWidth  = img.naturalWidth;
var naturalHeight = img.naturalHeight;

// smart crop for 3:2 (y-axis)
smartcrop.crop(img, {
    width    : 300,
    height   : 200,
    minScale : 1 // due to background-size:cover;
}).then(function(result) {
    var crop    = result.topCrop;

    // calc max value for crop.y given the height of the crop, this represents
    // 100% in terms of css background-position for the y-axis
    var Y_total = naturalHeight - crop.height;

    // calculate actual css background-position for the y-axis
    var Y_perc  = crop.y/Y_total;

    // smart crop for 2:3 (x-axis)
    smartcrop.crop(img, {
        width    : 200,
        height   : 300,
        minScale : 1 // due to background-size:cover;
    }).then(function(result) {
        var crop    = result.topCrop;

        // calc max value for crop.x given the width of the crop, this represents
        // 100% in terms of css background-position for the x-axis
        var X_total = naturalWidth - crop.width;
       
        // calculate actual css background-position for the x-axis
        var X_perc  = crop.x/X_total;

        var cssBgPos = (X_perc*100).toFixed(0) + '% ' + (Y_perc*100).toFixed(0) + '%';
        // cssBgPos is what I work with then
    });
});

If you only have one img ratio, you do not need to calculate multiple ratios, but this method works pretty well for varying ratios. You might want to use more extreme ratios like 2:1 and 1:2 if you have to cover a wider spectrum.

Candyffm avatar Aug 27 '21 21:08 Candyffm