前些年的时候,突然对Canvas感兴趣,利用空闲时间做一些Canvas小例子进行练习,仅供学习分享使用。如有不足之处,还请指正。
什么是 Canvas?
HTML5 的 canvas 元素使用 JavaScript 在网页上绘制图像。画布是一个矩形区域,您可以控制其每一像素。canvas 拥有多种绘制路径、矩形、圆形、字符以及添加图像的方法。
创建 Canvas 元素及JavaScript对象
向 HTML5 页面添加 canvas 元素。规定元素的 id、宽度和高度,如下所示:
<canvas id="myCanvas" width="200" height="100"></canvas>
JavaScript 使用 id 来寻找 canvas 元素:
var c=document.getElementById("myCanvas");
然后,创建 context 对象:
var cxt=c.getContext("2d");
注意:getContext("2d") 对象是内建的 HTML5 对象,拥有多种绘制路径、矩形、圆形、字符以及添加图像的方法。
实例一、灯笼绘制
以下是一个灯笼,并作了简要的说明。
具体绘制思路在页面上有说明,不再赘述,代码如下:
<script type="text/javascript">//绘制椭圆function ParamEllipse(context, x, y, a, b) {//max是等于1除以长轴值a和b中的较大者//i每次循环增加1/max,表示度数的增加//这样可以使得每次循环所绘制的路径(弧线)接近1像素var step = (a > b) ? 1 / a : 1 / b;context.fillStyle = "#ff0000";context.beginPath();context.moveTo(x + a, y); //从椭圆的左端点开始绘制for (var i = 0; i < 2 * Math.PI; i += step) {//参数方程为x = a * cos(i), y = b * sin(i),//参数为i,表示度数(弧度)context.lineTo(x + a * Math.cos(i), y + b * Math.sin(i));}context.closePath();context.stroke();context.fill();context.closePath();};//绘制矩形function FillRect(context, x, y, w, h, flag) {var grd = context.createLinearGradient(x+w/2, y, x + w/2, y + h);if (flag) {grd.addColorStop(0, "yellow");grd.addColorStop(1, "red");} else {grd.addColorStop(0, "red");grd.addColorStop(1, "yellow");}context.fillStyle = grd;context.fillRect(x, y, w, h);}//绘制线条function SetLine(ctx, x, y, x1, y1) {ctx.beginPath();ctx.strokeStyle = "yellow";ctx.moveTo(x,y);ctx.lineTo(x1,y1);ctx.stroke();ctx.closePath();}window.onload = function () {var c = document.getElementById("myCanvas");var ctx = c.getContext("2d");var startX = 150; //中心坐标xvar startY = 300; //中心坐标yvar pWidth = 120; //椭圆长轴var pHeigth = 80; //椭圆形短轴var fWidth = 120; //矩形宽var fheight = 40; //矩形高//绘制椭圆ParamEllipse(ctx, startX, startY, pWidth, pHeigth);//在椭圆上方和下方绘制长方形,且有一半的高度和椭圆重叠FillRect(ctx, startX - fWidth / 2, startY - pHeigth - (fheight / 2), fWidth, fheight, true);FillRect(ctx, startX - fWidth / 2, startY + pHeigth - (fheight / 2), fWidth, fheight, false);//在矩形下方绘制线条,8个单位一条线,长度为40,均匀分布在矩形下方var lLen = fheight; //画线的范围始终在矩形之下var lInterval = 8; //线与线之间的间隔for (var i = 0; i < (fWidth / 8) + 1; i++) {SetLine(ctx, startX - fWidth / 2 + i * lInterval, startY + pHeigth + fheight / 2, startX - fWidth / 2 + i * lInterval, startY + pHeigth + fheight / 2 + lLen);}//对三部分进行拆解//1. 上矩形var right = 380;FillRect(ctx, startX - fWidth / 2 + right, startY - pHeigth - (fheight / 2) - 150, fWidth, fheight, true);//2. 中椭圆ParamEllipse(ctx, startX + right, startY - 50, pWidth, pHeigth);//3. 下矩形FillRect(ctx, startX - fWidth / 2 + right, startY + pHeigth - (fheight / 2) + 50, fWidth, fheight, false);//4. 下线for (var i = 0; i < (fWidth / 8) + 1; i++) {SetLine(ctx, startX - fWidth / 2 + i * lInterval + right, startY + pHeigth + fheight / 2 + 100, startX - fWidth / 2 + i * lInterval + right, startY + pHeigth + fheight / 2 + lLen + 100);}//画线,将其连接起来var lsX = startX + pWidth + 20;var lsY = startY;var leX = startX + pWidth + 20 + 100;var leY = startY;SetLine(ctx, lsX, startY - 30, leX - 30, leY - 150);SetLine(ctx, lsX, startY - 15, leX, leY - 50);SetLine(ctx, lsX, startY + 15, leX, leY + 100);SetLine(ctx, lsX, startY + 30, leX - 30, leY + 150);//左上标写上说明ctx.font = "35px Arial";var t = "灯笼组成--2016-11-13";ctx.fillText(t, 50, 50);}</script>
实例二、绘制时钟
绘制一个走动的时钟,具体如下图所示:
具体思路在上图已有说明,代码如下:
<script type="text/javascript">//绘制圆形的弧度,ctx 为绘制环境,x,y为绘制中心,r为绘制半径,st为起始弧度,end为结束弧度function circle(ctx, x, y, r, st, end, w) {ctx.lineWidth = w;ctx.beginPath();ctx.moveTo(x, y);ctx.arc(x, y, r, st, end, true);ctx.stroke();}//画一个白色的圆,用以覆盖function circle0(ctx, x, y, r, st, end) {ctx.fillStyle = "#ffffff";ctx.beginPath();ctx.arc(x, y, r, st, end, true);ctx.fill();}function circle1(ctx, x, y, r, st, end, w) {ctx.strokeStyle = "gray";ctx.lineWidth = w;ctx.beginPath();ctx.arc(x, y, r, st, end, true);ctx.stroke();}//绘制时钟用的线function line(ctx, x1, y1, x2, y2, w) {if (w == 1) {ctx.strokeStyle = "red";} else if (w == 2) {ctx.strokeStyle = "blue";} else {ctx.strokeStyle = "black";}ctx.lineWidth = w;ctx.beginPath();ctx.moveTo(x1, y1);ctx.lineTo(x2, y2);ctx.stroke();}function drawClock() {var c = document.getElementById("myCanvas");var ctx = c.getContext("2d");ctx.clearRect(0, 0, c.width, c.height);//绘制一个钟表var cX = 300;var cY = 200;var radius = 100;//绘制分与秒的刻度for (var i = 0; i < 60; i++) {circle(ctx, cX, cY, radius, i * 6 * Math.PI / 180, (i + 1) * 6 * Math.PI / 180, 1);}circle0(ctx, cX, cY, radius * 9 / 10, 0, 2 * Math.PI, true);//绘制时刻度for (var i = 0; i < 12; i++) {circle(ctx, cX, cY, radius, i * 30 * Math.PI / 180, (i + 1) * 30 * Math.PI / 180, 2);}circle0(ctx, cX, cY, radius * 8 / 10, 0, 2 * Math.PI, true);//外围再画一圈circle1(ctx, cX, cY, radius * 11 / 10, 0, 2 * Math.PI, 1);ctx.save();ctx.fillStyle = "black";ctx.font = "10px Arial";//在钟表的周围画上数字for (var i = 0; i < 12; i++) {var fX = cX + Math.cos((i + 1) * 5 * 6 * Math.PI / 180 - Math.PI / 2) * radius * 7.5 / 10;var fY = cY + Math.sin((i + 1) * 5 * 6 * Math.PI / 180 - Math.PI / 2) * radius * 7.5 / 10;ctx.fillText((i + 1), fX, fY);}var date = new Date();var second = date.getSeconds();var minute = date.getMinutes();var hour = date.getHours();hour = hour % 12; //采用12小时制var secondX = cX + Math.cos(second * 6 * Math.PI / 180 - Math.PI / 2) * radius * 9 / 10;var secondY = cY + Math.sin(second * 6 * Math.PI / 180 - Math.PI / 2) * radius * 9 / 10;var minuteX = cX + Math.cos(minute * 6 * Math.PI / 180 - Math.PI / 2) * radius * 8 / 10;var minuteY = cY + Math.sin(minute * 6 * Math.PI / 180 - Math.PI / 2) * radius * 8 / 10;//小时为了准确起见,应该要加上分的弧度var hourX = cX + Math.cos(hour * 30 * Math.PI / 180 + (minute * 6 * Math.PI / 180) / 12 - Math.PI / 2) * radius * 6.5 / 10;var hourY = cY + Math.sin(hour * 30 * Math.PI / 180 + (minute * 6 * Math.PI / 180) / 12 - Math.PI / 2) * radius * 6.5 / 10;//画秒针,红色line(ctx, cX, cY, secondX, secondY, 1);//画分针,蓝色line(ctx, cX, cY, minuteX, minuteY, 2);//画时针,黑色line(ctx, cX, cY, hourX, hourY, 3);ctx.fillStyle = "black";ctx.font = "15px Arial";ctx.fillText("CurrentTime is : " + date.toLocaleString(), 150, 450);ctx.save();}window.onload = function () {//循环,1s一次,且要在加载完才可以开始,否则会出现找不到对象的异常setInterval(drawClock, 1000);}</script>
实例三、绘制太极图
采用Html5+JavaScript在Canvas中绘制旋转的太极图,如下图所示:
具体思路和绘制逻辑,在上图中已有说明,代码如下:
<script type="text/javascript">//只画边框线,无填充function bigCircle(ctx,x, y, r, st, end, w,oc) {ctx.lineWidth = w;ctx.beginPath();ctx.arc(x, y, r, st, end, oc);ctx.closePath();ctx.stroke();}//有填充,画小圆,x,y表示大圆的圆心,r表示大圆的半径,w表示线宽,oc表示方向,l表示上下,d表示度数function smallCircle(ctx, x, y, r, st, end, w, oc, l,d) {var Angle = d * Math.PI / 180; //偏移角用弧度表示ctx.lineWidth = w;ctx.beginPath();if (l) {ctx.fillStyle = "black";ctx.arc(x + (r / 2) * Math.sin(Angle), y - (r / 2) * Math.cos(Angle), r/10, st, end, oc);} else {ctx.fillStyle = "red";ctx.arc(x - (r / 2) * Math.sin(Angle), y + (r / 2) * Math.cos(Angle), r/10, st, end, oc);}ctx.closePath();ctx.stroke();ctx.fill();}//此函数是画带S形曲线的圆,l表示左右,true表示左,顺时针,false表示右,逆时针//d表示度数function halfCircle(ctx, x, y, r, w, l,d) {ctx.lineWidth = w;if (l) {ctx.fillStyle = "black";} else {ctx.fillStyle = "red";}ctx.beginPath();var Angle = d * Math.PI / 180;//偏移角用弧度表示ctx.arc(x + (r / 2) * Math.sin(Angle), y - (r / 2) * Math.cos(Angle), r / 2, Math.PI / 2 + Angle, Math.PI * 3 / 2 + Angle, true);ctx.arc(x - (r / 2) * Math.sin(Angle), y + (r / 2) * Math.cos(Angle), r / 2, Math.PI*3 / 2 + Angle, Math.PI / 2 + Angle, true);ctx.arc(x, y, r, Math.PI / 2 + Angle, Math.PI * 3 / 2 + Angle, l); //顺时针,逆时针通过参数判断ctx.closePath();ctx.stroke();ctx.fill();}var num = 0;//表示旋转的度数function drawTaichi() {var c = document.getElementById("myCanvas");var ctx = c.getContext("2d");var cX = 200;var cY = 200;var radius = 150;ctx.clearRect(0,0,c.width,c.height);//绘制s线 左halfCircle(ctx, cX, cY, radius, 1, true, num);//右halfCircle(ctx, cX, cY, radius, 1, false, num);//绘制小圆,上smallCircle(ctx, cX, cY, radius, 0, Math.PI * 2, 1, true, true, num);//绘制小圆,下smallCircle(ctx, cX, cY, radius, 0, Math.PI * 2, 1, true, false, num);//绘制外圆bigCircle(ctx, cX, cY, radius, 0, Math.PI * 2, 2, true);ctx.save();num++;num = num % 360;//只有360°,所以大于360,就重新开始}window.onload = function () {setInterval(drawTaichi, 200);}</script>
实例四、绘制五星红旗
Html5+JavaScript 在Canvas上绘制五星红旗,具体思路如下图所示:
绘制思路在上图中已有说明,具体代码如下:
<script type="text/javascript">//绘制五角星,其中一点垂直向上,相隔的点相连,即可绘制。function drawStar(ctx,starCenterX,starCenterY,starRadius) {var aX = starCenterX;var aY = starCenterY - starRadius;var bX = starCenterX - Math.cos(18 * Math.PI / 180) * starRadius;var bY = starCenterY - Math.sin(18 * Math.PI / 180) * starRadius;var cX = starCenterX - Math.cos(54 * Math.PI / 180) * starRadius;var cY = starCenterY + Math.sin(54 * Math.PI / 180) * starRadius;var dX = starCenterX + Math.cos(54 * Math.PI / 180) * starRadius;var dY = starCenterY + Math.sin(54 * Math.PI / 180) * starRadius;var eX = starCenterX + Math.cos(18 * Math.PI / 180) * starRadius;var eY = starCenterY - Math.sin(18 * Math.PI / 180) * starRadius;ctx.beginPath();ctx.fillStyle = "yellow";ctx.moveTo(aX, aY);ctx.lineTo(cX, cY);ctx.lineTo(eX, eY);ctx.lineTo(bX, bY);ctx.lineTo(dX, dY);ctx.lineTo(aX, aY);ctx.fill();ctx.closePath();}window.onload = function () {var c = document.getElementById("myCanvas");var ctx = c.getContext("2d");ctx.clearRect(0, 0, c.width, c.height);var width = 300*1.5;var height = 200*1.5;var sX = 50; //其实坐标var sY = 50; //其实坐标var step = 10*1.5;//绘制矩形ctx.beginPath();ctx.lineWidth = 1;ctx.fillStyle = "red";ctx.fillRect(sX, sY, width, height);ctx.closePath();//绘制大五角星var bigStarCenterX = sX + 5 * step;var bigStarCenterY = sY + 5 * step;var bigStarRadius = (height * 3 / 10) / 2; //外接圆直径为旗高3/10,半径要再除以2drawStar(ctx, bigStarCenterX, bigStarCenterY, bigStarRadius);//绘制小五角星var smallStarRadius = (height * 1 / 10) / 2; //外接圆直径为旗高1/10,半径要再除以2var smallStarCenterX_1 = sX + 10 * step;var smallStarCenterY_1 = sY + 2 * step;drawStar(ctx, smallStarCenterX_1, smallStarCenterY_1, smallStarRadius);var smallStarCenterX_2 = sX + 12 * step;var smallStarCenterY_2 = sY + 4 * step;drawStar(ctx, smallStarCenterX_2, smallStarCenterY_2, smallStarRadius);var smallStarCenterX_3 = sX + 12 * step;var smallStarCenterY_3 = sY + 7 * step;drawStar(ctx, smallStarCenterX_3, smallStarCenterY_3, smallStarRadius);var smallStarCenterX_4 = sX + 10 * step;var smallStarCenterY_4 = sY + 9 * step;drawStar(ctx, smallStarCenterX_4, smallStarCenterY_4, smallStarRadius);};</script>
备注
赤壁【作者】杜牧【朝代】唐
折戟沉沙铁未销,自将磨洗认前朝。东风不与周郎便,铜雀春深锁二乔。