内容简介:昨天公司培训canvas相关内容,然后培训完还留下一道homework,觉得挺有意思的,特来与大家分享分享。大家可以先不看我的实现,自己尝试试试,还是可以学到不少知识的。初看题目内容好像挺简单的,不就是个渐变嘛,看我的,翻翻万能的mdn查查canvas渐变api,
昨天公司培训canvas相关内容,然后培训完还留下一道homework,觉得挺有意思的,特来与大家分享分享。大家可以先不看我的实现,自己尝试试试,还是可以学到不少知识的。
题目内容
初看题目内容好像挺简单的,不就是个渐变嘛,看我的,翻翻万能的mdn查查canvas渐变api,
CanvasGradient
接口表示描述渐变的不透明对象。通过 CanvasRenderingContext2D.createLinearGradient()
或 CanvasRenderingContext2D.createRadialGradient()
的返回值得到. developer.mozilla.org/zh-CN/docs/…
好像哪不对,这两个渐变api只有线性渐变( LinearGradient
)和圆形渐变( RadialGradient
);而题目的意思是绘制一个扇形渐变,从0到360度的一个按照角度渐变的一个圆。然后我就问我们设计的小伙伴,怎么画这种圆锥渐变,毕竟 工具 画图和代码画图思路还是一样的,只不过过程不一样。然而现实是,ps自带角度渐变。
what?好吧,只能自己分析了。
分析题目
首先抛开渐变不谈,我们把颜色分成几块,每块一种颜色是不是就是我们熟悉的饼图。
那么我们运用微分的思想,把圆分成更多份的扇形,每种扇形一个颜色是不是就能实现题目的效果呢?我们来试试。
渐变色的实现
根据我们分析的思路,首先我们先从颜色等份开始做起,颜色常见的表示有四种十六进制颜色值(#000000),RGBA,HSL和HSV。
- HSL:H(hue)色相,S(saturation)饱和度,以及L(lightness)亮度
- HSV:H(hue)色相,S(saturation)饱和度,以及V(value)色调
- RGBA:Red(红色)Green(绿色)Blue(蓝色)和Alpha的色彩空间
色相(Hue):取值范围是从0°到360°正上方为0°的话,0度为R(红)色,120度为G(绿)色,240度为B(蓝)色
因此其实这个题目我认为用这个颜色值是最好的,算出来的渐变比较好看,不过这里我使用的是RGBA。感兴趣的小伙伴可以尝试用HSV写个渐变算法,用过角度变换。
亮度(lightness):最下面是0%也最暗,最上面是100%,最亮
饱和度(saturation):和亮度一样也是通过百分比表示的。
这些作为补充知识,这里我是使用的RGBA颜色。竟然颜色需要等分,那么我把颜色转换成RGBA,然后等分RGB三种颜色,每一份取三种颜色的差值的
/** * * @param startColor 指定起始颜色 * @param endColor 指定结束颜色 * @param step 划分渐变色区域数量 * @returns {Array} 返回渐变色数组 */ let gradientColor = function(startColor, endColor, step) { let startRGB = this.colorRgb(startColor); //转换为rgb数组模式 let startR = startRGB[0]; let startG = startRGB[1]; let startB = startRGB[2]; let endRGB = this.colorRgb(endColor); let endR = endRGB[0]; let endG = endRGB[1]; let endB = endRGB[2]; let sR = (endR - startR) / step; //总差值 let sG = (endG - startG) / step; let sB = (endB - startB) / step; let colorArr = []; for (let i = 0; i < step; i++) { //计算每一步的hex值 let hex = this.colorHex('rgb(' + parseInt((sR * i + startR)) + ',' + parseInt((sG * i + startG)) + ',' + parseInt((sB * i + startB)) + ')'); colorArr.push(hex); } return colorArr; }; 复制代码
我们把相应的十六进制颜色转换成RGB然后根据起始颜色和末颜色,计算出差值,即每份的颜色值。得出的数组就是梯度颜色的数组。相应的颜色装换函数如下:
// 将hex表示方式转换为rgb表示方式(这里返回rgb数组模式) gradientColor.prototype.colorRgb = function(sColor) { let reg = /^#([0-9a-fA-F]{3}|[0-9a-fA-F]{6})$/; sColor = sColor.toLowerCase(); if (sColor && reg.test(sColor)) { if (sColor.length === 4) { let sColorNew = "#"; for (let i = 1; i < 4; i += 1) { sColorNew += sColor.slice(i, i + 1).concat(sColor.slice(i, i + 1)); } sColor = sColorNew; } //处理六位的颜色值 let sColorChange = []; for (let i = 1; i < 7; i += 2) { sColorChange.push(parseInt("0x" + sColor.slice(i, i + 2))); } return sColorChange; } else { return sColor; } }; // 将rgb表示方式转换为hex表示方式 gradientColor.prototype.colorHex = function(rgb) { let _this = rgb; let reg = /^#([0-9a-fA-F]{3}|[0-9a-fA-F]{6})$/; if (/^(rgb|RGB)/.test(_this)) { let aColor = _this.replace(/(?:\(|\)|rgb|RGB)*/g, "").split(","); let strHex = "#"; for (let i = 0; i < aColor.length; i++) { let hex = Number(aColor[i]).toString(16); hex = hex < 10 ? 0 + '' + hex : hex; // 保证每个rgb的值为2位 if (hex === "0") { hex += hex; } strHex += hex; } if (strHex.length !== 7) { strHex = _this; } return strHex; } else if (reg.test(_this)) { let aNum = _this.replace(/#/, "").split(""); if (aNum.length === 6) { return _this; } else if (aNum.length === 3) { let numHex = "#"; for (let i = 0; i < aNum.length; i += 1) { numHex += (aNum[i] + aNum[i]); } return numHex; } } else { return _this; } }; 复制代码
更多颜色转换方法可以参考张鑫旭大大的文章 www.zhangxinxu.com/wordpress/2…
然后我们可以直接这样调用:
let color_list = new gradientColor("#706caa", "#f2f2b0", 360); console.log(color_list); 复制代码
这样控制台我们就能看到我们计算出的渐变颜色数组了
绘制圆
心急的小伙伴可能想画圆还不简单分分钟画一个圆
context.beginPath(); context.arc(150, 75, 50, 0, Math.PI * 2); context.stroke(); 复制代码
但是如果这么画圆,怎么填充渐变色呢,想想前面的饼图,我们把饼图分成更多份,分成360份呢?是不是就相当于有很多线段,起始点一样,长度一样,围绕起始点排列成一个圆!看到这里聪明的你应该就想到该怎么做了吧。是的,用画线的方式,来画圆,可能你觉得不可思议,moveTo和lineTo怎么可能画圆呢?下面我们就来分析如何画一个圆。
大家还记得圆的极坐标方程吗,我给大家回顾回顾;
圆的极坐标公式:ρ²=x²+y²,x=ρcosθ,y=ρsinθ tanθ=y/x,(x不为0)
下面的动图显示的很详细,圆上任意一点与圆心的线段都是可以通过极坐标表示出来的,并且如果我们每画一根线都保存下面,画满一圈后不就是一个填充圆吗。
通过上面的分析,我们来写代码
var center = [200, 200]; //圆的中心 var r = 100; // 圆的半径 ctx.moveTo(center[0] + r, center[1]); //先把起始点移到圆上 for (var i = 0; i < 360; i++) { var ii = i * Math.PI / 180; //角度转弧度 ctx.lineWidth = 2; var x = r + r * Math.cos(ii); //圆上任一点的横坐标 var y = r - r * Math.sin(ii); //圆上任一点纵坐标 ctx.lineTo(x, y); } ctx.stroke(); 复制代码
这样我们就能看到最后的结果了;
完美,我们通过moveTo和lineTo画出了一个圆,细心的小伙伴应该看到,右边有一点缺失,没连上,那是应为我们把圆分为360份但是,最后一份应该与第一份相连,也就是closePath,因此我们循环多加一次,361次就可以闭合了;
我们现在知道画圆了,那么同理我们把起始点移动到圆形,并且把圆心和圆上每一份的点连起来,不就是一个实心圆了吗。
var center = [200, 200]; //圆的中心 var r = 100; // 圆的半径 for (var i = 0; i < 360; i++) { var ii = i * Math.PI / 180; //角度转弧度 ctx.save(); ctx.beginPath(); ctx.lineWidth = 2; ctx.moveTo(center[0], center[1]); //移动路径到圆心 var x = r + r * Math.cos(ii); //圆上任一点的横坐标 var y = r - r * Math.sin(ii); //圆上任一点纵坐标 ctx.lineTo(x, y); ctx.closePath(); ctx.stroke(); } 复制代码
这样我们就得到一个实心圆,一个由360根线组成的圆
那么对应的,我们把每根线的颜色也由前面我们计算的渐变色来对应上,代码也很简单;
var center = [200, 200]; //圆的中心 var r = 100; // 圆的半径 for (var i = 0; i < 360; i++) { var ii = i * Math.PI / 180; //角度转弧度 ctx.save(); ctx.beginPath(); ctx.lineWidth = 2; ctx.strokeStyle = color_list[i]; ctx.moveTo(center[0], center[1]); //移动路径到圆心 var x = r + r * Math.cos(ii); //圆上任一点的横坐标 var y = r - r * Math.sin(ii); //圆上任一点纵坐标 ctx.lineTo(x, y); ctx.closePath(); ctx.stroke(); } 复制代码
完整代码请看这里canvas圆锥渐变
很完美,一切都按我们设想的一样。如果读者有更好的方法,可以给我留言,一起学习交流交流。
本着只是做个题目,但是发现很有意思,后续我会封装一下,做成一个渐变库,支持各种渐变。
参考资料
- css角度渐变conic-gradient: www.cnblogs.com/coco1s/p/70…
- www.zhangxinxu.com/wordpress/2…
- developer.mozilla.org/zh-CN/docs/…
以上就是本文的全部内容,希望本文的内容对大家的学习或者工作能带来一定的帮助,也希望大家多多支持 码农网
猜你喜欢:- iOS WHGradientHelper(线性、径向渐变;渐变动画;Lable字体渐变及动画)
- Flutter 中渐变的高级用法
- 沉浸式渐变图片轮播器
- CSS3 渐变(Gradients)
- java – 不同dpi的径向渐变
- 简易的iOS导航栏颜色渐变方案
本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们。
Paradigms of Artificial Intelligence Programming
Peter Norvig / Morgan Kaufmann / 1991-10-01 / USD 77.95
Paradigms of AI Programming is the first text to teach advanced Common Lisp techniques in the context of building major AI systems. By reconstructing authentic, complex AI programs using state-of-the-......一起来看看 《Paradigms of Artificial Intelligence Programming》 这本书的介绍吧!