Нужна помощь с несложной рисовалкой в 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 но как ни старался там что-то менять, у меня ничего не получилось. Подскажите что поправить? Заранее благодарю! |
После 15-й строки добавьте это:
el.width = el.offsetWidth; el.height = el.offsetHeight; |
Nexus,
Спасибо! Работает как надо, но появилась вторая проблема - если что то нарисовать, а потом кликнуть в canvas, то все что нарисовал ранее стирается. Попробовал эти строчки добавить во все функции, но тогда вообще ничего не работает. |
Цитата:
Нет у меня 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 то есть)) |
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 я не трогал. |
Изменил код по ссылке, привязал ресайз холста к событию resize окна, и добавил функцию throttle, чтобы ресайз происходил не чаще 10 раз в секунду.
Реализацию функции throttle взял отсюда: https://learn.javascript.ru/task/throttle |
А вообще, реализацию нужного для вас скрипта можете поискать на этом форуме. Сверху справа есть ссылка "поиск", нажмите на нее и ищите слово "рисовалка".
Не смог отредактировать прошлое сообщение, поэтому создал новое. |
Nexus,
возможно "потерялась" https: в ссылке на редактирование, добавить вручную. |
Часовой пояс GMT +3, время: 22:01. |