Vẽ trực tiếp lên bất kỳ trang web nào với các công cụ nâng cao!
OverDraw Enhanced là một tiện ích mở rộng (extension) cho trình duyệt Google Chrome (và các trình duyệt dựa trên Chromium) cho phép người dùng kích hoạt một bảng vẽ phủ lên trang web hiện tại. Người dùng có thể sử dụng các công cụ như bút vẽ, tẩy, công cụ văn bản, chọn màu, điều chỉnh kích thước bút, hoàn tác/làm lại hành động để ghi chú, phác thảo hoặc đánh dấu trực tiếp trên nội dung web.
- Tính năng chính
- Cài đặt
- Cách sử dụng
- Cấu trúc dự án
- Cách hoạt động của từng chức năng
- Đóng góp
- Giấy phép
- Building the Extension
- Kích hoạt/Vô hiệu hóa bằng phím F9: Dễ dàng bật hoặc tắt bảng vẽ trên bất kỳ trang web nào.
- Bảng vẽ toàn màn hình: Canvas vẽ phủ lên toàn bộ nội dung trang.
- Thanh công cụ trực quan:
- Công cụ Bút vẽ (Brush)
- Công cụ Tẩy (Eraser)
- Công cụ Văn bản (Text Tool)
- Bộ chọn màu (Color Picker)
- Điều chỉnh kích thước bút vẽ và kích thước văn bản (dạng thanh trượt).
- Hoàn tác (Undo) và Làm lại (Redo) các hành động vẽ.
- Nút Xóa toàn bộ bảng vẽ (Clear Canvas).
- Nút Thu nhỏ/Mở rộng bảng vẽ và thanh công cụ.
- Hỗ trợ chuột và cảm ứng: Vẽ mượt mà bằng cả chuột và thiết bị cảm ứng.
- Hướng dẫn sử dụng lần đầu: Một popup nhỏ hướng dẫn người dùng mới về các tính năng cơ bản.
- Modular Codebase: Mã nguồn được tổ chức thành các module JavaScript (ES6 Modules) để dễ quản lý và bảo trì.
- Tải xuống (hoặc clone) toàn bộ mã nguồn của dự án này.
- Mở trình duyệt Google Chrome, điều hướng đến
chrome://extensions/. - Bật chế độ Developer mode (Chế độ nhà phát triển) ở góc trên bên phải.
- Nhấp vào nút Load unpacked (Tải tiện ích đã giải nén).
- Chọn thư mục gốc của dự án (
overdraw-enhanced/) mà bạn vừa tải về/clone. - Tiện ích OverDraw Enhanced sẽ được cài đặt và sẵn sàng để sử dụng. Biểu tượng của tiện ích sẽ xuất hiện trên thanh công cụ của trình duyệt.
- Truy cập bất kỳ trang web nào bạn muốn vẽ lên.
- Nhấn phím F9. Một hộp thoại xác nhận sẽ hiện ra, hỏi bạn có muốn kích hoạt bảng vẽ không. Chọn "OK".
- Bảng vẽ và thanh công cụ sẽ xuất hiện.
- Sử dụng các công cụ trên thanh công cụ để bắt đầu vẽ.
- Để thu nhỏ bảng vẽ và thanh công cụ (chỉ giữ lại nút mở rộng), nhấp vào nút
<=trên thanh công cụ. Nhấp=>để mở rộng lại. - Nhấn F9 một lần nữa để vô hiệu hóa hoàn toàn bảng vẽ (sẽ có hộp thoại xác nhận).
overdraw-enhanced/
├── icons/ # Icon của tiện ích ở các kích thước khác nhau
│ ├── icon16.png
│ ├── icon48.png
│ └── icon128.png
├── css/
│ └── styles.css # Định dạng CSS cho bảng vẽ, thanh công cụ, modal
├── js/
│ ├── main.js # Điểm vào chính, điều phối toàn bộ tiện ích
│ │
│ ├── core/ # Các module cốt lõi
│ │ ├── state.js # Quản lý trạng thái toàn cục của ứng dụng
│ │ └── constants.js # Các hằng số (ID, tên class, giá trị mặc định)
│ │
│ ├── ui/ # Các module liên quan đến giao diện người dùng
│ │ ├── domElements.js # Tạo các phần tử DOM chính (bảng, toolbar)
│ │ ├── styleManager.js # (Hiện không dùng nhiều do CSS qua manifest)
│ │ ├── toolbarController.js # Xử lý sự kiện và logic cho thanh công cụ
│ │ └── firstRunGuide.js# Hiển thị modal hướng dẫn lần đầu
│ │
│ ├── canvas/ # Các module liên quan đến canvas vẽ
│ │ ├── canvasContext.js # Quản lý canvas và context 2D
│ │ ├── eventBinder.js # Gắn các sự kiện (mouse, touch) cho canvas
│ │ ├── inputHandler.js # Xử lý sự kiện đầu vào, lấy tọa độ
│ │ └── undoRedo.js # Logic Hoàn tác/Làm lại
│ │
│ ├── tools/ # Các module cho từng công cụ vẽ
│ │ ├── brush.js # Logic công cụ Bút vẽ
│ │ ├── eraser.js # Logic công cụ Tẩy
│ │ ├── textTool.js # Logic công cụ Văn bản
│ │ └── toolManager.js # Quản lý việc chuyển đổi giữa các công cụ
│ │
│ └── utils/ # Các hàm tiện ích nhỏ
│ └── storage.js # Helper cho chrome.storage.local
│
├── popup/ # Giao diện khi nhấp vào icon tiện ích
│ ├── popup.html
│ └── popup.js # (Tùy chọn, nếu popup cần JavaScript)
├── manifest.json # File cấu hình chính của tiện ích mở rộng
└── README.md # Chính là file này
- File chính:
js/main.js(hàmhandleGlobalKeyDown,enableExtension,disableExtension) - Hoạt động:
- Lắng nghe sự kiện nhấn phím trên toàn bộ tài liệu.
- Khi phím
F9được nhấn:- Nếu tiện ích đang tắt (
isExtensionEnabledlàfalse): Hiển thị hộp thoạiconfirm("Enable OverDraw board?"). Nếu người dùng đồng ý:- Hiển thị thanh công cụ (
toolbarElement.style.display = 'flex'). - Đưa bảng vẽ (
boardElement) lên trên cùng (z-index), vào trong viewport (top = '0'), và hiển thị nó. - Chặn cuộn trang (
document.documentElement.style.overflow = 'hidden'). - Khởi tạo canvas, context, gắn các sự kiện vẽ, và reset lịch sử undo/redo.
- Cập nhật trạng thái
isExtensionEnabled = true,isBoardActive = true. - Kiểm tra và hiển thị hướng dẫn lần đầu nếu cần.
- Hiển thị thanh công cụ (
- Nếu tiện ích đang bật (
isExtensionEnabledlàtrue): Hiển thị hộp thoạiconfirm("Disable OverDraw board?"). Nếu người dùng đồng ý:- Ẩn thanh công cụ.
- Đưa bảng vẽ ra sau, ra khỏi viewport.
- Hủy gắn các sự kiện vẽ.
- Cho phép cuộn trang trở lại.
- Cập nhật trạng thái
isExtensionEnabled = false,isBoardActive = false.
- Nếu tiện ích đang tắt (
- File chính:
js/ui/toolbarController.js(hàmtoggleBoardMinimize) - Hoạt động:
- Nút
<=(Minimize) /=>(Expand) trên thanh công cụ kích hoạt hàm này. - Khi thu nhỏ (
isToolbarMinimizedchuyển thànhtrue):- Ẩn bảng vẽ chính (
boardElement.style.display = 'none'). - Ẩn các nhóm công cụ (
.tool-group) trên thanh công cụ, chỉ giữ lại nút Minimize/Expand. - Đổi text của nút thành
=>. - Cho phép cuộn trang.
- Cập nhật trạng thái
isBoardActive = false(vì không thể vẽ khi thu nhỏ).
- Ẩn bảng vẽ chính (
- Khi mở rộng (
isToolbarMinimizedchuyển thànhfalse):- Hiển thị lại bảng vẽ chính.
- Hiển thị lại tất cả các nhóm công cụ.
- Đổi text của nút thành
<=. - Chặn cuộn trang.
- Cập nhật trạng thái
isBoardActive = true. - Gọi
resizeCanvas()để đảm bảo canvas có kích thước đúng sau khi hiển thị lại.
- Nút
- Files chính:
js/ui/domElements.js(tạo HTML),js/ui/toolbarController.js(xử lý sự kiện),css/styles.css(định dạng) - Hoạt động:
- Được tạo động và thêm vào
<body>khi tiện ích khởi tạo. - Chứa các nút và điều khiển cho từng công cụ.
toolbarController.jslắng nghe các sự kiện click, input, change trên các phần tử của toolbar để cập nhật trạng thái (js/core/state.js) và gọi các hàm tương ứng (ví dụ:setCurrentTool,updateStatecho màu/kích thước).
- Được tạo động và thêm vào
- Files chính:
js/tools/brush.js,js/tools/toolManager.js,js/canvas/inputHandler.js - Hoạt động:
- Khi được chọn từ toolbar,
toolManager.jscập nhậtstate.currentTool = TOOL_BRUSH. inputHandler.jsxử lý sự kiệnmousedown/touchstart: bắt đầu một đường vẽ mới (ctx.beginPath(),ctx.moveTo()).- Khi
mousemove/touchmove:inputHandler.jsgọiapplyCurrentTooltrongtoolManager.js, hàm này sẽ gọidrawWithBrushtừbrush.js. drawWithBrush:- Đặt
ctx.globalCompositeOperation = 'source-over'(chế độ vẽ bình thường). - Lấy
state.currentColorvàstate.currentBrushSizeđể đặtctx.strokeStylevàctx.lineWidth. - Vẽ một đường (
ctx.lineTo(),ctx.stroke()) đến vị trí chuột/chạm mới. Nếu là một điểm đơn (click), vẽ một hình tròn nhỏ.
- Đặt
- Khi
mouseup/touchend:inputHandler.jscập nhậtstate.isDrawing = falsevà gọirecordCanvasStateđể lưu vào lịch sử Undo.
- Khi được chọn từ toolbar,
- Files chính:
js/tools/eraser.js,js/tools/toolManager.js,js/canvas/inputHandler.js - Hoạt động: Tương tự như Bút vẽ, nhưng:
eraseAreatrongeraser.jsđược gọi.- Đặt
ctx.globalCompositeOperation = 'destination-out'. Thao tác vẽ với chế độ này sẽ làm cho các pixel trở nên trong suốt, tạo hiệu ứng tẩy. - Kích thước tẩy sử dụng
state.currentBrushSize.
- Files chính:
js/tools/textTool.js,js/tools/toolManager.js,js/canvas/inputHandler.js - Hoạt động:
- Khi được chọn,
toolManager.jscập nhậtstate.currentTool = TOOL_TEXTvà đổi con trỏ thành dạng text. - Khi người dùng nhấp chuột (
mousedown/touchstart) lên canvas:inputHandler.jsgọiapplyCurrentTool->activateTextModetrongtextTool.js.activateTextMode:- Tạo một phần tử
<textarea id="overdraw-text-input">tạm thời, định vị nó tại điểm nhấp chuột, phủ lên trên canvas. - Áp dụng các style (font, size, color) từ
statecho textarea. - Focus vào textarea.
- Tạo một phần tử
- Người dùng nhập văn bản.
- Khi textarea mất focus (
blur) hoặc người dùng nhấnEnter(không phảiShift+Enter):placeTextOnCanvasđược gọi.- Lấy nội dung text từ textarea.
- Sử dụng
ctx.fillText()để vẽ text lên canvas tại vị trí của textarea. Xử lý xuống dòng nếu có. - Màu và font được lấy từ
state. - Xóa textarea tạm thời.
- Gọi
recordCanvasStateđể lưu vào lịch sử Undo.
- Nếu nhấn
Escapetrong textarea, hủy bỏ việc nhập text.
- Khi được chọn,
- File chính:
js/ui/toolbarController.js(hàmhandleColorChange) - Hoạt động:
- Một phần tử
<input type="color">trên thanh công cụ. - Khi người dùng chọn một màu mới (sự kiện
inputhoặcchange):handleColorChangeđược gọi.- Cập nhật
state.currentColor. - Cập nhật
ctx.strokeStylevàctx.fillStyleđể các thao tác vẽ/text tiếp theo sử dụng màu mới.
- Một phần tử
- File chính:
js/ui/toolbarController.js - Hoạt động:
- Hai phần tử
<input type="range">trên thanh công cụ, một cho kích thước bút vẽ, một cho kích thước văn bản. - Khi người dùng kéo thanh trượt (sự kiện
input):- Cập nhật
state.currentBrushSizehoặcstate.currentTextSize. - Hiển thị giá trị kích thước hiện tại bên cạnh thanh trượt.
- Cập nhật
ctx.lineWidth(cho bút vẽ/tẩy) hoặcctx.font(cho văn bản) ngay lập tức.
- Cập nhật
- Hai phần tử
- Files chính:
js/canvas/undoRedo.js,js/ui/toolbarController.js - Hoạt động:
recordCanvasState(canvas):- Được gọi sau mỗi thao tác vẽ hoàn chỉnh (mouseup, touchend, text placed).
- Sử dụng
canvas.toDataURL()để lấy trạng thái hiện tại của canvas dưới dạng ảnh Base64. - Đẩy chuỗi Base64 này vào
undoStack. - Nếu
undoStackquá đầy (vượtMAX_HISTORY_STATES), xóa trạng thái cũ nhất. - Xóa
redoStackvì một hành động mới làm mất hiệu lực các hành động redo trước đó. - Cập nhật trạng thái
disabledcủa nút Undo/Redo.
undoLastAction(canvas, ctx):- Nếu
undoStackcó nhiều hơn 1 trạng thái (trạng thái đầu tiên là trạng thái rỗng/ban đầu). - Lấy trạng thái cuối cùng từ
undoStackvà đẩy vàoredoStack. - Lấy trạng thái mới nhất từ
undoStack(giờ là trạng thái trước đó). - Tạo một
Imageobject, đặtsrclà chuỗi Base64 của trạng thái đó. - Khi ảnh tải xong (
img.onload), xóa canvas và vẽ lại ảnh này lên canvas (ctx.drawImage(img, 0, 0)). - Cập nhật trạng thái nút.
- Nếu
redoLastAction(canvas, ctx):- Nếu
redoStackcó phần tử. - Lấy trạng thái cuối cùng từ
redoStackvà đẩy lại vàoundoStack. - Tải và vẽ lại ảnh tương tự như Undo.
- Cập nhật trạng thái nút.
- Nếu
- Phím tắt:
Ctrl+Zcho Undo,Ctrl+Ycho Redo được xử lý trongjs/main.js(chỉ khi bảng vẽ đang hoạt động).
- File chính:
js/canvas/canvasContext.js(hàmclearDrawingArea),js/ui/toolbarController.js - Hoạt động:
- Khi nút "Clear" trên toolbar được nhấp và người dùng xác nhận:
clearDrawingArea()được gọi, sử dụngctx.clearRect(0, 0, canvas.width, canvas.height)để xóa toàn bộ nội dung canvas.resetUndoRedoHistory(getCanvas())được gọi để xóa lịch sử và ghi lại trạng thái trống mới làm điểm bắt đầu cho Undo.
- Khi nút "Clear" trên toolbar được nhấp và người dùng xác nhận:
- Files chính:
js/ui/firstRunGuide.js,js/utils/storage.js - Hoạt động:
- Khi tiện ích được kích hoạt lần đầu (
enableExtensiontrongmain.js):checkAndShowFirstRunGuide()được gọi.- Hàm này sử dụng
storage.js(wrapper chochrome.storage.local) để kiểm tra xem khóaSTORAGE_KEY_GUIDE_SEENđã được đặt chưa. - Nếu chưa:
- Tạo (nếu chưa có) và hiển thị một modal HTML (
#overdraw-guide-modal) với các hướng dẫn cơ bản.
- Tạo (nếu chưa có) và hiển thị một modal HTML (
- Khi người dùng nhấp nút "Got it!" trên modal:
- Modal được ẩn.
- Khóa
STORAGE_KEY_GUIDE_SEENđược đặt thànhtruetrongchrome.storage.localđể không hiển thị lại ở các lần sau.
- Khi tiện ích được kích hoạt lần đầu (
Chào mừng mọi đóng góp! Vui lòng tạo Pull Request hoặc mở Issue để thảo luận về các thay đổi hoặc tính năng mới.
Dự án này được cấp phép theo MIT License (Bạn cần tạo file LICENSE.txt nếu muốn).
This project uses ES module syntax, which is not supported directly in Chrome extension content scripts. You must bundle the code before loading the extension in Chrome.
- Node.js installed
npm install --save-dev esbuild
node build.js
This will generate dist/bundle.js. The extension is now ready to load in Chrome.
If you make changes to the JS files, re-run the build command above.