Lexington has been awarded a grant from Astro, to celebrate. Get a 30% discount. Apply code LEXINGTON30 ( uppercase ) at checkout.

← Back to all tutorials

How to create a basic drawing tool and save to PNG with Tailwind CSS and JavaScript

js-drawing-tool
Published and written on Sep 11 2024 by Michael Andreuzza

Today we’ll be creating a basic drawing tool using Tailwind CSS and JavaScript. We’ll be using the canvas element to draw on the page and the toDataURL method to save the drawing as a PNG file.

What is a drawing tool?

A drawing tool is a digital application or feature that allows users to create, edit, and manipulate visual content on a computer or mobile device. It typically provides a canvas or workspace where users can draw freehand using various tools like brushes, pens, or shapes. Drawing tools can range from simple sketch applications to complex professional-grade software used in graphic design, illustration, and digital art.

Use cases

  1. Sketching:

    • Quick visualization of ideas or concepts
    • Creating rough drafts for more complex designs
    • Brainstorming sessions and mind mapping
  2. Digital Art:

    • Creating illustrations, paintings, and other forms of visual art
    • Comic book and manga creation
    • Character design for games or animation
  3. Graphic Design:

    • Logo design and branding elements
    • Creating marketing materials like flyers, posters, and social media graphics
    • User interface (UI) and user experience (UX) design mockups
  4. Education:

    • Interactive whiteboards for online teaching
    • Visual aids for explaining complex concepts
    • Student projects and assignments in art or design classes
  5. Annotation and Markup:

    • Adding notes or highlights to documents or images
    • Collaborative editing and feedback on visual projects
    • Creating visual instructions or tutorials
  6. Web Design:

    • Wireframing websites and web applications
    • Creating custom icons and graphics for web use
    • Designing responsive layouts and user interfaces
  7. Photo Editing:

    • Retouching and enhancing photographs
    • Creating photo manipulations and composites
    • Adding text or graphics to images
  8. Technical Drawing:

    • Creating diagrams and flowcharts
    • Architectural sketches and floor plans
    • Engineering drawings and schematics
  9. Game Development:

    • Designing game assets and sprites
    • Creating textures for 3D models
    • Concept art for game environments and characters
  10. Data Visualization:

    • Creating custom charts and graphs
    • Designing infographics
    • Mapping data in visual formats
  11. Personal Expression:

    • Digital journaling and scrapbooking
    • Creating personalized gifts or cards
    • Therapeutic art and self-expression
  12. Prototyping:

    • Quickly visualizing product designs
    • Creating interactive prototypes for apps or websites
    • Iterating on design concepts

By incorporating these various use cases, drawing tools become versatile instruments that cater to a wide range of creative, professional, and practical needs across multiple industries and personal applications.

Let’s start writing the code

The canvas

We’ll use the canvas element to draw on the page Id’s

  • id="drawingCanvas": This is the id of the canvas element. It’s used to reference the element in JavaScript. We’ll use this id to access the canvas element in our JavaScript code. Classes
  • class="w-full: This is a class that sets the width of the canvas to 100% of its parent container.
  • class="h-80": This is a class that sets the height of the canvas to 80 pixels. Addding the size of the canvas to the parent container will ensure that the canvas fills the entire space available to it. Otherwise the <canvas> element will be smaller than the parent container.
<canvas
   id="drawingCanvas"
   class="w-full h-80">
</canvas>

The color picker

We’ll use the input element to create a color picker. Thi is a native HTML element that allows users to select and change the color of an element. You can always another lubrary like pickr.js to create a more advanced color picker. Like i am using on many of the color pickers on Colors & fonts website. Type

  • type="color": This is the type of the color picker input element. It’s used to specify that the input element is a color picker. Id’s
  • id="colorPicker": This is the id of the color picker input element. It’s used to reference the element in JavaScript. We’ll use this id to access the color picker input element in our JavaScript code. Classes
  • class="h-10": This is a class that sets the height of the color picker input element to 10 pixels.
  • class="w-10": This is a class that sets the width of the color picker input element to 10 pixels.
<input
      type="color"
      id="colorPicker"
      class="h-10 w-10"
      />

The brush size slider

We’ll use the input element to create a slider for the brush size. This slider will allow users to change the size of the brush used to draw on the canvas. We’ll use the value attribute to set the initial value of the slider. The min and max attributes set the minimum and maximum values for the slider, and the step attribute sets the increment value for the slider. Type

  • type="range": This is the type of the range input element. It’s used to specify that the input element is a range slider. Id’s
  • id="brushSize": This is the id of the range slider input element. Attributes
  • min="1": This is an attribute that sets the minimum value of the range slider to 1.
  • max="20": This is an attribute that sets the maximum value of the range slider to 20.
  • value="5": This is an attribute that sets the initial value of the range slider to 5. Classes
  • class="w-full": This is a class that sets the width of the range slider input element to 100% of its parent container. Make it full if needed, otherwise it will be smaller than the parent container.
<input
   type="range"
   id="brushSize"
   min="1"
   max="20"
   value="5"
   class="w-full"
   />

The buttons

We’ll use the button element to create buttons for clearing the canvas and saving the drawing. Clearing the canvas button

  • id="clearBtn": This is the id of the clear button. This button will clear the canvas when clicked.
  • id="saveBtn": This is the id of the save button. This button will save the drawing when clicked.
<button
   id="clearBtn">
   Clear
</button>
<button
   id="saveBtn">
   Save
</button>

The full markup

<div >
   <canvas
      id="drawingCanvas"
      class="border border-neutral-200 shadow rounded-xl w-full h-80"
      ></canvas>
   <div class="mt-4 flex items-center space-x-4 w-full flex-row">
      <input
         type="color"
         id="colorPicker"
         class="h-10 w-10"
         />
      <input
         type="range"
         id="brushSize"
         min="1"
         max="20"
         value="5"
         class="w-full"
         />
   </div>
   <div class="flex  mt-8 gap-4">
      <button
         id="clearBtn"
         class="rounded-full bg-blue-50 px-8 py-2 h-12 text-sm font-semibold text-blue-600 hover:bg-blue-100 focus:outline-none focus:ring-2 focus:ring-blue-500 focus:ring-offset-2 w-full"
         >Clear</button
         >
      <button
         id="saveBtn"
         class="rounded-full bg-blue-600 px-8 py-2 h-12 text-sm font-semibold text-white hover:bg-blue-500 focus:outline-none focus:ring-2 focus:ring-blue-500 focus:ring-offset-2 w-full"
         >Save</button
         >
   </div>
</div>

Let´s write the JavaScript code

The variables

We’ll use the canvas element to draw on the page and the toDataURL method to save the drawing as a PNG file. We’ll also use the getContext method to get the 2D context of the canvas element. We’ll use the colorPicker and brushSize variables to store the color picker and brush size input elements. We’ll also use the clearBtn and saveBtn variables to store the clear and save buttons.

  • const canvas = document.getElementById("drawingCanvas");: This is a constant variable that stores the canvas element.
  • const ctx = canvas.getContext("2d");: This is a constant variable that stores the 2D context of the canvas element.
  • const colorPicker = document.getElementById("colorPicker");: This is a constant variable that stores the color picker input element.
  • const brushSize = document.getElementById("brushSize");: This is a constant variable that stores the brush size input element.
  • const clearBtn = document.getElementById("clearBtn");: This is a constant variable that stores the clear button.
  • const saveBtn = document.getElementById("saveBtn");: This is a constant variable that stores the save button.
  • let isDrawing = false;: This is a let variable that stores the state of the drawing.
const canvas = document.getElementById("drawingCanvas");
const ctx = canvas.getContext("2d");
const colorPicker = document.getElementById("colorPicker");
const brushSize = document.getElementById("brushSize");
const clearBtn = document.getElementById("clearBtn");
const saveBtn = document.getElementById("saveBtn");
let isDrawing = false;

Resizing the canvas

We’ll use the resizeCanvas function to resize the canvas element to the size of its parent container. We’ll use the canvas.width and canvas.height properties to get the width and height of the canvas element.

  • canvas.width = canvas.clientWidth;: This line of code sets the width of the canvas element to the width of its parent container.
  • canvas.height = canvas.clientHeight;: This line of code sets the height of the canvas element to the height of its parent container.
function resizeCanvas() {
   canvas.width = canvas.clientWidth;
   canvas.height = canvas.clientHeight;
}

Getting the mouse position

  • getMousePos(canvas, e): This function takes two arguments, canvas and e, and returns an object with the x and y coordinates of the mouse position relative to the canvas element.
  • const rect = canvas.getBoundingClientRect();: This line of code gets the bounding rectangle of the canvas element.
  • const scaleX = canvas.width / rect.width;: This line of code calculates the scale factor for the x-axis.
  • const scaleY = canvas.height / rect.height;: This line of code calculates the scale factor for the y-axis.
  • return {: This line of code returns an object with the x and y coordinates of the mouse position relative to the canvas element.
  • x: (e.clientX - rect.left) * scaleX,: This line of code calculates the x-coordinate of the mouse position relative to the canvas element.
  • y: (e.clientY - rect.top) * scaleY,: This line of code calculates the y-coordinate of the mouse position relative to the canvas element.
function getMousePos(canvas, e) {
   const rect = canvas.getBoundingClientRect();
   const scaleX = canvas.width / rect.width;
   const scaleY = canvas.height / rect.height;
   return {
      x: (e.clientX - rect.left) * scaleX,
      y: (e.clientY - rect.top) * scaleY,
   };
}

Starting and stopping drawing

  • startDrawing(e): This function is called when the user starts drawing on the canvas.
  • isDrawing = true;: This line of code sets the isDrawing variable to true.
  • draw(e): This function is called when the user is drawing on the canvas.
function startDrawing(e) {
   isDrawing = true;
   draw(e);
}

Stopping drawing

  • stopDrawing(): This function is called when the user stops drawing on the canvas.
  • isDrawing = false;: This line of code sets the isDrawing variable to false.
  • ctx.beginPath();: This line of code clears the current path of the canvas.
function stopDrawing() {
   isDrawing = false;
   ctx.beginPath();
}

Drawing on the canvas

  • draw(e): This function is called when the user is drawing on the canvas.
  • ctx.lineWidth = brushSize.value;: This line of code sets the line width of the canvas to the value of the brush size input element.
  • ctx.lineCap = "round";: This line of code sets the line cap of the canvas to “round”.
  • ctx.strokeStyle = colorPicker.value;: This line of code sets the stroke style of the canvas to the value of the color picker input element.
  • const pos = getMousePos(canvas, e);: This line of code gets the mouse position relative to the canvas element.
  • ctx.lineTo(pos.x, pos.y);: This line of code draws a line from the current position to the mouse position.
  • ctx.stroke();: This line of code strokes the path.
  • ctx.beginPath();: This line of code clears the current path of the canvas.
  • ctx.moveTo(pos.x, pos.y);: This line of code moves the current position to the mouse position.
function draw(e) {
   if (!isDrawing) return;
   ctx.lineWidth = brushSize.value;
   ctx.lineCap = "round";
   ctx.strokeStyle = colorPicker.value;
   const pos = getMousePos(canvas, e);
   ctx.lineTo(pos.x, pos.y);
   ctx.stroke();
   ctx.beginPath();
   ctx.moveTo(pos.x, pos.y);
}

Clearing the canvas

  • clearCanvas(): This function is called when the user clicks the clear button.
  • ctx.clearRect(0, 0, canvas.width, canvas.height);: This line of code clears the canvas by drawing a rectangle with the coordinates (0, 0) and the width and height of the canvas.
function clearCanvas() {
   ctx.clearRect(0, 0, canvas.width, canvas.height);
}

Saving the drawing

We’ll use the toDataURL method to save the drawing as a PNG file.

  • saveDrawing(): This function is called when the user clicks the save button.
  • const dataURL = canvas.toDataURL("image/png");: This line of code gets the data URL of the canvas element.
  • const link = document.createElement("a");: This line of code creates a new anchor element.
  • link.download = "drawing.png";: This line of code sets the download attribute of the anchor element to “drawing.png”.
  • link.href = dataURL;: This line of code sets the href attribute of the anchor element to the data URL of the canvas element.
  • link.click();: This line of code simulates a click on the anchor element.
function saveDrawing() {
   const dataURL = canvas.toDataURL("image/png");
   const link = document.createElement("a");
   link.download = "drawing.png";
   link.href = dataURL;
   link.click();
}

Event listeners and initialization

  • window.addEventListener("resize", resizeCanvas);: This line of code adds a resize event listener to the window object.
  • canvas.addEventListener("mousedown", startDrawing);: This line of code adds a mousedown event listener to the canvas object.
  • canvas.addEventListener("mousemove", draw);: This line of code adds a mousemove event listener to the canvas object.
  • canvas.addEventListener("mouseup", stopDrawing);: This line of code adds a mouseup event listener to the canvas object.
  • canvas.addEventListener("mouseout", stopDrawing);: This line of code adds a mouseout event listener to the canvas object.
  • clearBtn.addEventListener("click", clearCanvas);: This line of code adds a click event listener to the clear button.
  • saveBtn.addEventListener("click", saveDrawing);: This line of code adds a click event listener to the save button.
  • resizeCanvas();: This line of code calls the resizeCanvas function.
window.addEventListener("resize", resizeCanvas);
canvas.addEventListener("mousedown", startDrawing);
canvas.addEventListener("mousemove", draw);
canvas.addEventListener("mouseup", stopDrawing);
canvas.addEventListener("mouseout", stopDrawing);
clearBtn.addEventListener("click", clearCanvas);
saveBtn.addEventListener("click", saveDrawing);
// Initialize canvas size
resizeCanvas();

The full script

const canvas = document.getElementById("drawingCanvas");
const ctx = canvas.getContext("2d");
const colorPicker = document.getElementById("colorPicker");
const brushSize = document.getElementById("brushSize");
const clearBtn = document.getElementById("clearBtn");
const saveBtn = document.getElementById("saveBtn");
let isDrawing = false;

function resizeCanvas() {
   canvas.width = canvas.clientWidth;
   canvas.height = canvas.clientHeight;
}

function getMousePos(canvas, e) {
   const rect = canvas.getBoundingClientRect();
   const scaleX = canvas.width / rect.width;
   const scaleY = canvas.height / rect.height;
   return {
      x: (e.clientX - rect.left) * scaleX,
      y: (e.clientY - rect.top) * scaleY,
   };
}

function startDrawing(e) {
   isDrawing = true;
   draw(e);
}

function stopDrawing() {
   isDrawing = false;
   ctx.beginPath();
}

function draw(e) {
   if (!isDrawing) return;
   ctx.lineWidth = brushSize.value;
   ctx.lineCap = "round";
   ctx.strokeStyle = colorPicker.value;
   const pos = getMousePos(canvas, e);
   ctx.lineTo(pos.x, pos.y);
   ctx.stroke();
   ctx.beginPath();
   ctx.moveTo(pos.x, pos.y);
}

function clearCanvas() {
   ctx.clearRect(0, 0, canvas.width, canvas.height);
}

function saveDrawing() {
   const dataURL = canvas.toDataURL("image/png");
   const link = document.createElement("a");
   link.download = "drawing.png";
   link.href = dataURL;
   link.click();
}
window.addEventListener("resize", resizeCanvas);
canvas.addEventListener("mousedown", startDrawing);
canvas.addEventListener("mousemove", draw);
canvas.addEventListener("mouseup", stopDrawing);
canvas.addEventListener("mouseout", stopDrawing);
clearBtn.addEventListener("click", clearCanvas);
saveBtn.addEventListener("click", saveDrawing);
// Initialize canvas size
resizeCanvas();

Conclusion

This is a simple drawing tool that demonstrates how to use Tailwind CSS and JavaScript to create a basic drawing tool and add some interactivity and basic functionality like clearing the canvas, saving, adding brush size and color pickers. It’s a great starting point for building more complex drawing tools and applications.

Hope you enjoyed this tutorial and have a great day!

/Michael Andreuzza

Did you like this tutorial? Please share it with your friends!

Get lifetime access to every theme available today for $199 and own them forever. Plus, new themes, lifetime updates, use on unlimited projects and enjoy lifetime support.

— No subscription required!