CSS: рассчитать переполнение двух перекрывающихся прямоугольников после поворота одного - PullRequest
2 голосов
/ 22 марта 2019

странный вопрос, который я знаю, но я хотел знать, возможно ли рассчитать ширину, в которой прямоугольник должен идеально вписаться в другой прямоугольник после поворота первого с помощью transform: rotate. Вот картина того, что я пытаюсь сказать:

Example of what I'm trying to achieve

В идеале я хочу, чтобы это было динамическим, чтобы оно не зависело от фактического с первого прямоугольника.

Я использую SCSS, и вот что я получил до сих пор:

.background-box {
  background: black;
  padding: rem(30px 40px);
  position: relative;
  width: auto;
  &:after {
    content: "";
    width: 100%;
    height: 100%;
    position: absolute;
    top: 0;
    left: 0;
    @include transform(rotate(5deg));
    border: rem(2px) solid $primary;
    background: transparent;
    z-index: -1;
  }
}

HTML выглядит так:

<div class="background-box">
    //CONTENT
</div>

Теперь я хочу, чтобы width прямоугольника 2 (построенный по :after) был X , чтобы поместиться внутри родительского элемента. Что-то вроде width: calc(100% - overflow).

Возможно ли это, или мне нужно обойти что-то вроде width: 98%?

1 Ответ

2 голосов
/ 23 марта 2019

Вот иллюстрация, чтобы лучше показать проблему и расчет, который мы должны сделать:

.box {
  margin: 50px;
  width: 200px;
  height: 100px;
  outline: 2px solid;
  box-sizing: border-box;
}

.rect {
  width: 100%;
  height: 100%;
  border: 1px solid green;
  box-sizing: border-box;
  transform-origin: bottom left;
  background: linear-gradient(to bottom right, transparent 49%, red 49%, red 52%, transparent 52%);
  animation: change 5s linear infinite alternate;
}

@keyframes change {
  from {
    transform: rotate(0deg);
  }
  to {
    transform: rotate(53deg);
  }
}
<div class="box">
  <div class="rect">
  </div>
</div>

Как видите, у нас есть диагональная линия (красная), которую нам нужно уменьшить, чтобы избежать переполнения.

enter image description here

На рисунке ниже у нас есть угол поворота (синим цветом) и угол фиолетового цвета, основанный на размере прямоугольника. Отсюда получаем следующую формулу:

cos(PurpleAngle) = width/X
cos(PurpleAngle - BlueAngle) = width/X1 

, где X1 - ширина, необходимая для нашей диагонали (ограничена желтым крестом), а X - ширина диагонали (полная красная линия).

Затем мы можем написать это:

X/X1 = cos(PurpleAngle - BlueAngle)/cos(PurpleAngle)

тогда

X/X1 = (cos(PurpleAngle)*cos(BlueAngle) + sin(PurpleAngle)*sin(BlueAngle))/cos(PurpleAngle)

упрощаем до

X/X1 = cos(BlueAngle) + tan(PurpleAngle)*sin(BlueAngle)

Мы знаем BlueAngle, который является нашим углом поворота, и мы можем легко найти tan(PurpleAngle), который просто Height/Width. Да, нам нужно знать ширину и высоту или хотя бы соотношение между ними. В моем случае я использовал соотношение 0.5, поэтому будет иметь:

X/X1 = cos(BlueAngle) + 0.5*sin(BlueAngle)

Теперь мы можем видеть это как еще один поворот по оси Y, где у нас будет cos(B) = X1/X.

* * Пример тысяча сорок-одиной: * +1042 *

.box {
  margin: 50px;
  width: 200px;
  height: 100px;
  outline: 2px solid;
  box-sizing: border-box;
}

.rect {
  width: 100%;
  height: 100%;
  border: 1px solid green;
  box-sizing: border-box;
  transform:rotate(20deg) rotateY(25.84deg);
  background: linear-gradient(to bottom right, transparent 49%, red 49%, red 52%, transparent 52%);
  animation: change 5s linear infinite alternate;
}
<div class="box">
  <div class="rect">
  </div>
</div>

Или мы также можем видеть это как масштабное преобразование с коэффициентом, равным X1/X:

Пример: * * тысяча пятьдесят-три

.box {
  margin: 50px;
  width: 200px;
  height: 100px;
  outline: 2px solid;
  box-sizing: border-box;
}

.rect {
  width: 100%;
  height: 100%;
  border: 1px solid green;
  box-sizing: border-box;
  transform:rotate(20deg) scale(0.9);
  background: linear-gradient(to bottom right, transparent 49%, red 49%, red 52%, transparent 52%);
  animation: change 5s linear infinite alternate;
}
<div class="box">
  <div class="rect">
  </div>
</div>

Итак, все, что вам нужно сделать, это узнать соотношение, а затем угол поворота, используя формулу, чтобы найти значение шкалы или значение поворота.

Больше примеров:

.box {
  margin: 20px;
  width: 150px;
  height: 75px;
  display:inline-block;
  vertical-align:top;
  outline: 2px solid;
  box-sizing: border-box;
}

.rect {
  width: 100%;
  height: 100%;
  border: 1px solid green;
  box-sizing: border-box;
}
<!-- 1/(cos(20deg) + 0.5*sin(20deg)) -->
<div class="box">
  <div class="rect" style="
  transform:rotate(20deg) scale(0.9);">
  </div>
</div>
<!-- 1/(cos(45deg) + 1*sin(45deg)) -->
<div class="box" style="height:150px">
  <div class="rect" style="
  transform:rotate(45deg) scale(0.707);">
  </div>
</div>

<!-- 1/(cos(5deg) + 0.333*sin(5deg)) -->
<div class="box" style="height:50px">
  <div class="rect" style="
  transform:rotate(5deg) scale(0.972);">
  </div>
</div>

<!-- 1/(cos(15deg) + 2*sin(15deg)) -->
<div class="box" style="height:300px;">
  <div class="rect" style="
  transform:rotate(15deg) scale(0.674);">
  </div>
</div>

Используя SASS, вы можете рассмотреть эту ссылку (https://unindented.org/articles/trigonometry-in-sass/), где вы можете найти определение cos() sin(), тогда вы просто сделаете:

@function scale-factor($angle, $ratio) {
  @return 1/(cos($angle) + $ratio*sin($angle)); 
}


div {
  transform:rotate(15deg) scale(scale-factor(15deg,2));
}

И вы получите это:

div {
  transform: rotate(15deg) scale(0.6740525224);
}

Для решения CSS мы также можем положиться на calc(), чтобы упростить вычисления, выполнив scale(calc(1 / (cos(a) + r*sin(a))), где нам нужно только вычислить cos() и sin()

...