Спільне малювання в реальному часі в мобільному додатку

Реалізація колаборативного малювання в мобільному додатку Зустрічається ситуація: два користувачі малюють на одному полотні, і через 200 мс штрихи накладаються не в тому порядку. Причина — відсутність чесного впорядкування. Ми вирішуємо це за допомогою **CRDT** ([Conflict-free Replicated Data Typ

Розробка та підтримка будь-яких видів мобільних додатків:

Інформаційні та розважальні мобільні програми
Новинки, ігри, довідники, онлайн-каталоги, погодні, фітнес та здоров'я, туристичні, освітні, соціальні мережі та месенджери, квіз, блоги та подкасти, форуми, агрегатори
Мобільні програми електронної комерції
Інтернет-магазини, B2B-додатки, маркетплейси, онлайн-обмінники, кешбек-сервіси, біржі, дропшиппінг-платформи, програми лояльності, доставка їжі та товарів, платіжні системи
Мобільні програми для управління бізнес-процесами
CRM-системи, ERP-системи, управління проектами, інструменти для команди продажів, облік фінансів, управління виробництвом, логістика та доставка, управління персоналом, системи моніторингу даних
Мобільні програми електронних послуг
Дошки оголошень, онлайн-школи, онлайн-кінотеатри, платформи надання електронних послуг, платформи кешбеку, відеохостинги, тематичні портали, платформи онлайн-бронювання та запису, платформи онлайн-торгівлі

Це лише деякі з типів мобільних додатків, з якими ми працюємо, і кожен із них може мати свої специфічні особливості та функціональність, а також бути адаптованим під конкретні потреби та цілі клієнта.

Послуги, які ми пропонуємо
Показано 1 з 1Усі 1734 послуг
Спільне малювання в реальному часі в мобільному додатку
Складний
від 1 тижня до 3 місяців

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

Часті запитання

Останні роботи

  • image_mobile-applications_feedme_467_0.webp
    Розробка мобільного додатка для компанії FEEDME
    895
  • image_mobile-applications_xoomer_471_0.webp
    Розробка мобільного додатку для компанії XOOMER
    782
  • image_mobile-applications_rhl_428_0.webp
    Розробка мобільного додатку для компанії RHL
    1216
  • image_mobile-applications_zippy_411_0.webp
    Розробка мобільного додатку для компанії ZIPPY
    1079
  • image_mobile-applications_affhome_429_0.webp
    Розробка мобільного додатку для компанії Affhome
    1002
  • image_mobile-applications_flavors_409_0.webp
    Розробка мобільного додатку для компанії FLAVORS
    597

Реалізація колаборативного малювання в мобільному додатку

Зустрічається ситуація: два користувачі малюють на одному полотні, і через 200 мс штрихи накладаються не в тому порядку. Причина — відсутність чесного впорядкування. Ми вирішуємо це за допомогою CRDT (Conflict-free Replicated Data Type). Наш стек — Flutter 3.x, Kotlin Multiplatform, Swift 5.9. Синхронізація побудована на бінарному протоколі поверх WebSocket, що дає затримку менше 100 мс при 60 FPS.

Бінарний протокол замість JSON дає виграш у 3 рази за об'ємом даних. Типова помилка — відправляти кожну подію окремо. Ми використовуємо батчинг: групуємо точки за 50–80 мс і відправляємо одним повідомленням. Це знижує навантаження на канал і сервер, економлячи ресурси.

Як працює CRDT для малювання?

Конфлікти при одночасному малюванні в одній області — часта проблема. Ми застосовуємо CRDT з вектором годинників. Кожна дія (початок, точки, завершення штриха) отримує мітку часу. При отриманні конфліктуючих правок порядок відновлюється за вектором: відправник не чекає підтвердження, а просто застосовує локально і фоново синхронізує. Це гарантує відсутність втрати даних і чесний порядок.

Як забезпечується локальний відгук при віддаленій синхронізації?

Користувач повинен бачити свій штрих одразу, без очікування мережі. Для цього ми рендеримо локальний штрих негайно, а синхронізацію запускаємо паралельно.

// Flutter: локальний штрих class DrawingBloc extends Bloc<DrawingEvent, DrawingState> { void onPointerDown(PointerDownEvent e) { currentStroke = Stroke(id: uuid(), points: [e.localPosition]); emit(state.copyWith(activeStroke: currentStroke)); _syncService.beginStroke(currentStroke.id, color, brushSize); } void onPointerMove(PointerMoveEvent e) { currentStroke.points.add(e.localPosition); emit(state.copyWith(activeStroke: currentStroke)); _syncService.appendPoints(currentStroke.id, [e.localPosition]); } void onPointerUp(PointerUpEvent e) { _syncService.finalizeStroke(currentStroke.id); } } 

Синхронізація йде незалежно — локальний рендер не блокується.

Чому важливий батчинг точок?

На мобільному пристрої 60 кадрів на секунду генерують до 60 подій pointerMove. Якщо відправляти кожну одразу, буде надлишковий трафік і затримка на серіалізацію. Ми збираємо точки в батчі по 10–15 штук і відправляємо кожні 50–80 мс. Це баланс між затримкою і трафіком.

Формат бінарного повідомлення (економія 3–5x порівняно з JSON):

[strokeId: 16 bytes][pointCount: uint8][x1:f32][y1:f32][p1:f16][x2:f32]... 

Float16 для тиску (0.0–1.0 з точністю 0.001) достатньо. Координати — float32 для субпіксельної точності. Разом ~10 байт на точку проти ~30 в JSON.

На WebSocket передаємо бінарні кадри (ArrayBuffer в JS, Uint8List в Dart, ByteBuffer в Kotlin).

Алгоритм згладжування на стороні отримувача

Віддалені точки приходять батчами з затримкою і дискретно. Проста відмальовка ліній між точками дає східчасті лінії. Потрібне згладжування. Ми рекомендуємо два методи:

  • Catmull-Rom Spline — проходить через всі контрольні точки, низька складність, середня якість.
  • Perfect Freehand — симулює форму пензля з урахуванням тиску і швидкості, генерує SVG-path. Висока якість, середня складність.

Для віддаленого штриха застосовуємо Perfect Freehand до всього масиву точок при кожному оновленні. Path перемальовується повністю — це дорожче по CPU, але візуально правильно (згладжування враховує весь контекст).

Метод згладжування Складність Якість
Catmull-Rom Spline Низька Середня
Perfect Freehand Середня Висока

Шари і порядок об'єктів

Базова модель: кожен штрих має z-index (timestamp створення). При конкурентному малюванні в одній області — хто намалював останнім, той зверху.

Шари (layers) — опціональна фіча. Кожен шар — окремий Y.Array об'єктів. Користувач вибирає активний шар. Видимість/блокування шару — поле в Y.Map шару.

При рендерингу: Canvas малює шари знизу вгору. Кожен шар — окремий offscreen canvas (iOS: UIGraphicsImageRenderer, Android: Bitmap з Canvas). Шари кешуються і перемальовуються тільки при зміні.

Ластик: спеціальний інструмент

Ластик не малює білим — він видаляє пікселі. Два варіанти:

  1. Object-level eraser — видаляє весь штрих при перетині. Простий у реалізації, добре синхронізується (delete(strokeId) — атомарна операція).
  2. Pixel-level eraser — розрізає штрих на частини. Вимагає геометричних обчислень (clip polygon by path). У колаборативному контексті складніше — потрібно розрізати штрих і створити нові об'єкти, що проблема для CRDT.

Ми рекомендуємо object-level eraser для початку.

Apple Pencil та Android Stylus

Apple Pencil через UITouch.type == .pencil передає тиск (force 0.0–1.0), кут нахилу (altitudeAngle, azimuthAngle) та передбачені точки (predictedTouches). Flutter уніфікує: PointerEvent.pressure, PointerEvent.tilt, PointerEvent.orientation. Синхронізація pressure/tilt на віддалені клієнти дає реалістичне відображення пензля партнера.

Як інтегрувати колаборативне малювання: покрокова інструкція

  1. Аналіз вимог — визначте кількість одночасно малюючих, необхідні інструменти, рівень згладжування.
  2. Вибір стеку — Flutter, Kotlin Multiplatform або нативний Swift/Kotlin. Ми рекомендуємо Flutter для кроссплатформенності.
  3. Інтеграція SDK — підключіть наш SDK, дотримуйтесь документації. Приклади коду для iOS, Android та Flutter включені.
  4. Налаштування серверної частини — розгорніть WebSocket-сервер з підтримкою CRDT. Ми надаємо Docker-образ.
  5. Тестування — перевірте синхронізацію при різних мережевих умовах, використовуйте TestFlight/Firebase Distribution.
  6. Деплой — публікація в App Store / Google Play.

Терміни та що входить

Колаборативне малювання з базовими інструментами (пензель, ластик, колір) на Flutter — 8–14 тижнів. З підтримкою стилуса, шарами, pixel-level eraser та масштабованим полотном — 20–28 тижнів.

У розробку входить:

  • Документація API та архітектури
  • Доступ до репозиторію з прикладами
  • Навчання команди замовника
  • Підтримка протягом місяця після релізу

Для точної оцінки вашого сценарію зв'яжіться з нами — ми розрахуємо терміни та бюджет під конкретні вимоги. Отримайте консультацію наших інженерів з 10-річним досвідом.

Типові помилки при реалізації:

  • Відправка кожної події окремим повідомленням замість батчингу
  • Використання JSON для точок — високий overhead
  • Ігнорування передбачення дотиків для стилуса
  • Відсутність CRDT для конфліктів
  • Рендеринг всіх шарів кожен фрейм без кешування
Транспорт Розмір на точку Затримка серіалізації
JSON ~30 байт ~0.5 мс
Бінарний ~10 байт ~0.1 мс

Зв'яжіться з нами, щоб обговорити вашу задачу. Отримайте оцінку проекту вже сьогодні.