首页 文章

SVG viewBox:翻译和缩放的准确顺序

提问于
浏览
3

我正在努力从技术的角度(没有隐喻)准确理解 min-xmin-yviewBox 上是如何工作的 .

我花了很多时间在两个有用的资源上:

根据SVG 1.1 specification

'viewBox'属性的值是一个由四个数字组成的列表,并用空格和/或逗号分隔,它们在用户空间中指定一个矩形,该矩形应该映射到由给定元素 Build 的视口的边界,考虑属性'preserveAspectRatio' .

和:

'viewBox'属性的作用是用户代理自动提供适当的变换矩阵,以将用户空间中的指定矩形映射到指定区域(通常是视口)的边界 .

和:

(注意:在某些情况下,除了缩放转换之外,用户代理还需要提供转换转换 . 例如,在最外层的svg元素上,如果'viewBox'属性指定的值不是零,则需要转换转换为或 . )

所以,我的期望是定义一个viewBox与:

  • 首先 scaling 视图框,因此它填充视口(假设视口和viewBox具有相同的宽高比)

  • 然后 translating viewBox,因此它根据 min-xmin-y viewBox属性放置在视口中 .

如果我们看看Sara的两个例子,那不是正在发生的事情 .

在她的第一个例子( <svg width="800" height="600" viewbox="100 100 200 150">...</svg> )中,它看起来像:

  • viewBox根据视口中的 min-x / min-y 放置

  • viewBox与视口大小相同 scaled

  • viewBox原点是 translated (已移动)以与视口原点重合

然而,在她的第二个例子中( <svg width="800" height="600" viewbox="-100 -100 400 300">...</svg> ),它看起来像一个完全不同的顺序:

  • viewBox的大小与视口大小相同 scaled

  • viewBox原点是 translated (移动)以某种方式与viewBox min-x min-y 指示的方向相反 . 它与视口原点不一致 - 这与第一个示例不同

因此,我认识到我并不完全理解它,因为从技术上讲,它在两种情况下应该以相同的方式工作 .

最后,在Sara的例子中,我不明白为什么蓝色坐标系(用户坐标系)本身不会在视口坐标系中移动到(100,100)或(-100,-100) . 我认为viewBox应该翻译和缩放用户坐标系?


EDIT:

根据this SO answermin-xmin-y 确实遵循我的第一组步骤 . viewBox原点根据 min-xmin-y 放置在视口中,然后进行转换,使其原点位于视口原点的顶部 . 然后(缩放之前或之后)填充视口 .

如果这是正确的,我很难理解为什么Sara示例中的蓝色用户坐标系最终不会以其原点位于视口原点之上 . 毕竟,viewBox应该修改用户坐标系 .

3 回答

  • 1

    enter image description here

    • 在图片中,灰色矩形是无限 SVG canvas .

    • 绿色矩形是用户在其显示屏上看到的 viewport .

    • 黄色矩形是虚拟 viewBox 区域,用户通过该区域查看 viewport .

    viewBox 可沿无限 svg 画布的坐标轴移动,如正方向 x-min> 0 ; y-min> 0 并在负方向 -x-min ; -y-min

    Image processing svg

    • 接下来是捕获位于viewBox下面的SVG画布片段 .

    • 在下一步中,viewBox的坐标系与 viewport 坐标系的原点对齐 . 并且 viewBox 图像捕获的片段将传回 viewport .

    • 这里有一个谈判过程和选项:

    • 如果 min-x = 0min-y = 0viewport 的宽度和高度分别等于 viewBox 的宽度和高度,则片段图像不会移动或缩放 .

    • 如果 viewBox 向右移动 - min-x> 0 ,则图像向左移动 . 很明显,通过捕获 viewport 右侧的图像然后将其与原点组合,我们从而将图像向左移动 .

    • 如果 viewBox 移动到 viewport s - min-y> 0 以下,图像将会上升 .

    基于此,有人认为您可以在不使用 CSSJavaScript 的情况下实现水平和垂直视差 . 要执行此操作,只需沿SVG画布移动 viewBox ,如下图所示 . 单击 Start 按钮 .

    <svg version="1.1"   xmlns="http://www.w3.org/2000/svg"
     xmlns:xlink="http://www.w3.org/1999/xlink"
       width="600" height="360" viewBox="0 0 600 360"   >
      <title> Explanation horizontal of parallax viewBox </title>
      <desc> animate the horizontal parallax  by modifying a coordinate of the viewBox </desc>
     <defs>
    <g id="canvas-svg" stroke-width="2px">	
      <g id="canvas-frame1">
       <rect id="v-port1" x="25" y="200" width="110" height="110" stroke="skyblue"   fill="yellowgreen" /> 
    	<text id="t-port1" x="75" y="255" style="font-size: 16pt;">1 </text>
    	<text  x="26" y="303" > 0 </text>
     </g>		    
      <g id="canvas-frame2">		
    		<rect id="v-port2" x="135" y="200" width="110" height="110" stroke="skyblue"  fill="dodgerblue" /> 
    		<text id="t-port2" x="185" y="255" style="font-size: 16pt;">2 </text>
    		<text  x="136" y="303" > 1168 </text>
     </g>		  
      <g id="canvas-frame3">		
    		<rect id="v-port3" x="245" y="200" width="110" height="110" stroke="skyblue"  fill="crimson"  /> 
    		<text id="t-port3" x="295" y="255" style="font-size: 16pt;">3 </text>
    		<text  x="246" y="303" > 2336 </text>
      </g>
          <g id="canvas-frame4">		
    		<rect id="v-port4" x="355" y="200" width="110" height="110" stroke="skyblue"  fill="orange" /> 
    		<text id="t-port4" x="405" y="255" style="font-size: 16pt;">4 </text>
    		<text  x="356" y="303" > 3504 </text>
         </g>
           <g id="canvas-frame5">		
    		<rect id="v-port5" x="465" y="200" width="110" height="110" stroke="skyblue" stroke-width="1px" fill="yellow" /> 
    		<text id="t-port5" x="515" y="255" style="font-size: 16pt;">5 </text>
    		<text  x="466" y="303" > 4672 </text>
           </g>   
     </g>
    	
     </defs>
     
      <g id="first-rect">
       <rect  x="25" y="25" width="110" height="110" stroke="skyblue" stroke-width="1px" fill="yellowgreen" /> 
    	<text  x="75" y="85" style="font-size: 16pt;">1 </text>
    	<text  x="26" y="135" > 0 </text>
     </g>		    
    
    
      <desc>The SVG canvas is infinite in size. In our example, user a viewport of SVG is in the leftmost position.</desc>  
    <use xlink:href ="#canvas-svg" x="0" y="0"> </use>
      	
    <desc> viewBox is moved along canvas SVG</desc>
     <g id="viewBox1">
     <rect id="v-box" x="25" y="200" width="110" height="110" stroke="skyblue" stroke-width="5px" fill="none" />
    	 <text id="t-port1" x="45" y="225" style="font-size: 16pt; fill:blue;">viewBox </text>   
    	<animateTransform attributeName="transform" type="translate" begin="startButton.click+0.5s" end="stopButton.click" dur="20s" from="0 0" to="440 0" repeatCount="indefinite" restart="whenNotActive" fill="freeze"/>
     </g>	
     
    
    <desc> The image moves to the left viewport</desc>
    <use xlink:href ="#canvas-svg" x="0" y="0">
        <animateTransform attributeName="transform" type="translate" begin="startButton.click+0.5s" end="stopButton.click" dur="20s" from="0 -170" to="-440 -170" repeatCount="indefinite" restart="whenNotActive" fill="freeze" />
      </use>
    
    <desc> Grey background image of the canvas SVG</desc>
     <g fill="#E5E5E5" stroke="#E5E5E5">
     <rect  x="135" y="0" width="465" height="195"    />   
      <rect  x="0" y="0" width="25" height="195"    />   
      <rect  x="0" y="0" width="135" height="30"    />   
      <rect  x="25" y="135" width="135" height="60" />   
      <rect  x="0" y="315" width="600" height="85"  />   
      <rect  x="0" y="195" width="25" height="120"  />
      <rect  x="575" y="195" width="25" height="120" />
     </g> 
      
      <g stroke-width="1px" stroke-dasharray = "5 5"> 
      	<line x1="25" y1="140" x2="25" y2="195" stroke="blue"  />
     <line x1="135" y1="140" x2="135" y2="195" stroke="blue" stroke-width="1px"  />
      </g>		
       <g style="font-size: 16pt; fill:blue;">
    	<text  x="45" y="170"  > viewport </text> 
    	 <text  x="15" y="20" style="font-size: 14pt;"> display the user's  </text>
    	    <text  x="230" y="90" style="font-size: 40pt; fill:#1E90FF"> canvas SVG </text> 
       </g> 
    
    <g id="startButton">
    	<rect  x="520" y="325" rx="8" ry="8" width="60" height="20" fill="#58AE2A" />
    	<text  x="550" y="340" font-size="16" font-weight="bold" font-family="Arial" text-anchor="middle" 
    	fill="white" >Start</text>
    </g>
            <g id="stopButton">
    			<rect  x="450" y="325" rx="8" ry="8" width="60" height="20" fill="#1E90FF" />
    			<text  x="480" y="340" font-size="16" font-weight="bold" font-family="Arial" text-anchor="middle" 
    			fill="white" >Stop</text>
    		</g>	
    
    </svg>
    
  • 4

    The offset of the origin of the coordinates viewBox on the x-axismin-x=70px

    <svg width="400" height="400" viewBox="70px, 0, 400px, 400px">

    enter image description here

    在该图中,用户坐标的原点向右移动 70px ,从而移动整个矩形观察区域 viewBox (400 x 400px) 沿水平轴向右 .

    发生这种情况时,捕获 viewBox 下的SVG文档片段的图像,然后将捕获的片段的viewBox查看区域与固定用户视口区域对齐,左上角的原点(0,0) .

    重新计算图形的坐标,向左移动70px . 事实证明,在应用viewBox时,在视口的固定查看区域中,SVG文档的片段已向左移动 .

    enter image description here

    Live Demo

    The offset of the origin of the viewBox along two axes

    min-x=70px, min-y="70px"

    <svg width="400" height="400" viewBox="70px, 70px, 400px, 400px">

    为清楚起见,在图片底部添加另一个红色矩形 - 6

    enter image description here

    将原点传送到viewBox后,从原点(70.70)开始的宽度和高度计数的矩形 400 × 400 px SVG文档片段将进入viewBox .

    发生图像捕获 . 接下来,viewBox(70,70)的原点与视口(0,0)的原点组合在一起 . 重新计算数字的坐标 .

    enter image description here

    因此,红色矩形5和6变得完全可见 . 不属于这一领域的一切都被切断了 . 例如,彩色圆圈1,2和4的部分区域 .

    Live Demo

    使用viewBox缩放

    SVG文档片段的比例取决于宽高比: viewportviewBox

    如果 viewport / viewBox = 1 ,则比例为 1

    如果 viewport / viewBox 与1不同,则比例将在增加或减少的方向上改变 .

    enter image description here

    规模的增加如何解释下图

    一个像素 viewBox 拉伸到两个像素 viewport

    enter image description here

    Live Demo

    Zoom out svg image 1: 2

    <svg width="400" height="400" version="1.1" viewBox="0 0 800 800">

    viewport / viewBox = 1/2

    enter image description here

    viewBox 捕获一个矩形片段 800 x 800 px ,即SVG视口 400 x 400 px 的整个范围,以及视口右侧和底部的另一个 400px .

    enter image description here

    那是 viewBox 的两个像素被压缩成 viewport 的一个像素 . 因此SVG图像减少了一半 .

    Live Demo

  • 2

    我总是混淆viewBox和viewport . 所以,如果你想为浏览器或SVG设置转换矩阵,我就完全明白了 . 所以我也会尽量避免它 .

    viewBox属性向浏览器提供有关SVG图形的大小和坐标原点的信息 . 它定义了进入SVG的窗口 . 只能看到窗口中的部分 .

    那么让我们看一个例子:

    <svg width="800" height="600" viewbox="100 100 200 150">
    

    这告诉浏览器它应该在浏览器的坐标系中绘制尺寸为800px×600px的SVG图形 . 因此,在浏览器DOM中,SVG组件将具有该大小 .

    然后,viewbox属性告诉浏览器SVG图形的相关/可见部分大小为200pt×150pt(在SVG坐标系中) . 因此浏览器知道它需要应用400%的缩放比例来将SVG坐标转换为浏览器坐标 .

    此外,viewbox属性告诉浏览器SVG坐标系中的点(100,100)将是可见SVG图形窗口的左上角 . 因此浏览器会相应地进行翻译 .

    SVG坐标系中具有较小x和y值的所有内容都将被剪裁,即不可见,因为它在窗口之外以及浏览器为SVG创建的空间之外 . 类似地,SVG坐标300(100 200)右侧和坐标250(100 150)下方的所有内容都将位于窗口之外且不可见 .

相关问题