What could be the reason that the painting application is not functioning properly on mobile devices?

I am facing an issue with my painting app where it works perfectly on desktop browsers but fails to function on mobile devices. I tried adding event listeners for mobile events, which are understood by mobile devices, but unfortunately, that did not solve the problem. Any suggestions on how I can troubleshoot and fix this issue?

Here is the link to the app: https://codepen.io/sp2012/pen/oNWeZBx

Below is the code for reference:

HTML

<input type="color"  class="js-color-picker  color-picker">
<input type="range" class="js-line-range" min="1" max="72" value="1">
<label class="js-range-value">1</label>Px
<canvas class="js-paint  paint-canvas" width="200" height="200"></canvas>

CSS

.paint-canvas {
  border: 1px black solid;
  display: block;
  margin: 1rem;
}

.color-picker {
  margin: 1rem 1rem 0 1rem;
}

JS

const paintCanvas = document.querySelector( '.js-paint' );
const context = paintCanvas.getContext( '2d' );
context.lineCap = 'round';

const colorPicker = document.querySelector( '.js-color-picker');

colorPicker.addEventListener( 'change', event => {
    context.strokeStyle = event.target.value; 
} );

const lineWidthRange = document.querySelector( '.js-line-range' );
const lineWidthLabel = document.querySelector( '.js-range-value' );

lineWidthRange.addEventListener( 'input', event => {
    const width = event.target.value;
    lineWidthLabel.innerHTML = width;
    context.lineWidth = width;
} );

let x = 0, y = 0;
let isMouseDown = false;

const stopDrawing = () => { isMouseDown = false; }
const startDrawing = event => {
    isMouseDown = true;   
   [x, y] = [event.offsetX, event.offsetY];  
}
const drawLine = event => {
    if ( isMouseDown ) {
        const newX = event.offsetX;
        const newY = event.offsetY;
        context.beginPath();
        context.moveTo( x, y );
        context.lineTo( newX, newY );
        context.stroke();
        //[x, y] = [newX, newY];
        x = newX;
        y = newY;
    }
}

paintCanvas.addEventListener( 'mousedown', startDrawing );
paintCanvas.addEventListener( 'mousemove', drawLine );
paintCanvas.addEventListener( 'mouseup', stopDrawing );
paintCanvas.addEventListener( 'mouseout', stopDrawing );

paintCanvas.addEventListener("touchstart", startDrawing);
paintCanvas.addEventListener("touchend", stopDrawing);
paintCanvas.addEventListener("touchcancel", stopDrawing);
paintCanvas.addEventListener("touchmove", drawLine);

Answer №1

While I may not be an expert, one interesting observation is that inserting a console.table(event) statement within the startDrawing function reveals a distinction in the type of object received based on whether the application is in desktop or mobile mode. In desktop mode, a MouseEvent object is captured, whereas in mobile mode, a TouchEvent replaces it, lacking the offsetX/offsetY properties.

A workaround could involve utilizing either event.touches or event.targetTouches, which both offer a TouchList object comprising various properties like coordinates for each individual Touch object:

https://i.sstatic.net/riEgX.png

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

What sets Vue.js apart, class and staticClass - is there a distinction?

Can someone explain the distinction between class and staticClass in Vue.js render functions? While using Template Compilation, I noticed that the output varies based on what is provided to the HTML class attribute. For instance, when passing a single str ...

Having trouble getting two components to return in React

After successfully implementing the Hello World example by returning "Hello" and "world" from two different components, I encountered a problem with my code. In this specific code snippet, I am unable to return the Menubar component, although the Map compo ...

What is the best way to identify a specific AdWords account while utilizing campaignSelector within AdWords scripts?

I have been working on a script that aims to achieve the following tasks: Go through all the accounts in an MCC and pick out the ones with 'SEM' in their name. Go through the campaigns in a selected account and choose those that meet specific c ...

When scrolling, the fixed menu bar at the top of the page is making the content below jump

I am attempting to create a fixed submenu that sticks to the top of the page when scrolling, but I am encountering some issues. The current code I have is as follows: $(window).scroll(function () { if ($(window).scrollTop() > 175) { $('#loca ...

Encountering an issue: Module not found - 'cryptile' during express js installation

Just dipping my toes into the world of Node.js and I'm encountering some obstacles when trying to install Express.js. Seeking assistance in resolving this issue and successfully setting up Express.js. https://i.stack.imgur.com/PlHiB.png Interestingl ...

Mongoose Does Not Allow for Duplicate Data Submissions

I'm currently working on a project to develop a basic blog application. Everything works smoothly when submitting content to the database for the first time, but if you try to submit again, Node crashes unexpectedly. I've been struggling to pinpo ...

Please input new items by clicking a button

I have a dilemma with handling an array of objects in my Vue component. I am using v-for to display the objects, but now I want to update certain items in the array and save only those changes in a new object. Currently, when I attempt this by mapping over ...

Efficient scripting on Visual Studio

In Visual Studio, a helpful feature is the option box on the left side that allows you to collapse code within curly braces { } using a "-" to minimize and a "+" to expand. This keeps the code organized and clean. I'm curious if there's a way to ...

"Customizing a footer to resemble a bootstrap nav-bar: A step-by-step guide

My situation involves the need to have a footer that functions similarly to a navbar. I want to be able to hide the list items of a ul list by clicking on a custom button, similar to the functionality of the bootstrap hamburger menu. Is it possible to use ...

Impact when returning a React.FC Component

Using React, I have encountered a challenge with my site: I have a function that generates a Card component displaying information about my store's products (#1). To display this on the screen, I map through the array returned by the backend and pass ...

Is it possible to achieve a file upload in splinter using Python?

A challenging task lies ahead with my web application, where users can upload XML-style files and make modifications directly in the browser. To test this scenario using Splinter, I need to ensure correct input (id="form-widgets-body"): Finding it is eas ...

to invoke a jQuery function located on a different webpage

Imagine you have two web pages: hello.html and wow.html. hello.html contains the following script: <script> $(document).ready(function() { $( "#loader" ).load( "wow.html"); }); </script> while wow.html includes this jQuery function: $(fun ...

Implement a personalized click function for the delete icon in the mini cart

Is there a way to customize the click event for the remove button in the mini cart? function ajax_call(){ $.ajax({ url: ajax_url, type: 'post', data: {action : 'remove_from_cart','cart_item_key' : 10}, ...

Avoid triggering a second event: click versus changing the URL hash

One of the pages on my website has tabs that load dynamic content: HTML <ul> <li><a href="#tab-1">TAB 1</li> <li><a href="#tab-2">TAB 2</li> <li><a href="#tab-3">TAB 3</li> </ul&g ...

Dimensions of CSS Buttons

On my screen, I have 3 buttons with varying sizes determined by their padding. As the text wraps within each button, they adjust in height accordingly. However, the issue arises when the buttons end up being different heights. Instead of setting a specific ...

Fetching locales asynchronously in nuxt.js using i18n and axios: A step-by-step guide

I am facing an issue with getting the location asynchronously. Whenever I try to implement my code, it results in a "Maximum call stack size exceeded" error. How can I resolve this issue? Previously, I attempted to retrieve the location by using the axios ...

calls to res.send and res.render

I'm currently trying to determine if it's possible to use res.send(data) and res.render('reports') simultaneously in my code. To provide more details, when I navigate to '/reports', on the server side I am executing a REST ca ...

Troubleshooting height adjustment for header and footer in CSS with dynamic content not functioning properly on Safari for macOS and Safari for iOS (jsBin)

I recently came across a solution by @RokoC.Buljan, which works perfectly on Chrome and Firefox. However, I encountered an issue with Safari where the content section does not scroll properly and the footer sticks to the bottom of the content, making it di ...

"An interactive webpage utilizing HTML5 that transmits sensor information from an iPhone to a server

Recently, I have been immersed in a project that involves utilizing the gyroscope of an iPhone to manipulate items on a computer screen. To achieve this, I have been using an application called "Sensorlogger" which allows me to stream sensor data to the co ...

Merge multiple echoes to create a single echoed string that is valid HTML

<?php // link to Google Docs spreadsheet $url='https://docs.google.com/spreadsheets/d/1_4d-MPxTUOVZbxTOlhjXv1ebTlBPQ-_JrYUlS1rqX5Q/pub?output=csv'; // open file for reading if (($handle = fopen($url, "r")) !== FALSE) { while (($data = fge ...