What steps can I take to mimic a pen-like behavior for my cursor on my sketching website project?

My goal is to create a 16x16 grid with a white background, where each grid item changes color when the mouse is pressed and moved over it, similar to paint. I have written a script to achieve this:

let gridContainer = document.getElementById('grid-container');
let gridArray = [];
for(let i = 0; i < 256; i++){
    let div = document.createElement('div');
    div.setAttribute('class', 'grid-item');
    gridContainer.append(div);
    gridArray[i] = div;
}

gridContainer.addEventListener("mousedown", draw)
gridContainer.addEventListener("mouseup",stopDraw)

function draw(){
    gridArray.forEach(item => item.addEventListener("mouseover", () => {
        (item.classList.add('hover')) 
    }));
}

function stopDraw(){
    gridArray.forEach(item => item.removeEventListener("mouseover", () => {
        (item.classList.add('hover')) 
    }));
}

The hover class adds a blue background color to the grid item.

Although I have tried various approaches, I still encounter the same issue where the draw function remains active even after the mouse is released. I am using vanilla JS and I am still in the process of learning the basics.

For a better understanding of my problem, here is a link to my code: https://codepen.io/ahmedmk11/pen/VwrmyGW

EDIT: Upon reflection, I realize that my initial explanation was not clear. The draw function works correctly, but it does not cease when the mouse button is released. I intend for it to only be active when the mouse button is pressed and held, like a pen.

Answer №1

To enhance the functionality, implementing event listeners is a great way forward. I have made adjustments to your code by utilizing an object. This object serves the purpose of temporarily holding the mouse state. By utilizing the "canDraw()" method, we can check the object to determine if the mouse event is ongoing. This is indicated by the presence of the key "mousedown".

The events now simply add or remove the key from the "mouseEvent" object.

let gridContainer = document.getElementById('grid-container');
let gridArray = [];
let mouseEvent = {};
for(let i = 0; i < 256; i++){
    let div = document.createElement('div');
    div.setAttribute('class', 'grid-item');
    div.addEventListener("mouseover", draw);
    gridContainer.append(div);
    gridArray[i] = div;
}

gridContainer.addEventListener("mousedown", () => mouseEvent.mouseDown = true)
gridContainer.addEventListener("mouseup", () => delete mouseEvent.mouseDown)

function canDraw() {
  return mouseEvent.mouseDown;
}

function draw(e){
    if (canDraw()) {
      e.fromElement.classList.add('hover');
    }
}

Answer №2

It seems like the instructions mention that the divs should be painted when the mouse button is pressed, but they fail to specify that the divs should not be painted when the mouse button is not pressed. This issue occurs in the following section:

function draw(){
    gridArray.forEach(item => item.addEventListener("mouseover", () => {
        (item.classList.add('hover')) 
    }));
}

function stopDraw(){
    // this is where the problem lies!
    gridArray.forEach(item => item.removeEventListener("mouseover", () => {
        (item.classList.add('hover')) 
    }));
}

To address this issue, you can update the code to include a statement like "hey, when my mouse is up and over the divs, I don't want to add the class that paints them," as shown below:

function draw(){
    gridArray.forEach(item => item.addEventListener("mouseover", () => {
        item.classList.add('hover'); 
    }));
}

function stopDraw(){
    // now we have an event that removes the class
    gridArray.forEach(item => item.addEventListener("mouseover", () => {
        item.classList.remove('hover');
    }));
}

I have also made some refinements such as changing 'let' to 'const' where applicable, fixing the formatting, and rearranging the usage of the draw and stopDraw functions after their declarations. Here is the updated solution:

const gridContainer = document.getElementById('grid-container');
let gridArray = [];
for(let i = 0; i < 256; i += 1){
    const div = document.createElement('div');
    div.setAttribute('class', 'grid-item');
    gridContainer.append(div);
    gridArray.push(div);
}

function draw(){
    gridArray.forEach(item => item.addEventListener("mouseover", () => {
        item.classList.add('hover'); 
    }));
}

function stopDraw(){
    gridArray.forEach(item => item.addEventListener("mouseover", () => {
        item.classList.remove('hover');
    }));
}

gridContainer.addEventListener("mousedown", draw);
gridContainer.addEventListener("mouseup", stopDraw);

Similar questions

If you have not found the answer to your question or you are interested in this topic, then look at other similar questions below or use the search

Tips for keeping the app on the same route or page even after a refresh

I'm currently diving into the world of React and am in the process of constructing a CRUD application. I've successfully created multiple pages that utilize react-router-dom for navigation with authentication. The pages are accessible only to log ...

The menu field remains open even after clicking on the menu

I have encountered an issue with my code. Here is a DEMO that I created on jsfiddle.net Currently, when you click on the red div, the menu opens. However, if you click on the menu items, the menu area does not close. What do I need to do in order to clo ...

jQuery's show/hide functionality allows for the dynamic resizing of images,

I am experiencing an issue with a Joomla template that has a custom jQuery menu. When I hover over the map with my mouse, the overlay appears slightly larger than expected. This problem seems to be occurring in Firefox and IE 11, leading me to believe it ...

When resizing the browser, the divs stack neatly without overlapping

We need to ensure that the 4 divs stack on top of each other without overlapping! The header should have the same width as the footer, 100% The menu should stack with the header and footer The content should be centered on the page and stack with the oth ...

What is the best way to extract row data from a datatable and transmit it in JSON format?

I have successfully created a code that retrieves data from a dynamic table using ajax. However, I am facing an issue where I only want to send data from checked rows. Despite trying different approaches, I keep encountering errors or receive an empty arra ...

RStudio Connect now automatically inserts CSS code into cells when updating

My current project involves creating an app for holiday requests. The main page of the app is displayed like this: https://i.sstatic.net/z2qma.png At the bottom right corner, you'll notice a column labeled "Accepted?" which displays either "OK" or " ...

Exploring the power of Javascript for number lookup

I am currently working on a coding project using TypeScript and JavaScript to locate a specific number provided by the user within a list. The goal is to display whether or not the number is present in the list when the 'search' button is pressed ...

The css cropping issue with sprite image is not being resolved

I'm currently working on creating a sprite image for the bottom links on our media page, but I seem to be having trouble getting the image to crop correctly. Can anyone point out where I may be making a mistake? CSS .footer{ position:absolute; ...

Is it possible for Sequelize to utilize a getter or setter within a find query?

When it comes to storing and querying email addresses in my database, I always opt for lowercase strings to prevent duplicate emails such as <a href="/cdn-cgi/l/email-protection" class="__cf_email__" data-cfemail="077274627547627f666a776b62d48ed88e5"> ...

Using JQuery to Update Text, Link, and Icon in a Bootstrap Button Group

I have a Bootstrap Button group with a split button dropdown. My goal is to change the text, href, and icon on the button when an option is selected from the dropdown. I am able to change the text successfully, but I'm having trouble updating the HREF ...

ng-admin fails to identify custom field view

I've been exploring ng-admin. After referring to the documentation, I decided to create a custom field. However, even though ng-admin recognizes the FooFieldType, it is not rendering the FoofieldView and instead using the original FieldView! Conf ...

What are some methods for displaying images retrieved from an API onto an HTML webpage?

Problem: The image is not appearing on my HTML page. How can I fix this issue? Please see below for details. https://i.sstatic.net/XYoHg.png Here are the code snippets I am using to display the image: <div class="col-md-7"> <div c ...

Error in typescript: The property 'exact' is not found in the type 'IntrinsicAttributes & RouteProps'

While trying to set up private routing in Typescript, I encountered the following error. Can anyone provide assistance? Type '{ exact: true; render: (routerProps: RouterProps) => Element; }' is not compatible with type 'IntrinsicAttribu ...

When the canvasJS range column chart is below the horizontal axis, modify the color and width of the bars

For each day of the week, there are records of fuel consumed and refilled. I envisioned representing this data in a range column chart using CanvasJS library. The unique aspect is that the color and width of the bars should change dynamically based on thei ...

Adsense ad unit is not responsive and fails to display properly at dimensions of 320x50 px

I have a unique banner ad that I want to display as the footer on my responsive website. Using media queries recommended in the advertising documentation, I am adjusting the size based on different screen widths. Check out the CSS code below: <style&g ...

Getting the total number of child elements in a web page using Selenium web-driver with Node.js

I've been looking everywhere, but I can't seem to find the answer Here's my HTML code: <form id="search_form_homepage" > ... <div class="search__autocomplete" style="display: block;"> &l ...

Ways to deactivate a button with a designated identification through iteration using jQuery

Can't Figure out How to Deactivate a Button with Specific ID $('.likes-button').click(function(){ var el= this; var button1 = $(el).attr('id'); console.log(button1) $('#button1').attr("disabled",true); }) ...

Tips on customizing regex to selectively identify specific strings without capturing unrelated ones

Currently, I am working with this regex: /(?<=^|\/)(?:(?!\/)(?!.*\/))(.*?)[:-]v([\d.-]+)(?=\.|$)/ The goal is to extract the captured group from the following strings: rhmtc/openshift-velero-plugin-rhel8:v1.7.9-4 oc-mirror-plug ...

tips for loading json data into jqgrid

Utilizing the struts2-jquery-jqgrid plugins, I have created a Grid with a filter-search feature. The Grid includes a drop-down list in the column assigned_user for filtering based on the selected option from the drop-down list. <s:url var="remoteurl" a ...

Update options in HTML form dropdowns dynamically based on selections from other dropdowns using Node.js

In my Node.js application, I have the following file system structure: public elegant-aero.css stadium-wallpaper.jpg team-results.html public.js app.js teamresults.mustache I am trying to dynamically populate a dropdown menu based on user sele ...