You can edit the below JavaScript code to customize the image tool.
Apply Changes
function processImage(originalImg, defaultMode = 'trace', gridSize = 0, penColor = '#ff0000', defaultPenSize = 5) {
// Main container
const container = document.createElement('div');
container.style.display = 'flex';
container.style.flexDirection = 'column';
container.style.alignItems = 'center';
container.style.fontFamily = 'Arial, sans-serif';
container.style.width = '100%';
// Toolbar for game settings
const toolbar = document.createElement('div');
toolbar.style.marginBottom = '15px';
toolbar.style.display = 'flex';
toolbar.style.flexWrap = 'wrap';
toolbar.style.gap = '15px';
toolbar.style.justifyContent = 'center';
toolbar.style.alignItems = 'center';
const colorLabel = document.createElement('label');
colorLabel.innerText = 'Color: ';
colorLabel.style.display = 'flex';
colorLabel.style.alignItems = 'center';
const colorPicker = document.createElement('input');
colorPicker.type = 'color';
colorPicker.value = penColor;
colorPicker.style.marginLeft = '5px';
colorPicker.style.cursor = 'pointer';
colorLabel.appendChild(colorPicker);
const sizeLabel = document.createElement('label');
sizeLabel.innerText = 'Thickness: ';
sizeLabel.style.display = 'flex';
sizeLabel.style.alignItems = 'center';
const penSize = document.createElement('input');
penSize.type = 'range';
penSize.min = '1';
penSize.max = '50';
penSize.value = defaultPenSize.toString();
penSize.style.marginLeft = '5px';
penSize.style.cursor = 'pointer';
sizeLabel.appendChild(penSize);
const btnStyle = "padding: 6px 15px; border: 1px solid #aaa; border-radius: 4px; background: #f0f0f0; cursor: pointer; font-size: 14px; transition: background 0.2s;";
const toggleBgBtn = document.createElement('button');
toggleBgBtn.innerText = 'Toggle Image';
toggleBgBtn.style.cssText = btnStyle;
const toggleGridBtn = document.createElement('button');
toggleGridBtn.innerText = 'Toggle Grid';
toggleGridBtn.style.cssText = btnStyle;
const clearBtn = document.createElement('button');
clearBtn.innerText = 'Clear Drawing';
clearBtn.style.cssText = btnStyle;
toolbar.appendChild(colorLabel);
toolbar.appendChild(sizeLabel);
toolbar.appendChild(toggleBgBtn);
toolbar.appendChild(toggleGridBtn);
toolbar.appendChild(clearBtn);
container.appendChild(toolbar);
// Wrapper for both layered canvases
const canvasContainer = document.createElement('div');
canvasContainer.style.position = 'relative';
canvasContainer.style.width = '100%';
canvasContainer.style.maxWidth = originalImg.width + 'px';
canvasContainer.style.display = 'inline-block';
canvasContainer.style.border = '1px solid #ccc';
canvasContainer.style.boxSizing = 'border-box';
canvasContainer.style.backgroundColor = '#ffffff';
// Background Canvas (for Image and Grid)
const bgCanvas = document.createElement('canvas');
bgCanvas.width = originalImg.width;
bgCanvas.height = originalImg.height;
bgCanvas.style.width = '100%';
bgCanvas.style.height = '100%';
bgCanvas.style.position = 'absolute';
bgCanvas.style.top = '0';
bgCanvas.style.left = '0';
bgCanvas.style.pointerEvents = 'none'; // So drawing events pass to the interactive canvas below
const bgCtx = bgCanvas.getContext('2d');
function drawBackground(showImage, showGrid) {
bgCtx.clearRect(0, 0, bgCanvas.width, bgCanvas.height);
if (showImage) {
bgCtx.globalAlpha = 0.35; // Faint background for tracing
bgCtx.drawImage(originalImg, 0, 0);
bgCtx.globalAlpha = 1.0;
}
if (showGrid) {
// Calculate an even grid size relative to the canvas if none was explicitly configured
let parsedGridSize = parseInt(gridSize, 10);
const size = parsedGridSize > 0 ? parsedGridSize : Math.max(20, Math.floor(Math.min(bgCanvas.width, bgCanvas.height) / 10));
bgCtx.beginPath();
for (let x = 0; x <= bgCanvas.width; x += size) {
bgCtx.moveTo(x, 0);
bgCtx.lineTo(x, bgCanvas.height);
}
for (let y = 0; y <= bgCanvas.height; y += size) {
bgCtx.moveTo(0, y);
bgCtx.lineTo(bgCanvas.width, y);
}
bgCtx.strokeStyle = 'rgba(0, 0, 0, 0.4)';
bgCtx.lineWidth = 1;
bgCtx.stroke();
// Helpful coordinates for "Draw by grid" mode
bgCtx.fillStyle = 'rgba(0, 0, 0, 0.6)';
bgCtx.font = '12px Arial';
for (let x = 0; x < bgCanvas.width; x += size) {
for (let y = 0; y < bgCanvas.height; y += size) {
bgCtx.fillText(`${x/size},${y/size}`, x + 3, y + 13);
}
}
}
}
let isImageVisible = true;
let isGridVisible = defaultMode === 'grid';
drawBackground(isImageVisible, isGridVisible);
// Interactive Foreground Canvas
const drawCanvas = document.createElement('canvas');
drawCanvas.width = originalImg.width;
drawCanvas.height = originalImg.height;
drawCanvas.style.width = '100%';
drawCanvas.style.height = 'auto'; // Scales relative to wrapper dynamically
drawCanvas.style.display = 'block';
drawCanvas.style.cursor = 'crosshair';
drawCanvas.style.touchAction = 'none'; // Prevent swiping-to-scroll to allow clean drawing
const drawCtx = drawCanvas.getContext('2d');
drawCtx.lineCap = 'round';
drawCtx.lineJoin = 'round';
canvasContainer.appendChild(bgCanvas);
canvasContainer.appendChild(drawCanvas);
container.appendChild(canvasContainer);
// Core drawing logic
let isDrawing = false;
let lastX = 0;
let lastY = 0;
function getMousePos(e) {
const rect = drawCanvas.getBoundingClientRect();
const scaleX = drawCanvas.width / rect.width;
const scaleY = drawCanvas.height / rect.height;
let clientX = e.clientX;
let clientY = e.clientY;
if (e.touches && e.touches.length > 0) {
clientX = e.touches[0].clientX;
clientY = e.touches[0].clientY;
}
return {
x: (clientX - rect.left) * scaleX,
y: (clientY - rect.top) * scaleY
};
}
function startDrawing(e) {
e.preventDefault();
isDrawing = true;
const pos = getMousePos(e);
lastX = pos.x;
lastY = pos.y;
}
function draw(e) {
if (!isDrawing) return;
e.preventDefault();
const pos = getMousePos(e);
drawCtx.strokeStyle = colorPicker.value;
drawCtx.lineWidth = parseInt(penSize.value, 10);
drawCtx.beginPath();
drawCtx.moveTo(lastX, lastY);
drawCtx.lineTo(pos.x, pos.y);
drawCtx.stroke();
lastX = pos.x;
lastY = pos.y;
}
function stopDrawing(e) {
if (e) e.preventDefault();
isDrawing = false;
}
// Events mapping
drawCanvas.addEventListener('mousedown', startDrawing);
drawCanvas.addEventListener('mousemove', draw);
drawCanvas.addEventListener('mouseup', stopDrawing);
drawCanvas.addEventListener('mouseout', stopDrawing);
drawCanvas.addEventListener('touchstart', startDrawing, { passive: false });
drawCanvas.addEventListener('touchmove', draw, { passive: false });
drawCanvas.addEventListener('touchend', stopDrawing, { passive: false });
drawCanvas.addEventListener('touchcancel', stopDrawing, { passive: false });
toggleBgBtn.addEventListener('click', () => {
isImageVisible = !isImageVisible;
drawBackground(isImageVisible, isGridVisible);
});
toggleGridBtn.addEventListener('click', () => {
isGridVisible = !isGridVisible;
drawBackground(isImageVisible, isGridVisible);
});
clearBtn.addEventListener('click', () => {
drawCtx.clearRect(0, 0, drawCanvas.width, drawCanvas.height);
});
return container;
}
Apply Changes