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

时间:2018-12-02 16:37:43

标签: svg

从技术的角度(没有隐喻),我正在努力确切地了解min-x上的min-yviewBox的工作原理。

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

根据SVG 1.1 specification

  

“ viewBox”属性的值是四个数字的列表   ,,和,由空格和/或分隔   一个逗号,在用户空间中指定一个矩形,该矩形应为   映射到由给定元素建立的视口的边界,   考虑属性“ preserveAspectRatio”。

并且:

  

“ viewBox”属性的作用是用户代理   自动提供适当的变换矩阵以进行映射   用户空间中指定矩形的边界   地区(通常是视口)。

并且:

  

(注意:在某些情况下,用户代理将需要提供翻译   规模转换之外的其他转换。例如,在   最外层的svg元素,如果需要,则需要转换转换   “ viewBox”属性指定的值不为零   或。)

所以,我的期望是定义一个viewBox与以下内容相同:

  1. 首先缩放视图框,以使其填充视口(假设视口和viewBox的宽高比相同)
  2. 然后翻译视图框,以便根据min-xmin-y viewBox属性将其放置在视口中。

如果我们看一下萨拉的两个例子,starting here,那似乎就没有发生。

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

  1. viewBox根据min-x / min-y放置在视口中
  2. viewBox已缩放,使其大小与视口相同
  3. viewBox原点已进行翻译(已移动)以与视口原点一致

然而,在她的第二个示例(<svg width="800" height="600" viewbox="-100 -100 400 300">...</svg>)中,顺序似乎完全不同:

  1. viewBox已缩放,使其大小与视口相同
  2. viewBox的原点已以某种方式翻译(移动),与viewBox min-x min-y所指示的方向相反。它与视口原点不一致-这与第一个示例不同

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

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


编辑:

根据this SO answermin-xmin-y确实遵循了我的第一组步骤。 viewBox原点根据min-xmin-y放置在视口中,然后进行翻译,以使其原点位于视口原点之上。然后(在此之前或之后)缩放以填充视口。

如果这是正确的话,我很难理解为什么Sara的示例中的蓝色用户坐标系并不总是以视口原点为起点。毕竟,viewBox应该修改用户坐标系。

3 个答案:

答案 0 :(得分:5)

x轴上坐标viewBox的原点的偏移量min-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

viewBox的原点沿两个轴的偏移量

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

缩小svg图片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

答案 1 :(得分:2)

enter image description here

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

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

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

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

图像处理svg

  • 接下来是捕获位于下面的SVG画布片段 viewBox。
  • 在下一步中,将viewBox的坐标系对齐 viewport坐标系的原点。和 viewBox图像捕获的片段被传回给 viewport
  • 有一个协商过程,可以在这里进行选择:

    1. 如果min-x = 0min-y = 0,则viewport的宽度和高度分别等于viewBox s的宽度和高度,则片段图像不会移动或缩放。
    2. 如果viewBox向右移动-min-x> 0,则图像向左移动。显然,通过捕获viewport右侧的图像,然后将其与原点组合,可以将图像向左移动。
    3. 如果将viewBox移到viewport s-min-y> 0以下,图像将上升。

基于此,有种想法,您可以在不使用CSSJavaScript的情况下实现水平和垂直视差。为此,只需沿SVG画布移动viewBox,如下图所示。点击开始按钮。

<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>

答案 2 :(得分:1)

我总是混淆 viewBox viewport 。因此,我将尽量避免这种情况。我不完全了解您是否要为浏览器或SVG设置转换矩阵。因此,我也会尽量避免这种情况。

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

所以让我们看一个例子:

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

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

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

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

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