| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242 |
- const canvas = document.querySelector(".canvas canvas");
- const ctx = canvas.getContext("2d", { willReadFrequently: true });
- ctx.imageSmoothingEnabled = false;
- let drawing = false;
- let lastX, lastY;
- let strokeSize = 8;
- let strokeColor = "black";
- function drawPixelLine(x0, y0, x1, y1) {
- const dx = Math.abs(x1 - x0);
- const dy = Math.abs(y1 - y0);
- const sx = x0 < x1 ? 1 : -1;
- const sy = y0 < y1 ? 1 : -1;
- let err = dx - dy;
- while (true) {
- ctx.fillRect(x0, y0, strokeSize, strokeSize);
- if (x0 === x1 && y0 === y1) break;
- const e2 = 2 * err;
- if (e2 > -dy) {
- err -= dy;
- x0 += sx;
- }
- if (e2 < dx) {
- err += dx;
- y0 += sy;
- }
- }
- }
- // Disable dragging for all images on the page
- document.querySelectorAll('img').forEach(img => {
- img.addEventListener('dragstart', (e) => e.preventDefault());
- });
- canvas.addEventListener("mousedown", start);
- canvas.addEventListener("mouseup", () => (drawing = false));
- canvas.addEventListener("mouseleave", () => (drawing = false));
- canvas.addEventListener("mousemove", move);
- function start(e) {
- drawing = true;
- const rect = canvas.getBoundingClientRect();
- const scaleX = canvas.width / rect.width;
- const scaleY = canvas.height / rect.height;
- lastX = Math.floor((e.clientX - rect.left) * scaleX);
- lastY = Math.floor((e.clientY - rect.top) * scaleY);
- }
- function move(e) {
- if (!drawing) return;
- const rect = canvas.getBoundingClientRect();
- const scaleX = canvas.width / rect.width;
- const scaleY = canvas.height / rect.height;
- const x = Math.floor((e.clientX - rect.left) * scaleX);
- const y = Math.floor((e.clientY - rect.top) * scaleY);
- ctx.fillStyle = strokeColor;
- drawPixelLine(lastX, lastY, x, y);
- lastX = x;
- lastY = y;
- }
- canvas.addEventListener("touchstart", (e) => {
- e.preventDefault();
- const touch = e.touches[0];
- start(touch);
- });
- canvas.addEventListener("touchmove", (e) => {
- e.preventDefault();
- const touch = e.touches[0];
- move(touch);
- });
- canvas.addEventListener("touchend", (e) => {
- e.preventDefault();
- drawing = false;
- });
- /* BUTTONS */
- let pencilButton = document.querySelector("button#pencil");
- let eraserButton = document.querySelector("button#eraser");
- let smallButton = document.querySelector("button#small");
- let mediumButton = document.querySelector("button#medium");
- let clearButton = document.querySelector("button#clear");
- pencilButton.addEventListener("click", (e) => {
- e.preventDefault();
- strokeColor = "black";
- pencilButton.classList.add("active-tool");
- eraserButton.classList.remove("active-tool");
- });
- eraserButton.addEventListener("click", (e) => {
- e.preventDefault();
- strokeColor = "white";
- eraserButton.classList.add("active-tool");
- pencilButton.classList.remove("active-tool");
- });
- smallButton.addEventListener("click", (e) => {
- e.preventDefault();
- strokeSize = 4;
- smallButton.classList.add("active-tool");
- mediumButton.classList.remove("active-tool");
- });
- mediumButton.addEventListener("click", (e) => {
- e.preventDefault();
- strokeSize = 8;
- mediumButton.classList.add("active-tool");
- smallButton.classList.remove("active-tool");
- });
- clearButton.addEventListener("click", (e) => {
- e.preventDefault();
- ctx.clearRect(0, 0, canvas.width, canvas.height);
- window.clearCurrentText();
- });
- copyButton = document.querySelector("button#copy");
- copyButton.addEventListener("click", (e) => {
- e.preventDefault();
- // copy image
- const images = document.querySelectorAll(
- "#chat-log .message-box .canvas img"
- );
- const lastImage = images[0];
- if (lastImage) {
- const img = new Image();
- img.onload = function () {
- ctx.clearRect(0, 0, canvas.width, canvas.height);
- ctx.drawImage(img, 0, 0);
- };
- img.src = lastImage.src;
- }
- // copy text
- const texts = document.querySelectorAll(
- "#chat-log .message-box .canvas .message-text"
- );
- const lastText = texts[0];
- if (lastText) {
- const text = lastText.innerHTML.replace(/<br>/g, "\n");
- window.setCurrentText(text);
- }
- });
- // Color swaths
- const swaths = document.querySelectorAll(".swatch");
- swaths.forEach(swatch => {
- swatch.addEventListener("click", (e) => {
- e.preventDefault();
- const color = swatch.getAttribute("data-color");
- strokeColor = color;
- swaths.forEach(s => s.classList.remove("active-swatch"));
- swatch.classList.add("active-swatch");
-
- // Update user's theme color to match
- if (window.displayUserColor) {
- window.userColor = color;
- window.displayUserColor(color);
- }
-
- // Unset eraser if active
- pencilButton.classList.add("active-tool");
- eraserButton.classList.remove("active-tool");
- });
- });
- // Sync custom color picker with stroke color
- const picker = document.getElementById("user-color-picker");
- if (picker) {
- picker.addEventListener("input", (e) => {
- strokeColor = e.target.value;
- swaths.forEach(s => s.classList.remove("active-swatch"));
- // We could add an active class to the picker container but it's okay
- pencilButton.classList.add("active-tool");
- eraserButton.classList.remove("active-tool");
- });
- }
- // Expand Button
- const expandBtn = document.getElementById("expand-btn");
- if (expandBtn) {
- expandBtn.addEventListener("click", (e) => {
- e.preventDefault();
- document.body.classList.toggle("fullscreen-mode");
- if (document.body.classList.contains("fullscreen-mode")) {
- expandBtn.innerHTML = "shrink ⤡";
- } else {
- expandBtn.innerHTML = "expand ⤢";
- }
- });
- }
- // Randomize Color Button
- const randomColorBtn = document.getElementById("random-color-btn");
- if (randomColorBtn) {
- randomColorBtn.addEventListener("click", (e) => {
- e.preventDefault();
- const newColor = '#' + Math.floor(Math.random() * 16777215).toString(16).padStart(6, '0');
- strokeColor = newColor;
- swaths.forEach(s => s.classList.remove("active-swatch"));
-
- if (picker) picker.value = newColor;
-
- if (window.displayUserColor) {
- window.userColor = newColor;
- window.displayUserColor(newColor);
- }
-
- pencilButton.classList.add("active-tool");
- eraserButton.classList.remove("active-tool");
- });
- }
- // Theme Toggle Button
- const themeBtn = document.getElementById("theme-btn");
- if (themeBtn) {
- themeBtn.addEventListener("click", (e) => {
- e.preventDefault();
- document.body.classList.toggle("light-mode");
- if (document.body.classList.contains("light-mode")) {
- themeBtn.innerHTML = "dark mode 🌙";
- } else {
- themeBtn.innerHTML = "light mode ☀";
- }
- });
- }
- // Download Archive Button
- const downloadBtn = document.getElementById("download-btn");
- if (downloadBtn) {
- downloadBtn.addEventListener("click", (e) => {
- e.preventDefault();
- window.location.href = "/api/download_images";
- });
- }
|