- vừa được xem lúc

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

0 0 65

Người đăng: Phan Quang Hiếu

Theo Viblo Asia

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

<canvas id="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 2d
const H = 800
const W = 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 canvas
const 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ình const CIRCLE = { // 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

class Dot { constructor(x, y, vx, vy, r) { //tham số nhận vào this.x = x this.y = y this.vx = vx this.vy = vy this.r = r //bán kính của điểm this.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) return const 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

function init() { // khởi tạo các điểm for (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() * W const positionY = Math.random() * H const 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ên const vy = (Math.random() - 0.5) * DOT.vY dots.push(new Dot(positionX, positionY, vx, vy, r)) }
} function animate() { 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 + 3 const positionX = event.offsetX // tọa độ điểm xuất hiện là tọa độ click chuột const positionY = event.offsetY const vx = (Math.random() - 0.5) * DOT.vX const vy = (Math.random() - 0.5) * DOT.vY dots.push(new Dot(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é

function animate() { requestAnimationFrame(animate) context.fillStyle = gradient context.fillRect(0, 0, canvas.width, canvas.height) //filter trước khi update if (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 ?)

Bình luận

Bài viết tương tự

- vừa được xem lúc

Giới thiệu Typescript - Sự khác nhau giữa Typescript và Javascript

Typescript là gì. TypeScript là một ngôn ngữ giúp cung cấp quy mô lớn hơn so với JavaScript.

0 0 528

- vừa được xem lúc

Bạn đã biết các tips này khi làm việc với chuỗi trong JavaScript chưa ?

Hi xin chào các bạn, tiếp tục chuỗi chủ đề về cái thằng JavaScript này, hôm nay mình sẽ giới thiệu cho các bạn một số thủ thuật hay ho khi làm việc với chuỗi trong JavaScript có thể bạn đã hoặc chưa từng dùng. Cụ thể như nào thì hãy cùng mình tìm hiểu trong bài viết này nhé (go).

0 0 437

- vừa được xem lúc

Một số phương thức với object trong Javascript

Trong Javascript có hỗ trợ các loại dữ liệu cơ bản là giống với hầu hết những ngôn ngữ lập trình khác. Bài viết này mình sẽ giới thiệu về Object và một số phương thức thường dùng với nó.

0 0 159

- vừa được xem lúc

Tìm hiểu về thư viện axios

Giới thiệu. Axios là gì? Axios là một thư viện HTTP Client dựa trên Promise.

0 0 149

- vừa được xem lúc

Imports và Exports trong JavaScript ES6

. Giới thiệu. ES6 cung cấp cho chúng ta import (nhập), export (xuất) các functions, biến từ module này sang module khác và sử dụng nó trong các file khác.

0 0 113

- vừa được xem lúc

Bài toán đọc số thành chữ (phần 2) - Hoàn chỉnh chương trình dưới 100 dòng code

Tiếp tục bài viết còn dang dở ở phần trước Phân tích bài toán đọc số thành chữ (phần 1) - Phân tích đề và những mảnh ghép đầu tiên. Bạn nào chưa đọc thì có thể xem ở link trên trước nhé.

0 0 249