缩放

<canvas id="canvas"></canvas>
window.onload = function () {
    var flag = 0;
    var scale = 0;
    var flagScale = 0;
    var canvas = document.querySelector("#canvas");

    if (canvas.getContext) {
        const ctx = canvas.getContext('2d');

        const getPixelRatio = (context) => {
            return window.devicePixelRatio || 1;
        }

        // 高清绘制
        const ratio = getPixelRatio();
        canvas.style.width = document.documentElement.clientWidth + 'px';
        canvas.style.height = document.documentElement.clientHeight + 'px';
        canvas.width = document.documentElement.clientWidth * ratio;
        canvas.height = document.documentElement.clientHeight * ratio;

        // 此处保存默认状态到样式栈中
        ctx.save();

        // -----------此处修改 样式容器 start-----------
        // 原点位置:(150,150)
        ctx.translate(150, 150);
        ctx.beginPath();
        // 偏移量为自身的一半
        ctx.fillRect(-50, -50, 100, 100);
        // -----------此处修改 样式容器 end-----------

        // 此处弹出样式栈中的默认状态,替换当前样式容器的样式
        ctx.restore();

        setInterval(function () {
            flag++;
            ctx.clearRect(0, 0, canvas.width, canvas.height);
            ctx.save();
            ctx.translate(150, 150);
            // 每次旋转 1 度
            ctx.rotate(flag * Math.PI / 180);

            if (scale == 100) {
                flagScale = -1;
            } else if (scale == 0) {
                flagScale = 1;
            }
            scale += flagScale;
            // 缩放
            ctx.scale(scale / 50, scale / 50);

            ctx.beginPath();
            ctx.fillRect(-50, -50, 100, 100);
            ctx.restore();
        }, 10)
    }
}

表盘

<canvas id="clock" width="400" height="400"></canvas>
window.onload = function () {
    var clock = document.querySelector("#clock");
    if (clock.getContext) {
        var ctx = clock.getContext("2d");

        setInterval(function () {
            ctx.clearRect(0, 0, clock.width, clock.height);
            move();
        }, 1000);
        move();

        function move() {
            ctx.save();
            ctx.lineWidth = 8;
            ctx.strokeStyle = "black";
            ctx.lineCap = "round";
            ctx.translate(200, 200);
            ctx.rotate((-90 * Math.PI) / 180);
            ctx.beginPath();

            //外层空心圆盘
            ctx.save();
            ctx.strokeStyle = "#325FA2";
            ctx.lineWidth = 14;
            ctx.beginPath();
            ctx.arc(0, 0, 140, 0, (360 * Math.PI) / 180);
            ctx.stroke();
            ctx.restore();

            //时针刻度
            ctx.save();
            for (var i = 0; i < 12; i++) {
                ctx.rotate((30 * Math.PI) / 180);
                ctx.beginPath();
                ctx.moveTo(100, 0);
                ctx.lineTo(120, 0);
                ctx.stroke();
            }
            ctx.restore();

            //分针刻度
            ctx.save();
            ctx.lineWidth = 4;
            for (var i = 0; i < 60; i++) {
                ctx.rotate((6 * Math.PI) / 180);
                if ((i + 1) % 5 != 0) {
                    ctx.beginPath();
                    ctx.moveTo(117, 0);
                    ctx.lineTo(120, 0);
                    ctx.stroke();
                }
            }
            ctx.restore();

            //时针 分针 秒针 表座
            var date = new Date();
            var s = date.getSeconds();
            var m = date.getMinutes() + s / 60;
            var h = date.getHours() + m / 60;
            h = h > 12 ? h - 12 : h;

            //时针
            ctx.save();
            ctx.lineWidth = 14;
            ctx.rotate((h * 30 * Math.PI) / 180);
            ctx.beginPath();
            ctx.moveTo(-20, 0);
            ctx.lineTo(80, 0);
            ctx.stroke();
            ctx.restore();

            //分针
            ctx.save();
            ctx.lineWidth = 10;
            ctx.rotate((m * 6 * Math.PI) / 180);
            ctx.beginPath();
            ctx.moveTo(-28, 0);
            ctx.lineTo(112, 0);
            ctx.stroke();
            ctx.restore();

            //秒针
            ctx.save();
            ctx.lineWidth = 6;
            ctx.strokeStyle = "#D40000";
            ctx.fillStyle = "#D40000";
            ctx.rotate((s * 6 * Math.PI) / 180);
            ctx.beginPath();
            ctx.moveTo(-30, 0);
            ctx.lineTo(83, 0);
            ctx.stroke();

            //表座
            ctx.beginPath();
            ctx.arc(0, 0, 10, 0, (360 * Math.PI) / 180);
            ctx.fill();

            //秒头
            ctx.beginPath();
            ctx.arc(96, 0, 10, 0, (360 * Math.PI) / 180);
            ctx.stroke();
            ctx.restore();
            ctx.restore();
        }
    }
};

马赛克

<canvas id="canvas" height="400">您的浏览器不支持 canvas</canvas>
var canvas = document.querySelector("#canvas");
if (canvas.getContext) {
    var ctx = canvas.getContext("2d");

    const getPixelRatio = (context) => {
        return window.devicePixelRatio || 1;
    }
    const ratio = getPixelRatio();
    canvas.style.width = document.documentElement.clientWidth - 10 + 'px';
    canvas.style.height = document.documentElement.clientHeight - 10 + 'px';
    canvas.width = document.documentElement.clientWidth * ratio;
    canvas.height = document.documentElement.clientHeight * ratio;

    var img = new Image();
    img.src = "./meimei.jpg";

    img.onload = function () {
        draw(img.width / 2, img.height / 2);
    }

    function draw(width, height) {
        ctx.drawImage(img, 0, 0, width, height);

        var oldImgdata = ctx.getImageData(0, 0, width, height); // 获取原图
        var newImgdata = ctx.createImageData(width, height);

        /*  马赛克:
        		1.选取一个 x*x 的马赛克矩形
        		2.从马赛克矩形中随机抽出一个像素点的信息(rgba)
        		3.将整个马赛克矩形中的像素点信息统一调成随机抽出的那个
        */
        var size = 5; // 选取一个 5*5马赛克矩形
        for (var i = 0; i < oldImgdata.width / size; i++) {
            for (var j = 0; j < oldImgdata.height / size; j++) {
                // (i,j)  每一个马赛克矩形的坐标
                // 从马赛克矩形中随机抽出一个像素点的信息(rgba)
                // Math.random()  [0,1)
                // Math.random()*size  [0,5)
                // Math.floor(Math.random()*size) [0,4]
                var color = getPxInfo(oldImgdata,
                    i * size + Math.floor(Math.random() * size),
                    j * size + Math.floor(Math.random() * size));
                // 将整个马赛克矩形中的像素点信息统一调成随机抽出的那个
                for (var a = 0; a < size; a++) {
                    for (var b = 0; b < size; b++) {
                        setPxInfo(newImgdata, i * size + a, j * size + b, color)
                    }
                }
            }
        }
        // ctx.clearRect(0, 0, canvas .width, canvas .height);
        ctx.putImageData(newImgdata, img.width, 0);
    }

    function getPxInfo(imgdata, x, y) {
        var color = [];
        var data = imgdata.data;
        var w = imgdata.width;
        var h = imgdata.height;
        color[0] = data[(y * w + x) * 4];
        color[1] = data[(y * w + x) * 4 + 1];
        color[2] = data[(y * w + x) * 4 + 2];
        color[3] = data[(y * w + x) * 4 + 3];
        return color;
    }

    function setPxInfo(imgdata, x, y, color) {
        var data = imgdata.data;
        var w = imgdata.width;
        var h = imgdata.height;
        data[(y * w + x) * 4] = color[0];
        data[(y * w + x) * 4 + 1] = color[1];
        data[(y * w + x) * 4 + 2] = color[2];
        data[(y * w + x) * 4 + 3] = color[3];
    }
}

绘制直角坐标系

<canvas id="canvas" width="600" height="400">您的浏览器不支持 canvas</canvas>
const canvas = document.getElementById('canvas');
const ctx = canvas.getContext('2d');

const getPixelRatio = (context) => {
    return window.devicePixelRatio || 1;
}

// 高清绘制
const ratio = getPixelRatio();
canvas.style.width = canvas.width + 'px';
canvas.style.height = canvas.height + 'px';
canvas.width = canvas.width * ratio;
canvas.height = canvas.height * ratio;

// 提前设置相关属性
const ht = canvas.clientHeight;
const wd = canvas.clientWidth;
const pad = 20;
const bottomPad = 20;
const step = 100;

const drawAxis = (options) => {
    const {
        ht,
        wd,
        pad,
        bottomPad,
        step,
        ctx
    } = options;

    // 绘制坐标轴
    ctx.beginPath();
    ctx.lineWidth = 2;
    ctx.strokeStyle = 'lightblue';
    ctx.moveTo(pad, pad);
    ctx.lineTo(pad, ht * ratio - bottomPad);
    ctx.lineTo(wd * ratio - pad, ht * ratio - bottomPad);
    ctx.stroke();
    ctx.closePath();

    // 绘制 X 轴方向刻度
    ctx.beginPath();
    ctx.lineWidth = 1;
    ctx.strokeStyle = '#666';
    for (let i = 1; i < Math.floor(wd * ratio / step); i++) {
        ctx.moveTo(pad + i * step, ht * ratio - bottomPad);
        ctx.lineTo(pad + i * step, ht * ratio - bottomPad - 10);
    }
    ctx.stroke();
    ctx.closePath();

    // 绘制 Y 轴方向刻度
    ctx.beginPath();
    ctx.lineWidth = 1;
    ctx.strokeStyle = '#666';
    for (let i = 1; i < Math.floor(ht * ratio / step); i++) {
        ctx.moveTo(pad, (ht * ratio - bottomPad) - (i * step));
        ctx.lineTo(pad + 10, (ht * ratio - bottomPad) - (i * step));
    }
    ctx.stroke();
    ctx.closePath();
}

drawAxis({
    ht: ht,
    wd: wd,
    pad: pad,
    bottomPad: bottomPad,
    step: step,
    ctx: ctx
});

绘制直方图

<canvas id="canvas" width="600" height="400">您的浏览器不支持 canvas</canvas>
const canvas = document.getElementById("canvas");
const ctx = canvas.getContext("2d");
const getPixelRatio = (context) => {
    return window.devicePixelRatio || 1;
};

// 高清绘制
const ratio = getPixelRatio();
canvas.style.width = canvas.width + "px";
canvas.style.height = canvas.height + "px";
canvas.width = canvas.width * ratio;
canvas.height = canvas.height * ratio;

// 提前设置相关属性
const ht = canvas.clientHeight;
const wd = canvas.clientWidth;
const pad = 20;
const bottomPad = 20;
const step = 100;

const drawAxis = (options) => {
    const {
        ht,
        wd,
        pad,
        bottomPad,
        step,
        ctx
    } = options;
    // 绘制坐标轴
    ctx.beginPath();
    ctx.lineWidth = 2;
    ctx.strokeStyle = "lightblue";
    ctx.moveTo(pad, pad);
    ctx.lineTo(pad, ht * ratio - bottomPad);
    ctx.lineTo(wd * ratio - pad, ht * ratio - bottomPad);
    ctx.stroke();
    ctx.closePath();
    // 绘制 X 轴方向刻度
    ctx.beginPath();
    ctx.lineWidth = 1;
    ctx.strokeStyle = "#666";
    for (let i = 1; i < Math.floor((wd * ratio) / step); i++) {
        ctx.moveTo(pad + i * step, ht * ratio - bottomPad);
        ctx.lineTo(pad + i * step, ht * ratio - bottomPad + 10);
    }
    ctx.stroke();
    ctx.closePath();

    // 绘制 Y 轴方向刻度
    ctx.beginPath();
    ctx.lineWidth = 1;
    ctx.strokeStyle = "#666";
    for (let i = 1; i < Math.floor((ht * ratio) / step); i++) {
        ctx.moveTo(pad, ht * ratio - bottomPad - i * step);
        ctx.lineTo(pad + 10, ht * ratio - bottomPad - i * step);
    }
    ctx.stroke();
    ctx.closePath();
};

drawAxis({
    ht: ht,
    wd: wd,
    pad: pad,
    bottomPad: bottomPad,
    step: step,
    ctx: ctx,
});

// 绘制矩形:描边+填充
// ctx.beginPath()
// ctx.lineWidth = 5
// ctx.strokeStyle = 'orange'
// ctx.fillStyle = 'hotpink'
// ctx.rect(100, 100, 300, 200)
// ctx.fill()
// ctx.stroke()
// ctx.closePath()

// 绘制矩形:描边
// ctx.beginPath()
// ctx.lineWidth = 4
// ctx.strokeStyle = 'seagreen'
// ctx.strokeRect(100, 310, 300, 200)
// ctx.closePath()

// 绘制矩形:填充
// ctx.beginPath()
// ctx.fillStyle = 'skyblue'
// ctx.fillRect(410, 310, 300, 200)
// ctx.closePath()
// 绘制直方图
ctx.beginPath();
for (var i = 1; i < Math.floor((wd * ratio) / step); i++) {
    // 随机高度 [300,350)
    const height = Math.random() * 300 + 50;
    // 随机颜色 [0,255)的16进制
    ctx.fillStyle = "#" + parseInt(Math.random() * 0xffffff).toString(16);
    // x,y,宽度,高度
    ctx.fillRect(i * step, ht * ratio - bottomPad - height, 40, height);
}
ctx.closePath();

绘制圆弧

<canvas id="canvas" width="600" height="400">您的浏览器不支持 canvas</canvas>
const canvas = document.getElementById("canvas");
const ctx = canvas.getContext("2d");
const getPixelRatio = (context) => {
  return window.devicePixelRatio || 1;
};

// 高清绘制
const ratio = getPixelRatio();
canvas.style.width = canvas.width + "px";
canvas.style.height = canvas.height + "px";
canvas.width = canvas.width * ratio;
canvas.height = canvas.height * ratio;

// 提前设置相关属性
const ht = canvas.clientHeight;
const wd = canvas.clientWidth;
const pad = 20;
const bottomPad = 20;
const step = 100;

const drawAxis = (options) => {
  const { ht, wd, pad, bottomPad, step, ctx } = options;
  // 绘制坐标轴
  ctx.beginPath();
  ctx.lineWidth = 2;
  ctx.strokeStyle = "lightblue";
  ctx.moveTo(pad, pad);
  ctx.lineTo(pad, ht * ratio - bottomPad);
  ctx.lineTo(wd * ratio - pad, ht * ratio - bottomPad);
  ctx.stroke();
  ctx.closePath();
  // 绘制 X 轴方向刻度
  ctx.beginPath();
  ctx.lineWidth = 1;
  ctx.strokeStyle = "#666";
  for (let i = 1; i < Math.floor((wd * ratio) / step); i++) {
    ctx.moveTo(pad + i * step, ht * ratio - bottomPad);
    ctx.lineTo(pad + i * step, ht * ratio - bottomPad + 10);
  }
  ctx.stroke();
  ctx.closePath();

  // 绘制 Y 轴方向刻度
  ctx.beginPath();
  ctx.lineWidth = 1;
  ctx.strokeStyle = "#666";
  for (let i = 1; i < Math.floor((ht * ratio) / step); i++) {
    ctx.moveTo(pad, ht * ratio - bottomPad - i * step);
    ctx.lineTo(pad + 10, ht * ratio - bottomPad - i * step);
  }
  ctx.stroke();
  ctx.closePath();
};

drawAxis({
  ht: ht,
  wd: wd,
  pad: pad,
  bottomPad: bottomPad,
  step: step,
  ctx: ctx,
});

// 绘制圆环
ctx.beginPath();
ctx.lineWidth = 2;
ctx.strokeStyle = "orange";
// x,y,r,开始角度,结束角度,true为逆时针绘制
ctx.arc(400, 300, 200, 0, Math.PI / 4, true);
ctx.stroke();
ctx.closePath();

// 绘制圆形
ctx.beginPath();
ctx.fillStyle = "skyblue";
ctx.moveTo(400, 300);
// x,y,r,开始角度,结束角度,true为逆时针绘制
ctx.arc(400, 300, 100, 0, -Math.PI / 2, true);
ctx.fill();
ctx.closePath();

绘制饼图

<canvas id="canvas" width="600" height="400">您的浏览器不支持 canvas</canvas>
const canvas = document.getElementById("canvas");
const ctx = canvas.getContext("2d");
const getPixelRatio = (context) => {
  return window.devicePixelRatio || 1;
};

// 高清绘制
const ratio = getPixelRatio();
canvas.style.width = canvas.width + "px";
canvas.style.height = canvas.height + "px";
canvas.width = canvas.width * ratio;
canvas.height = canvas.height * ratio;

// 提前设置相关属性
const ht = canvas.clientHeight;
const wd = canvas.clientWidth;
const pad = 20;
const bottomPad = 20;
const step = 100;

const drawAxis = (options) => {
  const { ht, wd, pad, bottomPad, step, ctx } = options;
  // 绘制坐标轴
  ctx.beginPath();
  ctx.lineWidth = 2;
  ctx.strokeStyle = "lightblue";
  ctx.moveTo(pad, pad);
  ctx.lineTo(pad, ht * ratio - bottomPad);
  ctx.lineTo(wd * ratio - pad, ht * ratio - bottomPad);
  ctx.stroke();
  ctx.closePath();
  // 绘制 X 轴方向刻度
  ctx.beginPath();
  ctx.lineWidth = 1;
  ctx.strokeStyle = "#666";
  for (let i = 1; i < Math.floor((wd * ratio) / step); i++) {
    ctx.moveTo(pad + i * step, ht * ratio - bottomPad);
    ctx.lineTo(pad + i * step, ht * ratio - bottomPad + 10);
  }
  ctx.stroke();
  ctx.closePath();

  // 绘制 Y 轴方向刻度
  ctx.beginPath();
  ctx.lineWidth = 1;
  ctx.strokeStyle = "#666";
  for (let i = 1; i < Math.floor((ht * ratio) / step); i++) {
    ctx.moveTo(pad, ht * ratio - bottomPad - i * step);
    ctx.lineTo(pad + 10, ht * ratio - bottomPad - i * step);
  }
  ctx.stroke();
  ctx.closePath();
};

drawAxis({
  ht: ht,
  wd: wd,
  pad: pad,
  bottomPad: bottomPad,
  step: step,
  ctx: ctx,
});

ctx.beginPath();
ctx.shadowOffsetX = 0;
ctx.shadowOffsetY = 0;
ctx.shadowBlur = 4;
ctx.shadowColor = "#333";
ctx.fillStyle = "#5C1918";
ctx.moveTo(400, 300);
ctx.arc(400, 300, 100, -Math.PI / 2, -Math.PI / 4);
ctx.fill();
ctx.closePath();

ctx.beginPath();
ctx.shadowOffsetX = 0;
ctx.shadowOffsetY = 0;
ctx.shadowBlur = 4;
ctx.shadowColor = "#5C1918";
ctx.fillStyle = "#A32D29";
ctx.moveTo(400, 300);
ctx.arc(400, 300, 110, -Math.PI / 4, Math.PI / 4);
ctx.fill();
ctx.closePath();

ctx.beginPath();
ctx.shadowOffsetX = 0;
ctx.shadowOffsetY = 0;
ctx.shadowBlur = 4;
ctx.shadowColor = "#A32D29";
ctx.fillStyle = "#B9332E";
ctx.moveTo(400, 300);
ctx.arc(400, 300, 120, Math.PI / 4, (Math.PI * 5) / 8);
ctx.fill();
ctx.closePath();

ctx.beginPath();
ctx.shadowOffsetX = 0;
ctx.shadowOffsetY = 0;
ctx.shadowBlur = 4;
ctx.shadowColor = "#B9332E";
ctx.fillStyle = "#842320";
ctx.moveTo(400, 300);
ctx.arc(400, 300, 130, (Math.PI * 5) / 8, Math.PI);
ctx.fill();
ctx.closePath();

ctx.beginPath();
ctx.shadowOffsetX = 0;
ctx.shadowOffsetY = 0;
ctx.shadowBlur = 4;
ctx.shadowColor = "#842320";
ctx.fillStyle = "#D76662";
ctx.moveTo(400, 300);
ctx.arc(400, 300, 140, Math.PI, (Math.PI * 3) / 2);
ctx.fill();
ctx.closePath();

碰撞检测

<canvas id="canvas">您的浏览器不支持 canvas</canvas>
const canvas = document.getElementById('canvas');
const ctx = canvas.getContext('2d');

const getPixelRatio = (context) => {
    return window.devicePixelRatio || 1;
}

// 高清绘制
const ratio = getPixelRatio();
canvas.style.width = document.documentElement.clientWidth + 'px';
canvas.style.height = document.documentElement.clientHeight + 'px';
canvas.width = document.documentElement.clientWidth * ratio;
canvas.height = document.documentElement.clientHeight * ratio;

// 绘制小球
const drawCircle = (x, y, r) => {
    ctx.beginPath();
    ctx.fillStyle = 'orange';
    ctx.arc(x, y, r, 0, Math.PI * 2);
    ctx.fill();
    ctx.closePath();
}

// 配置属性
const wd = canvas.clientWidth * ratio;
const ht = canvas.clientHeight * ratio;
let x = y = 100; // 初始坐标
const r = 40;
let xSpeed = 6;
let ySpeed = 4;

drawCircle(x, y, r);

setInterval(() => {
    ctx.clearRect(0, 0, wd, ht); // 清空画布
    // 小球超出左右的边界,xSpeed偏移量为取反,向相反方向移动
    if (x - r <= 0 || x + r >= wd) {
        xSpeed = -xSpeed;
    }
    // 小球超出上下的边界,ySpeed偏移量取反,向相反方向移动
    if (y - r <= 0 || y + r >= ht) {
        ySpeed = -ySpeed;
    }
    // 小球向右下运动
    x += xSpeed;
    y += ySpeed;
    drawCircle(x, y, r);
}, 20);

弹性球

<canvas id="canvas">您的浏览器不支持 canvas</canvas>
const canvas = document.getElementById('canvas');
const ctx = canvas.getContext('2d');
const getPixelRatio = (context) => {
    return window.devicePixelRatio || 1;
}

// 高清绘制
const ratio = getPixelRatio()
canvas.style.width = document.documentElement.clientWidth + 'px';
canvas.style.height = document.documentElement.clientHeight + 'px';
canvas.width = document.documentElement.clientWidth * ratio;
canvas.height = document.documentElement.clientHeight * ratio;

class Ball {
    constructor(canvas) {
        this.canvas = canvas;
        this.ctx = this.canvas.getContext('2d');
        this.wd = this.canvas.clientWidth * ratio;
        this.ht = this.canvas.clientHeight * ratio;
        // 随机数 半径:【40,50)
        this.r = Math.random() * 40 + 10;
        // 随机数 x轴:【this.wd - (this.r * 2),this.wd - (this.r * 2)+ this.r)
        this.x = Math.random() * (this.wd - (this.r * 2)) + this.r;
        // 随机数 y轴:【this.ht - (this.r * 2),this.ht - (this.r * 2)+ this.r)
        this.y = Math.random() * (this.ht - (this.r * 2)) + this.r;
        // 随机数 颜色:【0,235)16进制
        this.color = '#' + parseInt(Math.random() * 0xFFFFFF).toString(16);
        // 随机数 x偏移:【4,10)
        this.xSpeed = Math.random() * 4 + 6;
        // 随机数 y偏移:【6,10)
        this.ySpeed = Math.random() * 6 + 4;
        this.init();
    }
    init() {
        this.run();
        this.draw();
    }
    draw() {
        this.ctx.beginPath();
        this.ctx.fillStyle = this.color;
        this.ctx.arc(this.x, this.y, this.r, 0, 2 * Math.PI);
        this.ctx.fill();
        this.ctx.closePath();
    }
    run() {
        if (this.x - this.r <= 0 || this.x + this.r >= this.wd) {
            this.xSpeed = -this.xSpeed;
        }
        if (this.y - this.r <= 0 || this.y + this.r >= this.ht) {
            this.ySpeed = -this.ySpeed;
        }
        this.x += this.xSpeed;
        this.y += this.ySpeed;
    }
}

let ballArr = [];
for (let i = 0; i < 100; i++) {
    let ball = new Ball(canvas);
    ballArr.push(ball);
}

// 动画
setInterval(() => {
    ctx.clearRect(0, 0, canvas.clientWidth * ratio, canvas.clientHeight * ratio);
    for (let i = 0; i < ballArr.length; i++) {
        let ball = ballArr[i];
        ball.init();
    }
}, 15);

绘制关系图

<canvas id="canvas">您的浏览器不支持 canvas</canvas>
const canvas = document.getElementById('canvas');
const ctx = canvas.getContext('2d');
const getPixelRatio = (context) => {
    return window.devicePixelRatio || 1;
}

// 高清绘制
const ratio = getPixelRatio();
canvas.style.width = document.documentElement.clientWidth + 'px';
canvas.style.height = document.documentElement.clientHeight + 'px';
canvas.width = document.documentElement.clientWidth * ratio;
canvas.height = document.documentElement.clientHeight * ratio;

class Ball {
    constructor(options) {
        this.canvas = options.canvas;
        this.text = options.title;
        this.ctx = this.canvas.getContext('2d');
        this.wd = this.canvas.clientWidth * ratio;
        this.ht = this.canvas.clientHeight * ratio;
        this.r = Math.random() * 40 + 10;
        this.x = Math.random() * (this.wd - (this.r * 2)) + this.r;
        this.y = Math.random() * (this.ht - (this.r * 2)) + this.r;
        this.color = '#' + parseInt(Math.random() * 0xFFFFFF).toString(16);
        this.xSpeed = Math.random() * 4 + 6;
        this.ySpeed = Math.random() * 6 + 4;
        this.init();
    }
    init() {
        this.run();
        this.draw();
    }
    draw() {
        this.drawCircle();
        this.drawText(this.text, this.x, this.y + this.r + 10);
    }
    // 绘制圆形
    drawCircle() {
        this.ctx.beginPath();
        this.ctx.fillStyle = this.color;
        this.ctx.arc(this.x, this.y, this.r, 0, 2 * Math.PI);
        this.ctx.fill();
        this.ctx.closePath();
    }
    // 绘制文字
    drawText(text, x, y) {
        this.ctx.font = 'normal 20px 微软雅黑';
        this.ctx.textAlign = 'center';
        this.ctx.textBaseline = 'middle';
        this.ctx.fillText(text, x, y);
    }
    // 绘制线条
    drawLine(startX, startY, endX, endY, color) {
        this.ctx.beginPath();
        this.ctx.lineWidth = 1;
        this.ctx.strokeStyle = color || '#666';
        this.ctx.moveTo(startX, startY);
        this.ctx.lineTo(endX, endY);
        this.ctx.stroke();
        this.ctx.closePath();
    }
    run() {
        if (this.x - this.r <= 0 || this.x + this.r >= this.wd) {
            this.xSpeed = -this.xSpeed;
        }
        if (this.y - this.r <= 0 || this.y + this.r >= this.ht) {
            this.ySpeed = -this.ySpeed;
        }
        this.x += this.xSpeed;
        this.y += this.ySpeed;
    }
}

let ballArr = [];
let titleArr = ['Vue', 'Webpack', 'React', 'Angular', 'Python', 'Nodejs', 'eCharts', 'Next'];

for (let i = 0; i < 8; i++) {
    let ball = new Ball({
        canvas: canvas,
        title: titleArr[i]
    })
    ballArr.push(ball);

    // 连线
    for (let j = 0; j < i; j++) {
        let preBall = ballArr[j];
        ball.drawLine(ball.x, ball.y, preBall.x, preBall.y);
    }
}

// 做动画
setInterval(() => {
    ctx.clearRect(0, 0, canvas.clientWidth * ratio + 10, canvas.clientHeight * ratio + 10);
    // 1.先绘制连线
    for (let i = 0; i < ballArr.length; i++) {
        let ball = ballArr[i];
        // 连线
        for (let j = 0; j < i; j++) {
            let preBall = ballArr[j];
            ball.drawLine(ball.x, ball.y, preBall.x, preBall.y, ball.color);
        }
    }
    // 2.再绘制小球(小球会在线的上面绘制)
    for (let i = 0; i < ballArr.length; i++) {
        let ball = ballArr[i];
        ball.init();
    }
}, 15);
打赏作者
您的打赏是我前进的动力
微信
支付宝
评论

你好👏🏻,我是 ✍🏻   疯狂 codding 中...

粽子

这有关于前端开发的技术文档和你分享。

相信你可以在这里找到对你有用的知识和教程。

了解更多

目录

  1. 1. 缩放
  2. 2. 表盘
  3. 3. 马赛克
  4. 4. 绘制直角坐标系
  5. 5. 绘制直方图
  6. 6. 绘制圆弧
  7. 7. 绘制饼图
  8. 8. 碰撞检测
  9. 9. 弹性球
  10. 10. 绘制关系图