Реализация Cursor Presence (курсоров пользователей) на сайте

Реализация Cursor Presence (курсоры пользователей) на сайте

Разработка и обслуживание любых видов сайтов:

Информационные сайты или веб-приложения
Сайты визитки, landing page, корпоративные сайты, онлайн каталоги, квиз, промо-сайты, блоги, новостные ресурсы, информационные порталы, форумы, агрегаторы
Сайты или веб-приложения электронной коммерции
Интернет-магазины, B2B-порталы, маркетплейсы, онлайн-обменники, кэшбэк-сайты, биржи, дропшиппинг-платформы, парсеры товаров
Веб-приложения для управления бизнес-процессами
CRM-системы, ERP-системы, корпоративные порталы, системы управления производством, парсеры информации
Сайты или веб-приложения электронных услуг
Доски объявлений, онлайн-школы, онлайн-кинотеатры, конструкторы сайтов, порталы предоставления электронных услуг, видеохостинги, тематические порталы

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

Услуги, которые мы предлагаем
Показано 1 из 1Все 2062 услуг
Реализация Cursor Presence (курсоров пользователей) на сайте
Средний
~3-5 дней

Наши компетенции:

Часто задаваемые вопросы

Последние работы

  • image_website-b2b-advance_0.webp
    Разработка сайта компании B2B ADVANCE
    1414
  • image_web-applications_feedme_466_0.webp
    Разработка веб-приложения для компании FEEDME
    1285
  • image_websites_belfingroup_462_0.webp
    Разработка веб-сайта для компании БЕЛФИНГРУПП
    982
  • image_ecommerce_furnoro_435_0.webp
    Разработка интернет магазина для компании FURNORO
    1241
  • image_crm_enviok_479_0.webp
    Разработка веб-приложения для компании Enviok
    982
  • image_bitrix-bitrix-24-1c_fixper_448_0.webp
    Разработка веб-сайта для компании ФИКСПЕР
    994

Реализация Cursor Presence (курсоры пользователей) на сайте

Представьте: десять редакторов правят один документ, а курсоры других участников дёргаются, исчезают или накладываются друг на друга. Типичная картина в проектах без грамотной реализации. Cursor presence — отображение курсоров и выделений в реальном времени — кажется простой задачей, но подводных камней хватает: эффективная передача координат, плавная анимация, корректный маппинг при скролле и отключении. Без оптимизации трафик может достигать 10 000 сообщений в секунду при 50 пользователях, что критично для мобильных сетей и увеличивает затраты на сервер до 50% (около 5000 руб./мес. на 10 пользователей). Мы — команда с пятилетним опытом в real-time коллаборации — внедрили cursor presence для 30+ проектов (редакторы, доски, чаты). Предлагаем готовое решение под ключ: за 1–2 дня мы встроим присутствие пользователей с оптимизацией трафика и гарантированной плавностью. Свяжитесь с нами, чтобы получить консультацию и демо.

Throttle и его влияние на трафик

Событие mousemove генерирует 50–100 кадров в секунду. Если отправлять каждое на сервер, при 10 пользователях трафик достигает тысяч сообщений в секунду. Оптимальное ограничение — 30 fps (33 мс). Используйте throttle-функцию — например, из lodash-es:

import { throttle } from 'lodash-es'; const sendCursor = throttle((x: number, y: number) => { socket.emit('cursor:move', { x, y }); }, 33); document.addEventListener('mousemove', (e) => { sendCursor(e.clientX, e.clientY); }); document.addEventListener('mouseleave', () => { socket.emit('cursor:leave'); }); 

На сервере (Socket.IO) — broadcast в комнату, исключая отправителя:

socket.on('cursor:move', (data: { x: number; y: number }) => { socket.to(roomId).emit('cursor:update', { userId: socket.data.userId, ...data, }); }); socket.on('cursor:leave', () => { socket.to(roomId).emit('cursor:remove', { userId: socket.data.userId, }); }); socket.on('disconnect', () => { socket.to(roomId).emit('cursor:remove', { userId: socket.data.userId, }); }); 

Экономия трафика при 30 fps вместо 60 составляет до 50% — это критично для мобильных сетей.

Расчёт экономии трафика При 50 сообщениях в секунду на пользователя и 10 пользователях, трафик составляет 500 сообщений/с. Throttle до 30 fps снижает до 300 сообщений/с. Экономия 40% — примерно 2000–3000 руб./мес. при текущих тарифах.

Почему lerp-интерполяция обязательна?

Прямое обновление позиции по каждому событию вызывает рывки. CSS-переход transition: transform 0.1s linear создаёт задержку в обратную сторону. Единственно правильное решение — linear interpolation (lerp) в requestAnimationFrame:

interface RemoteCursor { userId: string; name: string; color: string; current: { x: number; y: number }; target: { x: number; y: number }; el: HTMLElement; } const cursors = new Map<string, RemoteCursor>(); function lerp(a: number, b: number, t: number) { return a + (b - a) * t; } function animateCursors() { cursors.forEach((cursor) => { cursor.current.x = lerp(cursor.current.x, cursor.target.x, 0.35); cursor.current.y = lerp(cursor.current.y, cursor.target.y, 0.35); cursor.el.style.transform = `translate(${cursor.current.x}px, ${cursor.current.y}px)`; }); requestAnimationFrame(animateCursors); } animateCursors(); // При получении обновления — только меняем target socket.on('cursor:update', ({ userId, x, y, name, color }) => { if (!cursors.has(userId)) { const el = createCursorElement(userId, name, color); document.body.appendChild(el); cursors.set(userId, { userId, name, color, current: { x, y }, target: { x, y }, el, }); } else { cursors.get(userId)!.target = { x, y }; } }); 

Коэффициент интерполяции 0.35 даёт плавное движение без заметной задержки.

Сравнение подходов: WebSocket vs Yjs Awareness

Критерий Чистый WebSocket Yjs Awareness
Время внедрения 1–2 дня с нуля Полдня, если Yjs уже используется
Нагрузка на сервер Выше (своя логика broadcast) Ниже (встроенный broadcast)
Сложность расширения Средняя (добавление полей вручную) Низкая (автоматическое состояние)
Поддержка выделения текста Требует дополнительной логики Встроенная через Awareness

Yjs Awareness внедряется в 3 раза быстрее, чем чистый WebSocket, если Yjs уже используется. Стандарт WebSocket (см. RFC 6455) определяет протокол двусторонней связи.

Как выбрать между WebSocket и Yjs Awareness?

Если в проекте уже используется Yjs — используйте Awareness: он автоматически синхронизирует состояние курсоров, выделение текста и другие поля. В противном случае достаточно чистого WebSocket. Для справки: WebSocket — стандартный протокол, а Yjs — CRDT-библиотека для совместного редактирования.

Процесс работы

  1. Аналитика — определяем сценарии использования, нагрузку, текущий стек.
  2. Проектирование — выбираем протокол (WebSocket или Yjs), проектируем модель данных.
  3. Реализация — пишем клиент-серверную часть, подключаем throttle, lerp, TTL.
  4. Тестирование — проверяем при 50+ одновременных пользователях, замеряем трафик.
  5. Деплой и поддержка — разворачиваем на вашем хостинге, даём гарантию 30 дней.

Что делать, если курсоры исчезают при скролле?

Храните координаты относительно документа (clientX + scrollOffset), а при рендере вычитайте текущий scroll. Иначе чужие курсоры будут смещаться при прокрутке.

document.addEventListener('mousemove', throttle((e) => { provider.awareness.setLocalStateField('cursor', { x: e.clientX + window.scrollX, y: e.clientY + window.scrollY, }); }, 33)); function getCursorViewportPos(docX: number, docY: number) { return { x: docX - window.scrollX, y: docY - window.scrollY, }; } 

TTL и очистка зависших курсоров

Если пользователь закрыл вкладку без явного disconnect, курсор остаётся на экране. Решение — heartbeat + TTL на клиенте:

const CURSOR_TTL = 5000; // 5 секунд без обновлений const lastSeen = new Map<string, number>(); socket.on('cursor:update', ({ userId, ...pos }) => { lastSeen.set(userId, Date.now()); updateCursor(userId, pos); }); setInterval(() => { const now = Date.now(); lastSeen.forEach((ts, userId) => { if (now - ts > CURSOR_TTL) { removeCursor(userId); lastSeen.delete(userId); } }); }, 1000); 

Сравнение вариантов throttle

Частота (fps) Трафик на 10 пользователей (сообщений/сек) Плавность
60 600 Идеальная
30 300 Достаточная
15 150 Заметные рывки

Для большинства задач 30 fps — оптимальный баланс.

Что входит в работу?

При заказе реализации cursor presence вы получаете:

  • Архитектуру передачи данных (WebSocket или Yjs)
  • Клиентский код с throttle и lerp-интерполяцией
  • Обработку координат (document-relative, scroll)
  • TTL-механизм для удаления «зависших» курсоров
  • Интеграцию с существующей системой (редактор, чат и т.д.)
  • Документацию и обучение команды

Реализация cursor presence с нуля занимает 1–2 дня. Если уже используется Yjs или Socket.IO — полдня. Свяжитесь с нами для консультации: оценим ваш проект и предложим оптимальное решение. За пять лет мы выполнили более 30 интеграций — ваш проект будет в надёжных руках. Закажите реализацию сегодня и получите бесплатное тестирование.