【问题标题】:Maintain same font-size text regardless of viewBox zooming无论 viewBox 缩放如何,都保持相同的字体大小文本
【发布时间】:2014-05-14 03:30:03
【问题描述】:

我有an interactive SVG diagram,这与这个简单的演示几乎完全不同……

演示:http://jsfiddle.net/CphxH/6/

...除了它:

  • 有一堆<text>元素,
  • 动态调整viewBox,并
  • 无论 viewBox 有多大,我都希望屏幕上显示的文本的字体大小相同。

理想情况下,我想要vector-effect:non-scaling-stroke 的等价物(至少在Webkit 上),但对于font-size。这样的事情存在吗?如果没有,我最好的办法是计算 viewBox 的大小,将其与aspectRatio 结合以确定更大的轴,然后使用 JS 操作 font-size 属性的 CSS 规则?

【问题讨论】:

    标签: javascript css svg


    【解决方案1】:

    不,如果您更改 viewBox,没有任何自动方法可以保持文本大小不变。您必须按照您的想法使用 Javascript 调整文本大小。

    【讨论】:

      【解决方案2】:

      这是一个基于 JavaScript 的解决方案。您在开始时调用一次recordSVGFontSizes(),向其传递一个 SVG 元素和一个样式表。它calculates the viewport for the SVG,遍历样式表,找到所有提到font-size的规则并记录原始字体大小。

      然后,当您的 viewBox 发生变化时,将记录的值传递给 normalizeSVGFontSizes()。它将重新计算视口并适当地更新所有字体大小。

      请注意,由于视口计算目前不适用于 Firefox,因此该脚本不适用于那里。

      演示:http://jsfiddle.net/CphxH/8/

      // Do this once at startup
      var recording = recordSVGFontSizes( mySVG, document.styleSheets[0] );
      
      // Do this each time the viewport changes
      normalizeSVGFontSizes(recording);
      
      function recordSVGFontSizes(svgElement,styleSheet){
        var rules = [];
        var viewport = calculateViewport(svgElement);
        for (var i=styleSheet.cssRules.length;i--;){
          var rule = styleSheet.cssRules[i];
          if (rule.style.fontSize){
            var parts = rule.style.fontSize.split(/(\D+)/);
            rules.push({ rule:rule, units:parts[1], perpx:parts[0] / viewport.width });
          }
        }
        return {rules:rules, svg:svgElement};
      }
      
      function normalizeSVGFontSizes(fontSizeRecording){
        var viewport = calculateViewport(fontSizeRecording.svg);
        for (var i=fontSizeRecording.rules.length;i--;){
          var record = fontSizeRecording.rules[i];
          record.rule.style.fontSize = record.perpx*viewport.width + record.units;
        }
      }
      
      // Given an <svg> element, returns an object with the visible bounds
      // expressed in local viewBox units, e.g.
      // { x:-50, y:-50, width:100, height:100 }
      function calculateViewport(svg){ // http://phrogz.net/JS/_ReuseLicense.txt
        var outer    = svg.getBoundingClientRect();
        var aspect   = svg.preserveAspectRatio.baseVal,
            viewBox  = svg.viewBox.baseVal,
            width    = viewBox && viewBox.width  || outer.width,
            height   = viewBox && viewBox.height || outer.height,
            x        = viewBox ? viewBox.x : 0,
            y        = viewBox ? viewBox.y : 0;
        if (!width || !height || !outer.width) return;
        if (aspect.align==aspect.SVG_PRESERVEASPECTRATIO_NONE || !viewBox || !viewBox.height){
          return {x:x,y:y,width:width,height:height};
        }else{
          var inRatio  = viewBox.width / viewBox.height,
              outRatio = outer.width / outer.height;
          var meetFlag = aspect.meetOrSlice != aspect.SVG_MEETORSLICE_SLICE;
          var fillAxis = outRatio>inRatio ? (meetFlag?'y':'x') : (meetFlag?'x':'y');
          if (fillAxis=='x'){
            height = width/outRatio;
            var diff = viewBox.height - height;
            switch (aspect.align){
              case aspect.SVG_PRESERVEASPECTRATIO_UNKNOWN: 
              case aspect.SVG_PRESERVEASPECTRATIO_XMINYMID:
              case aspect.SVG_PRESERVEASPECTRATIO_XMIDYMID:
              case aspect.SVG_PRESERVEASPECTRATIO_XMAXYMID:
                y += diff/2;
              break;
              case aspect.SVG_PRESERVEASPECTRATIO_XMINYMAX:
              case aspect.SVG_PRESERVEASPECTRATIO_XMIDYMAX:
              case aspect.SVG_PRESERVEASPECTRATIO_XMAXYMAX:
                y += diff;
              break;
            }
          }
          else{
            width = height*outRatio;
            var diff = viewBox.width - width;
            switch (aspect.align){
              case aspect.SVG_PRESERVEASPECTRATIO_UNKNOWN: 
              case aspect.SVG_PRESERVEASPECTRATIO_XMIDYMIN:
              case aspect.SVG_PRESERVEASPECTRATIO_XMIDYMID:
              case aspect.SVG_PRESERVEASPECTRATIO_XMIDYMAX:
                x += diff/2;
              break;
              case aspect.SVG_PRESERVEASPECTRATIO_XMAXYMID:
              case aspect.SVG_PRESERVEASPECTRATIO_XMAXYMIN:
              case aspect.SVG_PRESERVEASPECTRATIO_XMAXYMAX:
                x += diff;
              break;
            }
          }
          return {x:x,y:y,width:width,height:height};
        }
      }
      

      【讨论】:

      • 上面的实现修改了样式表中的 CSS 规则,因此对于以其他方式设置样式的文本将失败,例如使用 font-size="…"style="font-size:…" 属性。一个更好的解决方案(最终即将出现)是将自定义 scale() 附加到每个 &lt;text&gt; 元素的转换上,并使用它来调整字体大小。
      猜你喜欢
      • 2014-08-19
      • 1970-01-01
      • 2016-03-06
      • 2021-12-03
      • 1970-01-01
      • 2018-11-12
      • 1970-01-01
      • 2018-12-08
      • 1970-01-01
      相关资源
      最近更新 更多