svg基础

150 阅读12分钟

基本图形和属性:

  • 基本图形
    • <rect>、<circle>、<ellipse>、<line>、<polyline>、<polygon>
  • 基本属性
    • fill、stroke、stroke-width、transform

矩形 <rect>

20220422105342

如果只指定rx, 不指定ry, ry使用rx的值。

<circle>

20220422105417

注意矩形指定位置是的属性是x, y, 圆是cx, cy; 更加明确

椭圆 <ellipse>

20220422105509

直线 <line>

20220422105539

折线 <polyline>

20220422112219

多边形 <polygon>

20220422112232

多边形跟折线和像, 唯一不同是会帮你把起点跟终点连接起来

基本属性

20220422112253

视野的概念

20220422112316

  • 世界是无穷大的
  • 视野是观察世界的一个矩形区域

svg视野, 视窗,世界的概念

  • width, height 控制视窗(浏览器显示svg的区域)
  • svg代码 - 定义世界
  • viewBox - 定义视野的大小, preserveAspectRatio - 定义视野和视窗的关系

默认视野跟视窗的大小是一致的。

20220422112331

  • viewBox=" [x] [y] [width] [height]"
  • preserveAspectRatio="[align] [meetOrSlice]"

其中meetOrSlice可能的取值:

  • meet 视窗完全包裹视野, 视觉上视野完全在视窗上显示出来
  • slice 视野宽度或高度匹配视窗的宽度或高度, 超出部分将被裁剪

align可能的取值:

对齐方式:

  • none 对视野进行拉伸
  • xMinYMin 视野视窗右上顶点对齐
  • xMidYMin
  • xMaxYMin
  • xMinYMid
  • xMaxYMid
  • xMinYMax
  • xMidYMax
  • xMaxYMax

Min相当与top Mid相当与center Max相当与bottom

svg中的4种坐标系

20220422112357

20220422112406

这里Ouser是用户坐标系, Oa是rect的自身坐标系, Ouser是Oa的前驱坐标系, 初始状态下Ouser和Oa是重合的. transform属性会根据前驱坐标系来改变自身坐标系. rect上设置的x, y都是基于自身坐标系的.

坐标变换

定义

数学上, [坐标变换] 是采用一定的数学方法将一个坐标系的坐标变换为另一个坐标系的坐标的过程

svg中, [坐标变换]是对一个坐标系到另一个坐标系的变换的描述

线性变换

平移

其实平移不是线性变换, 线性变换有两个特点:

  1. 直线在变换后仍然保持为直线, 不能有所弯曲
  2. 原点必须保持固定

平移相当于移动了原点, 所以不是线性变换.

3X3矩阵应该代表的3维的线性变换, 这里有点特殊, 在二维线性变换的基础上, 加上了平移.

x' = ax + cy + e;
y' = bx + dy + f;

不看e, f, 其实就是一个二维的线性变换方程。

旋转

svg的transform属性

相对于前驱坐标系变换得到新的自身坐标系.

语法:

变换的顺序是很重要的.

transform: rotate(30deg) translate(90)

跟:

transform: translate(90) rotate(30deg)

效果是不一样的.

颜色

RGB和HSL

RGB

  • 红色,绿色, 蓝色三个分量

  • 每个分量取值范围: [0, 255]

  • 优势: 显示器容易解析

  • 劣势: 不符合人类描述颜色的习惯

比如下图中, 对颜色的描述:

HSL

  • 三个分量分别表示颜色, 饱和度和亮度

  • 格式: hsl(h, s%, l%)

  • 取值范围:

    • h: [0, 359]
    • s,l: [0, 100]
  • 优势: 符合人类描述颜色的习惯

hue表示颜色, 0度表示红色, 120度表示绿色, 240度就是蓝色.

saturation表示色彩的饱和度, 100%是完全饱和的, 这个时候的颜色是最鲜艳的. 0就是完全不饱和, 这个时候颜色就退化成灰度.

lightness表示亮度, 0%时是暗的, 这个时候我们会得到一个黑色, 100%表示完全是亮的, 这个时候我们会得到一个白色. 当它是这两个极端的时候, 无论h,s 取什么值,都只会是黑色和白色.

线性渐变

  • 使用和的定义线性渐变
  • 使用两个点表示线性渐变的方向
  • 使用定义关键点位置及颜色
  • gradinetUnits
    • objectBoundingBox(默认) x1,y1,x2,y2的取值是 相对于图形的比值
    • userSpaceOnUse x1, y1, x2, y2是世界坐标系的取值

径向渐变

  • cx, cy表示径向渐变的圆心点
  • r表示径向渐变的圆的半径
  • fx, fy表示焦点, 也就是渐变的起点

笔刷

有点像css中背景repeat的效果.

效果:

patternUnits 和 patternContentUnits

patternUnits定义的是标签上x,y, width, height等的单位代表的意义. 跟径向渐变, 线性渐变一样, objectBoundingBox表示的是相对于使用的区域的一个百分比的取值; userSpaceOnUse表示在世界坐标系中的取值.

patternContentUnits表示的是笔刷内容的单位意思, 比如上面的例子中的上的cx, cy, r等属性.

路径

d属性是一个命令序列, 字母代表的是命令名称, 后面跟的是参数, 有一些是坐标值, 也有一些是命令的设定.

path的工作原理, 可以想象有一支笔, 当接收到一个命令的时候, 这支笔就移动到相应的位置, 也可能根据你的命令绘制一些直线曲线.

命令汇总

命令基本规律

  • 区分大小写: 大写表示坐标参数为绝对位置, 小写则为相对位置(相对于上一次命令画笔停留的位置)
  • 最后的参数表示最终要到达的位置
  • 上一个命令结束的位置就是下一个命令开始的位置
  • 命令可以重复表示重复执行统一体命令

移动和直线命令

  • M(x,y)+ 移动画笔, 后面如果有重复参数, 会当作是L命令处理

如果不用M命令, 画笔的位置由两种情况确定:

  1. 默认初始位置为(0, 0), 这个(0, 0)是自身坐标系
  2. 上一个命令的结束位置.

弧线命令

  • A(rx, ry, xr, laf, sf, x, y) - 绘制弧线
    • rx - (radius-x)弧线所在椭圆的x半轴长
    • ry - (radius-y)弧线所在椭圆的y半轴长
    • xr - (xAxis-rotation)弧线所在椭圆的长轴角度
    • laf - (large-arc-flag) 是否选择弧长较长的那一段弧
    • sf - (sweep-flag) 是否选择逆时针方向的那一段弧
    • x,y - 弧的终点位置

描述的是一个椭圆: 水平半径为rx, 竖直半径为ry, 顺时针旋转xr, 起点和终点都在这个椭圆上, 起点是上一个命令的终点. 如下图:

这样的椭圆有两个, 如下图:

  • laf为1表示取较大的弧, laf为0表示较小的弧.
  • sf为0表示取逆时针的弧, sf为1表示取顺时针的弧. 所谓顺时针,逆时针是以起点到终点来说的.

贝塞尔曲线

二次贝塞尔曲线

quadric(二次)

三次贝塞尔曲线

光滑曲线

  • T: Q(二次)的光滑版本
  • S: C(三次)的光滑版本

可以少设置一个控制点.

如果上一个命令也是一个贝塞尔曲线, 使用光滑曲线的第一个控制点为上一个曲线的最后一个控制点相对于当前曲线的起点的镜像位置, 如图:

M100,200 C100,100 250,100 250,200为上一次的三次贝塞尔曲线命令, S400,300 400,200为三次光滑贝塞尔曲线命令, 它指定了两个点, 第一个为控制点(三次贝塞尔曲线的第二个控制点C2), 第二个为终点. 第一个控制点为上次命令的最后一个控制点, 也就是(250, 100)的镜像位置(图中蓝色的点):

这种镜像关系, 保证了过渡点一个平滑的性质. 实际上, 只要说上一个曲线的最后一个控制点与当前曲线的第一个控制点关于过度位置是一个镜像关系, 它就是一个光滑的位置.

文字

svg中对文字的支持很有限, 仅仅是把文字作为图形来渲染, 不支持排版, 也就是说要实现文字换行的话, 要自己计算坐标.

<text><tspan>

  • x和y属性 - 定位标准
  • dx和dy属性 - 字形偏移
  • style属性 - 设置样式
<text x="100" y="100" style="font-size: 50px">x一段文字</text>
<path d="M100,0V200M0,100H200" stroke="red"/>

效果如图:

<path>画了参考线, <text>的x,y指定为(100, 100), x比较好理解, y的位置就有点不好理解了, 从图中可以看出, 既不与文字的顶部对齐, 也不与文字的底部对齐(中文有超出), 它实际上是与文字的基线对齐, 通常来说就是英文字母x的底部(可能有些字体中x不那么规范).

文字的偏移

设置dx, dy可以使文字进行偏移.

<text x="100" y="100" dx="50" dy="50" style="font-size: 50px">x一段文字</text>
<path d="M100,0V200M0,100H200" stroke="red"/>

效果如图:

文字整体向x轴偏移了50, 向y轴偏移了50, 其实我们之间设置x, y也可以办到~, dx, dy关键的地方在于它的值可以设置为一个数组, 可以为每个字形指定偏移量, 数组中第一值对应一个字形, 第二个值对应第二个字形, 以此内推.

<text x="100" y="100" dx="20 40 60" dy="20 20 20" style="font-size: 50px">ABCDEFG</text>
<path d="M100,0V200M0,100H200" stroke="red"/>

效果如图:

利用dy属性实现文字波浪效果

文字波浪效果效果

主要是利用了正弦曲线函数描绘出了正弦曲线.

y=Asin(ωx+φ)+k
  • A——振幅,当物体作轨迹符合正弦曲线的直线往复运动时,其值为行程的1/2。
  • (ωx+φ)——相位,反映变量y所处的状态。 φ——初相,x=0时的相位;反映在坐标系上则为图像的左右移动。
  • k——偏距,反映在坐标系上则为图像的上移或下移。
  • ω——角速度, 控制正弦周期(单位弧度内震动的次数)。

<tspan>

<tspan>是在<text中来使用, 作用可以理解为html中span一样, 可以单独的给一行文字中的某些文字设置样式.

  • dx, dy属性也可以设置在<tspan>
  • dx, dy属性会被覆盖, 比如在<text><tspan>中同时设置dx, dy; <tspan>上的设置会覆盖掉对应的<text>上的设置.

文字居中

  • text-anchor - 水平居中
  • 垂直居中需要模拟

我们通常会在<text>上设置x,y来确定文本的位置,
y的位置确定的文本的基线位置, 但是通常我们需要的效果是文字顶部, 底部,或中间对齐y的位置.

下图是<text y="y">的位置示意图:

b.y和b.h我们可以通过text.getBBox()来获取.

我们需要调整dy:

  • 顶部对齐y: dy = y - b.y
  • 底部对应y: dy = y - (b.y + b.h)
  • 中部对应y: dy = y - (b.y + b.h/2)

文本路径

<path id="path1" d="M100,200Q150,150 200,200T300, 200" stroke="red" fill="none"></path>
<text>
  <textPath xlink:href="#path1">ABCDEFG</textPath>
</text>

效果:

渲染原理

影响路径文本位置的属性

  • <text>

    • x属性
  • <textPath>

    • text-anchor: start, middle, end, 文本与文本的起始点(通过startOffset和x可以改变)的对齐方式。
    • startOffest, 效果与<text> 上x一样, 但是不同的是取值为百分比.
  • dx, dy属性

    • 切线和法线方向上的偏移

<text> 上设置x对<textPath>的影响

<path id="path1" d="M100,200Q150,0 200,200T300, 200" stroke="red" fill="none"></path>
<text x="50">
  <textPath xlink:href="#path1">ABCDEFGEFFFGSSDSD</textPath>
</text>

效果:

<text>设置y对路径文本没有效果.

<a> - 超链接

  • 可以添加到任意的图形上
  • xlink:href 地址
  • xlink:title 提示
  • target 指定打开目标

动画

动画原理

SMIL for SVG

  • 参考资料

  • 动画标签

    • <animate>, <animateTransform>, <animateMotion>
  • 动画元素, 属性定位以及动画参数设置

    • attributeName, attributeType
    • from, to, dur, repeatCount, fill( remove(默认):回到初始位置, freeze: 保持动画结束的位置 )..
    • calcMode..

使用动画

  1. 使用xlink:href找到使用动画的元素 <animate xlink:href="#rect1"></animate>
  2. 元素中包含动画标签,表示元素将使用该动画
<rect>
    <animate></animate>
</rect>
基本使用
<animate
  attributeType="XML"
  attributeName="x"
  from="0"
  to="100"
  dur="3s"
  xlink:href="#rect1"
>
  
</animate>
动画叠加

同时变换两个属性。

begin-指定动画什么时候开始
  • begin默认为0, 指的是文档加载结束就马上开始.
  • begin="0; goleft.end" 这个意思是, 除了了在0秒开始, 还有golfet动画结束的时候开始

这里的效果为: goright动画结束后马上进行goleft动画; goleft动画结束后马上执行goright动画, 一直循环.

变换动画

轨迹运动

例子: 力导向图

用到的物理公式:

  • Fi=kXi\vec{F_i} = k \vec{X_i}

弹性公式, FiF_i(所受的力)和XiX_i(可以理解为弹簧压缩或拉伸的长度, 与弹簧的自然长度相减)都为向量. k为弹性系数.

  • F=Fi\vec{F} = \sum \vec{F_i}

一个物体所受的力等于所有作用在它上的力的和. 主要力是向量, 是有方向的.

  • a=F/m\vec{a} = \vec{F}/m

加速度.

  • v=v0+aΔt\vec{v} = \vec{v_0} + a \Delta t

速度.

基本原理

如图, 有三个点, 他们之间的连线可以看出是弹簧, 初始位置是随机的, 他们之间会受到与他们链接的弹簧的引力或者斥力. 相互作用一段时间后, 最后会达到一个稳定的位置。

受力就会有一个加速度, 从而产生运动.

这里有个很重要的概念就是向量. 向量可以理解为有方向的线段, 力, 速度, 加速度, 位移都是有方向的。

关键代码

向量, 力, 速度, 加速度, 位移都可以用向量表示:

class Vector {
	constructor(x, y){
  	this.x = x || 0;
    this.y = y || 0;
  }
  square = () =>{
  	return this.x*this.x + this.y*this.y;
  }
  length = () =>{
  	return Math.sqrt(this.square());
  }
  add = (v) =>{
  	return new Vector(this.x + v.x, this.y + v.y);
  }
  minus = (v) =>{
  	return new Vector(this.x - v.x, this.y - v.y);
  }
  multipy = (scale) => {
  	return  new Vector(this.x * scale, this.y * scale);
  }
  // 与原矢量方向一致, 指定长度
  normalize = (length) =>{
  	if(length===undefined){
    	length = 1;
    }
    return this.multipy(length / this.length());
  }
  
  static fromPoints(p1, p2){
  	return new Vector(p2.x - p1.x, p2.y - p1.y);
  }
}

demo地址

引用 - <use>

重复使用定义好的图形.

<polygon id="star" points="-10 0,-2 2, 0 10, 2 2, 10 0, 2 -2, 0, -10, -2 -2" fill="white"></polygon>
<use xlink:href="#star" x="50"/>

裁剪 -

取两个图形重合的部分.

比如如下图两个图:

通过如下代码:

将得到如下图形.

蒙板 -

可以把蒙板也看成是一个图形, 最极端的例子, 蒙板图形上的颜色有白色有黑色, 将蒙板盖在一个图形上, 与蒙板重合的部分, 如果是白色将显示, 如果是黑色将隐藏.

原始图形:

蒙板图形,使用两个圆就能得到一个月牙的性质:

将蒙板运用在原始图形的效果:

代码如下:

<circle cx="0" cy="0" r="50" fill="yellow" mask="url(#moon-mask)"></circle>
<mask id="moon-mask">
  <circle cx="0" cy="0" r="50" fill="white"></circle>
  <circle cx="20" cy="-20" r="50" fill="black"></circle>
</mask>