deep dive · с кодом и интерактивом

Drag & Drop: как это реально устроено в TakeProfit — и как сделал бы Apple

По запросу — копнул глубже. Ниже: полная инвентаризация всех DnD-взаимодействий, фактика прямо из их бандлов (пороги, зоны, golden-ratio, магнит), 4 интерактивных демо «потрогай руками», и как Apple переосмыслил бы перетаскивание для mobile+desktop.

Инвентарь: где в TakeProfit есть drag & drop

DnD у них не один — это десяток разных механик. Раньше я свёл всё к «drag-to-dock», что было поверхностно. Полный список:

#ГдеЧто делает dragДвижок
1Докинг виджетовТащишь панель → док к краю/центру/во вкладку; сплит по золотому сечениюLumino DockPanel
2Вкладки виджетовReorder вкладок; «отрыв» вкладки в плавающее окноLumino TabBar
3Разделители панелейТащишь сплиттер → ресайз соседних пейновLumino SplitPanel
4Объекты на графике (целиком)Тащишь весь рисунок (трендлайн, прямоугольник…) → переносChart engine
5Контрольные точки (anchors)Тащишь отдельную точку → меняешь геометрию объектаChart engine · hitTest
6Серединные точки (midpoints)Тащишь середину сегмента → сдвиг/добавление точкиChart engine
7Индикаторы между пейнамиПеретаскиваешь индикатор в другой пейн / в новыйChart + reorder
8Reorder watchlist / легендыМеняешь порядок строк с placeholder-гэпомCustom reorder
9Символ → графикПеретаскиваешь тикер из watchlist/скринера на чарт → загрузкаMimeData transfer
10Линии ордеров/уровнейТащишь стоп/лимит/алерт-линию вверх-вниз по ценеChart engine
11Пан/зум графикаDrag = панорамирование времени; края осей = сжатие/растяжениеChart engine
12Drop файла/картинкиБросаешь изображение/ассет в нужный виджетtransfer_float

Как это устроено в коде (фактика из бандлов)

Не «по ощущениям», а из их минифицированных бандлов BgH94ARf.js (движок) и C3wOGcEP.js (Lumino-докинг).

Докинг виджетов (Lumino DockPanel)

КонстантаЗначениеСмысл
DRAG_THRESHOLD5pxСдвиг указателя, после которого начинается drag (отсечь случайные клики)
DETACH_THRESHOLD20pxНа сколько утащить вкладку за пределы таб-бара, чтобы она «оторвалась» в плавающее окно
GOLDEN_RATIO.618Пропорция сплита при доке к краю
DEFAULT_EDGES{top:12, right:40, bottom:40, left:40}Толщина краевых drop-зон (верх тоньше — там тулбары)

Зоны попадания (findDropTarget → zone)

// из C3wOGcEP.js — что возвращает поиск цели дропа
zone: "root-top" | "root-right" | "root-bottom" | "root-left" | "root-all"
    | "widget-all" // дроп по центру виджета = вложить во вкладку
    | "widget-tab" // дроп на таб-бар = вставить вкладку в позицию
    | "invalid"
op: addWidget · moveWidget · insertWidget · insertTab · SplitNode
feedback: lm-DockPanel-overlay (синий прямоугольник) · lm-mod-drag-image (ghost) · overrideCursor

Передача данных — через Lumino MimeData (setData/getData), результат — proposedAction → dropAction из набора copy · move · link · none (если none — дроп отклоняется, overlay прячется).

Объекты на графике

// BgH94ARf.js — порядок при работе с рисунком
pointerdown → hitTest(x,y) → что под курсором: AnchorPoint · midpoint · whole object · resize-handle
startDrag → dragMove → dragEnd
// привязки во время drag:
magnet: magnetThreshold: 16 // px — притяжение точки к OHLC при удержании ⌘
angle:  snapToAngle // Shift → 45°/90°
bar:   _getXThreshold // привязка X к ближайшей свече

Reorder списков

Watchlist/легенда — кастомный drag-reorder с placeholder-гэпом (строка-дырка на месте перетаскиваемого элемента), без сторонней sortable-библиотеки.

Интерактивные демо — потрогай

4 живых демо прямо здесь (мышь или палец). Это упрощённые модели реальных механик TakeProfit.

1 · Докинг с golden-ratio drop-зонамиинтерактив

Тащи плашку «Watchlist» в стейдж. Подсветятся зоны (как у Lumino: лево/право/верх/низ = сплит .618, центр = вкладка). Отпусти — панель докнётся.

График (контент)
Watchlist
BTC/USD+0.18%
ETH/USD+0.09%
SOL/USD−1.2%
▦ Watchlist — тащи сюда ↑
2 · Reorder с placeholder-гэпоминтерактив

Тащи строку вверх/вниз — остальные расступаются (placeholder), как в watchlist.

  • ⋮⋮BTC/USD+0.18%
  • ⋮⋮ETH/USD+0.09%
  • ⋮⋮SOL/USD−1.2%
  • ⋮⋮DOGE/USD+0.8%
  • ⋮⋮TSLA−0.4%
3 · Перетаскивание точки с магнитом (16px к свече)интерактив

Тащи синюю точку. При включённом магните она прилипает к close ближайшей свечи в радиусе 16px (как magnetThreshold:16).

4 · Символ → график (MimeData transfer)интерактив

Тащи тикер на область графика — он «загрузится» (так dnd из watchlist/скринера меняет символ).

⠿ BTC/USD
⠿ ETH/USD
⠿ SOL/USD
Брось тикер сюда
Замечание: все четыре демо работают и мышью, и пальцем (Pointer Events) — но именно это в реальном TakeProfit и есть слабое место на тач (см. ниже).

Где DnD TakeProfit ломается на тач

Проблема

Магнит = удержание ⌘. На телефоне нет ⌘ → точную привязку не вызвать.

Как должно быть

Магнит — это режим/тоггл в плашке + авто-снап по умолчанию на тач; ⌘ — лишь ускоритель на десктопе.

Проблема

Anchor-точки крошечные. Хит-таргет точки рисунка << 44pt — пальцем не попасть.

Как должно быть

На тач — увеличенная невидимая хит-зона ≥44pt вокруг точки + «лупа»/смещение для точного позиционирования под пальцем.

Проблема

Docking/детач — мышиная парадигма (drag header, drop overlay). На телефоне неуместна.

Как должно быть

В compact — нет докинга: свайп между полноэкранными виджетами; DnD-перекомпоновка только в regular/expanded.

Проблема

Drag конфликтует со скроллом/паном. На тач непонятно: я тащу объект или панорамирую график?

Как должно быть

Long-press, чтобы «поднять» объект (lift), затем drag; короткий drag по пустому = пан. Чёткое разделение жестов.

Как Apple сделал бы Drag & Drop

У Apple DnD — это формализованная система (UIDragInteraction/UIDropInteraction + NSItemProvider), единая на iPhone/iPad/Mac, с продуманными жестами, анимациями и доступностью.

Модель «поднять → нести → положить» (lift · drag · set-down)

ФазаTouch (iOS/iPadOS)Pointer (Mac)
НачалоLong-press = lift (объект «приподнимается» с тенью + лёгкий хаптик)press + сдвиг > порога (как DRAG_THRESHOLD 5px)
НесёшьПалец тащит «preview»; можно второй рукой листать/менять экранкурсор + ghost; меняется на drop-курсор
ЦельПодсветка drop-зоны + drop proposal (copy/move/forbidden бейдж)То же + overlay-индикатор (как Lumino)
КонецSpring set-down анимация на место; хаптик подтвержденияплавное «защёлкивание»

Что Apple добавил бы поверх текущего TakeProfit

Spring-loading

Задержал перетаскиваемое над свёрнутой группой/вкладкой — она авто-раскрывается, чтобы можно было дропнуть внутрь. Незаменимо для глубоких раскладок.

Item Providers

Тащимый объект несёт типизированные данные (символ, индикатор-конфиг, рисунок) → можно дропнуть и внутри приложения, и в другое приложение (в Notes, Mail).

Continuity-drag

Через Universal Control / Sidecar — тащишь рисунок или watchlist с iPad на Mac одним жестом. Одна модель данных это позволяет.

Apple Pencil

На iPad — Pencil для точного драга anchor-точек и рисования; палец остаётся для пана/скролла (разделение ввода).

Хаптика + звук

Lift, валидная цель, set-down — каждый этап с тактильным/звуковым подтверждением. Drag перестаёт быть «вслепую».

Доступность DnD

VoiceOver-режим перетаскивания: «выбрать как источник» → «выбрать как цель» без самого жеста. Drag доступен незрячим.

Главное отличие: у TakeProfit DnD — набор отдельных мышиных реализаций. У Apple это одна система взаимодействия с едиными фазами, обратной связью и поведением на любом устройстве и вводе. Те же дроп-зоны и golden-ratio-сплит остаются — но «поднять/положить», хит-зоны 44pt, spring-loading, хаптика и a11y делают их пригодными для тача.

Принципы DnD (свод)

Источники

Фактика по TakeProfit — грэп их бандлов: C3wOGcEP.js (Lumino DockPanel: DRAG_THRESHOLD=5, DETACH_THRESHOLD=20, GOLDEN_RATIO=.618, DEFAULT_EDGES, зоны, mimeData/dropAction) и BgH94ARf.js (движок: hitTest/startDrag, AnchorPoint, magnetThreshold:16, snapToAngle). Модель Apple — Human Interface Guidelines (Drag and Drop) + UIDragInteraction/UIDropInteraction/NSItemProvider + WWDC-сессии по DnD/spring-loading. Демо — упрощённые иллюстрации механик, не их реальный код. Концепт/мнение, не аффилировано.

Связанное: TakeProfit, by Apple · весь ресёрч одной лентой · оглавление.