【问题标题】:How to correctly translate part of SVG graphic after its parenthas been rotated?SVG图形的部分旋转后如何正确翻译?
【发布时间】:2022-01-23 08:33:13
【问题描述】:

我试图在整个图形已经旋转后翻译 SVG 图形的一部分。它由两个三角形支架组成,它们首先按比例缩小,然后旋转。 完成后,我只希望右括号在 x 轴上向右移动,而左括号保持在原位。

围绕元素的中心缩放和旋转元素不是问题,但是当我想在 x 轴上平移右括号时,我得到了意想不到的副作用。

这是一个说明问题的工作 sn-p:

    .brackets {
      animation: scaling 1s, rotating 2s 1s;
      transform-box: fill-box;
    }
    
    .bracket-left {
      animation: rotate-left 1s 3s forwards;
      transform-box: fill-box;
    }
    
    .bracket-right {
      animation: sliding 1s 3s forwards;
      transform-box: fill-box;
    }
    
    @keyframes scaling {
      0% {
        transform: scale(0);
      }
      25% {
        transform: scale(1);
      }
      100% {
        transform: scale(1);
      }
    }
    
    @keyframes rotating {
      0% {
        transform-origin: center;
        transform: rotate(0deg);
      }
      100% {
        transform-origin: center;
        transform: rotate(-405deg);
      }
    }
    
    @keyframes sliding {
      100% {
        transform: translate(40px, 0px) rotate(-45deg);
      }
    }
    
    @keyframes rotate-left {
      0% {
        transform-origin: center;
        transform: rotate(-45deg);
      }
      100% {
        transform-origin: center;
        transform: rotate(-45deg);
      }
    }
<html lang="en">
  <head>
    <meta charset="utf-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1" />
    <title>CSS SVG</title>
    <link rel="stylesheet" href="test.css" />
  </head>

  <body>
    <svg
      width="256"
      height="256"
      viewbox="0 0 100 100"
      xmlns:xlink="http://www.w3.org/1999/xlink"
      xmlns="http://www.w3.org/2000/svg"
    >
      <defs>
        <linearGradient
          xlink:href="#a"
          id="e"
          gradientUnits="userSpaceOnUse"
          x1="-3.999"
          y1=".503"
          x2="-.497"
          y2="4.005"
        />
        <linearGradient id="a">
          <stop
            style="stop-color: #17ce17; stop-opacity: 0.80000001"
            offset="0"
          />
          <stop
            style="stop-color: #11b3d4; stop-opacity: 0.49803922"
            offset=".5"
          />
          <stop style="stop-color: #00f; stop-opacity: 0" offset=".5" />
        </linearGradient>
        <linearGradient
          xlink:href="#b"
          id="f"
          gradientUnits="userSpaceOnUse"
          x1="1.906"
          y1="1.889"
          x2="15.117"
          y2="15.107"
        />
        <linearGradient id="b">
          <stop style="stop-color: #17ceb5; stop-opacity: 1" offset=".364" />
          <stop style="stop-color: #05fa05; stop-opacity: 0" offset="1" />
        </linearGradient>
        <linearGradient
          xlink:href="#a"
          id="c"
          gradientUnits="userSpaceOnUse"
          x1="-3.999"
          y1=".503"
          x2="-.497"
          y2="4.005"
        />
        <linearGradient
          xlink:href="#b"
          id="d"
          gradientUnits="userSpaceOnUse"
          x1="1.906"
          y1="1.889"
          x2="15.117"
          y2="15.107"
        />
      </defs>
      <g class="brackets" style="display: inline">
        <g class="bracket-right" style="display: inline">
          <path
            style="
              display: inline;
              fill: url(#c);
              fill-rule: evenodd;
              stroke-width: 0.264583;
            "
            transform="rotate(90 0 41.401) scale(3.77953)"
            d="M-3.5 0h3a.499.499 0 1 1 0 1h-3a.499.499 0 1 1 0-1Z"
          />
          <path
            style="
              display: inline;
              fill: url(#d);
              fill-opacity: 1;
              fill-rule: evenodd;
              stroke-width: 0.999999;
            "
            d="M1.89 0C.845 0 .002.845 0 1.89v3.78a1.89 1.89 0 0 1 1.885-1.89h11.344a1.884 1.884 0 0 0 1.888-1.89C15.117.845 14.275 0 13.23 0Zm1.89 5.67a1.89 1.89 0 0 1-.009.17h.008z"
            transform="rotate(179.997 20.7 20.7)"
          />
        </g>
        <g class="bracket-left" style="display: inline">
          <path
            style="
              display: inline;
              fill: url(#e);
              fill-rule: evenodd;
              stroke-width: 0.264583;
            "
            transform="rotate(-90 22.599 0) scale(3.77953)"
            d="M-3.5 0h3a.499.499 0 1 1 0 1h-3a.499.499 0 1 1 0-1Z"
          />
          <path
            style="
              display: inline;
              fill: url(#f);
              fill-opacity: 1;
              fill-rule: evenodd;
              stroke-width: 0.999999;
            "
            d="M1.89 0C.845 0 .002.845 0 1.89v3.78a1.89 1.89 0 0 1 1.885-1.89h11.344a1.884 1.884 0 0 0 1.888-1.89C15.117.845 14.275 0 13.23 0Zm1.89 5.67a1.89 1.89 0 0 1-.009.17h.008z"
            transform="matrix(1 0 0 1 22.599 22.598)"
          />
        </g>
      </g>
    </svg>
  </body>
</html>

这是迄今为止我最接近的。请注意左括号在最后一个动画期间看起来是如何平移的,即使我只有一个旋转活动。我也不希望右括号在 y 轴上移动,只在 x 轴上移动。

我不太清楚为什么会发生这种情况,但我认为这与旋转有关,也修改了 SVG 的坐标系。我已经尝试将每个括号作为 SVG 嵌套在主 SVG 中,但要么我太笨,无法正确地做到这一点,要么没有帮助。

我怎样才能做到这一点?在为不同/组合的 SVG 图形制作动画时,处理修改 SVG 坐标系的变换的最佳方法是什么?

【问题讨论】:

    标签: css svg


    【解决方案1】:

    此类问题几乎总是由以下两种情况之一引起:

    1. 意外将现有转换替换为非等效转换,或
    2. 变换原点意外改变

    在你的情况下,我相信是后者。当您移动.bracket-right 时,与transform-origin: center 对应的点会移动。那是因为fill-box 越来越大。这会影响组合转换集产生的结果。

    我建议您简化动画。你真的只发生了两个转换:

    1. 两个括号的缩放和旋转
    2. 右括号的移动

    我在下面所做的最重要的更改是 (a) 删除 transform-box: fill 和 (b) 对 transform-origin 使用绝对坐标。

    对于初始比例,我使用transform-origin: 22.6px, 22.6px。对应于括号的左上角。对于旋转,我使用transform-origin: 32px, 32px,它对应于两个括号的中心点。而且因为我使用的是绝对坐标,所以右括号移动时不会影响变换。

    至于右括号动画,我将其简化为简单的向下和向右平移。因为如果您考虑原始未旋转的图标,这就是它的真正含义。

    .brackets {
      animation: anim-both 3s forwards;
    }
    
    .bracket-right {
      animation: anim-right 1s 3s forwards;
    }
        
    @keyframes anim-both {
      0% {
        transform: rotate(0deg) scale(0);
        transform-origin: 22.6px 22.6px;
      }
      33% {
        transform: rotate(0deg) scale(1);
        transform-origin: 22.6px 22.6px;
      }
      34% {
        transform: rotate(0deg) scale(1);
        transform-origin: 32px 32px;
      }
      100% {
        transform: rotate(-405deg) scale(1);
        transform-origin: 32px 32px;
      }
    }
        
    @keyframes anim-right {
      0% {
        transform: translate(0, 0);
      }
      100% {
        transform: translate(40px, 40px);
      }
    }
    <html lang="en">
      <head>
        <meta charset="utf-8" />
        <meta name="viewport" content="width=device-width, initial-scale=1" />
        <title>CSS SVG</title>
        <link rel="stylesheet" href="test.css" />
      </head>
    
      <body>
        <svg
          width="256"
          height="256"
          viewbox="0 0 100 100"
        >
          <defs>
            <linearGradient
              xlink:href="#a"
              id="e"
              gradientUnits="userSpaceOnUse"
              x1="-3.999"
              y1=".503"
              x2="-.497"
              y2="4.005"
            />
            <linearGradient id="a">
              <stop
                style="stop-color: #17ce17; stop-opacity: 0.80000001"
                offset="0"
              />
              <stop
                style="stop-color: #11b3d4; stop-opacity: 0.49803922"
                offset=".5"
              />
              <stop style="stop-color: #00f; stop-opacity: 0" offset=".5" />
            </linearGradient>
            <linearGradient
              xlink:href="#b"
              id="f"
              gradientUnits="userSpaceOnUse"
              x1="1.906"
              y1="1.889"
              x2="15.117"
              y2="15.107"
            />
            <linearGradient id="b">
              <stop style="stop-color: #17ceb5; stop-opacity: 1" offset=".364" />
              <stop style="stop-color: #05fa05; stop-opacity: 0" offset="1" />
            </linearGradient>
            <linearGradient
              xlink:href="#a"
              id="c"
              gradientUnits="userSpaceOnUse"
              x1="-3.999"
              y1=".503"
              x2="-.497"
              y2="4.005"
            />
            <linearGradient
              xlink:href="#b"
              id="d"
              gradientUnits="userSpaceOnUse"
              x1="1.906"
              y1="1.889"
              x2="15.117"
              y2="15.107"
            />
          </defs>
          <g class="brackets">
            <g class="bracket-right">
              <path
                style="
                  fill: url(#c);
                  fill-rule: evenodd;
                  stroke-width: 0.264583;
                "
                transform="rotate(90 0 41.401) scale(3.77953)"
                d="M-3.5 0h3a.499.499 0 1 1 0 1h-3a.499.499 0 1 1 0-1Z"
              />
              <path
                style="
                  fill: url(#d);
                  fill-opacity: 1;
                  fill-rule: evenodd;
                  stroke-width: 0.999999;
                "
                d="M1.89 0C.845 0 .002.845 0 1.89v3.78a1.89 1.89 0 0 1 1.885-1.89h11.344a1.884 1.884 0 0 0 1.888-1.89C15.117.845 14.275 0 13.23 0Zm1.89 5.67a1.89 1.89 0 0 1-.009.17h.008z"
                transform="rotate(179.997 20.7 20.7)"
              />
            </g>
            <g class="bracket-left">
              <path
                style="
                  fill: url(#e);
                  fill-rule: evenodd;
                  stroke-width: 0.264583;
                "
                transform="rotate(-90 22.599 0) scale(3.77953)"
                d="M-3.5 0h3a.499.499 0 1 1 0 1h-3a.499.499 0 1 1 0-1Z"
              />
              <path
                style="
                  fill: url(#f);
                  fill-opacity: 1;
                  fill-rule: evenodd;
                  stroke-width: 0.999999;
                "
                d="M1.89 0C.845 0 .002.845 0 1.89v3.78a1.89 1.89 0 0 1 1.885-1.89h11.344a1.884 1.884 0 0 0 1.888-1.89C15.117.845 14.275 0 13.23 0Zm1.89 5.67a1.89 1.89 0 0 1-.009.17h.008z"
                transform="matrix(1 0 0 1 22.599 22.598)"
              />
            </g>
          </g>
        </svg>
      </body>
    </html>

    【讨论】:

      【解决方案2】:

      我会采取一种非常不同的方法。我会使用stroke-linecap="round"

      来代替填充路径

      在下一个示例中,笔触是黑色的,但如果需要,您可以使用渐变。

      请注意,我更改了 viewBox 属性的前 2 个参数的值,因为我想将括号居中在 0,0 附近。这大大简化了代码。

      观察:我保持 svg 的大小和纵横比与您的代码相同,但我会将其更改为更小的画布。为了理解我的意思,我在 svg 画布上添加了银色背景。

      svg{background:silver}
      
      path{animation: a 1s forwards;}
      
      g{animation: b 1s 1s forwards;}
      
      
       @keyframes a{
            100% {
              transform: rotate(-45deg);
            }
          }
      
      
       @keyframes b{
            100% {
              transform: translate(20px,0px);
            }
          }
      <svg width="256" height="256" viewbox="-20 -20 100 100" fill="none" stroke="black" stroke-width="4" stroke-linecap="round">
      
        <path d="M-7.5,-7.5h11" />
        <path d="M-7.5,-7.5v11" />
      
        <g>
          <path d="M7.5,7.5h-11" />
          <path d="M7.5,7.5v-11" />
        </g>
      </svg>

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2020-05-18
        • 1970-01-01
        • 2014-03-23
        • 2017-02-16
        • 1970-01-01
        • 2011-09-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多