Project Overview
Sketchpad is a web-based drawing application for creating pixel art. Built using vanilla JavaScript, HTML, and CSS without any external libraries or frameworks, this project serves as a practical exercise in core web technologies. It offers a range of drawing tools and features, allowing users to create colorful pixel art directly in their web browsers.
Key Features
- Customizable Grid: Users can adjust the size of the drawing grid from 16x16 up to 64x64 pixels.
- Drawing Modes:
- Hover mode: Color pixels by moving the cursor over them.
- Click-and-drag mode: Draw by clicking and dragging the cursor.
- Color Selection:
- Color picker for choosing any color.
- Swatch system for saving and quickly accessing favorite colors.
- Special Tools:
- Eraser for removing color.
- Shading tools to darken or lighten existing colors.
- Rainbow mode for drawing with randomly generated colors.
- Grid Toggle: Option to show or hide the pixel grid lines.
Implementation
Pixel Grid Creation
The drawing grid is created dynamically based on user input:
function createGrid(pixelCount) {
gridContainer.style.gridTemplateColumns = 'repeat(' + pixelCount + ', 1fr)';
for (let i = 0; i < pixelCount * pixelCount; i++) {
const pixelDiv = document.createElement('div');
pixelDiv.classList.add('pixel');
pixelDiv.style.backgroundColor = '#ffffff';
pixelDiv.setAttribute('draggable', false);
pixelDiv.setAttribute('data-shading', 0);
gridContainer.appendChild(pixelDiv);
}
}
// Usage
createGrid(16); // Creates a 16x16 grid
This function creates a grid of divs, each representing a pixel. The grid size is controlled by a slider in the UI, allowing users to change the canvas size dynamically.
Drawing Functionality
Drawing is implemented using event listeners, with different setups for hover and click modes:
function enableDrawing(isHover, isClick) {
const pixels = document.querySelectorAll('.pixel');
if (isHover) {
pixels.forEach((pixel) => {
pixel.addEventListener('mouseover', draw);
});
}
if (isClick) {
pixels.forEach((pixel) => {
pixel.addEventListener('click', draw);
});
window.addEventListener('mousedown', () => {
pixels.forEach((pixel) => {
pixel.addEventListener('mouseover', draw);
});
});
window.addEventListener('mouseup', () => {
pixels.forEach((pixel) => {
pixel.removeEventListener('mouseover', draw);
});
});
}
}
This setup allows for both single-pixel drawing (click mode) and continuous drawing (hover and click-and-drag modes).
Color Management
The color selection system includes a color picker and a swatch functionality:
const colorPicker = document.querySelector('#color-picker');
colorPicker.addEventListener('change', (e) => {
currentColor = e.target.value;
});
const swatches = document.querySelectorAll('.swatch');
swatches.forEach((swatch) => {
swatch.addEventListener('click', (e) => {
if (e.altKey) {
e.target.style.backgroundColor = colorPicker.value;
} else if (!e.target.style.backgroundColor == '') {
currentColor = e.target.style.backgroundColor;
currentColor = rgbToHex(currentColor);
colorPicker.value = currentColor;
}
});
});
This implementation allows users to select colors via the color picker and save them to swatches for quick access. Alt+clicking a swatch saves the current color to it.
Advanced Drawing Tools
The project includes several advanced drawing tools:
function draw() {
if (sketch) {
let nextVal = parseInt(this.dataset.shading);
nextVal = Math.min(nextVal + 1, 9);
this.setAttribute('data-shading', nextVal);
this.style.backgroundColor = darkenColor('rgb(255,255,255)', nextVal);
} else if (erase) {
this.style.backgroundColor = '#FFFFFF';
this.setAttribute('data-shading', 0);
} else if (darken) {
let nextVal = parseInt(this.dataset.shading);
nextVal = Math.min(nextVal + 1, 9);
this.setAttribute('data-shading', nextVal);
this.style.backgroundColor = darkenColor(this.style.backgroundColor, 1);
} else if (lighten) {
let nextVal = parseInt(this.dataset.shading);
nextVal = Math.max(nextVal - 1, -9);
this.setAttribute('data-shading', nextVal);
this.style.backgroundColor = lightenColor(this.style.backgroundColor, 1);
} else if (rainbow) {
this.style.backgroundColor = getRandomColor();
} else {
this.style.backgroundColor = currentColor;
}
}
This function handles different drawing modes, including sketching with shading, erasing, darkening, lightening, and rainbow mode.
Learning Outcomes
This project provided hands-on experience with:
- DOM manipulation for creating and modifying elements dynamically
- Event handling in JavaScript for interactive features
- CSS Grid for creating responsive layouts
- Color theory and manipulation in web development
- Implementing user interface controls (sliders, buttons, color pickers)
Challenges and Solutions
- Color Conversion: Implemented utility functions for converting between color formats (HEX and RGB) to support different color operations.
- Tool Implementation: Created modular functions for different drawing tools, allowing for easy addition of new features.
Looking Back
Looking back at this project from the perspective of a slightly experienced developer, it’s pretty cool to see how far I’ve come. Sketchpad represents an important stepping stone in my journey as a web developer. It demonstrates the power of hands-on learning and the rapid growth that comes from actually building things.
By challenging myself to build something functional using only vanilla JavaScript, HTML, and CSS, I laid a strong foundation for more complex projects to come. It’s a testament to how curiosity and willingness to create can push one to expand their skills rapidly.
While my current work and projects involve more advanced technologies and complex architectures, Sketchpad remains a fond reminder of where my journey began and how far self-motivation and consistent practice can take you in the world of web development.
The project code is available on GitHub. Feel free to explore, use, or contribute to the project.