前端SVG实现各式图片和动画

SVG介绍

SVG(Scable vector Graphics 可缩放矢量图形), 是一种使用XML来描述2D图形的语言; 因为是基于XML,那么svg DOM中的每一个元素都可以,绑定上javascript事件处理器; 在svg中每一个绘制的图形都被视为对象,svg元素的属性发生变化那么浏览器也会重新渲染图形的。

注意:

1、SVG并不属于html5专有内容,在html5之前就有SVG。

2、SVG文件的扩展名是".svg"。

3、SVG绘制的图像在图片质量不下降的情况下被放大。

4、SVG图像经常在网页中制作小图标和一些动态效果图。

 

在html5中使用svg必须使用 <svg> 标签,它的其中一个强大之处在于<path>标签可以表示任意的矢量形状,利用好这个path可以做出很多传统html/css做不出来的效果。

通过<path>路径元素的d属性,分析如下:

(1).d属性值是两个图形绘制命令,分别以字母开头。

(2).每一组命令中的参数用逗号分隔,命令与命令之间可以用空格或者换行分隔。

(3).M是Move to的缩写,表示将笔触移动到指定坐标,也就是从指定位置开始绘制。

(4).L是Line的缩写,表示绘制一条直线,L后面的参数表示直线的终点坐标。

(5).命令区分大小写,这一点需要特别注意,大写表示绝对坐标,小写表示相对坐标。

(6).绝对坐标表示以坐标系原点(0,0)为参考点,相对坐标表示当前坐标值相对上一个控制点坐标的变化。

对上述代码的坐标分析如下:

(1).M50,50:M是大写,说明是绝对坐标,相对于当前用户坐标系原点进行定位。

(2).l150,50:l是小写,相对的是M50,50,此点的绝对坐标位置就是(50+150,50+50)。

主要命令列表如下:

(1).M(m):将画笔移动到点指定坐标。

(2).L(l):绘制一条直线。

(3).H(h):绘制一条水平线段。

(4).V(v):绘制一条垂直线段。

(5).A(a):绘制一段圆弧。

(6).C(c):绘制三次赛贝尔曲线。

(7).S(s):特殊版本的三次赛贝尔曲线。

(8).Q(q):绘制二次赛贝尔曲线。

(9).T(t):绘制特殊版本二次赛贝尔曲线。

(10).Z(z):绘制闭合图形,如果不指定z命令,那么不是绘制闭合图形,而是绘制线段。

1. 做路径动画

<svg viewBox="0 0 2706 2048" width="120" height="66" class="svg-hand">
    <g id="hand">
        <!--手上的圆圏-->
        <circle cx="370" cy="90" r="210" fill="yellow"></circle>
        <!--手的形状-->
        <path d="..."></path>
    </g>
    <!--动画路径-->
    <path id="animation-hand-arc" d="M-514,665c0,0,1378.463-1138.762,2891,0" stroke="transparent" fill="transparent"/>
    <!--动画设置-->
    <animateMotion id="arcmove" xlink:href="#hand" dur="1s" begin="0" fill="freeze" repeatCount="1">
        <mpath xlink:href="#animation-hand-arc" />
    </animateMotion>
</svg>

animateMotion标签,通过它的mpath指定一个动画的路径

2. 实现不规则形状的点击

<svg width="580" height="400" xmlns="http://www.w3.org/2000/svg">
 <!-- Created with Method Draw - http://github.com/duopixel/Method-Draw/ -->
​
  <path onclick='myclick()' stroke="#56ffaa" id="svg_9" d="m173.396883,254.591074c-4.797775,-2.156114 1.462953,-6.46692 3.833221,-8.373818c1.596577,-1.468559 -9.1501,0.206007 -4.612947,-4.891952c4.977919,-4.164754 3.097524,-11.210596 -1.87824,-14.485767c-6.847691,-4.607715 -15.633716,-8.551275 -18.163505,-17.155134c-2.557992,-5.358961 3.508329,-11.003041 -0.393495,-15.842324c-3.140618,-6.283297 0.528516,-12.835459 2.809148,-18.655957c1.048806,-8.051478 -5.37599,-14.418665 -8.909232,-21.0334c-4.374957,-6.32119 -6.896883,-13.686831 -7.259278,-21.362704c-0.951437,-3.276388 0.101487,-8.364528 3.900756,-3.947296c7.956237,6.348832 16.690848,12.373108 22.259278,21.063127c1.054047,3.138905 5.274647,12.236351 5.510329,3.998095c0.110382,-11.322907 3.580615,-23.672231 12.472816,-31.260015c6.04832,-5.492224 9.310155,4.124439 9.592366,9.011263c1.574265,9.615218 -1.035268,19.150273 -3.943199,28.233152c-1.067531,4.221106 -3.847653,15.788477 4.081291,11.523392c18.265441,-7.027611 40.395378,0.353271 52.292699,15.450067c5.469094,7.309682 7.864207,16.700923 7.810134,25.718097c-2.816157,5.297548 7.647371,-0.09924 3.855897,6.012534c-2.232001,6.77039 -8.538279,10.444081 -12.955643,15.554332c-4.49503,4.094914 -1.159853,12.850016 -8.59333,14.140072c-10.846346,3.33214 -22.235901,4.791741 -33.527327,5.641328c-6.318649,1.290056 -9.385122,-5.91026 -3.328921,-8.903615c2.903508,-4.460576 11.210362,-4.773166 13.678493,-5.479802c-5.898027,0.575096 -13.171764,-1.823925 -18.141722,1.816237c-3.009867,4.869309 -5.420508,11.278377 -11.732233,12.668223c-2.836476,0.785072 -5.752881,1.414646 -8.65735,0.56186l-0.000004,0.000004z" stroke-width="1.5" fill="#007fff"/>
​
</svg>
   <script type="text/javascript">
function myclick(){
console.log(222);
}

 

3. 沿着路径拖拽的交互

<svg class="volumn-controller" width="580" height="400" xmlns="http://www.w3.org/2000/svg">
    <path class="volumn-path" stroke="#000" d="m100,247c93,-128 284,-129 388,6" opacity="0.5" stroke-width="1" fill="#fff"/>
    <circle class="drag-button" r="12" cy="247" cx="100" stroke-width="1" stroke="#000" fill="#fff"/>
 </g>
</svg>
​
<script type="text/javascript">
  let $volumnController = document.querySelector('.volumn-controller'),
    $volumnPath = $volumnController.querySelector('.volumn-path');
  // 得到当前路径的总长度
  let pathTotalLength = $volumnPath.getTotalLength() >> 0;
  let points = [];
  // 起始位置为长度为0的位置
  let startX = Math.round($volumnPath.getPointAtLength(0).x);
  // 每隔一个像素距离就保存一下路径上点的坐标
  for (let i = 0; i < pathTotalLength; i++) {
    let p = $volumnPath.getPointAtLength(i);
    // 保存的坐标用四舍五入,可以平衡误差
    points[Math.round(p.x) - startX] = Math.round(p.y);
  }
​
  let $dragButton = $volumnController.querySelector('.drag-button'),
    // 得到起始位置相对当前视窗的位置,相当于jQuery.fn.offset
    dragButtonPos = $dragButton.getBoundingClientRect();
  function movePoint (event) {
    // 当前鼠标的位置减去圆心起始位置就得到移位偏差,12是半径值,这里先直接写死
    let diffX = event.clientX - Math.round(dragButtonPos.left + 12);
    // 需要做个边界判断
    diffX < 0 && (diffX = 0);
    diffX >= points.length && (diffX = points.length - 1);
    // startX是在上面的代码得到的长度为0的位置
    $dragButton.setAttribute('cx', diffX + startX);
    // 使用points数组得到y坐标
    $dragButton.setAttribute('cy', points[diffX]);
  }
  $dragButton.addEventListener('mousedown', function (event) {
    document.addEventListener('mousemove', movePoint);
  });
  document.addEventListener('mouseup', function () {
    document.removeEventListener('mousemove', movePoint);
  });
</script>

 

4. 路径的变形动画

<svg viewBox="0 0 10 10" class="svg-1">
  <path d="M2,2 L8,8" />
</svg>
<style>
.svg-1:hover path {
  d: path("M8,2 L2,8");
}
path {
    transition: d 0.5s linear;
}
</style>

 

5. 结合clip-path做遮罩效果

使用clip-path + svg的路径能够做出任意形状遮罩,如下做一个心形的:

<div style="width:200px;height:200px">
    <img src="photo.png" alt style="width:100%">
</div>
<svg xmlns="http://www.w3.org/2000/svg" width="0" height="0">
    <clipPath id="heart" clipPathUnits="objectBoundingBox">
        <path transform="scale(0.0081967, 0.0101010)" d="m61.18795,24.08746c24.91828,-57.29309 122.5489,0 0,73.66254c-122.5489,-73.66254 -24.91828,-130.95562 0,-73.66254z"/>
    </clipPath>
</svg>
​
<style>
img {
    clip-path: url("#heart");
}
</style>

 

为了让这个path刚好能撑起div容器宽度的100%,需要设置:
clipPathUnits="objectBoundingBox"

这样会导致d属性里面的单位变成比例的0到1,所以需要把它缩小一下,原本的width是122,height是99,需要需要scale的值为(1 / 122, 1 / 99)。这样就达到100%占满的目的,如果一开始d属性坐标比例就是0到1,就不用这么搞了。

另外clip-path使用svg的path不支持变形动画。

做一个路径动画、不规则形状的点击、沿着路径拖拽、路径的变形动画以及和clip-path做一些遮罩效果。可以说svg的path效果还是很强大的,当你有些效果用html/css无法实现的时候,不妨往svg的方向思考。

 

  • SVG和Canvas的区别

    Canvas

    1.依赖分辨率 2.不支持事件绑定 3.弱的文本渲染能力 4.能够以.png和.jpg的格式保存结果图像 5.最适合图像密集的游戏,其中许多对象将会被频繁重绘

    SVG

    1.不依赖分辨率 2.支持事件处理器 3.最适合带有大型渲染区域的应用程序(比如谷歌地图) 4.复杂度高会减慢渲染速度(任何过度使用DOM的应用都不快) 5.不适合游戏应用

 

  • 2
    点赞
  • 17
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值