Max-height and max-width for divs with dynamic backgrounds?

Viewed 330

I have a code responsible for cropping image and saving its cropped areas in a list of divs. Each of these divs represents each of the cropped images. But the problem is - I dont want them to be so huge, I want them to have fixed height and width, e.g. max 100x100px.

Codesandbox with working image cropping: https://codesandbox.io/s/fast-frost-0b5tt Code revelant to cropping logic:

const width = pos.w + "px";
const height = pos.h + "px";
const marginLeft = - pos.x + "px";
const marginTop = - pos.y + "px";

return (
  <div
    key={i}
    style={{
      width: width,
      height: height,
      backgroundSize: "400px 300px",
      backgroundPosition: `top ${marginTop} left ${marginLeft}`,
      backgroundImage: "url('https://boygeniusreport.files.wordpress.com/2016/11/puppy-dog.jpg?quality=98&strip=all&w=400')"
    }}
  />
);

You will see that image cropping works great, however newly created images have dynamic height and width.

Question: How to make these newly created divs to have fixed width and height, but without destroying it? Thanks!

Edit: New link added (the old one was missing styles)

The goal is to make the children (cropped images) to have static height and width, but keep the background image in correct position. But seems like im too stopid to do it by myself

4 Answers

The following change within your render function will create a 100px square centered on the selection's center point, or as close as possible keeping within the image limits (I'm not sure how to reference the original image's width & height from here).

...
const previews = crops.map(({ pos }, i) => {
  const width = 100 + "px";
  const height = 100 + "px";
  let margx = (pos.w / 2) - 50 + pos.x;
  let margy = (pos.h / 2) - 50 + pos.y;
  if(margx < 0) margx = 0;
  if(margy < 0) margy = 0;
  // this needs origional image width & height (400,300) to get max values
  const maxx = 400-100;
  const maxy = 300-100;
  if(margx > maxx) margx = maxx;
  if(margy > maxy) margy = maxy;
  const marginLeft = - margx + "px";
  const marginTop = - margy + "px";

  return (
    <div
...

If you fix both height and width, the previews will look distorted. So I would recommend only fixing the height.

  const fixedHeight = 100;
  const zoom = fixedHeight / pos.h;
  const backgroundWidth = 400 * zoom;
  const backgroundHeight = 300 * zoom;
  const width = pos.w * zoom;
  const height = fixedHeight;
  const marginLeft = -pos.x * zoom;
  const marginTop = -pos.y * zoom;

See results in this codesandbox demo.

I can propose something in between solutions proposed by @MunimMunna and @ArleighHix improving both solutions. See result

// setup base image size
const imageBaseWidth = 400;
const imageBaseHeight = 300;
// choose thumbnail size and aspect ratio
const thumbHeight = 100;
const thumbWidth = 200;
// we check which axis needs to be filled to border
const zoomX = thumbWidth / pos.w;
const zoomY = thumbHeight / pos.h;
// you can improve it further by defining max zoom in level so that thumbnails don't show ugly pixels
// just use additional zoom = Math.min(zoom, maxZoom) and some more logic for handling min max margin offset so it wont go outside image bounds
const zoom = Math.max(zoomX, zoomY);
// scaling base image to best fit available space
const backgroundWidth = imageBaseWidth * zoom;
const backgroundHeight = imageBaseHeight * zoom;
// calculate offset to top left corner of biggest rect in selected region that keeps target aspect ratio
const marginLeft = thumbWidth / 2 - (pos.w / 2 + pos.x) * zoom;
const marginTop = thumbHeight / 2 - (pos.h / 2 + pos.y) * zoom;

return (
  <div
    className="preview"
    key={i}
    style={{
      width: thumbWidth + "px",
      height: thumbHeight + "px",
      backgroundSize: `${backgroundWidth}px ${backgroundHeight}px`,
      backgroundPosition: `top ${marginTop}px left ${marginLeft}px`,
      backgroundImage: "url('https://boygeniusreport.files.wordpress.com/2016/11/puppy-dog.jpg?quality=98&strip=all&w=400')"
    }}
  />
);

It chooses bigest posible region inside selection that keeps aspect ratio of targeted thumbnails and zooms in on it if required. You can setup target thumbnails size with fixedHeight, fixedWidth

Related