如何在保持容器右下角固定的情况下缩放容器?

xytpbqjk  于 2021-09-23  发布在  Java
关注(0)|答案(3)|浏览(251)

我有一个红色的容器,它最初位于黑色容器的右下角。我有一个缩放功能,可以逐渐缩放容器。我想使红色容器的右下角位置固定,并向左上角缩放。我该怎么做?

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>
uoifb46i

uoifb46i1#

要将红框的右下角锁定到黑框的右下角,此代码段执行两项操作:相对于父应用程序容器定位红框的右下角,并将变换原点设置为该点(通常变换原点位于元素的中心)。然后,它使用css动画展开红色框,并使用缩放再次收缩它。
此方法不需要js,因为它是一个简单的缩放变换,但当然,原始变换的一些微妙之处会因为绑定角而丢失。


* {

  box-sizing: border-box;
}
body {
  position: relative;
  width: 100vw;
  height: 100vh;
}

# app {

  position: absolute;
  height: 200px;
  width: 200px;
}
.box:nth-child(1) {
  height: 200px;
  width: 200px;
  background-color: black;
  position: absolute;
  top: 0;
  left: 0;
}

# box {

  background-color: red;
  width: 100px;
  height: 100px;
  position: absolute;
  bottom: 0;
  right: 0;
  transform-origin: right bottom;
  animation: scale 5s 1 ease-in-out;
}
@keyframes scale {
  0% {
    transform: scale(1);
  }
  50% {
    transform: scale(2);
  }
  100% {
    transform: scale(1);
  }
}
<div id="app">
  <div class="box"></div>
  <div class="box" id="box"></div>
</div>
i5desfxk

i5desfxk2#

好吧,我终于明白了,

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>

解释
诀窍是以这样一种方式平移容器,即在平移后缩放容器时,它总是将自身放置在紫色容器的右下角。
为了计算转换量,我们首先将容器缩放到0.5,而不进行任何转换。看起来是这样的,,

如您所见,容器的宽度为25 0.5(scale) * 50(init_width)=25 从容器的各个侧面(左上、左下、右上、右下)确定位置 (25/2, 25/2)=(12.5,12.5) 因为容器从各个侧面的比例相等。
因为右下角的位置是 (12.5,12.5) ,我们需要将容器转换为(+12.5,+12.5),然后缩放它以精确地将其放置在右下角。

uubf1zoe

uubf1zoe3#

你可以通过使用 display:flex ,太棒了!
以下是我如何处理您的问题:

const handleClick = () => {
  const blackDiv = document.getElementById("black-div");
  const redDiv = document.getElementById("red-div");

  let widthRatio = 0;
  let heightRatio = 0;

  const scaleUpTimer = setInterval(() => {
    if (widthRatio === 1 || heightRatio === 1) clearInterval(scaleUpTimer);

    widthRatio = redDiv.offsetWidth / blackDiv.offsetWidth;
    heightRatio = redDiv.offsetHeight / blackDiv.offsetHeight;
    redDiv.style.width = widthRatio * 100 + 2 + "%";
    redDiv.style.height = heightRatio * 100 + 2 + "%";

  }, 10);
};

# black-div {

  width: 200px;
  height: 200px;
  background-color: rgb(0, 0, 0);
  display: flex;
  align-items: flex-end;
  justify-content: flex-end;
}

# red-div {

  background-color: red;
  width: 50%;
  height: 50%;
}
<div id='black-div'>
  <div id='red-div' onclick={handleClick()}></div>
</div>

编辑:我在这里使用了onclick,但显然你必须处理有人点击红场的情况,并且红场已经放大,以避免设置不必要的计时器。或者您可以直接调用函数,而不必单击任何内容。

相关问题