【问题标题】:Providing the x,y,width and height value, how do I get the svg transform matrix that scales from center提供 x,y,width 和 height 值,我如何获得从中心缩放的 svg 变换矩阵
【发布时间】:2019-06-12 04:13:31
【问题描述】:

我有一个使用 php 和 imagemagick 从 svg 生成 gif 文件的代码。 下面是示例 svg 代码。 假设将通过将缩放变换比例值从 0 到 1 补间来创建动画,我如何使用 svg 元素属性 x、y、width、height 获得将变换原点居中的变换矩阵?

注意:我使用 php 进行所有计算,并使用 Imagemagick 转换为光栅,我认为它不支持 css 转换原点样式。

目前,过渡从左侧开始。我想用矩阵来翻译它。

下面的链接是当前实现的示例 gif https://i.imgur.com/juMX3uD.gifv

转换后的 SVG

<svg xmlns="http://www.w3.org/2000/svg" class="layer" overflow="visible" 
stroke="none" stroke-width="0" preserveAspectRatio="none" 
id="layer_1547759965149_0506449632092969" width="135.24545454545" 
height="110.9375" x="86.896363636365" y="84.286250000001"><g 
    id="translateLayer" transform="matrix(1 0 0 1 0 0)"><g id="effectLayer" 
transform="rotate(44.596407613288 67.622727272727 55.46875)" 
fill="#FF4400"><svg viewBox="0 0 657.01 569" width="100%" height="100%" 
preserveAspectRatio="none" overflow="hidden"><g id="Layer_2" data- 
name="Layer 2"><g id="Layer_1-2" data-name="Layer 1"><polygon points="0 569 
328.49 0 657.01 569 0 569"/></g></g></svg></g></g></svg>

转变发生在这里

&lt;g id="translateLayer" transform="matrix(1 0 0 1 0 0)"&gt;&lt;/g&gt;

【问题讨论】:

  • 我认为应该有一些 transform-origin 属性。但是,要获得具有“内置”原点的变换矩阵,您通常平移(移动)系统以将预期的变换原点设置为 (0;0),执行所有其他变换并将其移回(负平移) .通过按变换顺序将所有矩阵相乘,将所有步骤合并为一个矩阵。 en.wikipedia.org/wiki/Matrix_multiplication
  • 您还可以将视口设置为在中心具有原点。 (我对 SVG 的了解不多,但我熟悉 VR 3D 开发。)
  • 我猜这是css属性。我已经说过光栅化库 imagemagick 目前不解释 css 值。看看包含的 GIF 链接。我希望缩放从 center 转换。这可以使用矩阵转换来实现,但我只是不知道如何计算它。如果可能,提供示例 php 或 js 代码
  • 我记得你实际上可以以某种方式将 SVG 的视口设置为负上/左。
  • @Quasimodo'sclone,查看 gif 以更好地理解。 transform="matrix(1 0 0 1 0 0)" 是动画发生的地方。刻度值随时间改变。可以使用平移矩阵值来实现中心原点。我的问题是如何得到它,因为矩阵不太好

标签: php svg imagemagick


【解决方案1】:

如果我理解正确,您只想通过设置 viewBox 来应用特定的转换而不更改 SVG 的用户坐标系,这样可以更容易。

原点是三角形的中心点。在这种情况下,这是图像的一半 width 和 2/3 height

那么,为什么不直接应用后续的变换,而不是在矩阵计算中苦苦挣扎呢?而rotation 函数甚至可以接受原始参数。

    var
      svg = document.getElementById('layer_1547759965149_0506449632092969'),
      sca = svg.getElementById('translateLayer'),
      rot = svg.getElementById('effectLayer'),
      deg = 0,

      cx = svg.getAttribute('width') / 2,
      cy = svg.getAttribute('height') * 2/3
    ;

    function rotate()
    {
      deg++;
      let scale = 1 + Math.sin(deg/180*Math.PI);
      rot.setAttribute('transform',  (()=>`rotate(${deg} ${cx} ${cy})`)());
      sca.setAttribute('transform',  (()=>`translate(${cx} ${cy}) scale(${scale} ${scale}) translate(-${cx} -${cy})`)());
    }
    setInterval(rotate, 50);
    <svg xmlns="http://www.w3.org/2000/svg" class="layer" id="layer_1547759965149_0506449632092969"
         overflow="visible"
         stroke="none" stroke-width="0" preserveAspectRatio="none"
         width="135.24545454545" height="110.9375"
         x="86.896363636365" y="84.286250000001">
      <!--<g id="translateLayer" transform="matrix(0 67.622727272725 0  0 73.95833333333333   0)">-->
      <g id="translateLayer" transform="matrix(2 0 0 2 0.5 0.5)" transform-origin(200,100)>
        <g id="effectLayer"
           fill="#FF4400">
          <svg viewBox="0 0 657.01 569" width="100%" height="100%"
               preserveAspectRatio="none" overflow="hidden">
            <g id="Layer_2" data-name="Layer 2">
              <g id="Layer_1-2" data-name="Layer 1">
                <polygon points="0 569  328.49 0   657.01 569   0 569"/>
              </g>
            </g>
          </svg>
        </g>
      </g>
    </svg>

【讨论】:

    【解决方案2】:

    在与代码斗争了几个小时后,我得到了我正在寻找的解决方案。

    下面是我实现的最终矩阵计算

    x = (x/2);
    y = (y/2);
    matrix(scaleX 0 0 scaleY (x-scaleX*x) (y-scaleY*y));
    

    https://i.imgur.com/qAaZ1Tl.gifv

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2013-02-14
      • 1970-01-01
      • 2012-08-28
      • 2011-05-20
      相关资源
      最近更新 更多