Frontend/Canvas

[Canvas] 캔버스 resize

gamzaggang7 2024. 5. 22. 18:00
728x90

2024.05.22 - [Canvas] - [Canvas] dat.GUI 사용하기

 

[Canvas] dat.GUI 사용하기

2024.05.21 - [Canvas] - [Canvas] svg 필터 입히기(feGaussianBlur, feColorMatrix) | Gooey Effect [Canvas] svg 필터 입히기(feGaussianBlur, feColorMatrix) | Gooey Effect2024.05.20 - [Canvas] - [Canvas] 파티클 그리기 | 애니메이션 추가(re

gamzaggang7.tistory.com

 

현재 캔버스는 화면의 크기를 변경해도 바뀌지 않는다.

 

처음 js가 로드되었을 때

const canvasWidth = innerWidth
const canvasHeight = innerHeight

 위 코드로 인해 가로 세로 길이가 고정되었기 때문이다.

화면이 resize 될 때마다 캔버스의 크기가 바뀌도록 하자. 윈도우가 resize될 때마다 캔버스의 가로 세로 길이가 새로운 innerWidth와 innerHeight를 가지도록 하면 된다.

 

728x90

 

init() 함수를 만들고 캔버스 크기와 관련된 코드를 함수 안으로 가져온다.

function init() {
  const canvasWidth = innerWidth
  const canvasHeight = innerHeight

  canvas.style.width = canvasWidth + 'px'
  canvas.style.height = canvasHeight + 'px'

  canvas.width = canvasWidth * dpr
  canvas.height = canvasHeight * dpr
  ctx.scale(dpr, dpr)
}

canvasWidth와 canvasHeight 변수는 함수 밖에서 let으로 선언해둔다. 

그리고 화면이 resize될 때마다 생성되는 파티클의 랜덤 값들도 바껴야 하므로 해당 코드들도 init함수 안으로 옮긴다.

let canvasWidth
let canvasHeight
let particles

function init() {
  canvasWidth = innerWidth
  canvasHeight = innerHeight

  canvas.style.width = canvasWidth + 'px'
  canvas.style.height = canvasHeight + 'px'

  canvas.width = canvasWidth * dpr
  canvas.height = canvasHeight * dpr
  ctx.scale(dpr, dpr)

  particles = []

  for (let i = 0; i < Total; i++) {
    const x = randomNumBetween(0, canvasWidth)
    const y = randomNumBetween(0, canvasHeight)
    const r = randomNumBetween(50, 100)
    const vy = randomNumBetween(1, 5)
    const particle = new Particle(x, y, r, vy)
    particles.push(particle)
  }
}

윈도우가 resize될 때마다 이 init 함수를 실행시키면 된다.

window.addEventListener('load', () => {
  init()
  animate()
})

window.addEventListener('resize', () => {
  init()
})

윈도우가 로드되면 init과 animate 함수를 실행시키고 resize되면 init함수를 실행시킨다.

 

화면이 커지면 파티클 수가 늘어나게 해보자.

Total 변수를 init 함수 안으로 옮기고 Total값을 가로 사이즈/50 값으로 바꾼다.

const Total = canvasWidth / 50;

 

 

* 전체 코드 *

const canvas = document.querySelector('canvas')
const ctx = canvas.getContext('2d')
const dpr = window.devicePixelRatio

let canvasWidth
let canvasHeight
let particles

function init() {
  canvasWidth = innerWidth
  canvasHeight = innerHeight

  canvas.style.width = canvasWidth + 'px'
  canvas.style.height = canvasHeight + 'px'

  canvas.width = canvasWidth * dpr
  canvas.height = canvasHeight * dpr
  ctx.scale(dpr, dpr)

  particles = []

  const Total = canvasWidth / 50;

  for (let i = 0; i < Total; i++) {
    const x = randomNumBetween(0, canvasWidth)
    const y = randomNumBetween(0, canvasHeight)
    const r = randomNumBetween(50, 100)
    const vy = randomNumBetween(1, 5)
    const particle = new Particle(x, y, r, vy)
    particles.push(particle)
  }
}

const feGaussianBlur = document.querySelector('feGaussianBlur')
const feColorMatrix = document.querySelector('feColorMatrix')

const controls = new function () {
  this.blurValue = 40
  this.alphaChannel = 100
  this.alphaOffset = -23
  this.acc = -1.03
}

let gui = new dat.GUI()

const f1 = gui.addFolder('Gooey Effect')
f1.open()
const f2 = gui.addFolder('Particle Property')

f1.add(controls, 'blurValue', 0, 100).onChange(value => {
  feGaussianBlur.setAttribute('stdDeviation', value)
})
f1.add(controls, 'alphaChannel', 1, 200).onChange(value => {
  feColorMatrix.setAttribute('values', `1 0 0 0 0  0 1 0 0 0  0 0 1 0 0  0 0 0 ${value} ${controls.alphaOffset}`)
})
f1.add(controls, 'alphaOffset', -40, 40).onChange(value => {
  feColorMatrix.setAttribute('values', `1 0 0 0 0  0 1 0 0 0  0 0 1 0 0  0 0 0 ${controls.alphaChannel} ${value}`)
})
f2.add(controls, 'acc', 1, 1.5, 0.01).onChange(value => {
  particles.forEach(particle => particle.acc = value)
})

class Particle {
  constructor(x, y, r, vy) {
    this.x = x
    this.y = y
    this.r = r
    this.vy = vy
    this.acc = 1.05
  }
  update() {
    this.vy *= this.acc
    this.y += this.vy
  }
  draw() {
    ctx.beginPath()
    ctx.arc(this.x, this.y, this.r, 0, Math.PI / 180 * 360)
    ctx.fillStyle = 'skyblue'
    ctx.fill()
    ctx.closePath()
  }
}

const randomNumBetween = (min, max) => {
  return Math.random() * (max - min + 1) + min
}

console.log(particles);

let interval = 1000 / 60
let now, delta
let then = Date.now()

function animate() {
  window.requestAnimationFrame(animate)
  now = Date.now()
  delta = now - then

  if (delta < interval) return

  ctx.clearRect(0, 0, canvasWidth, canvasHeight)

  particles.forEach(particle => {
    particle.update()
    particle.draw()

    if (particle.y - particle.r > canvasHeight) {
      particle.y = -particle.r
      particle.x = randomNumBetween(0, canvasWidth)
      particle.r = randomNumBetween(50, 100)
      particle.vy = randomNumBetween(1, 5)
    }
  })

  then = now - (delta & interval)
}

window.addEventListener('load', () => {
  init()
  animate()
})

window.addEventListener('resize', () => {
  init()
})
728x90