Рисуем круг, движущийся вслед за курсором мыши

Сегодня мы при помощи canvas JavaScript нарисуем круг, который будет двигаться вслед за курсором мыши.

Основной подход

Прежде чем мы перейдем к коду, поговорим о том, как мы создадим круг, следующий за курсором мыши. Но сначала нам необходимо нарисовать эту окружность:

Рисуем круг, движущийся вслед за курсором мыши Надпись на картинке: Круг нарисован без соблюдения масштаба.

Положение круга будет меняться в зависимости от того, где находится курсор мыши. Это означает, что при каждом изменении положения курсора мыши нам необходимо перерисовывать круг:

Рисуем круг, движущийся вслед за курсором мыши Этот пример не такой уж сложный, чтобы разобраться в нем. Но это не значит, что нет ничего интересного “за кулисами”. Далее при рассмотрении JavaScript мы коснемся некоторых важных аспектов приведенного кода, которые вы, возможно, не поняли.

С чего начать работу?

Первое, что нам необходимо — это страница, готовая к работе с canvas JavaScript. Если у вас ещё нет ее, то поместите следующий программный код в пустую HTML-страницу:

<!DOCTYPE html><html> <head> <title>Canvas Follow Mouse</title> <style> canvas { border: #333 10px solid; } body { padding: 50px; } </style></head> <body>  <canvas id="myCanvas" width="550px" height="350px"></canvas>   <script>    var canvas = document.querySelector("#myCanvas");    var context = canvas.getContext("2d");  </script> </body> </html>

Есть canvas JavaScript, который имеет в себя идентификатор id со значением «myCanvas». Для экономии времен, я предоставил вам две строки кода, необходимых для доступа к элементу canvas и его контексту рендеринга. Если все это для вас ново, уделите пару минут и прочитайте статью «С чего начать работу с элементом Canvas».

Рисуем круг

Первое, что мы собираемся сделать, это нарисовать круг. Внутри тега <script> добавьте следующий код после строки с переменной context:

function update() {  context.beginPath();  context.arc(100, 100, 50, 0, 2 * Math.PI, true);  context.fillStyle = "#FF6A6A";  context.fill();}update();

Приведенный выше скрипт определяет возможность update, которая включает программный код для прорисовки круга. Обратите внимание, что мы не только определяем возможность update, но и вызываем ее. Если вы посмотрите страницу в браузере, то увидите следующее:

Рисуем круг, движущийся вслед за курсором мыши
Наш круг имеет в себя радиус 50 пикселей и расположен в точке(100, 100). На данный момент, мы собираемся сохранить позицию круга фиксированной. Это не надолго, до тех пор пока мы не получим позицию курсора мыши в canvas при помощи способов JavaScript!

Получение позиции курсора мыши

Дальше нас ждет волшебство. Мы собираемся добавить код, работающий с мышью. Он состоит из двух частей. Первая часть отслеживает перемещение курсора мыши на холсте и сохраняет эту позицию. Вторая часть кода гарантирует, что позиция мыши учитывает позицию элемента canvas. В следующих двух разделах мы разберемся с обеими частями кода.

Прослушивание события мыши

Давайте посмотрим на код для первой части. Добавьте следующий код чуть выше возможности update:

var mouseX = 0;var mouseY = 0;canvas.addEventListener("mousemove", setMousePosition, false);function setMousePosition(e) {  mouseX = e.clientX;  mouseY = e.clientY;}

Этот код выполняет довольно простые вещи. Мы отслеживаем событие MouseMove на холсте. И когда это событие наступает, мы вызываем обработчик события setMousePosition:

function setMousePosition(e) {  mouseX = e.clientX;  mouseY = e.clientY;}

Функцию setMousePosition присваивает текущее горизонтальное и вертикальное положение курсора мыши свойствам mouseX и mouseY. Она делает это, опираясь на свойства clientX и clientY, предоставляемые MouseEvent.

Получение точных координат курсора мыши

Позиция курсора мыши, сохраненная в свойствах mouseX и mouseY, по умолчанию включает координаты, заданные относительно левого верхнего угла окна браузера. Значения координат курсора мыши, которые мы имеем теперь, неточные, поскольку не учитывает положение элемента canvas JavaScript.

Чтобы исправить это, у нас есть функцию GetPosition:

function getPosition(el) {  var xPosition = 0;  var yPosition = 0;  while(el) {    xPosition +=(el.offsetLeft - el.scrollLeft + el.clientLeft);    yPosition +=(el.offsetTop - el.scrollTop + el.clientTop);    el = el.offsetParent;  }  return {    x: xPosition,    y: yPosition  };}

Добавьте эту возможность в нижнюю часть кода, ниже возможности update.

Эта функцию применяется для передачи интересующей нас позиции в элемент. Далее она возвращает объект, содержащий координаты х и у. Мы воспользуемся данной функцией, чтобы выяснить, где на странице находится элемент canvas JavaScript, а далее скорректируем значения mouseX и mouseY.

Чтобы использовать возможность GetPosition и исправить значения mouseX и mouseY, внесите следующие дополнения и изменения, которые я выделил:

var canvasPos = getPosition(canvas);var mouseX = 0;var mouseY = 0;canvas.addEventListener("mousemove", setMousePosition, false);function setMousePosition(e) {  mouseX = e.clientX - canvasPos.x;  mouseY = e.clientY - canvasPos.y;}

Сейчас переменная CanvasPos хранит позицию, которую возвращает функцию GetPosition. В обработчике событий setMousePosition мы используем значения х и у, возвращенные из canvasPos для коррекции значения, сохраненного при помощи переменных mouseX и mouseY.

Перемещение круга

В предыдущем разделе мы получили код курсора мыши и переменные mouseX и mouseY, хранящие текущее положение курсора мыши на холсте. Остается только подключить данные значения к нашему коду прорисовки круга внутри возможности update, чтобы приобрести положение круга, отражающее позицию курсора мыши для рисования на canvas JavaScript.

Для начала преобразуем возможность update в объект обратного вызова requestAnimationFrame . Благодаря данному функцию синхронизируется со скоростью рисования браузера (около 60 раз в секунду). Добавьте следующую выделенную строку в нижней части возможности update :

function update() {  context.beginPath();  context.arc(100, 100, 50, 0, 2 * Math.PI, true);  context.fillStyle = "#FF6A6A";  context.fill();  requestAnimationFrame(update);}update();

Сейчас нам необходимо обновить код прорисовки круга, чтобы использовать значения mouseX и mouseY вместо фиксированной позиции (100, 100), которую мы определили первоначально. Внесите в выделенную строку следующие изменения:

function update() {  context.beginPath();  context.arc(mouseX, mouseY, 50, 0, 2 * Math.PI, true);  context.fillStyle = "#FF6A6A";  context.fill();  requestAnimationFrame(update);}update();

После этого сохраните HTML-документ и посмотрите его в браузере. Посмотрите, что происходит при перемещении мыши по canvas JavaScript . Сейчас наш круг повсюду будет следовать за курсором мыши:

Рисуем круг, движущийся вслед за курсором мыши
Круг двигается вслед за движением мыши, но более ранние позиции круга не стираются. Это создает эффект рисования пальцем — не совсем то, чего мы добивались. Для решения данной проблемы перед прорисовкой круга на новом месте надо очистить весь холст.

Чтобы сделать это, добавьте следующую выделенную строку кода в возможность update :

unction update() {  context.clearRect(0, 0, canvas.width, canvas.height);  context.beginPath();  context.arc(mouseX, mouseY, 50, 0, 2 * Math.PI, true);  context.fillStyle = "#FF6A6A";  context.fill();  requestAnimationFrame(update);}

Строка, которую мы добавили, включает вызов способа clearRect , который отвечает за очистку всех пикселей холста. Для его применения необходимо передать размеры области, которую необходимо очистить:

context.clearRect (0, 0, canvas.width, canvas.height);

Это гарантирует, что круг прорисуется на canvas JavaScript без каких-либо следов ранее нарисованной графики. На данный момент при предварительном просмотре страницы в браузере наш пример должен работать безупречно.

Зачем использовать requestAnimationFrame?

Весь код, связанный с рисунком, находится внутри возможности update , которая циклично выполняет возможность requestAnimationFrame . Никакой анимации здесь нет. Мы просто перемещаем курсор мыши и обновляем позицию круга только, когда курсор перемещается. Учитывая все это, почему не весь код прорисовки присутствует в обработчике события MouseMove ? Это выглядело бы примерно так:

canvas.addEventListener("mousemove", setMousePosition, false);function setMousePosition(e) {  mouseX = e.clientX - canvasPos.x;  mouseY = e.clientY - canvasPos.y;  context.clearRect(0, 0, canvas.width, canvas.height);  context.beginPath();  context.arc(mouseX, mouseY, 50, 0, 2 * Math.PI, true);  context.fillStyle = "#FF6A6A";  context.fill();}

Если вы смогли сделать это изменение (и в полном объеме избавились от возможности update), наш пример все равно будет продолжать работать. Наш пример может работать так же, как requestAnimationFrame .

Причина кроется в помогающем нам браузере, который не делает лишнюю работу и выполняет «правильные» вещи, поскольку наша конечная цель. Когда дело доходит до рисования на canvas JavaScript , мы хотим быть синхронными с браузером в тот момент, когда он готов к прорисовке пикселей.

Событие MouseMove не имеет в себя представления о том, когда браузер готов отобразить что-то на экране, поэтому наш обработчик события будет стараться заставить браузер нарисовать что-то на экране. Единственный метод избежать этого — использовать возможность requestAnimationFrame .

Мы разделили код обновления координат курсора мыши и программный код рисования на экране. Это гарантирует, что когда браузер будет готов, мы нарисуем новый круг. Когда круг будет нарисован, позиция курсора в этот момент будет максимально точна.

Отображение

Все это начиналось, как простой эффект. Сейчас у нас есть круг, который следует за курсором мыши.

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *