问题 缩放父元素时保留子元素的大小


我有一个XHTML页面,SVG嵌入其中 <svg> 元件。我需要实现扩展,但有一个内在的要求 <text> 元素不得扩展。一个明显的解决方案是

<svg ...>
  <!-- Root <g> to programmatically `setAttribute("transform", ...)` -->
  <g transform="scale(0.5)">
    <!-- Various inner elements here -->
    <!-- Here is a text element.
         Additional <g> is to apply text position which
         *must* depend on the scaling factor set above -->
    <g transform="translate(100 50)">
      <!-- Apply the opposite scaling factor.
           Must be done for every `<text>` element on each change of the scaling factor... -->
      <text x="0" y="0" transform="scale(2)">Hello, World!</text>
    </g>
  </g>
</svg>

有比这更好的解决方案吗?也许,有一种方法可以“重置”内部的结果缩放因子 <text> 元素?该代码必须适用于Firefox和Chrome。

UPD。还有一个选项可以将文本元素放在要缩放的元素之外,并手动控制文本元素的位置。它避免了因缩放而出现在文本上的视觉故障。目前我使用这种方法。


12545
2018-01-16 13:27


起源



答案:


transform="ref(svg)" 在...中定义 SVG Tiny 1.2。据我所知,除Opera(Presto)之外的任何浏览器都没有实现。

<svg xmlns="http://www.w3.org/2000/svg" font-size="24" text-rendering="geometricPrecision">
  <!-- Root <g> to programmatically `setAttribute("transform", ...)` -->
  <text x="0" y="1em" stroke="gray" fill="none">Hello, World!</text>
  <g transform="scale(0.5) rotate(25)">
    <!-- Various inner elements here -->
    <!-- Here is a text element.
         Additional <g> is to apply text position which
         *must* depend on the scaling factor set above -->
    <g transform="translate(100 50)">
      <!-- Apply the opposite scaling factor.
           Must be done for every `<text>` element on each change of the scaling factor... -->
      <text x="0" y="1em" transform="ref(svg)">Hello, World!</text>
    </g>
  </g>
</svg>

在上面的示例中,文本应出现在灰色轮廓所在的位置(在左上角)。不应对具有的元素应用旋转或缩放 transform="ref(svg)",为了转换的目的,它就好像它是root svg元素的直接子元素。


5
2018-01-17 12:22



感谢您提供有用的建议。但 ref(...) 确实在Firefox中不起作用。 - Eugene


答案:


transform="ref(svg)" 在...中定义 SVG Tiny 1.2。据我所知,除Opera(Presto)之外的任何浏览器都没有实现。

<svg xmlns="http://www.w3.org/2000/svg" font-size="24" text-rendering="geometricPrecision">
  <!-- Root <g> to programmatically `setAttribute("transform", ...)` -->
  <text x="0" y="1em" stroke="gray" fill="none">Hello, World!</text>
  <g transform="scale(0.5) rotate(25)">
    <!-- Various inner elements here -->
    <!-- Here is a text element.
         Additional <g> is to apply text position which
         *must* depend on the scaling factor set above -->
    <g transform="translate(100 50)">
      <!-- Apply the opposite scaling factor.
           Must be done for every `<text>` element on each change of the scaling factor... -->
      <text x="0" y="1em" transform="ref(svg)">Hello, World!</text>
    </g>
  </g>
</svg>

在上面的示例中,文本应出现在灰色轮廓所在的位置(在左上角)。不应对具有的元素应用旋转或缩放 transform="ref(svg)",为了转换的目的,它就好像它是root svg元素的直接子元素。


5
2018-01-17 12:22



感谢您提供有用的建议。但 ref(...) 确实在Firefox中不起作用。 - Eugene


如果(a)使用JavaScript并且(b)通过指定每个unscaling元素的位置是可接受的 transform="translate(…,…)" 无论是在元素本身还是在包装组中(如您所做),您可以使用我的未缩放代码:
http://phrogz.net/svg/libraries/SVGPanUnscale.js

演示: http://jsfiddle.net/uPSc4/

正如您在演示中所看到的,它会撤消除转换(包括缩放,旋转和倾斜)之外的所有转换,同时保持元素位于它们应该位于的位置。

另请参阅此演示,该演示允许您使用缩放和平移图形 SVGPan 同时保持某些标记元素未缩放:
http://phrogz.net/svg/scale-independent-elements.svg

这是您需要的所有代码:

// Copyright 2012  Gavin Kistner, !@phrogz.net
// License: http://phrogz.net/JS/_ReuseLicense.txt

// Removes all transforms applied above an element.
// Apply a translation to the element to have it remain at a local position
function unscale(el){
  var svg = el.ownerSVGElement;
  var xf = el.scaleIndependentXForm;
  if (!xf){
    // Keep a single transform matrix in the stack for fighting transformations
    // Be sure to apply this transform after existing transforms (translate)
    xf = el.scaleIndependentXForm = svg.createSVGTransform();
    el.transform.baseVal.appendItem(xf);
  }
  var m = svg.getTransformToElement(el.parentNode);
  m.e = m.f = 0; // Ignore (preserve) any translations done up to this point
  xf.setMatrix(m);
}

这是演示代码,以防JSFiddle关闭:

<svg xmlns="http://www.w3.org/2000/svg"
     xmlns:x="http://www.w3.org/1999/xlink"
     font-size="36">
  <g transform="matrix(1 0 0 1 0 0)">
    <g transform="translate(100 50)"><text x="0" y="1em">A!</text></g>
    <g transform="translate(200 150)"><text x="0" y="1em">B!</text></g>
    <g transform="translate(150 75)"><text x="0" y="1em">C!</text></g>
  </g>
  <script x:href="http://phrogz.net/svg/libraries/SVGPanUnscale.js"></script>
  <script>
    var root = document.querySelector('g'),
        text = document.querySelectorAll('text'),
        xf   = root.transform.baseVal.getItem(0);

    // Keep scaling, spinning, and sliding the outer graphic
    // but "unscale" each text element afterwards.    
    setInterval(function(){
      var m = xf.matrix.scale(0.99).translate(10,0).rotate(1);
      xf.setMatrix(m);
      [].forEach.call(text,unscale);
    },100);​
  </script>
</svg>​

4
2018-05-23 05:20



上面的最后一行代码与 for (var i=0;i<text.length;++i) unscale(text[i],i); - Phrogz


尝试这个

HTML

<svg>  
  <g transform="scale(0.5)">   
    <g transform="translate(100 50)">      
      <text x="0" y="0">Hello, World!</text>
    </g>
  </g>
</svg>

找到逆矩阵并仅添加所需的转换。

var svg = document.getElementsByTagName('svg')[0]; 
var text = document.querySelectorAll('text')[0];  
var matrix = svg.createSVGTransformFromMatrix(text.getCTM().inverse().translate(100,50));
text.transform.baseVal.initialize(matrix);

JsFiddle - http://jsfiddle.net/uPSc4/10/


1
2018-05-07 11:50