How to scale a container keeping its bottom right corner fixed?



I have a red container which initially is at bottom right of black container. I have a scale function that gradually scales the container. I want to make the bottom right position of red container to be fixed and scale it towards top left. How can I do that?

const box = document.getElementById("box")

const initHeight = 200
const initWidth = 200

const centerX = initWidth / 2
const centerY = initHeight / 2

function transform(scale, translate) {
  if (translate) {
    translate[0] = -centerX + translate[0]
    translate[1] = -centerY + translate[1]
  }

  box.style.transform = `scale(${scale})${
    translate ? ` translate(${translate.map((x) => x + "px").toString()})` : ""
  }`
}

let initX = initWidth
let initY = initHeight
let scaleVal = 0.5

transform(scaleVal, [initX, initY])

function scale() {
  scaleVal = scaleVal + 0.01
  transform(scaleVal, [
    initX - scaleVal * initWidth,
    initY - scaleVal * initHeight
  ])
  if (scaleVal <= 1) {
    setTimeout(() => {
      requestAnimationFrame(scale)
    }, 50)
  }
}

scale()
* {
  box-sizing: border-box;
}
.box {
  height: 200px;
  width: 200px;
  background-color: black;
  position: absolute;
}
.box:nth-child(2) {
  background-color: red;
}
<div id="app">
  <div class="box"></div>
  <div class="box" id="box"></div>
</div>

Answer

Okay so I finally figured it out,

const box = document.getElementById("box")
let scale = 0

const initWidth = 50
const initHeight = 50

function fixed(num, fix = 1) {
  return Number(parseFloat(num).toFixed(fix))
}

function scaleBox() {
  const [x, y] = [
    fixed((initWidth - scale * initWidth) / 2),
    fixed((initHeight - scale * initHeight) / 2)
  ]

  box.style.transform = `translate(${x}px, ${y}px) scale(${scale})`
  scale = scale + 0.1

  if (scale < 1) {
    setTimeout(() => {
      requestAnimationFrame(scaleBox)
    }, 500)
  }
}

scaleBox()
* {
  box-sizing: border-box;
}
.box {
  height: 50px;
  width: 50px;
  background-color: black;
  position: absolute;
}
.box:nth-child(2) {
  background-color: red;
  transform: translate(0, 0) scale(0);
}
<div id="app">
  <div class="box"></div>
  <div class="box" id="box"></div>
</div>

Explanation

The trick is to translate the container in such a way that when its scaled after the translation, it always places itself in the bottom right of purple container.

To figure out the translation amount, let’s first scale the container to 0.5 without any translation. It looks like this,

enter image description here

As you can see the container’s width is 25 as 0.5(scale) * 50(init_width)=25 and position from container from all sides(top left, bottom left, top right, bottom right) will be (25/2, 25/2)=(12.5,12.5) since the container is scaled equally from all sides.

Since the position from bottom right is (12.5,12.5), we need to translate the container to (+12.5,+12.5) and then scale it to exactly place it at bottom right.

enter image description here

enter image description here



Source: stackoverflow