Canvas初级小案例

1 篇文章 0 订阅

canvas

画直线

const canvas = document.querySelector('#box');
const ctx = canvas.getContext('2d');

ctx.beginPath(); // 起始一条路径,或重置当前路径。
ctx.moveTo(10, 10); //  定义线条开始坐标,把路径移动到画布中的指定点,不创建线条。
ctx.lineTo(10, 400); //  定义线条结束坐标,添加一个新点,然后在画布中创建从该点到最后指定点的线条。
ctx.strokeStyle = '#0f0'; // 设置或返回用于笔触的颜色、渐变或模式。
ctx.lineWidth = 10; // 设置或返回当前的线条宽度。
ctx.stroke(); // 绘制已定义的路径。
ctx.closePath(); // 创建从当前点回到起始点的路径。

要在ctx.beginPath();ctx.closePath(); 中绘制想要的东西

画虚线

原理:就是由一段一段直线组成的

const canvas = document.querySelector('#dashed');
const ctx = canvas.getContext('2d');

drawDashed(100, 100, 110, 100, 50, 20, 0);
drawDashed(100, 100, 102, 102, 50, 15, 5);
drawDashed(100, 100, 102, 102, 50, 35, 5);
drawDashed(100, 100, 110, 110, 50, 20, 20);
drawDashed(100, 100, 100, 110, 50, 0, 20);
/* 
x1,y1: 起始坐标
x2,y2: 终点坐标
count: 有多少个虚点
stepX: 线段直线x的间距多远
stepY: 线段直线y的间距多远
*/
function drawDashed(x1, y1, x2, y2, count, stepX, stepY) {
    for (let i = 0; i < count; i++) {
        ctx.beginPath();
        ctx.moveTo(x1 + stepX * i, y1 + stepY * i);
        ctx.lineTo(x2 + stepX * i, y2 + stepY * i);
        ctx.stroke();
        ctx.closePath();
    }
}

画矩形

方法一: 绘制四条直线,拼接起来

const canvas = document.querySelector('#box');
const ctx = canvas.getContext('2d');

drawline(10, 10, 10, 400, 'red', 10);
drawline(15, 15, 400, 15, 'black', 10);
drawline(400, 400, 10, 400, 'yellow', 10);
drawline(10, 395, 395, 395, 'blue', 10);
/* 
x1,y1: 起始坐标
x2,y2: 终点坐标
color: 线条颜色
width: 线条宽度
*/
function drawline(x1, y1, x2, y2, color, width) {
    ctx.beginPath();
    ctx.moveTo(x1, y1);
    ctx.lineTo(x2, y2);
    ctx.strokeStyle = color;
    ctx.lineWidth = width;
    ctx.stroke();
    ctx.closePath();
}

方法二:直线连用

const canvas = document.querySelector('#line');
const ctx = canvas.getContext('2d');

ctx.lineWidth = 10;
ctx.strokeStyle = '#000';
ctx.beginPath();
ctx.moveTo(100, 100);
ctx.lineTo(400, 100);
ctx.lineTo(400, 400);
ctx.lineTo(100, 400);
ctx.lineTo(100, 95);

ctx.stroke();
ctx.closePath();

方法三:rect()方式创建一个矩形

const canvas = document.getElementById('rect');
const ctx = canvas.getContext('2d');
/* 
context.rect(x,y,width,height); x,y 表示矩形左上角的 x,y 坐标;width,height 表示矩形的宽高
*/
ctx.beginPath();
ctx.rect(100, 100, 200, 100);
// 原则:先填充再描边
ctx.fillStyle = '#0ff'; // 设置填充色
ctx.fill(); // 填充
ctx.strokeStyle = '#f00'; // 设置描边颜色
ctx.lineWidth = 5; // 设置描边线宽
ctx.stroke(); // 描边
ctx.closePath();

方法四:fillRect()方式创建一个"被填充"的矩形。

/* 
context.fillRect(x,y,width,height); x,y 表示矩形左上角的 x,y 坐标;width,height 表示矩形的宽高
*/
const canvas = document.getElementById('rect');
const ctx = canvas.getContext('2d');
ctx.beginPath();
ctx.fillRect(100, 300, 100, 100);
ctx.closePath();

方法五:strokeRect()方式创建一个"无填充"的矩形。

/* 
context.strokeRect(x,y,width,height); x,y 表示矩形左上角的 x,y 坐标;width,height 表示矩形的宽高
*/
const canvas = document.getElementById('rect');
const ctx = canvas.getContext('2d');
ctx.strokeRect(300, 300, 100, 100);

画坐标系

原理: 就是先画两条起始点相同,且垂直的直线,在画一个矩形

const canvas = document.getElementById('rect');
const ctx = canvas.getContext('2d');
ctx.beginPath();
ctx.moveTo(100, 100);
ctx.lineTo(100, 400);
ctx.lineTo(400, 400);
ctx.stroke();
ctx.closePath();

ctx.beginPath();
ctx.rect(300, 200, 50, 200);
ctx.fillStyle = 'red'; // 设置填充色
ctx.fill(); // 填充
ctx.strokeStyle = 'red'; // 设置描边颜色
ctx.lineWidth = 0; // 设置描边线宽
ctx.stroke(); // 描边
ctx.closePath();

随机生成柱状图

const canvas = document.getElementById('rect');
const ctx = canvas.getContext('2d');
init();
let timerId = setInterval(() => {
    ctx.clearRect(0, 0, canvas.width, canvas.height); // 在给定的矩形内清除指定的像素。
    drawCoordinateAxis();
    drawBars(6);
}, 1000);
setTimeout(() => {
    clearInterval(timerId);
}, 60 * 10000);

function init() {
    // 绘制坐标轴
    drawCoordinateAxis();
    // 绘制矩形
    drawBars(6);
}
// 绘制坐标系
function drawCoordinateAxis() {
    ctx.beginPath();
    ctx.moveTo(100, 0);
    ctx.lineTo(100, 400);
    ctx.lineTo(900, 400);
    ctx.stroke();
    ctx.closePath();
}
// 绘制多个矩形
function drawBars(count) {
    for (let i = 0; i < count; i++) {
        drawBar(130 + 60 * i, 400 * Math.random(), 30);
    }
}
// 实现矩形方法
function drawBar(x, y, w) {
    ctx.beginPath();
    ctx.rect(x, y, w, 400 - y);
    ctx.fillStyle = randomColor(); // 设置填充色
    ctx.fill(); // 填充
    ctx.strokeStyle = randomColor(); // 设置描边颜色
    ctx.stroke(); // 描边
    ctx.closePath();
}
// 生成随机颜色
function randomColor() {
    var r = Math.floor(Math.random() * 256);
    var g = Math.floor(Math.random() * 256);
    var b = Math.floor(Math.random() * 256);
    //返回随机生成的颜色
    return 'rgb(' + r + ',' + g + ',' + b + ')';
}

画圆

const canvas = document.querySelector('#arc');
const ctx = canvas.getContext('2d');
ctx.beginPath();
/* 
context.arc(x,y,r,sAngle,eAngle[,counterclockwise]); 
x,y 表示圆的中心 x,y 坐标;r 表示圆的半径;
sAngle 起始角,以弧度计(弧的圆形的三点钟位置是 0 度);eAngle 结束角,以弧度计;
counterclockwise 可选。规定应该逆时针还是顺时针绘图。False = 顺时针,true = 逆时针。
*/
ctx.arc(100, 100, 50, 0, Math.PI * 2, false);
ctx.fillStyle = randomColor();
ctx.fill();
ctx.lineWidth = 10; // 边的宽度
ctx.strokeStyle = randomColor();
ctx.stroke();
ctx.closePath();
function randomColor() {
    var r = Math.floor(Math.random() * 256);
    var g = Math.floor(Math.random() * 256);
    var b = Math.floor(Math.random() * 256);
    //返回随机生成的颜色
    return 'rgb(' + r + ',' + g + ',' + b + ')';
}

小案例 —— 绘制五环

此案例中点在于将五个圆的中心点找到

const canvas = document.querySelector('#arc');
const ctx = canvas.getContext('2d');
drawCircle();
function drawCircle(lineWidth) {
    ctx.lineWidth = 10;
    circle(200, 200);
    circle(540, 200);
    circle(370, 200);
    circle(285, 347);
    circle(460, 347);
}
function circle(x, y) {
    ctx.beginPath();
    ctx.arc(x, y, 100, 0, Math.PI * 2, false);
    ctx.strokeStyle = randomColor();
    ctx.stroke();
    ctx.closePath();
}
function randomColor() {
    var r = Math.floor(Math.random() * 256);
    var g = Math.floor(Math.random() * 256);
    var b = Math.floor(Math.random() * 256);
    //返回随机生成的颜色
    return 'rgb(' + r + ',' + g + ',' + b + ')';
}

小案例 —— 画一个字母 “S”

原理:一个字母 s 是由两个半圆组成,一个半圆顺时针一个半圆逆时针

const canvas = document.getElementById('arc');
const ctx = canvas.getContext('2d');

ctx.beginPath();
ctx.arc(100, 100, 50, 0, Math.PI);
ctx.lineWidth = 2;
ctx.stroke();
ctx.closePath();

ctx.beginPath();
ctx.arc(200, 100, 50, 0, Math.PI, true);
ctx.lineWidth = 2;
ctx.stroke();
ctx.closePath();

小案例 —— 画八卦镇

原理:先画最外面的大圆,再画两个小圆和一个 s,小圆的中心坐标是(大圆中心坐标 ± 大圆半径的一半), s 的中心点坐标和小圆的中心的坐标一样,半径是大圆的一半

const canvas = document.getElementById('circle');
const ctx = canvas.getContext('2d');
init();
function init() {
    bigCircle();
    smallCircle(100, 75, true);
    smallCircle(100, 125, false);
    halfCricle(100, 75, true);
    halfCricle(100, 125, false);
}
function bigCircle() {
    ctx.beginPath();
    ctx.arc(100, 100, 50, 0, Math.PI * 2);
    ctx.lineWidth = 2;
    ctx.stroke();
    ctx.closePath();
}
function smallCircle(x, y, color) {
    ctx.beginPath();
    ctx.arc(x, y, 10, 0, Math.PI * 2);
    ctx.fillStyle = color ? '#fff' : '#000';
    ctx.fill();
    ctx.lineWidth = 1;
    ctx.strokeStyle = color ? '#000' : '#fff';
    ctx.stroke();
    ctx.closePath();
}

function halfCricle(x, y, flag) {
    ctx.beginPath();
    ctx.arc(x, y, 25, Math.PI / 2, (Math.PI * 3) / 2, flag);
    ctx.lineWidth = 1;
    ctx.strokeStyle = '#000';
    ctx.stroke();
    ctx.closePath();
}

小案例 —— 圆形进度条

原理: 开启一个定时器一步一步的画圆

const canvas = document.getElementById('arc');
const ctx = canvas.getContext('2d');

ctx.lineWidth = 5;
ctx.strokeStyle = 'skyblue';
let step = (Math.PI * 2) / 360;
let count = 0;
let timerId = setInterval(() => {
    count++;
    if (count >= 360) {
        // 整圆时停止
        clearInterval(timerId);
    }
    ctx.beginPath();
    ctx.arc(250, 250, 30, -Math.PI / 2, step * count - Math.PI / 2, false);
    /* 
        context.clearRect(x,y,width,height); x,y 表示矩形左上角的 x,y 坐标;width,height 表示要清除的矩形的宽度和高度
    */
    ctx.clearRect(230, 230, 40, 40); // 清空指定位置的东西
    /* 
        context.font="字体样式 字体变体 字体的粗细 字号和行高 字体系列 ";
    */
    ctx.font = 'italic 20px 黑体'; // 定义字体的样式
    ctx.textAlign = 'center'; // 设置或返回文本内容的当前对齐方式
    /* 
        	context.fillText(text,x,y[,maxWidth]); text	规定在画布上输出的文本;x,y 表示开始绘制文本的 x,y 坐标;maxWidth 最大文本宽度
    */
    ctx.fillText(parseInt((100 / 360) * count) + '%', 250, 255, 30); // 插入文本
    ctx.stroke();
}, 10);

小案例 —— 饼状图

原理:通过将一个圆划分成不同比例给不同比例设置颜色实现

const canvas = document.getElementById('arc');
const ctx = canvas.getContext('2d');
drawCircle(0, (Math.PI * 2 * 1) / 10);
drawCircle((Math.PI * 2 * 1) / 10, (Math.PI * 2 * 3) / 10);
drawCircle((Math.PI * 2 * 3) / 10, (Math.PI * 2 * 4) / 10);
drawCircle((Math.PI * 2 * 4) / 10, (Math.PI * 2 * 7) / 10);
drawCircle((Math.PI * 2 * 7) / 10, (Math.PI * 2 * 10) / 10);
function drawCircle(start, end) {
    ctx.beginPath();
    ctx.moveTo(250, 250); // 这里注意,一点要将起始点放在圆的中心位置上,这样才能画出圆锥形
    ctx.arc(250, 250, 100, start, end);
    ctx.fillStyle = randomColor();
    ctx.fill();
}
function randomColor() {
    var r = Math.floor(Math.random() * 256);
    var g = Math.floor(Math.random() * 256);
    var b = Math.floor(Math.random() * 256);
    //返回随机生成的颜色
    return 'rgb(' + r + ',' + g + ',' + b + ')';
}

小案例 —— 小球弹一弹

const canvas = document.getElementById('arc');
const ctx = canvas.getContext('2d');

let xStep = 2;
let yStep = 4;
let r = 20; // 小球的半径
let x = 40; // 小球的起始位置,x坐标
let y = 40; // 小球的起始位置,y坐标
const timerId = setInterval(() => {
    // 清空canvas中的东西
    ctx.clearRect(0, 0, canvas.width, canvas.height);
    if (x - r <= 0 || x + r >= 500) {
        // 触碰左右边界回弹
        xStep = -xStep;
    }
    x += xStep;
    if (y - r <= 0 || y + r >= 500) {
        // 触碰上下边界回弹
        yStep = -yStep;
    }
    y += yStep;
    drawBall(x, y, r);
}, 1);
// 画小球
function drawBall(x, y, r) {
    ctx.beginPath();
    ctx.arc(x, y, r, 0, Math.PI * 2, false);
    ctx.fillStyle = '#000';
    ctx.fill();
}
setTimeout(() => {
    clearInterval(timerId);
}, 60 * 1000);

小案例 —— 小球弹一弹封装

const canvas = document.getElementById('arc');
const ctx = canvas.getContext('2d');
class Ball {
    constructor(x, y, r, xSpeed, ySpeed, color) {
        this.x = x; // 小球的起始位置,x坐标
        this.y = y; // 小球的起始位置,y坐标
        this.r = r; // 小球的半径
        this.xSpeed = xSpeed;
        this.ySpeed = ySpeed;
        this.color = color; // 小球的颜色
    }
    drawBall() {
        ctx.beginPath();
        ctx.arc(this.x, this.y, this.r, 0, Math.PI * 2, false);
        ctx.fillStyle = this.color;
        ctx.fill();
        return this;
    }
    run() {
        if (this.x - this.r <= 0 || this.x + this.r >= canvas.width) {
            this.xSpeed = -this.xSpeed;
        }
        this.x += this.xSpeed;
        if (this.y - this.r <= 0 || this.y + this.r >= canvas.height) {
            this.ySpeed = -this.ySpeed;
        }
        this.y += this.ySpeed;
    }
}

let ballList = [];
// 实例化多个小球
for (let i = 0; i < 10; i++) {
    let ball = new Ball(r() + 50, r() + 50, r(50), r(14), r(16), randomColor());
    ball.drawBall();
    ballList.push(ball);
}

const timerId = setInterval(() => {
    ctx.clearRect(0, 0, canvas.width, canvas.height);
    ballList.forEach(ball => {
        ball.run();
        ball.drawBall();
    });
}, 10);

setTimeout(() => {
    clearInterval(timerId);
}, 60 * 1000);

function r(n = 1) {
    return Math.random() * n;
}

画文字

const canvas = document.querySelector('#text');
const ctx = canvas.getContext('2d');
// 设置字体样式  context.font="字体样式 字体变体 字体的粗细 字号和行高 字体系列 ";
ctx.font = '40px 楷书';
// 设置字体填充颜色
ctx.fillStyle = 'gold';
// 绘制填充文字  context.fillText(text,x,y[,maxWidth]); text	规定在画布上输出的文本;x,y 表示开始绘制文本的 x,y 坐标;maxWidth 最大文本宽度
ctx.fillText('hello canvas!!!', 100, 100, 300);

// 绘制描边文字
// 设置文字边框颜色
ctx.strokeStyle = 'red';
ctx.strokeText('你好,canvas!!', 100, 200, 300);

// 绘制渐变文字
// 1. 创建渐变对象
const gradient = ctx.createLinearGradient(0, 0, canvas.width, 0);
// 2. 设置渐变颜色
gradient.addColorStop('0', 'orange');
gradient.addColorStop('0.25', 'purple');
gradient.addColorStop('0.5', 'red');
gradient.addColorStop('0.75', 'blue');
gradient.addColorStop('1', 'green');
// 3. 应用渐变
ctx.fillStyle = gradient;
ctx.strokeStyle = gradient;
// 4. 绘制渐变文字
ctx.fillText('hello gradient', 100, 300, 300);
ctx.strokeText('hello gradient', 100, 400, 300);

画一个闹钟

const canvas = document.querySelector('#clock');
const ctx = canvas.getContext('2d');
class Clock {
    /* 
    x: 时钟中心坐标
    y: 时钟中心坐标
    r: 时钟半径
    r_hour: 时针长度
    r_minute: 分针长度
    r_second: 秒针长度
    r_text: 文字距离中点的半径
    r_square: 刻度
    r_circle: 中心点
    deg: 基本周期
    */
    constructor(x, y, r, r_hour, r_minute, r_second, r_text, r_square, r_circle, deg) {
        this.x = x;
        this.y = y;
        this.r_hour = r_hour;
        this.r_minute = r_minute;
        this.r_second = r_second;
        this.r_text = r_text;
        this.r_square = r_square;
        this.r_circle = r_circle;
        this.deg = deg;
    }
    draw() {
        // 画圆
        this.drawCircle(0, 0, this.r, '#fff');
        // 获取当前时间
        var date = new Date();
        // 根据当前时间获取对应的角度
        var h = date.getHours() * (this.deg / 12) - Math.PI / 2;
        var m = date.getMinutes() * (this.deg / 60) - Math.PI / 2;
        var s = date.getSeconds() * (this.deg / 60) - Math.PI / 2;
        // 3、画指针
        this.drawLine(0, 0, this.r_hour * Math.cos(h), this.r_hour * Math.sin(h), '#000', 10);
        this.drawLine(0, 0, this.r_minute * Math.cos(m), this.r_minute * Math.sin(m), '#000', 6);
        this.drawLine(0, 0, this.r_second * Math.cos(s), this.r_second * Math.sin(s), '#000', 4);
        // 4、画指针中心
        this.drawCircle(0, 0, this.r_circle, 'black');
        // 5、画1-12数字
        for (var i = 1; i <= 12; i++) {
            var β = ((Math.PI * 2) / 12) * i - Math.PI / 2;
            var x = this.r_text * Math.cos(β);
            var y = this.r_text * Math.sin(β);
            this.drawText(i, x, y);
        }
        // 6、画60个刻度
        for (var i = 1; i <= 60; i++) {
            var β = ((Math.PI * 2) / 60) * i - Math.PI / 2;
            var x1 = this.r * Math.cos(β); // 最外层元的半径
            var y1 = this.r * Math.sin(β);
            if (i % 5 === 0) {
                var x2 = this.r_square * Math.cos(β);
                var y2 = this.r_square * Math.sin(β);
                this.drawLine(x1, y1, x2, y2, 'green', 3);
            } else {
                var x2 = (this.r_square + 5) * Math.cos(β);
                var y2 = (this.r_square + 5) * Math.sin(β);
                this.drawLine(x1, y1, x2, y2, '#999', 3);
            }
        }
    }
    drawCircle(x, y, r, color) {
        ctx.beginPath();
        ctx.arc(x, y, r, 0, Math.PI * 2);
        ctx.fillStyle = color;
        ctx.fill();
        ctx.closePath();
    }
    drawText(text, x, y) {
        ctx.font = '26px 微软雅黑';
        ctx.fillStyle = '#000';
        ctx.textAlign = 'center';
        ctx.textBaseline = 'middle';
        ctx.fillText(text, x, y);
    }
    drawLine(x1, y1, x2, y2, color, width) {
        ctx.beginPath();
        ctx.moveTo(x1, y1);
        ctx.lineTo(x2, y2);
        ctx.strokeStyle = color;
        ctx.lineWidth = width;
        ctx.lineCap = 'round'; // 指针尾部圆滑
        ctx.stroke();
        ctx.closePath();
    }
}
ctx.translate(canvas.width / 2, canvas.height / 2);
let clock = new Clock(200, 200, 180, 80, 120, 140, 140, 165, 10, Math.PI * 2);
clock.draw();

const timerId = setInterval(() => {
    ctx.clearRect(0, 0, 400, 400);
    clock.draw();
}, 1000);
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Hoki802

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值