马黑黑 发表于 2023-10-28 12:23

理解 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>
&lt;svg width="200" height="200"&gt;
        &lt;rect x="0" y="0" width="100" height="100" fill="green" /&gt;
        &lt;circle cx="10" cy="10" r="10" fill="red" /&gt;
&lt;/svg&gt;
</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>
&lt;svg width="200" height="200" <span class="rred">viewBox="0 0 100 100"</span>&gt;
        &lt;rect x="0" y="0" width="100" height="100" fill="green" /&gt;
        &lt;circle cx="10" cy="10" r="10" fill="red" /&gt;
&lt;/svg&gt;
</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>
&lt;svg width="200" height="200"&gt;
        &lt;rect x="0" y="0" width="100" height="100" fill="green" /&gt;
        &lt;circle cx="10" cy="10" r="10" fill="red" /&gt;
        &lt;circle cx="100" cy="100" r="10" fill="blue" /&gt;
&lt;/svg&gt;
</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>
&lt;svg width="200" height="200" <span class="rred">viewBox="0 0 100 100"</span>&gt;
        &lt;rect x="0" y="0" width="100" height="100" fill="green" /&gt;
        &lt;circle cx="10" cy="10" r="10" fill="red" /&gt;
        &lt;circle cx="100" cy="100" r="10" fill="blue" /&gt;
&lt;/svg&gt;
</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>
&lt;svg width="200" height="200" <span class="rred">viewBox="0 0 400 400"</span>&gt;
        &lt;rect x="0" y="0" width="100" height="100" fill="green" /&gt;
        &lt;circle cx="10" cy="10" r="10" fill="red" /&gt;
        &lt;circle cx="100" cy="100" r="10" fill="blue" /&gt;
&lt;/svg&gt;
</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>

红影 发表于 2023-10-28 13:41

说到底就是放大或缩小再映射回画布吧。

红影 发表于 2023-10-28 13:48

只是这放大和缩小从数值上看正好是反的。

红影 发表于 2023-10-28 13:50

“宽高比例不同,情况会更为复杂。”比例不同缩放也不同?

千羽 发表于 2023-10-28 20:48

俺不懂,飘过{:6_260:}

马黑黑 发表于 2023-10-28 21:07

千羽 发表于 2023-10-28 20:48
俺不懂,飘过

谢飘

马黑黑 发表于 2023-10-28 21:07

红影 发表于 2023-10-28 13:41
说到底就是放大或缩小再映射回画布吧。
具体工作原理看好了,应该说的很清楚了

马黑黑 发表于 2023-10-28 21:09

红影 发表于 2023-10-28 13:48
只是这放大和缩小从数值上看正好是反的。

不能用常规的思路去理解它。总的来说,它截取 viewBox 设定的svg画布上的区域,再放回画布里

红影 发表于 2023-10-29 13:07

马黑黑 发表于 2023-10-28 21:07
具体工作原理看好了,应该说的很清楚了

嗯嗯,黑黑说得很清楚了,只是我理解上还有点迷糊{:4_173:}

红影 发表于 2023-10-29 13:08

马黑黑 发表于 2023-10-28 21:09
不能用常规的思路去理解它。总的来说,它截取 viewBox 设定的svg画布上的区域,再放回画布里

当截取的区域超过画布大小时,这个是虚拟中的区域吧?并不存在。

红影 发表于 2023-10-29 13:12

viewBox="0 0 100 100"
这个0 0 的位置可以设置别的参数么?

“viewBox 属性是可以缺省的,缺省时,它从 {0,0} 开始”
这句没看都,0 0也可以不写?如果不写,变成viewBox=" 100 100" ?

马黑黑 发表于 2023-10-29 18:19

红影 发表于 2023-10-29 13:08
当截取的区域超过画布大小时,这个是虚拟中的区域吧?并不存在。

存在。你去多大就是多大,超出svg视口的部分是实际占位的空白

马黑黑 发表于 2023-10-29 18:19

红影 发表于 2023-10-29 13:07
嗯嗯,黑黑说得很清楚了,只是我理解上还有点迷糊

正常的

红影 发表于 2023-10-29 22:08

马黑黑 发表于 2023-10-29 18:19
存在。你去多大就是多大,超出svg视口的部分是实际占位的空白

哦,原来是这样。也不对啊,要是我取得更大呢?

红影 发表于 2023-10-29 22:09

马黑黑 发表于 2023-10-29 18:19
正常的

这个需要转换脑筋去接受{:4_173:}

马黑黑 发表于 2023-10-29 22:32

红影 发表于 2023-10-29 22:09
这个需要转换脑筋去接受

额,可能吧

马黑黑 发表于 2023-10-29 22:33

红影 发表于 2023-10-29 22:08
哦,原来是这样。也不对啊,要是我取得更大呢?

多大都一样原理,就是把viewBox的选区按比例投影到画布中

红影 发表于 2023-10-29 23:44

马黑黑 发表于 2023-10-29 22:32
额,可能吧

抛开习惯性思维。

红影 发表于 2023-10-29 23:44

马黑黑 发表于 2023-10-29 22:33
多大都一样原理,就是把viewBox的选区按比例投影到画布中

嗯嗯,知道了{:4_204:}

马黑黑 发表于 2023-10-31 11:13

红影 发表于 2023-10-29 23:44
嗯嗯,知道了

后面的viewBox内容会更复杂
页: [1] 2 3
查看完整版本: 理解 svg 的 viewBox 属性(一)