【问题标题】:Parse SVG transform attribute with javascript使用 javascript 解析 SVG 变换属性
【发布时间】:2013-07-23 08:19:07
【问题描述】:

假设我们有一个 SVG 转换字符串:

transform = "translate(6,5),scale(3,3)";

是否有一个灵活的正则表达式函数可以用来将其解析为可用的东西?

【问题讨论】:

  • 你能证明你是否尝试过一些东西吗?
  • 我不能做正则表达式@icedwater-我正在寻求可以的人的帮助
  • 如果你知道你需要正则表达式,那么你就知道你需要解析什么......然后就是为正则表达式找到正确的语法。在这里,我会用谷歌搜索 JavaScript 正则表达式,然后从它开始。
  • 我的意思是,如果您知道要过滤掉什么,您可以尝试自己做 - 然后遇到麻烦并在这里询问。否则 slickusable 由您来定义,您也不需要...
  • @Yarin 请将接受的答案更改为 Paul 的答案。使用 DOM API 是此类操作的唯一可靠实现。

标签: javascript regex svg


【解决方案1】:
var transform = "translate(6,5),scale(3,3)";
var translate  = /translate\(\s*([^\s,)]+)[ ,]([^\s,)]+)/.exec(transform);
var translateX = translate[1]
var translateY = translate[2]
var scale  = /scale\(\s*([^\s,)]+)[ ,]([^\s,)]+)/.exec(transform);
var scaleX = translate[1]
var scaleY = translate[2]

transformValues = {translate:{x:translateX,y:translateY},
scale:{x:scaleX,y:scaleY}}

很恶心,但@icedwater 让我自己做所有的工作,所以......

【讨论】:

  • 好吧,你打败了我——你可以把它编辑成上面的问题。我还需要查找 JS 正则表达式,所以。
【解决方案2】:

我将对此进行尝试,并说您希望将其解析为 JSON 对象,其中包含每个属性作为列表中的条目。这是我迄今为止最接近的一次:

function listIntoJSON(theTransformInQuestion) {

    // let's work with transform = "translate(6,5),scale(3,3)" as specified.
    var result = [];  // empty list to be returned
    var splitList = theTransformInQuestion.split(/\W/);
    // now splitList is ["translate", "6", "5", "", "scale", "3", "3", ""]

    for (var t = 0; t < splitList.length; t += 4) {
        var op  = {};
        op.name = splitList[t];
        op.x    = splitList[t + 1];
        op.y    = splitList[t + 2];
        result.push(op);  // add op to the result list
    }
    return result;
}

这将采取

transform = "translate(6,5),scale(3,3)";

然后返回

[
    {name: "translate", x: "6", y: "5"}, 
    {name: "scale", x: "3", y: "3"}
]

并且应该适用于任意数量的转换。有点小技巧,但现在可以了。

【讨论】:

  • 花费的时间比我想象的要长,提醒我稍后再处理;)
  • 我有一些看起来不错的东西;当我学习如何将事物转储到对象而不是使用列表时,我可能会再次研究这个问题。随意改进它:)
  • 谢谢 - 不过还是要把它交给@chernjie,他的太漂亮了
  • 好点,@fabiopagoti。它也不适用于小数,我刚刚检查过。
【解决方案3】:

这是一个漂亮的小 sn-p 代码,可能会为您提供所需的内容,它应该涵盖大多数情况,以防您要解析的字符串具有不同数量的参数:

function parse (a)
{
    var b={};
    for (var i in a = a.match(/(\w+\((\-?\d+\.?\d*e?\-?\d*,?)+\))+/g))
    {
        var c = a[i].match(/[\w\.\-]+/g);
        b[c.shift()] = c;
    }
    return b;
}

运行这个

parse('translate(6,5),scale(3,3.5),a(1,1),b(2,23,-34),c(300)');

将导致:

{
    translate: [ '6', '5' ],
    scale: [ '3', '3.5' ],
    a: [ '1', '1' ],
    b: [ '2', '23', '-34' ],
    c: [ '300' ]
}

【讨论】:

  • 优雅?噗。我查看了正则表达式并立即意识到它不会捕获比例(.5)
  • 这种获取小数的方法是\d*\.?\d+ 看起来很奇怪,但是小数点之前的可以没有数字,小数点之后的必须有他们。但是,在 3435 的情况下,捕获该数字的是第二部分。在 .3535 的情况下,它仍然是捕获数字的第二部分。
  • 您可以查看完全充实的浮点正则表达式,因为这就是那里发生的事情:[-+]?[0-9]*\.?[0-9]+([eE][ -+]?[0-9]+)? -- 从这里我们看到你也不会捕捉到 scale(+2) 。或缩放(1e+2)
  • 例如也可以有多个翻译
  • 这不应该是公认的答案,这太脆弱了。请使用 DOM API,请参阅 Paul 的回答。
【解决方案4】:

改编自@chernjie的解决方案:

function parse_transform(a) {
    var b = {};
    for (var i in a = a.match(/(\w+)\(([^,)]+),?([^)]+)?\)/gi)) {
        var c = a[i].match(/[\w\.\-]+/g);
        b[c.shift()] = c;
    }
    return b;
}

【讨论】:

  • 谢谢!在这里工作!
【解决方案5】:

假设您在浏览器中运行,您还可以使用 SVG DOM 来解析和解码转换字符串。

var svgns = "http://www.w3.org/2000/svg";

function getTransformList(transformStr)
{
  // Create a fake <rect> element to set the transform to
  var rect = document.createElementNS(svgns, "rect");
  rect.setAttribute("transform", transformStr);
  // Use the DOM to get the list of decoded transforms
  dumpTransform(rect.transform.baseVal);
}

function dumpTransform(transformList)
{
  for (var i = 0; i < transformList.numberOfItems; i++)
  {
    var transform = transformList.getItem(i);
    var m = transform.matrix;
    switch (transform.type)
    {
      case 2:
        console.log("translate("+m.e+","+m.f+")");
        break;
      case 3:
        console.log("scale("+m.a+","+m.d+")");
        break;
      case 4:
        console.log("rotate("+transform.angle+")");
        // TODO need to also handle rotate(angle, x, y) form
        break;
      case 5:
        // TODO skewX()
        break;
      case 6:
        // TODO skewY(()
        break;
      case 1:
      default:
        console.log("matrix("+m.a+","+m.b+","+m.c+","+m.d+","+m.e+","+m.f+")");
        break;
    }
  }
}

getTransformList("translate(6,5),scale(3,3)");

【讨论】:

  • 这应该是公认的答案。其他的都非常脆弱。
  • 我在这里创建了一个正确键入的解决方案版本stackoverflow.com/questions/57955159/…
  • 通过我的编辑,我制作了跨浏览器兼容的代码。它现在甚至可以在 IE10 中使用。我希望你没有反对它。
  • 谢谢大家 - 根据建议做出这个被接受的答案
【解决方案6】:

即使这是一个老问题,今天我也有同样的需求,最终得到了这个正则表达式:

const regex = /((\w+)\((,?\s*-?\d*\.?\d+(px|in|px|cm|mm|pt|pc|em|ex|ch|rem|deg|rad|grad|turn)?)+\)\s*)/gi;

相当长,但它也考虑了计量单位。

你可以在这里测试它:https://regex101.com/r/M8rRjo/1/

【讨论】:

    【解决方案7】:

    这不是正则表达式,但有一个类似的问题 (Replacing d3.transform in D3 v4) 有一个非常好的、全面的解决方案:

    function getTransformation(transform) {
      // Create a dummy g for calculation purposes only. This will never
      // be appended to the DOM and will be discarded once this function 
      // returns.
      var g = document.createElementNS("http://www.w3.org/2000/svg", "g");
      
      // Set the transform attribute to the provided string value.
      g.setAttributeNS(null, "transform", transform);
      
      // consolidate the SVGTransformList containing all transformations
      // to a single SVGTransform of type SVG_TRANSFORM_MATRIX and get
      // its SVGMatrix. 
      var matrix = g.transform.baseVal.consolidate().matrix;
      
      // Below calculations are taken and adapted from the private function
      // transform/decompose.js of D3's module d3-interpolate.
      var {a, b, c, d, e, f} = matrix;   // ES6, if this doesn't work, use below assignment
      // var a=matrix.a, b=matrix.b, c=matrix.c, d=matrix.d, e=matrix.e, f=matrix.f; // ES5
      var scaleX, scaleY, skewX;
      if (scaleX = Math.sqrt(a * a + b * b)) a /= scaleX, b /= scaleX;
      if (skewX = a * c + b * d) c -= a * skewX, d -= b * skewX;
      if (scaleY = Math.sqrt(c * c + d * d)) c /= scaleY, d /= scaleY, skewX /= scaleY;
      if (a * d < b * c) a = -a, b = -b, skewX = -skewX, scaleX = -scaleX;
      return {
        translateX: e,
        translateY: f,
        rotate: Math.atan2(b, a) * 180 / Math.PI,
        skewX: Math.atan(skewX) * 180 / Math.PI,
        scaleX: scaleX,
        scaleY: scaleY
      };
    }
    
    console.log(getTransformation("translate(20,30)"));  
    console.log(getTransformation("rotate(45) skewX(20) translate(20,30) translate(-5,40)"));

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2019-11-19
      • 1970-01-01
      • 1970-01-01
      • 2016-04-02
      • 2013-07-08
      • 2013-09-23
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多