前端canvas技术实现多种小案例(持续更新中)

目录

1.刮刮乐

2.在线画板

3.动态时钟

4.贪吃蛇


1.刮刮乐

                                         

<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <meta http-equiv="X-UA-Compatible" content="IE=edge" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>刮刮乐</title>
    <style>
      #ggk {
        width: 600px;
        height: 400px;
        font-size: 30px;
        text-align: center;
        line-height: 400px;
        position: absolute;
        top: 100px;
        z-index: -1;
      }
    </style>
  </head>
  <body>
    <div id="ggk">谢谢惠顾</div>
    <canvas id="canvas" width="600px" height="400px"></canvas>
  </body>
  <script>
    // 获取画笔
    var c1 = document.getElementById("canvas");
    var ctx = c1.getContext("2d");
    // 绘制图片
    let img = new Image();
    img.src = "./img/ggk.jpeg";
    img.onload = function () {
      ctx.drawImage(img, 0, 0, 600, 400);
    };
    // 判断是否可以画
    var isDraw = false;
    // 鼠标按下的时候设置为可以绘画
    c1.onmousedown = function () {
      isDraw = true;
    };
    // 鼠标抬起的时候设置为不可以绘画
    c1.onmouseup = function () {
      isDraw = false;
    };
    // 当鼠标移动并且可以绘画时,获取鼠标的坐标信息并以此为圆心绘制圆形
    c1.onmousemove = function (e) {
      if (isDraw) {
        var x = e.pageX;
        var y = e.pageY;
        // destination-out模式可以消除重叠的部分,也就是我们画的圆形和图片重叠的部分,然后显示不重叠的部分
        ctx.globalCompositeOperation = "destination-out";
        ctx.arc(x, y, 20, 0, 2 * Math.PI);
        ctx.fill();
      }
    };
    // 设置随机数,模拟概率,增加趣味性
    let random = Math.random();
    var ggk = document.querySelector("#ggk");
    if (random < 0.1) {
      ggk.innerHTML = "恭喜你获得iPhone14";
    } else {
      ggk.innerHTML = "谢谢惠顾";
    }
  </script>
</html>

2.在线画板

<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <meta http-equiv="X-UA-Compatible" content="IE=edge" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>Document</title>
    <style>
      body {
        background-color: #87ceeb;
      }
      #c1 {
        background-color: #fff;
      }
      /* 设置按钮点击时的样式 */
      .active {
        color: #fff;
        background-color: orange;
      }
    </style>
  </head>
  <body>
    <canvas id="c1" width="800px" height="400px"></canvas>
    <hr />
    <button id="boldBtn">粗线条</button>
    <button id="thinBtn">细线条</button>
    <button id="saveBtn">保存签名</button>
    <input type="color" name="" id="color" value="" />
    <button id="clearBtn">橡皮擦</button>
    <button id="nullBtn">清空画布</button>
  </body>
  <script>
    // 获取画笔
    var canvas = document.getElementById("c1");
    var ctx = canvas.getContext("2d");
    // 设置线条的细节样式(不是必须)
    ctx.lineJoin = "round"; //连接处圆润
    ctx.lineCap = "round"; //开始和结束也是圆润的

    var boldBtn = document.getElementById("boldBtn");
    var thinBtn = document.getElementById("thinBtn");
    var saveBtn = document.getElementById("saveBtn");
    var color = document.getElementById("color");
    var clearBtn = document.getElementById("clearBtn");
    var nullBtn = document.getElementById("nullBtn");
    //判断是否可以绘制
    var isDraw = false;
    // 鼠标按下
    canvas.onmousedown = function (e) {
      isDraw = true;
      ctx.beginPath();
      var x = e.pageX - canvas.offsetLeft;
      var y = e.pageY - canvas.offsetTop;
      ctx.moveTo(x, y);
    };
    // 鼠标离开
    canvas.onmouseleave = function () {
      isDraw = false;
      ctx.closePath();
    };
    // 鼠标抬回
    canvas.onmouseup = function (e) {
      isDraw = false;
      ctx.closePath();
    };
    // 鼠标移动
    canvas.onmousemove = function (e) {
      if (isDraw) {
        var x = e.pageX - canvas.offsetLeft;
        var y = e.pageY - canvas.offsetTop;
        ctx.lineTo(x, y);
        ctx.stroke();
      }
    };
    // 点击粗线按钮
    boldBtn.onclick = function () {
      ctx.globalCompositeOperation = "source-over";
      ctx.lineWidth = 20;
      boldBtn.classList.add("active");
      thinBtn.classList.remove("active");
      clearBtn.classList.remove("active");
    };
    // 点击细线按钮
    thinBtn.onclick = function () {
      ctx.globalCompositeOperation = "source-over";
      ctx.lineWidth = 2;
      thinBtn.classList.add("active");
      boldBtn.classList.remove("active");
      clearBtn.classList.remove("active");
    };
    // 点击橡皮擦按钮
    clearBtn.onclick = function () {
      ctx.globalCompositeOperation = "destination-out";
      ctx.lineWidth = 30;
      clearBtn.classList.add("active");
      thinBtn.classList.remove("active");
      boldBtn.classList.remove("active");
    };
    // 点击清空按钮
    nullBtn.onclick = function () {
      ctx.clearRect(0, 0, 800, 400);
    };
    // 点击保存签名按钮
    saveBtn.onclick = function () {
      var urlData = canvas.toDataURL();
      var downloadA = document.createElement("a");
      downloadA.setAttribute("download", "酷炫签名");
      downloadA.href = urlData;
      downloadA.click();
    };
    // 点击切换颜色
    color.onchange = function () {
      ctx.strokeStyle = color.value;
    };
  </script>
</html>

3.动态时钟

<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <meta http-equiv="X-UA-Compatible" content="IE=edge" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>动态时钟</title>
  </head>
  <body>
    <canvas id="c1" width="800" height="600"></canvas>
  </body>
  <script>
    // 获取画笔
    var canvas = document.getElementById("c1");
    var ctx = canvas.getContext("2d");

    render();
    // 绘制时钟
    function render() {
      // 在每一次绘画时钟的时候,先清空画布
      ctx.clearRect(0, 0, 800, 600);

      // 保存当前目标位置和渲染上下文对象的状态
      ctx.save();
      // 将原点放在400,300的位置
      ctx.translate(400, 300);
      // 将原点逆时针旋转90°,改变x,y轴的方向,此时x轴竖直向上,y轴水平向右
      ctx.rotate(-Math.PI / 2);
      // 保存当前的状态
      ctx.save();

      // 绘制12个大的竖线
      for (var i = 0; i < 12; i++) {
        ctx.beginPath();
        // 将画笔的起点放在x:170,y:0的位置处
        ctx.moveTo(170, 0);
        // 绘制起点到x:190,y:0处的一条直线
        ctx.lineTo(190, 0);
        // 设置直线的宽度
        ctx.lineWidth = 8;
        // 设置路径的颜色
        ctx.strokeStyle = "gray";
        ctx.stroke();
        ctx.closePath();
        // 将原点顺时针旋转30°,改变x,y轴方向
        ctx.rotate((2 * Math.PI) / 12);
      }
      // 将原点恢复到上一个保存的位置
      ctx.restore();
      // 保存当前状态,因为恢复将保存信息出栈,所以还要保存一下
      ctx.save();

      // 绘制60个小的竖线,原理和上面相同
      for (var i = 0; i < 60; i++) {
        ctx.beginPath();
        ctx.moveTo(170, 0);
        ctx.lineTo(190, 0);
        ctx.lineWidth = 2;
        ctx.strokeStyle = "gray";
        ctx.stroke();
        ctx.closePath();
        ctx.rotate((2 * Math.PI) / 60);
      }
      ctx.restore();
      ctx.save();

      // 获取当前时间
      var time = new Date();
      var hour = time.getHours();
      var min = time.getMinutes();
      var sec = time.getSeconds();
      hour = hour >= 12 ? hour - 12 : hour;
      // 绘制秒针
      // 计算一下秒针每次旋转的角度
      ctx.rotate(((2 * Math.PI) / 60) * sec);
      ctx.beginPath();
      //绘制一条直线
      ctx.moveTo(0, 0);
      ctx.lineTo(190, 0);
      // 设置路径样式
      ctx.lineWidth = 2;
      ctx.strokeStyle = "#C70039 ";
      ctx.stroke();
      ctx.closePath();
      ctx.restore();
      ctx.save();
      //   绘制分针
      // 计算一下分针每次旋转的角度
      ctx.rotate(((2 * Math.PI) / 60) * min + ((2 * Math.PI) / 60 / 60) * sec);
      ctx.beginPath();
      ctx.moveTo(0, 0);
      ctx.lineTo(150, 0);
      ctx.lineWidth = 4;
      ctx.strokeStyle = "gray";
      ctx.stroke();
      ctx.closePath();
      ctx.restore();
      ctx.save();
      //   绘制时针
      //   计算一下时针每次旋转的角度
      ctx.rotate(
        ((2 * Math.PI) / 12) * hour +
          ((2 * Math.PI) / 12 / 60) * min +
          ((2 * Math.PI) / 12 / 60 / 60) * sec
      );
      ctx.beginPath();
      ctx.moveTo(0, 0);
      ctx.lineTo(100, 0);
      ctx.lineWidth = 8;
      ctx.strokeStyle = "#17202A";
      ctx.stroke();
      ctx.closePath();
      ctx.restore();
      ctx.restore();
      requestAnimationFrame(render);
    }
  </script>
</html>

4.贪吃蛇

<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <meta http-equiv="X-UA-Compatible" content="IE=edge" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>贪吃蛇</title>
  </head>
  <body>
    <canvas
      id="canvas"
      width="600"
      height="600"
      style="border: 1px solid black"
    ></canvas>
  </body>
  <script>
    /**贪吃蛇步骤
     * 1.先把蛇画出来
     *   1.1 蛇头和蛇身
     * 2.让蛇动起来
     *   2.1 添加键盘事件
     *   2.2 animate运动
     * 3.随机投放食物
     *   3.1 坐标位置
     *   3.2 食物是否投放到了蛇头和蛇身上(数组排重)
     * 4.吃食物
     *   4.1 碰撞检测
     *   4.2 将食物添加到蛇身上
     * 5.边缘检测,判断是否游戏结束
     *   5.1 碰撞检测
     *   5.2 Game Over
     * **/
    var canvas = document.getElementById("canvas");
    var ctx = canvas.getContext("2d");

    // 判断吃到食物或者没吃到食物的移动(吃到食物长度+1)
    var isEatingFood = false;

    // 画方块
    function Rect(x, y, width, height, color) {
      this.x = x;
      this.y = y;
      this.width = width;
      this.height = height;
      this.color = color;
    }
    Rect.prototype.draw = function () {
      ctx.beginPath();
      ctx.fillStyle = this.color;
      ctx.fillRect(this.x, this.y, this.width, this.height);
      ctx.strokeRect(this.x, this.y, this.width, this.height);
      ctx.closePath();
    };

    // 创建snake对象(包括蛇头和蛇身)
    function Snake() {
      // 蛇头(初始状态居中显示)
      this.head = new Rect(
        canvas.width / 2 - 20,
        canvas.height / 2 - 20,
        40,
        40,
        "red"
      );
      //   蛇身(用数组来存储每一个正方形)
      this.body = new Array();
      var x = this.head.x;
      var y = this.head.y;
    }
    Snake.prototype.draw = function () {
      // 绘制蛇头
      this.head.draw();
      // 绘制蛇身
      ctx.fillStyle = "grey";
      for (var i = 0; i < this.body.length; i++) {
        this.body[i].draw();
      }
    };
    // 移动
    Snake.prototype.move = function () {
      var rect = new Rect(
        this.head.x,
        this.head.y,
        this.head.width,
        this.head.height
      );
      //    加头
      this.body.splice(0, 0, rect);
      //   去尾
      if (isEatingFood == false) {
        //没吃到食物情况
        this.body.pop();
      } else {
        //吃到食物情况
        isEatingFood = false;
      }
      //根据键盘输入来判断移动方向
      switch (this.direction) {
        case "left": {
          this.head.x -= this.head.width;
          break;
        }
        case "right": {
          this.head.x += this.head.width;
          break;
        }
        case "up": {
          this.head.y -= this.head.height;
          break;
        }
        case "down": {
          this.head.y += this.head.height;
          break;
        }
      }
      //   判断蛇头和蛇身是否重叠
      for (var i = 0; i < this.body.length; i++) {
        if (isRectHit(this.head, this.body[i])) {
          clearInterval(timer);
          alert("Game over~");
        } else {
          console.log(123);
        }
      }
      //   判断是否会撞上墙壁
      if (
        this.head.x > canvas.width - 40 ||
        this.head.x < 0 ||
        this.head.y > canvas.height - 40 ||
        this.head.y < 0
      ) {
        // 撞上的话,结束游戏
        clearInterval(timer);
        alert("Game over~");
      }
    };
    // 键盘输入
    document.onkeydown = function (event) {
      switch (event.keyCode) {
        case 37: {
          snake.direction = "left";
          break;
        }
        case 38: {
          snake.direction = "up";
          break;
        }
        case 39: {
          snake.direction = "right";
          break;
        }
        case 40: {
          snake.direction = "down";
        }
      }
    };
    // 食物的显示
    function randForFood() {
      var isInSnake = true;
      var rect;
      //   要去判断一下是否随机生成的正方形落在蛇所占的位置上,没有的话,才可以生成显示
      while (isInSnake) {
        var x = getRandInRange(0, (canvas.width - 40) / 40) * 40;
        var y = getRandInRange(0, (canvas.height - 40) / 40) * 40;
        // 食物矩形
        rect = new Rect(x, y, 40, 40, "green");
        // 判断食物是否与蛇头重叠
        if (isRectHit(snake.head, rect)) {
          isInSnake = true;
          continue;
        } else {
          isInSnake = false;
          // 判断食物是否与蛇身重叠
          for (var i = 0; i < snake.body.length; i++) {
            if (isRectHit(snake.body[i], rect)) {
              isInSnake = true;
              break;
            }
          }
        }
      }
      return rect;
    }
    // 获取随机数方法
    function getRandInRange(min, max) {
      return Math.round(Math.random() * (max - min) + min);
    }
    // 碰撞检测
    function isRectHit(rect1, rect2) {
      var minX1 = rect1.x;
      var minX2 = rect2.x;
      var minY1 = rect1.y;
      var minY2 = rect2.y;

      var maxX1 = rect1.x + rect1.width;
      var maxX2 = rect2.x + rect2.width;
      var maxY1 = rect1.y + rect1.height;
      var maxY2 = rect2.y + rect2.height;

      // 判断矩形相交的最大和最小值
      var minX = Math.max(minX1, minX2);
      var minY = Math.max(minY1, minY2);
      var maxX = Math.min(maxX1, maxX2);
      var maxY = Math.min(maxY1, maxY2);

      if (minX < maxX && minY < maxY) {
        return true;
      } else {
        return false;
      }
    }

    var snake = new Snake();
    var rect_food = randForFood();
    var timer;
    function render() {
      ctx.clearRect(0, 0, 600, 600);
      rect_food.draw();
      snake.move();
      if (isRectHit(snake.head, rect_food)) {
        isEatingFood = true;
        rect_food = randForFood();
      }
      snake.draw();
    }
    timer = setInterval(render, 200);
  </script>
</html>

 

  • 2
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

Kaven.js

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

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

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

打赏作者

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

抵扣说明:

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

余额充值