 
			
				29.06.2022, 21:36
			
			
			
		  
	 | 
 
	
		
		
		
			
			| 
			
				
				
				 Аспирант 
				
				
				
				
	
 
 
 
			 | 
			  | 
			
				
				
					Регистрация: 18.01.2011 
					
					
					
						Сообщений: 96
					 
					
					
			
		
 
		 
		
			 | 
		 
		 
		
	 | 
 
	| 
	
	
		
		
			
			 
				Нужна помощь с несложной рисовалкой в canvas
			 
			
		
		
		
		Привет! Нашел простенький скрипт, который рисует в canvas мышкой или на сенсорных устройствах пальцем. Но есть проблема - не могу управлять шириной поля canvas. Мне нужно, чтобы оно было адаптивным, занимало всю ширину родителя, бутстраповскую колонку col-12 col-lg-6, но если ему задать ширину 100%, то линии рисунка остают от курсора (или пальца), а если ширина указана 320px - то все четко, линия прямо под курсором, как если карандашом пишешь. Вот кодинг 
var canvas = document.getElementById('canvas');
var startedPainting = false;
canvas.addEventListener("mousedown", handleStart, false);
canvas.addEventListener("mousemove", handleMove, false);
canvas.addEventListener("mouseup", handleEnd, false);
canvas.addEventListener("touchstart", handleStart, false);
canvas.addEventListener("touchmove", handleMove, false);
canvas.addEventListener("touchend", handleEnd, false);
function handleStart(evt) {
    evt.preventDefault();
    startedPainting = true;
    var el = $("#canvas").get(0);
    var ctx = el.getContext("2d");
    ctx.lineWidth = 3;
    var touches = evt.changedTouches;
    if (touches) {
        ctx.moveTo(touches[0].pageX - el.offsetLeft, touches[0].pageY - el.offsetTop);
        for (var i = 0; i < touches.length; i++) {
            ctx.lineTo(touches[i].pageX - el.offsetLeft, touches[i].pageY - el.offsetTop);
        }
    } else {
        ctx.moveTo(evt.pageX - el.offsetLeft, evt.pageY - el.offsetTop);
        ctx.lineTo(evt.pageX - el.offsetLeft, evt.pageY - el.offsetTop);
    }
    ctx.stroke();
}
function handleMove(evt) {
    evt.preventDefault();
    if (startedPainting) {
        var el = $("#canvas").get(0);
        var ctx = el.getContext("2d");
        ctx.lineWidth = 3;
        var touches = evt.changedTouches;
        if (touches) {
            for (var i = 0; i < touches.length; i++) {
                ctx.lineTo(touches[i].pageX - el.offsetLeft, touches[i].pageY - el.offsetTop);
            }
        } else {
            ctx.lineTo(evt.pageX - el.offsetLeft, evt.pageY - el.offsetTop);
        }
        ctx.stroke();
    }
}
function handleEnd(evt) {
    evt.preventDefault();
    startedPainting = false;
    var el = $("#canvas").get(0);
    var ctx = el.getContext("2d");
    ctx.lineWidth = 3;
    var touches = evt.changedTouches;
    if (touches) {
        for (var i = 0; i < touches.length; i++) {
            ctx.lineTo(touches[i].pageX - el.offsetLeft, touches[i].pageY - el.offsetTop);
        }
    } else {
        ctx.lineTo(evt.pageX - el.offsetLeft, evt.pageY - el.offsetTop);
    }
    ctx.stroke();
}
подозреваю, что вся магия отступов кроется в строчках типа этой
 
el.offsetLeft, touches[0].pageY - el.offsetTop
 
но как ни старался там что-то менять, у меня ничего не получилось. 
Подскажите что поправить?  
Заранее благодарю!  
		
	
		
		
		
		
		
		
	
		
			
			
	
			
			
			
			
			
				 
			
			
			
			
			
			
				
			
			
			
		 
		
	
	
	 | 
 
 
	 
		 | 
 
 
	
	
	
		
	
		
		
		
			
			 
			
				29.06.2022, 23:04
			
			
			
		  
	 | 
 
	
		
		
		
			
			| 
			
				
				
				 Профессор 
				
				
				
				
	
 
 
 
			 | 
			  | 
			
				
				
					Регистрация: 04.12.2012 
					
					
					
						Сообщений: 3,841
					 
					
					
			
		
 
		 
		
			 | 
		 
		 
		
	 | 
 
	
	
	
		
		
		
		
		После 15-й строки добавьте это: 
el.width = el.offsetWidth;
el.height = el.offsetHeight;
  
		
	
		
		
		
		
		
		
	
		
		
	
	
	 | 
 
 
	 
		 | 
 
 
	
	
	
		
	
		
		
		
			
			 
			
				30.06.2022, 08:47
			
			
			
		  
	 | 
 
	
		
		
		
			
			| 
			
				
				
				 Аспирант 
				
				
				
				
	
 
 
 
			 | 
			  | 
			
				
				
					Регистрация: 18.01.2011 
					
					
					
						Сообщений: 96
					 
					
					
			
		
 
		 
		
			 | 
		 
		 
		
	 | 
 
	| 
	
	
		
		
		
		
		 Nexus, 
 Спасибо! Работает как надо, но появилась вторая проблема - если что то нарисовать, а потом кликнуть в canvas, то все что нарисовал ранее стирается. Попробовал эти строчки добавить во все функции, но тогда вообще ничего не работает. 
		
	
		
		
		
		
		
		
	
		
		
	
	
	 | 
 
 
	 
		 | 
 
 
	
	
	
		
	
		
		
		
			
			 
			
				30.06.2022, 08:55
			
			
			
		  
	 | 
 
	
		
		
		
			  | 
			
			
				
				
				 Профессор 
				
				
				
				
	
 
 
 
			 | 
			  | 
			
				
				
					Регистрация: 03.02.2020 
					
					
					
						Сообщений: 2,777
					 
					
					
			
		
 
		 
		
			 | 
		 
		 
		
	 | 
 
	
	
	
		
		
		
		
		
	
 
	| 
		
			Сообщение от Volonter
			
		
	 | 
 
	| 
		Привет! Нашел простенький скрипт, который рисует в canvas мышкой или на сенсорных устройствах пальцем.
	 | 
 
	
 
 На моем сенсорном устройстве он пальцем рисовать не будет! 
Нет у меня touchstart, touchmove и прочих таучей 
Но есть pointerevents. Pointerevents есть везде. И на десктопах, и на смартфонах, и на планшетах, и даже на моем ноуте с сенсорным экраном.
 
Вот их и надо использовать. Вместо мышиных событий и таучей.  
		
	
		
		
		
		
		
		
	
		
		
	
	
	 | 
 
 
	 
		 | 
 
 
	
	
	
		
	
		
		
		
			
			 
			
				30.06.2022, 08:58
			
			
			
		  
	 | 
 
	
		
		
		
			
			| 
			
				
				
				 Аспирант 
				
				
				
				
	
 
 
 
			 | 
			  | 
			
				
				
					Регистрация: 18.01.2011 
					
					
					
						Сообщений: 96
					 
					
					
			
		
 
		 
		
			 | 
		 
		 
		
	 | 
 
	
	
	
		
		
		
		
		
	
 
	| 
		
			Сообщение от voraa
			
		
	 | 
 
	| 
		Вот их и надо использовать. Вместо мышиных событий и таучей.
	 | 
 
	
 
 Понял, спасибо за наводку! Попробую!  
		
	
		
		
		
		
		
		
	
		
		
	
	
	 | 
 
 
	 
		 | 
 
 
	
	
	
		
	
		
		
		
			
			 
			
				30.06.2022, 10:49
			
			
			
		  
	 | 
 
	
		
		
		
			
			| 
			
				
				
				 Аспирант 
				
				
				
				
	
 
 
 
			 | 
			  | 
			
				
				
					Регистрация: 18.01.2011 
					
					
					
						Сообщений: 96
					 
					
					
			
		
 
		 
		
			 | 
		 
		 
		
	 | 
 
	
	
	
		
		
		
		
		
	
 
	
		
			Сообщение от voraa
			 
		
	 | 
 
	
		На моем сенсорном устройстве он пальцем рисовать не будет! 
Нет у меня touchstart, touchmove и прочих таучей 
Но есть pointerevents. Pointerevents есть везде. И на десктопах, и на смартфонах, и на планшетах, и даже на моем ноуте с сенсорным экраном. 
 
Вот их и надо использовать. Вместо мышиных событий и таучей.
	 | 
 
	
 
 Попробовал заменить это
 
canvas.addEventListener("mousedown", handleStart, false);
canvas.addEventListener("mousemove", handleMove, false);
canvas.addEventListener("mouseup", handleEnd, false);
canvas.addEventListener("touchstart", handleStart, false);
canvas.addEventListener("touchmove", handleMove, false);
canvas.addEventListener("touchend", handleEnd, false);
на это
 
canvas.addEventListener("pointerdown", handleStart, false);
canvas.addEventListener("pointermove", handleMove, false);
canvas.addEventListener("pointerup", handleEnd, false);
может, что то делаю не так, но как я понял pointerdown заменяет сразу и mousedown, и  touchstart, с другими событиями по аналогии. Но на десктопах работает, на сенсорных нет.  
Да это и не суть, мне больше важнее разобраться с основным вопросом, с шириной canvas то есть))  
		
	
		
		
		
		
		
		
	
		
			
			
	
			
			
			
			
			
				 
			
			
			
			
			
			
				
			
			
			
		 
		
	
	
	 | 
 
 
	 
		 | 
 
 
	
	
	
		
	
		
		
		
			
			 
			
				30.06.2022, 11:34
			
			
			
		  
	 | 
 
	
		
		
		
			
			| 
			
				
				
				 Профессор 
				
				
				
				
	
 
 
 
			 | 
			  | 
			
				
				
					Регистрация: 04.12.2012 
					
					
					
						Сообщений: 3,841
					 
					
					
			
		
 
		 
		
			 | 
		 
		 
		
	 | 
 
	
	
	
		
		
		
		
		Volonter, 
 https://codesandbox.io/s/musing-fog-...=/src/index.js
function resizeCanvas(ctx) {
  var canvas = ctx.canvas;
  var img = ctx.getImageData(0, 0, canvas.width, canvas.height);
  canvas.width = canvas.offsetWidth;
  canvas.height = canvas.offsetHeight;
  ctx.putImageData(img, 0, 0);
}
function handleStart(evt) {
  evt.preventDefault();
  startedPainting = true;
  var el = $("#canvas").get(0);
  var needToResize =
    el.width !== el.offsetWidth || el.height !== el.offsetHeight;
  var ctx = el.getContext("2d");
  if (needToResize) {
    resizeCanvas(ctx);
  }
  ctx.lineWidth = 3;
  var touches = evt.changedTouches;
  if (touches) {
    ctx.moveTo(
      touches[0].pageX - el.offsetLeft,
      touches[0].pageY - el.offsetTop
    );
    for (var i = 0; i < touches.length; i++) {
      ctx.lineTo(
        touches[i].pageX - el.offsetLeft,
        touches[i].pageY - el.offsetTop
      );
    }
  } else {
    ctx.moveTo(evt.pageX - el.offsetLeft, evt.pageY - el.offsetTop);
    ctx.lineTo(evt.pageX - el.offsetLeft, evt.pageY - el.offsetTop);
  }
  ctx.stroke();
}
При изменении свойств размеров холста он очищается. Чтобы избежать потери данных я попытался сохранить всё намалеванное с помощью метода getImagaData до изменений размера и отрисовать эти данные после. 
Получилось, НО при изменении уменьшении ширины холста данные, которые были у правого края будут утеряны. 
 
Как это пофиксить - я не знаю, возможно вам подскажет кто-нибудь другой, либо вы сами решите эту проблему. 
touches я не трогал.  
		
	
		
		
		
		
		
		
	
		
			
			
	
			
			
			
			
			
				 
			
			
			
			
			
			
				
			
			
			
		 
		
	
	
	 | 
 
 
	 
		 | 
 
 
	
	
	
		
	
		
		
		
			
			 
			
				30.06.2022, 11:55
			
			
			
		  
	 | 
 
	
		
		
		
			
			| 
			
				
				
				 Профессор 
				
				
				
				
	
 
 
 
			 | 
			  | 
			
				
				
					Регистрация: 04.12.2012 
					
					
					
						Сообщений: 3,841
					 
					
					
			
		
 
		 
		
			 | 
		 
		 
		
	 | 
 
	
	
	
		
		
		
		
		Изменил код по ссылке, привязал ресайз холста к событию resize окна, и добавил функцию throttle, чтобы ресайз происходил не чаще 10 раз в секунду. 
Реализацию функции throttle взял отсюда:  https://learn.javascript.ru/task/throttle 
		
	
		
		
		
		
		
		
		
						  
				
				Последний раз редактировалось Nexus, 30.06.2022 в 17:41.
				Причина: test
				
			
		
		
	
		
		
	
	
	 | 
 
 
	 
		 | 
 
 
	
	
	
		
	
		
		
		
			
			 
			
				30.06.2022, 12:01
			
			
			
		  
	 | 
 
	
		
		
		
			
			| 
			
				
				
				 Профессор 
				
				
				
				
	
 
 
 
			 | 
			  | 
			
				
				
					Регистрация: 04.12.2012 
					
					
					
						Сообщений: 3,841
					 
					
					
			
		
 
		 
		
			 | 
		 
		 
		
	 | 
 
	| 
	
	
		
		
		
		
		 А вообще, реализацию нужного для вас скрипта можете поискать на этом форуме. Сверху справа есть ссылка "поиск", нажмите на нее и ищите слово "рисовалка". 
 
Не смог отредактировать прошлое сообщение, поэтому создал новое. 
		
	
		
		
		
		
		
		
	
		
		
	
	
	 | 
 
 
	 
		 | 
 
 
	
	
	
		
	
		
		
		
			
			 
			
				30.06.2022, 13:26
			
			
			
		  
	 | 
 
	
		
		
		
			  | 
			
			
				
				
				 Профессор 
				
				
				
				
	
 
 
 
			 | 
			  | 
			
				
				
					Регистрация: 27.05.2010 
					
					
					
						Сообщений: 33,150
					 
					
					
			
		
 
		 
		
			 | 
		 
		 
		
	 | 
 
	| 
	
	
		
		
		
		
		 Nexus, 
 возможно "потерялась"  https: в ссылке на редактирование, добавить вручную. 
		
	
		
		
		
		
		
		
	
		
		
	
	
	 | 
 
 
	 
		 | 
 
 
 
 |  
  |