Canvas画图-一个比想象中更骚气的圆(渐变圆环)

之前介绍了Canvas画图基础,这篇介绍一下画一个带渐变效果的圆。

一个渐变的圆环

渐变色应用广泛,和圆环结合做进度条非常酷,今天我们就来画一个这样的圆环:

Canvas渐变

Canvas画图基础中我们知道给canvas上色主要是ctx.fillStylectx.strokeStyle方法,这里是圆环,所以主要讲strokeStyle方法,fillStyle方法也同样适用。

看一下上面那个圆,像把一个线性的渐变给『掰弯』成一个圆。Canvas中有线性渐变的支持,我们可以试一下:

var canvas = document.getElementById("canvas");
var ctx = canvas.getContext('2d');
ctx.lineWidth = 7;

ctx.beginPath(); // 开一条新路
ctx.moveTo(170, 120);

var grd=ctx.createLinearGradient(0,0,170,0);
grd.addColorStop("0","black");
grd.addColorStop("0.3","magenta");
grd.addColorStop("0.5","blue");
grd.addColorStop("0.6","green");
grd.addColorStop("0.8","yellow");
grd.addColorStop(1,"red");

ctx.strokeStyle = grd;
ctx.arc(120, 120, 50, 0 ,Math.PI*2);
ctx.stroke(); // 画圆

画出来的效果:

  • ctx.createLinearGradient就是创建一个线性渐变的对象,其中前两个参数是起始点的x,y坐标,后两个参数是结束点的x,y坐标,这里是一个水平的线性渐变。
  • grd.addColorStop就是设置渐变点,类似css3渐变中的color-stop
  • 设置完渐变的对象,把渐变对象用于strokeStyle就可以实现渐变效果了。

再加点动画上去,方便后面做进度条:

var canvas = document.getElementById("canvas1");
var ctx1 = canvas.getContext('2d');
//
// 中间设置渐变参数的代码一样
//
function draw(ctx, x) {
    ctx.clearRect(0, 0, 300, 300);
    ctx.beginPath();
    ctx.strokeStyle = grd;//'#ff4444';
    if (x < Math.PI*2) {
        x += Math.PI/100;
    } else {
        x = 0;
    }
    ctx.arc(80, 80, 50, 0, x, false); // 画圆
    ctx.stroke();
    requestAnimationFrame(function () {
        draw(ctx, x);
    });
}

requestAnimationFrame(function () {
    draw(ctx1, 0);
});

现在动画有了,渐变也有了,但是一个最大的问题是,这个画出来的是一个从左到右的渐变,上下颜色是对称的。而我们想要的效果是上下非对称的。

非对称的渐变圆环

Canvas提供了线性渐变和径向渐变(就是从圆心往外渐变,一个圆周上的颜色相同),二者都无法满足我们设计师画出的这个骚气的圆。

于是,这里要借助另一个东东,ctx.createPattern

关于createPattern方法的定义如下:

createPattern() 方法在指定的方向内重复指定的元素。元素可以是图片、视频,或者其他 canvas 元素。被重复的元素可用于绘制/填充矩形、圆形或线条等等。

上面说可以指定用图片来绘制圆形,斯国一。

来上代码:

var canvas = document.getElementById("canvas2");
var ctx2 = canvas.getContext('2d');
ctx2.lineWidth = 8;
ctx2.lineCap="round";

var img;
img = new Image();
img.src = "./bg.png";

if (img.complete) {
   setImageFill();
} else {
   img.onload = setImageFill;
}

var newFill = null;
function setImageFill() {
    newFill = ctx2.createPattern(img, 'no-repeat');
    drawNew(ctx2, 0);
}

function drawNew(ctx, x) {
    ctx.clearRect(0, 0, 300, 300);
    ctx.beginPath();
    ctx.strokeStyle = newFill;
    if (x < Math.PI*2) {
        x += Math.PI/100;
    } else {
        x = 0;
    }
    ctx.arc(50, 50, 46, 0, x, false);
    ctx.stroke();
    requestAnimationFrame(function () {
        drawNew(ctx, x);
    });
}

画出来的效果:

代码很多有几点需要注意:

  1. 首先是加载图片,要等图片加载完之后再去进行绘制,也可以考虑将图片base64进去;
  2. ctx2.createPattern(img, 'no-repeat')创建Pattern的时候不对图片做repeat;
  3. ctx.arc(50, 50, 46, 0, x, false);画圆的时候需要注意 如果想画出来的半径为50的话,需要用50减去描边宽度的一半,也就是50-8/2 这个就是这里半径设置46的由来。因为描边是把线放在中间然后往两边扩展来描,所以设置lineWidth为8的时候,实际我们看到的描边是4;
  4. ctx2.lineCap="round";设置描边的两头是圆形。

另外我们用的图片是这样的:

如果考虑到想支持各种Size可以现把图片画到另一个canvas上,做个resize。

var bg = $('<canvas>')[0];
var size = 100;
bg.width = size;
bg.height = size;
bg.getContext('2d').drawImage(img, 0, 0, size, size);

至此,一个如此骚气的圆环就画完了。

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

tips:移动端解决Canvas锯齿问题

Canvas画出来的实际上是位图,在移动端高清屏横行,我们需要根据window.devicePixelRatio来画一个更大的Canvas,然后再缩小,原理类似于移动端使用双倍图,这样可以很大程度上解决锯齿问题,白色背景下基本看不出来。不过在黑色背景下细看还是很发现有一点锯齿。

//Variables global to the chart
var width = context.canvas.width;
var height = context.canvas.height;

//High pixel density displays - multiply the size of the canvas height/width by the device pixel ratio, then scale.
if (window.devicePixelRatio) {
    context.canvas.style.width = width + "px";
    context.canvas.style.height = height + "px";
    context.canvas.height = height * window.devicePixelRatio;
    context.canvas.width = width * window.devicePixelRatio;
    context.scale(window.devicePixelRatio, window.devicePixelRatio);
}

参考

http://www.w3school.com.cn/tags/canvas_createlineargradient.asp

http://www.w3school.com.cn/tags/canvas_createpattern.asp

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

发表于

我来说两句

0 条评论
登录 后参与评论

相关文章

来自专栏codelang

用kotlin来实现一个饼图

1062
来自专栏Coco的专栏

谈谈一些有趣的CSS题目(三)-- 层叠顺序与堆栈上下文知多少

1645
来自专栏HTML5学堂

CSS3渐变,就是这么玩

HTML5学堂(码匠):渐变背景是一直在页面中常见的元素之一,但是在之前所有的渐变背景都是通过设计师通过图形软件设计出来的背景图。其实这种方法比较麻烦,需要设计...

3765
来自专栏何俊林

Android开发之贝塞尔曲线进阶篇(仿直播送礼物,饿了么购物车动画)

今天来自李晨玮分享的直播礼物效果Demo。对于直播中送车,点赞都有借鉴意义。李晨玮的简书为:http://www.jianshu.com/u/b2df0a5ea...

5378
来自专栏程序你好

CSS盒子(Box)模型入门

无论您是CSS的新手还是经验丰富的老手,了解和理解box模型都很重要。让我们更好地了解它。

1402
来自专栏菜鸟前端工程师

html+css学习笔记017-H5新背景属性0颜色0倒影0遮罩

1932
来自专栏Android知识点总结

D6-Android绘图之一言不合画个表

1214
来自专栏Jack的Android之旅

自定义天气显示温度变化的LinearChart控件

这次发表的是前几个月搞定的一个自定义控件,那时自己在写一个小的查看天气的软件,在这过程中就涉及了显示天气变化的折线图,一开始想用一些画图框架来解决问题,不过考虑...

2511
来自专栏向治洪

自定义绘制柱形图

设计思路: 1.画柱状图  2.画竖线  3.画顶部横线  4.画文字 1.画柱状图 画柱状图的方法很简单,就是使用canvas.drawRect...

2287
来自专栏葬爱家族

H5和微信小游戏 Canvas API 整理前言

这段时间闲下来,系统学习了微信小程序和微信小游戏,发现还是挺有意思的。现在微信小游戏的开发都离不开游戏引擎,用原生小游戏开发工具开发的很少很少。但是毕竟我不是专...

7884

扫码关注云+社区

领取腾讯云代金券