Canvas在Android原生开发和传统HTML5开发的用C应用舞台上都扮演着重要的角色,我们通过本文了解如何正确使用 canvas 画布,制快以及如何通过 canvas 绘制复杂的工具图形及动画。
快应用官方文档提供了快应用logo(如下图)的用C应用绘制过程:
本文我们来学习一下快应用开发工具的logo(如下图)的绘制过程:
分析图片
用PhotoShop打开路径为的图片,并添加参考线,制快主要为了获取透明边框的工具宽度(你可以理解为图片文件的padding)、蓝色边框的用C应用宽度、蓝色圆弧的制快厚度、红色圆点的工具直径以及红色和蓝色的具体RGB代码。
因为快应用的用C应用Canvas不支持透明背景(原文如下),所以本文成品略有瑕疵。制快
绘制白色填充和蓝色边框
Canvas 绘图的工具两大基本绘制方式就是绘制填充和描边。所谓填充,用C应用就是制快指用指定的内容填满所要绘制的图形,最终生成一个实心的高防服务器工具图案,绘制填充矩形的方法是这样的:ctx.fillRect(x, y, width, height);所谓描边,就是沿着所要绘制的图形边缘,使用指定的内容进行描绘,最终生成的是空心的图案,绘制描边矩形的方法是这样的ctx.strokeRect(x, y, width, height)。
看代码望文生义就可以知道如果既要填充又要描边,则不得不分别绘制两次才能完成最终图案,并且不能自定义描边宽度。
为了能够自定义描边宽度,我们可以利用路径来实现快应用开发工具的logo的蓝色边框和白色填充。绘制白色填充和蓝色边框的代码如下:
// 开始绘制路径 ctx.beginPath(); // 起点(左上角) ctx.moveTo(r , r); // 绘制到第二个点的线段(左下角) ctx.lineTo(r, h - r ); // 绘制到第三个点的线段(右下角) ctx.lineTo(h - r , h - r); // 绘制到终点的线段(右上角) ctx.lineTo(h - r, r ); // 用线段闭合路径(直接从终点连回到起点) ctx.closePath(); // 描边宽度 ctx.lineWidth = r; // 定义描边样式,本次是纯色 ctx.strokeStyle = #4286f5; // 绘制描边 ctx.stroke(); // 定义填充样式,用另一种格式的服务器托管纯色 // 注意顺序是R(红色)、G(绿色)、B(蓝色)、A(不透明度)而不是A、R、G、B ctx.fillStyle = rgba(255,255,255,255); // 绘制填充 ctx.fill(); 官方文档和我的注释都很详细,我补充几点: 1、strokeStyle和fillStyle的值可以为线性渐变或中心渐变,本文只讨论纯色的情况 2、rgba的四个参数分别为R(红色)、G(绿色)、B(蓝色)、A(不透明度)而不是常说的A、R、G、B 绘制蓝色圆弧和红色圆点 蓝色边框和白色背景绘制了以后,下一步就是绘制蓝色圆弧和红色圆点了。红色圆点的本质上就是一个实心圆,绘制实心圆的方法就是闭合的源码库圆形路径填充颜色。代码如下: // 绘制红色圆点 ctx.beginPath(); ctx.arc(h - 2 * s, h - 2.5 * s , s / 2 , 0, p * 2, false); ctx.fillStyle = rgb(234, 67, 53) ctx.fill(); 绘制圆弧的arc()方法的五个参数分别为圆心X坐标、圆心Y坐标、半径、圆弧起点、圆弧终点、是否逆时针。弧度的计算方法为角度乘以 2*PI/360,几个关键方向的弧度如下:左:0或2*PI,右:PI,上:P/2,下:P/2*3 。 弧线段的填充、描边方式和线段一样。 我们再绘制较复杂的蓝色圆弧: // 绘制蓝色圆弧 ctx.beginPath(); // arc()方法参数分别为圆心X坐标、圆心Y坐标、半径、起点弧度、的终点弧度、是否是逆时针 // 逆时针绘制空心内圈 ctx.arc(h / 2, h / 2, h/6, -p / 4 , -p / 4 * 7, true); // 顺时针绘制下侧封边 ctx.arc(h / 2 + (h / 6 + s / 2) * q , h / 2 + (h / 6 + s / 2) * q , s / 2,-p / 4 , p / 4 * 7,false); // 顺时针绘制实心外圈 ctx.arc(h / 2, h / 2, h/6 + s, -p / 4 * 7, -p / 4, false); // 顺时针绘制上侧封边 ctx.arc(h / 2 + (h / 6 + s / 2) * q , h / 2 - (h / 6 + s / 2) * q , s / 2,-p / 4*7 , p / 4 ,false); // 填充颜色 ctx.fillStyle = #4286f5; ctx.fill();注意弧线也必须闭合,否则会出bug
成品和完整源码
本文的成品如下图所示:
上文提到快应用的Canvas暂时不支持透明背景,所以官方logo的透明边框变成了白色边框,这是一个瑕疵所在。
本文的完整源码如下:
<template> <div class="doc-page"> <div class="content" > <canvas class="new_canvas" id="newCanvas"></canvas> </div> </div> </template> <style> .content { flex-direction: column; align-items: center; width: 100%; padding: 20px; background-color: #000000; } .new_canvas { height: 300px; width: 300px; background-color: #00000000; } </style> <script> export default { private: { drawComplete: false }, onInit() { this.$page.setTitleBar({ text: Canvas }) }, onShow() { if(!this.drawComplete) { this.drawCanvas(); } }, drawCanvas() { const canvas = this.$element(newCanvas); //获取 canvas 组件 const ctx = canvas.getContext(2d); //获取 canvas 绘图上下文 var r = 20;// 空白处和蓝色边框的宽度 var h = 300;// 画布大小 var p = Math.PI;// 圆周率 var q = Math.sin(45 * 2 * p / 360);// 45度角的正弦(角度乘以 2*PI/360就是弧度) var s = 30;// 蓝色圆弧厚度和红色圆点直径 // 开始绘制路径 ctx.beginPath(); // 起点(左上角) ctx.moveTo(r , r); // 绘制到第二个点的线段(左下角) ctx.lineTo(r, h - r ); // 绘制到第三个点的线段(右下角) ctx.lineTo(h - r , h - r); // 绘制到终点的线段(右上角) ctx.lineTo(h - r, r ); // 用线段闭合路径(直接从终点连回到起点) ctx.closePath(); // 描边宽度 ctx.lineWidth = r; // 定义描边样式,本次是纯色 ctx.strokeStyle = #4286f5; // 绘制描边 ctx.stroke(); // 定义填充样式,用另一种格式的纯色 // 注意顺序是R(红色)、G(绿色)、B(蓝色)、A(不透明度)而不是A、R、G、B ctx.fillStyle = rgba(255,255,255,255); // 绘制填充 ctx.fill(); // 绘制蓝色圆弧 ctx.beginPath(); // arc()方法参数分别为圆心X坐标、圆心Y坐标、半径、起点弧度、的终点弧度、是否是逆时针 // 逆时针绘制空心内圈 ctx.arc(h / 2, h / 2, h/6, -p / 4 , -p / 4 * 7, true); // 顺时针绘制下侧封边 ctx.arc(h / 2 + (h / 6 + s / 2) * q , h / 2 + (h / 6 + s / 2) * q , s / 2,-p / 4 , p / 4 * 7,false); // 顺时针绘制实心外圈 ctx.arc(h / 2, h / 2, h/6 + s, -p / 4 * 7, -p / 4, false); // 顺时针绘制上侧封边 ctx.arc(h / 2 + (h / 6 + s / 2) * q , h / 2 - (h / 6 + s / 2) * q , s / 2,-p / 4*7 , p / 4 ,false); // 填充颜色 ctx.fillStyle = #4286f5; ctx.fill(); // 绘制红色圆点 ctx.beginPath(); ctx.arc(h - 2 * s, h - 2.5 * s , s / 2 , 0, p * 2, false); ctx.fillStyle = rgb(234, 67, 53) ctx.fill(); this.drawComplete = true; } } </script>