一个比想象中更骚气的圆-svg实现

之前写了一篇Canvas画图-一个比想象中更骚气的圆(渐变圆环),其实SVG也可以实现类似的效果,而且两者api惊人的相似。

关于SVG

SVG是一种矢量图形,在图形改变尺寸的情况下质量不会损失。

相比canvas,svg有一个很大的优势就是内联进html的时候可以像操作dom一样操作svg,这样做起动画来非常方便。

本文不会介绍svg的基础知识,不过也没涉及什么复杂的东西,基于xml的语法还是比较好理解的。

期望实现的效果和Canvas一样是颜色非对称的沿着圆周进行渐变。

SVG的渐变

和之前讲canvas一样,svg也有线性渐变和径向渐变,这里主要讲线性渐变,径向渐变api差别不大。

老规矩,上代码:

<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"
     width="595.28px" height="841.89px" viewBox="0 0 595.28 841.89" enable-background="new 0 0 595.28 841.89" xml:space="preserve">
<linearGradient id="SVGID_1_" gradientUnits="userSpaceOnUse" x1="213.0787" y1="303.3227" x2="384.1807" y2="303.3227">
    <stop  offset="0.107" style="stop-color:#00A29A"/>
    <stop  offset="0.1301" style="stop-color:#28A891"/>
    <stop  offset="0.1968" style="stop-color:#76B874"/>
    <stop  offset="0.2649" style="stop-color:#9FC758"/>
    <stop  offset="0.3339" style="stop-color:#BBD338"/>
    <stop  offset="0.4041" style="stop-color:#CDDA06"/>
    <stop  offset="0.4761" style="stop-color:#D7DE00"/>
    <stop  offset="0.5527" style="stop-color:#DAE000"/>
    <stop  offset="0.9265" style="stop-color:#F39800"/>
</linearGradient>
<circle fill="none" stroke="url(#SVGID_1_)" stroke-width="16" stroke-miterlimit="10" cx="306.385" cy="355.208" r="77.551"/>
</svg>

这个是直接从AI里导出的,也可以尝试使用别的SVG编辑器,其中linearGradient就是定义一个线性渐变,和Canvas中的ctx.createLinearGradient一个意思,stop标签就类似Canvas中的grd.addColorStop方法,同样是设置渐变点,这里给这个渐变设置了一个id,id="SVGID_1_"

下面的那个circle标签就是定义一个圆,cx,cy,r分别是圆心坐标和半径,fill和stroke分辨对应canvas中的fillStyle和strokeStyle,stroke-width对应canvas中的lineWidth。

和之前给canvas版的骚气圆环用渐变一样,svg的实现也是定义一个线性渐变,然后让圆用这个渐变来描边stroke="url(#SVGID_1_)"

实际上出来的效果,和Canvas渐变是异曲同工,即使svg有路径的概念,渐变也没有按照路径来渐变,而是和canvas一样从左到右,上下颜色是对称的。

如图:

SVG非对称的渐变圆环

Canvas的非对称渐变圆环我们借助了ctx.createPattern,google一下,svg里同样有个<pattern>

这里为了方便,我把要用到的图片base64进去了,实际上用线上图片也可以。

代码如下,省略base64的内容:

<svg height="108" width="108" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" version="1.1">
  <defs>
    <pattern id="fill-img" patternUnits="userSpaceOnUse" width="108" height="108">
      <image xlink:href="data:image/png;base64,xxxxxxxxxxx"
        x="0" y="0" width="108" height="108">
      </image>
    </pattern>
  </defs>
   <circle fill="none" stroke="url(#fill-img)" stroke-width="10" stroke-miterlimit="1" cx="54" cy="54" r="49" >
   </circle>
</svg>

和canvas一样,定一个<pattern>,然后给圆描边的时候用这个东东。

出来的效果:

看了之前Canvas的文章的话,svg代码还是比较简单的,然后我们来加个动画。

SVG动画

SVG动画实际上是让路径动起来,要让路径动起来首先要了解stroke-dasharray和stroke-dashoffset这两个属性。

  • stroke-dasharray 表示用虚线描边。可选值为none, , inherit。
    • none 表示不用虚线描边
    • inherit 表示继承
    • 可就厉害了,基本上路径动画都需要用到,这是一个逗号或者空格分隔的数值列表,第一个值表示线段的长度,第二个值表示线段间空白的长度,举个例子stroke-dasharray="308 1000"中,308表示虚线中的线段的长度,而1000表示两个线段间的长度是1000px。其实这个dasharray可以不只两个值,可以有很多个,会循环依次用到线段和空白之间。
  • stroke-dashoffset 表示虚线的起始偏移。可选值为:, , inherit. 分别表示:百分比值,长度值,继承。这个dashoffset和上面那个结合起来用,一般来说虚线的第一段是实线线段,如果我想要第一段是空白怎么办,设置这个dashoffset就可以了。

现在就来试一试,只需要修改circle元素的代码就可以了:

<circle fill="none" stroke="url(#fill-img)" stroke-width="10" stroke-miterlimit="1" cx="54" cy="54" r="49"  stroke-dasharray="308 1000" stroke-dashoffset="100">
</circle>

如下图:

缺的那一块就是因为虚线的空白部分被移出来了,这里r设置49和Canvas的原理一样,想画看起来半径54的圆,需要用54减去描边宽度的一半,54-10/2,而这里stroke-dasharray的第一个数,我这里设置的是圆的周长,2Math.PI49=307.8760800517997 约等于308啦,至于第二个数,设大一点就好,大过圆的周长就可以了。

想要做动画就不断的改变stroke-dashoffset的值让虚线的空隙动起来就可以了,svg本身支持属性的动画,稍微改动一下代码:

<circle fill="none" stroke="#e5ece7" stroke-width="10" stroke-miterlimit="1" cx="54" cy="54" r="49"/>

<circle fill="none" stroke="url(#fill-img)" stroke-width="10" stroke-miterlimit="1" cx="54" cy="54" r="49"  stroke-dasharray="308 1000" stroke-dashoffset="308" stroke-linecap="round" transform="rotate(-88 54 54)">
    <animate attributeName="stroke-dashoffset" begin="0s" dur="1.5s" from="308" to="0" repeatCount="indefinite" />
</circle>

这里我把circle的初始stroke-dashoffset改成308,表示从空白开始,animate标签中attributeName表示动画属性是stroke-dashoffset,begin表示开始的延时,dur表示时间整个动画的时间,frometo表示初始值和最终值,repeatCount表示重复次数,这里是无限次。整体和CSS3动画还是很像的。

这里还有一个stroke-linecap="round"和Canvas的ctx2.lineCap="round";作用一样,是设置描边的两头是圆形。

另外我还在上面加了一个圆,用来做底色,同时给做动画的圆做了一个旋转transform="rotate(-88 54 54)"用来改变起始点。

效果如下:

SVG动画2

大致了解了SVG动画的原理之后,其实SVG还可以用CSS3的transition和animation来做动画。

添加css:

.animate-item {
    transition: stroke-dashoffset 1.5s ease;
}

添加js:

setTimeout(function(){
    $(".animate-item").css("stroke-dashoffset",94);
}, 1000)

前面说过svg联进html的时候可以像操作dom一样操作svg,这里修改了一下圆环,给了一个class.animate-item

修改圆环:

<circle class="animate-item" fill="none" stroke="url(#fill-img)" stroke-width="10" stroke-miterlimit="1" cx="54" cy="54" r="49"  stroke-dasharray="308 1000" stroke-dashoffset="308" stroke-linecap="round" transform="rotate(-88 54 54)">
</circle>

效果如下:

至此,骚气圆环SVG版也就完成了,总体上来说svg的实现更简单,做动画的代码也比较少,相对于canvas需要占用js线程进行一定量的计算来说,svg的性能要好一些。

不过svg在android4.3以上才有比较好的支持,相对来说canvas的支持就比较好了。

完整代码: https://github.com/bob-chen/canvas-demo/blob/master/basic/gradient-svg.html

参考

http://www.zhangxinxu.com/wordpress/2015/07/svg-circle-loading/

http://designmodo.com/svg-patterns/

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

发表于

我来说两句

0 条评论
登录 后参与评论

相关文章

来自专栏用户2442861的专栏

python数字图像处理(12):基本图形的绘制

skimage.draw.set_color(img, coords, color)

1742
来自专栏从零开始学 Web 前端

从零开始学 Web 之 CSS(二)文本、标签、特性

当多个样式作用于同一个(同一类)标签时,样式发生了冲突,总是执行后边的代码(后边代码层叠前边的代码)。和标签调用选择器的顺序没有关系。

1026
来自专栏知晓程序

开发 | 「小游戏」开发难?不妨先从 2048 入手试试看

最近流行微信「跳一跳」小游戏,我也心血来潮写了一个微信小程序版 2048,本篇文章主要分享实现 2048 的算法以及注意的点,一起来学习吧!

1404
来自专栏九彩拼盘的叨叨叨

SVG 直线路径写法示例

大写字母表示到后面值为绝对值,小写字母表示后面值为相对当前点的值 画一条起点是(10, 10)终点点是 (20, 30) 的线

924
来自专栏小灰灰

Java 实现图片合成

图片合成 利用Java的绘图方法,实现图片合成 在开始之前,先定一个小目标,我们希望通过图片合成的方式,创建一个类似下面样式的图片 ? I. 设计思路 首先...

1.4K10
来自专栏HTML5学堂

原生JS | 导航底部横线跟随鼠标缓动

HTML5学堂(码匠):在上周当中,我们用jQuery实现了 - 在导航底部存在一条横线,跟随着鼠标缓动到相应导航项 - 的特效,今天我们来讲讲原生JS的实现方...

5808
来自专栏林德熙的博客

WPF 在 DrawingContext 的 push 如何使用

如果在一个 DrawingContext 画出一个 DrawingVisual ,如何修改这个 DrawingVisual 的大小,对他进行变换?

1591
来自专栏Golang语言社区

【Go 语言社区】HTML5 canvas验证码识别

canvas 的历史这个 HTML 元素是为了客户端矢量图形而设计的。它自己没有行为,但却把一个绘图 API 展现给客户端 JavaScript 以使脚本能够把...

4714
来自专栏前端萌媛的成长之路

CSS选择器的优先级

1694
来自专栏向治洪

android绘制虚线

有的时候我们需要一种虚线效果,比如图片的边框,愤怒的小鸟的飞翔路径,那么怎么绘制这些虚线呢?方法很多,目前我觉得好的有两种: 一、自己创建模式,一个点一个点的绘...

2466

扫码关注云+社区

领取腾讯云代金券