canvas绘制网易云logo
最近在看《HTML5 Canvas核心技术 图形、动画与游戏开发》,顺便做点东西熟悉。
图形分解参考:https://www.ui.cn/detail/282301.html
简单讲下思路,按照上面文章的分解,网易云的logo可以拆分成几个圆,直径分别为:外围最大的圆400px、300px,偏右的中圆290px、190px,中间的小圆170px、70px,尾部的小圆150px、50px。还有一个宽50px*高度240的矩形。
另外头尾需要处理为圆形。
首先我们做一些准备工作。
HTML中我们需要搞一个画布,我懒得算比例,所以之后的编程全部按文章数据来,设置一个540*540的画布。
html:
<canvas id='canvas' width='540' height='540'> Canvas not supported </canvas>
还有一些js:
//获取画布 var canvas=document.getElementById("canvas"), context = canvas.getContext("2d"); var CAN_CENTER={ x:canvas.width/2, y:canvas.height/2 },//图像中点 LINEWIDTH=50,//线段粗细 center={x:0,y:0};//用于之后计算圆心位置
第一步我们绘制背景:填充一个和画布一样大的矩形。
//背景 context.fillStyle="#cc100f"; context.fillRect(0,0,canvas.width,canvas.height);
二、画最大圈的圆弧(如图)
canvas的arc按角度算,且默认为顺时针,所以这个圆弧的角度是0~1.35PI。
还需要在起点加上一个半径25的白色小圆,此处需要计算小圆圆心位置。
根据图片式子可以列出小圆圆心位置。填充一个半径为25的圆。
//大圆及终点 context.lineWidth=LINEWIDTH; context.fillStyle="#fff"; context.strokeStyle="#fff"; context.beginPath(); context.arc(CAN_CENTER.x,CAN_CENTER.y,175,0,Math.PI*1.35); context.stroke(); center.x=CAN_CENTER.x-(Math.cos(Math.PI*0.35)*175); center.y=CAN_CENTER.y-(Math.sin(Math.PI*0.35)*175) context.beginPath(); context.arc(center.x,center.y,25,0,Math.PI*2); context.fill();
三、画中间偏离的圆弧
同样需要计算圆心位置,分析图片两个圆在右侧相切,中圆的圆心x为中点x加上大圆半径减去小圆半径。
因为绘制上半圆,所以我这边设置为逆时针绘制,角度0~PI。
center.x=CAN_CENTER.x+175-(290-LINEWIDTH)/2;
center.y=CAN_CENTER.y;
context.beginPath();
context.arc(center.x,center.y,(290-LINEWIDTH)/2,0,Math.PI,true);
context.stroke();
四、接下来绘制中心小圆弧,直线和尾部小圆弧。
一起绘制是因为在canvas中,如果添加圆弧子路径时已经有路径,会自动在之前子路径的尾部到新圆弧路径的起点绘制直线,完美省去我们一大堆计算。
中心圆弧圆心计算同偏移圆弧,不多说。
尾部圆弧的圆心在大圆边缘上,计算如图:
x为中心加上sin a,y为中心y减去cos a。
// //中间小圆、直线、尾巴小圆 center.x=center.x-50; context.beginPath(); context.arc(center.x,center.y,(190-LINEWIDTH)/2,Math.PI,Math.PI*1.88,true); center.x=CAN_CENTER.x+Math.sin(Math.PI/8)*175; center.y=CAN_CENTER.y-Math.cos(Math.PI/8)*175; context.arc(center.x,center.y,50,Math.PI*0.88,Math.PI*1.75); context.stroke();
题外话:1.88、0.88为调整后找到的比较圆滑的值,一开始用2和1代入有点生硬,对比:
五、最后在尾部圆弧圆心的基础上计算尾部小圆圆心位置,并填充一个25的圆。
全部js代码:
//获取画布 var canvas=document.getElementById("canvas"), context = canvas.getContext("2d"); var CAN_CENTER={ x:canvas.width/2, y:canvas.height/2 },//图像中点 LINEWIDTH=50,//线段粗细 center={x:0,y:0};//用于之后计算圆心位置 //背景 context.fillStyle="#cc100f"; context.fillRect(0,0,canvas.width,canvas.height); //大圆及终点 context.lineWidth=LINEWIDTH; context.fillStyle="#fff"; context.strokeStyle="#fff"; context.beginPath(); context.arc(CAN_CENTER.x,CAN_CENTER.y,175,0,Math.PI*1.35); context.stroke(); center.x=CAN_CENTER.x-(Math.cos(Math.PI*0.35)*175); center.y=CAN_CENTER.y-(Math.sin(Math.PI*0.35)*175) context.beginPath(); context.arc(center.x,center.y,25,0,Math.PI*2); context.fill(); //中间偏离圆 center.x=CAN_CENTER.x+175-(290-LINEWIDTH)/2; center.y=CAN_CENTER.y; context.beginPath(); context.arc(center.x,center.y,(290-LINEWIDTH)/2,0,Math.PI,true); context.stroke(); // //中间小圆、直线、尾巴小圆 center.x=center.x-50; context.beginPath(); context.arc(center.x,center.y,(190-LINEWIDTH)/2,Math.PI,Math.PI*1.88,true); center.x=CAN_CENTER.x+Math.sin(Math.PI/8)*175; center.y=CAN_CENTER.y-Math.cos(Math.PI/8)*175; context.arc(center.x,center.y,50,Math.PI*0.88,Math.PI*1.75); context.stroke(); // //尾巴终点 context.beginPath(); center.x=center.x+(Math.cos(Math.PI*0.25)*50); center.y=center.y-(Math.sin(Math.PI*0.25)*50); context.arc(center.x,center.y,25,0,Math.PI*2); context.fill();