whiteboard / static /js /script.js
5m4ck3r's picture
Update static/js/script.js
dbd98df verified
raw
history blame
9.63 kB
class Whiteboard {
constructor() {
this.canvas = document.getElementById('whiteboard');
this.ctx = this.canvas.getContext('2d');
this.isDrawing = false;
this.history = new History();
this.tools = new DrawingTools(this.canvas, this.ctx);
this.pages = new Pages();
this.setupCanvas();
this.setupEventListeners();
this.setupBrushPreview();
this.setupToolbarToggle();
}
setupCanvas() {
const resize = () => {
this.canvas.width = window.innerWidth;
this.canvas.height = window.innerHeight;
this.setupDrawingStyle();
// Restore the current page
const pageContent = this.pages.getPageContent();
if (pageContent) {
this.ctx.putImageData(pageContent, 0, 0); // Use the drawing content from the current page
}
};
window.addEventListener('resize', resize);
resize();
}
setupToolbarToggle() {
const toolbar = document.querySelector('.bottom-toolbar');
const toggleBtn = document.getElementById('toggleToolbar');
toggleBtn.addEventListener('click', () => {
toolbar.classList.toggle('hidden');
});
}
setupBrushPreview() {
this.brushPreview = document.getElementById('brushPreview');
this.canvas.addEventListener('mousemove', (e) => {
const { x, y } = getMousePos(this.canvas, e);
this.updateBrushPreview(x, y);
});
this.canvas.addEventListener('mouseenter', () => {
this.brushPreview.style.display = 'block';
});
this.canvas.addEventListener('mouseleave', () => {
this.brushPreview.style.display = 'none';
});
}
updateBrushPreview(x, y) {
const size = this.tools.brushSize;
this.brushPreview.style.width = size + 'px';
this.brushPreview.style.height = size + 'px';
this.brushPreview.style.left = (x - size/2) + 'px';
this.brushPreview.style.top = (y - size/2) + 'px';
this.brushPreview.style.borderColor = this.tools.isEraser ? '#000' : this.tools.color;
}
setupDrawingStyle() {
this.ctx.lineCap = 'round';
this.ctx.lineJoin = 'round';
this.ctx.font = '24px Arial';
this.tools.applyToolSettings();
}
setupEventListeners() {
// Mouse events
this.canvas.addEventListener('mousedown', this.startDrawing.bind(this));
this.canvas.addEventListener('mousemove', this.draw.bind(this));
this.canvas.addEventListener('mouseup', this.stopDrawing.bind(this));
this.canvas.addEventListener('mouseout', this.stopDrawing.bind(this));
// Touch events
this.canvas.addEventListener('touchstart', this.handleTouch.bind(this));
this.canvas.addEventListener('touchmove', this.handleTouch.bind(this));
this.canvas.addEventListener('touchend', this.handleTouchEnd.bind(this));
// Button events
document.getElementById('aiBtn').addEventListener('click', this.processDrawing.bind(this));
document.getElementById('submitBtn').addEventListener('click', this.generatePDF.bind(this));
document.getElementById('clearBtn').addEventListener('click', this.clearCanvas.bind(this));
document.getElementById('undoBtn').addEventListener('click', this.undo.bind(this));
document.getElementById('redoBtn').addEventListener('click', this.redo.bind(this));
// Keyboard shortcuts
document.addEventListener('keydown', (e) => {
if (e.ctrlKey || e.metaKey) {
if (e.key === 'z') {
e.preventDefault();
this.undo();
} else if (e.key === 'y') {
e.preventDefault();
this.redo();
}
}
});
}
handleTouch(e) {
e.preventDefault();
const touch = e.touches[0];
const eventType = e.type === 'touchstart' ? 'mousedown' : 'mousemove';
const mouseEvent = new MouseEvent(eventType, {
clientX: touch.clientX,
clientY: touch.clientY
});
this.canvas.dispatchEvent(mouseEvent);
}
handleTouchEnd(e) {
e.preventDefault();
const mouseEvent = new MouseEvent('mouseup', {});
this.canvas.dispatchEvent(mouseEvent);
}
startDrawing(e) {
this.isDrawing = true;
const { x, y } = getMousePos(this.canvas, e);
this.tools.applyToolSettings();
this.ctx.beginPath();
this.ctx.moveTo(x, y);
}
draw(e) {
if (!this.isDrawing) return;
const { x, y } = getMousePos(this.canvas, e);
this.ctx.lineTo(x, y);
this.ctx.stroke();
}
stopDrawing() {
if (this.isDrawing) {
this.isDrawing = false;
this.saveState();
}
}
saveState() {
const imageData = this.ctx.getImageData(0, 0, this.canvas.width, this.canvas.height);
this.history.push(new DrawingState(imageData));
this.pages.setPageContent(this.history.states);
}
undo() {
const state = this.history.undo();
if (state) {
this.ctx.putImageData(state.imageData, 0, 0);
this.pages.setPageContent(this.history.states);
}
}
redo() {
const state = this.history.redo();
if (state) {
this.ctx.putImageData(state.imageData, 0, 0);
this.pages.setPageContent(this.history.states);
}
}
clearCanvas() {
this.ctx.clearRect(0, 0, this.canvas.width, this.canvas.height);
this.saveState();
}
processDrawing() {
const tempCanvas = document.createElement('canvas');
const tempContext = tempCanvas.getContext('2d');
tempCanvas.width = this.canvas.width;
tempCanvas.height = this.canvas.height;
tempContext.fillStyle = 'white';
tempContext.fillRect(0, 0, tempCanvas.width, tempCanvas.height);
tempContext.drawImage(this.canvas, 0, 0);
const imageData = tempCanvas.toDataURL('image/png');
console.log('Processing drawing with AI...');
console.log(imageData.substring(0, 100) + '...');
fetch('/whitebai', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
},
body: JSON.stringify({
image: imageData
})
})
.then(response => response.json())
.then(data => {
if (data.status && Array.isArray(data.data)) {
data.data.forEach(item => {
const result = item.result;
const x = item.location.x;
const y = item.location.y;
const size = item.size;
const sizePx = `${size}px`;
writeOnCanvasDynamic(whiteboard.pages, result, x, y, null, "Arial", sizePx, "black", false);
});
} else {
console.error("Invalid data object or empty data array");
}
})
.catch(error => {
console.error('Error:', error);
});
}
async generatePDF() {
const pages = this.pages.getAllPages();
for (let i = 0; i < pages.length; i++) {
const pageContent = pages[i];
const tempCanvas = document.createElement('canvas');
tempCanvas.width = this.canvas.width;
tempCanvas.height = this.canvas.height;
const tempCtx = tempCanvas.getContext('2d');
tempCtx.fillStyle = 'white';
tempCtx.fillRect(0, 0, tempCanvas.width, tempCanvas.height);
if (pageContent && pageContent.drawing) {
const imageData = pageContent.drawing;
if (imageData) {
try {
tempCtx.putImageData(imageData, 0, 0);
console.log("Image applied to canvas for page " + i);
} catch (error) {
console.log("Error putting image data on page " + i, error);
}
} else {
console.log("No image data for page " + i);
}
}
const imgData = tempCanvas.toDataURL('image/png');
console.log(`Base64 data for page ${i}:`, imgData);
}
}
writeText(text, x = 20, y = 40) {
this.setupDrawingStyle();
this.ctx.fillStyle = this.tools.color;
this.ctx.fillText(text.toString(), x, y);
this.saveState();
}
}
const whiteboard = new Whiteboard();
const canvas = document.getElementById('whiteboard');
document.addEventListener('keydown', function(event) {
if (event.ctrlKey && event.key === 's') {
event.preventDefault();
const tempCanvas = document.createElement('canvas');
const tempContext = tempCanvas.getContext('2d');
tempCanvas.width = canvas.width;
tempCanvas.height = canvas.height;
tempContext.fillStyle = 'white';
tempContext.fillRect(0, 0, tempCanvas.width, tempCanvas.height);
tempContext.drawImage(canvas, 0, 0);
const imageData = tempCanvas.toDataURL("image/png");
const link = document.createElement('a');
link.href = imageData;
link.download = 'canvas-image.png';
link.click();
console.log("Canvas saved as image with white background!");
}
});
function writeOnCanvasDynamic(pagesInstance, text, x, y, fontUrl, fontFamily, fontSize = "16px", color = "black", clear = false) {
const ctx = pagesInstance.ctx;
if (!ctx) return;
const applyFontAndWrite = () => {
ctx.globalCompositeOperation = 'source-over';
if (clear) {
const textWidth = ctx.measureText(text).width;
const lineHeight = parseInt(fontSize, 10) || 16;
ctx.clearRect(x, y - lineHeight, textWidth, lineHeight);
return;
}
ctx.font = `${fontSize} ${fontFamily}`;
ctx.fillStyle = color;
ctx.fillText(text, x, y);
};
if (fontUrl) {
const fontFace = new FontFace(fontFamily, `url(${fontUrl})`);
fontFace.load().then((loadedFont) => {
document.fonts.add(loadedFont);
applyFontAndWrite();
}).catch((err) => {
console.error("Font loading failed:", err);
});
} else {
applyFontAndWrite();
}
}