Реализация Whiteboard (совместная доска) на сайте

Синхронизация изменений при совместном редактировании доски — одна из сложнейших задач в веб-разработке. Без правильного стека рендеринга и механизма синхронизации проект рискует увязнуть в багах и низкой производительности. Мы разрабатываем онлайн-доски для командной работы: рисование от руки, стик

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

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

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

Услуги, которые мы предлагаем
Показано 1 из 1Все 2062 услуг
Реализация Whiteboard (совместная доска) на сайте
Сложный
~2-4 недели

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

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

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

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

Синхронизация изменений при совместном редактировании доски — одна из сложнейших задач в веб-разработке. Без правильного стека рендеринга и механизма синхронизации проект рискует увязнуть в багах и низкой производительности. Мы разрабатываем онлайн-доски для командной работы: рисование от руки, стикеры, фигуры, линии и синхронизация в реальном времени. Наши инженеры внедряют whiteboard под ключ с нуля или интегрируют готовые SDK (tldraw, Excalidraw) с кастомной CRDT-синхронизацией. За 5+ лет реализовано более 30 проектов — от простых досок для заметок до полноценных коллаборативных редакторов с WebRTC и аудиозвонками. Экономия времени — до 40% по сравнению с самостоятельной разработкой.

Как выбрать рендеринг-стек для whiteboard?

Вариант Скорость разработки Кастомизация Производительность (1000 shapes) Стоимость поддержки
tldraw 1–2 дня Средняя (SDK) Высокая (Canvas) Низкая (open-source)
Konva.js 3–4 недели Полная Высокая (Canvas) Средняя
Excalidraw 1–2 дня (форк) Низкая (форк сложен) Средняя (SVG) Высокая (форк)
Fabric.js 2–3 недели Средняя Средняя (Canvas) Высокая (устаревает)
SVG + vanilla 1–2 недели Полная Низкая при >500 shapes Средняя

Для production-продукта с кастомными требованиями предпочтительнее tldraw как основа или Konva.js с нуля. Excalidraw форкается, но стоимость поддержки форка высокая. Мы выбираем стек под ваши задачи и бюджет — закажите разработку и получите архитектурную документацию.

Почему CRDT — оптимальный выбор для синхронизации?

CRDT — это структура данных, которая автоматически разрешает конфликты при параллельном редактировании. Для whiteboard мы используем библиотеку Yjs, которая предоставляет CRDT-типы, оптимизированные для совместной работы. Yjs в 3 раза быстрее OT при одновременном редактировании 10 пользователей, что подтверждено бенчмарками.

Архитектура: состояние доски

Доска — это набор shape-объектов. Каждый shape имеет тип, геометрию и стили.

Основные типы фигур
Тип Свойства
Rect x, y, width, height, fill, stroke, strokeWidth, cornerRadius
Ellipse x, y, radiusX, radiusY, fill, stroke
Line points, stroke, strokeWidth
Arrow points, stroke, headStyle
Text content, fontSize, fontFamily, color, width
Freehand points, stroke, strokeWidth, pressure
Image src, x, y, width, height

CRDT для синхронизации shapes

Y.Map идеально подходит — каждый shape хранится по своему id:

import * as Y from 'yjs'; import { WebsocketProvider } from 'y-websocket'; const ydoc = new Y.Doc(); const yshapes = ydoc.getMap<Y.Map<unknown>>('shapes'); const provider = new WebsocketProvider( process.env.WS_URL!, `board-${boardId}`, ydoc ); // Добавление shape function addShape(shape: Shape) { const yshape = new Y.Map<unknown>(Object.entries(shape)); yshapes.set(shape.id, yshape); } // Обновление (например, при перетаскивании) function updateShape(id: string, patch: Partial<Shape>) { const yshape = yshapes.get(id); if (!yshape) return; ydoc.transact(() => { Object.entries(patch).forEach(([key, value]) => { yshape.set(key, value); }); }); } // Удаление function deleteShape(id: string) { yshapes.delete(id); } // Реактивность yshapes.observeDeep((events) => { events.forEach((event) => { rerenderCanvas(yshapes); }); }); 

Freehand drawing: оптимизация точек

При рисовании от руки накапливаются сотни точек. Передавать все — дорого. Используется алгоритм Ramer-Douglas-Peucker для упрощения кривых:

function rdp(points: [number, number][], epsilon: number): [number, number][] { if (points.length < 3) return points; let maxDist = 0; let maxIdx = 0; const end = points.length - 1; for (let i = 1; i < end; i++) { const dist = perpendicularDistance(points[i], points[0], points[end]); if (dist > maxDist) { maxDist = dist; maxIdx = i; } } if (maxDist > epsilon) { const left = rdp(points.slice(0, maxIdx + 1), epsilon); const right = rdp(points.slice(maxIdx), epsilon); return [...left.slice(0, -1), ...right]; } return [points[0], points[end]]; } 

После завершения рисования вызываем упрощение и синхронизацию. Для плавных кривых используем библиотеку perfect-freehand.

Viewport: pan и zoom

Доска бесконечная — нужен viewport transform. Все координаты хранятся в мировом пространстве, viewport описывает текущий вид:

interface Viewport { x: number; // смещение y: number; zoom: number; // 0.1 – 4.0 } // Мировые координаты → экранные function worldToScreen(wx: number, wy: number, vp: Viewport) { return { x: wx * vp.zoom + vp.x, y: wy * vp.zoom + vp.y, }; } // Экранные → мировые (для pointer events) function screenToWorld(sx: number, sy: number, vp: Viewport) { return { x: (sx - vp.x) / vp.zoom, y: (sy - vp.y) / vp.zoom, }; } // Zoom к точке (pinch или колёсико) function zoomAt(vp: Viewport, screenX: number, screenY: number, delta: number): Viewport { const factor = delta > 0 ? 1.1 : 0.9; const newZoom = Math.max(0.1, Math.min(4.0, vp.zoom * factor)); const zoomRatio = newZoom / vp.zoom; return { x: screenX - (screenX - vp.x) * zoomRatio, y: screenY - (screenY - vp.y) * zoomRatio, zoom: newZoom, }; } 

Canvas vs SVG: выбор под нагрузку

При менее 500 shapes SVG работает отлично и упрощает hit-testing. При более 1000 shapes и активном рисовании используем Canvas (2D или WebGL через Pixi.js). Гибридный подход: shapes рендерятся в Canvas, UI-элементы — в HTML поверх.

Реализация Undo/Redo

Yjs предоставляет UndoManager, который группирует операции за 500 мс:

const undoManager = new Y.UndoManager(yshapes, { trackedOrigins: new Set([ydoc.clientID]), captureTimeout: 500, }); document.addEventListener('keydown', (e) => { if (e.ctrlKey && e.key === 'z') undoManager.undo(); if (e.ctrlKey && e.key === 'y') undoManager.redo(); }); 

Экспорт доски

async function exportToPNG(boardId: string): Promise<Blob> { const canvas = document.getElementById('whiteboard-canvas') as HTMLCanvasElement; const shapes = Array.from(yshapes.values()).map(s => shapeFromYMap(s)); const bbox = getBoundingBox(shapes); const offscreen = new OffscreenCanvas(bbox.width + 80, bbox.height + 80); const ctx = offscreen.getContext('2d')!; ctx.fillStyle = '#ffffff'; ctx.fillRect(0, 0, offscreen.width, offscreen.height); renderShapes(ctx, shapes, { x: -bbox.x + 40, y: -bbox.y + 40, zoom: 1 }); return await offscreen.convertToBlob({ type: 'image/png' }); } 

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

  1. Аналитика: изучение пользовательских сценариев, подбор стека.
  2. Проектирование: архитектура данных, протокол синхронизации, дизайн интерфейса.
  3. Реализация: разработка canvas-движка, интеграция Yjs, кастомные инструменты.
  4. Тестирование: unit-тесты, нагрузочное тестирование, проверка рассинхронизации.
  5. Деплой: Docker-образ, настройка WebSocket, CDN для статики.

Сроки реализации

Встройка tldraw с кастомной синхронизацией через Yjs: 5–7 дней. Whiteboard с нуля на Konva.js с freehand, shapes, viewport, undo, presence и экспортом: 3–4 недели. Добавление video/audio через WebRTC параллельно с доской: ещё неделя. Гарантия на код — исправляем баги бесплатно в течение месяца.

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

  • Архитектурная документация (выбор стека, схема данных, протокол синхронизации).
  • Исходный код доски с комментариями и тестами критических модулей.
  • Интеграция с вашей системой аутентификации и API.
  • Деплой на сервер или CDN (Docker-образ, настройка WebSocket).
  • Обучение команды (воркшоп по кастомизации и поддержке).
  • Гарантия на код — исправляем баги бесплатно в течение месяца.
  • Сертифицированные инженеры с опытом 5+ лет.

Получите консультацию инженера — мы оценим ваш проект и предложим оптимальное решение. Свяжитесь с нами, чтобы обсудить детали.