在全局/根坐标中确定SVG视口

Phr*_*ogz 6 javascript svg

SVG元素内部实际可见的内容取决于其宽高比,viewBox值和preserveAspectRatio值.

例如,具有相同viewBox值(下面的红色虚线)的相同SVG元素大小可以具有不同的视口(在下面显示为蓝色),具体取决于preserveAspectRatio:

            更改preserveAspectRatio设置和生成的视图框的图片示例

  • Chrome有一个viewport属性,但在我的使用中它始终是一个空的(所有0值)SVGRect.Firefox没有实现此属性.

  • svg.getBBox()方法返回的值,而viewBox不是实际的可见视口内容.

给定对SVG元素的引用,我如何最容易地确定可见内容(视口),用SVG根部的用户坐标表示(与坐标相同viewBox)?

Phr*_*ogz 5

这是适用于 Chrome、Safari 和 Firefox 的函数。请参阅此处的测试页面:

测试页面:http://phrogz.net/SVG/CalculateSVGViewport.html

// 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 style    = getComputedStyle(svg),
      owidth   = parseInt(style.width,10),
      oheight  = parseInt(style.height,10),
      aspect   = svg.preserveAspectRatio.baseVal,
      viewBox  = svg.viewBox.baseVal,
      width    = viewBox && viewBox.width  || owidth,
      height   = viewBox && viewBox.height || oheight,
      x        = viewBox ? viewBox.x : 0,
      y        = viewBox ? viewBox.y : 0;
  if (!width || !height || !owidth || !oheight) 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 = owidth / oheight;
    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};
  }
}
Run Code Online (Sandbox Code Playgroud)