理解 svg 的 viewBox 属性(一)
<style>.ma p, .ma pre, .ma svg { margin: 8px 0; }
.rred { color: red; }
.ma > pre { padding: 16px; background: #efefef; font: normal 16px monospace; white-space: pre-wrap; word-wrap: break-word; tab-size: 4; line-height:1.5em; }
.ma > svg { border: 1px solid gray; }
</style>
<div class="ma">
<p>我们在 <a href="https://www.huachaowang.com/forum.php?mod=viewthread&tid=72079">《初识 svg 的 viewBox 属性》</a> 中已经初步了解到 viewBox 属性能将svg画布内的图形进行zoom操作,即放大或缩小图形。本讲,我们将深入了解 viewBox 是什么、具体怎么工作。</p>
<p>svg画布的 width 和 height <span class="rred">属性</span> 定义了画布的大小,svg 也有自己缺省的 width 和 height 值,300*150。宽高尺寸构成了整个画布的可视区域,它是一个矩形,所有的绘画内容就在它上面绘制。以下代码,定义了 200*200 的画布,并在其上绘制一个矩形和一个圆,矩形从 {0,0} 坐标开始绘制,宽高均为 100,圆的圆心在 {10,10} 坐标处,半径为 10。</p>
<p>代码:</p>
<pre>
<svg width="200" height="200">
<rect x="0" y="0" width="100" height="100" fill="green" />
<circle cx="10" cy="10" r="10" fill="red" />
</svg>
</pre>
<p>效果(我们在CSS里统一定义了 svg 的灰色边框):</p>
<svg width="200" height="200">
<rect x="0" y="0" width="100" height="100" fill="green" />
<circle cx="10" cy="10" r="10" fill="red" />
</svg>
<p>灰色边框框定的矩形区域就是svg画布,它有一个术语叫 viewport,即<span class="rred">视口</span>。而我们已经知道名称的svg属性 viewBox 它叫<span class="rred">视区</span>,它用来定义svg画布的<span class="rred">用户空间</span>(user space),该空间即视区相当于望远镜,对着svg画布进行“遥摄”,以“观赏”一定区域的内容。viewBox 需要四个参数,min-x,min-y,width,height,各值用空格或小角逗号隔开:</p>
<pre>
viewBox="0 0 100 100" 或者 viewBox="0,0,100,100"
</pre>
<p>这是定义了视区区域为,从 {0,0} 坐标处开始,宽高为 100*100。viewBox 属性是可以缺省的,缺省时,它从 {0,0} 开始,取 svg 的宽高尺寸为 视区的 width 和 height 值,相当于望远镜所看到的的尺寸正好与svg画布尺寸相重合。viewBox 的宽高可以小于 svg 的宽高,试看代码:</p>
<pre>
<svg width="200" height="200" <span class="rred">viewBox="0 0 100 100"</span>>
<rect x="0" y="0" width="100" height="100" fill="green" />
<circle cx="10" cy="10" r="10" fill="red" />
</svg>
</pre>
<p>效果会怎么样?请看:</p>
<svg width="200" height="200" viewBox="0 0 100 100">
<rect x="0" y="0" width="100" height="100" fill="green" />
<circle cx="10" cy="10" r="10" fill="red" />
</svg>
<p>这个结果不好理解吧?事实上,viewBox 属性一直令人困惑!</p>
<p>作为视区(viewBox),它定义的是用户空间(user space),viewBox 属性实际上是将 svg 画布上画好的图案重新规划,<span class="rred">viewBox="0 0 100 100"</span> 表示,从 {0,0} 开始对画布内原始图案进行“遥摄”,取 svg 上的 100*100 的图案,映射到整个画布中(就是望远镜所看到的的区域)。为了证实这一点,我们先把 viewBox 属性拿掉,再添加一个蓝色的圆,其圆心就在矩形的右下角:</p>
<pre>
<svg width="200" height="200">
<rect x="0" y="0" width="100" height="100" fill="green" />
<circle cx="10" cy="10" r="10" fill="red" />
<circle cx="100" cy="100" r="10" fill="blue" />
</svg>
</pre>
<p>结果是酱紫:</p>
<svg width="200" height="200">
<rect x="0" y="0" width="100" height="100" fill="green" />
<circle cx="10" cy="10" r="10" fill="red" />
<circle cx="100" cy="100" r="10" fill="blue" />
</svg>
<p>现在,我们加上 viewBox 属性:</p>
<pre>
<svg width="200" height="200" <span class="rred">viewBox="0 0 100 100"</span>>
<rect x="0" y="0" width="100" height="100" fill="green" />
<circle cx="10" cy="10" r="10" fill="red" />
<circle cx="100" cy="100" r="10" fill="blue" />
</svg>
</pre>
<p>现在看看效果是不是正好是把上面的矩形区域放大了一倍:</p>
<svg width="200" height="200" viewBox="0 0 100 100">
<rect x="0" y="0" width="100" height="100" fill="green" />
<circle cx="10" cy="10" r="10" fill="red" />
<circle cx="100" cy="100" r="10" fill="blue" />
</svg>
<p>这里换个方式解释一下 viewBox 的工作机制:viewBox 属性,定义从 min-x、min-y 开始,在 svg 原始画布上取 viewBox 的 width 和 height 区域,将这个区域的内容重新映射到整个画布,从而全新改变了画布的样貌。</p>
<p>viewBox 的 width 和 height 还可以大于 svg 设定的 width 和 height,试看以下代码和效果:</p>
<pre>
<svg width="200" height="200" <span class="rred">viewBox="0 0 400 400"</span>>
<rect x="0" y="0" width="100" height="100" fill="green" />
<circle cx="10" cy="10" r="10" fill="red" />
<circle cx="100" cy="100" r="10" fill="blue" />
</svg>
</pre>
<svg width="200" height="200" viewBox="0 0 400 400">
<rect x="0" y="0" width="100" height="100" fill="green" />
<circle cx="10" cy="10" r="10" fill="red" />
<circle cx="100" cy="100" r="10" fill="blue" />
</svg>
<p>可以看到,矩形和圆都缩小了一半!这是因为,viewBox 从 {0,0} 处开始,取画布上的 400*400 的区域重新映射到画布上。画布实际尺寸只有 200*200 的尺寸,viewBox 多出的部分是画布以外的,是空白的,但不管怎样,就按这个 400*400 的尺寸完整映射到画布中,这个 400*400 的区域就按比例缩小自身,然后完整映射给 200*200 的画布。注意观察右下角的蓝色圆,因为它的整体在 400*400 区域内,所以圆是完整的,不像前例的圆四分之三不在 100*100 区域内从而被无情切走。</p>
<p>说明:上面所举示例,viewBox 的 宽高 和 svg 的宽高都是成比例的,若比例不同,情况会更为复杂,这里先不表。</p>
</div>
说到底就是放大或缩小再映射回画布吧。 只是这放大和缩小从数值上看正好是反的。 “宽高比例不同,情况会更为复杂。”比例不同缩放也不同? 俺不懂,飘过{:6_260:} 千羽 发表于 2023-10-28 20:48
俺不懂,飘过
谢飘 红影 发表于 2023-10-28 13:41
说到底就是放大或缩小再映射回画布吧。
具体工作原理看好了,应该说的很清楚了 红影 发表于 2023-10-28 13:48
只是这放大和缩小从数值上看正好是反的。
不能用常规的思路去理解它。总的来说,它截取 viewBox 设定的svg画布上的区域,再放回画布里 马黑黑 发表于 2023-10-28 21:07
具体工作原理看好了,应该说的很清楚了
嗯嗯,黑黑说得很清楚了,只是我理解上还有点迷糊{:4_173:} 马黑黑 发表于 2023-10-28 21:09
不能用常规的思路去理解它。总的来说,它截取 viewBox 设定的svg画布上的区域,再放回画布里
当截取的区域超过画布大小时,这个是虚拟中的区域吧?并不存在。 viewBox="0 0 100 100"
这个0 0 的位置可以设置别的参数么?
“viewBox 属性是可以缺省的,缺省时,它从 {0,0} 开始”
这句没看都,0 0也可以不写?如果不写,变成viewBox=" 100 100" ? 红影 发表于 2023-10-29 13:08
当截取的区域超过画布大小时,这个是虚拟中的区域吧?并不存在。
存在。你去多大就是多大,超出svg视口的部分是实际占位的空白 红影 发表于 2023-10-29 13:07
嗯嗯,黑黑说得很清楚了,只是我理解上还有点迷糊
正常的 马黑黑 发表于 2023-10-29 18:19
存在。你去多大就是多大,超出svg视口的部分是实际占位的空白
哦,原来是这样。也不对啊,要是我取得更大呢? 马黑黑 发表于 2023-10-29 18:19
正常的
这个需要转换脑筋去接受{:4_173:} 红影 发表于 2023-10-29 22:09
这个需要转换脑筋去接受
额,可能吧 红影 发表于 2023-10-29 22:08
哦,原来是这样。也不对啊,要是我取得更大呢?
多大都一样原理,就是把viewBox的选区按比例投影到画布中 马黑黑 发表于 2023-10-29 22:32
额,可能吧
抛开习惯性思维。 马黑黑 发表于 2023-10-29 22:33
多大都一样原理,就是把viewBox的选区按比例投影到画布中
嗯嗯,知道了{:4_204:} 红影 发表于 2023-10-29 23:44
嗯嗯,知道了
后面的viewBox内容会更复杂