Turn off scrolling and zooming when drawing on image with touch screen (ie: phones and tablets)

thenelson
thenelson used Ask the Experts™
on
Turn off scrolling and zooming when drawing on image with touch screen (ie: phones and tablets)

I have a webpage designed for the user to draw on an image. When the user moves their finger across the image on a touch screen, especially when zoomed in, the page scrolls instead of drawing on the image.  How do I turn off scrolling and zooming when the user draws on the image?

Here is a link to the webpage modified so it doesn't send data to me: www.barnwellmd.com/PainDiagram/Testdrawing.html.

Here is the code:
/* © 2009 ROBO Design
 * http://www.robodesign.ro
 */

var imageData, context, pixels;

function clearCanvas()
{
	context.putImageData(imageData, 0, 0);
}

function checkFields()
{
	var themessage = "Please complete the following fields:";
	if (document.form.ptname.value=="") 
		{
		themessage = themessage + "\n     Patient's Name";
		}
	if (document.form.dob.value=="") 
		{
		themessage = themessage + "\n     Birthdate";
		}
	//alert if fields are empty and cancel form submit
	if (themessage != "Please complete the following fields:") 
		{
			alert(themessage);
			return true;
		}
		else
		{
			return checkdate(document.form.dob.value);
		}
}
function checkdate(input)
{
	
	var validformat=/^\d{2}\/\d{2}\/\d{4}$/ //Basic check for format validity
	var returnval=true
	if (!validformat.test(input))
		alert("Invalid Date Format. Format: (mm/dd/yyyy) \nPlease correct and submit again.")
	else
	{ //Detailed check for valid date ranges
		var monthfield=input.split("/")[0]
		var dayfield=input.split("/")[1]
		var yearfield=input.split("/")[2]
		var dayobj = new Date(yearfield, monthfield-1, dayfield)
		if ((dayobj.getMonth()+1!=monthfield)||(dayobj.getDate()!=dayfield)||(dayobj.getFullYear()!=yearfield))
			alert("Invalid Day, Month, or Year range detected. \nPlease correct and submit again.")
		else
			returnval=false
	}
	if (returnval==true) input.select()
	return returnval
}

function saveCanvas() 
{
	if (checkFields()) return;
	clearGray();
	createPrint();
	var testCanvas = document.getElementById("imageView");  
	var img = testCanvas.toDataURL("image/png");
	newwindow = window.open()
	newwindow.document.write('<img src="' + img + '"/>');
	newwindow.document.close();
	newwindow.focus();
	newwindow.alert("You can now use your browser's print function to print the image\nor right click on the image and select \"save image as\" to save it.\n\nClose this window to return to the previous window.");
}
		
function sendCanvas()
{
	if (checkFields()) return;
	clearGray();
	createPrint();
	var testCanvas = document.getElementById("imageView");  
	var canvasData = testCanvas.toDataURL("image/png");
	//alert(canvasData);
	var ajax = new XMLHttpRequest();
	//alert ('https://www.barnwellmd.com/Uploadroutines/uploadbase64.php?name=' + document.form.ptname.value.replace(/ /g,"_"));
	ajax.open("POST",'https://www.barnwellmd.com/Uploadroutines/uploadbase64.php?name=' + document.form.ptname.value.replace(/ /g,"_"),false);
	//ajax.open("POST",'https://www.barnwellmd.com/Uploadroutines/uploadbase64.php',true);    
	ajax.setRequestHeader('Content-Type', 'canvas/upload');
	//ajax.setRequestHeader('Content-Type', 'application/upload');
	ajax.onreadystatechange=function()
	{
		if (ajax.readyState == 4)
		{
			alert(ajax.responseText);
			// Write out the filename.
			//document.getElementById("debugFilenameConsole").innerHTML="Saved as<br><a target='_blank' href='"+ajax.responseText+"'>"+ajax.responseText+"</a><br>Reload this page to generate new image or click the filename to open the image file.";
		}
	}
	ajax.send(canvasData);
}

function createPrint()
{
	context.font="25px Arial";
	context.fillStyle  = "black";
	context.fillText(document.form.ptname.value + " DOB: " + document.form.dob.value,10,640);
	context.fillText("Legend:",275,425);
	context.font="bold 25px Arial";
	context.fillStyle  = "#FF0000";
	context.fillText("Burning",275,450);
	context.fillStyle  = "#FFFF00";
	context.fillText("Aching",275,475);
	context.fillStyle  = "#8080FF";
	context.fillText("Numbness",275,500);
	context.fillStyle  = "#B26B00";
	context.fillText("Pins & needles",275,525);
	context.fillStyle  = "#FF00FF";
	context.fillText("Stabbing",275,550);
	context.fillStyle  = "#59B200";
	context.fillText("Shooting pain",275,575);
	context.fillStyle  = "#FF7F50";
	context.fillText("Referred pain",275,600);
}

function clearGray()
{
	var imageData2 = context.getImageData(0, 0, 700, 643);
	var newPixels = imageData2.data;
	for (var i = 0, il = pixels.length; i < il; i += 4) 
	{
		if((pixels[i] == 255 && pixels[i+1] == 204 && pixels[i+2] == 153) 
		|| (newPixels[i] > 235 && newPixels[i+1] < 150 && newPixels[i+2] > 75 && newPixels[i+2] < 110))
		{
		}
		else
		{
		   newPixels[i] = pixels[i];
		   newPixels[i+1] = pixels[i+1];
		   newPixels[i+2] = pixels[i+2];
		}
	}
	context.putImageData(imageData2, 0, 0);
	context.fillStyle  = "#CDCDCD";
	context.fillText("Referred pain",275,600);
}

// Keep everything in anonymous function, called on window load.
if(window.addEventListener) {
window.addEventListener('load', function () {
	var canvas, tool;
	var lastX, lastY, prevX, prevY, segCount, reptSeg;


function init () {
	// Find the canvas element.
	canvas = document.getElementById('imageView');
	if (!canvas) {
		alert('Error: I cannot find the canvas element!');
		return;
	}

	if (!canvas.getContext) {
		alert('Error: no canvas.getContext!');
		return;
	}

	// Get the 2D canvas context.
	context = canvas.getContext('2d');
	if (!context) {
		alert('Error: failed to getContext!');
		return;
	}
	
	var img=new Image();
	img.onload = function(){
		setTimeout( function(){ 
			context.drawImage(img,0,0);
			imageData = context.getImageData(0, 0, 700, 643);
			pixels = imageData.data;
		},0);
	};
	img.src="PainDiagram.png";


	// Pencil tool instance.
	tool = new tool_pencil();

	// Attach the mousedown, mousemove and mouseup event listeners.
	canvas.addEventListener('mousedown', ev_canvas, false);
	canvas.addEventListener('mousemove', ev_canvas, false);
	canvas.addEventListener('mouseup', ev_canvas, false);
	// Attach the touchstart, touchmove and touchend event listeners.
	canvas.addEventListener('touchstart', ev_canvas, false);
	canvas.addEventListener('touchmove', ev_canvas, false);
	canvas.addEventListener('touchend', ev_canvas, false);
	canvas.addEventListener('touchcancel', ev_canvas, false);
	canvas.addEventListener('touchend', clearGray, false); 
}

	// This painting tool works like a drawing pencil which tracks the mouse 
	// movements.
	function tool_pencil () {
	var tool = this;
	this.started = false;


	// This is called when you start holding down the mouse button.
	// This starts the pencil drawing.
	this.mousedown = this.touchstart = function (ev) {
			context.lineCap = "round";
			context.strokeStyle = color_value;
			lastX = ev._x;
			lastY = ev._y;
			prevX = ev._x;
			prevY = ev._y;
			segCount = 0;
			if (color_value == "#FF7F50")	 //referred pain
			{
				context.lineWidth = 2;
				reptSeg = 7;
			}
			else
			{
				context.lineWidth = 10;
				reptSeg = 1;
			}
	
	    context.beginPath();
//        context.moveTo(ev._x, ev._y);
		tool.started = true;
	};

	// This function is called every time you move the mouse. Obviously, it only 
	// draws if the tool.started state is set to true (when you are holding down 
	// the mouse button).
	this.mousemove = this.touchmove = function (ev) {
		if (tool.started) {
			if(!segCount)
			{
				prevX = lastX;
				prevY = lastY;
				lastX = ev._x;
				lastY = ev._y;
				segCount = reptSeg;
				context.lineTo(ev._x, ev._y);
				context.stroke();
			}
			segCount--;
		}
    };

	// This is called when you release the mouse button.
	this.mouseup = this.touchend = this.touchcancel = function (ev) {
		if (tool.started) 
		{
			if (color_value == "#FF7F50")
			{
				var angle = Math.atan2(lastY-prevY,lastX-prevX);
		  		context.beginPath();
				context.moveTo(lastX+15*Math.cos(angle),lastY+15*Math.sin(angle));
				context.lineTo(lastX-7*Math.cos(angle-Math.PI/4),lastY-7*Math.sin(angle-Math.PI/4));
		  		context.lineTo(lastX-7*Math.cos(angle+Math.PI/4),lastY-7*Math.sin(angle+Math.PI/4)); 
				context.closePath();
				context.fillStyle  = color_value;
				context.fill();
			}
			tool.started = false;
			tool.mousemove(ev);
			tool.touchmove(ev);
			clearGray();
			//document.form.output.value = document.form.output.value + " x= " + ev._x + ",  y= " + ev._y + "\nLX= " + lastX + ", LY= " + lastY +  "\npX= " + prevX + ", pY= " + prevY + "\nsegCount= " + segCount + "\n\n";
		}
    };
  }

	// The general-purpose event handler. This function just determines the mouse 
	// position relative to the canvas element.
  

 
	function ev_canvas (ev) {
		if (ev.offsetX || ev.offsetX == 0) { // Opera and WebKit
		ev._x = ev.offsetX;
		ev._y = ev.offsetY;
		} 
		else if (ev.layerX || ev.layerX == 0) { // Firefox
			ev._x = ev.layerX;
			ev._y = ev.layerY;
		} 
		if( ev.targetTouches ) {
			var rect = ev.target.getBoundingClientRect();
			
			ev._x = ev.targetTouches[0].pageX - rect.left;
			ev._y = ev.targetTouches[0].pageY - rect.top;
		}
		// Call the event handler of the tool.
		var func = tool[ev.type];
		if (func) {
			func(ev);
		}
	}

window.onload = init();

}, false); }


// vim:set spell spl=en fo=wan1croql tw=80 ts=2 sw=2 sts=2 sta et ai cin fenc=utf-8 ff=unix:

Open in new window

Comment
Watch Question

Do more with

Expert Office
EXPERT OFFICE® is a registered trademark of EXPERTS EXCHANGE®
leakim971Multitechnician
Top Expert 2014

Commented:
Just after line 224 add :
// disable scrolling 
document.body.style.overflowX = "hidden";
document.body.style.overflowY = "hidden";

Open in new window

and after line 261:
// enable scrolling 
document.body.style.overflowX = "";
document.body.style.overflowY = "";

Open in new window

leakim971,

Adding those lines did not work.
I am guessing that:
     this.mousedown = this.touchstart = function (ev) {
and
     this.mouseup = this.touchend = this.touchcancel = function (ev) {
are not firing  with touchstart and touchend because other items in the function are not running and you suggested adding:
     canvas.addEventListener('touchend',   clearGray, false);
to get clearGrey to run.
I tried changing to:
	// This is called when you release the mouse button.
	this.mouseup = this.touchend = this.touchcancel = function (ev) {
		ftoucnend()
	}
	
	function ftoucnend(){
		if (tool.started) 
		{
			if (color_value == "#FF7F50")
			{
				var angle = Math.atan2(lastY-prevY,lastX-prevX);
		  		context.beginPath();
				context.moveTo(lastX+15*Math.cos(angle),lastY+15*Math.sin(angle));
				context.lineTo(lastX-7*Math.cos(angle-Math.PI/4),lastY-7*Math.sin(angle-Math.PI/4));
		  		context.lineTo(lastX-7*Math.cos(angle+Math.PI/4),lastY-7*Math.sin(angle+Math.PI/4)); 
				context.closePath();
				context.fillStyle  = color_value;
				context.fill();
			}
			tool.started = false;
			
			// enable scrolling 
			document.body.style.overflowX = "";
			document.body.style.overflowY = "";
			
			tool.mousemove(ev);
			tool.touchmove(ev);
			clearGray();
			//document.form.output.value = document.form.output.value + " x= " + ev._x + ",  y= " + ev._y + "\nLX= " + lastX + ", LY= " + lastY +  "\npX= " + prevX + ", pY= " + prevY + "\nsegCount= " + segCount + "\n\n";
		}
    };
  }

Open in new window

and changing:
     canvas.addEventListener('touchend',   clearGray, false);
to:
     canvas.addEventListener('touchend', ftoucnend, false);
but that did not work.
Starting with Angular 5

Learn the essential features and functions of the popular JavaScript framework for building mobile, desktop and web applications.

If I use two fingers on the canvas,
     this.mouseup = this.touchend = this.touchcancel = function (ev) {
does fire.  But with one finger, it does not fire.
leakim971Multitechnician
Top Expert 2014

Commented:
I don't follow you :(

so let's forget :  canvas.addEventListener('touchend',   clearGray, false);
and let's forget : pinch alias two fingers on screen

let's focus just on theses line :
document.body.style.overflowX = "hidden";
document.body.style.overflowY = "hidden";

Open in new window

just after (or before) this line :
tool.started = true;

Open in new window


please confirm it remove the scrolling, don't put the line putting the scroll back yet ?
otherwise use the following (check this new last line) :
document.body.style.overflowX = "hidden";
document.body.style.overflowY = "hidden";
document.body.style.position = "relative";

Open in new window

I've confirmed that:
     this.mousedown = this.touchstart = function (ev) {
does not fire on touchstart so putting anything just before or after:
     tool.started = true;
will do nothing.

So we need to fix
     this.mousedown = this.touchstart = function (ev) {
not firing first.
I got it.

I figured out that touchstart and touchmove were firing but touchend was not firing so to fix that, I replaced
this.mouseup = this.touchend = this.touchcancel = function (ev) {

Open in new window

with
			canvas.addEventListener('touchend', function(ev) {
				if (tool.started) 
				{
					if (color_value == "#FF7F50")
					{
						var angle = Math.atan2(lastY-prevY,lastX-prevX);
						context.beginPath();
						context.moveTo(lastX+15*Math.cos(angle),lastY+15*Math.sin(angle));
						context.lineTo(lastX-7*Math.cos(angle-Math.PI/4),lastY-7*Math.sin(angle-Math.PI/4));
						context.lineTo(lastX-7*Math.cos(angle+Math.PI/4),lastY-7*Math.sin(angle+Math.PI/4)); 
						context.closePath();
						context.fillStyle  = color_value;
						context.fill();
					}

					tool.started = false;
						
					tool.mousemove(ev);
					tool.touchmove(ev);

					clearGray();
				
			}, false); 

Open in new window

To stop the scrolling, I added:
if (ev.target == canvas) {
	ev.preventDefault();
}

Open in new window

to the touchstart and touchmove events.

Thanks for your help!

Do more with

Expert Office
Submit tech questions to Ask the Experts™ at any time to receive solutions, advice, and new ideas from leading industry professionals.

Start 7-Day Free Trial