您的位置:澳门新葡8455最新网站 > Web前端 > 基本形状转换那些事

基本形状转换那些事

发布时间:2019-11-14 16:55编辑:Web前端浏览(175)

    聊聊 SVG 基本形状转换那些事

    2017/01/20 · HTML5 · SVG

    原文出处: 凹凸实验室   

    图片 1

    SVG即Scalable Vector Graphics可缩放矢量图形,使用XML格式定义图形, 主要优势在于可缩放的同时不会影响图片的质量。

    一、前言

    前段时间研究 SVG 压缩优化,发现SVG预定义的 rectcircleellipselinepolylinepolygon 六种基本形状可通过path路径转换实现,这样可以在一定程度上减少代码量。不仅如此,我们常用的 SVG Path 动画(路径动画),是以操作path中两个属性值stroke-dasharraystroke-dashoffset来实现,基本形状转换为path路径,有利于实现路径动画。

     

    二、SVG基本形状

    SVG 提供了rectcircleellipselinepolylinepolygon六种基本形状用于图形绘制,这些形状可以直接用来绘制一些基本的形状,如矩形、椭圆等,而复杂图形的绘制则需要使用 path 路径来实现。

    图片 2

    SVG 在html 中常用的方法

    1.rect 矩形

    XHTML

    <rect x="10" y="10" width="30" height="30"/> <rect x="60" y="10" rx="10" ry="10" width="30" height="30"/>

    1
    2
    <rect x="10" y="10" width="30" height="30"/>
    <rect x="60" y="10" rx="10" ry="10" width="30" height="30"/>

    SVG中rect元素用于绘制矩形、圆角矩形,含有6个基本属性用于控制矩形的形状以及坐标,具体如下:

    x 矩形左上角x位置, 默认值为 0 y 矩形左上角y位置, 默认值为 0 width 矩形的宽度, 不能为负值否则报错, 0 值不绘制 height 矩形的高度, 不能为负值否则报错, 0 值不绘制 rx 圆角x方向半径, 不能为负值否则报错 ry 圆角y方向半径, 不能为负值否则报错

    1
    2
    3
    4
    5
    6
    x 矩形左上角x位置, 默认值为 0
    y 矩形左上角y位置, 默认值为 0
    width 矩形的宽度, 不能为负值否则报错, 0 值不绘制
    height 矩形的高度, 不能为负值否则报错, 0 值不绘制
    rx 圆角x方向半径, 不能为负值否则报错
    ry 圆角y方向半径, 不能为负值否则报错

    这里需要注意,rxry 的还有如下规则:

    • rxry 都没有设置, 则 rx = 0 ry = 0
    • rxry 有一个值为0, 则相当于 rx = 0 ry = 0,圆角无效
    • rxry 有一个被设置, 则全部取这个被设置的值
    • rx 的最大值为 width 的一半, ry 的最大值为 height 的一半
    JavaScript
    
    rx = rx || ry || 0; ry = ry || rx || 0;   rx = rx &gt; width / 2 ?
    width / 2 : rx; ry = ry &gt; height / 2 ? height / 2 : ry;   if(0
    === rx || 0 === ry){ rx = 0, ry = 0;
    //圆角不生效,等同于,rx,ry都为0 }
    
    <table>
    <colgroup>
    <col style="width: 50%" />
    <col style="width: 50%" />
    </colgroup>
    <tbody>
    <tr class="odd">
    <td><div class="crayon-nums-content" style="font-size: 13px !important; line-height: 15px !important;">
    <div class="crayon-num" data-line="crayon-5b8f49eccc27a188181481-1">
    1
    </div>
    <div class="crayon-num crayon-striped-num" data-line="crayon-5b8f49eccc27a188181481-2">
    2
    </div>
    <div class="crayon-num" data-line="crayon-5b8f49eccc27a188181481-3">
    3
    </div>
    <div class="crayon-num crayon-striped-num" data-line="crayon-5b8f49eccc27a188181481-4">
    4
    </div>
    <div class="crayon-num" data-line="crayon-5b8f49eccc27a188181481-5">
    5
    </div>
    <div class="crayon-num crayon-striped-num" data-line="crayon-5b8f49eccc27a188181481-6">
    6
    </div>
    <div class="crayon-num" data-line="crayon-5b8f49eccc27a188181481-7">
    7
    </div>
    <div class="crayon-num crayon-striped-num" data-line="crayon-5b8f49eccc27a188181481-8">
    8
    </div>
    <div class="crayon-num" data-line="crayon-5b8f49eccc27a188181481-9">
    9
    </div>
    <div class="crayon-num crayon-striped-num" data-line="crayon-5b8f49eccc27a188181481-10">
    10
    </div>
    </div></td>
    <td><div class="crayon-pre" style="font-size: 13px !important; line-height: 15px !important; -moz-tab-size:4; -o-tab-size:4; -webkit-tab-size:4; tab-size:4;">
    <div id="crayon-5b8f49eccc27a188181481-1" class="crayon-line">
    rx = rx || ry || 0;
    </div>
    <div id="crayon-5b8f49eccc27a188181481-2" class="crayon-line crayon-striped-line">
    ry = ry || rx || 0;
    </div>
    <div id="crayon-5b8f49eccc27a188181481-3" class="crayon-line">
     
    </div>
    <div id="crayon-5b8f49eccc27a188181481-4" class="crayon-line crayon-striped-line">
    rx = rx &gt; width / 2 ? width / 2 : rx;
    </div>
    <div id="crayon-5b8f49eccc27a188181481-5" class="crayon-line">
    ry = ry &gt; height / 2 ? height / 2 : ry;
    </div>
    <div id="crayon-5b8f49eccc27a188181481-6" class="crayon-line crayon-striped-line">
     
    </div>
    <div id="crayon-5b8f49eccc27a188181481-7" class="crayon-line">
    if(0 === rx || 0 === ry){
    </div>
    <div id="crayon-5b8f49eccc27a188181481-8" class="crayon-line crayon-striped-line">
    rx = 0,
    </div>
    <div id="crayon-5b8f49eccc27a188181481-9" class="crayon-line">
    ry = 0; //圆角不生效,等同于,rx,ry都为0
    </div>
    <div id="crayon-5b8f49eccc27a188181481-10" class="crayon-line crayon-striped-line">
    }
    </div>
    </div></td>
    </tr>
    </tbody>
    </table>
    

    1.使用<img>元素来嵌入SVG图像

    2.circle 圆形

    XHTML

    <circle cx="100" cy="100" r="50" fill="#fff"></circle>

    1
    <circle cx="100" cy="100" r="50" fill="#fff"></circle>

    SVG中circle元素用于绘制圆形,含有3个基本属性用于控制圆形的坐标以及半径,具体如下:

    r 半径 cx 圆心x位置, 默认为 0 cy 圆心y位置, 默认为 0

    1
    2
    3
    r 半径
    cx 圆心x位置, 默认为 0
    cy 圆心y位置, 默认为 0

    <img src=”  width=”300″ />

    3.ellipse 椭圆

    XHTML

    <ellipse cx="75" cy="75" rx="20" ry="5"/>

    1
    <ellipse cx="75" cy="75" rx="20" ry="5"/>

    SVG中ellipse元素用于绘制椭圆,是circle元素更通用的形式,含有4个基本属性用于控制椭圆的形状以及坐标,具体如下:

    rx 椭圆x半径 ry 椭圆y半径 cx 圆心x位置, 默认为 0 cy 圆心y位置, 默认为 0

    1
    2
    3
    4
    rx 椭圆x半径
    ry 椭圆y半径
    cx 圆心x位置, 默认为 0
    cy 圆心y位置, 默认为 0

    2.将SVG图像作为背景图像嵌入

    4.line 直线

    XHTML

    <line x1="10" x2="50" y1="110" y2="150"/>

    1
    <line x1="10" x2="50" y1="110" y2="150"/>

    Line绘制直线。它取两个点的位置作为属性,指定这条线的起点和终点位置。

    x1 起点的x位置 y1 起点的y位置 x2 终点的x位置 y2 终点的y位置

    1
    2
    3
    4
    x1 起点的x位置
    y1 起点的y位置
    x2 终点的x位置
    y2 终点的y位置

    background: url(‘) no-repeat;

    5.polyline 折线

    XHTML

    <polyline points="60 110, 65 120, 70 115, 75 130, 80 125, 85 140, 90 135, 95 150, 100 145"/>

    1
    <polyline points="60 110, 65 120, 70 115, 75 130, 80 125, 85 140, 90 135, 95 150, 100 145"/>

    polyline是一组连接在一起的直线。因为它可以有很多的点,折线的的所有点位置都放在一个points属性中:

    points 点集数列,每个数字用空白、逗号、终止命令符或者换行符分隔开,每个点必须包含2个数字,一个是x坐标,一个是y坐标 如0 0, 1 1, 2 2”

    1
    points 点集数列,每个数字用空白、逗号、终止命令符或者换行符分隔开,每个点必须包含2个数字,一个是x坐标,一个是y坐标 如0 0, 1 1, 2 2”

    3.使用svg元素,通过代码将SVG图像嵌入到HTML代码中

    6.polygon 多边形

    XHTML

    <polygon points="50 160, 55 180, 70 180, 60 190, 65 205, 50 195, 35 205, 40 190, 30 180, 45 180"/>

    1
    <polygon points="50 160, 55 180, 70 180, 60 190, 65 205, 50 195, 35 205, 40 190, 30 180, 45 180"/>

    polygon和折线很像,它们都是由连接一组点集的直线构成。不同的是,polygon的路径在最后一个点处自动回到第一个点。需要注意的是,矩形也是一种多边形,如果需要更多灵活性的话,你也可以用多边形创建一个矩形。

    points 点集数列,每个数字用空白、逗号、终止命令符或者换行符分隔开,每个点必须包含2个数字,一个是x坐标,一个是y坐标 如0 0, 1 1, 2 2, 路径绘制完闭合图形”

    1
    points 点集数列,每个数字用空白、逗号、终止命令符或者换行符分隔开,每个点必须包含2个数字,一个是x坐标,一个是y坐标 如0 0, 1 1, 2 2, 路径绘制完闭合图形”

    <svg width=”100%” height=”100%”>

    三、SVG path 路径

    SVG 的路径<path>功能非常强大,它不仅能创建基本形状,还能创建更多复杂的形状。<path>路径是由一些命令来控制的,每一个命令对应一个字母,并且区分大小写,大写主要表示绝对定位,小写表示相对定位。<path> 通过属性 d 来定义路径, d 是一系列命令的集合,主要有以下几个命令:

    图片 3

    通常大部分形状,都可以通过指令M(m)L(l)H(h)V(v)A(a)来实现,注意特别要区分大小写,相对与绝对坐标情况,转换时推荐使用相对路径可减少代码量,例如:

    // 以下两个等价 d='M 10 10 20 20' // (10, 10) (20 20) 都是绝对坐标 d='M 10 10 L 20 20'   // 以下两个等价 d='m 10 10 20 20' // (10, 10) 绝对坐标, (20 20) 相对坐标 d='M 10 10 l 20 20'

    1
    2
    3
    4
    5
    6
    7
    // 以下两个等价
    d='M 10 10 20 20' // (10, 10) (20 20) 都是绝对坐标
    d='M 10 10 L 20 20'
     
    // 以下两个等价
    d='m 10 10 20 20' // (10, 10) 绝对坐标, (20 20) 相对坐标
    d='M 10 10 l 20 20'

    <rect x=”20″ y=”20″ width=”250″ height=”250″style=”fill:#fecdddd;”/>

    四、SVG 基本形状路径转换原理

    </svg>

    1.rect to path

    如下图所示,一个 rect 是由 4 个弧和 4 个线段构成;如果 rect 没有设置 rx 和 ry 则 rect 只是由 4 个线段构成。rect 转换为 path 只需要将 A ~ H 之间的弧和线段依次实现即可。

    图片 4

    JavaScript

    function rect2path(x, y, width, height, rx, ry) { /* * rx 和 ry 的规则是: * 1. 如果其中一个设置为 0 则圆角不生效 * 2. 如果有一个没有设置则取值为另一个 */ rx = rx || ry || 0; ry = ry || rx || 0;   //非数值单位计算,如当宽度像100%则移除 if (isNaN(x - y + width - height + rx - ry)) return;   rx = rx > width / 2 ? width / 2 : rx; ry = ry > height / 2 ? height / 2 : ry;   //如果其中一个设置为 0 则圆角不生效 if(0 == rx || 0 == ry){ // var path = // 'M' + x + ' ' + y

    • // 'H' + (x + width) + 不推荐用绝对路径,相对路径节省代码量 // 'V' + (y + height) + // 'H' + x + // 'z'; var path = 'M' + x + ' ' + y + 'h' + width + 'v' + height + 'h' + -width + 'z'; }else{ var path = 'M' + x + ' ' + (y+ry) + 'a' + rx + ' ' + ry + ' 0 0 1 ' + rx + ' ' + (-ry) + 'h' + (width - rx - rx) + 'a' + rx + ' ' + ry + ' 0 0 1 ' + rx + ' ' + ry + 'v' + (height - ry -ry) + 'a' + rx + ' ' + ry + ' 0 0 1 ' + (-rx) + ' '
    • ry + 'h' + (rx + rx -width) + 'a' + rx + ' ' + ry + ' 0 0 1 ' + (-rx)
    • ' ' + (-ry) + 'z'; }   return path; }
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    function rect2path(x, y, width, height, rx, ry) {
    /*
    * rx 和 ry 的规则是:
    * 1. 如果其中一个设置为 0 则圆角不生效
    * 2. 如果有一个没有设置则取值为另一个
    */
    rx = rx || ry || 0;
    ry = ry || rx || 0;
     
    //非数值单位计算,如当宽度像100%则移除
    if (isNaN(x - y + width - height + rx - ry)) return;
     
    rx = rx > width / 2 ? width / 2 : rx;
    ry = ry > height / 2 ? height / 2 : ry;
     
    //如果其中一个设置为 0 则圆角不生效
    if(0 == rx || 0 == ry){
    // var path =
    // 'M' + x + ' ' + y +
    // 'H' + (x + width) + 不推荐用绝对路径,相对路径节省代码量
    // 'V' + (y + height) +
    // 'H' + x +
    // 'z';
    var path =
    'M' + x + ' ' + y +
    'h' + width +
    'v' + height +
    'h' + -width +
    'z';
    }else{
    var path =
    'M' + x + ' ' + (y+ry) +
    'a' + rx + ' ' + ry + ' 0 0 1 ' + rx + ' ' + (-ry) +
    'h' + (width - rx - rx) +
    'a' + rx + ' ' + ry + ' 0 0 1 ' + rx + ' ' + ry +
    'v' + (height - ry -ry) +
    'a' + rx + ' ' + ry + ' 0 0 1 ' + (-rx) + ' ' + ry +
    'h' + (rx + rx -width) +
    'a' + rx + ' ' + ry + ' 0 0 1 ' + (-rx) + ' ' + (-ry) +
    'z';
    }
     
    return path;
    }

    兼容性

    2.circle/ellipse to path

    圆可视为是一种特殊的椭圆,即 rx 与 ry 相等的椭圆,所以可以放在一起讨论。 椭圆可以看成A点到C做180度顺时针画弧、C点到A做180度顺时针画弧即可。

    图片 5

    JavaScript

    function ellipse2path(cx, cy, rx, ry) { //非数值单位计算,如当宽度像100%则移除 if (isNaN(cx - cy + rx - ry)) return;   var path = 'M' + (cx-rx) + ' ' + cy + 'a' + rx + ' ' + ry + ' 0 1 0 ' + 2*rx + ' 0' + 'a' + rx + ' ' + ry + ' 0 1 0 ' + (-2*rx) + ' 0' + 'z';   return path; }

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    function ellipse2path(cx, cy, rx, ry) {
    //非数值单位计算,如当宽度像100%则移除
    if (isNaN(cx - cy + rx - ry)) return;
     
    var path =
    'M' + (cx-rx) + ' ' + cy +
    'a' + rx + ' ' + ry + ' 0 1 0 ' + 2*rx + ' 0' +
    'a' + rx + ' ' + ry + ' 0 1 0 ' + (-2*rx) + ' 0' +
    'z';
     
    return path;
    }

    IE   9~11          Firefox   40 +       Chrome  43+     Safari   8+      Opera  32+

    3.line to path

    相对来说比较简单,如下:

    JavaScript

    function line2path(x1, y1, x2, y2) { //非数值单位计算,如当宽度像100%则移除 if (isNaN(x1 - y1 + x2 - y2)) return;   x1 = x1 || 0; y1 = y1 || 0; x2 = x2 || 0; y2 = y2 || 0;   var path = 'M' + x1 + ' '+ y1 + 'L' + x2 + ' ' + y2; return path; }

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    function line2path(x1, y1, x2, y2) {
    //非数值单位计算,如当宽度像100%则移除
    if (isNaN(x1 - y1 + x2 - y2)) return;
     
    x1 = x1 || 0;
    y1 = y1 || 0;
    x2 = x2 || 0;
    y2 = y2 || 0;
     
    var path = 'M' + x1 + ' '+ y1 + 'L' + x2 + ' ' + y2;
    return path;
    }

     

    4.polyline/polygon to path

    polyline折线、polygon多边形的转换为path比较类似,差别就是polygon多边形会闭合。

    JavaScript

    // polygon折线转换 points = [x1, y1, x2, y2, x3, y3 ...]; function polyline2path (points) { var path = 'M' + points.slice(0,2).join(' ') + 'L' + points.slice(2).join(' '); return path; }   // polygon多边形转换 points = [x1, y1, x2, y2, x3, y3 ...]; function polygon2path (points) { var path = 'M' + points.slice(0,2).join(' ') + 'L' + points.slice(2).join(' ') + 'z'; return path; }

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    // polygon折线转换
    points = [x1, y1, x2, y2, x3, y3 ...];
    function polyline2path (points) {
    var path = 'M' + points.slice(0,2).join(' ') +
    'L' + points.slice(2).join(' ');
    return path;
    }
     
    // polygon多边形转换
    points = [x1, y1, x2, y2, x3, y3 ...];
    function polygon2path (points) {
    var path = 'M' + points.slice(0,2).join(' ') +
    'L' + points.slice(2).join(' ') + 'z';
    return path;
    }

    svg sprites

    五、convertpath 转换工具

    为了方便处理SVG基本元素路径转换,本人抽空写了convertpath工具,具体如下:

    安装:

    Shell

    npm i convertpath

    1
    npm i convertpath

    使用:

    JavaScript

    const parse = require('convertpath'); parse.parse("./test/test.svg") /** * <circle cx="500" cy="500" r="20" fill="red"/> */ console.log(parse.toSimpleSvg())   /** * <path d="M500,500,m-20,0,a20,20,0,1,0,40,0,a20,20,0,1,0,-40,0,Z" fill="red"/> */

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    const parse = require('convertpath');
    parse.parse("./test/test.svg")
    /**
    * <circle cx="500" cy="500" r="20" fill="red"/>
    */
    console.log(parse.toSimpleSvg())
     
    /**
    * <path d="M500,500,m-20,0,a20,20,0,1,0,40,0,a20,20,0,1,0,-40,0,Z" fill="red"/>
    */

    参考资料:

    Basic Shapes – SVG 1.1 (Second Edition)
    基本形状 – SVG | MDN
    SVG (一) 图形, 路径, 变换总结; 以及椭圆弧线, 贝塞尔曲线的详细解释
    路径 – SVG | MDN
    XMLDOM

    1 赞 1 收藏 评论

    图片 6

    svg sprites类似于css sprites,将各个svg合并在一起。

    最主要的优点就是能减少页面的加载时间,优化开发流程,以及保持页面中图片元素的一致性。

    实践中我们可以把整块的svg放在head头部, 因此可以在一处地方更新svg即可,而不是让svg的代码块散落在文档的各个地方。

    <head>

    <meta charset=”utf-8″ />

    <title>svg</title>

    <svg version=”1.1″ xmlns=” xmlns:xlink=” width=”32″ height=”158″ viewBox=”0 0 32 158″>

    <!– SVG等省略  –>

    </svg>

    </head>

     

    SVG形状

    矩形 <rect>

    <rect x=”20″ y=”20″ rx=”20″ ry=”20″ width=”250″ height=”100″ style=”fill:red;stroke:black; stroke-width:5;opacity:0.5″/>

    解释:x为x坐标,y为y坐标;width 和 height 分别为形状的高度和宽度;rx 和 ry 属性可使矩形产生圆角。

    属性: fill 属性定义形状的填充颜色

    stroke 属性定义图形边框的颜色

    stroke-width 属性定义形状边框的宽度

    圆形 <circle>

    <circle cx=”100″ cy=”50″ r=”40″ stroke=”black” stroke-width=”2″ fill=”red”/>

    解释:cx 和 cy分别为圆点的 x 和 y 坐标;r为半径。

    椭圆<ellipse>

    <ellipse cx=”300″ cy=”150″ rx=”200″ ry=”80″ style=”fill:rgb(200,100,50); stroke:rgb(0,0,100);stroke-width:2″/>

    解释:cx 圆点的 x 坐标,cy 圆点的 y 坐标;rx 水平半径,ry 垂直半径。

    线<line>

    <line x1=”0″ y1=”0″ x2=”300″ y2=”300″ style=”stroke:rgb(99,99,99);stroke-width:2″/>

    解释:(x1,y1)为线条的开始坐标;(x2,y2)为线条的结束坐标。

    折线<polyline>

    <polyline points=”0,0 0,20 20,20 20,40 40,40 40,60″ style=”fill:white;stroke:red;stroke-width:2″/>

    解释:points 属性定义多边形每个角的 x 和 y 坐标。为了可读性,建议x与y坐标用逗号分开,每个角之间的坐标用空格分开。

    多边形<polygon>

    <polygon points=”220,100 300,210 170,250″ style=”fill:#cccccc; stroke:#000000;stroke-width:1″/>

    解释:points 属性定义多边形每个角的 x 和 y 坐标。

    路径<path>

    直线指令:

    M = moveto

    L = lineto

    H = horizontal lineto

    V = vertical lineto

    Z = closepath

    注释:以上所有命令均允许小写字母。大写表示绝对定位,小写表示相对定位。

    <svg>

    <path d=”M250 150 L150 350 L350 350 Z” />

    </svg>

    解释:该路径开始于位置 250 150,到达位置 150 350,然后从那里开始到 350 350,最后在 250 150 关闭路径。

    由于绘制路径的复杂性,建议使用 SVG 编辑器来创建复杂的图形。

    svg的贝塞尔曲线

    贝塞尔曲线指令:

    C = curveto

    S = smooth curveto

    Q = quadratic Belzier curve

    T = smooth quadratic Belzier curveto

    C三次贝塞尔曲线

    C x1 y1, x2 y2, x y (or c dx1 dy1, dx2 dy2, dx dy)

    S光滑三次贝塞尔曲线

    S x2 y2, x y (or s dx2 dy2, dx dy)

    Q二次贝塞尔曲线

    Q x1 y1, x y (or q dx1 dy1, dx dy)

    T光滑二次贝塞尔曲线

    T x y (or t dx dy)

    本文由澳门新葡8455最新网站发布于Web前端,转载请注明出处:基本形状转换那些事

    关键词: