likes
comments
collection
share

SVG奇淫巧技(一):viewBox和viewPort是个啥?

作者站长头像
站长
· 阅读数 36

我报名参加金石计划1期挑战——瓜分10万奖池,这是我的第1篇文章。

首先,抛出一个小问题,前几篇的演示案例中,<svg>标签总会出现一个viewBox属性,那么它是什么呢?想要弄清楚这个属性,就必须要了解另一个概念viewPort

不卖关子,让我们带着这个问题开始今天的正文吧。

一、viewPort 和 viewBox

viewport 表示SVG可见区域的大小,其实就是<svg>标签占位的大小,同理于Canvas画布的大小。

<svg width="200" height="100"></svg>

上述代码就是定义了一个宽500单位,高300单位的一个视区。

注意:这里的措辞是“单位”,不是“像素”。虽然说,width/height如果是纯数字,使用的就是“像素”作为单位的。

也就是说,上面SVG的视区大小就是 200px * 100px

而之所以用“单位”来描述,是因为这里是不限制单位类型的,可使用的范围几乎涵盖常见的CSS单位: empx%in (英寸)cm(厘米)mm(毫米)pt(1/72英寸)ex(相对于小写字母‘x’的高度)等等。

<rect>width/height<svg>同理。

了解了可视区域的概念后,我们再来看下viewbox的定义:

MDN:

viewBox是一个包含 4 个参数的列表 min-xmin-ywidth 和 height, 以空格或者逗号分隔开, 在用户空间中指定一个矩形区域映射到给定的元素,查看属性preserveAspectRatio

另外,width and height不允许为负值,为 0 则禁用元素的呈现。

绕来绕去的描述不如几行代码来的直观,我们直接上代码:

SVG奇淫巧技(一):viewBox和viewPort是个啥?

<svg width="200" height="100" viewBox="0,0,20,10">
    <rect x="5" y="0" width="10" height="10" fill="red"/>
</svg>

可以看到,我们在一个200px * 100px的可视区域内,指定了一个viewBox="0,0,20,10"的矩形区域映射给<rect>

根据MDN的定义我们将这里的viewBox分解一下:

min-x(左上角横坐标x): 0

min-y(左上角纵坐标y): 0

width(宽度): 20

height(高度): 10

此时,就得到了一个左上角为(0,0)点的 20*10 尺寸的矩形区域。不过,这时候又有了一个新的问题,为什么一个200px*100px的可视窗口,会被一个10px*10px的正方形填充了一半的面积呢?

这就是viewBox在大显神通了,毕竟10px*10px的正方形是被映射到了viewBox的管辖范围。

其实这个问题很好理解,你可以把viewBox想象成一个按照长宽比来缩放的舞台,通过下面这个动图应该会更容易理解。

SVG奇淫巧技(一):viewBox和viewPort是个啥?

viewbox在可视区域中根据自身长宽比例拉伸直至充满整个viewport视区。

SVG奇淫巧技(一):viewBox和viewPort是个啥?

所以,被映射到viewBox中的<rect>自然也被等比拉大了,这也就解释了,为什么200px*100px的视窗,会被一个10px*10px的正方形填充了一半的面积。

说道这里,不知道有没有小伙伴把viewBox看做成一个比例尺,无非是宽度分为20份,高度10份,映射区域的尺寸不是单位,而是占比的份数。

错,这是一个误区,最早我也是这么理解的,再解释为什么之前,请先记住:

viewBox不是比例尺,viewBox不是比例尺,viewBox不是比例尺!

好了摒弃这个误区之后,我们来试想一个问题,刚才的例子中200*100viewport20*10viewBox,恰巧宽高比一致,那么如果宽高比不一致,SVG又会如何表现呢?

SVG奇淫巧技(一):viewBox和viewPort是个啥?

<svg width="200" height="100" viewBox="0,0,40,30">
    <rect x="0" y="0" width="40" height="30" stroke="red" fill="none"/>
</svg>

我们看到,4:3viewbox2:1viewport中2侧均有留白区域,并且居中,可是为什么会居中呢?

这就牵扯出另一个属性 preserveAspectRatio 了。

preserveAspectRatio 是应用在<svg>元素上,但作用对象却是viewBox,其默认值为:

preserveAspectRatio="xMidYMid meet"

preserveAspectRatio属性的值为空格分隔的两个值组合而成。例如,上面的xMidYMid和meet

1个值负责控制viewBoxviewport的对齐方式;

2个值负责控制viewbox"撑满"viewport的方式。

我们来一个一个的了解,先看第1个值是如何表示对齐方式的?

首先这个值是由两部分组成,前半部分表示x方向对齐,后半部分表示y方向对齐(这里注意Y是大写)。除了默认xMidYMid 之外,还有其余的值:

对齐方式
xMin左对齐
xMid水平居中
xMax右对齐
YMin上对齐
YMid垂直居中
YMax下对齐

然后,从以上的值中选择你需要的xy对齐方式之后,自由组合就好了,看起来和flex中的对齐方式十分类似不是吗?所以,上面的例子之所以居中,就是因为默认的xMidYMid让其垂直水平居中了,是不是很简单。

OK,到了最后一个知识点,preserveAspectRatio的第2个值,负责控制viewbox"撑满"viewport的方式,具体支持3个属性:

含义
meet保持宽高等比缩放viewbox来适应viewport
slice保持宽高比,同时比例小的方向撑满viewport
none不保持宽高比,充分撑满viewport

看描述是不是有种似曾相识的感觉,没错,就如同我们电脑设置桌面时的平铺裁剪拉伸,结合案例来看就一目了然了:

SVG奇淫巧技(一):viewBox和viewPort是个啥?

巧用的preserveAspectRatio的不等比缩放

现在,关于 viewPortviewBox的知识我们已经掌握了,当preserveAspectRatio的第二个值设为none的时候,SVG就失去了等比缩放的能力。

不知道大家有没有疑问,SVG的核心优势不就是等比缩放吗?那么什么场景下会用到非等比缩放的SVG呢?

这里也有个小误区,SVG的核心优势是矢量,而矢量与等比缩放无关,与放大后不失真有关。搞混的同学罚去看《SVG擅长些啥》

话说回来,有些时候SVG的非等比缩放可能会产生意想不到的效果,例如:

SVG奇淫巧技(一):viewBox和viewPort是个啥?

上面的倒三角区域就是由空白处的SVG遮挡实现的,这里的SVG就是使用的非等比缩放,所以在不同的尺寸下,表现出的效果要比等比缩放的死板看起来自然的多。

二、利用SVG实现前端截图

一直以来,截图功能基本都是后端的专属,前端想要实现至少也要通过node.js来做到,但通过SVG中的foreignObject 元素再配合Canvas就可以轻松实现,不了解foreignObject的同学可以去《SVG不擅长些啥》补课,具体实现原理如下:

  1. 获取对应DOM元素的outerHTML代码;
  2. 放在<foreignObject>元素中;
  3. <img>来显示我们的SVG
    <img width="300" height="150"
         src='data:image/svg+xml;charset=utf-8,
              <svg xmlns="http://www.w3.org/2000/svg">
     	       <foreignObject width="120" height="50">
     		 <body xmlns="http://www.w3.org/1999/xhtml">
     		    <p style="font-size:12px;margin:0;">
     		       一段需要word wrap的文字
     		    </p>
     	         </body>
     	       </foreignObject>
              </svg>'>
    
  4. 上一步的图片本质还是SVG,我们可以借助canvasdrawImage() 方法将图片放在画布上,然后使用canvas.toDataURL() 方法转换成.png.jpg 图片,核心代码:
    var canvas = document.createElement('canvas');
    var context = canvas.getContext('2d');
    canvas.drawImage(img, 0, 0);
    img.src = canvas.toDataURL('image/png');
    

关于前端截图的代码和思路均来自于张鑫旭大佬,具体的实现方式和代码都在下方的参考链接里,大家可以去膜拜一下大佬的风采。

好了,今天就先到这里吧,下一篇我们来聊聊《SVG奇淫巧技(二):关于交互那点事》

参考链接

SVG<foreignObject>简介与截图等应用

理解SVG viewport,viewBox,preserveAspectRatio缩放

转载自:https://juejin.cn/post/7139708499054821406
评论
请登录