近期完成的下图的实际效果,跟大伙儿共享1下
倘若大家要画下图曲线图的动漫
假如每次都画1条短线联接起来,以下图被分为5段
再看10段
如果被分的段数充足多时每次画1段就很像曲线图运动轨迹了
2次贝赛尔曲线图
/** * 2次贝塞尔曲线图动漫 * @param {Array<number>} start 起始点座标 * @param {Array<number>} 曲度点座标(也便是拐弯的点,并不是精确的座标,只是大概的方位) * @param {Array<number>} end 终点站座标 * @param {number} percent 绘图百分比(0⑴00) */ function drawCurvePath(start, point, end, percent){ ctx.beginPath(); //刚开始画线 ctx.moveTo(start[0], start[1]); //画笔挪动到起始点 for (var t = 0; t <= percent / 100; t += 0.005) { //获得每一个時间点的座标 var x = quadraticBezier(start[0], point[0], end[0], t); var y = quadraticBezier(start[1], point[1], end[1], t); ctx.lineTo(x, y); //画出上个時间点到当今時间点的平行线 } ctx.stroke(); //描边 } /** * 2次贝塞尔曲线图方程 * @param {Array<number>} start 起始点 * @param {Array<number>} 曲度点 * @param {Array<number>} end 终点站 * @param {number} 绘图进度(0⑴) */ function quadraticBezier(p0, p1, p2, t) { var k = 1 - t; return k * k * p0 + 2 * (1 - t) * t * p1 + t * t * p2; }
更为详尽的贝塞尔曲线图內容请参照这篇blog
放入详细的编码中
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF⑻"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <meta http-equiv="X-UA-Compatible" content="ie=edge"> <title>2次贝塞尔曲线图动漫</title> <style> body { background: #0f1632; } #canvas { border: 1px solid #ccc; } #img { display: none; <!--img立即掩藏就行,后边会立即引入--> } </style> </head> <body> <canvas id="canvas" width="1500" height="750"></canvas> <img id="img" src="https://s3.imgsha.com/2019/04/22/light.png"> <script> var ctx = document.getElementById('canvas').getContext('2d'); var img = document.getElementById('img'); var percent = 0; var data = { start: [400, 200], point: [300, 100], end: [100, 400], department: '数据信息1', value: 4321 } function init(){ percent = 0; //每次重设过程 draw(); } function draw(){ ctx.clearRect(0, 0, 1500, 750); //每次消除画布 ctx.strokeStyle = '#ffffff'; //设定线条款式 drawCurvePath(data.start, data.point, data.end, percent); percent += 0.8; //过程提升,这个操纵动漫速率 if (percent <= 100) { //沒有画完接着启用,画完的话重设进度 requestAnimationFrame(draw); }else{ init() } } function drawCurvePath(start, point, end, percent) //... } function quadraticBezier(p0, p1, p2, t) { //... } </script> </body> </html>
动漫就出来了
以前说了 drawCurvePath(start, point, end, percent)
涵数中point
这个主要参数并不是实际曲度的点,只是1个大概的方位
再开看1下 point
改成[200,200]
的状况
加上渐变色
假如想完成跌落的实际效果,由高到低由远及近必须给线条加1个渐变色的实际效果
/** * 建立线形渐变色 * @param {Array<number>} start 起始点 * @param {Array<number>} 曲度点 * @param {Array<number>} end 终点站 * @param {number} 绘图进度(0⑴) */ function createLinearGradient(start,end,startColor,endColor){ var lineGradient = ctx.createLinearGradient(...start, ...end); lineGradient.addColorStop(0, startColor); // lineGradient.addColorStop(0.3, '#fff'); lineGradient.addColorStop(1, endColor); return lineGradient } //draw涵数必须做些调剂 function draw(){ //ctx.strokeStyle = '#ffffff'; ctx.strokeStyle = createLinearGradient(data.start, data.end, 'rgba(255,255,255,.2)', '#fff' ); //... }
canvas渐变色详细信息请参照MDN
头顶部光晕
加上头顶部光晕必须画1个圆,并设定轴向渐变色,运用drawCurvePath
涵数获得x,y并重设圆的部位
function createHeadLight(x,y){ ctx.beginPath(); //建立轴向渐变色 var radialGradient = ctx.createRadialGradient(x, y, 0, x, y, 20); radialGradient.addColorStop(0, "rgba(255,255,255,1)"); radialGradient.addColorStop(.2, "rgba(255,255,255,.8)"); radialGradient.addColorStop(1, "transparent"); ctx.fillStyle = radialGradient; //画圆 ctx.arc(x, y, 20, 0, 2 * Math.PI, false); ctx.fill(); } //drawCurvePath涵数必须做些调剂 function drawCurvePath(start, point, end, percent){ //... ctx.stroke(); //描边 createHeadLight(x,y) //和画线频率1样画圆 }
绘图圆arc
主要参数详细信息参照MDN
加上文字
加上文字和加上头顶部光晕很类似,全是运用drawCurvePath
涵数获得x,y并重设文字块的部位
/** * 建立文字 * @param {String} 单位数据信息 * @param {Number} 数据信息 * @param {Number} x轴座标 * @param {Number} y轴座标 */ function drawText(department, value, x, y) { ctx.fillStyle = '#fff' ctx.font = "22px 微软雅黑"; ctx.fillText(department, x + 30, y + 20); //以便使文字在光晕右下角x,y轴必须偏位1些间距 var width = ctx.measureText(value).width; //获得文字的宽度 ctx.fillStyle = createLinearGradient([x + 30, 0], //文字渐变色x轴的3D渲染范畴是[x+30,x+30+文字的宽度], [x + 30 + width, 0], //这里y取0,是由于没寻找获得文字高的api,写0也是能够的 '#fffd00', '#ff6d00' ); ctx.fillText(value.toLocaleString(), x + 30, y + 50); } //drawCurvePath涵数必须做些调剂 function drawCurvePath(start, point, end, percent, department, value) { //... createHeadLight(x,y) drawText(department, value, x, y) }
动漫进行后完毕部位加上文字和照片
动漫进行后加上文字和照片必须留意下,曲线图动漫进行后必须马上清除画布,随后加上文字和照片
/** * 建立照片 * @param {Number} x轴座标 * @param {Number} y轴座标 */ function drawImg(x, y) { ctx.drawImage(img, x - img.width / 2, y - img.height); } //draw 涵数必须做些调剂 draw(){ //... if (percent <= 100) { requestAnimationFrame(draw); }else{ ctx.clearRect(0, 0, 1500, 750); //曲线图动漫完马上消除画布 drawText(data.department, //3D渲染文字 data.value, data.end[0], data.end[1]) drawImg(data.end[0], data.end[1]) //3D渲染照片 setTimeout(function(){ //2000ms后重绘 init() },2000) } }
完毕
本篇示例详细编码
文章内容首图示例详细编码
参照文章内容:用canvas绘图1个曲线图动漫——深层次了解贝塞尔曲线图
以上便是本文的所有內容,期待对大伙儿的学习培训有一定的协助,也期待大伙儿多多适用脚本制作之家。