关于SVG的一次小分享

255 阅读4分钟
  1. 是什么?
    SVG(Scalable Vector Graphics)是可缩放矢量图形的缩写,基于可扩展标记语言XML来描述二维矢量图形的一种图形格式,由W3C制定,是一个开放标准。

  2. 特点

    和Canvas相比,Canvas基于像素,提供2D绘制函数,是一种HTML元素类型,依赖于HTML,只能通过脚本来绘制图形,Canvas提供的功能比较原始,适合像素处理,动态渲染和大数据量绘制的应用场景;
    SVG为矢量,提供一系列图形元素(Rect, Path, Circle, Line …),还有完整的动画,事件机制,本身可以独立使用,也可以嵌入到HTML中,SVG很早就成为了国际标准,功能更完善,适合静态图片展示,高保真文档查看和打印的应用场景

    本质上是文本文件,体积较小,且不管放大多少倍都不会失真

  3. 坐标定位

    以页面的左上角为(0,0)坐标点,坐标以像素为单位,x轴正方向是向右,y轴正方向是向下

  4. 基本形状

       <svg width="600" height="250" version="1.1" xmlns="http://www.w3.org/2000/svg">
          <!--矩形-->
          <rect x="10" y="10" width="30" height="60" stroke="#9B7B56" fill="transparent" stroke-width="10"/>
          <!--圆角矩形-->
          <rect x="60" y="10" rx="10" ry="10" width="60" height="40" stroke="#FF9090" fill="transparent" stroke-width="5"/>
          <!--圆形-->
          <circle cx="180" cy="50" r="40" stroke="green" fill="#C3413D" stroke-width="5"/>
          <!--椭圆-->
          <ellipse cx="320" cy="28" rx="80" ry="20" stroke="#FFC302" fill="transparent" stroke-width="5"/>
          <!--直线-->
          <line x1="10" x2="50" y1="110" y2="150" stroke="orange" fill="transparent" stroke-width="5"/>
          <!--折线-->
          <polyline points="60 110 65 120 70115 75 130 80 125 85140 90 135 95 150 100 145" stroke="#9B7B56" fill="transparent" stroke-width="5"/>
          <!--多边形-->
          <polygon points="50 160 55 180 70180 60 190 65 205 50195 35 205 40 190 30 180 45 180" stroke="#FFC302" fill="transparent" stroke-width="5"/>
          <!--路径 -->
          <path d="M20,230 Q40,205 50,230 T90,230" fill="none" stroke="#9B7B56" stroke-width="5"/>
        </svg>
    

  5. 样式

    1. 轮廓stroke
      用于设置绘制对象线条的颜色,同时stroke有如下属性:

      1. stroke-width:设置轮廓的宽度
      2. stroke-linecap:设置轮廓结尾处的渲染方式,value有butt(直接一刀切断)、square(保留一点切断)、round(圆弧切断) 3个设置值
      3. stroke-linejoin:设置两条线之间的连接方式,value有miter(尖角连接)、round(圆弧连接)、bevel(切断连接) 3个设置值
      4. stroke-opacity:设置描边的不透明度
      5. stroke-dasharray:使用虚线呈现SVG形状的描边,需要提供一个数值数组来描述,定义破折号和空格的长度
      6. stroke-dashoffset:设置虚线模式中的开始点
    2. 填充fill

      用来描述SVG对象内部的颜色,除此还有如下两个属性:

      • fill-opacity:用于设置填充颜色的不透明度;

      • fill-rule:用于设置填充的方式,value有nonzero、evenodd 两个值

      • nonzero:从一个点往任何方向上绘制一条射线,形状中的路径每次穿过此射线时,如果路径从左到右穿过射线,则计数器加1,如果路径从右到左穿过射线,则计数器减1。计数器总数为0时候,则该点被认为在路径外。如果计数器非0,则该点被认为在路径内。

      • evenodd:从一个点往任何方向上绘制一条射线。每次路径穿过射线,计数器加1。如果总数是偶数,则点在外部。如果总计数为奇数,点在形状内。

    3. 变换transform
      此属性和css3中的transform相类似,有translate、rotate、scale、skew

    4. 还有其他的渐变linearGradient、遮罩mask、裁剪clipPath等属性

  6. 动画

  7. 使用方式

    1. 通过img标签
      新建svg文件,写入内容:

      <svg width="600" height="250" version="1.1" xmlns="http://www.w3.org/2000/svg">
         <rect x="10" y="10" width="30" height="60" stroke="#9B7B56" fill="transparent" stroke-width="10"/>
      </svg>
      //在html中引入
      <img src="./1.svg" style="width: 120px;height: 120px;">
      
    2. 内置在HTML中

      <svg width="600" height="250" version="1.1" xmlns="http://www.w3.org/2000/svg">
        <rect x="10" y="10" width="30" height="60" stroke="#909090" fill="transparent" stroke-width="10"/>
      </svg>
      
    3. 通过css background(svg转为base64)

      .logo { background: url("data:image/svg+xml;base64,[data]"); }
      
    4. 通过object(svg转为base64)

      <object type="image/svg+xml" data="data:image/svg+xml;base64,[data]"> fallback </object>
      
    5. c,d中的data来自:encodeURIComponent('<svg version="1.1" ...')

  8. 应用

    1. iconfont

      //HTML
      <p>1.iconfont</p>
      <div>  
        <img src="./add-iconfont.svg" alt="">  
        <img src="./radio.svg" style="width: 120px;height: 120px;"/> 
      </div>
      //add-iconfont.svg
      <svg width="120" height="120" version="1.1" xmlns="http://www.w3.org/2000/svg">  
        <!-- 横线 -->  
        <line x1="20" x2="90" y1="55" y2="55" stroke="#ccc" fill="#ccc" stroke-width="5" />  
        <!-- 竖线 -->  
        <line x1="55" x2="55" y1="20" y2="90" stroke="#ccc" fill="#ccc" stroke-width="5" />  
      <circle cx="54" cy="54" r="50" stroke="#ccc" fill-opacity="0" stroke-width="5" />
      </svg>
      //radio.svg 使用adobe lllustrator(AI)工具生成的svg文件
      <?xml version="1.0" encoding="utf-8"?><!-- Generator: Adobe Illustrator 24.0.1, SVG Export Plug-In . SVG Version: 6.00 Build 0)  --><svg version="1.1" id="图层_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"   viewBox="0 0 120 120" style="enable-background:new 0 0 120 120;" xml:space="preserve"><style type="text/css">  .st0{fill:#CCCCCC;}  .st1{fill:none;stroke:#CCCCCC;stroke-width:5;stroke-miterlimit:10;}</style><g>  <path class="st0" d="M60,15c24.81,0,45,20.19,45,45s-20.19,45-45,45S15,84.81,15,60S35.19,15,60,15 M60,10c-27.61,0-50,22.39-50,50    s22.39,50,50,50s50-22.39,50-50S87.61,10,60,10L60,10z"/></g><line class="st1" x1="47" y1="84" x2="47" y2="34"/><line class="st1" x1="87" y1="60" x2="47" y2="82"/><line class="st1" x1="48.5" y1="36" x2="88.5" y2="61"/></svg>
      
    2. loading动画

      //HTML
      <p>2.loading动画</p>  
      <div>    
        <svg width="200" height="200" version="1.1" xmlns="http://www.w3.org/2000/svg">      <g>        <circle cx="50" cy="60" r="40" stroke="#ccc" stroke-width="10" />        <circle id="circle" cx="50" cy="60" r="40" stroke="orange" stroke-width="10" />       </g>     </svg>   </div>
      //css    
      circle {      
       fill: transparent;    
      }    
      #circle {      
       stroke-dasharray: 250;      
       stroke-dashoffset: 250; /* pi*r*2 大约是250 */      
       animation: round 3s linear infinite;    
      }    
      /*       stroke-dasharray为一个参数时: 其实是表示虚线长度和每段虚线之间的间距   
           如:stroke-dasharray = '10' 表示:虚线长10,间距10,然后重复 虚线长10,间距10      
      stroke-dashoffset: offset:偏移的意思      
      这个属性是相对于起始点的偏移,正数偏移x值的时候,相当于往左移动了x个长度单位,负数偏移x的时候,相当于往右移动了x个长度单位。      
      需要注意的是,不管偏移的方向是哪边,dasharray 是循环的,也就是 虚线-间隔-虚线-间隔。     */    
      @keyframes round {      to {        stroke-dashoffset: 0;      }    }
      
    3. HUOLALA线条动画

          //HTML   
          <p>3.线性动画</p>    
          <!-- 设置了不同的stroke-dasharray和stroke-dashoffset动画参数,从而实现了这种效果 -->    
          <div>      
           <svg width="500" height="240" version="1.1" xmlns="http://www.w3.org/2000/svg">        
             <symbol id="text">          
              <text x="10" y="130" class="text" font-size="90">HUOLALA</text>       
             </symbol>        
              <g>         
               <!-- SVG <use>元素可以重用SVG文档中其他位置(包括 <g>元素和 <symbol>元素)的SVG形状 -->          
               <use xlink:href="#text" id="text1" class="text"></use>        
               </g>      
            </svg>    
           </div>
      
          //css
          #text1{         
            stroke: red;        
            fill:#fff;        
            stroke-dashoffset: 4;        
            stroke-dasharray: 0 35%;        
            font-size: 20px;        
            animation: animationText 5s linear infinite forwards;      
           }      
           @keyframes animationText {          
             0% {           stroke-dasharray: 0, 378;          }          
            40% {            stroke-dasharray: 378, 378;            fill: rgba(0, 0, 0, 0);            opacity: 1;          }          
            100% {            stroke-dasharray: 378, 378;            fill: red;            opacity: 0;          }      
           }
      
    4. 页面水印
      涉及MutationObserver API,可以查看另一篇观察元素博文
      juejin.cn/post/685512…

      (function () {      // svg 实现 watermark      function __svgWM({        container = document.body,        content = 'Rachel.yu',        width = '120px',        height = '120px',        opacity = '0.1',        fontSize = '15px',        zIndex = 1,      } = {}) {        const args = arguments[0]        const svgStr = `<svg xmlns="http://www.w3.org/2000/svg" width="${width}" height="${height}">          <text x="30" y="30" dy="12px"            text-anchor="middle"            stroke="orange"            stroke-width="1"            stroke-opacity="${opacity}"            fill="#f4f5f7"            transform="rotate(-45, 20 20)"            style="font-size: ${fontSize};">            ${content}          </text>        </svg>`        const base64Url = `data:image/svg+xml;base64,${window.btoa(          unescape(encodeURIComponent(svgStr))        )}`        const __wm = document.querySelector('.__wm')        const watermarkDiv = __wm || document.createElement('div')        const styleStr = `          position:absolute;          top:0;          left:0;          width:100%;          height:100%;          z-index:${zIndex};          pointer-events:none;          background-repeat:repeat;          background-image:url('${base64Url}')`        watermarkDiv.setAttribute('style', styleStr)        watermarkDiv.classList.add('__wm')        if (!__wm) {          container.style.position = 'relative'          container.insertBefore(watermarkDiv, container.firstChild)        }        const MutationObserver =          window.MutationObserver || window.WebKitMutationObserver        if (MutationObserver) {          let mo = new MutationObserver(function () {            const __wm = document.querySelector('.__wm')            // 只在__wm元素变动才重新调用 __svgWM            if ((__wm && __wm.getAttribute('style') !== styleStr) || !__wm) {              // 避免一直触发              mo.disconnect()              mo = null              __svgWM(JSON.parse(JSON.stringify(args)))            }          })          mo.observe(container, {            attributes: true,            subtree: true,            childList: true,          })        }      }      if (typeof module != 'undefined' && module.exports) {        //CMD        module.exports = __svgWM      } else if (typeof define == 'function' && define.amd) {        // AMD        define(function () {          return __svgWM        })      } else {        window.__svgWM = __svgWM      }    })();    __svgWM()
      
    5. 关于工具AI(adobe lllustrator)应用于出版、多媒体和在线图像的工业标准矢量插画的软件
      可以结合使用AI生成复杂矢量图,导出后使用
      示例代码地址:gitee.com/wisdom_QQ/l…

  9. 更厉害的动画-www.bootstrapmb.com/chajian/svg