Изменение размеров отдельных фигур динамически без масштабирования всего SVG

У меня есть стрелка как SVG, длина которой я хочу изменить в ответ на ширину обертывания DIV (например).

Все мои предыдущие попытки привели к такому поведению (масштабирование всего SVG):

Масштабирование всего SVG

Вместо этого я хочу добиться такого поведения:

Только масштабирование фигур

Можно ли просто изменить отдельные фигуры внутри SVG, просто добавив в код процентные значения? Если нет, как я могу это сделать?

SVG как код:

<svg width="35px" viewBox="0 0 35 985" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
  <g id="Group" stroke="none" stroke-width="1" fill="none" fill-rule="evenodd" transform="translate(0.000000, 0.000000)">
    <rect id="Rectangle-2" fill="#5FDCC7" x="12" y="19.7987928" width="11" height="100%"></rect>
    <polygon id="Triangle" fill="#5FDBC6" points="17.5 0 35 20.7887324 0 20.7887324"></polygon>
    <rect id="Rectangle-3" fill="#5FDBC6" x="0" y="973.110664" width="35" height="11"></rect>
  </g>
</svg>

Ответ 1

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

Ближайшее, что вы можете сделать, это ограничить масштабирование по оси X. Однако стрелка еще будет растягиваться.

<svg width="35px" height="150px" viewBox="0 0 35 985" preserveAspectRatio="none">

        <g id="Group" stroke="none" stroke-width="1" fill="none" fill-rule="evenodd" transform="translate(0.000000, 0.000000)">
            <rect id="Rectangle-2" fill="#5FDCC7" x="12" y="19.7987928" width="11" height="100%"></rect>
            <polygon id="Triangle" fill="#5FDBC6" points="17.5 0 35 20.7887324 0 20.7887324"></polygon>
            <rect id="Rectangle-3" fill="#5FDBC6" x="0" y="973.110664" width="35" height="11"></rect>
        </g>
</svg>


<svg width="35px" height="300px" viewBox="0 0 35 985" preserveAspectRatio="none">

        <g id="Group" stroke="none" stroke-width="1" fill="none" fill-rule="evenodd" transform="translate(0.000000, 0.000000)">
            <rect id="Rectangle-2" fill="#5FDCC7" x="12" y="19.7987928" width="11" height="100%"></rect>
            <polygon id="Triangle" fill="#5FDBC6" points="17.5 0 35 20.7887324 0 20.7887324"></polygon>
            <rect id="Rectangle-3" fill="#5FDBC6" x="0" y="973.110664" width="35" height="11"></rect>
        </g>
</svg>

Ответ 2

Для этого подробного использования я думаю, что я бы пошел на подход CSS, он мог (в зависимости от вашей разметки) добавить элемент html, если вы не можете использовать псевдоэлементы, но он не потребует JS или ручных входных значений для элементов ширины штриха или преобразования.

Вот способ сделать эту стрелку с помощью тега абзаца:

p {
  position: relative;
  max-width: 300px;
  border-bottom: 4px solid #5FDBC6;
  padding-bottom:6px;
}
p:nth-child(2) {max-width: 400px;}
p:nth-child(3) {max-width: 200px;}
p::before, p::after{
  content:'';
  position:absolute;
  bottom:-8px;
}
p::before {
  height: 12px;
  left:0;
  border-left: 4px solid #5FDBC6;
}
p::after{
  right:-4px;
  border-style:solid;
  border-width:6px 0 6px 8px;
  border-color:transparent transparent transparent #5FDBC6;
}
<p>Lorem ipsum dolor sit amet, consectetur adipiscing elit. a dapibus, tincidunt velit eget, rutrum urna.</p>
<p>Lorem ipsum dolor sit amet, consectetur adipiscing elit. Cras in purus risus. Ut id est suscipit, tincidunt sem a, fermentum magna. Class aptent taciti sociosqu ad litora torquent per conubia nostra, per inceptos himenaeos. Ut rutrum ac ligula</p>
<p>Lorem ipsum dolor sit amet, consectetur adipiscing elit. Cras in purus risus. Ut id est suscipit, tincidunt sem a, fermentum magna.</p>

Ответ 3

Да, вы можете использовать проценты в svg.

для основных фигур довольно просто. Вы можете написать свой основной прямоугольник как

<rect x="0" y="5" width="100%" height="10"/>

ваш второй прямоугольник еще проще, так как он все время находится на 0,0

<rect x="0" y="0" width="10" height="20"/>

но со стрелкой возникает проблема с патчами и полигоном, вы не можете использовать проценты. Чтобы обойти эту проблему, существует двухэтапное решение.

сначала введите путь в элемент символа:

<symbol id="arrow" viewBox="0 0 20 20" width="20" height="20">
  <path d="M0,0L20 10L0 20z" />
</symbol>

теперь вы можете поместить этот символ, как если бы вы разместили прямоугольник... easy...

<use xlink:href="#arrow" x="100%" y="0" width="20" height="20"/>

но теперь ваша стрелка начинается на 100% и полностью выходит за пределы вашего окна просмотра. вы можете просто установить переполнение: видимо на вашем svg и покончить с ним, но это не то, что мы хотим... мы хотим, чтобы стрела закончилась со 100%. Но так легко, мы знаем, что стрела шириной 20 пикселей. Так что просто переведите использование обратно 20px:

<use xlink:href="#arrow" x="100%" y="0" width="20" height="20" transform="translate(-20 0)"/>

используя этот подход, вы можете позиционировать любую форму в любой позиции на процентах...

чтобы все испортить, ваш полный svg теперь выглядит следующим образом:

<svg id="svg" height="20px" xmlns:xlink="http://www.w3.org/1999/xlink">
  <symbol id="arrow" viewBox="0 0 20 20" width="20" height="20">
    <path d="M0,0L20 10L0 20z" />
  </symbol>
  <g id="Group" fill="#5FDCC7">
    <rect x="0" y="5" width="100%" height="10" transform="translate(-20 0)" />
    <rect x="0" y="0" width="10" height="20" />
    <use xlink:href="#arrow" width="20" height="20" x="100%" y="0" transform="translate(-20 0)" />
  </g>
</svg>

и вот фрагмент с использованием этого svg с 3 различными ширинами:

svg:nth-of-type(1) {
  width: 100px
}
svg:nth-of-type(2) {
  width: 200px
}
svg:nth-of-type(3) {
  width: 300px
}
<svg height="20px" xmlns:xlink="http://www.w3.org/1999/xlink">
  <symbol id="arrow" viewBox="0 0 20 20" width="20" height="20">
    <path d="M0,0L20 10L0 20z" />
  </symbol>
  <g id="Group" fill="#5FDCC7">
    <rect x="0" y="5" width="100%" height="10" transform="translate(-20 0)" />
    <rect x="0" y="0" width="10" height="20" />
    <use xlink:href="#arrow" width="20" height="20" x="100%" y="0" transform="translate(-20 0)" />
  </g>
</svg>
<br/>
<svg height="20px" xmlns:xlink="http://www.w3.org/1999/xlink">
  <symbol id="arrow" viewBox="0 0 20 20" width="20" height="20">
    <path d="M0,0L20 10L0 20z" />
  </symbol>
  <g id="Group" fill="#5FDCC7">
    <rect x="0" y="5" width="100%" height="10" transform="translate(-20 0)" />
    <rect x="0" y="0" width="10" height="20" />
    <use xlink:href="#arrow" width="20" height="20" x="100%" y="0" transform="translate(-20 0)" />
  </g>
</svg>
<br/>
<svg height="20px" xmlns:xlink="http://www.w3.org/1999/xlink">
  <symbol id="arrow" viewBox="0 0 20 20" width="20" height="20">
    <path d="M0,0L20 10L0 20z" />
  </symbol>
  <g id="Group" fill="#5FDCC7">
    <rect x="0" y="5" width="100%" height="10" transform="translate(-20 0)" />
    <rect x="0" y="0" width="10" height="20" />
    <use xlink:href="#arrow" width="20" height="20" x="100%" y="0" transform="translate(-20 0)" />
  </g>
</svg>

Ответ 4

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

<svg xmlns="http://www.w3.org/2000/svg">

  <symbol id="base">
    <g xmlns="http://www.w3.org/2000/svg">
      <path fill="#5FDBC6" d="M0,0 L0,20 L4,20 L4,0z"></path>
    </g>
  </symbol>
  <symbol id="triangle" >
    <g>
      <path fill="#5FDBC6" d="M0,0 L15,10 L0,20z"></path>
    </g>
  </symbol>

  <path stroke-width="4" stroke="#5FDBC6" d="M0,10 L100,10"></path>
  <g class="first" transform="translate(0,00)">
    <use xlink:href="#base" />
  </g>
  <g class="first" transform="translate(90,00)">
    <use xlink:href="#triangle" />
  </g>
  
  <path stroke-width="4" stroke="#5FDBC6" d="M0,50 L200,50"></path>
  <g class="first" transform="translate(0,40)">
    <use xlink:href="#base" />
  </g>
  <g class="first" transform="translate(200,40)">
    <use xlink:href="#triangle" />
  </g>


</svg>

Ответ 5

** EDITED **

Это поведение вызвано вашим атрибутом viewBox на <svg>. Соотношение сторон вашего SVG сохраняется по умолчанию. Это поведение требуется для #Triangle и #Rectangle-3, но не для #Rectangle-2 (вы хотите, чтобы height увеличивалось, а width оставалось неизменным).

Я думаю, вам нужно добавить preserveAspectRatio=none в свой <svg> встроенный CSS, а затем сделать некоторую настройку (поскольку это искажает соотношение сторон ваших #Triangle и #Rectangle-3 - или вместо этого, вы может попробовать изменить height of #triangle-2 на ту же высоту, что и ваш оберточный div (в моей скрипте JS я сделал это таким образом, установив #triangle-2 height до 25vh). Играйте с высотой окна - #Rectangle-2 height удлиняется, но не меняет ширину, хотя я еще не получил ваш #Rectangle-3, чтобы динамически придерживаться нижней части #Rectangle-2 (#Rectangle-3 застрял в нижней части окна): https://jsfiddle.net/KyleVassella/dnagft6q/6/

Я подозреваю, что вы знаете, как это исправить, но в любом случае Ill продолжит работать над этим, и тем временем вы можете прочитать здесь, где есть гораздо больше информации по этому вопросу:

Как я могу создать масштаб svg с его родительским контейнером?