Cùng làm một chiếc Background xịn xò cho Landing Page của bạn với Canvas

Mở đầu Là một lập trình viên Web chắc chắn ai cũng biết đến HTML, JavaScript, nhưng không phải ai cũng biết đến một thẻ HTML khá thú vị, nó làm cho Website trở nên sinh động hơn, đó chính là canvas. Vậy nên hôm nay chúng ta sẽ cũng làm một hình background độc

Mở đầu 👋

Là một lập trình viên Web chắc chắn ai cũng biết đến HTML, JavaScript, nhưng không phải ai cũng biết đến một thẻ HTML khá thú vị, nó làm cho Website trở nên sinh động hơn, đó chính là canvas. Vậy nên hôm nay chúng ta sẽ cũng làm một hình background độc đáo cho trang Web của bạn, hình có tương tác với sự kiện onclick nhé

Công nghệ mình sử dụng cho project là Canvas, JavaScript

Nội Dung

Cho những bạn chưa biết thì <canvas> là một thẻ HTML được sử dụng để vẽ đồ họa trên trang web một cách nhanh chóng. Thẻ <canvas> chỉ là vùng chứa cho đồ họa, chúng ta phải sử dụng JavaScript để thao tác với đối tượng do thẻ canvas tạo ra. Đối tượng canvas có một số method để giúp chúng ta vẽ đoạn thẳng, hình hộp, hình tròn, văn bản và thêm hình ảnh. Chi tiết sử dụng thế nào mình sẽ nói ở phần tiếp theo nhé.

HTML

Ở file HTML mình chỉ đơn giản sử dụng một thẻ canvas với idcanvas

<canvasid="canvas"></canvas>

Khởi tạo

Đầu tiên chúng ta khởi tạo đối tượng canvas 2d, và một số hằng số

const canvas = document.querySelector('#canvas')const context = canvas.getContext('2d')// khởi tạo đối tượng canvas 2dconstH=800constW=800
canvas.width =W
canvas.height =H// canvas cung cấp method createLinearGradient để tạo hằng số biểu thị Gradient Color để ta có thể sử dụng trong canvasconst gradient = context.createLinearGradient(0,0,W,H)// tham số là tọa độ 2 điểm chỉ định chiều của gradient
gradient.addColorStop(0,'#92fe9d')// bạn có thể thêm bao nhiêu màu tùy ý
gradient.addColorStop(1,'#00c9ff')let circles =[]// khởi tạo biến global chứ các điểm di chuyển trên hìnhconstCIRCLE={// hằng số các giá trị cho điểm
  color:'rgb(256,256,256,0.7)',// màu sắc của điểm
  colorLine:'rgb(256,256,256,0.5)',// màu sắc đoạn nối các điểm
  count:30,// số lượng điểm xuất hiện cùng lúc trên hình
  vX:3,// velocityX vận tốc tối đa theo trục X
  vY:3,// velocityY vận tốc tối đa theo trục Y
  range:150,// khi dưới khoảng cách này 2 điểm sẽ có đoạn nối}

Đối tượng Dot

Tiếp theo chúng ta viết class Dot

classDot{constructor(x, y, vx, vy, r){//tham số nhận vàothis.x = x
   this.y = y
   this.vx = vx
   this.vy = vy
   this.r = r   //bán kính của điểmthis.dotsNears =[]// property xác định danh sách các điểm ở gần, mỗi object gồm tọa độ x y và khoảng cách d giữa 2 điểm}draw(){// vẽ điểm và đoạn nối trên canvas
   context.beginPath()// bắt đầu một đường vẽ, các thuộc tính như màu sắc sẽ trở về mặc định 
   context.arc(this.x,this.y,this.r,0, Math.PI*2,false)//vẽ đường tròn
   context.fillStyle =DOT.color   // style màu cho hình tròn bên trong
   context.fill()// giờ mới chính tức vẽthis.dotsNears.forEach((dotNear)=>{// vẽ các đoạn thẳng nối điểm hiện tại với các điểm gần đấy 
     context.beginPath() 
     context.moveTo(this.x,this.y)// di chuyển đến tọa độ điểm hiện tại
     context.lineTo(dotNear.x, dotNear.y)// vẽ đường thằng đến điểm gần đó
     context.lineWidth =(DOT.range - dotNear.d)*(2/DOT.range)// độ dày của đoạn thẳng, càng gần nhau thì càng dày, tối đa 2px
     context.strokeStyle =DOT.colorLine    // style màu cho đoạn thằng
     context.stroke()// gọi thì mới vẽ})}update(dots){// update tọa độ điểm theo vận tốc của điểm đó, nhận vào biến global dots để tìm các điểm gần điểm hiện tại// khi điểm ta ngoài phạm vi của canvas thì ta sẽ đặt lại tọa độ và random lại vận tốc cho điểm đóif(this.x -this.r >=W){this.x =0-this.r
     this.vy =(Math.random()-0.5)*DOT.vY    // ramdom 1 chiều vận tốc thôi, ramdom cả 2 thì sẽ có trường hợp điểm không vào lại canvas mà sẽ bị random tiếp}if(this.x +this.r <0){this.x =W+this.r
     this.vy =(Math.random()-0.5)*DOT.vY
   }if(this.y -this.r >=H){this.y =0-this.r
     this.vx =(Math.random()-0.5)*DOT.vX
   }if(this.y +this.r <0){this.y =H+this.r
     this.vx =(Math.random()-0.5)*DOT.vX
   }this.x +=this.vx   // nếu trong hình thì update tọa độthis.y +=this.vy

   this.dotsNears =[]   
   dots.forEach((dot)=>{// tìm tọa độ điểm gần đóif(dot ===this)returnconst d = Math.sqrt((this.x - dot.x)**2+(this.y - dot.y)**2)if(d <DOT.range){this.dotsNears.push({ x: dot.x, y: dot.y, d: d })}})this.draw()}}

Khởi tạo animate

Ở đây chúng ta sử dụng method requestAnimationFrame của đối tượng window. Hiểu nôm na nó sẽ như 1 vòng lặp, thay vì while(true) vẽ xong xóa thì chúng ra sẽ sử dụng , method của window. Cách sử dụng nó gần giống như kiểu hàm đệ quy, cụ thể như sau

functioninit(){// khởi tạo các điểmfor(let i =0; i <DOT.count; i++){const r = Math.random()*3+3//  random bán kính của điểm từ 3 đến 6px const positionX = Math.random()*Wconst positionY = Math.random()*Hconst vx =(Math.random()-0.5)*DOT.vX    // -0.5 để có cả vận tốc âm, dương, theo trục Y âm sẽ di chuyển từ dưới lên trênconst vy =(Math.random()-0.5)*DOT.vY
    dots.push(newDot(positionX, positionY, vx, vy, r))}}functionanimate(){requestAnimationFrame(animate) 
  context.fillStyle = gradient   // style màu nền của canvas là màu gradient ta định nghĩ ban đầu
  context.fillRect(0,0, canvas.width, canvas.height)// ....
  
  dots.forEach((dot)=>{// update lại tọa độ các điểm 
    dot.update(dots)})}// sau đó chúng ta gọi hàm là đã ok rồi đóinit()animate()

Ở đâu mình muốn nói rõ thêm method requestAnimationFrame thông thường có tốc độ là 60 lần mỗi giây (sẽ khớp với tốc độ làm mới hiển thị trong hầu hết các trình duyệt web). Tức là vận tốc di chuyển của các điểm sẽ là vận tốc theo trục của điểm đó (vx, vy) nhân với 60/giây. Như ở đầu ta để vận tốc tối đa của điểm là DOT.vY là 3px tức là nó sẽ có vận tốc tối đa 180px/s

Thêm sự kiện Click

Giờ chúng ta sẽ thêm sự kiện click vào canvas để mỗi khi click vào sẽ có 3 điểm xuất hiện từ đó và nở ra, trông khá thích mắt ☺️

canvas.addEventListener('click',function(event){for(let i =0; i <3; i++){const r = Math.random()*3+3const positionX = event.offsetX   // tọa độ điểm xuất hiện là tọa độ click chuộtconst positionY = event.offsetY
    const vx =(Math.random()-0.5)*DOT.vX
    const vy =(Math.random()-0.5)*DOT.vY
    dots.push(newDot(positionX, positionY, vx, vy, r))}})

Nhưng nếu click nhiều quá thì sẽ có rất nhiều điểm mới được thêm vào, mà cái gì nhiều quá cũng không tốt. Vậy nên ta filter dots nếu nó nhiều hơn DOT.count điểm thì điểm nào ra khỏi canvas ta sẽ cho nó đi luôn, khỏi random lại nhé

functionanimate(){requestAnimationFrame(animate)
  context.fillStyle = gradient
  context.fillRect(0,0, canvas.width, canvas.height)//filter trước khi updateif(dots.length >DOT.count){
    dots = dots.filter((dot)=> dot.x + dot.r >0&& dot.x - dot.r <W&& dot.y + dot.r >0&& dot.y - dot.r <H)}
  dots.forEach((dot)=>{
    dot.update(dots)})}

Vậy là ta đã hoàn thành rồi đó 👏
Đây là link demo

Kết luận

Mình hi vọng với chút chia sẻ như trên sẽ giúp được cho nhiều bạn, đặc biệt là các bạn mới biết thêm những như hay ho mà ta có thể làm được với HTML, JS, từ đó khơi đậy sự sáng tạo, làm cho việc lập trình trở nên thú vị hơn !
Cảm ơn các bạn đã đọc (hay hay không hay thì cũng cho xin 1 vote up nhé mọi người 😂)

Nguồn: viblo.asia

Bài viết liên quan

WebP là gì? Hướng dẫn cách để chuyển hình ảnh jpg, png qua webp

WebP là gì? WebP là một định dạng ảnh hiện đại, được phát triển bởi Google

Điểm khác biệt giữa IPv4 và IPv6 là gì?

IPv4 và IPv6 là hai phiên bản của hệ thống địa chỉ Giao thức Internet (IP). IP l

Check nameservers của tên miền xem website trỏ đúng chưa

Tìm hiểu cách check nameservers của tên miền để xác định tên miền đó đang dùn

Mình đang dùng Google Domains để check tên miền hàng ngày

Từ khi thông báo dịch vụ Google Domains bỏ mác Beta, mình mới để ý và bắt đầ