代码之家  ›  专栏  ›  技术社区  ›  Magnus

SVG视图框:精确的平移和缩放顺序

svg
  •  3
  • Magnus  · 技术社区  · 6 年前

    我正在努力理解 min-x min-y viewBox 作品,从技术角度(没有隐喻)。

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

    根据 SVG 1.1 specification :

    __viewbox_属性的值是四个数字的列表 ,和,用空格分隔和/或 一个逗号,指定用户空间中的矩形 映射到由给定元素建立的视区边界, 考虑到属性__PreserveAsElectratio__。

    还有:

    __viewbox_属性的效果是用户代理 自动为映射提供适当的转换矩阵 用户空间中指定的矩形到指定的 区域(通常是视区)。

    还有:

    (注意:在某些情况下,用户代理需要提供翻译 除尺度变换外的变换。例如,在 最外层的svg元素,如果 __viewbox_ 或者)

    因此,我的期望是定义一个视图框与:

    1. 弗斯特 缩放比例 视图框,因此它填充了视区(假定视区和视图框的纵横比相同)
    2. 然后 翻译 视图框,因此根据 明-X 敏Y ViewBox属性。

    如果我们看看萨拉的两个例子, starting here ,这似乎不是正在发生的事情。

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

    1. 可视框的放置依据 明-X / 敏Y 在视口中
    2. 视箱是 缩放的 与视区大小相同
    3. 视盒原点是 翻译 (已移动)以与视区原点重合

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

    1. 视箱是 按比例缩放 与视区大小相同
    2. 视盒原点是 翻译 (移动)以某种方式与视盒相反的方向 明-X 敏Y 指示。它与视区原点不一致-这与第一个示例不同

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

    最后,在Sara的示例中,我不理解为什么蓝色坐标系(用户坐标系)本身不移动到视区坐标系中的(100,100)或(-100,-100)。我以为ViewBox应该 翻译 规模 用户坐标系?


    编辑:

    根据 this SO answer , 明-X 敏Y 确实遵循了我的第一套步骤。根据 明-X 最小Y值 ,然后进行翻译,使其原点位于视区原点的顶部。然后(前后)缩放以填充视区。

    如果这是正确的,我很难理解为什么Sara例子中的蓝色用户坐标系并不总是以其原点位于视区原点的顶部而结束。毕竟,viewbox应该修改用户坐标系。

    3 回复  |  直到 6 年前
        1
  •  5
  •   Alexandr_TT    6 年前

    坐标原点的偏移 viewBox 在X轴上 ( min-x=70px )

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

    enter image description here

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

    发生这种情况时,位于 视窗 被捕获,然后带有捕获片段的Viewbox查看区域与固定用户视区反向对齐,原点(0,0)位于左上角。

    最后一次向左移动70px,重新计算图形的坐标。正式的结果是,在应用ViewBox时,在视区的固定查看区域中,SVG文档的片段已向左移动。

    enter image description here

    Live Demo

    观察框原点沿两个轴的偏移量

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

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

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

    enter image description here

    在将原点传输到视盒后,矩形 400 × 400 px 从原点(70.70)开始计算宽度和高度的SVG文档片段进入视图框。

    图像捕获发生。接下来,观察框的原点(70,70)与观察窗的原点(0,0)组合在一起。这些数字的坐标重新计算。

    enter image description here

    因此,红色矩形5和6完全可见。所有不属于这个地区的东西都被切断了。例如,彩色圆圈1、2和4的部分区域。

    Live Demo

    使用可视框缩放

    SVG文档片段的比例取决于纵横比: viewport 视窗

    如果 视口 / 视窗 = 1 ,则刻度为

    如果 视口 / 可视框 与之不同的是,比例会随着增加或减少的方向而变化。

    enter image description here

    规模的增加如何解释下面的数字

    一像素 视窗 延伸到两个像素 视口

    enter image description here

    Live Demo

    缩小SVG图像1:2

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

    viewport / viewBox = 1/2

    enter image description here

    这个 可视框 捕获矩形碎片 800 x 800 px 也就是说,SVG视区的整个范围 400 x 400 px 另外一个 400px 分别位于视区的右侧和底部。

    enter image description here

    这是两个像素的 视窗 被压缩为 视口 . 因此,SVG图像减少了一半。

    Live Demo

        2
  •  2
  •   Alexandr_TT    6 年前

    enter image description here

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

    2. 绿色矩形是 viewport 用户在其显示器上看到的。

    3. 黄色矩形是虚拟的 viewBox 用户查看的区域 视口 .

    视窗 可以沿无穷大的坐标轴移动 svg 画布为正方向 x-min> 0 ; y-min> 0 在负方向 -x-min (二) -y-min

    图像处理SVG

    • 接下来是SVG画布片段的捕获,位于 查看框。
    • 在下一步中,将对齐视图框的坐标系。 坐标系的原点 视口 . 以及 碎片被 视窗 图像传回 视口 .
    • 这里有一个谈判过程,可以选择:

      1. 如果 min-x = 0 min-y = 0 ,的宽度和高度 视口 s分别等于 可视框 s,则片段图像不会移动或缩放。
      2. 如果 视窗 向右移动- min-x> 0 ,图像向左移动。很明显,通过在 视口 然后将其与原点结合,从而将图像向左移动。
      3. 如果 视窗 移动到 视口 S - min-y> 0 ,图像将上升。

    在此基础上,有一些想法,你可以实现水平和垂直视差而不使用 CSS , JavaScript . 为此,只需移动 视窗 沿着SVG画布,如下图所示。单击 起点 按钮。

    <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>
        3
  •  1
  •   Codo    6 年前

    我总是混淆 视窗 视口 .所以我会尽量避免。我不完全理解您是想为浏览器还是SVG设置转换矩阵。所以我也会尽量避免。

    这个 视窗 属性向浏览器提供有关SVG图形的大小和坐标原点的信息。它定义了进入SVG的窗口。只有窗口中的部分可见。

    让我们来看一个例子:

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

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

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

    而且, 视窗 属性告诉浏览器SVG坐标系中的点(100,100)将是可见SVG图形窗口的左上角。所以浏览器会相应地翻译它。

    所有较小的 X Y SVG坐标系中的值将被剪裁,即不可见,因为它位于窗口外部和浏览器为SVG创建的空间之外。同样,SVG坐标300(100+200)右侧和坐标250(100+150)下方的所有内容都将在窗口外且不可见。