HomeJavascriptPixel Art Maker With Javascript

Pixel Art Maker With Javascript

Hey everyone. Welcome to today’s tutorial. In today’s tutorial, we will learn how to create a pixel art maker. To build this project, we need HTML, CSS and vanilla Javascript.
 
This project is perfect for javascript intermediates. If you are looking for simpler projects or more complex, you should check out this playlist. This playlist consists of 70+ projects created with HTML, CSS and vanilla Javascript.

Video Tutorial:

If you like to code along to a video tutorial rather than reading this blog post, you can check out the video version of this tutorial here down below. If you find this tutorial interesting, subscribe to my youtube channel. I post new tutorials on web development regularly there. Along with that, I also keep you updated with the latest tips and tricks.

 

Project Folder Structure:

Before we start the coding, let us take a look at the project folder structure. We create a project folder called – ‘Pixel Art Maker’. Within this folder, we have three files- index.html, style.css and script.js.

HTML:

We begin with the HTML code. Firstly copy the code provided to you below and paste it into your HTML document. We create the elements necessary for the layout using HTML.

<!DOCTYPE html>
<html lang="en">
  <head>
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>Pixel Art Generator</title>
    <!-- Google Fonts -->
    <link
      href="https://fonts.googleapis.com/css2?family=Roboto+Mono:wght@500&display=swap"
      rel="stylesheet"
    />
    <!-- Stylesheet -->
    <link rel="stylesheet" href="style.css" />
  </head>
  <body>
    <div class="wrapper">
      <div class="options">
        <div class="opt-wrapper">
          <div class="slider">
            <label for="width-range">Grid Width</label>
            <input type="range" id="width-range" min="1" max="35" />
            <span id="width-value">00</span>
          </div>
          <div class="slider">
            <label for="height-range">Grid Height</label>
            <input type="range" id="height-range" min="1" max="35" />
            <span id="height-value">00</span>
          </div>
        </div>
        <div class="opt-wrapper">
          <button id="submit-grid">Create Grid</button>
          <button id="clear-grid">Clear Grid</button>
          <input type="color" id="color-input" />
          <button id="erase-btn">Erase</button>
          <button id="paint-btn">Paint</button>
        </div>
      </div>
      <div class="container"></div>
    </div>
    <!-- Script -->
    <script src="script.js"></script>
  </body>
</html>

CSS:

Next, we style these elements using CSS. Now copy the code below and paste it into your stylesheet.

* {
  padding: 0;
  margin: 0;
  box-sizing: border-box;
  font-family: "Roboto Mono", monospace;
}
body {
  background-color: #f4c531;
}
.wrapper {
  background-color: #ffffff;
  width: 80vmin;
  position: absolute;
  transform: translate(-50%, -50%);
  top: 50%;
  left: 50%;
  padding: 40px 20px;
  border-radius: 8px;
}
label {
  display: block;
}
span {
  position: relative;
  font-size: 22px;
  bottom: -1px;
}
.opt-wrapper {
  display: flex;
  justify-content: space-between;
  margin-bottom: 20px;
  gap: 10px;
}
button {
  background-color: #f4c531;
  border: none;
  border-radius: 5px;
  padding: 5px;
}
input[type="color"] {
  -webkit-appearance: none;
  -moz-appearance: none;
  appearance: none;
  background-color: transparent;
  width: 70px;
  height: 40px;
  border: none;
  cursor: pointer;
}
input[type="color"]::-webkit-color-swatch {
  border-radius: 8px;
  border: 4px solid #000000;
}
input[type="color"]::-moz-color-swatch {
  border-radius: 8px;
  border: 4px solid #000000;
}
.gridCol {
  height: 1em;
  width: 1em;
  border: 1px solid #ddd;
}
.gridRow {
  display: flex;
}
@media only screen and (max-width: 768px) {
  .gridCol {
    height: 0.8em;
    width: 0.8em;
  }
}

Javascript:

Lastly, we implement the functionality using javascript. Once again copy the code below and paste it into your javascript file. We implement the logic in six steps. The steps are as follows:
1. Create the initial references.
2. Create an events object.
3. Function to detect touch device.
4. Function to create the grid.
5. Add event listeners to clear grid, erase and paint button.
6. Display grid height and width.

//Initial references
let container = document.querySelector(".container");
let gridButton = document.getElementById("submit-grid");
let clearGridButton = document.getElementById("clear-grid");
let gridWidth = document.getElementById("width-range");
let gridHeight = document.getElementById("height-range");
let colorButton = document.getElementById("color-input");
let eraseBtn = document.getElementById("erase-btn");
let paintBtn = document.getElementById("paint-btn");
let widthValue = document.getElementById("width-value");
let heightValue = document.getElementById("height-value");

//Events object
let events = {
  mouse: {
    down: "mousedown",
    move: "mousemove",
    up: "mouseup",
  },
  touch: {
    down: "touchstart",
    move: "touchmove",
    up: "touchend",
  },
};

let deviceType = "";

//Initially draw and erase would be false
let draw = false;
let erase = false;

//Detect touch device
const isTouchDevice = () => {
  try {
    //We try to create TouchEvent(it would fail for desktops and throw error)
    document.createEvent("TouchEvent");
    deviceType = "touch";
    return true;
  } catch (e) {
    deviceType = "mouse";
    return false;
  }
};

isTouchDevice();

//Create Grid
gridButton.addEventListener("click", () => {
  //Initially clear the grid (old grids cleared)
  container.innerHTML = "";
  //count variable for generating unique ids
  let count = 0;
  //loop for creating rows
  for (let i = 0; i < gridHeight.value; i++) {
    //incrementing count by 2
    count += 2;
    //Create row div
    let div = document.createElement("div");
    div.classList.add("gridRow");
    //Create Columns
    for (let j = 0; j < gridWidth.value; j++) {
      count += 2;
      let col = document.createElement("div");
      col.classList.add("gridCol");
      /* We need unique ids for all columns (for touch screen specifically) */
      col.setAttribute("id", `gridCol${count}`);

      /*
      For eg if deviceType = "mouse"
      the statement for the event would be events[mouse].down which equals to mousedown
      if deviceType="touch"
      the statement for event would be events[touch].down which equals to touchstart
       */

      col.addEventListener(events[deviceType].down, () => {
        //user starts drawing
        draw = true;
        //if erase = true then background = transparent else color
        if (erase) {
          col.style.backgroundColor = "transparent";
        } else {
          col.style.backgroundColor = colorButton.value;
        }
      });

      col.addEventListener(events[deviceType].move, (e) => {
        /* elementFromPoint returns the element at x,y position of mouse */
        let elementId = document.elementFromPoint(
          !isTouchDevice() ? e.clientX : e.touches[0].clientX,
          !isTouchDevice() ? e.clientY : e.touches[0].clientY
        ).id;
        //checker
        checker(elementId);
      });
      //Stop drawing
      col.addEventListener(events[deviceType].up, () => {
        draw = false;
      });
      //append columns
      div.appendChild(col);
    }
    //append grid to container
    container.appendChild(div);
  }
});
function checker(elementId) {
  let gridColumns = document.querySelectorAll(".gridCol");
  //loop through all boxes
  gridColumns.forEach((element) => {
    //if id matches then color
    if (elementId == element.id) {
      if (draw && !erase) {
        element.style.backgroundColor = colorButton.value;
      } else if (draw && erase) {
        element.style.backgroundColor = "transparent";
      }
    }
  });
}

//Clear Grid
clearGridButton.addEventListener("click", () => {
  container.innerHTML = "";
});
//Erase Button
eraseBtn.addEventListener("click", () => {
  erase = true;
});

//Paint button
paintBtn.addEventListener("click", () => {
  erase = false;
});

//Display grid width and height
gridWidth.addEventListener("input", () => {
  widthValue.innerHTML =
    gridWidth.value < 9 ? `0${gridWidth.value}` : gridWidth.value;
});

gridHeight.addEventListener("input", () => {
  heightValue.innerHTML =
    gridHeight.value < 9 ? `0${gridHeight.value}` : gridHeight.value;
});

window.onload = () => {
  gridWidth.value = 0;
  gridHeight.value = 0;
};

Your pixel art maker is now ready. If you have any issues while creating this code you can download the source code by clicking on the download button below. Also if you have any queries, suggestions or feedback drop them in the comments below.
Happy Coding!

RELATED ARTICLES

3 COMMENTS

  1. Hi do you have some ideas how to fix ” cursor: not-allowed; ” during drawing ?? When you finish draw and do not move cursor and than again start drowing suddenly appear “cursor: not-allowed” and than is True maybe ‘stuck’ and drawing is going without mousedown.

  2. Hi do you have some ideas how to fix ” cursor: not-allowed; ” during drawing ?? When you finish draw and do not move cursor and than again start drowing suddenly appear “cursor: not-allowed” and than is True maybe ‘stuck’ and drawing is going without mousedown.

LEAVE A REPLY

Please enter your comment!
Please enter your name here

17 − 16 =

Most Popular