Canvas gets a contact position on the mobile network

I have a code that drags a line from the coordinate (x, y) to the new mouse coordinate (x, y). This works great in desktop browsers, but for some reason it doesn't work in mobile browsers. I have added event message listeners, but I think that the coordinates are some of them as incorrect. Here is my code:

function getMouse(e) { var element = canvas, offsetX = 0, offsetY = 0; if (element.offsetParent) { do { offsetX += element.offsetLeft; offsetY += element.offsetTop; } while ((element = element.offsetParent)); } mx = (e.pageX - offsetX) - LINE_WIDTH; my =( e.pageY - offsetY )- LINE_WIDTH; } function mouseDown(e){ getMouse(e); clear(fctx); var l = lines.length; for (var i = l-1; i >= 0; i--) { draw(fctx,lines[i]); var imageData = fctx.getImageData(mx, my, 1, 1); if (imageData.data[3] > 0) { selectedObject = lines[i]; isDrag = true; canvas.onmousemove = drag; clear(fctx); } } } function mouseUp(){ isDrag = false; } canvas.onmousedown = mouseDown; canvas.onmouseup = mouseUp; canvas.addEventListener('touchstart', mouseDown, false); canvas.addEventListener('touchend', mouseUp, false); 

you can see the working part here: http://codepen.io/nirajmchauhan/pen/yYdMJR

+6
source share
1 answer

Mouse event generation from touch events

OK, I saw this question here for a while, and no one comes up with the answer that I will give him.

Touching events, unlike mouse events, is associated with many points of contact with the user interface. To satisfy this, sensory events provide many sensory points. Since the mouse cannot be in two places at the same time, the two interaction methods really should be handled separately for a better user experience. OP, since you are not asking about detecting the touch of a device or mouse, I left this for another person to ask.

Handling both

Mouse and touch events can coexist. Adding listeners to mouse or touch events on a device that does not have one or the other is not a problem. The missing input interface simply does not generate any events. This simplifies the implementation of a transparent solution for your page.

It depends on which interface you prefer and emulate that interface when the hardware is not available for it. In this case, I will emulate a mouse from any generated touch events.

Creating events programmatically.

The code uses the MouseEvent object to create and dispatch events. It is easy to use, and events are indistinguishable from real mouse events. Detailed Description MouseEvents goto MDN MouseEvent

In the most basic.

Create a mouse click event and send it to the document

  var event = new MouseEvent( "click", {'view': window, 'bubbles': true,'cancelable': true}); document.dispatchEvent(event); 

You can also send an event to individual items.

  document.getElementById("someButton").dispatchEvent(event); 

To listen to an event is exactly the same as listening to an actual mouse.

  document.getElementById("someButton").addEventListener(function(event){ // your code )); 

The second argument to the MouseEvent function is where you can add additional information about the event. Say, for example, clientX and clientY the mouse positions or which or buttons for which the / s button is pressed.

If you have ever looked at MouseEvent , you will find out that there are many properties. Thus, exactly what you send in the mouse event will depend on what your event listener is using.

Touch events.

Touching events is like a mouse. There is touchstart , touchmove and touchend . They differ in that they provide multiple locations, one element for each contact point. Not sure what max is, but for this answer we are only interested in one. See MDN touchEvent for details .

What we need to do is for sensory events in which only one contact point is involved, which we want to generate the corresponding mouse events in one place. If a touch event returns more than one contact point, we cannot know which one the focus is on, so we will simply ignore them.

 function touchEventHandler(event){ if (event.touches.length > 1){ // Ignor multi touch events return; } } 

So, now we know that the touch of one contact we can do about creating mouse events based on information in touch events.

In the most basic

 touch = event.changedTouches[0]; // get the position information if(type === "touchmove"){ mouseEventType = "mousemove"; // get the name of the mouse event // this touch will emulate }else if(type === "touchstart"){ mouseEventType = "mousedown"; // mouse event to create }else if(type === "touchend"){ mouseEventType = "mouseup"; // ignore mouse up if click only } var mouseEvent = new MouseEvent( // create event mouseEventType, // type of event { 'view': event.target.ownerDocument.defaultView, 'bubbles': true, 'cancelable': true, 'screenX':touch.screenX, // get the touch coords 'screenY':touch.screenY, // and add them to the 'clientX':touch.clientX, // mouse event 'clientY':touch.clientY, }); // send it to the same target as the touch event contact point. touch.target.dispatchEvent(mouseEvent); 

Now your mice will receive mousedown , mousemove , mouseup events when the user touches the device in only one place.

Missing click

Everything is still fine, but there is one mouse event that is not needed, and it is necessary. "onClick" I am not sure that there is an equilibrio touch event, and just like the exercise that I saw, there is enough information in that we have to decide whether it is possible to read a set of sensory events with one click.

This will depend on how far apart the initial and final touch events, more than a few pixels and its drag and drop are. It will also depend on how long. (Although this is not the same as a mouse), I find that people usually click on a button, while the mouse can be held, instead of conformation in the release, or pushed to cancel, this is not how people use the touch interface.

So, I am recording the time when the touchStart event occurs. event.timeStamp and where it started. Then, in the touchend event touchend I find the distance that he has moved, and the time since. If both of them are under the limits that I set, I will also generate a mouse click event along with the mouse event.

So, this is the basic way to convert touch events to mouse events.

Some CODES

Below is a tiny API called mouseTouch that does what I just explained. It covers the most basic mouse interactions required in a simple graphical application.

 // _______ _ // |__ __| | | // _ __ ___ ___ _ _ ___ ___| | ___ _ _ ___| |__ // | '_ ` _ \ / _ \| | | / __|/ _ \ |/ _ \| | | |/ __| '_ \ // | | | | | | (_) | |_| \__ \ __/ | (_) | |_| | (__| | | | // |_| |_| |_|\___/ \__,_|___/\___|_|\___/ \__,_|\___|_| |_| // // // Demonstration of a simple mouse emulation API using touch events. // Using touch to simulate a mouse. // Keeping it clean with touchMouse the only pubic reference. // See Usage instructions at bottom. var touchMouse = (function(){ "use strict"; var timeStart, touchStart, mouseTouch, listeningElement, hypot; mouseTouch = {}; // the public object // public properties. mouseTouch.clickRadius = 3; // if touch start and end within 3 pixels then may be a click mouseTouch.clickTime = 200; // if touch start and end in under this time in ms then may be a click mouseTouch.generateClick = true; // if true simulates onClick event // if false only generate mousedown, mousemove, and mouseup mouseTouch.clickOnly = false; // if true on generate click events mouseTouch.status = "Started."; // just for debugging // ES6 new math function // not sure the extent of support for Math.hypot so hav simple poly fill if(typeof Math.hypot === 'function'){ hypot = Math.hypot; }else{ hypot = function(x,y){ // Untested return Math.sqrt(Math.pow(x,2)+Math.pow(y,2)); }; } // Use the new API and MouseEvent object function triggerMouseEvemt(type,fromTouch,fromEvent){ var mouseEvent = new MouseEvent( type, { 'view': fromEvent.target.ownerDocument.defaultView, 'bubbles': true, 'cancelable': true, 'screenX':fromTouch.screenX, 'screenY':fromTouch.screenY, 'clientX':fromTouch.clientX, 'clientY':fromTouch.clientY, 'offsetX':fromTouch.clientX, // this is for old Chrome 'offsetY':fromTouch.clientY, 'ctrlKey':fromEvent.ctrlKey, 'altKey':fromEvent.altKey, 'shiftKey':fromEvent.shiftKey, 'metaKey':fromEvent.metaKey, 'button':0, 'buttons':1, }); // to do. // dispatch returns cancelled you will have to // add code here if needed fromTouch.target.dispatchEvent(mouseEvent); } // touch listener. Listens to Touch start, move and end. // dispatches mouse events as needed. Also sends a click event // if click falls within supplied thresholds and conditions function emulateMouse(event) { var type, time, touch, isClick, mouseEventType, x, y, dx, dy, dist; event.preventDefault(); // stop any default happenings interfering type = event.type ; // the type. // ignore multi touch input if (event.touches.length > 1){ if(touchStart !== undefined){ // don't leave the mouse down triggerMouseEvent("mouseup",event.changedTouches[0],event); } touchStart = undefined; return; } mouseEventType = ""; isClick = false; // default no click // check for each event type I have the most numorus move event first, Good practice to always think about the efficancy for conditional coding. if(type === "touchmove" && !mouseTouch.clickOnly){ // touchMove touch = event.changedTouches[0]; mouseEventType = "mousemove"; // not much to do just move the mouse }else if(type === "touchstart"){ touch = touchStart = event.changedTouches[0]; // save the touch start for dist check timeStart = event.timeStamp; // save the start time mouseEventType = !mouseTouch.clickOnly?"mousedown":""; // mouse event to create }else if(type === "touchend"){ // end check time and distance touch = event.changedTouches[0]; mouseEventType = !mouseTouch.clickOnly?"mouseup":""; // ignore mouse up if click only // if click generator active if(touchStart !== undefined && mouseTouch.generateClick){ time = event.timeStamp - timeStart; // how long since touch start // if time is right if(time < mouseTouch.clickTime){ // get the distance from the start touch dx = touchStart.clientX-touch.clientX; dy = touchStart.clientY-touch.clientY; dist = hypot(dx,dy); if(dist < mouseTouch.clickRadius){ isClick = true; } } } } // send mouse basic events if any if(mouseEventType !== ""){ // send the event triggerMouseEvent(mouseEventType,touch,event); } // if a click also generates a mouse click event if(isClick){ // generate mouse click triggerMouseEvent("click",touch,event); } } // remove events function removeTouchEvents(){ listeningElement.removeEventListener("touchstart", emulateMouse); listeningElement.removeEventListener("touchend", emulateMouse); listeningElement.removeEventListener("touchmove", emulateMouse); listeningElement = undefined; } // start adds listeners and makes it all happen. // element is optional and will default to document. // or will Listen to element. function startTouchEvents(element){ if(listeningElement !== undefined){ // untested // throws to stop cut and past useage of this example code. // Overwriting the listeningElement can result in a memory leak. // You can remove this condition block and it will work // BUT IT IS NOT RECOGMENDED throw new ReferanceError("touchMouse says!!!! API limits functionality to one element."); } if(element === undefined){ element = document; } listeningElement = element; listeningElement.addEventListener("touchstart", emulateMouse); listeningElement.addEventListener("touchend", emulateMouse); listeningElement.addEventListener("touchmove", emulateMouse); } // add the start event to public object. mouseTouch.start = startTouchEvents; // stops event listeners and remove them from the DOM mouseTouch.stop = removeTouchEvents; return mouseTouch; })(); // How to use touchMouse.start(); // done using defaults will emulate mouse on the entier page // For one element and only clicks // HTML <input value="touch click me" id="touchButton" type="button"></input> // Script var el = document.getElementById("touchButton"); if(el !== null){ touchMouse.clickOnly = true; touchMouse.start(el); } // For drawing on a canvas <canvas id="touchCanvas"></canvas> // script var el = document.getElementById("touchButton"); if(el !== null){ touchMouse.generateClick = false; // no mouse clicks please touchMouse.start(el); } // For switching elements call stop then call start on the new element // warning touchMouse retained a reference to the element you // pass it with start. Dereferencing touchMouse will not delete it. // Once you have called start you must call stop in order to delete it. // API //--------------------------------------------------------------- // To dereference call the stop method if you have called start . Then dereference touchMouse // Example touchMouse.stop(); touchMouse = undefined; // Methods. //--------------------------------------------------------------- // touchMouse.start(element); // element optional. Element is the element to attach listeners to. // Calling start a second time without calling stop will // throw a reference error. This is to stop memory leaks. // YOU Have been warned... // touchMouse.stop(); // removes listeners and dereferences any DOM objects held //--------------------------------------------------------------- // Properties // mouseTouch.clickRadius = 3; // Number. Default 3. If touch start and end within 3 pixels then may be a click // mouseTouch.clickTime = 200; // Number. Default 200. If touch start and end in under this time in ms then may be a click // mouseTouch.generateClick; // Boolean. Default true. If true simulates onClick event // // if false only generate mousedown, mousemove, and mouseup // mouseTouch.clickOnly; // Boolean. Default false. If true only generate click events Default false // mouseTouch.status; // String. Just for debugging kinda pointless really. 

So hope that helps you with your code.

+3
source

All Articles