使用打字稿解析SVG变换属性 [英] Parse SVG transform attribute with typescript

查看:76
本文介绍了使用打字稿解析SVG变换属性的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

如何使用Typescript解析svg元素的transform属性?

How do I parse the transform attribute of svg elements using typescript?

也就是说,如何解析svg.g字符串中的所有数字和运算在以下内容中进行转换:

That is, how can I parse all the numbers and operations in the string at svg.g.transform in the following:

<svg viewBox="-40 0 150 100" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
  <g fill="grey"
     transform="rotate(-10 50 100)
                translate(-36 45.5)
                skewX(40)
                scale(1 0.5)">
    <path id="heart" d="M 10,30 A 20,20 0,0,1 50,30 A 20,20 0,0,1 90,30 Q 90,60 50,90 Q 10,60 10,30 z" />
  </g>

  <use xlink:href="#heart" fill="none" stroke="red"/>
</svg>


推荐答案

使用 https://developer.mozilla.org/en-US/docs/Web/API/SVGGraphicsElement 又名由本地DOM元素实现的 SVGLocatable SVGTransformable 接口/ API。

Use the https://developer.mozilla.org/en-US/docs/Web/API/SVGGraphicsElement aka. SVGLocatable and SVGTransformable interfaces/API that is implemented by the native DOM elements.

这些元素具有对应于transform属性的 .transform 属性。此属性的类型为 https://developer.mozilla.org/en -US / docs / Web / API / SVGAnimatedTransformList ,并且您要查看静态定义的baseVal。

These elements have a .transform property that corresponds to the transform attribute. This property has the type https://developer.mozilla.org/en-US/docs/Web/API/SVGAnimatedTransformList and you want to look at the statically defined baseVal.

转换列表的属性为 numberOfItems getItem 方法。它可能具有 .length 属性和 [] 数组访问器,并且在浏览器中可能是可迭代的,但是不要

The transform list has an attribute numberOfItems and a getItem method. It may have a .lengthproperty and [] array accessor and it may be iterable in your browser, but don't count on that.

每个项目的类型均为 https://developer.mozilla.org/zh-CN/docs/Web/API/SVGTransform

The .type 属性告诉您使用了哪一条指令。

The .type property tells you which instruction was used.

因此,这里是您解析然后手动合成的方法再次变换属性:

Therefore, here is how you can parse and then manually synthesize the transform attribute again:

// javascript js equivalent declaration:
// function getAttributeTransform_js(nativeSVGElement) {
// typescript ts declaration
function getAttributeTransform_ts(nativeSVGElement: SVGGraphicsElement) {
  // this definition works in ts and js
  const tl = nativeSVGElement.transform.baseVal;
  const st = [];
  for (let i = 0; i < tl.numberOfItems; i++) {
    const t/*: SVGTransform*/ = tl.getItem(i);
    switch (t.type) {
      case SVGTransform.SVG_TRANSFORM_UNKNOWN: break;
      case SVGTransform.SVG_TRANSFORM_MATRIX: {
        // A matrix(…) transformation
        // Note: this is the most general transformation, capable of representing more transformations than the other combined.
        // For SVG_TRANSFORM_MATRIX, the matrix contains the a, b, c, d, e, f values supplied by the user.
        //
        // Note: instead of comma (,), whitespace separation would also be allowed
        st.push(`matrix(${t.matrix.a}, ${t.matrix.b}, ${t.matrix.c}, ${t.matrix.d}, ${t.matrix.e}, ${t.matrix.f})`);
        break;
      }
      case SVGTransform.SVG_TRANSFORM_TRANSLATE: {
        // A translate(…) transformation
        // For SVG_TRANSFORM_TRANSLATE, e and f represent the translation amounts (a=1, b=0, c=0 and d=1).
        st.push(`translate(${t.matrix.e}, ${t.matrix.f})`);
        break;
      }
      case SVGTransform.SVG_TRANSFORM_SCALE: {
        // A scale(…) transformation
        // For SVG_TRANSFORM_SCALE, a and d represent the scale amounts (b=0, c=0, e=0 and f=0).
        st.push(`scale(${t.matrix.a}, ${t.matrix.d})`);
        break;
      }
      case SVGTransform.SVG_TRANSFORM_ROTATE: {
        // A rotate(…) transformation
        // For SVG_TRANSFORM_ROTATE, a, b, c, d, e and f together represent the matrix which will result in the given rotation.
        // When the rotation is around the center point (0, 0), e and f will be zero.
        /*
        angle   float   A convenience attribute for SVG_TRANSFORM_ROTATE, SVG_TRANSFORM_SKEWX and SVG_TRANSFORM_SKEWY. It holds the angle that was specified.

        For SVG_TRANSFORM_MATRIX, SVG_TRANSFORM_TRANSLATE and SVG_TRANSFORM_SCALE, angle will be zero.
        */
        /*
        This is the hardest case since the origin information is lost!
        We need to recompute it from the matrix.
        from https://math.stackexchange.com/questions/2093314/rotation-matrix-of-rotation-around-a-point-other-than-the-origin

        matrix.a = cos_angle = c;
        matrix.b = sin_angle = s;
        Note that by the laws of geometry: c^2+s^2 = 1 (c and s are coordinates on the unit circle)
        matrix.e = -x*c + y*s + x;
        matrix.f = -x*s - y*c + y;

        Using Mathematica/Wolfram Language:
        "Assuming[c^2+s^2==1,Solve[e == -x*c + y*s + x&& f == -x*s - y*c + y,{x,y},Reals]//Simplify]//InputForm"
        (you can use WL for free here: https://develop.wolframcloud.com/objects/c26e16f7-44e7-4bb6-81b3-bc07782f9cc5)
        {{x -> (e + (f*s)/(-1 + c))/2, y -> (f - c*f + e*s)/(2 - 2*c)}}
        */
        const e = t.matrix.e, f = t.matrix.f, c = t.matrix.a, s = t.matrix.b;
        const originx = (e + (f*s)/(-1 + c))/2;
        const originy = (f - c*f + e*s)/(2 - 2*c);
        st.push(`rotate(${t.angle}, ${originx}, ${originy})`);
        break;
      }
      case SVGTransform.SVG_TRANSFORM_SKEWX: {
        // A skewx(…) transformation
        // For SVG_TRANSFORM_SKEWX and SVG_TRANSFORM_SKEWY, a, b, c and d represent the matrix which will result in the given skew (e=0 and f=0).
        /*
        angle   float   A convenience attribute for SVG_TRANSFORM_ROTATE, SVG_TRANSFORM_SKEWX and SVG_TRANSFORM_SKEWY. It holds the angle that was specified.

        For SVG_TRANSFORM_MATRIX, SVG_TRANSFORM_TRANSLATE and SVG_TRANSFORM_SCALE, angle will be zero.
        */
        st.push(`skewx(${t.angle})`);
        break;
      }
      case SVGTransform.SVG_TRANSFORM_SKEWY: {
        // A skewy(…) transformation
        // For SVG_TRANSFORM_SKEWX and SVG_TRANSFORM_SKEWY, a, b, c and d represent the matrix which will result in the given skew (e=0 and f=0).
        /*
        angle   float   A convenience attribute for SVG_TRANSFORM_ROTATE, SVG_TRANSFORM_SKEWX and SVG_TRANSFORM_SKEWY. It holds the angle that was specified.

        For SVG_TRANSFORM_MATRIX, SVG_TRANSFORM_TRANSLATE and SVG_TRANSFORM_SCALE, angle will be zero.
        */
        st.push(`skewy(${t.angle})`);
        break;
      }
    }
  }
  return st.join(','); // instead of comma (,), whitespace separation is also allowed
}



// example
const r = <SVGRectElement>document.createElementNS("http://www.w3.org/2000/svg", "rect");

// the parseable syntax for the transform attribute is pretty relaxed
r.setAttribute("transform", "translate(1, 0),rotate(0.5),   scale(1 2)");

// note that the browser may canonicalize your syntax
// EDGE canonicalizes the transform to read:
// 'translate(1) rotate(0.5) scale(1, 2)'
console.log(r.getAttribute("transform"));

// basically equivalent:
console.log(getAttributeTransform_ts(r));

您的示例:

function createElementFromHTML(htmlString) {
  var div = document.createElement('div');
  div.innerHTML = htmlString.trim();

  // Change this to div.childNodes to support multiple top-level nodes
  return div.firstChild; 
}

getAttributeTransform_ts(createElementFromHTML(`
<g fill="grey"
     transform="rotate(-10 50 100)
                translate(-36 45.5)
                skewX(40)
                scale(1 0.5)">
    <path id="heart" d="M 10,30 A 20,20 0,0,1 50,30 A 20,20 0,0,1 90,30 Q 90,60 50,90 Q 10,60 10,30 z" />
  </g>
`))

// gives
// 'rotate(-10, 49.99999999999982, 99.99999999999972),translate(-36, 45.5),skewx(40),scale(1, 0.5)'

请注意,您应该使用 .getAttribute( transform),让浏览器为您合成SVGTransformList的字符串形式,而不是使用上面的脚本!

Note that you should use .getAttribute("transform") to let the browser synthesize the string form of an SVGTransformList for you, instead of using my script above!

请注意,我们无法检索旋转,因为它没有API。

Note that we cannot retrieve the origin argument of "rotate" perfectly, because there is no API for it. It has to be computed from the 2d-homogeneous (rotation) matrix.

灵感来自于:

  • Parse SVG transform attribute with javascript
  • https://stackoverflow.com/a/41102221/524504

另请参见:

  • https://developer.mozilla.org/en-US/docs/Web/SVG/Attribute/transform

这篇关于使用打字稿解析SVG变换属性的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆