当前位置: 首页 > article >正文

Html5学习教程,从入门到精通, HTML5 Canvas 全攻略:从入门到精通(19)

HTML5 Canvas 全攻略:从入门到精通

一、Canvas 基础

1.1 什么是 Canvas

Canvas 是 HTML5 中的一个绘图元素,允许通过 JavaScript 绘制图形、图像和动画。它提供了一个空白的绘图区域,开发者可以使用其 API 进行各种绘图操作。

1.2 创建 Canvas 元素

在 HTML 中,通过 <canvas> 标签创建 Canvas 元素,并为其指定 idwidthheight 属性。

<canvas id="myCanvas" width="500" height="500"></canvas>

1.3 获取绘图上下文

在 JavaScript 中,通过 getContext() 方法获取 Canvas 的绘图上下文,通常使用 2D 上下文进行绘图。

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

二、绘图基础

2.1 设置线条样式

可以使用 lineWidthstrokeStyle 等属性设置线条的宽度和颜色。

ctx.lineWidth = 5; // 设置线条宽度
ctx.strokeStyle = 'blue'; // 设置线条颜色

2.2 绘制路径

使用 beginPath() 开始绘制路径,moveTo() 移动到起始点,lineTo() 绘制直线,最后使用 stroke() 绘制路径。

ctx.beginPath();
ctx.moveTo(50, 50);
ctx.lineTo(200, 50);
ctx.stroke();

2.3 填充路径

使用 fillStyle 设置填充颜色,fill() 方法填充路径。

ctx.fillStyle = 'red';
ctx.fillRect(50, 100, 100, 50); // 绘制并填充矩形

三、绘制图形

3.1 矩形

使用 rect() 方法绘制矩形路径,再结合 stroke()fill() 绘制边框或填充。

ctx.beginPath();
ctx.rect(50, 150, 100, 50);
ctx.stroke(); // 绘制矩形边框

3.2 圆形

使用 arc() 方法绘制圆形,参数包括圆心坐标、半径、起始角和结束角。

ctx.beginPath();
ctx.arc(150, 250, 40, 0, Math.PI * 2);
ctx.stroke();

3.3 椭圆

使用 ellipse() 方法绘制椭圆,参数包括圆心坐标、长轴半径、短轴半径、旋转角度、起始角和结束角。

ctx.beginPath();
ctx.ellipse(250, 250, 50, 30, 0, 0, Math.PI * 2);
ctx.stroke();

四、文本绘制

4.1 设置文本样式

使用 font 设置字体,textAlign 设置文本对齐方式。

ctx.font = '20px Arial';
ctx.textAlign = 'center';

4.2 绘制文本

使用 fillText() 绘制填充文本,strokeText() 绘制描边文本。

ctx.fillText('Hello Canvas!', 150, 300);
ctx.strokeText('Hello Canvas!', 150, 350);

五、图像绘制

5.1 绘制图像

使用 drawImage() 方法绘制图像,可以绘制整个图像或部分图像。

const img = new Image();
img.src = 'image.jpg';
img.onload = function() {
  ctx.drawImage(img, 50, 50, 100, 100); // 绘制图像到指定区域
};

六、变换

6.1 平移

使用 translate() 方法平移绘图上下文的原点。

ctx.translate(50, 50);
ctx.fillRect(0, 0, 50, 50); // 相对于平移后的原点绘制矩形

6.2 旋转

使用 rotate() 方法旋转绘图上下文。

ctx.rotate(Math.PI / 4); // 旋转 45 度
ctx.fillRect(0, 0, 50, 50);

6.3 缩放

使用 scale() 方法缩放绘图上下文。

ctx.scale(2, 2); // 水平和垂直方向各缩放 2 倍
ctx.fillRect(0, 0, 50, 50);

七、动画

7.1 创建动画

使用 requestAnimationFrame() 方法创建动画,不断更新绘图内容。

let x = 0;
function animate() {
  ctx.clearRect(0, 0, canvas.width, canvas.height); // 清除画布
  ctx.fillRect(x, 50, 50, 50); // 绘制矩形
  x++; // 更新位置
  if (x < canvas.width) {
    requestAnimationFrame(animate); // 请求下一帧动画
  }
}
animate();

八、事件处理

8.1 监听鼠标事件

可以为 Canvas 元素添加鼠标事件监听器,实现与用户的交互。

canvas.addEventListener('click', function(event) {
  const rect = canvas.getBoundingClientRect();
  const clickX = event.clientX - rect.left;
  const clickY = event.clientY - rect.top;
  ctx.beginPath();
  ctx.arc(clickX, clickY, 10, 0, Math.PI * 2);
  ctx.fill(); // 在点击位置绘制圆形
});

九、高级技巧

9.1 阴影效果

使用 shadowColorshadowBlur 等属性添加阴影效果。

ctx.shadowColor = 'rgba(0, 0, 0, 0.5)';
ctx.shadowBlur = 10;
ctx.fillRect(50, 50, 100, 50); // 绘制带有阴影的矩形

9.2 渐变和图案填充

创建线性渐变或径向渐变,用于填充图形。

const gradient = ctx.createLinearGradient(0, 0, 200, 0);
gradient.addColorStop(0, 'red');
gradient.addColorStop(1, 'blue');
ctx.fillStyle = gradient;
ctx.fillRect(50, 100, 100, 50); // 使用渐变填充矩形

9.3 复合操作

使用 globalCompositeOperation 属性设置图形的合成方式。

ctx.globalCompositeOperation = 'destination-over';
ctx.fillStyle = 'green';
ctx.fillRect(100, 100, 100, 50); // 使用复合操作绘制矩形

以上是 HTML5 Canvas 的全面知识点及案例代码,涵盖了从基础到高级的各种功能和应用。通过这些示例,你可以深入理解并掌握 Canvas 的强大绘图能力,为你的 Web 开发项目增添丰富的视觉效果。

以下是HTML5 Canvas在实际开发中的一些具体案例,涵盖了不同应用场景,每个案例都附有详细代码和注释:

案例一:Flappy Bird 小游戏

实现思路

  • 使用Canvas绘制游戏背景、小鸟、管道等元素。
  • 监听鼠标点击事件,更新小鸟的垂直速度。
  • 通过物理模拟计算小鸟的运动轨迹,包括重力下降和空气阻力。
  • 定时更新画面,检测小鸟与管道的碰撞,根据碰撞结果更新游戏状态。

核心代码

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Flappy Bird</title>
    <style>
        canvas {
            display: block;
            margin: auto;
            background-color: #70c5ce;
        }
    </style>
</head>
<body>
    <canvas id="gameCanvas" width="400" height="600"></canvas>

    <script>
        const canvas = document.getElementById('gameCanvas');
        const ctx = canvas.getContext('2d');

        // 游戏变量
        let bird = {
            x: 50,
            y: 300,
            width: 40,
            height: 30,
            speed: 0,
            gravity: 0.5,
            jump: -8
        };
        let pipes = [];
        let score = 0;
        let gameRunning = true;

        // 创建管道
        function createPipe() {
            let gapPosition = Math.random() * (canvas.height - 200) + 100;
            pipes.push({
                x: canvas.width,
                y: gapPosition,
                width: 50,
                height: gapPosition - 100,
                passed: false
            });
            pipes.push({
                x: canvas.width,
                y: gapPosition + 100,
                width: 50,
                height: canvas.height - gapPosition - 100,
                passed: false
            });
        }

        // 绘制小鸟
        function drawBird() {
            ctx.fillStyle = 'yellow';
            ctx.fillRect(bird.x, bird.y, bird.width, bird.height);
        }

        // 绘制管道
        function drawPipes() {
            ctx.fillStyle = 'green';
            pipes.forEach(pipe => {
                ctx.fillRect(pipe.x, pipe.y, pipe.width, pipe.height);
            });
        }

        // 更新游戏状态
        function update() {
            // 更新小鸟位置
            bird.speed += bird.gravity;
            bird.y += bird.speed;

            // 创建新管道
            if (pipes.length === 0 || pipes[pipes.length - 1].x < canvas.width - 200) {
                createPipe();
            }

            // 更新管道位置
            for (let i = 0; i < pipes.length; i++) {
                pipes[i].x -= 2;

                // 检测碰撞
                if (pipes[i].x + pipes[i].width > bird.x && pipes[i].x < bird.x + bird.width &&
                    (pipes[i].y > bird.y && pipes[i].y < bird.y + bird.height || pipes[i].y + pipes[i].height > bird.y && pipes[i].y + pipes[i].height < bird.y + bird.height)) {
                    gameRunning = false;
                }

                // 更新得分
                if (!pipes[i].passed && pipes[i].x + pipes[i].width < bird.x) {
                    pipes[i].passed = true;
                    score++;
                }

                // 移除超出屏幕的管道
                if (pipes[i].x + pipes[i].width < 0) {
                    pipes.splice(i, 1);
                    i--;
                }
            }

            // 检测地面碰撞
            if (bird.y + bird.height > canvas.height) {
                gameRunning = false;
            }
        }

        // 游戏主循环
        function gameLoop() {
            ctx.clearRect(0, 0, canvas.width, canvas.height);

            if (gameRunning) {
                update();
            }

            drawBird();
            drawPipes();

            ctx.fillStyle = 'black';
            ctx.font = '20px Arial';
            ctx.fillText('Score: ' + score, 10, 30);

            requestAnimationFrame(gameLoop);
        }

        // 事件监听
        canvas.addEventListener('click', function() {
            if (gameRunning) {
                bird.speed = bird.jump;
            } else {
                // 重置游戏
                bird.y = 300;
                bird.speed = 0;
                pipes = [];
                score = 0;
                gameRunning = true;
            }
        });

        // 启动游戏
        gameLoop();
    </script>
</body>
</html>

案例二:动态烟花秀

实现思路

  • 使用Canvas绘制烟花粒子。
  • 通过定时器控制烟花的生成和爆炸效果。
  • 每个烟花由多个粒子组成,粒子的颜色和速度随机生成。
  • 粒子在爆炸后逐渐消失,形成自然的烟花效果。

核心代码

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Fireworks Show</title>
    <style>
        canvas {
            display: block;
            background-color: black;
        }
    </style>
</head>
<body>
    <canvas id="fireworksCanvas" width="800" height="600"></canvas>

    <script>
        const canvas = document.getElementById('fireworksCanvas');
        const ctx = canvas.getContext('2d');

        // 烟花数组
        let fireworks = [];

        // 烟花类
        class Firework {
            constructor() {
                this.x = Math.random() * canvas.width;
                this.y = canvas.height;
                this.speed = Math.random() * 2 + 2;
                this.angle = Math.random() * Math.PI / 2;
                this.particles = [];
                this.exploded = false;
            }

            // 更新烟花状态
            update() {
                if (!this.exploded) {
                    this.y -= this.speed * Math.sin(this.angle);
                    this.x += this.speed * Math.cos(this.angle);

                    // 检测爆炸条件
                    if (this.y < Math.random() * canvas.height / 2) {
                        this.explode();
                    }
                } else {
                    // 更新粒子状态
                    for (let i = 0; i < this.particles.length; i++) {
                        this.particles[i].update();
                    }

                    // 移除消失的粒子
                    this.particles = this.particles.filter(particle => !particle.fadeOut);
                }
            }

            // 爆炸效果
            explode() {
                this.exploded = true;

                // 创建粒子
                for (let i = 0; i < 100; i++) {
                    let angle = Math.random() * Math.PI * 2;
                    let speed = Math.random() * 3 + 1;
                    let radius = Math.random() * 2 + 1;
                    let red = Math.floor(Math.random() * 256);
                    let green = Math.floor(Math.random() * 256);
                    let blue = Math.floor(Math.random() * 256);

                    this.particles.push({
                        x: this.x,
                        y: this.y,
                        vx: Math.cos(angle) * speed,
                        vy: Math.sin(angle) * speed,
                        radius: radius,
                        red: red,
                        green: green,
                        blue: blue,
                        fadeOut: false
                    });
                }
            }

            // 绘制烟花
            draw() {
                if (!this.exploded) {
                    ctx.beginPath();
                    ctx.arc(this.x, this.y, 2, 0, Math.PI * 2);
                    ctx.fillStyle = 'white';
                    ctx.fill();
                } else {
                    // 绘制粒子
                    this.particles.forEach(particle => {
                        ctx.beginPath();
                        ctx.arc(particle.x, particle.y, particle.radius, 0, Math.PI * 2);
                        ctx.fillStyle = `rgba(${particle.red}, ${particle.green}, ${particle.blue}, ${particle.radius / 3})`;
                        ctx.fill();
                    });
                }
            }
        }

        // 粒子更新方法
        Firework.prototype.particles.update = function() {
            this.x += this.vx;
            this.y += this.vy;
            this.vy += 0.1; // 重力加速度
            this.radius -= 0.05; // 缩小粒子

            // 判断粒子是否消失
            if (this.radius <= 0) {
                this.fadeOut = true;
            }
        };

        // 创建烟花
        function createFirework() {
            fireworks.push(new Firework());
        }

        // 游戏主循环
        function gameLoop() {
            ctx.clearRect(0, 0, canvas.width, canvas.height);

            // 更新烟花
            fireworks.forEach(firework => {
                firework.update();
                firework.draw();
            });

            // 移除已经爆炸且粒子消失的烟花
            fireworks = fireworks.filter(firework => !firework.exploded || firework.particles.length > 0);

            // 随机生成新烟花
            if (Math.random() < 0.02) {
                createFirework();
            }

            requestAnimationFrame(gameLoop);
        }

        // 启动游戏
        gameLoop();
    </script>
</body>
</html>

案例三:绘制图表

实现思路

  • 使用Canvas绘制各种类型的图表,如柱状图、折线图、饼图等。
  • 通过数据数组生成图表的坐标点。
  • 使用不同的颜色和样式区分不同的数据系列。
  • 添加图例和标签,使图表更易读。

核心代码

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Chart Example</title>
    <style>
        canvas {
            border: 1px solid #ccc;
        }
    </style>
</head>
<body>
    <canvas id="chartCanvas" width="600" height="400"></canvas>

    <script>
        const canvas = document.getElementById('chartCanvas');
        const ctx = canvas.getContext('2d');

        // 数据
        const data = [12, 19, 3, 5, 2, 3];
        const labels = ['January', 'February', 'March', 'April', 'May', 'June'];
        const colors = ['#FF6384', '#36A2EB', '#FFCE56', '#4BC0C0', '#9966FF', '#FF9F40'];

        // 绘制柱状图
        function drawBarChart() {
            // 绘制背景
            ctx.fillStyle = '#f8f9fa';
            ctx.fillRect(0, 0, canvas.width, canvas.height);

            // 绘制坐标轴
            ctx.beginPath();
            ctx.moveTo(50, 350);
            ctx.lineTo(550, 350); // X轴
            ctx.lineTo(50, 50); // Y轴
            ctx.strokeStyle = '#6c757d';
            ctx.stroke();

            // 绘制刻度
            for (let i = 0; i <= 7; i++) {
                ctx.beginPath();
                ctx.moveTo(50, 350 - i * 50);
                ctx.lineTo(55, 350 - i * 50);
                ctx.strokeStyle = '#6c757d';
                ctx.stroke();

                ctx.fillStyle = '#6c757d';
                ctx.font = '12px Arial';
                ctx.fillText((7 - i) * 2, 30, 350 - i * 50 + 5);
            }

            // 绘制柱状图
            for (let i = 0; i < data.length; i++) {
                ctx.fillStyle = colors[i];
                ctx.fillRect(80 + i * 80, 350 - data[i] * 30, 60, data[i] * 30);

                // 绘制标签
                ctx.fillStyle = '#6c757d';
                ctx.font = '12px Arial';
                ctx.fillText(labels[i], 80 + i * 80, 370);
            }

            // 绘制图例
            for (let i = 0; i < data.length; i++) {
                ctx.fillStyle = colors[i];
                ctx.fillRect(570, 50 + i * 25, 15, 15);

                ctx.fillStyle = '#6c757d';
                ctx.font = '12px Arial';
                ctx.fillText(labels[i], 590, 65 + i * 25);
            }
        }

        // 绘制折线图
        function drawLineChart() {
            // 绘制背景
            ctx.fillStyle = '#f8f9fa';
            ctx.fillRect(0, 0, canvas.width, canvas.height);

            // 绘制坐标轴
            ctx.beginPath();
            ctx.moveTo(50, 350);
            ctx.lineTo(550, 350); // X轴
            ctx.lineTo(50, 50); // Y轴
            ctx.strokeStyle = '#6c757d';
            ctx.stroke();

            // 绘制刻度
            for (let i = 0; i <= 7; i++) {
                ctx.beginPath();
                ctx.moveTo(50, 350 - i * 50);
                ctx.lineTo(55, 350 - i * 50);
                ctx.strokeStyle = '#6c757d';
                ctx.stroke();

                ctx.fillStyle = '#6c757d';
                ctx.font = '12px Arial';
                ctx.fillText((7 - i) * 2, 30, 350 - i * 50 + 5);
            }

            // 绘制数据点和连线
            ctx.beginPath();
            ctx.moveTo(80, 350 - data[0] * 30);
            for (let i = 1; i < data.length; i++) {
                ctx.lineTo(80 + i * 80, 350 - data[i] * 30);
            }
            ctx.strokeStyle = '#36A2EB';
            ctx.lineWidth = 2;
            ctx.stroke();

            // 绘制数据点圆圈
            for (let i = 0; i < data.length; i++) {
                ctx.beginPath();
                ctx.arc(80 + i * 80, 350 - data[i] * 30, 4, 0, Math.PI * 2);
                ctx.fillStyle = '#36A2EB';
                ctx.fill();
            }

            // 绘制标签
            for (let i = 0; i < data.length; i++) {
                ctx.fillStyle = '#6c757d';
                ctx.font = '12px Arial';
                ctx.fillText(labels[i], 80 + i * 80, 370);
            }

            // 绘制图例
            ctx.fillStyle = '#36A2EB';
            ctx.fillRect(570, 50, 15, 15);

            ctx.fillStyle = '#6c757d';
            ctx.font = '12px Arial';
            ctx.fillText('Data', 590, 65);
        }

        // 绘制饼图
        function drawPieChart() {
            // 绘制背景
            ctx.fillStyle = '#f8f9fa';
            ctx.fillRect(0, 0, canvas.width, canvas.height);

            // 绘制饼图
            let total = data.reduce((sum, value) => sum + value, 0);
            let startAngle = 0;

            for (let i = 0; i < data.length; i++) {
                let endAngle = startAngle + (data[i] / total) * Math.PI * 2;
                ctx.beginPath();
                ctx.moveTo(300, 200);
                ctx.arc(300, 200, 150, startAngle, endAngle);
                ctx.fillStyle = colors[i];
                ctx.fill();
                startAngle = endAngle;
            }

            // 绘制图例
            for (let i = 0; i < data.length; i++) {
                ctx.fillStyle = colors[i];
                ctx.fillRect(570, 50 + i * 30, 15, 15);

                ctx.fillStyle = '#6c757d';
                ctx.font = '12px Arial';
                ctx.fillText(labels[i], 590, 65 + i * 30);
            }
        }

        // 绘制柱状图
        drawBarChart();

        // 绘制折线图
        // drawLineChart();

        // 绘制饼图
        // drawPieChart();
    </script>
</body>
</html>

以上案例展示了HTML5 Canvas在游戏开发、动画效果和数据可视化等实际开发场景中的应用,通过这些示例,你可以深入理解Canvas的强大功能,并将其应用于自己的项目中。


案例四:绘制动态时钟

描述

使用 Canvas 绘制一个动态更新的时钟,显示当前时间,包括时针、分针和秒针。

代码

<canvas id="clockCanvas" width="300" height="300"></canvas>

<script>
  var canvas = document.getElementById("clockCanvas");
  var ctx = canvas.getContext("2d");
  var radius = canvas.height / 2;

  // 将原点移动到画布中心
  ctx.translate(radius, radius);
  radius = radius * 0.90;

  // 每秒更新一次时钟
  setInterval(drawClock, 1000);

  function drawClock() {
    // 清空画布
    ctx.clearRect(-radius, -radius, canvas.width, canvas.height);

    // 绘制时钟外框
    ctx.beginPath();
    ctx.arc(0, 0, radius, 0, 2 * Math.PI);
    ctx.strokeStyle = "black";
    ctx.lineWidth = 5;
    ctx.stroke();

    // 绘制时钟数字
    ctx.font = radius * 0.15 + "px Arial";
    ctx.textBaseline = "middle";
    ctx.textAlign = "center";
    for (var i = 1; i <= 12; i++) {
      var angle = (i * Math.PI) / 6;
      ctx.rotate(angle);
      ctx.translate(0, -radius * 0.85);
      ctx.rotate(-angle);
      ctx.fillText(i.toString(), 0, 0);
      ctx.rotate(angle);
      ctx.translate(0, radius * 0.85);
      ctx.rotate(-angle);
    }

    // 获取当前时间
    var now = new Date();
    var hour = now.getHours();
    var minute = now.getMinutes();
    var second = now.getSeconds();

    // 绘制时针
    hour = hour % 12;
    drawHand((hour * Math.PI) / 6 + (minute * Math.PI) / 360, radius * 0.5, radius * 0.07);

    // 绘制分针
    drawHand((minute * Math.PI) / 30, radius * 0.8, radius * 0.07);

    // 绘制秒针
    drawHand((second * Math.PI) / 30, radius * 0.9, radius * 0.02);
  }

  // 绘制时钟指针
  function drawHand(angle, length, width) {
    ctx.beginPath();
    ctx.lineWidth = width;
    ctx.lineCap = "round";
    ctx.moveTo(0, 0);
    ctx.rotate(angle);
    ctx.lineTo(0, -length);
    ctx.stroke();
    ctx.rotate(-angle);
  }
</script>

案例 五:绘制动态粒子效果

描述

使用 Canvas 绘制随机运动的粒子,粒子之间会连接成线,形成动态背景效果。

代码

<canvas id="particleCanvas" width="800" height="600"></canvas>

<script>
  var canvas = document.getElementById("particleCanvas");
  var ctx = canvas.getContext("2d");
  var particles = [];
  var particleCount = 100;

  // 创建粒子对象
  function Particle() {
    this.x = Math.random() * canvas.width;
    this.y = Math.random() * canvas.height;
    this.vx = Math.random() * 2 - 1;
    this.vy = Math.random() * 2 - 1;
    this.radius = Math.random() * 3 + 1;
  }

  // 初始化粒子数组
  for (var i = 0; i < particleCount; i++) {
    particles.push(new Particle());
  }

  // 绘制粒子
  function draw() {
    ctx.clearRect(0, 0, canvas.width, canvas.height);

    // 更新粒子位置并绘制
    for (var i = 0; i < particles.length; i++) {
      var p = particles[i];

      // 更新位置
      p.x += p.vx;
      p.y += p.vy;

      // 边界检测
      if (p.x < 0 || p.x > canvas.width) p.vx *= -1;
      if (p.y < 0 || p.y > canvas.height) p.vy *= -1;

      // 绘制粒子
      ctx.beginPath();
      ctx.arc(p.x, p.y, p.radius, 0, Math.PI * 2);
      ctx.fillStyle = "rgba(255, 255, 255, 0.8)";
      ctx.fill();

      // 绘制粒子之间的连线
      for (var j = i + 1; j < particles.length; j++) {
        var p2 = particles[j];
        var dx = p.x - p2.x;
        var dy = p.y - p2.y;
        var dist = Math.sqrt(dx * dx + dy * dy);

        if (dist < 100) {
          ctx.beginPath();
          ctx.moveTo(p.x, p.y);
          ctx.lineTo(p2.x, p2.y);
          ctx.strokeStyle = "rgba(255, 255, 255, " + (1 - dist / 100) + ")";
          ctx.lineWidth = 1;
          ctx.stroke();
        }
      }
    }

    requestAnimationFrame(draw);
  }

  draw();
</script>

案例 六:绘制简单的柱状图

描述

使用 Canvas 绘制一个动态柱状图,展示随机生成的数据。

代码

<canvas id="barChartCanvas" width="600" height="400"></canvas>

<script>
  var canvas = document.getElementById("barChartCanvas");
  var ctx = canvas.getContext("2d");
  var data = [30, 80, 120, 60, 150, 90, 180]; // 示例数据
  var barWidth = 50;
  var barSpacing = 20;
  var startX = 50;
  var startY = canvas.height - 50;

  // 绘制柱状图
  function drawBarChart() {
    ctx.clearRect(0, 0, canvas.width, canvas.height);

    for (var i = 0; i < data.length; i++) {
      var x = startX + i * (barWidth + barSpacing);
      var y = startY - data[i];

      // 绘制柱状条
      ctx.fillStyle = "rgba(75, 192, 192, 0.8)";
      ctx.fillRect(x, y, barWidth, data[i]);

      // 绘制数据标签
      ctx.fillStyle = "black";
      ctx.font = "14px Arial";
      ctx.fillText(data[i], x + barWidth / 2 - 10, y - 10);
    }
  }

  drawBarChart();
</script>

案例 七:绘制简单的游戏(小球碰撞)

描述

使用 Canvas 实现一个简单的小球碰撞游戏,小球在画布内反弹。

代码

<canvas id="gameCanvas" width="600" height="400"></canvas>

<script>
  var canvas = document.getElementById("gameCanvas");
  var ctx = canvas.getContext("2d");
  var ball = {
    x: 100,
    y: 100,
    radius: 20,
    vx: 4,
    vy: 4,
    color: "red"
  };

  // 绘制小球
  function drawBall() {
    ctx.beginPath();
    ctx.arc(ball.x, ball.y, ball.radius, 0, Math.PI * 2);
    ctx.fillStyle = ball.color;
    ctx.fill();
    ctx.closePath();
  }

  // 更新小球位置
  function updateBall() {
    ball.x += ball.vx;
    ball.y += ball.vy;

    // 边界检测
    if (ball.x + ball.radius > canvas.width || ball.x - ball.radius < 0) {
      ball.vx *= -1;
    }
    if (ball.y + ball.radius > canvas.height || ball.y - ball.radius < 0) {
      ball.vy *= -1;
    }
  }

  // 主循环
  function gameLoop() {
    ctx.clearRect(0, 0, canvas.width, canvas.height);
    drawBall();
    updateBall();
    requestAnimationFrame(gameLoop);
  }

  gameLoop();
</script>

总结

以上案例展示了 HTML5 Canvas 在实际开发中的应用,包括动态时钟、粒子效果、数据可视化以及简单游戏开发。通过这些案例,您可以更好地理解 Canvas 的强大功能,并将其应用到自己的项目中。


http://www.kler.cn/a/581578.html

相关文章:

  • 《苍穹外卖》SpringBoot后端开发项目核心知识点整理(DAY1 to DAY3)
  • 使用外挂工具,简化教师资格面试的纸质试题打印操作
  • 探秘 CSS 盒子模型:构建网页布局的基石
  • Leetcode 55: 跳跃游戏
  • 物联网时代的车队管理系统阐述
  • 【2025】Electron 基础二(进程模型三大核心)
  • 【ISP】ISP的pipeline的几种关键算法
  • 封装AJAX(带详细注释)
  • OWL: 适用于现实任务自动化的多智能体协作框架
  • 版本控制器Git(1)
  • 从零开始用HTML、CSS和JavaScript制作贪吃蛇网页小游戏
  • XXE靶机详细通关攻略(flag)
  • 云计算VS网络安全,应该怎么选?
  • Chebykan wx 文章阅读
  • 新一代开源数字供应链安全审查与治理平台:悬镜源鉴SCA
  • OWL(Optimized Workforce Learning): 优化劳动力学习的通用智能体,用于处理现实世界的自动化任务(58.18 平均分)
  • 《C#上位机开发从门外到门内》1-1:上位机简介
  • Unity 带阻尼感的转盘
  • Helm 安装zookeeper集群
  • Linux网络编程——UDP网络通信的简单实现