码字,杂谈

JavaScript 之 canvas(二)-- 绘制基本图形

JavaScript 之 canvas(一)中理解了canvas的绘图原理,这次就开始绘制基本图形。

一般来说,canvas的图形分成实心(fill)和空心(stroke),我们的绘图板基本使用的是空心图形,但是也要了解一下实心图形,其原理是一毛一样的。

直线

一般来说,直线需要知道两端坐标,所以代码如下:

// 直线
context.moveTo(150, 150);  // 移动到某一位置
context.lineTo(300, 150);  // 画直线从当前点到给定的位置
context.stroke();

《JavaScript 之 canvas(二)-- 绘制基本图形》

这样就绘制出一条起点在 (150, 150),终点在 (300, 150) 的水平直线。

好像很简单的样子,接着来看下一个。

箭头

箭头的思路和直线差不多,先画直线,然后在终点位置画一个填充的三角形即可。
注意三角形需要按照直线的方向,所以用到的数学属性如下:

// 箭头
// 箭头的思路和直线差不多,先画直线,然后在终点位置画一个填充的三角形即可
// 注意三角形需要按照直线的方向,所以用到的数学属性如下
context.moveTo(230, 230);  // 移动到指定坐标
context.lineTo(500, 230);  // 画直线
context.stroke();  // 填充直线
let endRadians = Math.atan((230 - 230) / (500 - 230));  // 计算出当前直线的角度
endRadians += ((500 >= 230) ? 90 : -90) * Math.PI / 180;  // 角度的正负取值
context.translate(500, 230);  // 使用translate函数转换坐标系,将该坐标重新定义为原点
context.rotate(endRadians);  // 把该直线看做水平坐标(目的是让整个canvas没有角度,方便计算)

// 下面就是根据直线终点绘制三角箭头,并填充三角形
context.moveTo(0,  -2 * context.lineWidth);
context.lineTo(2 * context.lineWidth, 3 * context.lineWidth);
context.lineTo(-2 * context.lineWidth, 3 * context.lineWidth);
context.fillStyle = context.strokeStyle;
context.fill();

里面具体的参数小伙伴可以自行修改,具体的实现思路,我已经写在代码中的注释部分,应该还算详细。

这样就得到一个如下图的图片:

《JavaScript 之 canvas(二)-- 绘制基本图形》

颜色我重新调整了,方便截图,第一讲中已经说过颜色的调整,这里就不赘述。

继续下一个图形。

矩形

基本图形刚才已经说过,分为实心和空心,先来看实心矩形,上代码:

// 矩形
// 使用fillRect函数,(起点x,起点y,终点x,终点y), 颜色为fillStyle给定的颜色
context.fillRect(50, 50, 150, 150);

一行代码就能够得到一个实心矩形。

那么空心矩形如下:

// 空心矩形
// 使用strokeRect函数,坐标参数与矩形一致,颜色为strokeStyle给定的颜色,画笔粗细为lineWidth的值
context.strokeRect(100, 100, 200, 200);

这两个矩形同时显示效果如下,注意后面的代码永远在上面展示:
《JavaScript 之 canvas(二)-- 绘制基本图形》

矩形介绍完,该介绍圆形,更加简单。

圆形

圆形同样一个函数就可以搞定:

// 圆形
// 使用arc函数,(圆心x,圆心y,半径,起始角度,结束角度,[可选参数:顺时针false/逆时针true])
let r = 50;  // 半径
context.arc(200, 200, r, 0, Math.PI * 2);  // 绘制圆
context.fill();  // 填充
context.stroke();  // 描边

这里面稍微有个不太好理解的地方,参数比想象的要多一些。起始arc函数可以绘制圆形,同样也可以绘制弧线。
除了给定圆心坐标和半径之外,还要给定绘制的弧度(包括起始角度和结束角度),我们要绘制圆形,所以给定0Math.PI * 2,这样才能绘制一个完整的圆形。
在w3c网站上我找到这张解释图片,还是比较清晰明了:

《JavaScript 之 canvas(二)-- 绘制基本图形》

根据最后一个可选参数(false为顺时针,也是默认值,true为逆时针),就可以绘制出对应的弧线。

最后两行代码,如果需要空心圆,使用stroke()描边即可。如果需要实心圆,使用fill()填充即可。


那么基本的图形就说完了,贴上完整代码:

var canvas = document.getElementById("canvas");

if (canvas.getContext) {
    var context = canvas.getContext("2d");  //2d用引用括起来
}

// 检测浏览器是否支持canvas 该方法是否存在 取得上下文对象
if (canvas.getContext) {
    var context = canvas.getContext('2d'); //2d用单引用括起来
    if (canvas.getContext) {
        context.fillStyle = "red";  // 填充颜色为红色
        context.strokeStyle = "blue";  // 画笔的颜色
        context.lineWidth = 5;  // 指定描边线的宽度

        // 保存当前状态,开始绘图
        context.save();
        context.beginPath();

        // 直线
        context.moveTo(150, 150);  // 移动到某一位置
        context.lineTo(300, 150);  // 画直线从当前点到给定的位置
        context.stroke();

        // 箭头
        // 箭头的思路和直线差不多,先画直线,然后在终点位置画一个填充的三角形即可
        // 注意三角形需要按照直线的方向,所以用到的数学属性如下
        context.moveTo(230, 230);  // 移动到指定坐标
        context.lineTo(500, 230);  // 画直线
        context.stroke();  // 填充直线
        let endRadians = Math.atan((230 - 230) / (500 - 230));  // 计算出当前直线的角度
        endRadians += ((500 >= 230) ? 90 : -90) * Math.PI / 180;  // 角度的正负取值
        context.translate(500, 230);  // 使用translate函数转换坐标系,将该坐标重新定义为原点
        context.rotate(endRadians);  // 把该直线看做水平坐标(目的是让整个canvas没有角度,方便计算)

        // 下面就是根据直线终点绘制三角箭头,并填充三角形
        context.moveTo(0,  -2 * context.lineWidth);
        context.lineTo(2 * context.lineWidth, 3 * context.lineWidth);
        context.lineTo(-2 * context.lineWidth, 3 * context.lineWidth);
        context.fillStyle = context.strokeStyle;
        context.fill();

        // 矩形
        // 使用fillRect函数,(起点x,起点y,终点x,终点y), 颜色为fillStyle给定的颜色
        context.fillRect(50, 50, 150, 150);

        // 空心矩形
        // 使用strokeRect函数,坐标参数与矩形一致,颜色为strokeStyle给定的颜色,画笔粗细为lineWidth的值
        context.strokeRect(100, 100, 200, 200);

        // 圆形
        // 使用arc函数,(圆心x,圆心y,半径,起始角度,结束角度,[可选参数:顺时针false/逆时针true])
        let r = 50;  // 半径
        context.arc(200, 200, r, 0, Math.PI * 2);  // 绘制圆
        context.fill();  // 填充
        context.stroke();  // 描边

        // 还原状态,结束当前绘画
        context.restore();
        context.closePath();
    }
}

可以看到在绘制之前使用了save()beginPath()函数,作用如下:

  • save():保存当前绘制状态,比如画笔粗细,颜色等信息
  • beginPath():开始绘画

同时在结尾使用了restore()closePath()函数,作用如下:

  • restore():还原之前的画笔状态
  • closePath():结束绘画

这样就可以完整的开始绘图了,小伙伴们多多练习。

点赞

发表评论

电子邮件地址不会被公开。 必填项已用*标注