Skip to content

Canvas

基本使用

在 HTML 文件中插入一个<canvas>元素,以界定网页中的绘图区域。

html
<canvas width="320" height="240"></canvas>

确定canvas的尺寸,得到了一个充满窗口的画布

js
const canvas = document.querySelector(".myCanvas")
const width = (canvas.width = window.innerWidth)
const height = (canvas.height = window.innerHeight)

获取画布上下文

ctx 变量包含一个 CanvasRenderingContext2D 对象,画布上所有绘画操作都会涉及到这个对象。

js
const ctx = canvas.getContext("2d")

绘制一个矩形:

js
ctx.fillStyle = "rgb(0, 0, 0)"
ctx.fillRect(0, 0, width, height)

2D画布基础

绘制矩形、边框:

ts
const canvas = document.querySelector("#canvas-comp1") as HTMLCanvasElement

const ctx = canvas.getContext("2d")

ctx.fillStyle = "rgb(220, 0, 0)"
ctx.fillRect(50, 50, 100, 150)

ctx.fillStyle = "rgba(255, 0, 255, 0.40)"
ctx.fillRect(25, 100, 175, 50)

// 绘制边框
ctx.strokeStyle = "#e6e6e6"
ctx.lineWidth = 5
ctx.strokeRect(25, 25, 175, 200)

绘制线条:

ts
const degToRad = (degrees: number) => {
    return (degrees * Math.PI) / 180
}

const canvas = document.querySelector("#canvas-comp2") as HTMLCanvasElement

const ctx = canvas.getContext("2d")

ctx.fillStyle = "rgb(220, 0, 0)"
ctx.beginPath()
ctx.moveTo(50, 50)
ctx.lineTo(150, 50)
const triHeight = 50 * Math.tan(degToRad(60))
ctx.lineTo(100, 50 + triHeight)
ctx.lineTo(50, 50)
ctx.fill()


ctx.fillStyle = 'rgb(0, 0, 220)'
ctx.beginPath()
ctx.arc(150, 106, 50, degToRad(0), degToRad(360), false)
ctx.fill()


ctx.fillStyle = 'rgb(220, 220, 0)'
ctx.beginPath()
ctx.arc(200, 106, 50, degToRad(-45), degToRad(45), true)
ctx.lineTo(200, 106)
ctx.fill()

绘制文本:

ts
const canvas = document.querySelector("#canvas-comp3") as HTMLCanvasElement

const ctx = canvas.getContext("2d")

ctx.strokeStyle = "black"
ctx.lineWidth = 1
ctx.font = "36px arial"
ctx.strokeText("Canvas text", 50, 50)

ctx.fillStyle = "red"
ctx.font = "48px georgia"
ctx.fillText("Canvas text", 50, 150)

const image = new Image()
image.src = "blogqrcode_icon.png"
image.onload = function () {
ctx.drawImage(image, 50, 50)
}

循环:

ts
const canvas = document.querySelector("#canvas-comp4") as HTMLCanvasElement

const ctx = canvas.getContext("2d")

ctx.translate(canvas.width / 2, canvas.height / 2)

const degToRad = (degrees: number) => {
return (degrees * Math.PI) / 180
}

let length = 250
let moveOffset = 20

for (let i = 0; i < length; i++) {
ctx.fillStyle =
    "rgba(" + (255 - length) + ", 0, " + (255 - length) + ", 0.9)";
ctx.beginPath()
ctx.moveTo(moveOffset, moveOffset)
ctx.lineTo(moveOffset + length, moveOffset)
const triHeight = (length / 2) * Math.tan(degToRad(60))
ctx.lineTo(moveOffset + length / 2, moveOffset + triHeight)
ctx.lineTo(moveOffset, moveOffset)
ctx.fill()

length--
moveOffset += 0.7
ctx.rotate(degToRad(5))
}

动画:

ts
const canvas = document.querySelector("#canvas-comp5") as HTMLCanvasElement

const ctx = canvas.getContext("2d")

const width = canvas.width
const height = canvas.height

function random(min, max) {
return Math.floor(Math.random() * (max - min + 1)) + min;
}

// function to generate random RGB color value

function randomRGB() {
return `rgb(${random(0, 255)},${random(0, 255)},${random(0, 255)})`;
}

class Ball {
x: any
y: any
velX: any
velY: any
color: any
size: any
constructor(x, y, velX, velY, color, size) {
  this.x = x;
  this.y = y;
  this.velX = velX;
  this.velY = velY;
  this.color = color;
  this.size = size;
}

draw() {
  ctx.beginPath();
  ctx.fillStyle = this.color;
  ctx.arc(this.x, this.y, this.size, 0, 2 * Math.PI);
  ctx.fill();
}

update() {
  if (this.x + this.size >= width) {
    this.velX = -Math.abs(this.velX);
  }

  if (this.x - this.size <= 0) {
    this.velX = Math.abs(this.velX);
  }

  if (this.y + this.size >= height) {
    this.velY = -Math.abs(this.velY);
  }

  if (this.y - this.size <= 0) {
    this.velY = Math.abs(this.velY);
  }

  this.x += this.velX;
  this.y += this.velY;
}

collisionDetect() {
  for (const ball of balls) {
    if (!(this === ball)) {
      const dx = this.x - ball.x;
      const dy = this.y - ball.y;
      const distance = Math.sqrt(dx * dx + dy * dy);

      if (distance < this.size + ball.size) {
        ball.color = this.color = randomRGB();
      }
    }
  }
}
}

const balls = [];

while (balls.length < 25) {
const size = random(10, 20)
const ball = new Ball(
    // ball position always drawn at least one ball width
    // away from the edge of the canvas, to avoid drawing errors
    random(0 + size, width - size),
    random(0 + size, height - size),
    random(-7, 7),
    random(-7, 7),
    randomRGB(),
    size
);

balls.push(ball)
}


function loop() {
ctx.fillStyle = "rgba(0, 0, 0, 0.1)"
ctx.fillRect(0, 0, width, height)

for (const ball of balls) {
  ball.draw()
  ball.update()
  ball.collisionDetect()
}

requestAnimationFrame(loop)
}

loop()